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

Generated on Wed Apr 3 22:34:15 2002 for The Sword Project by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002