diff options
Diffstat (limited to 'src/keys/treekeyidx.cpp')
-rw-r--r-- | src/keys/treekeyidx.cpp | 590 |
1 files changed, 590 insertions, 0 deletions
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; +} |