[sword-svn] r1946 - in trunk: include src/modules/filters src/utilfuns utilities utilities/diatheke

scribe at crosswire.org scribe at crosswire.org
Sat Jul 15 13:41:30 MST 2006


Author: scribe
Date: 2006-07-15 13:41:24 -0700 (Sat, 15 Jul 2006)
New Revision: 1946

Modified:
   trunk/include/osishtmlhref.h
   trunk/include/osisrtf.h
   trunk/include/osiswebif.h
   trunk/include/utilxml.h
   trunk/src/modules/filters/osishtmlhref.cpp
   trunk/src/modules/filters/osisplain.cpp
   trunk/src/modules/filters/osisrtf.cpp
   trunk/src/modules/filters/osiswebif.cpp
   trunk/src/utilfuns/utilxml.cpp
   trunk/utilities/diatheke/osiscgi.cpp
   trunk/utilities/osis2mod.cpp
Log:
Updated support for more OSIS markup, including q marker (DM Smith)
Basic filter cleanups


Modified: trunk/include/osishtmlhref.h
===================================================================
--- trunk/include/osishtmlhref.h	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/include/osishtmlhref.h	2006-07-15 20:41:24 UTC (rev 1946)
@@ -34,7 +34,12 @@
 	public:
 		bool osisQToTick;
 		bool inBold;
+		bool inQuote;
 		bool inName;
+		bool providesQuote;
+		SWBuf quoteMark;
+		SWBuf wordsOfChristStart;
+		SWBuf wordsOfChristEnd;
 		SWBuf lastTransChange;
 		SWBuf w;
 		SWBuf fn;

Modified: trunk/include/osisrtf.h
===================================================================
--- trunk/include/osisrtf.h	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/include/osisrtf.h	2006-07-15 20:41:24 UTC (rev 1946)
@@ -37,6 +37,8 @@
 		bool BiblicalText;
 		bool inXRefNote;
 		bool inQuote;
+		bool providesQuote;
+		SWBuf quoteMark;
 		SWBuf w;
 		SWBuf version;
 		MyUserData(const SWModule *module, const SWKey *key);

Modified: trunk/include/osiswebif.h
===================================================================
--- trunk/include/osiswebif.h	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/include/osiswebif.h	2006-07-15 20:41:24 UTC (rev 1946)
@@ -34,6 +34,7 @@
 
 protected:
 	virtual bool handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData);
+	virtual BasicFilterUserData *createUserData(const SWModule *module, const SWKey *key);
 public:
 	OSISWEBIF();
 	void setJavascript(bool mode) { javascript = mode; }

Modified: trunk/include/utilxml.h
===================================================================
--- trunk/include/utilxml.h	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/include/utilxml.h	2006-07-15 20:41:24 UTC (rev 1946)
@@ -65,6 +65,8 @@
 		if (!parsed)
 			parse();
 		empty = value;
+		if (value)
+			endTag = false;
 	}
 
 	inline bool isEndTag() const { return endTag; }

Modified: trunk/src/modules/filters/osishtmlhref.cpp
===================================================================
--- trunk/src/modules/filters/osishtmlhref.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/src/modules/filters/osishtmlhref.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -9,8 +9,7 @@
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
+ *   the Free Software Foundation version 2 of the License.                *
  *                                                                         *
  ***************************************************************************/
 
