diff options
Diffstat (limited to 'src/keys')
-rw-r--r-- | src/keys/listkey.cpp | 257 | ||||
-rw-r--r-- | src/keys/strkey.cpp | 41 | ||||
-rw-r--r-- | src/keys/swkey.cpp | 196 | ||||
-rw-r--r-- | src/keys/treekey.cpp | 30 | ||||
-rw-r--r-- | src/keys/treekeyidx.cpp | 590 | ||||
-rw-r--r-- | src/keys/versekey.cpp | 1450 |
6 files changed, 2564 insertions, 0 deletions
diff --git a/src/keys/listkey.cpp b/src/keys/listkey.cpp new file mode 100644 index 0000000..0d1ff33 --- /dev/null +++ b/src/keys/listkey.cpp @@ -0,0 +1,257 @@ +/****************************************************************************** + * listkey.cpp - code for base class 'ListKey'. ListKey is the basis for all + * types of keys that have lists of specified indexes + * (e.g. a list of verses, place, etc.) + */ + +#include <utilfuns.h> +#include <string.h> +#include <stdlib.h> +#include <swkey.h> +#include <listkey.h> + +static const char *classes[] = {"ListKey", "SWKey", "SWObject", 0}; +SWClass ListKey::classdef(classes); + +/****************************************************************************** + * ListKey Constructor - initializes instance of ListKey + * + * ENT: ikey - text key + */ + +ListKey::ListKey(const char *ikey): SWKey(ikey) { + arraymax = 0; + ClearList(); + init(); +} + + +ListKey::ListKey(ListKey const &k) : SWKey(k.keytext) { + arraymax = k.arraymax; + arraypos = k.arraypos; + arraycnt = k.arraycnt; + array = (arraymax)?(SWKey **)malloc(k.arraymax * sizeof(SWKey *)):0; + for (int i = 0; i < arraycnt; i++) + array[i] = k.array[i]->clone(); + init(); +} + + +void ListKey::init() { + myclass = &classdef; +} + + +SWKey *ListKey::clone() const +{ + return new ListKey(*this); +} + +/****************************************************************************** + * ListKey Destructor - cleans up instance of ListKey + */ + +ListKey::~ListKey() +{ + ClearList(); +} + + +/****************************************************************************** + * ListKey::ClearList - Clears out elements of list + */ + +void ListKey::ClearList() +{ + int loop; + + if (arraymax) { + for (loop = 0; loop < arraycnt; loop++) + delete array[loop]; + + free(array); + arraymax = 0; + } + arraycnt = 0; + arraypos = 0; + array = 0; +} + + +/****************************************************************************** + * ListKey::copyFrom Equates this ListKey to another ListKey object + * + * ENT: ikey - other ListKey object + */ + +void ListKey::copyFrom(const ListKey &ikey) { + ClearList(); + + arraymax = ikey.arraymax; + arraypos = ikey.arraypos; + arraycnt = ikey.arraycnt; + array = (arraymax)?(SWKey **)malloc(ikey.arraymax * sizeof(SWKey *)):0; + for (int i = 0; i < arraycnt; i++) + array[i] = ikey.array[i]->clone(); + + SetToElement(0); +} + + +/****************************************************************************** + * ListKey::add - Adds an element to the list + */ + +void ListKey::add(const SWKey &ikey) { + if (++arraycnt > arraymax) { + array = (SWKey **) ((array) ? realloc(array, (arraycnt + 32) * sizeof(SWKey *)) : calloc(arraycnt + 32, sizeof(SWKey *))); + arraymax = arraycnt + 32; + } + array[arraycnt-1] = ikey.clone(); + SetToElement(arraycnt-1); +} + + + +/****************************************************************************** + * ListKey::setPosition(SW_POSITION) - Positions this key + * + * ENT: p - position + * + * RET: *this + */ + +void ListKey::setPosition(SW_POSITION p) { + switch (p) { + case 1: // GCC won't compile P_TOP + SetToElement(0); + break; + case 2: // GCC won't compile P_BOTTOM + SetToElement(arraycnt-1); + break; + } +} + + +/****************************************************************************** + * ListKey::increment - Increments a number of elements + */ + +void ListKey::increment(int step) { + if (step < 0) { + decrement(step*-1); + return; + } + Error(); // clear error + for(; step && !Error(); step--) { + if (arraypos < arraycnt) { + (*(array[arraypos]))++; + if (array[arraypos]->Error()) { + SetToElement(arraypos+1); + } + else *this = (const char *)(*array[arraypos]); + } + else error = KEYERR_OUTOFBOUNDS; + } +} + + +/****************************************************************************** + * ListKey::decrement - Decrements a number of elements + */ + +void ListKey::decrement(int step) { + if (step < 0) { + increment(step*-1); + return; + } + Error(); // clear error + for(; step && !Error(); step--) { + if (arraypos > -1) { + (*(array[arraypos]))--; + if (array[arraypos]->Error()) { + SetToElement(arraypos-1, BOTTOM); + } + else *this = (const char *)(*array[arraypos]); + } + else error = KEYERR_OUTOFBOUNDS; + } +} + + +/****************************************************************************** + * ListKey::Count - Returns number of elements in list + */ + +int ListKey::Count() { + return arraycnt; +} + + +/****************************************************************************** + * ListKey::SetToElement - Sets key to element number + * + * ENT: ielement - element number to set to + * + * RET: error status + */ + +char ListKey::SetToElement(int ielement, SW_POSITION pos) { + arraypos = ielement; + if (arraypos >= arraycnt) { + arraypos = (arraycnt>0)?arraycnt - 1:0; + error = KEYERR_OUTOFBOUNDS; + } + else { + if (arraypos < 0) { + arraypos = 0; + error = KEYERR_OUTOFBOUNDS; + } + else { + error = 0; + } + } + + if (arraycnt) { + (*array[arraypos]) = pos; + *this = (const char *)(*array[arraypos]); + } + else *this = ""; + + return error; +} + + +/****************************************************************************** + * ListKey::GetElement - Gets a key element number + * + * ENT: pos - element number to get (or default current) + * + * RET: Key or null on error + */ + +SWKey *ListKey::GetElement(int pos) { + if (pos < 0) + pos = arraypos; + + if (pos >=arraycnt) + error = KEYERR_OUTOFBOUNDS; + + return (error) ? 0:array[pos]; +} + + +/****************************************************************************** + * ListKey::Remove - Removes current element from list + */ + +void ListKey::Remove() { + if ((arraypos > -1) && (arraypos < arraycnt)) { + delete array[arraypos]; + if (arraypos < arraycnt - 1) + memmove(&array[arraypos], &array[arraypos+1], (arraycnt - arraypos - 1) * sizeof(SWKey *)); + arraycnt--; + + SetToElement((arraypos)?arraypos-1:0); + } +} diff --git a/src/keys/strkey.cpp b/src/keys/strkey.cpp new file mode 100644 index 0000000..7e2d539 --- /dev/null +++ b/src/keys/strkey.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * StrKey.cpp - code for class 'StrKey'- a standard string key class (used + * for modules that index on single strings (eg. cities, + * names, words, etc.) + */ + +#include <swmacs.h> +#include <utilfuns.h> +#include <strkey.h> +#include <string.h> +#include <stdio.h> + + +static const char *classes[] = {"StrKey", "SWKey", "SWObject", 0}; +SWClass StrKey::classdef(classes); + +/****************************************************************************** + * StrKey Constructor - initializes instance of StrKey + * + * ENT: ikey - text key (word, city, name, etc.) + */ + +StrKey::StrKey(const char *ikey) : SWKey(ikey) +{ + init(); +} + + +void StrKey::init() { + myclass = &classdef; +} + + +/****************************************************************************** + * StrKey Destructor - cleans up instance of StrKey + * + * ENT: ikey - text key + */ + +StrKey::~StrKey() { +} diff --git a/src/keys/swkey.cpp b/src/keys/swkey.cpp new file mode 100644 index 0000000..e633369 --- /dev/null +++ b/src/keys/swkey.cpp @@ -0,0 +1,196 @@ +/****************************************************************************** + * swkey.cpp - code for base class 'SWKey'. SWKey is the basis for all + * types of keys for indexing into modules (e.g. verse, word, + * place, etc.) + */ + +#include <swkey.h> +#include <utilfuns.h> +#include <string.h> + +static const char *classes[] = {"SWKey", "SWObject", 0}; +SWClass SWKey::classdef(classes); + +/****************************************************************************** + * SWKey Constructor - initializes instance of SWKey + * + * ENT: ikey - text key + */ + +SWKey::SWKey(const char *ikey) +{ + index = 0; + persist = 0; + keytext = 0; + error = 0; + stdstr(&keytext, ikey); + init(); +} + +SWKey::SWKey(SWKey const &k) +{ + index = k.index; + persist = k.persist; + userData = k.userData; + keytext = 0; + error = k.error; + stdstr(&keytext, k.keytext); + init(); +} + +void SWKey::init() { + myclass = &classdef; +} + +SWKey *SWKey::clone() const +{ + return new SWKey(*this); +} + +/****************************************************************************** + * SWKey Destructor - cleans up instance of SWKey + */ + +SWKey::~SWKey() { + if (keytext) + delete [] keytext; +} + + +/****************************************************************************** + * SWKey::Persist - Gets whether this object itself persists within a + * module that it was used to SetKey or just a copy. + * (1 - persists in module; 0 - a copy is attempted + * + * RET: value of persist + */ + +char SWKey::Persist() const +{ + return persist; +} + + +/****************************************************************************** + * SWKey::Persist - Set/gets whether this object itself persists within a + * module that it was used to SetKey or just a copy. + * (1 - persists in module; 0 - a copy is attempted + * + * ENT: ipersist - value which to set persist + * [-1] - only get + * + * RET: value of persist + */ + +char SWKey::Persist(signed char ipersist) +{ + if (ipersist != -1) + persist = ipersist; + + return persist; +} + + +/****************************************************************************** + * SWKey::Error - Gets and clears error status + * + * RET: error status + */ + +char SWKey::Error() +{ + char retval = error; + + error = 0; + return retval; +} + + +/****************************************************************************** + * SWKey::setText Equates this SWKey to a character string + * + * ENT: ikey - other swkey object + */ + +void SWKey::setText(const char *ikey) { + stdstr(&keytext, ikey); +} + + +/****************************************************************************** + * SWKey::copyFrom Equates this SWKey to another SWKey object + * + * ENT: ikey - other swkey object + */ + +void SWKey::copyFrom(const SWKey &ikey) { +// not desirable Persist(ikey.Persist()); + setText((const char *)ikey); +} + + +/****************************************************************************** + * SWKey::getText - returns text key if (char *) cast is requested + */ + +const char *SWKey::getText() const { + return keytext; +} + + +/****************************************************************************** + * SWKey::compare - Compares another VerseKey object + * + * ENT: ikey - key to compare with this one + * + * RET: > 0 if this key is greater than compare key + * < 0 + * 0 + */ + +int SWKey::compare(const SWKey &ikey) +{ + return strcmp((const char *)*this, (const char *)ikey); +} + + +/****************************************************************************** + * SWKey::setPosition(SW_POSITION) - Positions this key if applicable + */ + +void SWKey::setPosition(SW_POSITION p) { + switch (p) { + case POS_TOP: +// *this = ""; + break; + case POS_BOTTOM: +// *this = "zzzzzzzzz"; + break; + } +} + + +/****************************************************************************** + * SWKey::increment - Increments key a number of entries + * + * ENT: increment - Number of entries to jump forward + * + * RET: *this + */ + +void SWKey::increment(int) { + error = KEYERR_OUTOFBOUNDS; +} + + +/****************************************************************************** + * SWKey::decrement - Decrements key a number of entries + * + * ENT: decrement - Number of entries to jump backward + * + * RET: *this + */ + +void SWKey::decrement(int) { + error = KEYERR_OUTOFBOUNDS; +} diff --git a/src/keys/treekey.cpp b/src/keys/treekey.cpp new file mode 100644 index 0000000..d92b7a4 --- /dev/null +++ b/src/keys/treekey.cpp @@ -0,0 +1,30 @@ +/****************************************************************************** + * versekey.h - code for class 'versekey'- a standard Biblical verse key + * + * $Id: treekey.cpp,v 1.2 2002/04/15 21:26:44 scribe Exp $ + * + * Copyright 1998 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 <treekey.h> + +static const char *classes[] = {"TreeKey", "SWKey", "SWObject", 0}; +SWClass TreeKey::classdef(classes); + +void TreeKey::init() { + myclass = &classdef; +} diff --git a/src/keys/treekeyidx.cpp b/src/keys/treekeyidx.cpp new file mode 100644 index 0000000..acd9b5a --- /dev/null +++ b/src/keys/treekeyidx.cpp @@ -0,0 +1,590 @@ +/****************************************************************************** + * versekey.h - code for class 'versekey'- a standard Biblical verse key + * + * $Id: treekeyidx.cpp,v 1.7 2002/04/15 21:26:44 scribe Exp $ + * + * Copyright 1998 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 <treekeyidx.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <string> + +#ifndef __GNUC__ +#include <io.h> +#else +#include <unistd.h> +#endif + +using namespace std; +static const char nl = '\n'; +static const char *classes[] = {"TreeKeyIdx", "TreeKey", "SWKey", "SWObject", 0}; +SWClass TreeKeyIdx::classdef(classes); + + +TreeKeyIdx::TreeKeyIdx(const TreeKeyIdx &ikey) : currentNode() { + init(); + path = 0; + idxfd = 0; + datfd = 0; + copyFrom(ikey); +} + +TreeKeyIdx::TreeKeyIdx(const char *idxPath, int fileMode) : currentNode() { + char buf[127]; + + init(); + path = 0; + stdstr(&path, idxPath); + +#ifndef O_BINARY // O_BINARY is needed in Borland C++ 4.53 +#define O_BINARY 0 // If it hasn't been defined than we probably +#endif // don't need it. + + if (fileMode == -1) { // try read/write if possible + fileMode = O_RDWR; + } + + sprintf(buf, "%s.idx", path); + idxfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true); + sprintf(buf, "%s.dat", path); + datfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true); + + if (datfd <= 0) { + sprintf(buf, "Error: %d", errno); + perror(buf); + error = errno; + } + else { + root(); + } +} + + +void TreeKeyIdx::init() { + myclass = &classdef; +} + + +TreeKeyIdx::~TreeKeyIdx () { + if (path) + delete [] path; + + FileMgr::systemFileMgr.close(idxfd); + FileMgr::systemFileMgr.close(datfd); +} + + +const char *TreeKeyIdx::getLocalName() { + return currentNode.name; +} + + +const char *TreeKeyIdx::getUserData(int *size) { + if (size) + *size = (int)currentNode.dsize; + return currentNode.userData; +} + + +void TreeKeyIdx::setUserData(const char *userData, int size) { + if (currentNode.userData) + delete currentNode.userData; + + if (!size) + size = strlen(userData) + 1; + + currentNode.userData = new char [ size ]; + memcpy(currentNode.userData, userData, size); + currentNode.dsize = size; +} + +const char *TreeKeyIdx::setLocalName(const char *newName) { + stdstr(&(currentNode.name), newName); + return currentNode.name; +} + + +void TreeKeyIdx::save() { + saveTreeNode(¤tNode); +} + + +const char *TreeKeyIdx::getFullName() const { + TreeNode parent; + static string fullPath; + fullPath = currentNode.name; + parent.parent = currentNode.parent; + while (parent.parent > -1) { + getTreeNodeFromIdxOffset(parent.parent, &parent); + fullPath = ((string)parent.name) + (string) "/" + fullPath; + } + return fullPath.c_str(); +} + + +void TreeKeyIdx::root() { + error = getTreeNodeFromIdxOffset(0, ¤tNode); +} + + +bool TreeKeyIdx::parent() { + if (currentNode.parent > -1) { + error = getTreeNodeFromIdxOffset(currentNode.parent, ¤tNode); + return true; + } + return false; +} + + +bool TreeKeyIdx::firstChild() { + if (currentNode.firstChild > -1) { + error = getTreeNodeFromIdxOffset(currentNode.firstChild, ¤tNode); + return true; + } + return false; +} + + +bool TreeKeyIdx::nextSibling() { + if (currentNode.next > -1) { + error = getTreeNodeFromIdxOffset(currentNode.next, ¤tNode); + return true; + } + return false; +} + + +bool TreeKeyIdx::previousSibling() { + TreeNode iterator; + __u32 target = currentNode.offset; + if (currentNode.parent > -1) { + getTreeNodeFromIdxOffset(currentNode.parent, &iterator); + getTreeNodeFromIdxOffset(iterator.firstChild, &iterator); + if (iterator.offset != target) { + while ((iterator.next != target) && (iterator.next > -1)) + getTreeNodeFromIdxOffset(iterator.next, &iterator); + if (iterator.next > -1) { + error = getTreeNodeFromIdxOffset(iterator.offset, ¤tNode); + return true; + } + } + } + return false; +} + + +bool TreeKeyIdx::hasChildren() { + return (currentNode.firstChild > -1); +} + + +void TreeKeyIdx::append() { + TreeNode lastSib; + if (currentNode.offset) { + getTreeNodeFromIdxOffset(currentNode.offset, &lastSib); + while (lastSib.next > -1) { + getTreeNodeFromIdxOffset(lastSib.next, &lastSib); + } + __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END); + lastSib.next = idxOffset; + saveTreeNodeOffsets(&lastSib); + __u32 parent = currentNode.parent; + currentNode.clear(); + currentNode.offset = idxOffset; + currentNode.parent = parent; + } +} + + +void TreeKeyIdx::appendChild() { + if (firstChild()) { + append(); + } + else { + __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END); + currentNode.firstChild = idxOffset; + saveTreeNodeOffsets(¤tNode); + __u32 parent = currentNode.offset; + currentNode.clear(); + currentNode.offset = idxOffset; + currentNode.parent = parent; + } +} + + +void TreeKeyIdx::insertBefore() { +} + + +void TreeKeyIdx::remove() { +} + + +/****************************************************************************** + * TreeKeyIdx::Create - Creates new key idx/dat files + * + * ENT: path - directory to store module files + * RET: error status + */ + +signed char TreeKeyIdx::create(const char *ipath) { + char *path = 0; + char *buf = new char [ strlen (ipath) + 20 ]; + FileDesc *fd, *fd2; + + stdstr(&path, ipath); + + if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\')) + path[strlen(path)-1] = 0; + + sprintf(buf, "%s.dat", path); + unlink(buf); + fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE); + fd->getFd(); + FileMgr::systemFileMgr.close(fd); + + sprintf(buf, "%s.idx", path); + unlink(buf); + fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE); + fd2->getFd(); + FileMgr::systemFileMgr.close(fd2); + + TreeKeyIdx newTree(path); + TreeKeyIdx::TreeNode root; + stdstr(&(root.name), ""); + newTree.saveTreeNode(&root); + + delete [] path; + + return 0; +} + + +/****************************************************************************** + * zStr::getidxbufdat - Gets the index string at the given dat offset + * NOTE: buf is calloc'd, or if not null, realloc'd and must + * be free'd by calling function + * + * ENT: ioffset - offset in dat file to lookup + * node - address of pointer to allocate for storage of string + */ + +void TreeKeyIdx::getTreeNodeFromDatOffset(long ioffset, TreeNode *node) const { + char ch; + __s32 tmp; + __u16 tmp2; + + if (datfd > 0) { + + lseek(datfd->getFd(), ioffset, SEEK_SET); + + read(datfd->getFd(), &tmp, 4); + node->parent = swordtoarch32(tmp); + + read(datfd->getFd(), &tmp, 4); + node->next = swordtoarch32(tmp); + + read(datfd->getFd(), &tmp, 4); + node->firstChild = swordtoarch32(tmp); + + string name; + do { + read(datfd->getFd(), &ch, 1); + name += ch; + } while (ch); + + stdstr(&(node->name), name.c_str()); + + read(datfd->getFd(), &tmp2, 2); + node->dsize = swordtoarch16(tmp2); + + if (node->dsize) { + if (node->userData) + delete [] node->userData; + node->userData = new char [node->dsize]; + read(datfd->getFd(), node->userData, node->dsize); + } + } +} + + +/****************************************************************************** + * zStr::getidxbuf - Gets the index string at the given idx offset + * NOTE: buf is calloc'd, or if not null, realloc'd + * and must be freed by calling function + * + * ENT: ioffset - offset in idx file to lookup + * buf - address of pointer to allocate for storage of string + */ + +char TreeKeyIdx::getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const { + __u32 offset; + char error = 0; + + if (ioffset < 0) { + ioffset = 0; + error = KEYERR_OUTOFBOUNDS; + } + + node->offset = ioffset; + if (idxfd > 0) { + lseek(idxfd->getFd(), ioffset, SEEK_SET); + if (read(idxfd->getFd(), &offset, 4) == 4) { + offset = swordtoarch32(offset); + getTreeNodeFromDatOffset(offset, node); + } + else { + lseek(idxfd->getFd(), -4, SEEK_END); + if (read(idxfd->getFd(), &offset, 4) == 4) { + offset = swordtoarch32(offset); + getTreeNodeFromDatOffset(offset, node); + } + error = KEYERR_OUTOFBOUNDS; + } + } + return error; +} + + +unsigned long TreeKeyIdx::getOffset() const { + return currentNode.offset; +} + +void TreeKeyIdx::setOffset(unsigned long offset) { + error = getTreeNodeFromIdxOffset(offset, ¤tNode); +} + + +void TreeKeyIdx::saveTreeNodeOffsets(TreeNode *node) { + long datOffset = 0; + __s32 tmp; + + if (idxfd > 0) { + lseek(idxfd->getFd(), node->offset, SEEK_SET); + if (read(idxfd->getFd(), &tmp, 4) != 4) { + datOffset = lseek(datfd->getFd(), 0, SEEK_END); + tmp = archtosword32(datOffset); + write(idxfd->getFd(), &tmp, 4); + } + else { + datOffset = swordtoarch32(tmp); + lseek(datfd->getFd(), datOffset, SEEK_SET); + } + + tmp = archtosword32(node->parent); + write(datfd->getFd(), &tmp, 4); + + tmp = archtosword32(node->next); + write(datfd->getFd(), &tmp, 4); + + tmp = archtosword32(node->firstChild); + write(datfd->getFd(), &tmp, 4); + } +} + + +void TreeKeyIdx::copyFrom(const TreeKeyIdx &ikey) { + + SWKey::copyFrom(ikey); + + currentNode.offset = ikey.currentNode.offset; + currentNode.parent = ikey.currentNode.parent; + currentNode.next = ikey.currentNode.next; + currentNode.firstChild = ikey.currentNode.firstChild; + stdstr(&(currentNode.name), ikey.currentNode.name); + currentNode.dsize = ikey.currentNode.dsize; + + if (currentNode.userData) + delete [] currentNode.userData; + if (currentNode.dsize) { + currentNode.userData = new char [ currentNode.dsize ]; + memcpy(currentNode.userData, ikey.currentNode.userData, currentNode.dsize); + } + else currentNode.userData = 0; + + bool newFiles = true; + + if (path && ikey.path) + newFiles = strcmp(path, ikey.path); + + if (newFiles) { + stdstr(&path, ikey.path); + + if (idxfd) { + FileMgr::systemFileMgr.close(idxfd); + FileMgr::systemFileMgr.close(datfd); + } + idxfd = FileMgr::systemFileMgr.open(ikey.idxfd->path, ikey.idxfd->mode, ikey.idxfd->perms); + datfd = FileMgr::systemFileMgr.open(ikey.datfd->path, ikey.datfd->mode, ikey.datfd->perms); + } +} + + +void TreeKeyIdx::saveTreeNode(TreeNode *node) { + long datOffset = 0; + __s32 tmp; + if (idxfd > 0) { + + lseek(idxfd->getFd(), node->offset, SEEK_SET); + datOffset = lseek(datfd->getFd(), 0, SEEK_END); + tmp = archtosword32(datOffset); + write(idxfd->getFd(), &tmp, 4); + + saveTreeNodeOffsets(node); + + write(datfd->getFd(), node->name, strlen(node->name)); + char null = 0; + write(datfd->getFd(), &null, 1); + + __u16 tmp2 = archtosword16(node->dsize); + write(datfd->getFd(), &tmp2, 2); + + if (node->dsize) { + write(datfd->getFd(), node->userData, node->dsize); + } + } +} + + +void TreeKeyIdx::setText(const char *ikey) { + char *buf = 0; + stdstr(&buf, ikey); + char *leaf = strtok(buf, "/"); + root(); + while ((leaf) && (!Error())) { + bool ok, inChild = false; + for (ok = firstChild(); ok; ok = nextSibling()) { + inChild = true; + if (!stricmp(leaf, getLocalName())) + break; + } + leaf = strtok(0, "/"); + if (!ok) { + if (inChild) { // if we didn't find a matching child node, default to first child + parent(); + firstChild(); + } + if (leaf) + error = KEYERR_OUTOFBOUNDS; + break; + } + } + delete [] buf; +} + + + +void TreeKeyIdx::copyFrom(const SWKey &ikey) { + SWKey::copyFrom(ikey); +} + +void TreeKeyIdx::setPosition(SW_POSITION p) { + switch (p) { + case POS_TOP: + root(); + break; + case POS_BOTTOM: + error = getTreeNodeFromIdxOffset(lseek(idxfd->getFd(), -4, SEEK_END), ¤tNode); + break; + } + Error(); // clear error from normalize +} + +const char *TreeKeyIdx::getText() const { + return getFullName(); +} + + +int TreeKeyIdx::_compare (const TreeKeyIdx & ikey) { + return (getOffset() - ikey.getOffset()); +} + + +int TreeKeyIdx::compare(const SWKey &ikey) { + TreeKeyIdx *treeKey = SWDYNAMIC_CAST(TreeKeyIdx, (&ikey)); + if (treeKey) + return _compare(*treeKey); + return SWKey::compare(ikey); +} + + +void TreeKeyIdx::decrement(int steps) { + error = getTreeNodeFromIdxOffset(currentNode.offset - (4*steps), ¤tNode); +} + +void TreeKeyIdx::increment(int steps) { + error = getTreeNodeFromIdxOffset(currentNode.offset + (4*steps), ¤tNode); + +/* + // assert positive + if (steps < 0) { + decrement(steps * -1); + return; + } + + while (steps > 0) { + if (!firstChild()) { + if (!nextSibbling() { + error = KEYERR_OUTOFBOUNDS; + return; + } + } + steps--; + } +*/ +} + + + +TreeKeyIdx::TreeNode::TreeNode() { + + name = 0; + stdstr(&name, ""); + userData = 0; + + clear(); +} + + +void TreeKeyIdx::TreeNode::clear() { + offset = 0; + parent = -1; + next = -1; + firstChild = -1; + dsize = 0; + + if (name) + delete [] name; + name = 0; + stdstr(&name, ""); + + if (userData) + delete [] userData; + userData = 0; +} + + +TreeKeyIdx::TreeNode::~TreeNode() { + if (name) + delete [] name; + + if (userData) + delete [] userData; +} diff --git a/src/keys/versekey.cpp b/src/keys/versekey.cpp new file mode 100644 index 0000000..05f1b8b --- /dev/null +++ b/src/keys/versekey.cpp @@ -0,0 +1,1450 @@ +/****************************************************************************** + * VerseKey.cpp - code for class 'VerseKey'- a standard Biblical verse key + */ + +#include <swmacs.h> +#include <utilfuns.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> + +#ifndef __GNUC__ +#include <io.h> +#else +#include <unistd.h> +#endif + +#include <utilstr.h> +#include <swkey.h> +#include <swlog.h> +#include <versekey.h> +#include <localemgr.h> +extern "C" { +#include <roman.h> +} + + +static const char *classes[] = {"VerseKey", "SWKey", "SWObject", 0}; +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() { + myclass = &classdef; + if (!instance) + initstatics(); + + instance++; + autonorm = 1; // default auto normalization to true + headings = 0; // default display headings option is false + upperBound = 0; + lowerBound = 0; + testament = 0; + book = 0; + chapter = 0; + verse = 0; + locale = 0; + + setLocale(LocaleMgr::systemLocaleMgr.getDefaultLocaleName()); +} + +/****************************************************************************** + * VerseKey Constructor - initializes instance of VerseKey + * + * ENT: ikey - base key (will take various forms of 'BOOK CH:VS'. See + * VerseKey::parse for more detailed information) + */ + +VerseKey::VerseKey(const SWKey *ikey) : SWKey(*ikey) +{ + init(); + if (ikey) + parse(); +} + + +/****************************************************************************** + * VerseKey Constructor - initializes instance of VerseKey + * + * ENT: ikey - text key (will take various forms of 'BOOK CH:VS'. See + * VerseKey::parse for more detailed information) + */ + +VerseKey::VerseKey(const char *ikey) : SWKey(ikey) +{ + init(); + if (ikey) + parse(); +} + + +VerseKey::VerseKey(VerseKey const &k) : SWKey(k) +{ + init(); + autonorm = k.autonorm; + headings = k.headings; + testament = k.Testament(); + book = k.Book(); + chapter = k.Chapter(); + verse = k.Verse(); + LowerBound(k.LowerBound()); + UpperBound(k.UpperBound()); +} + + +VerseKey::VerseKey(const char *min, const char *max) : SWKey() +{ + init(); + LowerBound(min); + UpperBound(max); + setPosition(TOP); +} + + +SWKey *VerseKey::clone() const +{ + return new VerseKey(*this); +} + + +/****************************************************************************** + * VerseKey Destructor - cleans up instance of VerseKey + * + * ENT: ikey - text key + */ + +VerseKey::~VerseKey() { + if (upperBound) + delete upperBound; + if (lowerBound) + delete lowerBound; + if (locale) + delete [] locale; + + --instance; +} + + +void VerseKey::setLocale(const char *name) { + char *BMAX; + struct sbook **books; + bool useCache = false; + + 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::systemLocaleMgr.getLocale(name); + localeCache.locale = locale; + + if (locale) { + locale->getBooks(&BMAX, &books); + setBooks(BMAX, books); + setBookAbbrevs(locale->getBookAbbrevs(), localeCache.abbrevsCnt); + localeCache.abbrevsCnt = abbrevsCnt; + } + else { + setBooks(builtin_BMAX, builtin_books); + setBookAbbrevs(builtin_abbrevs, localeCache.abbrevsCnt); + localeCache.abbrevsCnt = abbrevsCnt; + } + stdstr(&(this->locale), localeCache.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); + } + */ + } + for (int t = 0; t < 2; t++) { + for (int i = 0; i < BMAX[t]; i++) { + int bn = getBookAbbrev(books[t][i].name); + if ((bn-1)%39 != i) { + SWLog::systemlog->LogError("Book: %s does not have a matching toupper abbrevs entry! book number returned was: %d", books[t][i].name, bn); + } + } + } + } + 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; + + 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; + } + } +} + + +/****************************************************************************** + * VerseKey::parse - parses keytext into testament|book|chapter|verse + * + * RET: error status + */ + +char VerseKey::parse() +{ + + + testament = 1; + book = 1; + chapter = 1; + verse = 1; + + int error = 0; + + if (keytext) { + ListKey tmpListKey = VerseKey::ParseVerseList(keytext); + if (tmpListKey.Count()) { + SWKey::setText((const char *)tmpListKey); + for (testament = 1; testament < 3; testament++) { + for (book = 1; book <= BMAX[testament-1]; book++) { + if (!strncmp(keytext, books[testament-1][book-1].name, strlen(books[testament-1][book-1].name))) + break; + } + if (book <= BMAX[testament-1]) + break; + } + + if (testament < 3) { + sscanf(&keytext[strlen(books[testament-1][book-1].name)], "%d:%d", &chapter, &verse); + } + else error = 1; + } else error = 1; + } + Normalize(1); + freshtext(); + + return (this->error) ? this->error : (this->error = error); +} + + +/****************************************************************************** + * VerseKey::freshtext - refreshes keytext based on + * testament|book|chapter|verse + */ + +void VerseKey::freshtext() const +{ + char buf[2024]; + int realtest = testament; + int realbook = book; + + if (book < 1) { + if (testament < 1) + sprintf(buf, "[ Module Heading ]"); + 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]; + } + sprintf(buf, "%s %d:%d", books[realtest-1][realbook-1].name, chapter, verse); + } + + stdstr((char **)&keytext, buf); +} + + + +/****************************************************************************** + * VerseKey::getBookAbbrev - Attempts to find a book abbreviation for a buffer + * + * ENT: abbr - key for which to search; + * RET: book number or < 0 = not valid + */ + +int VerseKey::getBookAbbrev(const char *iabbr) +{ + int loop, diff, abLen, min, max, target, retVal = -1; + + char *abbr = 0; + + stdstr(&abbr, iabbr); + strstrip(abbr); + toupperstr(abbr); + abLen = strlen(abbr); + + if (abLen) { + min = 0; +// max = abbrevsCnt - 1; + max = abbrevsCnt; + while(1) { + target = min + ((max - min) / 2); + diff = strncmp(abbr, abbrevs[target].ab, abLen); + if ((!diff)||(target >= max)||(target <= min)) + break; + if (diff > 0) + min = target; + else max = target; + } + for (; target > 0; target--) { + if (strncmp(abbr, abbrevs[target-1].ab, abLen)) + break; + } + + retVal = (!diff) ? abbrevs[target].book : -1; + } + delete [] abbr; + return retVal; +} + +/****************************************************************************** + * VerseKey::ParseVerseList - Attempts to parse a buffer into separate + * verse entries returned in a ListKey + * + * ENT: buf - buffer to parse; + * defaultKey - if verse, chap, book, or testament is left off, + * pull info from this key (ie. Gen 2:3; 4:5; + * Gen would be used when parsing the 4:5 section) + * expandRange - whether or not to expand eg. John 1:10-12 or just + * save John 1:10 + * + * RET: ListKey reference filled with verse entries contained in buf + * + * COMMENT: This code works but wreaks. Rewrite to make more maintainable. + */ + +ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool expandRange) { + SWKey textkey; + + char book[255]; + char number[255]; + int tobook = 0; + int tonumber = 0; + int chap = -1, verse = -1; + int bookno = 0; + VerseKey curkey, lBound; + curkey.setLocale(getLocale()); + lBound.setLocale(getLocale()); + int loop; + char comma = 0; + char dash = 0; + const char *orig = buf; + ListKey tmpListKey; + ListKey internalListKey; + SWKey tmpDefaultKey = defaultKey; + char lastPartial = 0; + + curkey.AutoNormalize(0); + tmpListKey << tmpDefaultKey; + tmpListKey.GetElement()->userData = (void *)buf; + + while (*buf) { + switch (*buf) { + case ':': + number[tonumber] = 0; + tonumber = 0; + if (*number) + chap = atoi(number); + *number = 0; + break; + + case '-': + case ',': // on number new verse + case ';': // on number new chapter + number[tonumber] = 0; + tonumber = 0; + if (*number) { + if (chap >= 0) + verse = atoi(number); + else chap = atoi(number); + } + *number = 0; + book[tobook] = 0; + tobook = 0; + bookno = -1; + if (*book) { + for (loop = strlen(book) - 1; loop+1; loop--) { + if ((isdigit(book[loop])) || (book[loop] == ' ')) { + book[loop] = 0; + continue; + } + else { + if ((SW_toupper(book[loop])=='F')&&(loop)) { + if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) { + book[loop] = 0; + continue; + } + } + } + break; + } + + for (loop = strlen(book) - 1; loop+1; loop--) { + if (book[loop] == ' ') { + if (isroman(&book[loop+1])) { + if (verse == -1) { + verse = chap; + chap = from_rom(&book[loop+1]); + book[loop] = 0; + } + } + break; + } + } + + if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) { // Verse abbrev + if (verse == -1) { + verse = chap; + chap = VerseKey(tmpListKey).Chapter(); + *book = 0; + } + } + + bookno = getBookAbbrev(book); + } + if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) { + char partial = 0; + curkey.Verse(1); + curkey.Chapter(1); + curkey.Book(1); + + if (bookno < 0) { + curkey.Testament(VerseKey(tmpListKey).Testament()); + curkey.Book(VerseKey(tmpListKey).Book()); + } + else { + curkey.Testament(1); + curkey.Book(bookno); + } + + if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) { +// if (comma) { + curkey.Chapter(VerseKey(tmpListKey).Chapter()); + curkey.Verse(chap); // chap because this is the first number captured + } + else { + if (chap >= 0) { + curkey.Chapter(chap); + } + else { + partial++; + curkey.Chapter(1); + } + if (verse >= 0) { + curkey.Verse(verse); + } + else { + partial++; + curkey.Verse(1); + } + } + + if ((*buf == '-') && (expandRange)) { // if this is a dash save lowerBound and wait for upper + VerseKey newElement; + newElement.LowerBound(curkey); + newElement.setPosition(TOP); + tmpListKey << newElement; + tmpListKey.GetElement()->userData = (void *)buf; + } + else { + if (!dash) { // if last separator was not a dash just add + if (expandRange && partial) { + VerseKey newElement; + newElement.LowerBound(curkey); + if (partial > 1) + curkey.setPosition(MAXCHAPTER); + if (partial > 0) + curkey = MAXVERSE; + newElement.UpperBound(curkey); + newElement = TOP; + tmpListKey << newElement; + tmpListKey.GetElement()->userData = (void *)buf; + } + else { + tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey; + tmpListKey.GetElement()->userData = (void *)buf; + } + } + else if (expandRange) { + VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement()); + if (newElement) { + if (partial > 1) + curkey = MAXCHAPTER; + if (partial > 0) + curkey = MAXVERSE; + newElement->UpperBound(curkey); + *newElement = TOP; + tmpListKey.GetElement()->userData = (void *)buf; + } + } + } + lastPartial = partial; + } + *book = 0; + chap = -1; + verse = -1; + if (*buf == ',') + comma = 1; + else comma = 0; + if (*buf == '-') + dash = 1; + else dash = 0; + break; + case 10: // ignore these + case 13: + break; + case '.': + if (buf > orig) // ignore (break) if preceeding char is not a digit + if (!isdigit(*(buf-1))) + break; + + default: + if (isdigit(*buf)) { + number[tonumber++] = *buf; + } + else { + switch (*buf) { + case ' ': // ignore these and don't reset number + case 'f': + case 'F': + break; + default: + number[tonumber] = 0; + tonumber = 0; + break; + } + } + if (chap == -1) + book[tobook++] = *buf; + } + buf++; + } + number[tonumber] = 0; + tonumber = 0; + if (*number) { + if (chap >= 0) + verse = atoi(number); + else chap = atoi(number); + } + *number = 0; + book[tobook] = 0; + tobook = 0; + if (*book) { + for (loop = strlen(book) - 1; loop+1; loop--) { + if ((isdigit(book[loop])) || (book[loop] == ' ')) { + book[loop] = 0; + continue; + } + else { + if ((SW_toupper(book[loop])=='F')&&(loop)) { + if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) { + book[loop] = 0; + continue; + } + } + } + break; + } + + for (loop = strlen(book) - 1; loop+1; loop--) { + if (book[loop] == ' ') { + if (isroman(&book[loop+1])) { + if (verse == -1) { + verse = chap; + chap = from_rom(&book[loop+1]); + book[loop] = 0; + } + } + break; + } + } + + if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) { // Verse abbrev. + if (verse == -1) { + verse = chap; + chap = VerseKey(tmpListKey).Chapter(); + *book = 0; + } + } + + bookno = getBookAbbrev(book); + } + if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) { + char partial = 0; + curkey.Verse(1); + curkey.Chapter(1); + curkey.Book(1); + + if (bookno < 0) { + curkey.Testament(VerseKey(tmpListKey).Testament()); + curkey.Book(VerseKey(tmpListKey).Book()); + } + else { + curkey.Testament(1); + curkey.Book(bookno); + } + + if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) { +// if (comma) { + curkey.Chapter(VerseKey(tmpListKey).Chapter()); + curkey.Verse(chap); // chap because this is the first number captured + } + else { + if (chap >= 0) { + curkey.Chapter(chap); + } + else { + partial++; + curkey.Chapter(1); + } + if (verse >= 0) { + curkey.Verse(verse); + } + else { + partial++; + curkey.Verse(1); + } + } + + if ((*buf == '-') && (expandRange)) { // if this is a dash save lowerBound and wait for upper + VerseKey newElement; + newElement.LowerBound(curkey); + newElement = TOP; + tmpListKey << newElement; + tmpListKey.GetElement()->userData = (void *)buf; + } + else { + if (!dash) { // if last separator was not a dash just add + if (expandRange && partial) { + VerseKey newElement; + newElement.LowerBound(curkey); + if (partial > 1) + curkey = MAXCHAPTER; + if (partial > 0) + curkey = MAXVERSE; + newElement.UpperBound(curkey); + newElement = TOP; + tmpListKey << newElement; + tmpListKey.GetElement()->userData = (void *)buf; + } + else { + tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey; + tmpListKey.GetElement()->userData = (void *)buf; + } + } + else if (expandRange) { + VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement()); + if (newElement) { + if (partial > 1) + curkey = MAXCHAPTER; + if (partial > 0) + curkey = MAXVERSE; + newElement->UpperBound(curkey); + *newElement = TOP; + tmpListKey.GetElement()->userData = (void *)buf; + } + } + } + } + *book = 0; + tmpListKey = TOP; + tmpListKey.Remove(); // remove defaultKey + internalListKey = tmpListKey; + internalListKey = TOP; // Align internalListKey to first element before passing back; + + return internalListKey; +} + + +/****************************************************************************** + * VerseKey::LowerBound - sets / gets the lower boundary for this key + */ + +VerseKey &VerseKey::LowerBound(const char *lb) +{ + if (!lowerBound) + initBounds(); + + (*lowerBound) = lb; + lowerBound->Normalize(); + + return (*lowerBound); +} + + +/****************************************************************************** + * VerseKey::UpperBound - sets / gets the upper boundary for this key + */ + +VerseKey &VerseKey::UpperBound(const char *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(); + +// 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; + + +// -- end kludge + + return (*upperBound); +} + + +/****************************************************************************** + * VerseKey::LowerBound - sets / gets the lower boundary for this key + */ + +VerseKey &VerseKey::LowerBound() const +{ + if (!lowerBound) + initBounds(); + + return (*lowerBound); +} + + +/****************************************************************************** + * VerseKey::UpperBound - sets / gets the upper boundary for this key + */ + +VerseKey &VerseKey::UpperBound() const +{ + if (!upperBound) + initBounds(); + + return (*upperBound); +} + + +/****************************************************************************** + * VerseKey::ClearBounds - clears bounds for this VerseKey + */ + +void VerseKey::ClearBounds() +{ + initBounds(); +} + + +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); + + 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]); +} + + +/****************************************************************************** + * VerseKey::copyFrom - Equates this VerseKey to another VerseKey + */ + +void VerseKey::copyFrom(const VerseKey &ikey) { + SWKey::copyFrom(ikey); + + parse(); +} + + +/****************************************************************************** + * VerseKey::copyFrom - Equates this VerseKey to another SWKey + */ + +void VerseKey::copyFrom(const SWKey &ikey) { + SWKey::copyFrom(ikey); + + parse(); +} + + +/****************************************************************************** + * VerseKey::getText - refreshes keytext before returning if cast to + * a (char *) is requested + */ + +const char *VerseKey::getText() const { + freshtext(); + return keytext; +} + + +const char *VerseKey::getShortText() const { + static char *stext = 0; + char buf[2047]; + freshtext(); + if (book < 1) { + if (testament < 1) + sprintf(buf, "[ Module Heading ]"); + else sprintf(buf, "[ Testament %d Heading ]", (int)testament); + } + else { + sprintf(buf, "%s %d:%d", books[testament-1][book-1].prefAbbrev, chapter, verse); + } + stdstr(&stext, buf); + return stext; +} + + +const char *VerseKey::getBookName() const { + return books[testament-1][book-1].name; +} + + +const char *VerseKey::getBookAbbrev() const { + return books[testament-1][book-1].prefAbbrev; +} +/****************************************************************************** + * VerseKey::setPosition(SW_POSITION) - Positions this key + * + * ENT: p - position + * + * RET: *this + */ + +void VerseKey::setPosition(SW_POSITION p) { + switch (p) { + case POS_TOP: + testament = LowerBound().Testament(); + book = LowerBound().Book(); + chapter = LowerBound().Chapter(); + verse = LowerBound().Verse(); + break; + case POS_BOTTOM: + testament = UpperBound().Testament(); + book = UpperBound().Book(); + chapter = UpperBound().Chapter(); + verse = UpperBound().Verse(); + break; + case POS_MAXVERSE: + Normalize(); + verse = books[testament-1][book-1].versemax[chapter-1]; + break; + case POS_MAXCHAPTER: + verse = 1; + Normalize(); + chapter = books[testament-1][book-1].chapmax; + break; + } + Normalize(1); + Error(); // clear error from normalize +} + + +/****************************************************************************** + * VerseKey::increment - Increments key a number of verses + * + * ENT: step - Number of verses to jump forward + * + * RET: *this + */ + +void VerseKey::increment(int step) { + char ierror = 0; + Index(Index() + step); + while ((!verse) && (!headings) && (!ierror)) { + Index(Index() + 1); + ierror = Error(); + } + + error = (ierror) ? ierror : error; +} + + +/****************************************************************************** + * VerseKey::decrement - Decrements key a number of verses + * + * ENT: step - Number of verses to jump backward + * + * RET: *this + */ + +void VerseKey::decrement(int step) { + char ierror = 0; + + Index(Index() - step); + while ((!verse) && (!headings) && (!ierror)) { + Index(Index() - 1); + ierror = Error(); + } + if ((ierror) && (!headings)) + (*this)++; + + error = (ierror) ? ierror : error; +} + + +/****************************************************************************** + * VerseKey::Normalize - checks limits and normalizes if necessary (e.g. + * Matthew 29:47 = Mark 2:2). If last verse is + * exceeded, key is set to last Book CH:VS + * RET: *this + */ + +void VerseKey::Normalize(char autocheck) +{ + error = 0; + + if ((autocheck) && (!autonorm)) // only normalize if we were explicitely called or if autonorm is turned on + return; + + if ((headings) && (!verse)) // this is cheeze and temporary until deciding what actions should be taken. + return; // so headings should only be turned on when positioning with Index() or incrementors + + while ((testament < 3) && (testament > 0)) { + + if (book > BMAX[testament-1]) { + book -= BMAX[testament-1]; + testament++; + continue; + } + + if (book < 1) { + if (--testament > 0) { + book += BMAX[testament-1]; + } + continue; + } + + if (chapter > books[testament-1][book-1].chapmax) { + chapter -= books[testament-1][book-1].chapmax; + 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 (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]; + continue; + } + + if (verse < 1) { + if (--chapter > 0) { + verse += books[testament-1][book-1].versemax[chapter-1]; + } + else { + if (book > 1) { + verse += books[testament-1][book-2].versemax[books[testament-1][book-2].chapmax-1]; + } + else { + if (testament > 1) { + verse += books[0][BMAX[0]-1].versemax[books[0][BMAX[0]-1].chapmax-1]; + } + } + } + continue; + } + + break; // If we've made it this far (all failure checks continue) we're ok + } + + if (testament > 2) { + testament = 2; + book = BMAX[testament-1]; + chapter = books[testament-1][book-1].chapmax; + verse = books[testament-1][book-1].versemax[chapter-1]; + error = KEYERR_OUTOFBOUNDS; + } + + if (testament < 1) { + error = ((!headings) || (testament < 0) || (book < 0)) ? KEYERR_OUTOFBOUNDS : 0; + testament = ((headings) ? 0 : 1); + book = ((headings) ? 0 : 1); + chapter = ((headings) ? 0 : 1); + verse = ((headings) ? 0 : 1); + } + if (_compare(UpperBound()) > 0) { + *this = UpperBound(); + error = KEYERR_OUTOFBOUNDS; + } + if (_compare(LowerBound()) < 0) { + *this = LowerBound(); + error = KEYERR_OUTOFBOUNDS; + } +} + + +/****************************************************************************** + * VerseKey::Testament - Gets testament + * + * RET: value of testament + */ + +char VerseKey::Testament() const +{ + return testament; +} + + +/****************************************************************************** + * VerseKey::Book - Gets book + * + * RET: value of book + */ + +char VerseKey::Book() const +{ + return book; +} + + +/****************************************************************************** + * VerseKey::Chapter - Gets chapter + * + * RET: value of chapter + */ + +int VerseKey::Chapter() const +{ + return chapter; +} + + +/****************************************************************************** + * VerseKey::Verse - Gets verse + * + * RET: value of verse + */ + +int VerseKey::Verse() const +{ + return verse; +} + + +/****************************************************************************** + * VerseKey::Testament - Sets/gets testament + * + * ENT: itestament - value which to set testament + * [MAXPOS(char)] - only get + * + * RET: if unchanged -> value of testament + * if changed -> previous value of testament + */ + +char VerseKey::Testament(char itestament) +{ + char retval = testament; + + if (itestament != MAXPOS(char)) { + testament = itestament; + Normalize(1); + } + return retval; +} + + +/****************************************************************************** + * VerseKey::Book - 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) +{ + char retval = book; + + Chapter(1); + book = ibook; + Normalize(1); + + return retval; +} + + +/****************************************************************************** + * VerseKey::Chapter - Sets/gets chapter + * + * ENT: ichapter - value which to set chapter + * [MAXPOS(int)] - only get + * + * RET: if unchanged -> value of chapter + * if changed -> previous value of chapter + */ + +int VerseKey::Chapter(int ichapter) +{ + int retval = chapter; + + Verse(1); + chapter = ichapter; + Normalize(1); + + return retval; +} + + +/****************************************************************************** + * VerseKey::Verse - Sets/gets verse + * + * ENT: iverse - value which to set verse + * [MAXPOS(int)] - only get + * + * RET: if unchanged -> value of verse + * if changed -> previous value of verse + */ + +int VerseKey::Verse(int iverse) +{ + int retval = verse; + + verse = iverse; + Normalize(1); + + return retval; +} + + +/****************************************************************************** + * 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) +{ + char retval = autonorm; + + if (iautonorm != MAXPOS(char)) { + autonorm = iautonorm; + Normalize(1); + } + return retval; +} + + +/****************************************************************************** + * VerseKey::Headings - Sets/gets flag that tells VerseKey to include + * chap/book/testmnt/module headings + * + * ENT: iheadings - value which to set headings + * [MAXPOS(char)] - only get + * + * RET: if unchanged -> value of headings + * if changed -> previous value of headings + */ + +char VerseKey::Headings(char iheadings) +{ + char retval = headings; + + if (iheadings != MAXPOS(char)) { + headings = iheadings; + Normalize(1); + } + return retval; +} + + +/****************************************************************************** + * VerseKey::findindex - binary search to find the index closest, but less + * than the given value. + * + * ENT: array - long * to array to search + * size - number of elements in the array + * value - value to find + * + * RET: the index into the array that is less than but closest to value + */ + +int VerseKey::findindex(long *array, int size, long value) +{ + int lbound, ubound, tval; + + lbound = 0; + ubound = size - 1; + while ((ubound - lbound) > 1) { + tval = lbound + (ubound-lbound)/2; + if (array[tval] <= value) + lbound = tval; + else ubound = tval; + } + return (array[ubound] <= value) ? ubound : lbound; +} + + +/****************************************************************************** + * VerseKey::Index - Gets index based upon current verse + * + * RET: offset + */ + +long VerseKey::Index() const +{ + long offset; + + if (!testament) { // if we want module heading + offset = 0; + verse = 0; + } + 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; + } + return (offset + verse); +} + + +/****************************************************************************** + * VerseKey::Index - Gets index based upon current verse + * + * RET: offset + */ + +long VerseKey::NewIndex() 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(); +} + + +/****************************************************************************** + * VerseKey::Index - Sets index based upon current verse + * + * ENT: iindex - value to set index to + * + * RET: offset + */ + +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) + } + } + +// -------------------------------------------------------------------- + + + 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(); + error = KEYERR_OUTOFBOUNDS; + } + if (_compare(LowerBound()) < 0) { + *this = LowerBound(); + error = KEYERR_OUTOFBOUNDS; + } + return Index(); +} + + +/****************************************************************************** + * VerseKey::compare - Compares another SWKey object + * + * ENT: ikey - key to compare with this one + * + * RET: >0 if this versekey is greater than compare versekey + * <0 < + * 0 = + */ + +int VerseKey::compare(const SWKey &ikey) +{ + VerseKey ivkey = (const char *)ikey; + return _compare(ivkey); +} + + +/****************************************************************************** + * VerseKey::_compare - Compares another VerseKey object + * + * ENT: ikey - key to compare with this one + * + * RET: >0 if this versekey is greater than compare versekey + * <0 < + * 0 = + */ + +int VerseKey::_compare(const VerseKey &ivkey) +{ + long keyval1 = 0; + long keyval2 = 0; + + 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 + return keyval1; +} + + +const char *VerseKey::getOSISRef() const { + static char buf[5][254]; + static char loop = 0; + + if (loop > 4) + loop = 0; + + static char *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"}; + static char *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"}; + static char **osisbooks[] = { osisotbooks, osisntbooks }; + if (Verse()) + sprintf(buf[loop], "%s.%d.%d", osisbooks[Testament()-1][Book()-1], (int)Chapter(), (int)Verse()); + else if (Chapter()) + sprintf(buf[loop], "%s.%d", osisbooks[Testament()-1][Book()-1], (int)Chapter()); + else if (Book()) + sprintf(buf[loop], "%s", osisbooks[Testament()-1][Book()-1]); + else sprintf(buf[loop], ""); + return buf[loop++]; +} |