00001
00002
00003
00004
00005 #include <swmacs.h>
00006 #include <utilfuns.h>
00007 #include <string.h>
00008 #include <stdio.h>
00009 #include <fcntl.h>
00010 #include <stdlib.h>
00011
00012 #ifndef __GNUC__
00013 #include <io.h>
00014 #else
00015 #include <unistd.h>
00016 #endif
00017
00018 #include <utilstr.h>
00019 #include <swkey.h>
00020 #include <swlog.h>
00021 #include <versekey.h>
00022 #include <localemgr.h>
00023 extern "C" {
00024 #include <roman.h>
00025 }
00026
00027
00028 static const char *classes[] = {"VerseKey", "SWKey", "SWObject", 0};
00029 SWClass VerseKey::classdef(classes);
00030
00031
00032
00033
00034
00035 #include <canon.h>
00036
00037 struct sbook *VerseKey::builtin_books[2] = {0,0};
00038 const char VerseKey::builtin_BMAX[2] = {39, 27};
00039 long *VerseKey::offsets[2][2] = {{VerseKey::otbks, VerseKey::otcps}, {VerseKey::ntbks, VerseKey::ntcps}};
00040 int VerseKey::instance = 0;
00041 VerseKey::LocaleCache VerseKey::localeCache;
00042
00043
00044
00045
00046
00047
00048 void VerseKey::init() {
00049 myclass = &classdef;
00050 if (!instance)
00051 initstatics();
00052
00053 instance++;
00054 autonorm = 1;
00055 headings = 0;
00056 upperBound = 0;
00057 lowerBound = 0;
00058 testament = 0;
00059 book = 0;
00060 chapter = 0;
00061 verse = 0;
00062 locale = 0;
00063
00064 setLocale(LocaleMgr::systemLocaleMgr.getDefaultLocaleName());
00065 }
00066
00067
00068
00069
00070
00071
00072
00073
00074 VerseKey::VerseKey(const SWKey *ikey) : SWKey(*ikey)
00075 {
00076 init();
00077 if (ikey)
00078 parse();
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 VerseKey::VerseKey(const char *ikey) : SWKey(ikey)
00090 {
00091 init();
00092 if (ikey)
00093 parse();
00094 }
00095
00096
00097 VerseKey::VerseKey(VerseKey const &k) : SWKey(k)
00098 {
00099 init();
00100 autonorm = k.autonorm;
00101 headings = k.headings;
00102 testament = k.Testament();
00103 book = k.Book();
00104 chapter = k.Chapter();
00105 verse = k.Verse();
00106 LowerBound(k.LowerBound());
00107 UpperBound(k.UpperBound());
00108 }
00109
00110
00111 VerseKey::VerseKey(const char *min, const char *max) : SWKey()
00112 {
00113 init();
00114 LowerBound(min);
00115 UpperBound(max);
00116 setPosition(TOP);
00117 }
00118
00119
00120 SWKey *VerseKey::clone() const
00121 {
00122 return new VerseKey(*this);
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132 VerseKey::~VerseKey() {
00133 if (upperBound)
00134 delete upperBound;
00135 if (lowerBound)
00136 delete lowerBound;
00137 if (locale)
00138 delete [] locale;
00139
00140 --instance;
00141 }
00142
00143
00144 void VerseKey::setLocale(const char *name) {
00145 char *BMAX;
00146 struct sbook **books;
00147 bool useCache = false;
00148
00149 if (localeCache.name)
00150 useCache = (!strcmp(localeCache.name, name));
00151
00152 if (!useCache) {
00153 stdstr(&(localeCache.name), name);
00154 localeCache.abbrevsCnt = 0;
00155 }
00156
00157 SWLocale *locale = (useCache) ? localeCache.locale : LocaleMgr::systemLocaleMgr.getLocale(name);
00158 localeCache.locale = locale;
00159
00160 if (locale) {
00161 locale->getBooks(&BMAX, &books);
00162 setBooks(BMAX, books);
00163 setBookAbbrevs(locale->getBookAbbrevs(), localeCache.abbrevsCnt);
00164 localeCache.abbrevsCnt = abbrevsCnt;
00165 }
00166 else {
00167 setBooks(builtin_BMAX, builtin_books);
00168 setBookAbbrevs(builtin_abbrevs, localeCache.abbrevsCnt);
00169 localeCache.abbrevsCnt = abbrevsCnt;
00170 }
00171 stdstr(&(this->locale), localeCache.name);
00172 }
00173
00174
00175 void VerseKey::setBooks(const char *iBMAX, struct sbook **ibooks) {
00176 BMAX = iBMAX;
00177 books = ibooks;
00178 }
00179
00180
00181 void VerseKey::setBookAbbrevs(const struct abbrev *bookAbbrevs, unsigned int size) {
00182 abbrevs = bookAbbrevs;
00183 if (!size) {
00184 for (abbrevsCnt = 1; *abbrevs[abbrevsCnt].ab; abbrevsCnt++) {
00185
00186
00187
00188
00189
00190
00191 }
00192 for (int t = 0; t < 2; t++) {
00193 for (int i = 0; i < BMAX[t]; i++) {
00194 int bn = getBookAbbrev(books[t][i].name);
00195 if ((bn-1)%39 != i) {
00196 SWLog::systemlog->LogError("Book: %s does not have a matching toupper abbrevs entry! book number returned was: %d", books[t][i].name, bn);
00197 }
00198 }
00199 }
00200 }
00201 else abbrevsCnt = size;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210 void VerseKey::initstatics() {
00211 int l1, l2, chaptmp = 0;
00212
00213 builtin_books[0] = otbooks;
00214 builtin_books[1] = ntbooks;
00215
00216 for (l1 = 0; l1 < 2; l1++) {
00217 for (l2 = 0; l2 < builtin_BMAX[l1]; l2++) {
00218 builtin_books[l1][l2].versemax = &vm[chaptmp];
00219 chaptmp += builtin_books[l1][l2].chapmax;
00220 }
00221 }
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231 char VerseKey::parse()
00232 {
00233
00234
00235 testament = 1;
00236 book = 1;
00237 chapter = 1;
00238 verse = 1;
00239
00240 error = 0;
00241
00242 if (keytext) {
00243 ListKey tmpListKey = VerseKey::ParseVerseList(keytext);
00244 if (tmpListKey.Count()) {
00245 SWKey::setText((const char *)tmpListKey);
00246 for (testament = 1; testament < 3; testament++) {
00247 for (book = 1; book <= BMAX[testament-1]; book++) {
00248 if (!strncmp(keytext, books[testament-1][book-1].name, strlen(books[testament-1][book-1].name)))
00249 break;
00250 }
00251 if (book <= BMAX[testament-1])
00252 break;
00253 }
00254
00255 if (testament < 3) {
00256 sscanf(&keytext[strlen(books[testament-1][book-1].name)], "%d:%d", &chapter, &verse);
00257 }
00258 else error = 1;
00259 }
00260 }
00261 Normalize(1);
00262 freshtext();
00263
00264 return error;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 void VerseKey::freshtext() const
00274 {
00275 char buf[2024];
00276 int realtest = testament;
00277 int realbook = book;
00278
00279 if (book < 1) {
00280 if (testament < 1)
00281 sprintf(buf, "[ Module Heading ]");
00282 else sprintf(buf, "[ Testament %d Heading ]", (int)testament);
00283 }
00284 else {
00285 if (realbook > BMAX[realtest-1]) {
00286 realbook -= BMAX[realtest-1];
00287 if (realtest < 2)
00288 realtest++;
00289 if (realbook > BMAX[realtest-1])
00290 realbook = BMAX[realtest-1];
00291 }
00292 sprintf(buf, "%s %d:%d", books[realtest-1][realbook-1].name, chapter, verse);
00293 }
00294
00295 stdstr((char **)&keytext, buf);
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 int VerseKey::getBookAbbrev(const char *iabbr)
00308 {
00309 int loop, diff, abLen, min, max, target, retVal = -1;
00310
00311 char *abbr = 0;
00312
00313 stdstr(&abbr, iabbr);
00314 strstrip(abbr);
00315 abLen = strlen(abbr);
00316 for (loop = 0; loop < abLen; loop++)
00317 abbr[loop] = SW_toupper(abbr[loop]);
00318
00319 if (abLen) {
00320 min = 0;
00321
00322 max = abbrevsCnt;
00323 while(1) {
00324 target = min + ((max - min) / 2);
00325 diff = strncmp(abbr, abbrevs[target].ab, abLen);
00326 if ((!diff)||(target >= max)||(target <= min))
00327 break;
00328 if (diff > 0)
00329 min = target;
00330 else max = target;
00331 }
00332 for (; target > 0; target--) {
00333 if (strncmp(abbr, abbrevs[target-1].ab, abLen))
00334 break;
00335 }
00336
00337 retVal = (!diff) ? abbrevs[target].book : -1;
00338 }
00339 delete [] abbr;
00340 return retVal;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool expandRange) {
00360 SWKey textkey;
00361
00362 char book[255];
00363 char number[255];
00364 int tobook = 0;
00365 int tonumber = 0;
00366 int chap = -1, verse = -1;
00367 int bookno = 0;
00368 VerseKey curkey, lBound;
00369 curkey.setLocale(getLocale());
00370 lBound.setLocale(getLocale());
00371 int loop;
00372 char comma = 0;
00373 char dash = 0;
00374 const char *orig = buf;
00375 ListKey tmpListKey;
00376 ListKey internalListKey;
00377 SWKey tmpDefaultKey = defaultKey;
00378 char lastPartial = 0;
00379
00380 curkey.AutoNormalize(0);
00381 tmpListKey << tmpDefaultKey;
00382 tmpListKey.GetElement()->userData = (void *)buf;
00383
00384 while (*buf) {
00385 switch (*buf) {
00386 case ':':
00387 number[tonumber] = 0;
00388 tonumber = 0;
00389 if (*number)
00390 chap = atoi(number);
00391 *number = 0;
00392 break;
00393
00394 case '-':
00395 case ',':
00396 case ';':
00397 number[tonumber] = 0;
00398 tonumber = 0;
00399 if (*number) {
00400 if (chap >= 0)
00401 verse = atoi(number);
00402 else chap = atoi(number);
00403 }
00404 *number = 0;
00405 book[tobook] = 0;
00406 tobook = 0;
00407 bookno = -1;
00408 if (*book) {
00409 for (loop = strlen(book) - 1; loop+1; loop--) {
00410 if ((isdigit(book[loop])) || (book[loop] == ' ')) {
00411 book[loop] = 0;
00412 continue;
00413 }
00414 else {
00415 if ((SW_toupper(book[loop])=='F')&&(loop)) {
00416 if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) {
00417 book[loop] = 0;
00418 continue;
00419 }
00420 }
00421 }
00422 break;
00423 }
00424
00425 for (loop = strlen(book) - 1; loop+1; loop--) {
00426 if (book[loop] == ' ') {
00427 if (isroman(&book[loop+1])) {
00428 if (verse == -1) {
00429 verse = chap;
00430 chap = from_rom(&book[loop+1]);
00431 book[loop] = 0;
00432 }
00433 }
00434 break;
00435 }
00436 }
00437
00438 if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) {
00439 if (verse == -1) {
00440 verse = chap;
00441 chap = VerseKey(tmpListKey).Chapter();
00442 *book = 0;
00443 }
00444 }
00445 bookno = getBookAbbrev(book);
00446 }
00447 if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) {
00448 char partial = 0;
00449 curkey.Verse(1);
00450 curkey.Chapter(1);
00451 curkey.Book(1);
00452
00453 if (bookno < 0) {
00454 curkey.Testament(VerseKey(tmpListKey).Testament());
00455 curkey.Book(VerseKey(tmpListKey).Book());
00456 }
00457 else {
00458 curkey.Testament(1);
00459 curkey.Book(bookno);
00460 }
00461
00462 if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) {
00463
00464 curkey.Chapter(VerseKey(tmpListKey).Chapter());
00465 curkey.Verse(chap);
00466 }
00467 else {
00468 if (chap >= 0) {
00469 curkey.Chapter(chap);
00470 }
00471 else {
00472 partial++;
00473 curkey.Chapter(1);
00474 }
00475 if (verse >= 0) {
00476 curkey.Verse(verse);
00477 }
00478 else {
00479 partial++;
00480 curkey.Verse(1);
00481 }
00482 }
00483
00484 if ((*buf == '-') && (expandRange)) {
00485 VerseKey newElement;
00486 newElement.LowerBound(curkey);
00487 newElement.setPosition(TOP);
00488 tmpListKey << newElement;
00489 tmpListKey.GetElement()->userData = (void *)buf;
00490 }
00491 else {
00492 if (!dash) {
00493 if (expandRange && partial) {
00494 VerseKey newElement;
00495 newElement.LowerBound(curkey);
00496 if (partial > 1)
00497 curkey.setPosition(MAXCHAPTER);
00498 if (partial > 0)
00499 curkey = MAXVERSE;
00500 newElement.UpperBound(curkey);
00501 newElement = TOP;
00502 tmpListKey << newElement;
00503 tmpListKey.GetElement()->userData = (void *)buf;
00504 }
00505 else {
00506 tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey;
00507 tmpListKey.GetElement()->userData = (void *)buf;
00508 }
00509 }
00510 else if (expandRange) {
00511 VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement());
00512 if (newElement) {
00513 if (partial > 1)
00514 curkey = MAXCHAPTER;
00515 if (partial > 0)
00516 curkey = MAXVERSE;
00517 newElement->UpperBound(curkey);
00518 *newElement = TOP;
00519 tmpListKey.GetElement()->userData = (void *)buf;
00520 }
00521 }
00522 }
00523 lastPartial = partial;
00524 }
00525 *book = 0;
00526 chap = -1;
00527 verse = -1;
00528 if (*buf == ',')
00529 comma = 1;
00530 else comma = 0;
00531 if (*buf == '-')
00532 dash = 1;
00533 else dash = 0;
00534 break;
00535 case 10:
00536 case 13:
00537 break;
00538 case '.':
00539 if (buf > orig)
00540 if (!isdigit(*(buf-1)))
00541 break;
00542
00543 default:
00544 if (isdigit(*buf)) {
00545 number[tonumber++] = *buf;
00546 }
00547 else {
00548 switch (*buf) {
00549 case ' ':
00550 case 'f':
00551 case 'F':
00552 break;
00553 default:
00554 number[tonumber] = 0;
00555 tonumber = 0;
00556 break;
00557 }
00558 }
00559 if (chap == -1)
00560 book[tobook++] = SW_toupper(*buf);
00561 }
00562 buf++;
00563 }
00564 number[tonumber] = 0;
00565 tonumber = 0;
00566 if (*number) {
00567 if (chap >= 0)
00568 verse = atoi(number);
00569 else chap = atoi(number);
00570 }
00571 *number = 0;
00572 book[tobook] = 0;
00573 tobook = 0;
00574 if (*book) {
00575 for (loop = strlen(book) - 1; loop+1; loop--) {
00576 if ((isdigit(book[loop])) || (book[loop] == ' ')) {
00577 book[loop] = 0;
00578 continue;
00579 }
00580 else {
00581 if ((SW_toupper(book[loop])=='F')&&(loop)) {
00582 if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) {
00583 book[loop] = 0;
00584 continue;
00585 }
00586 }
00587 }
00588 break;
00589 }
00590
00591 for (loop = strlen(book) - 1; loop+1; loop--) {
00592 if (book[loop] == ' ') {
00593 if (isroman(&book[loop+1])) {
00594 if (verse == -1) {
00595 verse = chap;
00596 chap = from_rom(&book[loop+1]);
00597 book[loop] = 0;
00598 }
00599 }
00600 break;
00601 }
00602 }
00603
00604 if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) {
00605 if (verse == -1) {
00606 verse = chap;
00607 chap = VerseKey(tmpListKey).Chapter();
00608 *book = 0;
00609 }
00610 }
00611
00612 bookno = getBookAbbrev(book);
00613 }
00614 if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) {
00615 char partial = 0;
00616 curkey.Verse(1);
00617 curkey.Chapter(1);
00618 curkey.Book(1);
00619
00620 if (bookno < 0) {
00621 curkey.Testament(VerseKey(tmpListKey).Testament());
00622 curkey.Book(VerseKey(tmpListKey).Book());
00623 }
00624 else {
00625 curkey.Testament(1);
00626 curkey.Book(bookno);
00627 }
00628
00629 if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) {
00630
00631 curkey.Chapter(VerseKey(tmpListKey).Chapter());
00632 curkey.Verse(chap);
00633 }
00634 else {
00635 if (chap >= 0) {
00636 curkey.Chapter(chap);
00637 }
00638 else {
00639 partial++;
00640 curkey.Chapter(1);
00641 }
00642 if (verse >= 0) {
00643 curkey.Verse(verse);
00644 }
00645 else {
00646 partial++;
00647 curkey.Verse(1);
00648 }
00649 }
00650
00651 if ((*buf == '-') && (expandRange)) {
00652 VerseKey newElement;
00653 newElement.LowerBound(curkey);
00654 newElement = TOP;
00655 tmpListKey << newElement;
00656 tmpListKey.GetElement()->userData = (void *)buf;
00657 }
00658 else {
00659 if (!dash) {
00660 if (expandRange && partial) {
00661 VerseKey newElement;
00662 newElement.LowerBound(curkey);
00663 if (partial > 1)
00664 curkey = MAXCHAPTER;
00665 if (partial > 0)
00666 curkey = MAXVERSE;
00667 newElement.UpperBound(curkey);
00668 newElement = TOP;
00669 tmpListKey << newElement;
00670 tmpListKey.GetElement()->userData = (void *)buf;
00671 }
00672 else {
00673 tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey;
00674 tmpListKey.GetElement()->userData = (void *)buf;
00675 }
00676 }
00677 else if (expandRange) {
00678 VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement());
00679 if (newElement) {
00680 if (partial > 1)
00681 curkey = MAXCHAPTER;
00682 if (partial > 0)
00683 curkey = MAXVERSE;
00684 newElement->UpperBound(curkey);
00685 *newElement = TOP;
00686 tmpListKey.GetElement()->userData = (void *)buf;
00687 }
00688 }
00689 }
00690 }
00691 *book = 0;
00692 tmpListKey = TOP;
00693 tmpListKey.Remove();
00694 internalListKey = tmpListKey;
00695 internalListKey = TOP;
00696
00697 return internalListKey;
00698 }
00699
00700
00701
00702
00703
00704
00705 VerseKey &VerseKey::LowerBound(const char *lb)
00706 {
00707 if (!lowerBound)
00708 initBounds();
00709
00710 (*lowerBound) = lb;
00711 lowerBound->Normalize();
00712
00713 return (*lowerBound);
00714 }
00715
00716
00717
00718
00719
00720
00721 VerseKey &VerseKey::UpperBound(const char *ub)
00722 {
00723 if (!upperBound)
00724 initBounds();
00725
00726
00727 (*upperBound) = ub;
00728 if (*upperBound < *lowerBound)
00729 *upperBound = *lowerBound;
00730 upperBound->Normalize();
00731
00732
00733 int len = strlen(ub);
00734 bool alpha = false;
00735 bool versespec = false;
00736 bool chapspec = false;
00737 for (int i = 0; i < len; i++) {
00738 if (isalpha(ub[i]))
00739 alpha = true;
00740 if (ub[i] == ':')
00741 versespec = true;
00742 if ((isdigit(ub[i])) && (alpha))
00743 chapspec = true;
00744 }
00745 if (!chapspec)
00746 *upperBound = MAXCHAPTER;
00747 if (!versespec)
00748 *upperBound = MAXVERSE;
00749
00750
00751
00752
00753 return (*upperBound);
00754 }
00755
00756
00757
00758
00759
00760
00761 VerseKey &VerseKey::LowerBound() const
00762 {
00763 if (!lowerBound)
00764 initBounds();
00765
00766 return (*lowerBound);
00767 }
00768
00769
00770
00771
00772
00773
00774 VerseKey &VerseKey::UpperBound() const
00775 {
00776 if (!upperBound)
00777 initBounds();
00778
00779 return (*upperBound);
00780 }
00781
00782
00783
00784
00785
00786
00787 void VerseKey::ClearBounds()
00788 {
00789 initBounds();
00790 }
00791
00792
00793 void VerseKey::initBounds() const
00794 {
00795 if (!upperBound) {
00796 upperBound = new VerseKey();
00797 upperBound->AutoNormalize(0);
00798 upperBound->Headings(1);
00799 }
00800 if (!lowerBound) {
00801 lowerBound = new VerseKey();
00802 lowerBound->AutoNormalize(0);
00803 lowerBound->Headings(1);
00804 }
00805
00806 lowerBound->Testament(0);
00807 lowerBound->Book(0);
00808 lowerBound->Chapter(0);
00809 lowerBound->Verse(0);
00810
00811 upperBound->Testament(2);
00812 upperBound->Book(BMAX[1]);
00813 upperBound->Chapter(books[1][BMAX[1]-1].chapmax);
00814 upperBound->Verse(books[1][BMAX[1]-1].versemax[upperBound->Chapter()-1]);
00815 }
00816
00817
00818
00819
00820
00821
00822 void VerseKey::copyFrom(const VerseKey &ikey) {
00823 SWKey::copyFrom(ikey);
00824
00825 parse();
00826 }
00827
00828
00829
00830
00831
00832
00833 void VerseKey::copyFrom(const SWKey &ikey) {
00834 SWKey::copyFrom(ikey);
00835
00836 parse();
00837 }
00838
00839
00840
00841
00842
00843
00844
00845 const char *VerseKey::getText() const {
00846 freshtext();
00847 return keytext;
00848 }
00849
00850
00851 const char *VerseKey::getShortText() const {
00852 static char *stext = 0;
00853 char buf[2047];
00854 freshtext();
00855 if (book < 1) {
00856 if (testament < 1)
00857 sprintf(buf, "[ Module Heading ]");
00858 else sprintf(buf, "[ Testament %d Heading ]", (int)testament);
00859 }
00860 else {
00861 sprintf(buf, "%s %d:%d", books[testament-1][book-1].prefAbbrev, chapter, verse);
00862 }
00863 stdstr(&stext, buf);
00864 return stext;
00865 }
00866
00867
00868 const char *VerseKey::getBookName() const {
00869 return books[testament-1][book-1].name;
00870 }
00871
00872
00873 const char *VerseKey::getBookAbbrev() const {
00874 return books[testament-1][book-1].prefAbbrev;
00875 }
00876
00877
00878
00879
00880
00881
00882
00883
00884 void VerseKey::setPosition(SW_POSITION p) {
00885 switch (p) {
00886 case POS_TOP:
00887 testament = LowerBound().Testament();
00888 book = LowerBound().Book();
00889 chapter = LowerBound().Chapter();
00890 verse = LowerBound().Verse();
00891 break;
00892 case POS_BOTTOM:
00893 testament = UpperBound().Testament();
00894 book = UpperBound().Book();
00895 chapter = UpperBound().Chapter();
00896 verse = UpperBound().Verse();
00897 break;
00898 case POS_MAXVERSE:
00899 Normalize();
00900 verse = books[testament-1][book-1].versemax[chapter-1];
00901 break;
00902 case POS_MAXCHAPTER:
00903 verse = 1;
00904 Normalize();
00905 chapter = books[testament-1][book-1].chapmax;
00906 break;
00907 }
00908 Normalize(1);
00909 Error();
00910 }
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921 void VerseKey::increment(int step) {
00922 char ierror = 0;
00923 Index(Index() + step);
00924 while ((!verse) && (!headings) && (!ierror)) {
00925 Index(Index() + 1);
00926 ierror = Error();
00927 }
00928
00929 error = (ierror) ? ierror : error;
00930 }
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941 void VerseKey::decrement(int step) {
00942 char ierror = 0;
00943
00944 Index(Index() - step);
00945 while ((!verse) && (!headings) && (!ierror)) {
00946 Index(Index() - 1);
00947 ierror = Error();
00948 }
00949 if ((ierror) && (!headings))
00950 (*this)++;
00951
00952 error = (ierror) ? ierror : error;
00953 }
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963 void VerseKey::Normalize(char autocheck)
00964 {
00965 error = 0;
00966
00967 if ((autocheck) && (!autonorm))
00968 return;
00969
00970 if ((headings) && (!verse))
00971 return;
00972
00973 while ((testament < 3) && (testament > 0)) {
00974
00975 if (book > BMAX[testament-1]) {
00976 book -= BMAX[testament-1];
00977 testament++;
00978 continue;
00979 }
00980
00981 if (book < 1) {
00982 if (--testament > 0) {
00983 book += BMAX[testament-1];
00984 }
00985 continue;
00986 }
00987
00988 if (chapter > books[testament-1][book-1].chapmax) {
00989 chapter -= books[testament-1][book-1].chapmax;
00990 book++;
00991 continue;
00992 }
00993
00994 if (chapter < 1) {
00995 if (--book > 0) {
00996 chapter += books[testament-1][book-1].chapmax;
00997 }
00998 else {
00999 if (testament > 1) {
01000 chapter += books[0][BMAX[0]-1].chapmax;
01001 }
01002 }
01003 continue;
01004 }
01005
01006 if (verse > books[testament-1][book-1].versemax[chapter-1]) {
01007 verse -= books[testament-1][book-1].versemax[chapter++ - 1];
01008 continue;
01009 }
01010
01011 if (verse < 1) {
01012 if (--chapter > 0) {
01013 verse += books[testament-1][book-1].versemax[chapter-1];
01014 }
01015 else {
01016 if (book > 1) {
01017 verse += books[testament-1][book-2].versemax[books[testament-1][book-2].chapmax-1];
01018 }
01019 else {
01020 if (testament > 1) {
01021 verse += books[0][BMAX[0]-1].versemax[books[0][BMAX[0]-1].chapmax-1];
01022 }
01023 }
01024 }
01025 continue;
01026 }
01027
01028 break;
01029 }
01030
01031 if (testament > 2) {
01032 testament = 2;
01033 book = BMAX[testament-1];
01034 chapter = books[testament-1][book-1].chapmax;
01035 verse = books[testament-1][book-1].versemax[chapter-1];
01036 error = KEYERR_OUTOFBOUNDS;
01037 }
01038
01039 if (testament < 1) {
01040 error = ((!headings) || (testament < 0) || (book < 0)) ? KEYERR_OUTOFBOUNDS : 0;
01041 testament = ((headings) ? 0 : 1);
01042 book = ((headings) ? 0 : 1);
01043 chapter = ((headings) ? 0 : 1);
01044 verse = ((headings) ? 0 : 1);
01045 }
01046 if (_compare(UpperBound()) > 0) {
01047 *this = UpperBound();
01048 error = KEYERR_OUTOFBOUNDS;
01049 }
01050 if (_compare(LowerBound()) < 0) {
01051 *this = LowerBound();
01052 error = KEYERR_OUTOFBOUNDS;
01053 }
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063 char VerseKey::Testament() const
01064 {
01065 return testament;
01066 }
01067
01068
01069
01070
01071
01072
01073
01074
01075 char VerseKey::Book() const
01076 {
01077 return book;
01078 }
01079
01080
01081
01082
01083
01084
01085
01086
01087 int VerseKey::Chapter() const
01088 {
01089 return chapter;
01090 }
01091
01092
01093
01094
01095
01096
01097
01098
01099 int VerseKey::Verse() const
01100 {
01101 return verse;
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115 char VerseKey::Testament(char itestament)
01116 {
01117 char retval = testament;
01118
01119 if (itestament != MAXPOS(char)) {
01120 testament = itestament;
01121 Normalize(1);
01122 }
01123 return retval;
01124 }
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137 char VerseKey::Book(char ibook)
01138 {
01139 char retval = book;
01140
01141 Chapter(1);
01142 book = ibook;
01143 Normalize(1);
01144
01145 return retval;
01146 }
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159 int VerseKey::Chapter(int ichapter)
01160 {
01161 int retval = chapter;
01162
01163 Verse(1);
01164 chapter = ichapter;
01165 Normalize(1);
01166
01167 return retval;
01168 }
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181 int VerseKey::Verse(int iverse)
01182 {
01183 int retval = verse;
01184
01185 verse = iverse;
01186 Normalize(1);
01187
01188 return retval;
01189 }
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203 char VerseKey::AutoNormalize(char iautonorm)
01204 {
01205 char retval = autonorm;
01206
01207 if (iautonorm != MAXPOS(char)) {
01208 autonorm = iautonorm;
01209 Normalize(1);
01210 }
01211 return retval;
01212 }
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226 char VerseKey::Headings(char iheadings)
01227 {
01228 char retval = headings;
01229
01230 if (iheadings != MAXPOS(char)) {
01231 headings = iheadings;
01232 Normalize(1);
01233 }
01234 return retval;
01235 }
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 int VerseKey::findindex(long *array, int size, long value)
01250 {
01251 int lbound, ubound, tval;
01252
01253 lbound = 0;
01254 ubound = size - 1;
01255 while ((ubound - lbound) > 1) {
01256 tval = lbound + (ubound-lbound)/2;
01257 if (array[tval] <= value)
01258 lbound = tval;
01259 else ubound = tval;
01260 }
01261 return (array[ubound] <= value) ? ubound : lbound;
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271 long VerseKey::Index() const
01272 {
01273 long offset;
01274
01275 if (!testament) {
01276 offset = 0;
01277 verse = 0;
01278 }
01279 else {
01280 if (!book)
01281 chapter = 0;
01282 if (!chapter)
01283 verse = 0;
01284
01285 offset = offsets[testament-1][0][book];
01286 offset = offsets[testament-1][1][(int)offset + chapter];
01287 if (!(offset|verse))
01288 offset = 1;
01289 }
01290 return (offset + verse);
01291 }
01292
01293
01294
01295
01296
01297
01298
01299
01300 long VerseKey::NewIndex() const
01301 {
01302 static long otMaxIndex = 32300 - 8245;
01303
01304 return ((testament-1) * otMaxIndex) + Index();
01305 }
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316 long VerseKey::Index(long iindex)
01317 {
01318 long offset;
01319
01320
01321
01322 if (!testament)
01323 testament = 1;
01324
01325 if (iindex < 1) {
01326 if (testament < 2) {
01327 if (iindex < 0) {
01328 testament = 0;
01329 error = KEYERR_OUTOFBOUNDS;
01330 }
01331 else testament = 0;
01332 }
01333 else {
01334 testament--;
01335 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;
01336 }
01337 }
01338
01339
01340
01341
01342 if (testament) {
01343 if ((!error) && (iindex)) {
01344 offset = findindex(offsets[testament-1][1], offsize[testament-1][1], iindex);
01345 verse = iindex - offsets[testament-1][1][offset];
01346 book = findindex(offsets[testament-1][0], offsize[testament-1][0], offset);
01347 chapter = offset - offsets[testament-1][0][VerseKey::book];
01348 verse = (chapter) ? verse : 0;
01349 if (verse) {
01350 if (verse > books[testament-1][book-1].versemax[chapter-1]) {
01351 if (testament > 1) {
01352 verse = books[testament-1][book-1].versemax[chapter-1];
01353 error = KEYERR_OUTOFBOUNDS;
01354 }
01355 else {
01356 testament++;
01357 Index(verse - books[testament-2][book-1].versemax[chapter-1]);
01358 }
01359 }
01360 }
01361 }
01362 }
01363 if (_compare(UpperBound()) > 0) {
01364 *this = UpperBound();
01365 error = KEYERR_OUTOFBOUNDS;
01366 }
01367 if (_compare(LowerBound()) < 0) {
01368 *this = LowerBound();
01369 error = KEYERR_OUTOFBOUNDS;
01370 }
01371 return Index();
01372 }
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385 int VerseKey::compare(const SWKey &ikey)
01386 {
01387 VerseKey ivkey = (const char *)ikey;
01388 return _compare(ivkey);
01389 }
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402 int VerseKey::_compare(const VerseKey &ivkey)
01403 {
01404 long keyval1 = 0;
01405 long keyval2 = 0;
01406
01407 keyval1 += Testament() * 1000000000;
01408 keyval2 += ivkey.Testament() * 1000000000;
01409 keyval1 += Book() * 1000000;
01410 keyval2 += ivkey.Book() * 1000000;
01411 keyval1 += Chapter() * 1000;
01412 keyval2 += ivkey.Chapter() * 1000;
01413 keyval1 += Verse();
01414 keyval2 += ivkey.Verse();
01415 keyval1 -= keyval2;
01416 keyval1 = (keyval1) ? ((keyval1 > 0) ? 1 : -1) :0;
01417 return keyval1;
01418 }
01419
01420
01421 const char *VerseKey::getOSISRef() const {
01422 static char buf[5][254];
01423 static char loop = 0;
01424
01425 if (loop > 4)
01426 loop = 0;
01427
01428 static char *osisotbooks[] = {
01429 "Gen","Exod","Lev","Num","Deut","Josh","Judg","Ruth","_1Sam","_2Sam",
01430 "_1Kgs","_2Kgs","_1Chr","_2Chr","Ezra","Neh","Esth","Job","Ps",
01431 "Prov",
01432 "Eccl",
01433 "Song","Isa","Jer","Lam","Ezek","Dan","Hos","Joel","Amos","Obad",
01434 "Jonah","Mic","Nah","Hab","Zeph","Hag","Zech","Mal","Bar","PrAzar",
01435 "Bel","Sus","_1Esd","_2Esd","AddEsth","EpJer","Jdt","_1Macc","_2Macc","_3Macc",
01436 "_4Macc","PrMan","Ps151","Sir","Tob","Wis"};
01437 static char *osisntbooks[] = {
01438 "Matt","Mark","Luke","John","Acts","Rom","_1Cor","_2Cor","Gal","Eph",
01439 "Phil","Col","_1Thess","_2Thess","_1Tim","_2Tim","Titus","Phlm","Heb","Jas",
01440 "_1Pet","_2Pet","_1John","_2John","_3John","Jude","Rev"};
01441 static char **osisbooks[] = { osisotbooks, osisntbooks };
01442 if (Verse())
01443 sprintf(buf[loop], "%s.%d.%d", osisbooks[Testament()-1][Book()-1], (int)Chapter(), (int)Verse());
01444 else if (Chapter())
01445 sprintf(buf[loop], "%s.%d", osisbooks[Testament()-1][Book()-1], (int)Chapter());
01446 else if (Book())
01447 sprintf(buf[loop], "%s", osisbooks[Testament()-1][Book()-1]);
01448 else sprintf(buf[loop], "");
01449 return buf[loop++];
01450 }