@@ -26,6 +25,9 @@
 
 
 OSISHTMLHREF::MyUserData::MyUserData(const SWModule *module, const SWKey *key) : BasicFilterUserData(module, key) {
+	providesQuote = false;
+	wordsOfChristStart = "<font color=\"red\"> ";
+	wordsOfChristEnd   = "</font> ";
 	if (module) {
 		osisQToTick = ((!module->getConfigEntry("OSISqToTick")) || (strcmp(module->getConfigEntry("OSISqToTick"), "false")));
 		version = module->Name();
@@ -46,18 +48,25 @@
 
 	setEscapeStringCaseSensitive(true);
 
-	addEscapeStringSubstitute("amp",  "&");
-	addEscapeStringSubstitute("apos", "'");
-	addEscapeStringSubstitute("lt",   "<");
-	addEscapeStringSubstitute("gt",   ">");
-	addEscapeStringSubstitute("quot", "\"");
-	
+//   commenting these out.  If someone is sure we shouldn't
+//   convert these since we are outputing to a markup that
+//   recognizes them, then please delete these lines
+//   addEscapeStringSubstitute("amp",  "&");
+//   addEscapeStringSubstitute("apos", "'");
+//   addEscapeStringSubstitute("lt",   "<");
+//   addEscapeStringSubstitute("gt",   ">");
+//   addEscapeStringSubstitute("quot", "\"");
+
 	setTokenCaseSensitive(true);
 	
 	addTokenSubstitute("lg",  "<br />");
 	addTokenSubstitute("/lg", "<br />");
 }
 
+// though this might be slightly slower, possibly causing an extra bool check, this is a renderFilter
+// so speed isn't the absolute highest priority, and this is a very minor possible hit
+static inline void outText(const char *t, SWBuf &o, BasicFilterUserData *u) { if (!u->suspendTextPassThru) o += t; }
+static inline void outText(char t, SWBuf &o, BasicFilterUserData *u) { if (!u->suspendTextPassThru) o += t; }
 
 bool OSISHTMLHREF::handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData) {
   // manually process if it wasn't a simple substitution
@@ -90,14 +99,14 @@
 				if (attrib = tag.getAttribute("xlit")) {
 					val = strchr(attrib, ':');
 					val = (val) ? (val + 1) : attrib;
-					if (!u->suspendTextPassThru)
-						buf.appendFormatted(" %s", val);
+					outText(" ", buf, u);
+					outText(val, buf, u);
 				}
 				if (attrib = tag.getAttribute("gloss")) {
 					val = strchr(attrib, ':');
 					val = (val) ? (val + 1) : attrib;
-					if (!u->suspendTextPassThru)
-						buf.appendFormatted(" %s", val);
+					outText(" ", buf, u);
+					outText(val, buf, u);
 				}
 				if (attrib = tag.getAttribute("lemma")) {
 					int count = tag.getAttributePartCount("lemma", ' ');
@@ -118,11 +127,12 @@
 						//if ((!strcmp(val2, "3588")) && (lastText.length() < 1))
 						//	show = false;
 						//else {
-							if (!u->suspendTextPassThru)
+							if (!u->suspendTextPassThru) {
 								buf.appendFormatted(" <small><em>&lt;<a href=\"passagestudy.jsp?action=showStrongs&type=%s&value=%s\">%s</a>&gt;</em></small> ", 
 										(gh.length()) ? gh.c_str() : "", 
 										URL::encode(val2).c_str(), 
 										val2);
+							}
 						//}
 						
 					} while (++i < count);
@@ -142,19 +152,20 @@
 							const char *val2 = val;
 							if ((*val == 'T') && (strchr("GH", val[1])) && (isdigit(val[2])))
 								val2+=2;
-							if (!u->suspendTextPassThru)
+							if (!u->suspendTextPassThru) {
 								buf.appendFormatted(" <small><em>(<a href=\"passagestudy.jsp?action=showMorph&type=%s&value=%s\">%s</a>)</em></small> ", 
 										URL::encode(tag.getAttribute("morph")).c_str(),
 										URL::encode(val).c_str(), 
 										val2);
+							}
 						} while (++i < count);
 					//}
 				}
 				if (attrib = tag.getAttribute("POS")) {
 					val = strchr(attrib, ':');
 					val = (val) ? (val + 1) : attrib;
-					if (!u->suspendTextPassThru)
-						buf.appendFormatted(" %s", val);
+					outText(" ", buf, u);
+					outText(val, buf, u);
 				}
 
 				/*if (endTag)
@@ -203,17 +214,14 @@
 		// <p> paragraph tag
 		else if (!strcmp(tag.getName(), "p")) {
 			if ((!tag.isEndTag()) && (!tag.isEmpty())) {	// non-empty start tag
-				if (!u->suspendTextPassThru)
-					buf += "<!P><br />";
+				outText("<!P><br />", buf, u);
 			}
 			else if (tag.isEndTag()) {	// end tag
-				if (!u->suspendTextPassThru)
-					buf += "<!/P><br />";
+				outText("<!/P><br />", buf, u);
 				userData->supressAdjacentWhitespace = true;
 			}
 			else {					// empty paragraph break marker
-				if (!u->suspendTextPassThru)
-					buf += "<!P><br />";
+				outText("<!P><br />", buf, u);
 				userData->supressAdjacentWhitespace = true;
 			}
 		}
@@ -221,68 +229,65 @@
 		// <reference> tag
 		else if (!strcmp(tag.getName(), "reference")) {			
 			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				if (!u->suspendTextPassThru)
-					buf += "<a href=\"\">";
+				outText("<a href=\"\">", buf, u);
 			}
 			else if (tag.isEndTag()) {
-				if (!u->suspendTextPassThru)
-					buf += "</a>";
+				outText("</a>", buf, u);
 			}
 		}
 
 		// <l> poetry, etc
 		else if (!strcmp(tag.getName(), "l")) {
-			if (tag.isEmpty()) {
-				if (!u->suspendTextPassThru)
-					buf += "<br />";
+			// end line marker
+			if (tag.getAttribute("eID")) {
+				outText("<br />", buf, u);
 			}
+			// <l/> without eID or sID
+			// Note: this is improper osis. This should be <lb/>
+			else if (tag.isEmpty() && !tag.getAttribute("sID")) {
+				outText("<br />", buf, u);
+			}
+			// end of the line
 			else if (tag.isEndTag()) {
-				if (!u->suspendTextPassThru)
-					buf += "<br />";
+				outText("<br />", buf, u);
 			}
-			else if (tag.getAttribute("sID")) {	// empty line marker
-				if (!u->suspendTextPassThru)
-					buf += "<br />";
-			}
 		}
 
+		// <lb.../>
+		else if (!strcmp(tag.getName(), "lb")) {
+			outText("<br />", buf, u);
+			userData->supressAdjacentWhitespace = true;
+		}
 		// <milestone type="line"/>
 		else if ((!strcmp(tag.getName(), "milestone")) && (tag.getAttribute("type"))) {
 			if(!strcmp(tag.getAttribute("type"), "line")) {
-				if (!u->suspendTextPassThru)
-					buf += "<br />";
-					userData->supressAdjacentWhitespace = true;
+				outText("<br />", buf, u);
+				userData->supressAdjacentWhitespace = true;
 			}
 			else if(!strcmp(tag.getAttribute("type"),"x-p"))  {
-			//	buf += tag.getAttribute("marker");
 				if( tag.getAttribute("marker"))
-					buf += tag.getAttribute("marker");
-				else
-					buf +=  "<!p>";
+					outText(tag.getAttribute("marker"), buf, u);
+				else outText("<!p>", buf, u);
 			}
 		}
 
 		// <title>
 		else if (!strcmp(tag.getName(), "title")) {
 			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				if (!u->suspendTextPassThru)
-					buf += "<b>";
+				outText("<b>", buf, u);
 			}
 			else if (tag.isEndTag()) {
-				if (!u->suspendTextPassThru)
-					buf += "</b><br />";
+				outText("</b><br />", buf, u);
 			}
 		}
 
 		// <catchWord> & <rdg> tags (italicize)
 		else if (!strcmp(tag.getName(), "rdg") || !strcmp(tag.getName(), "catchWord")) {
 			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				if (!u->suspendTextPassThru)
-					buf += "<i>";
+				outText("<i>", buf, u);
 			}
 			else if (tag.isEndTag()) {
-				if (!u->suspendTextPassThru)
-					buf += "</i>";
+				outText("</i>", buf, u);
 			}
 		}
 
@@ -301,11 +306,12 @@
 					char firstChar = *u->lastTextNode.c_str();
 					const char *name = u->lastTextNode.c_str();
 					++name;
-					buf += firstChar;
-					buf += "<font size=\"-1\">";
+					outText(firstChar, buf, u);
+					outText("<font size=\"-1\">", buf, u);
+					
 					for(int i=0;i<strlen(name);i++)
-						buf += toupper(name[i]);
-					buf += "</font>";
+						outText(toupper(name[i]), buf, u);
+					outText("</font>", buf, u);
 					u->inName = false;
 					u->suspendTextPassThru = false;
 				}
@@ -317,25 +323,20 @@
 			SWBuf type = tag.getAttribute("type");
 			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
 				if (type == "b" || type == "x-b") {
-					if (!u->suspendTextPassThru)
-						buf += "<b>";
+					outText("<b>", buf, u);
 					u->inBold = true;
 				}
 				else {	// all other types
-					if (!u->suspendTextPassThru)
-						buf += "<i>";
+					outText("<i>", buf, u);
 					u->inBold = false;
 				}
 			}
 			else if (tag.isEndTag()) {
 				if(u->inBold) {
-					if (!u->suspendTextPassThru)
-						buf += "</b>";
+					outText("</b>", buf, u);
 					u->inBold = false;
 				}
-				else
-					if (!u->suspendTextPassThru)
-						 buf += "</i>";
+				else outText("</i>", buf, u);
 			}
 		}
 
@@ -344,50 +345,88 @@
 			SWBuf type = tag.getAttribute("type");
 			SWBuf who = tag.getAttribute("who");
 			const char *lev = tag.getAttribute("level");
+			const char *mark = tag.getAttribute("marker");
 			int level = (lev) ? atoi(lev) : 1;
 
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				/*buf += "{";*/
+			// open <q> or <q sID... />
+			if ((!tag.isEmpty()) || (tag.getAttribute("sID"))) {
 
+				// Honor the marker attribute, ignoring the osisQToTick
+				u->providesQuote = false;
+				if (mark) {
+					if (*mark) {
+						outText(mark, buf, u);
+					}
+					u->quoteMark = mark;
+					u->providesQuote = true;
+				}
 				//alternate " and '
-				if (u->osisQToTick)
-					if (!u->suspendTextPassThru)
-						buf += (level % 2) ? '\"' : '\'';
+				else if (u->osisQToTick)
+					outText((level % 2) ? '\"' : '\'', buf, u);
 				
-				if (who == "Jesus") {
-					if (!u->suspendTextPassThru)
-						buf += "<font color=\"red\">";
+				if (who == "Jesus" && !u->suspendTextPassThru) {
+					outText(u->wordsOfChristStart, buf, u);
+					u->inQuote = true;
 				}
 			}
-			else if (tag.isEndTag()) {
-				//alternate " and '
-				if (u->osisQToTick)
-					if (!u->suspendTextPassThru)
-						buf += (level % 2) ? '\"' : '\'';
-				//buf += "</font>";
+			// close </q> or <q eID... />
+			else if ((tag.isEndTag()) || (tag.getAttribute("eID"))) {
+				// if we've changed font color, we should put it back
+				if (u->inQuote) {
+					outText(u->wordsOfChristEnd, buf, u);
+					u->inQuote = false;
+				}
+				// first check to see if we've been given an explicit mark
+				if (mark) {
+					if (*mark) {
+						outText(mark, buf, u);
+					}
+				}
+				// next check to see if our opening q provided an explicit mark
+				else if (u->providesQuote) {
+					if (u->quoteMark.length()) {
+						outText(u->quoteMark, buf, u);
+					}
+				}
+				// finally, alternate " and ', if config says we should supply a mark
+				else if (u->osisQToTick)
+					outText((level % 2) ? '\"' : '\'', buf, u);
 			}
-			else {	// empty quote marker
-				//alternate " and '
-				if (u->osisQToTick)
-					if (!u->suspendTextPassThru)
-						buf += (level % 2) ? '\"' : '\'';
+		}
+
+		// <milestone type="cQuote" marker="x"/>
+		else if (!strcmp(tag.getName(), "milestone") && tag.getAttribute("type") && !strcmp(tag.getAttribute("type"), "cQuote")) {
+			const char *mark = tag.getAttribute("marker");
+			const char *lev = tag.getAttribute("level");
+			int level = (lev) ? atoi(lev) : 1;
+
+			// first check to see if we've been given an explicit mark
+			if (mark) {
+				if (*mark) {
+					outText(mark, buf, u);
+				}
 			}
+			// finally, alternate " and ', if config says we should supply a mark
+			else if (u->osisQToTick)
+				outText((level % 2) ? '\"' : '\'', buf, u);
 		}
 
 		// <transChange>
 		else if (!strcmp(tag.getName(), "transChange")) {
-			SWBuf type = tag.getAttribute("type");
-
 			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+				SWBuf type = tag.getAttribute("type");
+				u->lastTransChange = type;
 
-// just do all transChange tags this way for now
-//				if (type == "supplied")
-					if (!u->suspendTextPassThru)
-						buf += "<i>";
+				// just do all transChange tags this way for now
+				if ((type == "added") || (type == "supplied"))
+					outText("<i>", buf, u);
+				else if (type == "tenseChange")
+					buf += "*";
 			}
 			else if (tag.isEndTag()) {
-				if (!u->suspendTextPassThru)
-					buf += "</i>";
+				SWBuf type = u->lastTransChange;
+				if ((type == "added") || (type == "supplied"))
+					outText("</i>", buf, u);
 			}
 			else {	// empty transChange marker?
 			}
@@ -408,11 +447,9 @@
 			filepath += src;
 
 // we do this because BibleCS looks for this EXACT format for an image tag
-				if (!u->suspendTextPassThru) {
-					buf+="<image src=\"";
-					buf+=filepath;
-					buf+="\" />";
-				}
+			outText("<image src=\"", buf, u);
+			outText(filepath, buf, u);
+			outText("\" />", buf, u);
 		}
 
 		else {

Modified: trunk/src/modules/filters/osisplain.cpp
===================================================================
--- trunk/src/modules/filters/osisplain.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/src/modules/filters/osisplain.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -155,6 +155,12 @@
 				buf.append('\n');
 		}
 
+                // <lb .../>
+                else if (!strncmp(token, "lb", 2)) {
+			userData->supressAdjacentWhitespace = true;
+			buf.append('\n');
+		}
+
                 // <milestone type="line"/>
                 else if (!strncmp(token, "milestone", 9)) {
 			const char* type = strstr(token+10, "type=\"");

Modified: trunk/src/modules/filters/osisrtf.cpp
===================================================================
--- trunk/src/modules/filters/osisrtf.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/src/modules/filters/osisrtf.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -9,8 +9,7 @@
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
+ *   the Free Software Foundation version 2 of the License.                *
  *                                                                         *
  ***************************************************************************/
 
@@ -26,9 +25,10 @@
 
 
 OSISRTF::MyUserData::MyUserData(const SWModule *module, const SWKey *key) : BasicFilterUserData(module, key) {
-	inXRefNote = false;
-	BiblicalText = false;
-	inQuote = false;
+	inXRefNote    = false;
+	BiblicalText  = false;
+	inQuote       = false;
+	providesQuote = false;
 	if (module) {
 		version = module->Name();
 		BiblicalText = (!strcmp(module->Type(), "Biblical Texts"));
@@ -203,19 +203,23 @@
 
 		// <l> poetry
 		else if (!strcmp(tag.getName(), "l")) {
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				buf += "";
+			// end line marker
+			if (tag.getAttribute("eID")) {
+				buf += "{\\par}";
 			}
-			else if (tag.isEndTag()) {
+			// <l/> without eID or sID
+			// Note: this is improper osis. This should be <lb/>
+			else if (tag.isEmpty() && !tag.getAttribute("sID")) {
 				buf += "{\\par}";
 			}
-			else if (tag.getAttribute("sID")) {	// empty line marker
+			// end of the line
+			else if (tag.isEndTag()) {
 				buf += "{\\par}";
 			}
 		}
 
-		// <milestone type="line"/>
-		else if ((!strcmp(tag.getName(), "milestone")) && (tag.getAttribute("type")) && (!strcmp(tag.getAttribute("type"), "line"))) {
+		// <milestone type="line"/> or <lb.../>
+		else if ((!strcmp(tag.getName(), "lb")) || ((!strcmp(tag.getName(), "milestone")) && (tag.getAttribute("type")) && (!strcmp(tag.getAttribute("type"), "line")))) {
 			buf += "{\\par}";
 			userData->supressAdjacentWhitespace = true;
 		}
@@ -259,39 +263,70 @@
 			SWBuf type = tag.getAttribute("type");
 			SWBuf who = tag.getAttribute("who");
 			const char *lev = tag.getAttribute("level");
+			const char *mark = tag.getAttribute("marker");
 			int level = (lev) ? atoi(lev) : 1;
 
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				buf += "{";
+			// open <q> or <q sID... />
+			if ((!tag.isEmpty()) || (tag.getAttribute("sID"))) {
 
+				// Honor the marker attribute, ignoring the osisQToTick
+				u->providesQuote = false;
+				if (mark) {
+					if (*mark) {
+						buf += mark;
+					}
+					u->quoteMark = mark;
+					u->providesQuote = true;
+				}
 				//alternate " and '
-				if (u->osisQToTick)
+				else if (u->osisQToTick)
 					buf += (level % 2) ? '\"' : '\'';
 
-				if (who == "Jesus")
+				if (who == "Jesus") {
 					buf += "\\cf6 ";
+					u->inQuote = true;
+				}
 			}
-			else if (tag.isEndTag()) {
-				//alternate " and '
-				if (u->osisQToTick)
+			// close </q> or <q eID... />
+			else if ((tag.isEndTag()) || (tag.getAttribute("eID"))) {
+				// if we've changed color, we should put it back
+				if (u->inQuote) {
+					buf += "\\cf0 ";
+					u->inQuote = false;
+				}
+				// first check to see if we've been given an explicit mark
+				if (mark) {
+					if (*mark) {
+						buf += mark;
+					}
+				}
+				// next check to see if our opening q provided an explicit mark
+				else if (u->providesQuote) {
+					if (u->quoteMark.length()) {
+						buf += u->quoteMark;
+					}
+				}
+				// finally, alternate " and ', if config says we should supply a mark
+				else if (u->osisQToTick)
 					buf += (level % 2) ? '\"' : '\'';
-				buf += "}";
 			}
-			else {	// empty quote marker
-				//alternate " and '
-				if (u->osisQToTick)
-					buf += (level % 2) ? '\"' : '\'';
-				if (!u->inQuote) {
-					if (who == "Jesus")
-						buf += "\\cf6 ";
-					u->inQuote = 1;
+		}
+
+		// <milestone type="cQuote" marker="x"/>
+		else if (!strcmp(tag.getName(), "milestone") && tag.getAttribute("type") && !strcmp(tag.getAttribute("type"), "cQuote")) {
+			const char *mark = tag.getAttribute("marker");
+			const char *lev = tag.getAttribute("level");
+			int level = (lev) ? atoi(lev) : 1;
+
+			// first check to see if we've been given an explicit mark
+			if (mark) {
+				if (*mark) {
+					buf += mark;
 				}
-				else {
-					if (who == "Jesus")
-						buf += "\\cf0 ";
-					u->inQuote = 0;
-				}
 			}
+			// finally, alternate " and ', if config says we should supply a mark
+			else if (u->osisQToTick)
+				buf += (level % 2) ? '\"' : '\'';
 		}
 
 		// <transChange>

Modified: trunk/src/modules/filters/osiswebif.cpp
===================================================================
--- trunk/src/modules/filters/osiswebif.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/src/modules/filters/osiswebif.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -30,6 +30,15 @@
 OSISWEBIF::OSISWEBIF() : baseURL(""), passageStudyURL(baseURL + "passagestudy.jsp"), javascript(false) {
 }
 
+
+BasicFilterUserData *OSISWEBIF::createUserData(const SWModule *module, const SWKey *key) {
+	MyUserData *u = new MyUserData(module, key);
+	u->wordsOfChristStart = "<span class=\"wordsOfJesus\"> ";
+	u->wordsOfChristEnd   = "</span> ";
+	return u;
+}
+
+
 bool OSISWEBIF::handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData) {
   // manually process if it wasn't a simple substitution
 	if (!substituteToken(buf, token)) {
@@ -158,96 +167,6 @@
 			}
 		}
 
-		// <catchWord> & <rdg> tags (italicize)
-		else if (!strcmp(tag.getName(), "rdg") || !strcmp(tag.getName(), "catchWord")) {
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				if (!u->suspendTextPassThru)
-					buf += "<i>";
-			}
-			else if (tag.isEndTag()) {
-				if (!u->suspendTextPassThru)
-					buf += "</i>";
-			}
-		}
-
-                // <hi> text highlighting
-		else if (!strcmp(tag.getName(), "hi")) {
-			SWBuf type = tag.getAttribute("type");
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				if (type == "b" || type == "x-b") {
-					if (!u->suspendTextPassThru)
-						buf += "<b>";
-					u->inBold = true;
-				}
-				else {	// all other types
-					if (!u->suspendTextPassThru)
-						buf += "<i>";
-					u->inBold = false;
-				}
-			}
-			else if (tag.isEndTag()) {
-				if(u->inBold) {
-					if (!u->suspendTextPassThru)
-						buf += "</b>";
-				}
-				else {
-					if (!u->suspendTextPassThru)
-						 buf += "</i>";
-				}
-			}
-		}
-
-		// <q> quote
-		else if (!strcmp(tag.getName(), "q")) {
-			SWBuf type = tag.getAttribute("type");
-			SWBuf who = tag.getAttribute("who");
-			const char *lev = tag.getAttribute("level");
-			int level = (lev) ? atoi(lev) : 1;
-			
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				/*buf += "{";*/
-
-				//alternate " and '
-				if (u->osisQToTick)
-					buf += (level % 2) ? '\"' : '\'';
-				
-				if (who == "Jesus") {
-					buf += "<span class=\"wordsOfJesus\"> ";
-				}
-			}
-			else if (tag.isEndTag()) {
-				//alternate " and '
-				if (u->osisQToTick)
-					buf += (level % 2) ? '\"' : '\'';
-				buf += "</span>";
-			}
-			else {	// empty quote marker
-				//alternate " and '
-				if (u->osisQToTick)
-					buf += (level % 2) ? '\"' : '\'';
-			}
-		}
-
-		// <transChange>
-		else if (!strcmp(tag.getName(), "transChange")) {
-			if ((!tag.isEndTag()) && (!tag.isEmpty())) {
-				SWBuf type = tag.getAttribute("type");
-				u->lastTransChange = type;
-
-				// just do all transChange tags this way for now
-				if ((type == "added") || (type == "supplied"))
-					buf += "<i>";
-				else if (type == "tenseChange")
-					buf += "*";
-			}
-			else if (tag.isEndTag()) {
-				SWBuf type = u->lastTransChange;
-				if ((type == "added") || (type == "supplied"))
-					buf += "</i>";
-			}
-			else {	// empty transChange marker?
-			}
-		}
 		// ok to leave these in
 		else if (!strcmp(tag.getName(), "div")) {
 			buf += tag;
@@ -258,6 +177,13 @@
 		else if (!strcmp(tag.getName(), "br")) {
 			buf += tag;
 		}
+
+		// handled appropriately in base class
+		// <catchWord> & <rdg> tags (italicize)
+		// <hi> text highlighting
+		// <q> quote
+		// <milestone type="cQuote" marker="x"/>
+		// <transChange>
 		else {
 			return OSISHTMLHREF::handleToken(buf, token, userData);
 		}

Modified: trunk/src/utilfuns/utilxml.cpp
===================================================================
--- trunk/src/utilfuns/utilxml.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/src/utilfuns/utilxml.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -41,7 +41,10 @@
 			for (; ((buf[i]) && (!isalpha(buf[i]))); i++);
 			if (buf[i]) {		// we have an attribute name
 				start = i;
+				// Deprecated: check for following whitespacee
+				// Should be: for (; (buf[i] && buf[i] != '='; i++);
 				for (; ((buf[i]) && (!strchr(" =", buf[i]))); i++);
+
 				if (i-start) {
 					if (name)
 						delete [] name;
@@ -49,23 +52,47 @@
 					strncpy(name, buf+start, i-start);
 					name[i-start] = 0;
 				}
-				for (; ((buf[i]) && (strchr(" =\"\'", buf[i]))); i++);
+
+				// The following does not allow for empty attributes
+				//for (; ((buf[i]) && (strchr(" =\"\'", buf[i]))); i++);
+
+				// skip space preceding the = sign
+				// Deprecated: this is not part of the xml spec
+				for (; buf[i] == ' '; i++) ;
+
+				// skip the = sign
+				i++;
+
+				// skip space following the = sign
+				// Deprecated: this is not part of the xml spec
+				for (; buf[i] == ' '; i++) ;
+
+				// remember and skip the quote sign
+				char quoteChar = buf[i];
+				i++;
+
 				if (buf[i]) {	// we have attribute value
 					start = i;
-					for (; ((buf[i]) && (buf[i] != '\"') && (buf[i] != '\'')); i++);
-					if (i-start) {
+					// Skip until matching quote character
+					for (; ((buf[i]) && (buf[i] != quoteChar)); i++);
+
+					// Allow for empty quotes
+					//if (i-start) {
 						if (value)
 							delete [] value;
 						value = new char [ (i-start) + 1 ];
-						strncpy(value, buf+start, i-start);
+						if (i-start) {
+							strncpy(value, buf+start, i-start);
+						}
 						value[i-start] = 0;
 						attributes[name] = value;
-					}
+					//}
 				}
 			}
 		}
-		if (!buf[i])
-			break;
+		if (buf[i])
+			buf[i] = ' ';
+		else break;
 	}
 	for (;i;i--) {
 		if (buf[i] == '/')

Modified: trunk/utilities/diatheke/osiscgi.cpp
===================================================================
--- trunk/utilities/diatheke/osiscgi.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/utilities/diatheke/osiscgi.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -226,8 +226,8 @@
 			}
 		}
 
-		// <milestone type="line"/>
-		else if ((!strcmp(tag.getName(), "milestone")) && (tag.getAttribute("type")) && (!strcmp(tag.getAttribute("type"), "line"))) {
+		// <milestone type="line"/> or <lb.../>
+		else if ((!strcmp(tag.getName(), "lb")) || ((!strcmp(tag.getName(), "milestone")) && (tag.getAttribute("type")) && (!strcmp(tag.getAttribute("type"), "line")))) {
 			buf += "<br />";
 			userData->supressAdjacentWhitespace = true;
 		}

Modified: trunk/utilities/osis2mod.cpp
===================================================================
--- trunk/utilities/osis2mod.cpp	2006-07-10 20:24:28 UTC (rev 1945)
+++ trunk/utilities/osis2mod.cpp	2006-07-15 20:41:24 UTC (rev 1946)
@@ -32,6 +32,7 @@
 
 SWText *module = 0;
 VerseKey *currentVerse = 0;
+char activeOsisID[255];
 
 
 // remove subverse elements from osisIDs
@@ -58,7 +59,7 @@
 	test = buf;
 
 	if (vk.Testament() && vk.Book() && vk.Chapter() && vk.Verse()) { // if we're not a heading
-//		std::cerr << (const char*)vk << " == "  << (const char*)test << std::endl;
+//		cout << (const char*)vk << " == "  << (const char*)test << endl;
 		return (vk == test);
 	}
 	else return true;	// no check if we're a heading... Probably bad.
@@ -79,28 +80,57 @@
 }
 
 
-void writeEntry(VerseKey &key, SWBuf &text, bool suppressOutput = false) {
-//	cout << "Verse: " << key << "\n";
-//	cout << "TEXT: " << text << "\n\n";
+void writeEntry(VerseKey &key, SWBuf &text, bool force = false) {
+	static SWBuf activeVerseText;
+        char keyOsisID[255];
+	strcpy(keyOsisID, key.getOSISRef());
+
+	// set keyOsisID to anything that an osisID cannot be.
+	if (force) {
+		strcpy(keyOsisID, "-force");
+	}
+
+	static VerseKey lastKey;
+	lastKey.AutoNormalize(0);
+	lastKey.Headings(1);
+
 	VerseKey saveKey;
 	saveKey.AutoNormalize(0);
 	saveKey.Headings(1);
 	saveKey = key;
 
-	if (!isKJVRef(key)) {
-		makeKJVRef(key);
-	}
+	// If we have seen a verse and the supplied one is different then we output the collected one.
+	if (*activeOsisID && strcmp(activeOsisID, keyOsisID)) {
 
-	SWBuf currentText = module->getRawEntry();
-	if (currentText.length()) {
-		if (!suppressOutput) {
-			cout << "Appending entry: " << key << endl;
+		key = lastKey;
+
+		if (!isKJVRef(key)) {
+			makeKJVRef(key);
 		}
-		text = currentText + " " + text;
+
+		SWBuf currentText = module->getRawEntry();
+		if (currentText.length()) {
+			cout << "Appending entry: " << key.getOSISRef() << ": " << activeVerseText << endl;
+			activeVerseText = currentText + " " + activeVerseText;
+		}
+
+//		cout << "Write: " << activeOsisID << ":" << key.getOSISRef() << ": " << activeVerseText << endl;
+
+		module->setEntry(activeVerseText);
+		activeVerseText = "";
 	}
-	module->setEntry(text);
 
+	if (activeVerseText.length()) {
+		activeVerseText += " ";
+		activeVerseText += text;
+	}
+	else {
+		activeVerseText = text;
+	}
+
 	key = saveKey;
+	lastKey = key;
+	strcpy(activeOsisID, keyOsisID);
 }
 
 
@@ -138,7 +168,7 @@
 	static bool inBook = false;
 	static bool inChapter = false;
 	static bool inVerse = true;
-	
+
 	static SWBuf header = "";
 
 	// Used to remember titles that need to be handle specially
@@ -175,6 +205,7 @@
 		lastTitle = "";
 		inTitle = true;
 		tagStack.push(token);
+//		cout << "push " << token->getName() << endl;
 		titleDepth = tagStack.size();
 		return false; 
 	}
@@ -183,10 +214,12 @@
 		lastTitle.append(text.c_str() + titleOffset); //<title ...> up to the end </title>
 		lastTitle.append(*token); //</title>
 
-// 		printf("lastTitle:	%s\n", lastTitle.c_str());
-// 		printf("text-lastTitle:	%s\n", text.c_str()+titleOffset);
+// 		cout << "lastTitle:      " << lastTitle.c_str() << endl;
+// 		cout << "text-lastTitle: " << text.c_str()+titleOffset << endl;
+//		cout << "text:           " << text.c_str() << endl;
 		inTitle = false;
 		titleDepth = 0;
+//		cout << "pop " << tagStack.top()->getName() << endl;
 		tagStack.pop();
 		return false; // don't add </title> to the text itself
 	}
@@ -200,11 +233,12 @@
 		// Remember non-empty start tags
 		if (!token->isEmpty()) {
 			tagStack.push(token);
+//			cout << "push " << token->getName() << endl;
 		}
 
 		//-- WITH OSIS ID -------------------------------------------------------------------------
 		if (token->getAttribute("osisID")) {
-	
+
 			// BOOK START
 			if ((!strcmp(tokenName, "div")) && (!strcmp(typeAttr, "book"))) {
 				inVerse = false;
@@ -248,7 +282,7 @@
 				text = "";
 				chapterDepth = tagStack.size();
 				verseDepth = 0;
-				
+
 				return true;
 			}
 
@@ -256,29 +290,24 @@
 			else if (!strcmp(tokenName, "verse")) {
 				inVerse = true;
 				if (inChapterHeader) {
+					SWBuf heading = text;
+
 					//make sure we don't insert the preverse title which belongs to the first verse of this chapter!
 					// Did we have a preverse title?
 					if (lastTitle.length())
 					{
 						//Was the preVerse title in the header (error if not)?
-						const char* header = text.c_str();
+						const char* header = heading.c_str();
 						const char* preVerse = strstr(header, lastTitle);
 						if (preVerse) {
 							if (preVerse == header) {
-								; // do nothing
+								heading = ""; // do nothing
 							}
 							else {
-								int preVerseLen = strlen(preVerse);
-								int headerLen = strlen(header);
-								// Was it the last thing?
-								if (header == preVerseLen + preVerse - headerLen) {
-									// Remove it from the end of the header.
-									text.setSize(headerLen - preVerseLen);
-								}
-								// It was not the last thing so it cannot be preVerse
-								else {
-									lastTitle = "";
-								}
+								// remove everything before the title from the beginning.
+								text = preVerse;
+								// Remove text from the end of the header.
+								heading.setSize(preVerse - header);
 							}
 						}
 						else {
@@ -286,10 +315,11 @@
 						}
 					}
 
-//					cout << "CHAPTER HEADING "<< text.c_str() << endl;
-					writeEntry(*currentVerse, text);
-			
-					text = "";
+					if (heading.length()) {
+//						cout << "CHAPTER HEADING "<< heading.c_str() << endl;
+						writeEntry(*currentVerse, heading);
+					}
+
 					inChapterHeader = false;
 				}
 
@@ -318,6 +348,26 @@
 				return true;
 			}
 		}
+		// Handle stuff between the verses
+		// Whitespace producing empty tokens are appended to prior entry
+		// Also the quote
+		// This is a hack to get ESV to work
+		else if (!inTitle && !inVerse && token->isEmpty()) { // && !inBookHeader && !inChapterHeader) {
+			if (!strcmp(tokenName, "p") ||
+					!strcmp(tokenName, "div") ||
+					!strcmp(tokenName, "q")  ||
+					!strcmp(tokenName, "l") ||
+					!strcmp(tokenName, "lb") ||
+					!strcmp(tokenName, "lg")
+					) {
+//					if (token) {
+//						cout << "start token " << *token << ":" << text.c_str() << endl;
+//					}
+				SWBuf tmp = token->toString();
+				writeEntry(*currentVerse, tmp);
+				return true;
+			}
+		}
 	}
 
 //-- END TAG ---------------------------------------------------------------------------------------------
@@ -329,15 +379,19 @@
 			exit(1);
 		}
 
-		XMLTag *topToken = tagStack.top();
-		tagDepth = tagStack.size();
-		tagStack.pop();
+		XMLTag *topToken = 0;
+		if (!token->isEmpty()) {
+			topToken = tagStack.top();
+			tagDepth = tagStack.size();
+//			cout << "pop " << topToken->getName() << endl;
+			tagStack.pop();
 
-		if (strcmp(topToken->getName(), tokenName)) {
-			cout << "Expected " << topToken->getName() << " found " << tokenName << endl;
-			exit(1);
+			if (strcmp(topToken->getName(), tokenName)) {
+				cout << "Error: " << *currentVerse << ": Expected " << topToken->getName() << " found " << tokenName << endl;
+				exit(1);
+			}
 		}
-		
+
 		// VERSE END
 		if (!strcmp(tokenName, "verse")) {
 			inVerse = false;
@@ -349,11 +403,11 @@
 			if (lastTitle.length()) {
 				const char* end = strchr(lastTitle, '>');
 //				cout << lastTitle << endl;
-//	 			printf("length=%d, tag; %s\n", end+1 - lastTitle.c_str(), lastTitle.c_str());
+//	 			cout << "length=" << int(end+1 - lastTitle.c_str()) << ", tag:" << lastTitle.c_str() << endl;
 
 				SWBuf titleTagText;
 				titleTagText.append(lastTitle.c_str(), end+1 - lastTitle.c_str());
-//				printf("tagText: %s\n", titleTagText.c_str());
+//				cout << "tagText: " << titleTagText.c_str() << endl;;
 
 				XMLTag titleTag(titleTagText);
 				titleTag.setAttribute("type", "section");
@@ -367,7 +421,7 @@
 					temp.append(pos+lastTitle.length());
 					text = temp;
 				}
-			
+
 				//if a title was already inserted at the beginning insert this one after that first title
 				int titlePos = 0;
 				if (!strncmp(text.c_str(),"<title ",7)) {
@@ -402,7 +456,8 @@
 			verseDepth = 0;
 			return true;
 		}
-		else if (!inVerse) {
+		else if (!inTitle && !inVerse && !inBookHeader && !inChapterHeader) {
+//			cout << "End tag not in verse: " << tokenName << "(" << tagDepth << "," << chapterDepth << "," << bookDepth << ")" << endl;
 			// Is this the end of a chapter.
 			if (tagDepth == chapterDepth && (!strcmp(tokenName, "div") || !strcmp(tokenName, "chapter"))) {
 				chapterDepth = 0;
@@ -412,6 +467,7 @@
 			}
 			// Or is it the end of a book
 			else if (tagDepth == bookDepth && (!strcmp(tokenName, "div"))) {
+//				cout << "Saw an end div: " << *topToken << endl;
 				bookDepth = 0;
 				chapterDepth = 0;
 				verseDepth = 0;
@@ -421,13 +477,17 @@
 			// OTHER MISC END TAGS WHEN !INVERSE
 			// Test that is between verses, or after the last is appended to the preceeding verse.
 			else if (!strcmp(tokenName, "p") ||
-					 !strcmp(tokenName, "div") ||
-					 !strcmp(tokenName, "q")  ||
-					 !strcmp(tokenName, "l") ||
-					 !strcmp(tokenName, "lg")
-					  ) {
+					!strcmp(tokenName, "div") ||
+					!strcmp(tokenName, "q")  ||
+					!strcmp(tokenName, "l") ||
+					!strcmp(tokenName, "lb") ||
+					!strcmp(tokenName, "lg")
+					) {
+//				if (topToken) {
+//					cout << "start token " << *topToken << endl;
+//				}
 				text.append(*token);
-				writeEntry(*currentVerse, text, true);
+				writeEntry(*currentVerse, text);
 				text = "";
 				return true;
 			}
@@ -436,6 +496,50 @@
 	return false;
 }
 
+XMLTag* transform(XMLTag* t) {
+	static std::stack<XMLTag*> tagStack;
+	static int sID = 1;
+	char buf[11];
+
+	// Support simplification transformations
+	if (!t->isEmpty()) {
+		if (!t->isEndTag()) {
+			tagStack.push(t);
+			// Transform <q> into <q sID=""/> except for <q who="Jesus">
+			if ((!strcmp(t->getName(), "q")) && (!t->getAttribute("who") || strcmp(t->getAttribute("who"), "Jesus"))) {
+				t->setEmpty(true);
+				sprintf(buf, "q%d", sID++);
+				t->setAttribute("sID", buf);
+			}
+
+			// Transform <p> into <lb type="x-begin-paragraph"/>
+			else if (!strcmp(t->getName(), "p")) {
+				// note there is no process that should care about type, it is there for reversability
+				t->setText("<lb type=\"x-begin-paragraph\" />");
+			}
+		}
+		else {
+			XMLTag *topToken = tagStack.top();
+			tagStack.pop();
+
+			// If we have found an end tag for a <q> that was transformed then transform this one as well.
+			if ((!strcmp(t->getName(), "q")) && (!strcmp(topToken->getName(), "q")) && (!topToken->getAttribute("who") || strcmp(topToken->getAttribute("who"), "Jesus"))) {
+				// make this a clone of the start tag with sID changed to eID
+				*t = *topToken;
+				t->setAttribute("eID", t->getAttribute("sID"));
+				t->setAttribute("sID", 0);
+			}
+
+			// Look for paragraph tags.
+			// If we have found an end tag for a <p> that was transformed then transform this as well.
+			else if ((!strcmp(t->getName(), "p")) && (!strcmp(topToken->getName(), "lb"))) {
+				t->setText("<lb type=\"x-end-paragraph\" />");
+			}
+		}
+	}
+	return t;
+}
+
 int main(int argc, char **argv) {
 
 	// Let's test our command line arguments
@@ -454,8 +558,8 @@
 	string cipherKey = "";
 	SWCompress *compressor = 0;
 // 	SWModule *outModule    = 0;
-	
 
+
 	if (argc > 4) {
 		compType = atoi(argv[4]);
 		if (argc > 5) {
@@ -472,8 +576,8 @@
 		case 2: compressor = new ZipCompress(); break;
 	}
 
-//	cerr << "path: " << argv[1] << " osisDoc: " << argv[2] << " create: " << argv[3] << " compressType: " << compType << " blockType: " << iType << " cipherKey: " << cipherKey.c_str() << "\n";
-//	cerr << "";
+//	cout << "path: " << argv[1] << " osisDoc: " << argv[2] << " create: " << argv[3] << " compressType: " << compType << " blockType: " << iType << " cipherKey: " << cipherKey.c_str() << "\n";
+//	cout << "";
 //	exit(-3);
 
 
@@ -498,7 +602,7 @@
 		fprintf(stderr, "error: %s: couldn't open input file: %s \n", argv[0], argv[2]);
 		exit(-2);
 	}
-	
+
 	// Do some initialization stuff
 	SWBuf buffer;
 
@@ -521,8 +625,8 @@
 		fprintf(stderr, "The module is not writable. Writing text to it will not work.\nExiting.\n" );
 		exit(-1);
 	}
-	
 
+	activeOsisID[0] = '\0';
 
 	currentVerse = new VerseKey();
 	currentVerse->AutoNormalize(0);
@@ -554,8 +658,9 @@
 				if ((isalpha(token[1])) || (isalpha(token[2]))) {
 					//cout << "Handle:" << token.c_str() << endl;
 					XMLTag *t = new XMLTag(token.c_str());
-					if (!handleToken(text, t)) {
-						text.append(token);
+
+					if (!handleToken(text, transform(t))) {
+						text.append(*t);
 					}
 				}
 				continue;
@@ -566,10 +671,14 @@
 			else	
 				text.append(*from);
 		}
-		
+
 		if (intoken)
 			token.append("\n");
 	}
+
+	// Force the last entry from the buffer.
+	text = "";
+	writeEntry(*currentVerse, text, true);
 	delete module;
 	delete currentVerse;
 	if (cipherFilter)



More information about the sword-cvs mailing list