The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
osiscgi.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * osiscgi.cpp - OSISCGI: OSIS to Diatheke/CGI format filter
4  *
5  * $Id: osiscgi.cpp 3808 2020-10-02 13:23:34Z scribe $
6  *
7  * Copyright 2003-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 "osiscgi.h"
25 #include <utilxml.h>
26 #include <versekey.h>
27 #include <swmodule.h>
28 #include <ctype.h>
29 
31 
32 
34  osisQToTick = ((!module->getConfigEntry("OSISqToTick")) || (strcmp(module->getConfigEntry("OSISqToTick"), "false")));
35 }
36 
37 
39  setTokenStart("<");
40  setTokenEnd(">");
41 
42  setEscapeStart("&");
43  setEscapeEnd(";");
44 
46 
47  addEscapeStringSubstitute("amp", "&");
48  addEscapeStringSubstitute("apos", "'");
49  addEscapeStringSubstitute("lt", "<");
50  addEscapeStringSubstitute("gt", ">");
51  addEscapeStringSubstitute("quot", "\"");
52  addTokenSubstitute("lg", "<br />");
53  addTokenSubstitute("/lg", "<br />");
54 
56 }
57 
58 
59 bool OSISCGI::handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData) {
60  // manually process if it wasn't a simple substitution
61  if (!substituteToken(buf, token)) {
62  MyUserData *u = (MyUserData *)userData;
63  XMLTag tag(token);
64 
65  // <w> tag
66  if (!strcmp(tag.getName(), "w")) {
67 
68  // start <w> tag
69  if ((!tag.isEmpty()) && (!tag.isEndTag())) {
70  u->w = token;
71  }
72 
73  // end or empty <w> tag
74  else {
75  bool endTag = tag.isEndTag();
76  SWBuf lastText;
77  bool show = true; // to handle unplaced article in kjv2003-- temporary till combined
78 
79  if (endTag) {
80  tag = u->w.c_str();
81  lastText = u->lastTextNode.c_str();
82  }
83  else lastText = "stuff";
84 
85  const char *attrib;
86  const char *val;
87  if ((attrib = tag.getAttribute("xlit"))) {
88  val = strchr(attrib, ':');
89  val = (val) ? (val + 1) : attrib;
90  buf.appendFormatted(" %s", val);
91  }
92  if ((attrib = tag.getAttribute("gloss"))) {
93  val = strchr(attrib, ':');
94  val = (val) ? (val + 1) : attrib;
95  buf.appendFormatted(" %s", val);
96  }
97  if ((attrib = tag.getAttribute("lemma"))) {
98  int count = tag.getAttributePartCount("lemma");
99  int i = (count > 1) ? 0 : -1; // -1 for whole value cuz it's faster, but does the same thing as 0
100  do {
101  attrib = tag.getAttribute("lemma", i);
102  if (i < 0) i = 0; // to handle our -1 condition
103  val = strchr(attrib, ':');
104  val = (val) ? (val + 1) : attrib;
105  const char *val2 = val;
106  if ((strchr("GH", *val)) && (isdigit(val[1])))
107  val2++;
108  if ((!strcmp(val2, "3588")) && (lastText.length() < 1))
109  show = false;
110  else {
111  if (!strchr("G", *val)) {
112  buf.appendFormatted(" <small><em>&lt;<a href=\"!DIATHEKE_URL!StrongsGreek=on&verse=%s\">%s</a>&gt;</em></small> ", val2, val);
113  }
114  else {
115  buf.appendFormatted(" <small><em>&lt;<a href=\"!DIATHEKE_URL!StrongsHebrew=on&verse=%s\">%s</a>&gt;</em></small> ", val2, val);
116  }
117  }
118  } while (++i < count);
119  }
120  if ((attrib = tag.getAttribute("morph")) && (show)) {
121  SWBuf savelemma = tag.getAttribute("savlm");
122  if ((strstr(savelemma.c_str(), "3588")) && (lastText.length() < 1))
123  show = false;
124  if (show) {
125  int count = tag.getAttributePartCount("morph");
126  int i = (count > 1) ? 0 : -1; // -1 for whole value cuz it's faster, but does the same thing as 0
127  do {
128  attrib = tag.getAttribute("morph", i);
129  if (i < 0) i = 0; // to handle our -1 condition
130  val = strchr(attrib, ':');
131  val = (val) ? (val + 1) : attrib;
132  const char *val2 = val;
133  if ((*val == 'T') && (strchr("GH", val[1])) && (isdigit(val[2])))
134  val2+=2;
135  if (!strchr("G", *val)) {
136  buf.appendFormatted(" <small><em>(;<a href=\"!DIATHEKE_URL!StrongsGreek=on&verse=%s\">%s</a>)</em></small> ", val+1, tag.getAttribute("morph"));
137  }
138  else if (!strchr("H", *val)) {
139  buf.appendFormatted(" <small><em>(<a href=\"!DIATHEKE_URL!StrongsHebrew=on&verse=%s\">%s</a>)</em></small> ", val+1, tag.getAttribute("morph"));
140  }
141  else {
142  buf.appendFormatted(" <small><em>(<a href=\"!DIATHEKE_URL!Packard=on&verse=%s\">%s</a>)</em></small> ", val, tag.getAttribute("morph"));
143  }
144  } while (++i < count);
145  }
146  }
147  if ((attrib = tag.getAttribute("POS"))) {
148  val = strchr(attrib, ':');
149  val = (val) ? (val + 1) : attrib;
150  buf.appendFormatted(" %s", val);
151  }
152 
153  /*if (endTag)
154  buf += "}";*/
155  }
156  }
157 
158  // <note> tag
159  else if (!strcmp(tag.getName(), "note")) {
160  if (!tag.isEndTag()) {
161  if (!tag.isEmpty()) {
162  SWBuf type = tag.getAttribute("type");
163 
164  if (type != "x-strongsMarkup" && // leave strong's markup notes out, in the future we'll probably have different option filters to turn different note types on or off
165  type != "strongsMarkup") { // deprecated
166  SWBuf footnoteNumber = tag.getAttribute("swordFootnote");
167  const VerseKey *vkey = NULL;
168  // see if we have a VerseKey * or descendant
169  SWTRY {
170  vkey = SWDYNAMIC_CAST(const VerseKey, u->key);
171  }
172  SWCATCH ( ... ) { }
173  if (vkey) {
174  char ch = ((tag.getAttribute("type") && (!strcmp(tag.getAttribute("type"), "crossReference"))) ? 'x':'n');
175  buf.appendFormatted("<a href=\"noteID=%s.%c.%s\"><small><sup>*%c</sup></small></a> ", vkey->getText(), ch, footnoteNumber.c_str(), ch);
176  }
177  }
178  u->suspendTextPassThru = true;
179  }
180  }
181  if (tag.isEndTag()) {
182  u->suspendTextPassThru = false;
183  }
184  }
185 
186  // <p> paragraph tag
187  else if (!strcmp(tag.getName(), "p")) {
188  if ((!tag.isEndTag()) && (!tag.isEmpty())) { // non-empty start tag
189  buf += "<p><br />";
190  }
191  else if (tag.isEndTag()) { // end tag
192  buf += "</p><br />";
193  userData->supressAdjacentWhitespace = true;
194  }
195  else { // empty paragraph break marker
196  buf += "<p><br />";
197  userData->supressAdjacentWhitespace = true;
198  }
199  }
200 
201  // <reference> tag
202  else if (!strcmp(tag.getName(), "reference")) {
203  const char *attrib;
204  const char *val;
205 
206  if ((!tag.isEndTag()) && (!tag.isEmpty())) {
207  buf += "<a href=\"!DIATHEKE_URL!verse=";
208  if ((attrib = tag.getAttribute("osisRef"))) {
209  val = strchr(attrib, ':');
210  val = (val) ? (val + 1) : attrib;
211  buf.appendFormatted("%s", val);
212  }
213  buf += "\">";
214  }
215  else if (tag.isEndTag()) {
216  buf += "</a>";
217  }
218  }
219 
220  // <l> poetry, etc
221  else if (!strcmp(tag.getName(), "l")) {
222  if (tag.isEmpty()) {
223  buf += "<br />";
224  }
225  else if (tag.isEndTag()) {
226  buf += "<br />";
227  }
228  else if (tag.getAttribute("sID")) { // empty line marker
229  buf += "<br />";
230  }
231  }
232 
233  // <milestone type="line"/> or <lb.../>
234  else if ((!strcmp(tag.getName(), "lb")) || ((!strcmp(tag.getName(), "milestone")) && (tag.getAttribute("type")) && (!strcmp(tag.getAttribute("type"), "line")))) {
235  buf += "<br />";
236  userData->supressAdjacentWhitespace = true;
237  }
238 
239  // <title>
240  else if (!strcmp(tag.getName(), "title")) {
241  if ((!tag.isEndTag()) && (!tag.isEmpty())) {
242  buf += "<b>";
243  }
244  else if (tag.isEndTag()) {
245  buf += "</b><br />";
246  }
247  }
248 
249  // <hi> hi? hi contrast?
250  else if (!strcmp(tag.getName(), "hi")) {
251  SWBuf type = tag.getAttribute("type");
252  if ((!tag.isEndTag()) && (!tag.isEmpty())) {
253  if (type == "bold" || type == "x-b") {
254  buf += "<b> ";
255  u->inBold = true;
256  }
257  else { // all other types
258  buf += "<i> ";
259  u->inBold = false;
260  }
261  }
262  else if (tag.isEndTag()) {
263  if(u->inBold) {
264  buf += "</b>";
265  u->inBold = false;
266  }
267  else
268  buf += "</i>";
269  }
270  else { // empty hi marker
271  // what to do? is this even valid?
272  }
273  }
274 
275  // <q> quote
276  else if (!strcmp(tag.getName(), "q")) {
277  SWBuf type = tag.getAttribute("type");
278  SWBuf who = tag.getAttribute("who");
279  const char *lev = tag.getAttribute("level");
280  int level = (lev) ? atoi(lev) : 1;
281 
282  if ((!tag.isEndTag()) && (!tag.isEmpty())) {
283  /*buf += "{";*/
284 
285  //alternate " and '
286  if (u->osisQToTick)
287  buf += (level % 2) ? '\"' : '\'';
288 
289  if (who == "Jesus") {
290  buf += "<font color=\"red\"> ";
291  }
292  }
293  else if (tag.isEndTag()) {
294  //alternate " and '
295  if (u->osisQToTick)
296  buf += (level % 2) ? '\"' : '\'';
297  //buf += "</font>";
298  }
299  else { // empty quote marker
300  //alternate " and '
301  if (u->osisQToTick)
302  buf += (level % 2) ? '\"' : '\'';
303  }
304  }
305 
306  // <transChange>
307  else if (!strcmp(tag.getName(), "transChange")) {
308  SWBuf type = tag.getAttribute("type");
309 
310  if ((!tag.isEndTag()) && (!tag.isEmpty())) {
311 
312 // just do all transChange tags this way for now
313 // if (type == "supplied")
314  buf += "<i>";
315  }
316  else if (tag.isEndTag()) {
317  buf += "</i>";
318  }
319  else { // empty transChange marker?
320  }
321  }
322 
323  else {
324  return false; // we still didn't handle token
325  }
326  }
327  return true;
328 }
329 
330 
#define SWORD_NAMESPACE_START
Definition: defs.h:39
SWBuf & appendFormatted(const char *format,...)
Definition: swbuf.cpp:81
void setTokenEnd(const char *tokenEnd)
Definition: swbuf.h:47
unsigned long length() const
Definition: swbuf.h:197
virtual const char * getConfigEntry(const char *key) const
Definition: swmodule.cpp:1159
const char * getName() const
Definition: utilxml.h:58
SWText * module
Definition: osis2mod.cpp:105
Definition: utilxml.h:38
#define SWTRY
Definition: defs.h:57
void setTokenCaseSensitive(bool val)
void setEscapeStart(const char *escStart)
bool isEmpty() const
Definition: utilxml.h:60
bool substituteToken(SWBuf &buf, const char *token)
virtual const char * getText() const
Definition: versekey.cpp:1242
void addEscapeStringSubstitute(const char *findString, const char *replaceString)
void setTokenStart(const char *tokenStart)
#define SWCATCH(x)
Definition: defs.h:58
return NULL
Definition: regex.c:7953
const char * c_str() const
Definition: swbuf.h:158
#define SWDYNAMIC_CAST(className, object)
Definition: defs.h:47
const SWKey * key
Definition: swbasicfilter.h:43
const char * getAttribute(const char *attribName, int partNum=-1, char partSplit= '|') const
Definition: utilxml.cpp:230
virtual bool handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData)
Definition: osiscgi.cpp:59
void setEscapeStringCaseSensitive(bool val)
bool isEndTag(const char *eID=0) const
Definition: utilxml.cpp:323
void addTokenSubstitute(const char *findString, const char *replaceString)
MyUserData(const SWModule *module, const SWKey *key)
Definition: osiscgi.cpp:33
OSISCGI()
Definition: osiscgi.cpp:38
void setEscapeEnd(const char *escEnd)
#define SWORD_NAMESPACE_END
Definition: defs.h:40
Definition: swkey.h:77
int getAttributePartCount(const char *attribName, char partSplit= '|') const
Definition: utilxml.cpp:218