1
/******************************************************************************
2
* versekey.h - code for class 'versekey'- a standard Biblical verse key
4
* $Id: treekeyidx.cpp,v 1.14 2003/06/27 01:41:07 scribe Exp $
6
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
7
* CrossWire Bible Society
11
* This program is free software; you can redistribute it and/or modify it
12
* under the terms of the GNU General Public License as published by the
13
* Free Software Foundation version 2.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
23
#include <treekeyidx.h>
36
static const char nl = '\n';
37
static const char *classes[] = {"TreeKeyIdx", "TreeKey", "SWKey", "SWObject", 0};
38
SWClass TreeKeyIdx::classdef(classes);
41
TreeKeyIdx::TreeKeyIdx(const TreeKeyIdx &ikey) : currentNode() {
49
TreeKeyIdx::TreeKeyIdx(const char *idxPath, int fileMode) : currentNode() {
54
stdstr(&path, idxPath);
56
#ifndef O_BINARY // O_BINARY is needed in Borland C++ 4.53
57
#define O_BINARY 0 // If it hasn't been defined than we probably
58
#endif // don't need it.
60
if (fileMode == -1) { // try read/write if possible
64
sprintf(buf, "%s.idx", path);
65
idxfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
66
sprintf(buf, "%s.dat", path);
67
datfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
70
sprintf(buf, "Error: %d", errno);
80
void TreeKeyIdx::init() {
85
TreeKeyIdx::~TreeKeyIdx () {
89
FileMgr::systemFileMgr.close(idxfd);
90
FileMgr::systemFileMgr.close(datfd);
94
const char *TreeKeyIdx::getLocalName() {
95
return currentNode.name;
99
const char *TreeKeyIdx::getUserData(int *size) {
101
*size = (int)currentNode.dsize;
102
return currentNode.userData;
106
void TreeKeyIdx::setUserData(const char *userData, int size) {
107
if (currentNode.userData)
108
delete currentNode.userData;
111
size = strlen(userData) + 1;
113
currentNode.userData = new char [ size ];
114
memcpy(currentNode.userData, userData, size);
115
currentNode.dsize = size;
118
const char *TreeKeyIdx::setLocalName(const char *newName) {
119
stdstr(&(currentNode.name), newName);
120
return currentNode.name;
124
void TreeKeyIdx::save() {
125
saveTreeNode(¤tNode);
129
const char *TreeKeyIdx::getFullName() const {
131
static SWBuf fullPath;
132
fullPath = currentNode.name;
133
parent.parent = currentNode.parent;
134
while (parent.parent > -1) {
135
getTreeNodeFromIdxOffset(parent.parent, &parent);
136
fullPath = ((SWBuf)parent.name) + (SWBuf) "/" + fullPath;
138
return fullPath.c_str();
142
void TreeKeyIdx::root() {
143
error = getTreeNodeFromIdxOffset(0, ¤tNode);
147
bool TreeKeyIdx::parent() {
148
if (currentNode.parent > -1) {
149
error = getTreeNodeFromIdxOffset(currentNode.parent, ¤tNode);
156
bool TreeKeyIdx::firstChild() {
157
if (currentNode.firstChild > -1) {
158
error = getTreeNodeFromIdxOffset(currentNode.firstChild, ¤tNode);
165
bool TreeKeyIdx::nextSibling() {
166
if (currentNode.next > -1) {
167
error = getTreeNodeFromIdxOffset(currentNode.next, ¤tNode);
174
bool TreeKeyIdx::previousSibling() {
176
__u32 target = currentNode.offset;
177
if (currentNode.parent > -1) {
178
getTreeNodeFromIdxOffset(currentNode.parent, &iterator);
179
getTreeNodeFromIdxOffset(iterator.firstChild, &iterator);
180
if (iterator.offset != target) {
181
while ((iterator.next != target) && (iterator.next > -1))
182
getTreeNodeFromIdxOffset(iterator.next, &iterator);
183
if (iterator.next > -1) {
184
error = getTreeNodeFromIdxOffset(iterator.offset, ¤tNode);
193
bool TreeKeyIdx::hasChildren() {
194
return (currentNode.firstChild > -1);
198
void TreeKeyIdx::append() {
200
if (currentNode.offset) {
201
getTreeNodeFromIdxOffset(currentNode.offset, &lastSib);
202
while (lastSib.next > -1) {
203
getTreeNodeFromIdxOffset(lastSib.next, &lastSib);
205
__u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
206
lastSib.next = idxOffset;
207
saveTreeNodeOffsets(&lastSib);
208
__u32 parent = currentNode.parent;
210
currentNode.offset = idxOffset;
211
currentNode.parent = parent;
216
void TreeKeyIdx::appendChild() {
221
__u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
222
currentNode.firstChild = idxOffset;
223
saveTreeNodeOffsets(¤tNode);
224
__u32 parent = currentNode.offset;
226
currentNode.offset = idxOffset;
227
currentNode.parent = parent;
232
void TreeKeyIdx::insertBefore() {
236
void TreeKeyIdx::remove() {
240
/******************************************************************************
241
* TreeKeyIdx::Create - Creates new key idx/dat files
243
* ENT: path - directory to store module files
247
signed char TreeKeyIdx::create(const char *ipath) {
249
char *buf = new char [ strlen (ipath) + 20 ];
252
stdstr(&path, ipath);
254
if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
255
path[strlen(path)-1] = 0;
257
sprintf(buf, "%s.dat", path);
259
fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
261
FileMgr::systemFileMgr.close(fd);
263
sprintf(buf, "%s.idx", path);
265
fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
267
FileMgr::systemFileMgr.close(fd2);
269
TreeKeyIdx newTree(path);
270
TreeKeyIdx::TreeNode root;
271
stdstr(&(root.name), "");
272
newTree.saveTreeNode(&root);
280
/******************************************************************************
281
* zStr::getidxbufdat - Gets the index string at the given dat offset
282
* NOTE: buf is calloc'd, or if not null, realloc'd and must
283
* be free'd by calling function
285
* ENT: ioffset - offset in dat file to lookup
286
* node - address of pointer to allocate for storage of string
289
void TreeKeyIdx::getTreeNodeFromDatOffset(long ioffset, TreeNode *node) const {
296
lseek(datfd->getFd(), ioffset, SEEK_SET);
298
read(datfd->getFd(), &tmp, 4);
299
node->parent = swordtoarch32(tmp);
301
read(datfd->getFd(), &tmp, 4);
302
node->next = swordtoarch32(tmp);
304
read(datfd->getFd(), &tmp, 4);
305
node->firstChild = swordtoarch32(tmp);
309
read(datfd->getFd(), &ch, 1);
313
stdstr(&(node->name), name.c_str());
315
read(datfd->getFd(), &tmp2, 2);
316
node->dsize = swordtoarch16(tmp2);
320
delete [] node->userData;
321
node->userData = new char [node->dsize];
322
read(datfd->getFd(), node->userData, node->dsize);
328
/******************************************************************************
329
* zStr::getidxbuf - Gets the index string at the given idx offset
330
* NOTE: buf is calloc'd, or if not null, realloc'd
331
* and must be freed by calling function
333
* ENT: ioffset - offset in idx file to lookup
334
* buf - address of pointer to allocate for storage of string
337
char TreeKeyIdx::getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const {
339
char error = KEYERR_OUTOFBOUNDS;
343
error = 77; // out of bounds but still position to 0;
346
node->offset = ioffset;
348
if (idxfd->getFd() > 0) {
349
lseek(idxfd->getFd(), ioffset, SEEK_SET);
350
if (read(idxfd->getFd(), &offset, 4) == 4) {
351
offset = swordtoarch32(offset);
352
error = (error == 77) ? KEYERR_OUTOFBOUNDS : 0;
353
getTreeNodeFromDatOffset(offset, node);
356
lseek(idxfd->getFd(), -4, SEEK_END);
357
if (read(idxfd->getFd(), &offset, 4) == 4) {
358
offset = swordtoarch32(offset);
359
getTreeNodeFromDatOffset(offset, node);
368
unsigned long TreeKeyIdx::getOffset() const {
369
return currentNode.offset;
372
void TreeKeyIdx::setOffset(unsigned long offset) {
373
error = getTreeNodeFromIdxOffset(offset, ¤tNode);
377
void TreeKeyIdx::saveTreeNodeOffsets(TreeNode *node) {
382
lseek(idxfd->getFd(), node->offset, SEEK_SET);
383
if (read(idxfd->getFd(), &tmp, 4) != 4) {
384
datOffset = lseek(datfd->getFd(), 0, SEEK_END);
385
tmp = archtosword32(datOffset);
386
write(idxfd->getFd(), &tmp, 4);
389
datOffset = swordtoarch32(tmp);
390
lseek(datfd->getFd(), datOffset, SEEK_SET);
393
tmp = archtosword32(node->parent);
394
write(datfd->getFd(), &tmp, 4);
396
tmp = archtosword32(node->next);
397
write(datfd->getFd(), &tmp, 4);
399
tmp = archtosword32(node->firstChild);
400
write(datfd->getFd(), &tmp, 4);
405
void TreeKeyIdx::copyFrom(const TreeKeyIdx &ikey) {
407
SWKey::copyFrom(ikey);
409
currentNode.offset = ikey.currentNode.offset;
410
currentNode.parent = ikey.currentNode.parent;
411
currentNode.next = ikey.currentNode.next;
412
currentNode.firstChild = ikey.currentNode.firstChild;
413
stdstr(&(currentNode.name), ikey.currentNode.name);
414
currentNode.dsize = ikey.currentNode.dsize;
416
if (currentNode.userData)
417
delete [] currentNode.userData;
418
if (currentNode.dsize) {
419
currentNode.userData = new char [ currentNode.dsize ];
420
memcpy(currentNode.userData, ikey.currentNode.userData, currentNode.dsize);
422
else currentNode.userData = 0;
424
bool newFiles = true;
426
if (path && ikey.path)
427
newFiles = strcmp(path, ikey.path);
430
stdstr(&path, ikey.path);
433
FileMgr::systemFileMgr.close(idxfd);
434
FileMgr::systemFileMgr.close(datfd);
436
idxfd = FileMgr::systemFileMgr.open(ikey.idxfd->path, ikey.idxfd->mode, ikey.idxfd->perms);
437
datfd = FileMgr::systemFileMgr.open(ikey.datfd->path, ikey.datfd->mode, ikey.datfd->perms);
442
void TreeKeyIdx::saveTreeNode(TreeNode *node) {
447
lseek(idxfd->getFd(), node->offset, SEEK_SET);
448
datOffset = lseek(datfd->getFd(), 0, SEEK_END);
449
tmp = archtosword32(datOffset);
450
write(idxfd->getFd(), &tmp, 4);
452
saveTreeNodeOffsets(node);
454
write(datfd->getFd(), node->name, strlen(node->name));
456
write(datfd->getFd(), &null, 1);
458
__u16 tmp2 = archtosword16(node->dsize);
459
write(datfd->getFd(), &tmp2, 2);
462
write(datfd->getFd(), node->userData, node->dsize);
468
void TreeKeyIdx::setText(const char *ikey) {
471
char *leaf = strtok(buf, "/");
473
while ((leaf) && (!Error())) {
474
bool ok, inChild = false;
475
for (ok = firstChild(); ok; ok = nextSibling()) {
477
if (!stricmp(leaf, getLocalName()))
480
leaf = strtok(0, "/");
482
if (inChild) { // if we didn't find a matching child node, default to first child
487
error = KEYERR_OUTOFBOUNDS;
496
void TreeKeyIdx::copyFrom(const SWKey &ikey) {
497
SWKey::copyFrom(ikey);
500
void TreeKeyIdx::setPosition(SW_POSITION p) {
506
error = getTreeNodeFromIdxOffset(lseek(idxfd->getFd(), -4, SEEK_END), ¤tNode);
509
Error(); // clear error from normalize
512
const char *TreeKeyIdx::getText() const {
513
return getFullName();
517
int TreeKeyIdx::_compare (const TreeKeyIdx & ikey) {
518
return (getOffset() - ikey.getOffset());
522
int TreeKeyIdx::compare(const SWKey &ikey) {
523
TreeKeyIdx *treeKey = SWDYNAMIC_CAST(TreeKeyIdx, (&ikey));
525
return _compare(*treeKey);
526
return SWKey::compare(ikey);
530
void TreeKeyIdx::decrement(int steps) {
531
error = getTreeNodeFromIdxOffset(currentNode.offset - (4*steps), ¤tNode);
534
void TreeKeyIdx::increment(int steps) {
535
error = getTreeNodeFromIdxOffset(currentNode.offset + (4*steps), ¤tNode);
540
decrement(steps * -1);
546
if (!nextSibbling() {
547
error = KEYERR_OUTOFBOUNDS;
558
TreeKeyIdx::TreeNode::TreeNode() {
568
void TreeKeyIdx::TreeNode::clear() {
586
TreeKeyIdx::TreeNode::~TreeNode() {
595
SWKey *TreeKeyIdx::clone() const
597
return new TreeKeyIdx(*this);