Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

treekeyidx.cpp

00001 /******************************************************************************
00002  *  versekey.h - code for class 'versekey'- a standard Biblical verse key
00003  *
00004  * $Id: treekeyidx_8cpp-source.html,v 1.3 2002/06/20 20:23:10 mgruner Exp $
00005  *
00006  * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
00007  *      CrossWire Bible Society
00008  *      P. O. Box 2528
00009  *      Tempe, AZ  85280-2528
00010  *
00011  * This program is free software; you can redistribute it and/or modify it
00012  * under the terms of the GNU General Public License as published by the
00013  * Free Software Foundation version 2.
00014  *
00015  * This program is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  *
00020  */
00021 
00022 
00023 #include <treekeyidx.h>
00024 #include <fcntl.h>
00025 #include <stdio.h>
00026 #include <errno.h>
00027 #include <string>
00028 
00029 #ifndef __GNUC__
00030 #include <io.h>
00031 #else
00032 #include <unistd.h>
00033 #endif
00034 
00035 using namespace std;
00036 static const char nl = '\n';
00037 static const char *classes[] = {"TreeKeyIdx", "TreeKey", "SWKey", "SWObject", 0};
00038 SWClass TreeKeyIdx::classdef(classes);
00039 
00040 
00041 TreeKeyIdx::TreeKeyIdx(const TreeKeyIdx &ikey) : currentNode() {
00042         init();
00043         path = 0;
00044         idxfd = 0;
00045         datfd = 0;
00046         copyFrom(ikey);
00047 }
00048 
00049 TreeKeyIdx::TreeKeyIdx(const char *idxPath, int fileMode) : currentNode() {
00050         char buf[127];
00051 
00052         init();
00053         path = 0;
00054         stdstr(&path, idxPath);
00055 
00056 #ifndef O_BINARY                // O_BINARY is needed in Borland C++ 4.53
00057 #define O_BINARY 0              // If it hasn't been defined than we probably
00058 #endif                          // don't need it.
00059 
00060         if (fileMode == -1) { // try read/write if possible
00061                 fileMode = O_RDWR;
00062         }
00063                 
00064         sprintf(buf, "%s.idx", path);
00065         idxfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
00066         sprintf(buf, "%s.dat", path);
00067         datfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
00068 
00069         if (datfd <= 0) {
00070                 sprintf(buf, "Error: %d", errno);
00071                 perror(buf);
00072                 error = errno;
00073         }
00074         else {
00075                 root();
00076         }
00077 }
00078 
00079 
00080 void TreeKeyIdx::init() {
00081         myclass = &classdef;
00082 }
00083 
00084 
00085 TreeKeyIdx::~TreeKeyIdx () {
00086         if (path)
00087                 delete [] path;
00088 
00089         FileMgr::systemFileMgr.close(idxfd);
00090         FileMgr::systemFileMgr.close(datfd);
00091 }
00092 
00093 
00094 const char *TreeKeyIdx::getLocalName() {
00095         return currentNode.name;
00096 }
00097 
00098 
00099 const char *TreeKeyIdx::getUserData(int *size) {
00100         if (size)
00101                 *size = (int)currentNode.dsize;
00102         return currentNode.userData;
00103 }
00104 
00105 
00106 void TreeKeyIdx::setUserData(const char *userData, int size) {
00107         if (currentNode.userData)
00108                 delete currentNode.userData;
00109 
00110         if (!size)
00111                 size = strlen(userData) + 1;
00112 
00113         currentNode.userData = new char [ size ];
00114         memcpy(currentNode.userData, userData, size);
00115         currentNode.dsize = size;
00116 }
00117 
00118 const char *TreeKeyIdx::setLocalName(const char *newName) {
00119         stdstr(&(currentNode.name), newName);
00120         return currentNode.name;
00121 }
00122 
00123 
00124 void TreeKeyIdx::save() {
00125         saveTreeNode(&currentNode);
00126 }
00127 
00128 
00129 const char *TreeKeyIdx::getFullName() const {
00130         TreeNode parent;
00131         static string fullPath;
00132         fullPath = currentNode.name;
00133         parent.parent = currentNode.parent;
00134         while (parent.parent > -1) {
00135                 getTreeNodeFromIdxOffset(parent.parent, &parent);
00136                 fullPath = ((string)parent.name) + (string) "/" + fullPath;
00137         }
00138         return fullPath.c_str();
00139 }
00140 
00141 
00142 void TreeKeyIdx::root() {
00143         error = getTreeNodeFromIdxOffset(0, &currentNode);
00144 }
00145 
00146 
00147 bool TreeKeyIdx::parent() {
00148         if (currentNode.parent > -1) {
00149                 error = getTreeNodeFromIdxOffset(currentNode.parent, &currentNode);
00150                 return true;
00151         }
00152         return false;
00153 }
00154 
00155 
00156 bool TreeKeyIdx::firstChild() {
00157         if (currentNode.firstChild > -1) {
00158                 error = getTreeNodeFromIdxOffset(currentNode.firstChild, &currentNode);
00159                 return true;
00160         }
00161         return false;
00162 }
00163 
00164 
00165 bool TreeKeyIdx::nextSibling() {
00166         if (currentNode.next > -1) {
00167                 error = getTreeNodeFromIdxOffset(currentNode.next, &currentNode);
00168                 return true;
00169         }
00170         return false;
00171 }
00172 
00173 
00174 bool TreeKeyIdx::previousSibling() {
00175         TreeNode iterator;
00176         __u32 target = currentNode.offset;
00177         if (currentNode.parent > -1) {
00178                 getTreeNodeFromIdxOffset(currentNode.parent, &iterator);
00179                 getTreeNodeFromIdxOffset(iterator.firstChild, &iterator);
00180                 if (iterator.offset != target) {
00181                         while ((iterator.next != target) && (iterator.next > -1))
00182                                 getTreeNodeFromIdxOffset(iterator.next, &iterator);
00183                         if (iterator.next > -1) {
00184                                 error = getTreeNodeFromIdxOffset(iterator.offset, &currentNode);
00185                                 return true;
00186                         }
00187                 }
00188         }
00189         return false;
00190 }
00191 
00192 
00193 bool TreeKeyIdx::hasChildren() {
00194         return (currentNode.firstChild > -1);
00195 }
00196 
00197 
00198 void TreeKeyIdx::append() {
00199         TreeNode lastSib;
00200         if (currentNode.offset) {
00201                 getTreeNodeFromIdxOffset(currentNode.offset, &lastSib);
00202                 while (lastSib.next > -1) {
00203                         getTreeNodeFromIdxOffset(lastSib.next, &lastSib);
00204                 }
00205                 __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
00206                 lastSib.next = idxOffset;
00207                 saveTreeNodeOffsets(&lastSib);
00208                 __u32 parent = currentNode.parent;
00209                 currentNode.clear();
00210                 currentNode.offset = idxOffset;
00211                 currentNode.parent = parent;
00212         }
00213 }
00214 
00215 
00216 void TreeKeyIdx::appendChild() {
00217         if (firstChild()) {
00218                 append();
00219         }
00220         else {
00221                 __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
00222                 currentNode.firstChild = idxOffset;
00223                 saveTreeNodeOffsets(&currentNode);
00224                 __u32 parent = currentNode.offset;
00225                 currentNode.clear();
00226                 currentNode.offset = idxOffset;
00227                 currentNode.parent = parent;
00228         }
00229 }
00230 
00231 
00232 void TreeKeyIdx::insertBefore() {
00233 }
00234 
00235 
00236 void TreeKeyIdx::remove() {
00237 }
00238 
00239 
00240 /******************************************************************************
00241  * TreeKeyIdx::Create   - Creates new key idx/dat files
00242  *
00243  * ENT: path    - directory to store module files
00244  * RET: error status
00245  */
00246 
00247 signed char TreeKeyIdx::create(const char *ipath) {
00248         char *path = 0;
00249         char *buf = new char [ strlen (ipath) + 20 ];
00250         FileDesc *fd, *fd2;
00251 
00252         stdstr(&path, ipath);
00253 
00254         if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
00255                 path[strlen(path)-1] = 0;
00256 
00257         sprintf(buf, "%s.dat", path);
00258         unlink(buf);
00259         fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
00260         fd->getFd();
00261         FileMgr::systemFileMgr.close(fd);
00262 
00263         sprintf(buf, "%s.idx", path);
00264         unlink(buf);
00265         fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
00266         fd2->getFd();
00267         FileMgr::systemFileMgr.close(fd2);
00268 
00269         TreeKeyIdx newTree(path);
00270         TreeKeyIdx::TreeNode root;
00271         stdstr(&(root.name), "");
00272         newTree.saveTreeNode(&root);
00273 
00274         delete [] path;
00275         
00276         return 0;
00277 }
00278 
00279 
00280 /******************************************************************************
00281  * zStr::getidxbufdat   - Gets the index string at the given dat offset
00282  *                              NOTE: buf is calloc'd, or if not null, realloc'd and must
00283  *                                      be free'd by calling function
00284  *
00285  * ENT: ioffset - offset in dat file to lookup
00286  *              node            - address of pointer to allocate for storage of string
00287  */
00288 
00289 void TreeKeyIdx::getTreeNodeFromDatOffset(long ioffset, TreeNode *node) const {
00290         char ch;
00291         __s32  tmp;
00292         __u16  tmp2;
00293 
00294         if (datfd > 0) {
00295 
00296                 lseek(datfd->getFd(), ioffset, SEEK_SET);
00297 
00298                 read(datfd->getFd(), &tmp, 4);
00299                 node->parent = swordtoarch32(tmp);
00300 
00301                 read(datfd->getFd(), &tmp, 4);
00302                 node->next = swordtoarch32(tmp);
00303 
00304                 read(datfd->getFd(), &tmp, 4);
00305                 node->firstChild = swordtoarch32(tmp);
00306 
00307                 string name;
00308                 do {
00309                         read(datfd->getFd(), &ch, 1);
00310                         name += ch;
00311                 } while (ch);
00312 
00313                 stdstr(&(node->name), name.c_str());
00314 
00315                 read(datfd->getFd(), &tmp2, 2);
00316                 node->dsize = swordtoarch16(tmp2);
00317 
00318                 if (node->dsize) {
00319                         if (node->userData)
00320                                 delete [] node->userData;
00321                         node->userData = new char [node->dsize];
00322                         read(datfd->getFd(), node->userData, node->dsize);
00323                 }
00324         }
00325 }
00326 
00327 
00328 /******************************************************************************
00329  * zStr::getidxbuf      - Gets the index string at the given idx offset
00330  *                                              NOTE: buf is calloc'd, or if not null, realloc'd
00331  *                                                      and must be freed by calling function
00332  *
00333  * ENT: ioffset - offset in idx file to lookup
00334  *              buf             - address of pointer to allocate for storage of string
00335  */
00336 
00337 char TreeKeyIdx::getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const {
00338         __u32 offset;
00339         char error = 0;
00340         
00341         if (ioffset < 0) {
00342                 ioffset = 0;
00343                 error = KEYERR_OUTOFBOUNDS;
00344         }
00345 
00346         node->offset = ioffset;
00347         if (idxfd > 0) {
00348                 lseek(idxfd->getFd(), ioffset, SEEK_SET);
00349                 if (read(idxfd->getFd(), &offset, 4) == 4) {
00350                         offset = swordtoarch32(offset);
00351                         getTreeNodeFromDatOffset(offset, node);
00352                 }
00353                 else {
00354                         lseek(idxfd->getFd(), -4, SEEK_END);
00355                         if (read(idxfd->getFd(), &offset, 4) == 4) {
00356                                 offset = swordtoarch32(offset);
00357                                 getTreeNodeFromDatOffset(offset, node);
00358                         }
00359                         error = KEYERR_OUTOFBOUNDS;
00360                 }
00361         }
00362         return error;
00363 }
00364 
00365 
00366 unsigned long TreeKeyIdx::getOffset() const {
00367         return currentNode.offset;
00368 }
00369 
00370 void TreeKeyIdx::setOffset(unsigned long offset) {
00371         error = getTreeNodeFromIdxOffset(offset, &currentNode);
00372 }
00373 
00374 
00375 void TreeKeyIdx::saveTreeNodeOffsets(TreeNode *node) {
00376         long datOffset = 0;
00377         __s32 tmp;
00378 
00379         if (idxfd > 0) {
00380                 lseek(idxfd->getFd(), node->offset, SEEK_SET);
00381                 if (read(idxfd->getFd(), &tmp, 4) != 4) {
00382                         datOffset = lseek(datfd->getFd(), 0, SEEK_END);
00383                         tmp = archtosword32(datOffset);
00384                         write(idxfd->getFd(), &tmp, 4);
00385                 }
00386                 else {
00387                         datOffset = swordtoarch32(tmp);
00388                         lseek(datfd->getFd(), datOffset, SEEK_SET);
00389                 }
00390 
00391                 tmp = archtosword32(node->parent);
00392                 write(datfd->getFd(), &tmp, 4);
00393 
00394                 tmp = archtosword32(node->next);
00395                 write(datfd->getFd(), &tmp, 4);
00396 
00397                 tmp = archtosword32(node->firstChild);
00398                 write(datfd->getFd(), &tmp, 4);
00399         }
00400 }
00401 
00402 
00403 void TreeKeyIdx::copyFrom(const TreeKeyIdx &ikey) {
00404 
00405         SWKey::copyFrom(ikey);
00406 
00407         currentNode.offset = ikey.currentNode.offset;
00408         currentNode.parent = ikey.currentNode.parent;
00409         currentNode.next = ikey.currentNode.next;
00410         currentNode.firstChild = ikey.currentNode.firstChild;
00411         stdstr(&(currentNode.name), ikey.currentNode.name);
00412         currentNode.dsize = ikey.currentNode.dsize;
00413 
00414         if (currentNode.userData)
00415                 delete [] currentNode.userData;
00416         if (currentNode.dsize) {
00417                 currentNode.userData = new char [ currentNode.dsize ];
00418                 memcpy(currentNode.userData, ikey.currentNode.userData, currentNode.dsize);
00419         }
00420         else currentNode.userData = 0;
00421 
00422         bool newFiles = true;
00423 
00424         if (path && ikey.path)
00425                 newFiles = strcmp(path, ikey.path);
00426 
00427         if (newFiles) {
00428                 stdstr(&path, ikey.path);
00429 
00430                 if (idxfd) {
00431                         FileMgr::systemFileMgr.close(idxfd);
00432                         FileMgr::systemFileMgr.close(datfd);
00433                 }
00434                 idxfd = FileMgr::systemFileMgr.open(ikey.idxfd->path, ikey.idxfd->mode, ikey.idxfd->perms);
00435                 datfd = FileMgr::systemFileMgr.open(ikey.datfd->path, ikey.datfd->mode, ikey.datfd->perms);
00436         }
00437 }
00438 
00439 
00440 void TreeKeyIdx::saveTreeNode(TreeNode *node) {
00441         long datOffset = 0;
00442         __s32 tmp;
00443         if (idxfd > 0) {
00444 
00445                 lseek(idxfd->getFd(), node->offset, SEEK_SET);
00446                 datOffset = lseek(datfd->getFd(), 0, SEEK_END);
00447                 tmp = archtosword32(datOffset);
00448                 write(idxfd->getFd(), &tmp, 4);
00449 
00450                 saveTreeNodeOffsets(node);
00451 
00452                 write(datfd->getFd(), node->name, strlen(node->name));
00453                 char null = 0;
00454                 write(datfd->getFd(), &null, 1);
00455 
00456                 __u16 tmp2 = archtosword16(node->dsize);
00457                 write(datfd->getFd(), &tmp2, 2);
00458 
00459                 if (node->dsize) {
00460                         write(datfd->getFd(), node->userData, node->dsize);
00461                 }
00462         }
00463 }
00464 
00465 
00466 void TreeKeyIdx::setText(const char *ikey) {
00467         char *buf = 0;
00468         stdstr(&buf, ikey);
00469         char *leaf = strtok(buf, "/");
00470         root();
00471         while ((leaf) && (!Error())) {
00472                 bool ok, inChild = false;
00473                 for (ok = firstChild(); ok; ok = nextSibling()) {
00474                         inChild = true;
00475                         if (!stricmp(leaf, getLocalName()))
00476                                 break;
00477                 }
00478                 leaf = strtok(0, "/");
00479                 if (!ok) {
00480                         if (inChild) {  // if we didn't find a matching child node, default to first child
00481                                 parent();
00482                                 firstChild();
00483                         }
00484                         if (leaf)
00485                                 error = KEYERR_OUTOFBOUNDS;
00486                         break;
00487                 }
00488         }
00489         delete [] buf;
00490 }
00491 
00492 
00493 
00494 void TreeKeyIdx::copyFrom(const SWKey &ikey) {
00495         SWKey::copyFrom(ikey);
00496 }
00497 
00498 void TreeKeyIdx::setPosition(SW_POSITION p) {
00499         switch (p) {
00500         case POS_TOP:
00501                 root();
00502                 break;
00503         case POS_BOTTOM:
00504                 error = getTreeNodeFromIdxOffset(lseek(idxfd->getFd(), -4, SEEK_END), &currentNode);
00505                 break;
00506         } 
00507         Error();        // clear error from normalize
00508 }
00509 
00510 const char *TreeKeyIdx::getText() const {
00511         return getFullName();
00512 }
00513 
00514 
00515 int TreeKeyIdx::_compare (const TreeKeyIdx & ikey) {
00516                 return (getOffset() - ikey.getOffset());
00517 }
00518 
00519 
00520 int TreeKeyIdx::compare(const SWKey &ikey) {
00521         TreeKeyIdx *treeKey = SWDYNAMIC_CAST(TreeKeyIdx, (&ikey));
00522         if (treeKey)
00523                 return _compare(*treeKey);
00524         return SWKey::compare(ikey);
00525 }
00526 
00527 
00528 void TreeKeyIdx::decrement(int steps) {
00529         error = getTreeNodeFromIdxOffset(currentNode.offset - (4*steps), &currentNode);
00530 }
00531 
00532 void TreeKeyIdx::increment(int steps) {
00533         error = getTreeNodeFromIdxOffset(currentNode.offset + (4*steps), &currentNode);
00534 
00535 /*
00536         // assert positive
00537         if (steps < 0) {
00538                 decrement(steps * -1);
00539                 return;
00540         }
00541 
00542         while (steps > 0) {
00543                 if (!firstChild()) {
00544                         if (!nextSibbling() {
00545                                 error = KEYERR_OUTOFBOUNDS;
00546                                 return;
00547                         }
00548                 }
00549                 steps--;
00550         }
00551 */
00552 }
00553 
00554 
00555 
00556 TreeKeyIdx::TreeNode::TreeNode() {
00557 
00558         name       = 0;
00559         stdstr(&name, "");
00560         userData   = 0;
00561 
00562         clear();
00563 }
00564 
00565 
00566 void TreeKeyIdx::TreeNode::clear() {
00567         offset     = 0;
00568         parent     = -1;
00569         next       = -1;
00570         firstChild = -1;
00571         dsize      = 0;
00572 
00573         if (name)
00574                 delete [] name;
00575         name = 0;
00576         stdstr(&name, "");
00577 
00578         if (userData)
00579                 delete [] userData;
00580         userData   = 0;
00581 }
00582 
00583 
00584 TreeKeyIdx::TreeNode::~TreeNode() {
00585         if (name)
00586                 delete [] name;
00587         
00588         if (userData)
00589                 delete [] userData;
00590 }

Generated on Thu Jun 20 22:13:01 2002 for The Sword Project by doxygen1.2.15