1 /******************************************************************************
2 *
3 * gbfwordjs.cpp - SWFilter descendant for ???
4 *
5 * $Id: gbfwordjs.cpp 3515 2017-11-01 11:38:09Z scribe $
6 *
7 * Copyright 2005-2013 CrossWire Bible Society (http://www.crosswire.org)
8 * CrossWire Bible Society
9 * P. O. Box 2528
10 * Tempe, AZ 85280-2528
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation version 2.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <gbfwordjs.h>
26 #include <swmodule.h>
27 #include <ctype.h>
28 #include <utilstr.h>
29 #include <versekey.h>
30
31
32 SWORD_NAMESPACE_START
33
34 namespace {
35
36 static const char oName[] = "Word Javascript";
37 static const char oTip[] = "Toggles Word Javascript data";
38
oValues()39 static const StringList *oValues() {
40 static const SWBuf choices[3] = {"Off", "On", ""};
41 static const StringList oVals(&choices[0], &choices[2]);
42 return &oVals;
43 }
44 }
45
46
GBFWordJS()47 GBFWordJS::GBFWordJS() : SWOptionFilter(oName, oTip, oValues()) {
48
49 defaultGreekLex = 0;
50 defaultHebLex = 0;
51 defaultGreekParse = 0;
52 defaultHebParse = 0;
53 mgr = 0;
54 }
55
56
~GBFWordJS()57 GBFWordJS::~GBFWordJS() {
58 }
59
60
processText(SWBuf & text,const SWKey * key,const SWModule * module)61 char GBFWordJS::processText(SWBuf &text, const SWKey *key, const SWModule *module) {
62 if (option) {
63 char token[2112]; // cheese. Fix.
64 int tokpos = 0;
65 bool intoken = false;
66 int word = 1;
67 char val[128];
68 char wordstr[5];
69 unsigned int textStart = 0, lastAppendLen = 0, textEnd = 0;
70 SWBuf tmp;
71 bool newText = false;
72 bool needWordOut = false;
73 AttributeValue *wordAttrs = 0;
74 SWBuf modName = (module)?module->getName():"";
75 SWBuf wordSrcPrefix = modName;
76
77 const SWBuf orig = text;
78 const char * from = orig.c_str();
79 VerseKey *vkey = 0;
80 if (key) {
81 vkey = SWDYNAMIC_CAST(VerseKey, key);
82 }
83
84 for (text = ""; *from; from++) {
85 if (*from == '<') {
86 intoken = true;
87 tokpos = 0;
88 token[0] = 0;
89 token[1] = 0;
90 token[2] = 0;
91 textEnd = (unsigned int)text.length();
92 continue;
93 }
94 if (*from == '>') { // process tokens
95 intoken = false;
96 if (*token == 'W' && (token[1] == 'G' || token[1] == 'H')) { // Strongs
97 strcpy(val,token+1);
98 if (atoi((!isdigit(*val))?val+1:val) < 5627) {
99 // normal strongs number
100 sprintf(wordstr, "%03d", word++);
101 needWordOut = (word > 2);
102 wordAttrs = &(module->getEntryAttributes()["Word"][wordstr]);
103 (*wordAttrs)["Lemma"] = val;
104 //printf("Adding: [\"Word\"][%s][\"Strongs\"] = %s\n", wordstr, val);
105 tmp = "";
106 tmp.append(text.c_str()+textStart, (int)(textEnd - textStart));
107 (*wordAttrs)["Text"] = tmp;
108 text.append("</span>");
109 SWBuf ts;
110 ts.appendFormatted("%d", textStart);
111 (*wordAttrs)["TextStart"] = ts;
112 //printf("Adding: [\"Word\"][%s][\"Text\"] = %s\n", wordstr, tmp.c_str());
113 newText = true;
114 }
115 else {
116 // verb morph
117 if (wordAttrs) {
118 (*wordAttrs)["Morph"] = val;
119 }
120 //printf("Adding: [\"Word\"][%s][\"Morph\"] = %s\n", wordstr, val);
121 }
122
123 }
124 if (*token == 'W' && token[1] == 'T') { // Morph
125 if (token[2] == 'G' || token[2] == 'H') {
126 strcpy(val, token+2);
127 }
128 else strcpy(val, token+1);
129 if (wordAttrs) {
130 (*wordAttrs)["Morph"] = val;
131 (*wordAttrs)["MorphClass"] = "StrongsMorph";
132 }
133 newText = true;
134 }
135 // if not a strongs token, keep token in text
136 text += '<';
137 text += token;
138 text += '>';
139 if (needWordOut) {
140 char wstr[11];
141 sprintf(wstr, "%03d", word-2);
142 AttributeValue *wAttrs = &(module->getEntryAttributes()["Word"][wstr]);
143 needWordOut = false;
144 SWBuf strong = (*wAttrs)["Lemma"];
145 SWBuf morph = (*wAttrs)["Morph"];
146 SWBuf morphClass = (*wAttrs)["MorphClass"];
147 SWBuf wordText = (*wAttrs)["Text"];
148 SWBuf textSt = (*wAttrs)["TextStart"];
149 if (strong.size()) {
150 char gh = 0;
151 gh = isdigit(strong[0]) ? 0:strong[0];
152 if (!gh) {
153 if (vkey) {
154 gh = vkey->getTestament() ? 'H' : 'G';
155 }
156 }
157 else strong << 1;
158
159 SWModule *sLex = 0;
160 SWModule *sMorph = 0;
161 if (gh == 'G') {
162 sLex = defaultGreekLex;
163 sMorph = defaultGreekParse;
164 }
165 if (gh == 'H') {
166 sLex = defaultHebLex;
167 sMorph = defaultHebParse;
168 }
169 SWBuf lexName = "";
170 if (sLex) {
171 // we can pass the real lex name in, but we have some
172 // aliases in the javascript to optimize bandwidth
173 lexName = sLex->getName();
174 if (lexName == "StrongsGreek")
175 lexName = "G";
176 if (lexName == "StrongsHebrew")
177 lexName = "H";
178 }
179 SWBuf wordID;
180 if (vkey) {
181 // optimize for bandwidth and use only the verse as the unique entry id
182 wordID.appendFormatted("%d", vkey->getVerse());
183 }
184 else {
185 wordID = key->getText();
186 }
187 for (unsigned int i = 0; i < wordID.size(); i++) {
188 if ((!isdigit(wordID[i])) && (!isalpha(wordID[i]))) {
189 wordID[i] = '_';
190 }
191 }
192 wordID.appendFormatted("_%s%d", wordSrcPrefix.c_str(), atoi(wstr));
193 if (textSt.size()) {
194 int textStr = atoi(textSt.c_str());
195 textStr += lastAppendLen;
196 SWBuf spanStart = "";
197
198
199
200 if (!sMorph) sMorph = 0; // to pass unused warning for now
201 /*
202 if (sMorph) {
203 SWBuf popMorph = "<a onclick=\"";
204 popMorph.appendFormatted("p(\'%s\',\'%s\','%s','');\" >%s</a>", sMorph->getName(), morph.c_str(), wordID.c_str(), morph.c_str());
205 morph = popMorph;
206 }
207 */
208
209 // 'p' = 'fillpop' to save bandwidth
210 const char *m = strchr(morph.c_str(), ':');
211 if (m) m++;
212 else m = morph.c_str();
213 spanStart.appendFormatted("<span class=\"clk\" onclick=\"p('%s','%s','%s','%s','','%s');\" >", lexName.c_str(), strong.c_str(), wordID.c_str(), m, modName.c_str());
214 text.insert(textStr, spanStart);
215 lastAppendLen = (unsigned int)spanStart.length();
216 }
217 }
218
219 }
220 if (newText) {
221 textStart = (unsigned int)text.length(); newText = false;
222 }
223 continue;
224 }
225 if (intoken) {
226 if (tokpos < 2045) {
227 token[tokpos++] = *from;
228 // TODO: why is this + 2 ?
229 token[tokpos+2] = 0;
230 }
231 }
232 else {
233 text += *from;
234 }
235 }
236
237 char wstr[11];
238 sprintf(wstr, "%03d", word-1);
239 AttributeValue *wAttrs = &(module->getEntryAttributes()["Word"][wstr]);
240 needWordOut = false;
241 SWBuf strong = (*wAttrs)["Lemma"];
242 SWBuf morph = (*wAttrs)["Morph"];
243 SWBuf morphClass = (*wAttrs)["MorphClass"];
244 SWBuf wordText = (*wAttrs)["Text"];
245 SWBuf textSt = (*wAttrs)["TextStart"];
246 if (strong.size()) {
247 char gh = 0;
248 gh = isdigit(strong[0]) ? 0:strong[0];
249 if (!gh) {
250 if (vkey) {
251 gh = vkey->getTestament() ? 'H' : 'G';
252 }
253 }
254 else strong << 1;
255
256 SWModule *sLex = 0;
257 if (gh == 'G') {
258 sLex = defaultGreekLex;
259 }
260 if (gh == 'H') {
261 sLex = defaultHebLex;
262 }
263 SWBuf lexName = "";
264 if (sLex) {
265 // we can pass the real lex name in, but we have some
266 // aliases in the javascript to optimize bandwidth
267 lexName = sLex->getName();
268 if (lexName == "StrongsGreek")
269 lexName = "G";
270 if (lexName == "StrongsHebrew")
271 lexName = "H";
272 }
273 SWBuf wordID;
274 if (vkey) {
275 // optimize for bandwidth and use only the verse as the unique entry id
276 wordID.appendFormatted("%d", vkey->getVerse());
277 }
278 else {
279 wordID = key->getText();
280 }
281 for (unsigned int i = 0; i < wordID.size(); i++) {
282 if ((!isdigit(wordID[i])) && (!isalpha(wordID[i]))) {
283 wordID[i] = '_';
284 }
285 }
286 wordID.appendFormatted("_%s%d", wordSrcPrefix.c_str(), atoi(wstr));
287 if (textSt.size()) {
288 int textStr = atoi(textSt.c_str());
289 textStr += lastAppendLen;
290 SWBuf spanStart = "";
291 // 'p' = 'fillpop' to save bandwidth
292 const char *m = strchr(morph.c_str(), ':');
293 if (m) m++;
294 else m = morph.c_str();
295 spanStart.appendFormatted("<span class=\"clk\" onclick=\"p('%s','%s','%s','%s','','%s');\" >", lexName.c_str(), strong.c_str(), wordID.c_str(), m, modName.c_str());
296 text.insert(textStr, spanStart);
297 }
298 }
299 }
300
301 return 0;
302 }
303
304 SWORD_NAMESPACE_END
305