diff options
Diffstat (limited to 'src/keys/versekey.cpp')
-rw-r--r-- | src/keys/versekey.cpp | 1193 |
1 files changed, 636 insertions, 557 deletions
diff --git a/src/keys/versekey.cpp b/src/keys/versekey.cpp index cb7bbfc..9c50a04 100644 --- a/src/keys/versekey.cpp +++ b/src/keys/versekey.cpp @@ -1,7 +1,24 @@ /****************************************************************************** * VerseKey.cpp - code for class 'VerseKey'- a standard Biblical verse key + * + * + * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org) + * CrossWire Bible Society + * P. O. Box 2528 + * Tempe, AZ 85280-2528 + * + * 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 version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * */ + #include <swmacs.h> #include <stdio.h> #include <fcntl.h> @@ -13,9 +30,9 @@ #include <swkey.h> #include <swlog.h> #include <versekey.h> -#include <localemgr.h> #include <swlocale.h> #include <roman.h> +#include <versemgr.h> SWORD_NAMESPACE_START @@ -26,23 +43,15 @@ SWClass VerseKey::classdef(classes); * Initialize static members of VerseKey */ -#include <canon.h> // Initialize static members of canonical books structure - -struct sbook *VerseKey::builtin_books[2] = {0,0}; -const char VerseKey::builtin_BMAX[2] = {39, 27}; -long *VerseKey::offsets[2][2] = {{VerseKey::otbks, VerseKey::otcps}, {VerseKey::ntbks, VerseKey::ntcps}}; int VerseKey::instance = 0; -VerseKey::LocaleCache VerseKey::localeCache; /****************************************************************************** * VerseKey::init - initializes instance of VerseKey */ -void VerseKey::init() { +void VerseKey::init(const char *v11n) { myclass = &classdef; - if (!instance) - initstatics(); instance++; autonorm = 1; // default auto normalization to true @@ -50,13 +59,15 @@ void VerseKey::init() { upperBound = 0; lowerBound = 0; boundSet = false; - testament = 0; - book = 0; - chapter = 0; - verse = 0; - locale = 0; - - setLocale(LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName()); + testament = 1; + book = 1; + chapter = 1; + verse = 1; + suffix = 0; + tmpClone = 0; + refSys = 0; + + setVersificationSystem(v11n); } /****************************************************************************** @@ -104,6 +115,57 @@ VerseKey::VerseKey(VerseKey const &k) : SWKey(k) /****************************************************************************** + * VerseKey::setFromOther - Positions this VerseKey to another VerseKey + */ + +void VerseKey::setFromOther(const VerseKey &ikey) { + if (refSys == ikey.refSys) { + testament = ikey.Testament(); + book = ikey.Book(); + chapter = ikey.Chapter(); + verse = ikey.Verse(); + suffix = ikey.getSuffix(); + } + // Here is where we will do v11n system conversions in the future + // when we have a conversion mechanism (Ben Morgan has started + // thinking about this) + else { + // For now, this is the best we can do + setText(ikey.getText()); + } +} + + +void VerseKey::positionFrom(const SWKey &ikey) { + error = 0; + const SWKey *fromKey = &ikey; + ListKey *tryList = SWDYNAMIC_CAST(ListKey, fromKey); + if (tryList) { + SWKey *k = tryList->getElement(); + if (k) fromKey = k; + } + VerseKey *tryVerse = SWDYNAMIC_CAST(VerseKey, fromKey); + if (tryVerse) { + setFromOther(*tryVerse); + } + else { + SWKey::positionFrom(*fromKey); + parse(); + } + + // should we always perform bounds checks? Tried but seems to cause infinite recursion + if (_compare(UpperBound()) > 0) { + setFromOther(UpperBound()); + error = KEYERR_OUTOFBOUNDS; + } + if (_compare(LowerBound()) < 0) { + setFromOther(LowerBound()); + error = KEYERR_OUTOFBOUNDS; + } +} + + +/****************************************************************************** * VerseKey::copyFrom - Equates this VerseKey to another VerseKey */ @@ -114,6 +176,9 @@ void VerseKey::copyFrom(const VerseKey &ikey) { book = ikey.Book(); chapter = ikey.Chapter(); verse = ikey.Verse(); + suffix = ikey.getSuffix(); + setLocale(ikey.getLocale()); + setVersificationSystem(ikey.getVersificationSystem()); if (ikey.isBoundSet()) { LowerBound(ikey.LowerBound()); UpperBound(ikey.UpperBound()); @@ -145,11 +210,19 @@ void VerseKey::copyFrom(const SWKey &ikey) { } -VerseKey::VerseKey(const char *min, const char *max) : SWKey() +VerseKey::VerseKey(const char *min, const char *max, const char *v11n) : SWKey() { - init(); - LowerBound(min); - UpperBound(max); + init(v11n); + ListKey tmpListKey = ParseVerseList(min); + if (tmpListKey.Count()) { + VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement(0)); + LowerBound(*newElement); + } + tmpListKey = ParseVerseList(max, min, true); + if (tmpListKey.Count()) { + VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement(0)); + UpperBound((newElement->isBoundSet())?newElement->UpperBound():*newElement); + } setPosition(TOP); } @@ -167,117 +240,33 @@ SWKey *VerseKey::clone() const */ VerseKey::~VerseKey() { - if (upperBound) - delete upperBound; - if (lowerBound) - delete lowerBound; - if (locale) - delete [] locale; + + delete tmpClone; --instance; } -void VerseKey::setLocale(const char *name) { - char *BMAX; - struct sbook **lbooks; - bool useCache = false; +void VerseKey::setVersificationSystem(const char *name) { + const VerseMgr::System *newRefSys = VerseMgr::getSystemVerseMgr()->getVersificationSystem(name); + // TODO: cheese, but what should we do if requested v11n system isn't found? + if (!newRefSys) newRefSys = VerseMgr::getSystemVerseMgr()->getVersificationSystem("KJV"); + if (refSys != newRefSys) { + refSys = newRefSys; + BMAX[0] = refSys->getBMAX()[0]; + BMAX[1] = refSys->getBMAX()[1]; - if (localeCache.name) - useCache = (!strcmp(localeCache.name, name)); - - if (!useCache) { // if we're setting params for a new locale - stdstr(&(localeCache.name), name); - localeCache.abbrevsCnt = 0; - } - - SWLocale *locale = (useCache) ? localeCache.locale : LocaleMgr::getSystemLocaleMgr()->getLocale(name); - localeCache.locale = locale; - - if (locale) { - locale->getBooks(&BMAX, &lbooks); - setBooks(BMAX, lbooks); - setBookAbbrevs(locale->getBookAbbrevs(), localeCache.abbrevsCnt); - localeCache.abbrevsCnt = abbrevsCnt; + // TODO: adjust bounds for versificaion system ??? + // TODO: when we have mapping done, rethink this + //necessary as our bounds might not mean anything in the new v11n system + ClearBounds(); } - else { - setBooks(builtin_BMAX, builtin_books); - setBookAbbrevs(builtin_abbrevs, localeCache.abbrevsCnt); - localeCache.abbrevsCnt = abbrevsCnt; - } - stdstr(&(this->locale), localeCache.name); - - if (lowerBound) - LowerBound().setLocale(name); - if (upperBound) - UpperBound().setLocale(name); -} - -void VerseKey::setBooks(const char *iBMAX, struct sbook **ibooks) { - BMAX = iBMAX; - books = ibooks; -} - -void VerseKey::setBookAbbrevs(const struct abbrev *bookAbbrevs, unsigned int size) { - abbrevs = bookAbbrevs; - if (!size) { - for (abbrevsCnt = 0; *abbrevs[abbrevsCnt].ab; abbrevsCnt++) { - /* - if (strcmp(abbrevs[abbrevsCnt-1].ab, abbrevs[abbrevsCnt].ab) > 0) { - fprintf(stderr, "ERROR: book abbreviation (canon.h or locale) misordered at entry: %s\n", abbrevs[abbrevsCnt].ab); - exit(-1); - } - */ - } - - if (SWLog::getSystemLog()->getLogLevel() > 0) { //make sure log is wanted, this loop stuff costs a lot of time - for (int t = 0; t < 2; t++) { - for (int i = 0; i < BMAX[t]; i++) { - const int bn = getBookAbbrev(books[t][i].name); - if ((bn-1)%39 != i) { - SWLog::getSystemLog()->logError("VerseKey::Book: %s does not have a matching toupper abbrevs entry! book number returned was: %d(%d). Required entry should be:", - books[t][i].name, bn, i); - char *abbr = 0; - stdstr(&abbr, books[t][i].name, 2); - strstrip(abbr); - - StringMgr* stringMgr = StringMgr::getSystemStringMgr(); - const bool hasUTF8Support = StringMgr::hasUTF8Support(); - if (hasUTF8Support) { //we have support for UTF-8 handling; we expect UTF-8 encoded locales - stringMgr->upperUTF8(abbr, strlen(abbr)*2); - } - else { - stringMgr->upperLatin1(abbr); - } - SWLog::getSystemLog()->logError("%s=%d", abbr, (t*39)+i+1); - } - } - } - } - } - else abbrevsCnt = size; } -/****************************************************************************** - * VerseKey::initstatics - initializes statics. Performed only when first - * instance on VerseKey (or descendent) is created. - */ - -void VerseKey::initstatics() { - int l1, l2, chaptmp = 0; - - builtin_books[0] = otbooks; - builtin_books[1] = ntbooks; +const char *VerseKey::getVersificationSystem() const { return refSys->getName(); } - for (l1 = 0; l1 < 2; l1++) { - for (l2 = 0; l2 < builtin_BMAX[l1]; l2++) { - builtin_books[l1][l2].versemax = &vm[chaptmp]; - chaptmp += builtin_books[l1][l2].chapmax; - } - } -} /****************************************************************************** @@ -288,37 +277,18 @@ void VerseKey::initstatics() { char VerseKey::parse(bool checkAutoNormalize) { - - - testament = 2; - book = BMAX[1]; + testament = BMAX[1]?2:1; + book = BMAX[BMAX[1]?1:0]; chapter = 1; verse = 1; - int booklen = 0; int error = 0; if (keytext) { - ListKey tmpListKey = VerseKey::ParseVerseList(keytext); + ListKey tmpListKey = ParseVerseList(keytext); if (tmpListKey.Count()) { - SWKey::setText((const char *)tmpListKey); - for (int i = 1; i < 3; i++) { - for (int j = 1; j <= BMAX[i-1]; j++) { - int matchlen = strlen(books[i-1][j-1].name); - if (!strncmp(keytext, books[i-1][j-1].name, matchlen)) { - if (matchlen > booklen) { - booklen = matchlen; - testament = i; - book = j; - } - } - } - } - - if (booklen) { - sscanf(&keytext[booklen], "%d:%d", &chapter, &verse); - } - else error = 1; + this->positionFrom(*tmpListKey.getElement(0)); + error = this->error; } else error = 1; } if (checkAutoNormalize) { @@ -338,7 +308,7 @@ char VerseKey::parse(bool checkAutoNormalize) void VerseKey::freshtext() const { char buf[2024]; - int realtest = testament; + int realTest = testament; int realbook = book; if (book < 1) { @@ -347,14 +317,18 @@ void VerseKey::freshtext() const else sprintf(buf, "[ Testament %d Heading ]", (int)testament); } else { - if (realbook > BMAX[realtest-1]) { - realbook -= BMAX[realtest-1]; - if (realtest < 2) - realtest++; - if (realbook > BMAX[realtest-1]) - realbook = BMAX[realtest-1]; + if (realbook > BMAX[realTest-1]) { + realbook -= BMAX[realTest-1]; + if (realTest < 2) + realTest++; + if (realbook > BMAX[realTest-1]) + realbook = BMAX[realTest-1]; + } + sprintf(buf, "%s %d:%d", getBookName(), chapter, verse); + if (suffix) { + buf[strlen(buf)+1] = 0; + buf[strlen(buf)] = suffix; } - sprintf(buf, "%s %d:%d", books[realtest-1][realbook-1].name, chapter, verse); } stdstr((char **)&keytext, buf); @@ -362,19 +336,24 @@ void VerseKey::freshtext() const -/****************************************************************************** - * VerseKey::getBookAbbrev - Attempts to find a book abbreviation for a buffer +/************************************************************************ + * VerseKey::getBookAbbrev - Attempts to find a book no from a name or + * abbreviation * * ENT: abbr - key for which to search; * RET: book number or < 0 = not valid */ -int VerseKey::getBookAbbrev(const char *iabbr) +int VerseKey::getBookAbbrev(const char *iabbr) const { int diff, abLen, min, max, target, retVal = -1; char *abbr = 0; + int abbrevsCnt; + + const struct abbrev *abbrevs = getPrivateLocale()->getBookAbbrevs(&abbrevsCnt); + StringMgr* stringMgr = StringMgr::getSystemStringMgr(); const bool hasUTF8Support = StringMgr::hasUTF8Support(); @@ -420,7 +399,15 @@ int VerseKey::getBookAbbrev(const char *iabbr) break; } - retVal = (!diff) ? abbrevs[target].book : -1; + if (!diff) { + // lets keep moving forward till we find an abbrev in our refSys + retVal = refSys->getBookNumberByOSISName(abbrevs[target].osis); + while ((retVal < 0) && (target < max) && (!strncmp(abbr, abbrevs[target+1].ab, abLen))) { + target++; + retVal = refSys->getBookNumberByOSISName(abbrevs[target].osis); + } + } + else retVal = -1; } if (retVal > 0) break; @@ -431,6 +418,36 @@ int VerseKey::getBookAbbrev(const char *iabbr) /****************************************************************************** + * VerseKey::validateCurrentLocale - be sure a locale book abbrevs set is complete + * + */ +void VerseKey::validateCurrentLocale() const { + if (SWLog::getSystemLog()->getLogLevel() >= SWLog::LOG_DEBUG) { //make sure log is wanted, this loop stuff costs a lot of time + for (int i = 0; i < refSys->getBookCount(); i++) { + const int bn = getBookAbbrev(getPrivateLocale()->translate(refSys->getBook(i)->getLongName())); + if (bn != i+1) { + char *abbr = 0; + stdstr(&abbr, getPrivateLocale()->translate(refSys->getBook(i)->getLongName()), 2); + strstrip(abbr); + SWLog::getSystemLog()->logDebug("VerseKey::Book: %s does not have a matching toupper abbrevs entry! book number returned was: %d, should be %d. Required entry to add to locale:", abbr, bn, i); + + StringMgr* stringMgr = StringMgr::getSystemStringMgr(); + const bool hasUTF8Support = StringMgr::hasUTF8Support(); + if (hasUTF8Support) { //we have support for UTF-8 handling; we expect UTF-8 encoded locales + stringMgr->upperUTF8(abbr, strlen(abbr)*2); + } + else { + stringMgr->upperLatin1(abbr); + } + SWLog::getSystemLog()->logDebug("%s=%s\n", abbr, refSys->getBook(i)->getOSISName()); + delete [] abbr; + } + } + } +} + + +/****************************************************************************** * VerseKey::ParseVerseList - Attempts to parse a buffer into separate * verse entries returned in a ListKey * @@ -446,19 +463,24 @@ int VerseKey::getBookAbbrev(const char *iabbr) * COMMENT: This code works but wreaks. Rewrite to make more maintainable. */ -ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool expandRange) { - char book[2048]; - char number[2048]; +ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool expandRange, bool useChapterAsVerse) { + + // hold on to our own copy of params, as threads/recursion may change outside values + const char *bufStart = buf; + SWBuf iBuf = buf; + buf = iBuf.c_str(); + SWBuf iDefaultKey = defaultKey; + if (defaultKey) defaultKey = iDefaultKey.c_str(); + + char book[2048]; // TODO: bad, remove + char number[2048]; // TODO: bad, remove *book = 0; *number = 0; int tobook = 0; int tonumber = 0; + char suffix = 0; int chap = -1, verse = -1; int bookno = 0; - VerseKey curKey, lBound, lastKey; - curKey.setLocale(getLocale()); - lBound.setLocale(getLocale()); - lastKey.setLocale(getLocale()); int loop; char comma = 0; char dash = 0; @@ -470,13 +492,50 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e bool inTerm = true; int notAllDigits = 0; - curKey.AutoNormalize(0); - if (defaultKey) lastKey = defaultKey; - + // assert we have a buffer + if (!buf) return internalListKey; + + VerseKey *curKey = (VerseKey *)this->clone(); + VerseKey *lastKey = (VerseKey *)this->clone(); + lastKey->ClearBounds(); + curKey->ClearBounds(); + + // some silly checks for corner cases + if (!strcmp(buf, "[ Module Heading ]")) { + curKey->Verse(0); + curKey->Chapter(0); + curKey->Book(0); + curKey->Testament(0); + lastKey->LowerBound(*curKey); + lastKey->UpperBound(*curKey); + internalListKey << *lastKey; + delete curKey; + delete lastKey; + return internalListKey; + } + if ((!strncmp(buf, "[ Testament ", 12)) && + (isdigit(buf[12])) && + (!strcmp(buf+13, " Heading ]"))) { + curKey->Verse(0); + curKey->Chapter(0); + curKey->Book(0); + curKey->Testament(buf[12]-48); + lastKey->LowerBound(*curKey); + lastKey->UpperBound(*curKey); + internalListKey << *lastKey; + delete curKey; + delete lastKey; + return internalListKey; + } + + curKey->AutoNormalize(AutoNormalize()); + lastKey->AutoNormalize(0); + if (defaultKey) *lastKey = defaultKey; + while (*buf) { switch (*buf) { case ':': - if (buf[1] != ' ') { // for silly Mat 1:1: this verse.... + if (buf[1] != ' ') { // for silly "Mat 1:1: this verse...." number[tonumber] = 0; tonumber = 0; if (*number) @@ -502,7 +561,7 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e break; } - case '-': + case '-': case ',': // on number new verse case ';': // on number new chapter number[tonumber] = 0; @@ -535,7 +594,8 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e for (loop = strlen(book) - 1; loop+1; loop--) { if (book[loop] == ' ') { - if (isroman(&book[loop+1])) { + // "PS C" is ok, but "II C" is not ok + if (isroman(&book[loop+1]) && !isroman(book,loop)) { if (verse == -1) { verse = chap; chap = from_rom(&book[loop+1]); @@ -549,49 +609,64 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) { // Verse abbrev if (verse == -1) { verse = chap; - chap = lastKey.Chapter(); + chap = lastKey->Chapter(); *book = 0; } } if ((!stricmp(book, "ch")) || (!stricmp(book, "chap"))) { // Verse abbrev - strcpy(book, lastKey.getBookName()); + strcpy(book, lastKey->getBookName()); } bookno = getBookAbbrev(book); } if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) { char partial = 0; - curKey.Verse(1); - curKey.Chapter(1); - curKey.Book(1); + curKey->Verse(1); + curKey->Chapter(1); + curKey->Book(1); if (bookno < 0) { - curKey.Testament(lastKey.Testament()); - curKey.Book(lastKey.Book()); + curKey->Testament(lastKey->Testament()); + curKey->Book(lastKey->Book()); } else { - curKey.Testament(1); - curKey.Book(bookno); + int t = 1; + if (bookno > BMAX[0]) { + t++; + bookno -= BMAX[0]; + } + curKey->Testament(t); + curKey->Book(bookno); } + if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) { // if (comma) { - curKey.Chapter(lastKey.Chapter()); - curKey.Verse(chap); // chap because this is the first number captured + curKey->Chapter(lastKey->Chapter()); + curKey->Verse(chap); // chap because this is the first number captured } else { + if (useChapterAsVerse && verse < 0 && chap > 0 && curKey->getChapterMax() == 1) { + verse = chap; + chap = 1; + } + + if (chap >= 0) { - curKey.Chapter(chap); + curKey->Chapter(chap); } else { partial++; - curKey.Chapter(1); + curKey->Chapter(1); } if (verse >= 0) { - curKey.Verse(verse); + curKey->Verse(verse); + if (suffix) { + curKey->setSuffix(suffix); + } } else { partial++; - curKey.Verse(1); + curKey->Verse(1); } } @@ -599,43 +674,42 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e for (q = 0; ((buf[q]) && (buf[q] == ' ')); q++); if ((buf[q] == '-') && (expandRange)) { // if this is a dash save lowerBound and wait for upper buf+=q; - lastKey.LowerBound(curKey); - lastKey.setPosition(TOP); - tmpListKey << lastKey; - tmpListKey.GetElement()->userData = (void *)buf; + lastKey->LowerBound(*curKey); + lastKey->setPosition(TOP); + tmpListKey << *lastKey; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } else { if (!dash) { // if last separator was not a dash just add if (expandRange && partial) { - lastKey.LowerBound(curKey); + lastKey->LowerBound(*curKey); if (partial > 1) - curKey.setPosition(MAXCHAPTER); + curKey->setPosition(MAXCHAPTER); if (partial > 0) - curKey = MAXVERSE; - lastKey.UpperBound(curKey); - lastKey = TOP; - tmpListKey << lastKey; - tmpListKey.GetElement()->userData = (void *)buf; + *curKey = MAXVERSE; + lastKey->UpperBound(*curKey); + *lastKey = TOP; + tmpListKey << *lastKey; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } else { - // we store non-range entries as strings so we don't traverse - // maybe we should consider just setting - // lowerBound and upperBound to the same value - tmpListKey << curKey.getText(); - tmpListKey.GetElement()->userData = (void *)buf; - lastKey = curKey; + lastKey->LowerBound(*curKey); + lastKey->UpperBound(*curKey); + *lastKey = TOP; + tmpListKey << *lastKey; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } } else if (expandRange) { VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement()); if (newElement) { if (partial > 1) - curKey = MAXCHAPTER; + *curKey = MAXCHAPTER; if (partial > 0) - curKey = MAXVERSE; - newElement->UpperBound(curKey); + *curKey = MAXVERSE; + newElement->UpperBound(*curKey); *newElement = TOP; - tmpListKey.GetElement()->userData = (void *)buf; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } } } @@ -644,6 +718,7 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e *book = 0; chap = -1; verse = -1; + suffix = 0; if (*buf == ',') comma = 1; else comma = 0; @@ -652,13 +727,13 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e else dash = 0; break; case 10: // ignore these - case 13: - case '[': - case ']': - case '(': - case ')': - case '{': - case '}': + case 13: + case '[': + case ']': + case '(': + case ')': + case '{': + case '}': break; case '.': if (buf > orig) // ignore (break) if preceeding char is not a digit @@ -675,7 +750,7 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e chap = atoi(number); *number = 0; break; - + default: if (isdigit(*buf)) { number[tonumber++] = *buf; @@ -683,12 +758,17 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e else { switch (*buf) { case ' ': // ignore these and don't reset number - case 'f': case 'F': break; default: - number[tonumber] = 0; - tonumber = 0; + // suffixes (and oddly 'f'-- ff.) + if ((*buf >= 'a' && *buf <= 'z') && (chap >=0)) { + suffix = *buf; + } + else { + number[tonumber] = 0; + tonumber = 0; + } break; } } @@ -726,7 +806,8 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e for (loop = strlen(book) - 1; loop+1; loop--) { if (book[loop] == ' ') { - if (isroman(&book[loop+1])) { + // "PS C" is ok, but "II C" is not ok + if (isroman(&book[loop+1]) && !isroman(book,loop)) { if (verse == -1) { verse = chap; chap = from_rom(&book[loop+1]); @@ -735,92 +816,109 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e } break; } - } - + } + if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) { // Verse abbrev. if (verse == -1) { verse = chap; - chap = lastKey.Chapter(); + chap = lastKey->Chapter(); *book = 0; } } - + if ((!stricmp(book, "ch")) || (!stricmp(book, "chap"))) { // Verse abbrev - strcpy(book, lastKey.getBookName()); + strcpy(book, lastKey->getBookName()); } bookno = getBookAbbrev(book); } if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) { char partial = 0; - curKey.Verse(1); - curKey.Chapter(1); - curKey.Book(1); + curKey->Verse(1); + curKey->Chapter(1); + curKey->Book(1); if (bookno < 0) { - curKey.Testament(lastKey.Testament()); - curKey.Book(lastKey.Book()); + curKey->Testament(lastKey->Testament()); + curKey->Book(lastKey->Book()); } else { - curKey.Testament(1); - curKey.Book(bookno); + int t = 1; + if (bookno > BMAX[0]) { + t++; + bookno -= BMAX[0]; + } + curKey->Testament(t); + curKey->Book(bookno); } if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) { - curKey.Chapter(lastKey.Chapter()); - curKey.Verse(chap); // chap because this is the first number captured + curKey->Chapter(lastKey->Chapter()); + curKey->Verse(chap); // chap because this is the first number captured } else { + if (useChapterAsVerse && verse < 0 && chap > 0 && curKey->getChapterMax() == 1) { + verse = chap; + chap = 1; + } + + if (chap >= 0) { - curKey.Chapter(chap); + curKey->Chapter(chap); } else { partial++; - curKey.Chapter(1); + curKey->Chapter(1); } if (verse >= 0) { - curKey.Verse(verse); + curKey->Verse(verse); + if (suffix) { + curKey->setSuffix(suffix); + } } else { partial++; - curKey.Verse(1); + curKey->Verse(1); } } if ((*buf == '-') && (expandRange)) { // if this is a dash save lowerBound and wait for upper - lastKey.LowerBound(curKey); - lastKey = TOP; - tmpListKey << lastKey; - tmpListKey.GetElement()->userData = (void *)buf; + lastKey->LowerBound(*curKey); + *lastKey = TOP; + tmpListKey << *lastKey; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } else { if (!dash) { // if last separator was not a dash just add if (expandRange && partial) { - lastKey.LowerBound(curKey); + lastKey->LowerBound(*curKey); if (partial > 1) - curKey = MAXCHAPTER; + *curKey = MAXCHAPTER; if (partial > 0) - curKey = MAXVERSE; - lastKey.UpperBound(curKey); - lastKey = TOP; - tmpListKey << lastKey; - tmpListKey.GetElement()->userData = (void *)buf; + *curKey = MAXVERSE; + lastKey->UpperBound(*curKey); + *lastKey = TOP; + tmpListKey << *lastKey; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } else { - tmpListKey << curKey.getText(); - tmpListKey.GetElement()->userData = (void *)buf; - lastKey = curKey; + lastKey->LowerBound(*curKey); + lastKey->UpperBound(*curKey); + *lastKey = TOP; + tmpListKey << *lastKey; +// tmpListKey << curKey->getText(); + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } } else if (expandRange) { VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement()); if (newElement) { if (partial > 1) - curKey = MAXCHAPTER; + *curKey = MAXCHAPTER; if (partial > 0) - curKey = MAXVERSE; - newElement->UpperBound(curKey); + *curKey = MAXVERSE; + newElement->UpperBound(*curKey); *newElement = TOP; - tmpListKey.GetElement()->userData = (void *)buf; + tmpListKey.GetElement()->userData = (void *)(bufStart+(buf-iBuf.c_str())); } } } @@ -830,6 +928,9 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e internalListKey = tmpListKey; internalListKey = TOP; // Align internalListKey to first element before passing back; + delete curKey; + delete lastKey; + return internalListKey; } @@ -838,16 +939,23 @@ ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool e * VerseKey::LowerBound - sets / gets the lower boundary for this key */ -VerseKey &VerseKey::LowerBound(const char *lb) +VerseKey &VerseKey::LowerBound(const VerseKey &lb) { - if (!lowerBound) - initBounds(); + initBounds(); - (*lowerBound) = lb; - lowerBound->Normalize(); - lowerBound->setLocale( this->getLocale() ); + lowerBound = lb.Index(); + lowerBoundComponents.test = lb.getTestament(); + lowerBoundComponents.book = lb.getBook(); + lowerBoundComponents.chap = lb.getChapter(); + lowerBoundComponents.verse = lb.getVerse(); + + // both this following check and UpperBound check force upperBound to + // change allowing LowerBound then UpperBound logic to always flow + // and set values without restrictions, as expected + if (upperBound < lowerBound) upperBound = lowerBound; boundSet = true; - return (*lowerBound); + + return LowerBound(); } @@ -855,40 +963,21 @@ VerseKey &VerseKey::LowerBound(const char *lb) * VerseKey::UpperBound - sets / gets the upper boundary for this key */ -VerseKey &VerseKey::UpperBound(const char *ub) +VerseKey &VerseKey::UpperBound(const VerseKey &ub) { - if (!upperBound) - initBounds(); - -// need to set upperbound parsing to resolve to max verse/chap if not specified - (*upperBound) = ub; - if (*upperBound < *lowerBound) - *upperBound = *lowerBound; - upperBound->Normalize(); - upperBound->setLocale( this->getLocale() ); - -// until we have a proper method to resolve max verse/chap use this kludge - int len = strlen(ub); - bool alpha = false; - bool versespec = false; - bool chapspec = false; - for (int i = 0; i < len; i++) { - if (isalpha(ub[i])) - alpha = true; - if (ub[i] == ':') // if we have a : we assume verse spec - versespec = true; - if ((isdigit(ub[i])) && (alpha)) // if digit after alpha assume chap spec - chapspec = true; - } - if (!chapspec) - *upperBound = MAXCHAPTER; - if (!versespec) - *upperBound = MAXVERSE; - + initBounds(); + + upperBound = ub.Index(); + upperBoundComponents.test = ub.getTestament(); + upperBoundComponents.book = ub.getBook(); + upperBoundComponents.chap = ub.getChapter(); + upperBoundComponents.verse = ub.getVerse(); -// -- end kludge + // see LowerBound comment, above + if (upperBound < lowerBound) upperBound = lowerBound; boundSet = true; - return (*upperBound); + + return UpperBound(); } @@ -898,10 +987,16 @@ VerseKey &VerseKey::UpperBound(const char *ub) VerseKey &VerseKey::LowerBound() const { - if (!lowerBound) - initBounds(); + initBounds(); + if (!isAutoNormalize()) { + tmpClone->testament = lowerBoundComponents.test; + tmpClone->book = lowerBoundComponents.book; + tmpClone->chapter = lowerBoundComponents.chap; + tmpClone->setVerse (lowerBoundComponents.verse); + } + else tmpClone->Index(lowerBound); - return (*lowerBound); + return (*tmpClone); } @@ -911,10 +1006,16 @@ VerseKey &VerseKey::LowerBound() const VerseKey &VerseKey::UpperBound() const { - if (!upperBound) - initBounds(); + initBounds(); + if (!isAutoNormalize()) { + tmpClone->testament = upperBoundComponents.test; + tmpClone->book = upperBoundComponents.book; + tmpClone->chapter = upperBoundComponents.chap; + tmpClone->setVerse (upperBoundComponents.verse); + } + else tmpClone->Index(upperBound); - return (*upperBound); + return (*tmpClone); } @@ -924,33 +1025,36 @@ VerseKey &VerseKey::UpperBound() const void VerseKey::ClearBounds() { - initBounds(); + delete tmpClone; + tmpClone = 0; + boundSet = false; } void VerseKey::initBounds() const { - if (!upperBound) { - upperBound = new VerseKey(); - upperBound->AutoNormalize(0); - upperBound->Headings(1); - } - if (!lowerBound) { - lowerBound = new VerseKey(); - lowerBound->AutoNormalize(0); - lowerBound->Headings(1); - } - - lowerBound->Testament(0); - lowerBound->Book(0); - lowerBound->Chapter(0); - lowerBound->Verse(0); + if (!tmpClone) { + tmpClone = (VerseKey *)this->clone(); + tmpClone->AutoNormalize(0); + tmpClone->Headings(1); + tmpClone->Testament((BMAX[1])?2:1); + tmpClone->Book(BMAX[(BMAX[1])?1:0]); + tmpClone->Chapter(tmpClone->getChapterMax()); + tmpClone->Verse(tmpClone->getVerseMax()); + upperBound = tmpClone->Index(); + upperBoundComponents.test = tmpClone->getTestament(); + upperBoundComponents.book = tmpClone->getBook(); + upperBoundComponents.chap = tmpClone->getChapter(); + upperBoundComponents.verse = tmpClone->getVerse(); + + lowerBound = 0; + lowerBoundComponents.test = 0; + lowerBoundComponents.book = 0; + lowerBoundComponents.chap = 0; + lowerBoundComponents.verse = 0; - upperBound->Testament(2); - upperBound->Book(BMAX[1]); - upperBound->Chapter(books[1][BMAX[1]-1].chapmax); - upperBound->Verse(books[1][BMAX[1]-1].versemax[upperBound->Chapter()-1]); - boundSet = false; + } + else tmpClone->setLocale(getLocale()); } @@ -975,7 +1079,7 @@ const char *VerseKey::getShortText() const { else sprintf(buf, "[ Testament %d Heading ]", (int)testament); } else { - sprintf(buf, "%s %d:%d", books[testament-1][book-1].prefAbbrev, chapter, verse); + sprintf(buf, "%s %d:%d", getBookAbbrev(), chapter, verse); } stdstr(&stext, buf); return stext; @@ -983,13 +1087,20 @@ const char *VerseKey::getShortText() const { const char *VerseKey::getBookName() const { - return books[testament-1][book-1].name; + return getPrivateLocale()->translate(refSys->getBook(((testament>1)?BMAX[0]:0)+book-1)->getLongName()); +} + + +const char *VerseKey::getOSISBookName() const { + return refSys->getBook(((testament>1)?BMAX[0]:0)+book-1)->getOSISName(); } const char *VerseKey::getBookAbbrev() const { - return books[testament-1][book-1].prefAbbrev; + return refSys->getBook(((testament>1)?BMAX[0]:0)+book-1)->getPreferredAbbreviation(); } + + /****************************************************************************** * VerseKey::setPosition(SW_POSITION) - Positions this key * @@ -1000,32 +1111,50 @@ const char *VerseKey::getBookAbbrev() const { void VerseKey::setPosition(SW_POSITION p) { switch (p) { - case POS_TOP: - testament = LowerBound().Testament(); - book = LowerBound().Book(); - chapter = LowerBound().Chapter(); - verse = LowerBound().Verse(); + case POS_TOP: { + const VerseKey *lb = &LowerBound(); + testament = (lb->Testament() || headings) ? lb->Testament() : 1; + book = (lb->Book() || headings) ? lb->Book() : 1; + chapter = (lb->Chapter() || headings) ? lb->Chapter() : 1; + verse = (lb->Verse() || headings) ? lb->Verse() : 1; + suffix = lb->getSuffix(); break; - case POS_BOTTOM: - testament = UpperBound().Testament(); - book = UpperBound().Book(); - chapter = UpperBound().Chapter(); - verse = UpperBound().Verse(); + } + case POS_BOTTOM: { + const VerseKey *ub = &UpperBound(); + testament = (ub->Testament() || headings) ? ub->Testament() : 1; + book = (ub->Book() || headings) ? ub->Book() : 1; + chapter = (ub->Chapter() || headings) ? ub->Chapter() : 1; + verse = (ub->Verse() || headings) ? ub->Verse() : 1; + suffix = ub->getSuffix(); break; + } case POS_MAXVERSE: Normalize(); - verse = books[testament-1][book-1].versemax[chapter-1]; + verse = getVerseMax(); + suffix = 0; break; case POS_MAXCHAPTER: verse = 1; + suffix = 0; Normalize(); - chapter = books[testament-1][book-1].chapmax; + chapter = getChapterMax(); break; - } + } Normalize(1); Error(); // clear error from normalize } +int VerseKey::getChapterMax() const { + const VerseMgr::Book *b = refSys->getBook(((testament>1)?BMAX[0]:0)+book-1); + return (b) ? b->getChapterMax() : -1; +} + +int VerseKey::getVerseMax() const { + const VerseMgr::Book *b = refSys->getBook(((testament>1)?BMAX[0]:0)+book-1); + return (b) ? b->getVerseMax(chapter) : -1; +} + /****************************************************************************** * VerseKey::increment - Increments key a number of verses @@ -1079,11 +1208,11 @@ void VerseKey::decrement(int step) { void VerseKey::Normalize(char autocheck) { - error = 0; if (((!autocheck) || (autonorm)) // only normalize if we were explicitely called or if autonorm is turned on && ((!headings) || ((verse) && (chapter)))) { // this is cheeze and temporary until deciding what actions should be taken; so headings should only be turned on when positioning with Index() or incrementors + error = 0; while ((testament < 3) && (testament > 0)) { @@ -1100,40 +1229,45 @@ void VerseKey::Normalize(char autocheck) continue; } - if (chapter > books[testament-1][book-1].chapmax) { - chapter -= books[testament-1][book-1].chapmax; + if (chapter > getChapterMax()) { + chapter -= getChapterMax(); book++; continue; } - if (chapter < 1) { - if (--book > 0) { - chapter += books[testament-1][book-1].chapmax; - } - else { - if (testament > 1) { - chapter += books[0][BMAX[0]-1].chapmax; - } - } - continue; - } + if (chapter < 1) { + if (--book > 0) { + chapter += getChapterMax(); + verse = getVerseMax(); + } + else { + if (testament > 1) { + chapter += refSys->getBook(BMAX[0]-1)->getChapterMax(); + verse = refSys->getBook(BMAX[0]-1)->getVerseMax(chapter); + } + } + continue; + } - if (verse > books[testament-1][book-1].versemax[chapter-1]) { // -1 because e.g chapter 1 of Matthew is books[1][0].versemax[0] - verse -= books[testament-1][book-1].versemax[chapter++ - 1]; + if (verse > getVerseMax()) { // -1 because e.g chapter 1 of Matthew is books[1][0].versemax[0] + verse -= getVerseMax(); + chapter++; continue; } if (verse < 1) { if (--chapter > 0) { - verse += books[testament-1][book-1].versemax[chapter-1]; + verse += getVerseMax(); } else { if (book > 1) { - verse += books[testament-1][book-2].versemax[books[testament-1][book-2].chapmax-1]; + const VerseMgr::Book *prevBook = refSys->getBook(((testament>1)?BMAX[0]:0)+book-2); + verse += prevBook->getVerseMax(prevBook->getChapterMax()); } else { if (testament > 1) { - verse += books[0][BMAX[0]-1].versemax[books[0][BMAX[0]-1].chapmax-1]; + const VerseMgr::Book *lastOTBook = refSys->getBook(BMAX[0]-1); + verse += lastOTBook->getVerseMax(lastOTBook->getChapterMax()); } } } @@ -1143,11 +1277,11 @@ void VerseKey::Normalize(char autocheck) break; // If we've made it this far (all failure checks continue) we're ok } - if (testament > 2) { - testament = 2; + if (testament > (BMAX[1]?2:1)) { + testament = BMAX[1]?2:1; book = BMAX[testament-1]; - chapter = books[testament-1][book-1].chapmax; - verse = books[testament-1][book-1].versemax[chapter-1]; + chapter = getChapterMax(); + verse = getVerseMax(); error = KEYERR_OUTOFBOUNDS; } @@ -1161,11 +1295,11 @@ void VerseKey::Normalize(char autocheck) // should we always perform bounds checks? Tried but seems to cause infinite recursion if (_compare(UpperBound()) > 0) { - setText(UpperBound(), false); + positionFrom(UpperBound()); error = KEYERR_OUTOFBOUNDS; } if (_compare(LowerBound()) < 0) { - setText(LowerBound(), false); + positionFrom(LowerBound()); error = KEYERR_OUTOFBOUNDS; } } @@ -1173,24 +1307,24 @@ void VerseKey::Normalize(char autocheck) /****************************************************************************** - * VerseKey::Testament - Gets testament + * VerseKey::getTestament - Gets testament * * RET: value of testament */ -char VerseKey::Testament() const +char VerseKey::getTestament() const { return testament; } /****************************************************************************** - * VerseKey::Book - Gets book + * VerseKey::getBook - Gets book * * RET: value of book */ -char VerseKey::Book() const +char VerseKey::getBook() const { return book; } @@ -1202,7 +1336,7 @@ char VerseKey::Book() const * RET: value of chapter */ -int VerseKey::Chapter() const +int VerseKey::getChapter() const { return chapter; } @@ -1214,14 +1348,14 @@ int VerseKey::Chapter() const * RET: value of verse */ -int VerseKey::Verse() const +int VerseKey::getVerse() const { return verse; } /****************************************************************************** - * VerseKey::Testament - Sets/gets testament + * VerseKey::setTestament - Sets/gets testament * * ENT: itestament - value which to set testament * [MAXPOS(char)] - only get @@ -1230,64 +1364,68 @@ int VerseKey::Verse() const * if changed -> previous value of testament */ -char VerseKey::Testament(char itestament) +void VerseKey::setTestament(char itestament) { - char retval = testament; - if (itestament != MAXPOS(char)) { testament = itestament; Normalize(1); } - return retval; } /****************************************************************************** - * VerseKey::Book - Sets/gets book + * VerseKey::setBook - Sets/gets book * * ENT: ibook - value which to set book - * [MAXPOS(char)] - only get - * - * RET: if unchanged -> value of book - * if changed -> previous value of book */ -char VerseKey::Book(char ibook) +void VerseKey::setBook(char ibook) { - char retval = book; - - Chapter(1); - book = ibook; + verse = ibook ? 1 : 0; + chapter = ibook ? 1 : 0; + book = ibook; Normalize(1); - - return retval; } + /****************************************************************************** - * VerseKey::Chapter - Sets/gets chapter - * - * ENT: ichapter - value which to set chapter - * [MAXPOS(int)] - only get + * VerseKey::setBookName - Sets/gets book by name * - * RET: if unchanged -> value of chapter - * if changed -> previous value of chapter + * ENT: bname - book name/abbrev */ -int VerseKey::Chapter(int ichapter) +void VerseKey::setBookName(const char *bname) { - int retval = chapter; + int bnum = getBookAbbrev(bname); + if (bnum > -1) { + if (bnum > BMAX[0]) { + bnum -= BMAX[0]; + testament = 2; + } + else testament = 1; + setBook(bnum); + } + else error = KEYERR_OUTOFBOUNDS; +} + + +/****************************************************************************** + * VerseKey::setChapter - Sets/gets chapter + * + * ENT: ichapter - value which to set chapter + */ - Verse(1); +void VerseKey::setChapter(int ichapter) +{ + verse = ichapter ? 1 : 0; chapter = ichapter; Normalize(1); - - return retval; } /****************************************************************************** - * VerseKey::Verse - Sets/gets verse + * VerseKey::setVerse - Sets/gets verse * * ENT: iverse - value which to set verse * [MAXPOS(int)] - only get @@ -1296,37 +1434,36 @@ int VerseKey::Chapter(int ichapter) * if changed -> previous value of verse */ -int VerseKey::Verse(int iverse) +void VerseKey::setVerse(int iverse) { - int retval = verse; - + setSuffix(0); verse = iverse; Normalize(1); +} - return retval; + +char VerseKey::getSuffix() const { + return suffix; } +void VerseKey::setSuffix(char suf) { + suffix = suf; +} /****************************************************************************** * VerseKey::AutoNormalize - Sets/gets flag that tells VerseKey to auto- * matically normalize itself when modified - * - * ENT: iautonorm - value which to set autonorm - * [MAXPOS(char)] - only get - * - * RET: if unchanged -> value of autonorm - * if changed -> previous value of autonorm */ -char VerseKey::AutoNormalize(char iautonorm) +bool VerseKey::isAutoNormalize() const { - char retval = autonorm; + return autonorm; +} - if (iautonorm != MAXPOS(char)) { - autonorm = iautonorm; - Normalize(1); - } - return retval; +void VerseKey::setAutoNormalize(bool iautonorm) +{ + autonorm = iautonorm?1:0; + Normalize(1); } @@ -1392,34 +1529,27 @@ long VerseKey::Index() const if (!testament) { // if we want module heading offset = 0; - verse = 0; + } + else if (!book) { // we want testament heading + offset = ((testament == 2) ? refSys->getNTStartOffset():0) + 1; } else { - if (!book) - chapter = 0; - if (!chapter) - verse = 0; - - offset = offsets[testament-1][0][book]; - offset = offsets[testament-1][1][(int)offset + chapter]; - if (!(offset|verse)) // if we have a testament but nothing else. - offset = 1; + offset = refSys->getOffsetFromVerse((((testament>1)?BMAX[0]:0)+book-1), chapter, verse); } - return (offset + verse); + return offset; } /****************************************************************************** - * VerseKey::Index - Gets index based upon current verse + * VerseKey::TestamentIndex - Gets index based upon current verse * * RET: offset */ -long VerseKey::NewIndex() const +long VerseKey::TestamentIndex() const { - static long otMaxIndex = 32300 - 8245; // total positions - new testament positions -// static long otMaxIndex = offsets[0][1][(int)offsets[0][0][BMAX[0]] + books[0][BMAX[0]].chapmax]; - return ((testament-1) * otMaxIndex) + Index(); + long offset = Index(); + return (testament > 1) ? offset - refSys->getNTStartOffset() : offset; } @@ -1433,60 +1563,31 @@ long VerseKey::NewIndex() const long VerseKey::Index(long iindex) { - long offset; - -// This is the dirty stuff -------------------------------------------- - - if (!testament) - testament = 1; - - if (iindex < 1) { // if (-) or module heading - if (testament < 2) { - if (iindex < 0) { - testament = 0; // previously we changed 0 -> 1 - error = KEYERR_OUTOFBOUNDS; - } - else testament = 0; // we want module heading - } - else { - testament--; - iindex = (offsets[testament-1][1][offsize[testament-1][1]-1] + books[testament-1][BMAX[testament-1]-1].versemax[books[testament-1][BMAX[testament-1]-1].chapmax-1]) + iindex; // What a doozy! ((offset of last chapter + number of verses in the last chapter) + iindex) - } + int b; + error = refSys->getVerseFromOffset(iindex, &b, &chapter, &verse); + book = (unsigned char)b; + testament = 1; + if (book > BMAX[0]) { + book -= BMAX[0]; + testament = 2; } + // special case for Module and Testament heading + if (book < 0) { testament = 0; book = 0; } + if (chapter < 0) { book = 0; chapter = 0; } -// -------------------------------------------------------------------- - - - if (testament) { - if ((!error) && (iindex)) { - offset = findindex(offsets[testament-1][1], offsize[testament-1][1], iindex); - verse = iindex - offsets[testament-1][1][offset]; - book = findindex(offsets[testament-1][0], offsize[testament-1][0], offset); - chapter = offset - offsets[testament-1][0][VerseKey::book]; - verse = (chapter) ? verse : 0; // funny check. if we are index=1 (testmt header) all gets set to 0 exept verse. Don't know why. Fix if you figure out. Think its in the offsets table. - if (verse) { // only check if -1 won't give negative - if (verse > books[testament-1][book-1].versemax[chapter-1]) { - if (testament > 1) { - verse = books[testament-1][book-1].versemax[chapter-1]; - error = KEYERR_OUTOFBOUNDS; - } - else { - testament++; - Index(verse - books[testament-2][book-1].versemax[chapter-1]); - } - } - } - } - } - if (_compare(UpperBound()) > 0) { - *this = UpperBound(); + long i = Index(); + + initBounds(); + if (i > upperBound) { + i = Index(upperBound); error = KEYERR_OUTOFBOUNDS; } - if (_compare(LowerBound()) < 0) { - *this = LowerBound(); + if (i < lowerBound) { + i = Index(lowerBound); error = KEYERR_OUTOFBOUNDS; } - return Index(); + + return i; } @@ -1524,37 +1625,23 @@ int VerseKey::compare(const SWKey &ikey) int VerseKey::_compare(const VerseKey &ivkey) { - long keyval1 = 0; - long keyval2 = 0; + unsigned long keyval1 = 0; + unsigned long keyval2 = 0; - keyval1 += Testament() * 1000000000; + keyval1 += Testament() * 1000000000; keyval2 += ivkey.Testament() * 1000000000; - keyval1 += Book() * 1000000; - keyval2 += ivkey.Book() * 1000000; - keyval1 += Chapter() * 1000; - keyval2 += ivkey.Chapter() * 1000; - keyval1 += Verse(); - keyval2 += ivkey.Verse(); - keyval1 -= keyval2; - keyval1 = (keyval1) ? ((keyval1 > 0) ? 1 : -1) /*keyval1/labs(keyval1)*/:0; // -1 | 0 | 1 + keyval1 += Book() * 10000000; + keyval2 += ivkey.Book() * 10000000; + keyval1 += Chapter() * 10000; + keyval2 += ivkey.Chapter() * 10000; + keyval1 += Verse() * 50; + keyval2 += ivkey.Verse() * 50; + keyval1 += (int)getSuffix(); + keyval2 += (int)ivkey.getSuffix(); + keyval1 = (keyval1 != keyval2) ? ((keyval1 > keyval2) ? 1 : -1) : 0; // -1 | 0 | 1 return keyval1; } -const char *VerseKey::osisotbooks[] = { - "Gen","Exod","Lev","Num","Deut","Josh","Judg","Ruth","1Sam","2Sam", - "1Kgs","2Kgs","1Chr","2Chr","Ezra","Neh","Esth","Job","Ps", - "Prov", // added this. Was not in OSIS spec - "Eccl", - "Song","Isa","Jer","Lam","Ezek","Dan","Hos","Joel","Amos","Obad", - "Jonah","Mic","Nah","Hab","Zeph","Hag","Zech","Mal","Bar","PrAzar", - "Bel","Sus","1Esd","2Esd","AddEsth","EpJer","Jdt","1Macc","2Macc","3Macc", - "4Macc","PrMan","Ps151","Sir","Tob","Wis"}; -const char *VerseKey::osisntbooks[] = { - "Matt","Mark","Luke","John","Acts","Rom","1Cor","2Cor","Gal","Eph", - "Phil","Col","1Thess","2Thess","1Tim","2Tim","Titus","Phlm","Heb","Jas", - "1Pet","2Pet","1John","2John","3John","Jude","Rev"}; -const char **VerseKey::osisbooks[] = { osisotbooks, osisntbooks }; - const char *VerseKey::getOSISRef() const { static char buf[5][254]; @@ -1564,53 +1651,50 @@ const char *VerseKey::getOSISRef() const { loop = 0; if (Verse()) - sprintf(buf[loop], "%s.%d.%d", osisbooks[Testament()-1][Book()-1], (int)Chapter(), (int)Verse()); + sprintf(buf[loop], "%s.%d.%d", getOSISBookName(), (int)Chapter(), (int)Verse()); else if (Chapter()) - sprintf(buf[loop], "%s.%d", osisbooks[Testament()-1][Book()-1], (int)Chapter()); + sprintf(buf[loop], "%s.%d", getOSISBookName(), (int)Chapter()); else if (Book()) - sprintf(buf[loop], "%s", osisbooks[Testament()-1][Book()-1]); + sprintf(buf[loop], "%s", getOSISBookName()); else buf[loop][0] = 0; return buf[loop++]; } -const int VerseKey::getOSISBookNum(const char *bookab) { - int i; - for (i=0; i < 39; i++) - { - if (!strncmp(bookab, osisotbooks[i], strlen(osisotbooks[i]))) - { - //printf("VerseKey::getOSISBookNum %s is OT %d\n", bookab, i+1); - return i+1; - } - } - for (i=0; i < 27; i++) - { - if (!strncmp(bookab, osisntbooks[i], strlen(osisotbooks[i]))) - { - //printf("VerseKey::getOSISBookNum %s is NT %d\n", bookab, i+1); - return i+1; - } - } - return -1; -} - - /****************************************************************************** * VerseKey::getRangeText - returns parsable range text for this key */ const char *VerseKey::getRangeText() const { - if (isBoundSet()) { - char buf[1023]; - sprintf(buf, "%s-%s", (const char *)LowerBound(), (const char *)UpperBound()); - stdstr(&rangeText, buf); + if (isBoundSet() && lowerBound != upperBound) { + SWBuf buf = (const char *)LowerBound(); + buf += "-"; + buf += (const char *)UpperBound(); + stdstr(&rangeText, buf.c_str()); } else stdstr(&rangeText, getText()); return rangeText; } +/****************************************************************************** + * VerseKey::getOSISRefRangeText - returns parsable range text for this key + */ + +const char *VerseKey::getOSISRefRangeText() const { + if (isBoundSet() && (lowerBound != upperBound)) { + SWBuf buf = LowerBound().getOSISRef(); + buf += "-"; + buf += UpperBound().getOSISRef(); + stdstr(&rangeText, buf.c_str()); + } + else stdstr(&rangeText, getOSISRef()); + return rangeText; +} + + +// TODO: this is static so we have no context. We can only parse KJV v11n now +// possibly add a const char *versification = KJV param? const char *VerseKey::convertToOSIS(const char *inRef, const SWKey *lastKnownKey) { static SWBuf outRef; @@ -1620,12 +1704,13 @@ const char *VerseKey::convertToOSIS(const char *inRef, const SWKey *lastKnownKey ListKey verses = defLanguage.ParseVerseList(inRef, (*lastKnownKey), true); const char *startFrag = inRef; for (int i = 0; i < verses.Count(); i++) { - VerseKey *element = SWDYNAMIC_CAST(VerseKey, verses.GetElement(i)); - char buf[5120]; + SWKey *element = verses.GetElement(i); +// VerseKey *element = SWDYNAMIC_CAST(VerseKey, verses.GetElement(i)); + SWBuf buf; + // TODO: This code really needs to not use fixed size arrays char frag[800]; char preJunk[800]; char postJunk[800]; - memset(buf, 0, 5120); memset(frag, 0, 800); memset(preJunk, 0, 800); memset(postJunk, 0, 800); @@ -1633,32 +1718,26 @@ const char *VerseKey::convertToOSIS(const char *inRef, const SWKey *lastKnownKey outRef += *startFrag; startFrag++; } - if (element) { - memmove(frag, startFrag, ((const char *)element->userData - startFrag) + 1); - frag[((const char *)element->userData - startFrag) + 1] = 0; - int j; - for (j = strlen(frag)-1; j && (strchr(" {};,()[].", frag[j])); j--); - if (frag[j+1]) - strcpy(postJunk, frag+j+1); - frag[j+1]=0; - startFrag += ((const char *)element->userData - startFrag) + 1; - sprintf(buf, "<reference osisRef=\"%s-%s\">%s</reference>%s", element->LowerBound().getOSISRef(), element->UpperBound().getOSISRef(), frag, postJunk); - } - else { - memmove(frag, startFrag, ((const char *)verses.GetElement(i)->userData - startFrag) + 1); - frag[((const char *)verses.GetElement(i)->userData - startFrag) + 1] = 0; - int j; - for (j = strlen(frag)-1; j && (strchr(" {};,()[].", frag[j])); j--); - if (frag[j+1]) - strcpy(postJunk, frag+j+1); - frag[j+1]=0; - startFrag += ((const char *)verses.GetElement(i)->userData - startFrag) + 1; - sprintf(buf, "<reference osisRef=\"%s\">%s</reference>%s", VerseKey(*verses.GetElement(i)).getOSISRef(), frag, postJunk); - } - outRef+=buf; + memmove(frag, startFrag, ((const char *)element->userData - startFrag) + 1); + frag[((const char *)element->userData - startFrag) + 1] = 0; + int j; + for (j = strlen(frag)-1; j && (strchr(" {};,()[].", frag[j])); j--); + if (frag[j+1]) + strcpy(postJunk, frag+j+1); + frag[j+1]=0; + startFrag += ((const char *)element->userData - startFrag) + 1; + buf = "<reference osisRef=\""; + buf += element->getOSISRefRangeText(); + buf += "\">"; + buf += frag; + buf += "</reference>"; + buf += postJunk; + + outRef += buf; + } if (startFrag < (inRef + strlen(inRef))) - outRef+=startFrag; + outRef += startFrag; return outRef.c_str(); } SWORD_NAMESPACE_END |