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.keytext)
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
00383 while (*buf) {
00384 switch (*buf) {
00385 case ':':
00386 number[tonumber] = 0;
00387 tonumber = 0;
00388 if (*number)
00389 chap = atoi(number);
00390 *number = 0;
00391 break;
00392
00393 case '-':
00394 case ',':
00395 case ';':
00396 number[tonumber] = 0;
00397 tonumber = 0;
00398 if (*number) {
00399 if (chap >= 0)
00400 verse = atoi(number);
00401 else chap = atoi(number);
00402 }
00403 *number = 0;
00404 book[tobook] = 0;
00405 tobook = 0;
00406 bookno = -1;
00407 if (*book) {
00408 for (loop = strlen(book) - 1; loop+1; loop--) {
00409 if ((isdigit(book[loop])) || (book[loop] == ' ')) {
00410 book[loop] = 0;
00411 continue;
00412 }
00413 else {
00414 if ((SW_toupper(book[loop])=='F')&&(loop)) {
00415 if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) {
00416 book[loop] = 0;
00417 continue;
00418 }
00419 }
00420 }
00421 break;
00422 }
00423
00424 for (loop = strlen(book) - 1; loop+1; loop--) {
00425 if (book[loop] == ' ') {
00426 if (isroman(&book[loop+1])) {
00427 if (verse == -1) {
00428 verse = chap;
00429 chap = from_rom(&book[loop+1]);
00430 book[loop] = 0;
00431 }
00432 }
00433 break;
00434 }
00435 }
00436
00437 if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) {
00438 if (verse == -1) {
00439 verse = chap;
00440 chap = VerseKey(tmpListKey).Chapter();
00441 *book = 0;
00442 }
00443 }
00444 bookno = getBookAbbrev(book);
00445 }
00446 if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) {
00447 char partial = 0;
00448 curkey.Verse(1);
00449 curkey.Chapter(1);
00450 curkey.Book(1);
00451
00452 if (bookno < 0) {
00453 curkey.Testament(VerseKey(tmpListKey).Testament());
00454 curkey.Book(VerseKey(tmpListKey).Book());
00455 }
00456 else {
00457 curkey.Testament(1);
00458 curkey.Book(bookno);
00459 }
00460
00461 if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) {
00462
00463 curkey.Chapter(VerseKey(tmpListKey).Chapter());
00464 curkey.Verse(chap);
00465 }
00466 else {
00467 if (chap >= 0) {
00468 curkey.Chapter(chap);
00469 }
00470 else {
00471 partial++;
00472 curkey.Chapter(1);
00473 }
00474 if (verse >= 0) {
00475 curkey.Verse(verse);
00476 }
00477 else {
00478 partial++;
00479 curkey.Verse(1);
00480 }
00481 }
00482
00483 if ((*buf == '-') && (expandRange)) {
00484 VerseKey newElement;
00485 newElement.LowerBound(curkey);
00486 newElement.setPosition(TOP);
00487 tmpListKey << newElement;
00488 }
00489 else {
00490 if (!dash) {
00491 if (expandRange && partial) {
00492 VerseKey newElement;
00493 newElement.LowerBound(curkey);
00494 if (partial > 1)
00495 curkey.setPosition(MAXCHAPTER);
00496 if (partial > 0)
00497 curkey = MAXVERSE;
00498 newElement.UpperBound(curkey);
00499 newElement = TOP;
00500 tmpListKey << newElement;
00501 }
00502 else tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey;
00503 }
00504 else if (expandRange) {
00505 VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement());
00506 if (newElement) {
00507 if (partial > 1)
00508 curkey = MAXCHAPTER;
00509 if (partial > 0)
00510 curkey = MAXVERSE;
00511 newElement->UpperBound(curkey);
00512 *newElement = TOP;
00513 }
00514 }
00515 }
00516 lastPartial = partial;
00517 }
00518 *book = 0;
00519 chap = -1;
00520 verse = -1;
00521 if (*buf == ',')
00522 comma = 1;
00523 else comma = 0;
00524 if (*buf == '-')
00525 dash = 1;
00526 else dash = 0;
00527 break;
00528 case 10:
00529 case 13:
00530 break;
00531 case '.':
00532 if (buf > orig)
00533 if (!isdigit(*(buf-1)))
00534 break;
00535
00536 default:
00537 if (isdigit(*buf)) {
00538 number[tonumber++] = *buf;
00539 }
00540 else {
00541 switch (*buf) {
00542 case ' ':
00543 case 'f':
00544 case 'F':
00545 break;
00546 default:
00547 number[tonumber] = 0;
00548 tonumber = 0;
00549 break;
00550 }
00551 }
00552 if (chap == -1)
00553 book[tobook++] = SW_toupper(*buf);
00554 }
00555 buf++;
00556 }
00557 number[tonumber] = 0;
00558 tonumber = 0;
00559 if (*number) {
00560 if (chap >= 0)
00561 verse = atoi(number);
00562 else chap = atoi(number);
00563 }
00564 *number = 0;
00565 book[tobook] = 0;
00566 tobook = 0;
00567 if (*book) {
00568 for (loop = strlen(book) - 1; loop+1; loop--) {
00569 if ((isdigit(book[loop])) || (book[loop] == ' ')) {
00570 book[loop] = 0;
00571 continue;
00572 }
00573 else {
00574 if ((SW_toupper(book[loop])=='F')&&(loop)) {
00575 if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) {
00576 book[loop] = 0;
00577 continue;
00578 }
00579 }
00580 }
00581 break;
00582 }
00583
00584 for (loop = strlen(book) - 1; loop+1; loop--) {
00585 if (book[loop] == ' ') {
00586 if (isroman(&book[loop+1])) {
00587 if (verse == -1) {
00588 verse = chap;
00589 chap = from_rom(&book[loop+1]);
00590 book[loop] = 0;
00591 }
00592 }
00593 break;
00594 }
00595 }
00596
00597 if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) {
00598 if (verse == -1) {
00599 verse = chap;
00600 chap = VerseKey(tmpListKey).Chapter();
00601 *book = 0;
00602 }
00603 }
00604
00605 bookno = getBookAbbrev(book);
00606 }
00607 if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) {
00608 char partial = 0;
00609 curkey.Verse(1);
00610 curkey.Chapter(1);
00611 curkey.Book(1);
00612
00613 if (bookno < 0) {
00614 curkey.Testament(VerseKey(tmpListKey).Testament());
00615 curkey.Book(VerseKey(tmpListKey).Book());
00616 }
00617 else {
00618 curkey.Testament(1);
00619 curkey.Book(bookno);
00620 }
00621
00622 if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) {
00623
00624 curkey.Chapter(VerseKey(tmpListKey).Chapter());
00625 curkey.Verse(chap);
00626 }
00627 else {
00628 if (chap >= 0) {
00629 curkey.Chapter(chap);
00630 }
00631 else {
00632 partial++;
00633 curkey.Chapter(1);
00634 }
00635 if (verse >= 0) {
00636 curkey.Verse(verse);
00637 }
00638 else {
00639 partial++;
00640 curkey.Verse(1);
00641 }
00642 }
00643
00644 if ((*buf == '-') && (expandRange)) {
00645 VerseKey newElement;
00646 newElement.LowerBound(curkey);
00647 newElement = TOP;
00648 tmpListKey << newElement;
00649 }
00650 else {
00651 if (!dash) {
00652 if (expandRange && partial) {
00653 VerseKey newElement;
00654 newElement.LowerBound(curkey);
00655 if (partial > 1)
00656 curkey = MAXCHAPTER;
00657 if (partial > 0)
00658 curkey = MAXVERSE;
00659 newElement.UpperBound(curkey);
00660 newElement = TOP;
00661 tmpListKey << newElement;
00662 }
00663 else tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey;
00664 }
00665 else if (expandRange) {
00666 VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement());
00667 if (newElement) {
00668 if (partial > 1)
00669 curkey = MAXCHAPTER;
00670 if (partial > 0)
00671 curkey = MAXVERSE;
00672 newElement->UpperBound(curkey);
00673 *newElement = TOP;
00674 }
00675 }
00676 }
00677 }
00678 *book = 0;
00679 tmpListKey = TOP;
00680 tmpListKey.Remove();
00681 internalListKey = tmpListKey;
00682 internalListKey = TOP;
00683
00684 return internalListKey;
00685 }
00686
00687
00688
00689
00690
00691
00692 VerseKey &VerseKey::LowerBound(const char *lb)
00693 {
00694 if (!lowerBound)
00695 initBounds();
00696
00697 (*lowerBound) = lb;
00698 lowerBound->Normalize();
00699
00700 return (*lowerBound);
00701 }
00702
00703
00704
00705
00706
00707
00708 VerseKey &VerseKey::UpperBound(const char *ub)
00709 {
00710 if (!upperBound)
00711 initBounds();
00712
00713
00714 (*upperBound) = ub;
00715 if (*upperBound < *lowerBound)
00716 *upperBound = *lowerBound;
00717 upperBound->Normalize();
00718
00719
00720 int len = strlen(ub);
00721 bool alpha = false;
00722 bool versespec = false;
00723 bool chapspec = false;
00724 for (int i = 0; i < len; i++) {
00725 if (isalpha(ub[i]))
00726 alpha = true;
00727 if (ub[i] == ':')
00728 versespec = true;
00729 if ((isdigit(ub[i])) && (alpha))
00730 chapspec = true;
00731 }
00732 if (!chapspec)
00733 *upperBound = MAXCHAPTER;
00734 if (!versespec)
00735 *upperBound = MAXVERSE;
00736
00737
00738
00739
00740 return (*upperBound);
00741 }
00742
00743
00744
00745
00746
00747
00748 VerseKey &VerseKey::LowerBound() const
00749 {
00750 if (!lowerBound)
00751 initBounds();
00752
00753 return (*lowerBound);
00754 }
00755
00756
00757
00758
00759
00760
00761 VerseKey &VerseKey::UpperBound() const
00762 {
00763 if (!upperBound)
00764 initBounds();
00765
00766 return (*upperBound);
00767 }
00768
00769
00770
00771
00772
00773
00774 void VerseKey::ClearBounds()
00775 {
00776 initBounds();
00777 }
00778
00779
00780 void VerseKey::initBounds() const
00781 {
00782 if (!upperBound) {
00783 upperBound = new VerseKey();
00784 upperBound->AutoNormalize(0);
00785 upperBound->Headings(1);
00786 }
00787 if (!lowerBound) {
00788 lowerBound = new VerseKey();
00789 lowerBound->AutoNormalize(0);
00790 lowerBound->Headings(1);
00791 }
00792
00793 lowerBound->Testament(0);
00794 lowerBound->Book(0);
00795 lowerBound->Chapter(0);
00796 lowerBound->Verse(0);
00797
00798 upperBound->Testament(2);
00799 upperBound->Book(BMAX[1]);
00800 upperBound->Chapter(books[1][BMAX[1]-1].chapmax);
00801 upperBound->Verse(books[1][BMAX[1]-1].versemax[upperBound->Chapter()-1]);
00802 }
00803
00804
00805
00806
00807
00808
00809 void VerseKey::copyFrom(const VerseKey &ikey) {
00810 SWKey::copyFrom(ikey);
00811
00812 parse();
00813 }
00814
00815
00816
00817
00818
00819
00820 void VerseKey::copyFrom(const SWKey &ikey) {
00821 SWKey::copyFrom(ikey);
00822
00823 parse();
00824 }
00825
00826
00827
00828
00829
00830
00831
00832 const char *VerseKey::getText() const {
00833 freshtext();
00834 return keytext;
00835 }
00836
00837
00838 const char *VerseKey::getShortText() const {
00839 static char *stext = 0;
00840 char buf[2047];
00841 freshtext();
00842 if (book < 1) {
00843 if (testament < 1)
00844 sprintf(buf, "[ Module Heading ]");
00845 else sprintf(buf, "[ Testament %d Heading ]", (int)testament);
00846 }
00847 else {
00848 sprintf(buf, "%s %d:%d", books[testament-1][book-1].prefAbbrev, chapter, verse);
00849 }
00850 stdstr(&stext, buf);
00851 return stext;
00852 }
00853
00854
00855 const char *VerseKey::getBookName() const {
00856 return books[testament-1][book-1].name;
00857 }
00858
00859
00860 const char *VerseKey::getBookAbbrev() const {
00861 return books[testament-1][book-1].prefAbbrev;
00862 }
00863
00864
00865
00866
00867
00868
00869
00870
00871 void VerseKey::setPosition(SW_POSITION p) {
00872 switch (p) {
00873 case POS_TOP:
00874 testament = LowerBound().Testament();
00875 book = LowerBound().Book();
00876 chapter = LowerBound().Chapter();
00877 verse = LowerBound().Verse();
00878 break;
00879 case POS_BOTTOM:
00880 testament = UpperBound().Testament();
00881 book = UpperBound().Book();
00882 chapter = UpperBound().Chapter();
00883 verse = UpperBound().Verse();
00884 break;
00885 case POS_MAXVERSE:
00886 Normalize();
00887 verse = books[testament-1][book-1].versemax[chapter-1];
00888 break;
00889 case POS_MAXCHAPTER:
00890 verse = 1;
00891 Normalize();
00892 chapter = books[testament-1][book-1].chapmax;
00893 break;
00894 }
00895 Normalize(1);
00896 Error();
00897 }
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908 void VerseKey::increment(int step) {
00909 char ierror = 0;
00910 Index(Index() + step);
00911 while ((!verse) && (!headings) && (!ierror)) {
00912 Index(Index() + 1);
00913 ierror = Error();
00914 }
00915
00916 error = (ierror) ? ierror : error;
00917 }
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 void VerseKey::decrement(int step) {
00929 char ierror = 0;
00930
00931 Index(Index() - step);
00932 while ((!verse) && (!headings) && (!ierror)) {
00933 Index(Index() - 1);
00934 ierror = Error();
00935 }
00936 if ((ierror) && (!headings))
00937 (*this)++;
00938
00939 error = (ierror) ? ierror : error;
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 void VerseKey::Normalize(char autocheck)
00951 {
00952 error = 0;
00953
00954 if ((autocheck) && (!autonorm))
00955 return;
00956
00957 if ((headings) && (!verse))
00958 return;
00959
00960 while ((testament < 3) && (testament > 0)) {
00961
00962 if (book > BMAX[testament-1]) {
00963 book -= BMAX[testament-1];
00964 testament++;
00965 continue;
00966 }
00967
00968 if (book < 1) {
00969 if (--testament > 0) {
00970 book += BMAX[testament-1];
00971 }
00972 continue;
00973 }
00974
00975 if (chapter > books[testament-1][book-1].chapmax) {
00976 chapter -= books[testament-1][book-1].chapmax;
00977 book++;
00978 continue;
00979 }
00980
00981 if (chapter < 1) {
00982 if (--book > 0) {
00983 chapter += books[testament-1][book-1].chapmax;
00984 }
00985 else {
00986 if (testament > 1) {
00987 chapter += books[0][BMAX[0]-1].chapmax;
00988 }
00989 }
00990 continue;
00991 }
00992
00993 if (verse > books[testament-1][book-1].versemax[chapter-1]) {
00994 verse -= books[testament-1][book-1].versemax[chapter++ - 1];
00995 continue;
00996 }
00997
00998 if (verse < 1) {
00999 if (--chapter > 0) {
01000 verse += books[testament-1][book-1].versemax[chapter-1];
01001 }
01002 else {
01003 if (book > 1) {
01004 verse += books[testament-1][book-2].versemax[books[testament-1][book-2].chapmax-1];
01005 }
01006 else {
01007 if (testament > 1) {
01008 verse += books[0][BMAX[0]-1].versemax[books[0][BMAX[0]-1].chapmax-1];
01009 }
01010 }
01011 }
01012 continue;
01013 }
01014
01015 break;
01016 }
01017
01018 if (testament > 2) {
01019 testament = 2;
01020 book = BMAX[testament-1];
01021 chapter = books[testament-1][book-1].chapmax;
01022 verse = books[testament-1][book-1].versemax[chapter-1];
01023 error = KEYERR_OUTOFBOUNDS;
01024 }
01025
01026 if (testament < 1) {
01027 error = ((!headings) || (testament < 0) || (book < 0)) ? KEYERR_OUTOFBOUNDS : 0;
01028 testament = ((headings) ? 0 : 1);
01029 book = ((headings) ? 0 : 1);
01030 chapter = ((headings) ? 0 : 1);
01031 verse = ((headings) ? 0 : 1);
01032 }
01033 if (_compare(UpperBound()) > 0) {
01034 *this = UpperBound();
01035 error = KEYERR_OUTOFBOUNDS;
01036 }
01037 if (_compare(LowerBound()) < 0) {
01038 *this = LowerBound();
01039 error = KEYERR_OUTOFBOUNDS;
01040 }
01041 }
01042
01043
01044
01045
01046
01047
01048
01049
01050 char VerseKey::Testament() const
01051 {
01052 return testament;
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062 char VerseKey::Book() const
01063 {
01064 return book;
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074 int VerseKey::Chapter() const
01075 {
01076 return chapter;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086 int VerseKey::Verse() const
01087 {
01088 return verse;
01089 }
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 char VerseKey::Testament(char itestament)
01103 {
01104 char retval = testament;
01105
01106 if (itestament != MAXPOS(char)) {
01107 testament = itestament;
01108 Normalize(1);
01109 }
01110 return retval;
01111 }
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124 char VerseKey::Book(char ibook)
01125 {
01126 char retval = book;
01127
01128 Chapter(1);
01129 book = ibook;
01130 Normalize(1);
01131
01132 return retval;
01133 }
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146 int VerseKey::Chapter(int ichapter)
01147 {
01148 int retval = chapter;
01149
01150 Verse(1);
01151 chapter = ichapter;
01152 Normalize(1);
01153
01154 return retval;
01155 }
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168 int VerseKey::Verse(int iverse)
01169 {
01170 int retval = verse;
01171
01172 verse = iverse;
01173 Normalize(1);
01174
01175 return retval;
01176 }
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190 char VerseKey::AutoNormalize(char iautonorm)
01191 {
01192 char retval = autonorm;
01193
01194 if (iautonorm != MAXPOS(char)) {
01195 autonorm = iautonorm;
01196 Normalize(1);
01197 }
01198 return retval;
01199 }
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213 char VerseKey::Headings(char iheadings)
01214 {
01215 char retval = headings;
01216
01217 if (iheadings != MAXPOS(char)) {
01218 headings = iheadings;
01219 Normalize(1);
01220 }
01221 return retval;
01222 }
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236 int VerseKey::findindex(long *array, int size, long value)
01237 {
01238 int lbound, ubound, tval;
01239
01240 lbound = 0;
01241 ubound = size - 1;
01242 while ((ubound - lbound) > 1) {
01243 tval = lbound + (ubound-lbound)/2;
01244 if (array[tval] <= value)
01245 lbound = tval;
01246 else ubound = tval;
01247 }
01248 return (array[ubound] <= value) ? ubound : lbound;
01249 }
01250
01251
01252
01253
01254
01255
01256
01257
01258 long VerseKey::Index() const
01259 {
01260 long offset;
01261
01262 if (!testament) {
01263 offset = 0;
01264 verse = 0;
01265 }
01266 else {
01267 if (!book)
01268 chapter = 0;
01269 if (!chapter)
01270 verse = 0;
01271
01272 offset = offsets[testament-1][0][book];
01273 offset = offsets[testament-1][1][(int)offset + chapter];
01274 if (!(offset|verse))
01275 offset = 1;
01276 }
01277 return (offset + verse);
01278 }
01279
01280
01281
01282
01283
01284
01285
01286
01287 long VerseKey::NewIndex() const
01288 {
01289 static long otMaxIndex = 32300 - 8245;
01290
01291 return ((testament-1) * otMaxIndex) + Index();
01292 }
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303 long VerseKey::Index(long iindex)
01304 {
01305 long offset;
01306
01307
01308
01309 if (!testament)
01310 testament = 1;
01311
01312 if (iindex < 1) {
01313 if (testament < 2) {
01314 if (iindex < 0) {
01315 testament = 0;
01316 error = KEYERR_OUTOFBOUNDS;
01317 }
01318 else testament = 0;
01319 }
01320 else {
01321 testament--;
01322 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;
01323 }
01324 }
01325
01326
01327
01328
01329 if (testament) {
01330 if ((!error) && (iindex)) {
01331 offset = findindex(offsets[testament-1][1], offsize[testament-1][1], iindex);
01332 verse = iindex - offsets[testament-1][1][offset];
01333 book = findindex(offsets[testament-1][0], offsize[testament-1][0], offset);
01334 chapter = offset - offsets[testament-1][0][VerseKey::book];
01335 verse = (chapter) ? verse : 0;
01336 if (verse) {
01337 if (verse > books[testament-1][book-1].versemax[chapter-1]) {
01338 if (testament > 1) {
01339 verse = books[testament-1][book-1].versemax[chapter-1];
01340 error = KEYERR_OUTOFBOUNDS;
01341 }
01342 else {
01343 testament++;
01344 Index(verse - books[testament-2][book-1].versemax[chapter-1]);
01345 }
01346 }
01347 }
01348 }
01349 }
01350 if (_compare(UpperBound()) > 0) {
01351 *this = UpperBound();
01352 error = KEYERR_OUTOFBOUNDS;
01353 }
01354 if (_compare(LowerBound()) < 0) {
01355 *this = LowerBound();
01356 error = KEYERR_OUTOFBOUNDS;
01357 }
01358 return Index();
01359 }
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 int VerseKey::compare(const SWKey &ikey)
01373 {
01374 VerseKey ivkey = (const char *)ikey;
01375 return _compare(ivkey);
01376 }
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389 int VerseKey::_compare(const VerseKey &ivkey)
01390 {
01391 long keyval1 = 0;
01392 long keyval2 = 0;
01393
01394 keyval1 += Testament() * 1000000000;
01395 keyval2 += ivkey.Testament() * 1000000000;
01396 keyval1 += Book() * 1000000;
01397 keyval2 += ivkey.Book() * 1000000;
01398 keyval1 += Chapter() * 1000;
01399 keyval2 += ivkey.Chapter() * 1000;
01400 keyval1 += Verse();
01401 keyval2 += ivkey.Verse();
01402 keyval1 -= keyval2;
01403 keyval1 = (keyval1) ? ((keyval1 > 0) ? 1 : -1) :0;
01404 return keyval1;
01405 }