~ubuntu-branches/debian/squeeze/sword/squeeze

« back to all changes in this revision

Viewing changes to src/keys/treekeyidx.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Glassey
  • Date: 2004-01-15 15:50:07 UTC
  • Revision ID: james.westby@ubuntu.com-20040115155007-n9mz4x0zxrs1isd3
Tags: upstream-1.5.7
ImportĀ upstreamĀ versionĀ 1.5.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 *  versekey.h - code for class 'versekey'- a standard Biblical verse key
 
3
 *
 
4
 * $Id: treekeyidx.cpp,v 1.14 2003/06/27 01:41:07 scribe Exp $
 
5
 *
 
6
 * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
 
7
 *      CrossWire Bible Society
 
8
 *      P. O. Box 2528
 
9
 *      Tempe, AZ  85280-2528
 
10
 *
 
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.
 
14
 *
 
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.
 
19
 *
 
20
 */
 
21
 
 
22
 
 
23
#include <treekeyidx.h>
 
24
#include <fcntl.h>
 
25
#include <stdio.h>
 
26
#include <errno.h>
 
27
 
 
28
#ifndef __GNUC__
 
29
#include <io.h>
 
30
#else
 
31
#include <unistd.h>
 
32
#endif
 
33
 
 
34
SWORD_NAMESPACE_START
 
35
 
 
36
static const char nl = '\n';
 
37
static const char *classes[] = {"TreeKeyIdx", "TreeKey", "SWKey", "SWObject", 0};
 
38
SWClass TreeKeyIdx::classdef(classes);
 
39
 
 
40
 
 
41
TreeKeyIdx::TreeKeyIdx(const TreeKeyIdx &ikey) : currentNode() {
 
42
        init();
 
43
        path = 0;
 
44
        idxfd = 0;
 
45
        datfd = 0;
 
46
        copyFrom(ikey);
 
47
}
 
48
 
 
49
TreeKeyIdx::TreeKeyIdx(const char *idxPath, int fileMode) : currentNode() {
 
50
        char buf[127];
 
51
 
 
52
        init();
 
53
        path = 0;
 
54
        stdstr(&path, idxPath);
 
55
 
 
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.
 
59
 
 
60
        if (fileMode == -1) { // try read/write if possible
 
61
                fileMode = O_RDWR;
 
62
        }
 
63
                
 
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);
 
68
 
 
69
        if (datfd <= 0) {
 
70
                sprintf(buf, "Error: %d", errno);
 
71
                perror(buf);
 
72
                error = errno;
 
73
        }
 
74
        else {
 
75
                root();
 
76
        }
 
77
}
 
78
 
 
79
 
 
80
void TreeKeyIdx::init() {
 
81
        myclass = &classdef;
 
82
}
 
83
 
 
84
 
 
85
TreeKeyIdx::~TreeKeyIdx () {
 
86
        if (path)
 
87
                delete [] path;
 
88
 
 
89
        FileMgr::systemFileMgr.close(idxfd);
 
90
        FileMgr::systemFileMgr.close(datfd);
 
91
}
 
92
 
 
93
 
 
94
const char *TreeKeyIdx::getLocalName() {
 
95
        return currentNode.name;
 
96
}
 
97
 
 
98
 
 
99
const char *TreeKeyIdx::getUserData(int *size) {
 
100
        if (size)
 
101
                *size = (int)currentNode.dsize;
 
102
        return currentNode.userData;
 
103
}
 
104
 
 
105
 
 
106
void TreeKeyIdx::setUserData(const char *userData, int size) {
 
107
        if (currentNode.userData)
 
108
                delete currentNode.userData;
 
109
 
 
110
        if (!size)
 
111
                size = strlen(userData) + 1;
 
112
 
 
113
        currentNode.userData = new char [ size ];
 
114
        memcpy(currentNode.userData, userData, size);
 
115
        currentNode.dsize = size;
 
116
}
 
117
 
 
118
const char *TreeKeyIdx::setLocalName(const char *newName) {
 
119
        stdstr(&(currentNode.name), newName);
 
120
        return currentNode.name;
 
121
}
 
122
 
 
123
 
 
124
void TreeKeyIdx::save() {
 
125
        saveTreeNode(&currentNode);
 
126
}
 
127
 
 
128
 
 
129
const char *TreeKeyIdx::getFullName() const {
 
130
        TreeNode parent;
 
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;
 
137
        }
 
138
        return fullPath.c_str();
 
139
}
 
140
 
 
141
 
 
142
void TreeKeyIdx::root() {
 
143
        error = getTreeNodeFromIdxOffset(0, &currentNode);
 
144
}
 
145
 
 
146
 
 
147
bool TreeKeyIdx::parent() {
 
148
        if (currentNode.parent > -1) {
 
149
                error = getTreeNodeFromIdxOffset(currentNode.parent, &currentNode);
 
150
                return true;
 
151
        }
 
152
        return false;
 
153
}
 
154
 
 
155
 
 
156
bool TreeKeyIdx::firstChild() {
 
157
        if (currentNode.firstChild > -1) {
 
158
                error = getTreeNodeFromIdxOffset(currentNode.firstChild, &currentNode);
 
159
                return true;
 
160
        }
 
161
        return false;
 
162
}
 
163
 
 
164
 
 
165
bool TreeKeyIdx::nextSibling() {
 
166
        if (currentNode.next > -1) {
 
167
                error = getTreeNodeFromIdxOffset(currentNode.next, &currentNode);
 
168
                return true;
 
169
        }
 
170
        return false;
 
171
}
 
172
 
 
173
 
 
174
bool TreeKeyIdx::previousSibling() {
 
175
        TreeNode iterator;
 
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, &currentNode);
 
185
                                return true;
 
186
                        }
 
187
                }
 
188
        }
 
189
        return false;
 
190
}
 
191
 
 
192
 
 
193
bool TreeKeyIdx::hasChildren() {
 
194
        return (currentNode.firstChild > -1);
 
195
}
 
196
 
 
197
 
 
198
void TreeKeyIdx::append() {
 
199
        TreeNode lastSib;
 
200
        if (currentNode.offset) {
 
201
                getTreeNodeFromIdxOffset(currentNode.offset, &lastSib);
 
202
                while (lastSib.next > -1) {
 
203
                        getTreeNodeFromIdxOffset(lastSib.next, &lastSib);
 
204
                }
 
205
                __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
 
206
                lastSib.next = idxOffset;
 
207
                saveTreeNodeOffsets(&lastSib);
 
208
                __u32 parent = currentNode.parent;
 
209
                currentNode.clear();
 
210
                currentNode.offset = idxOffset;
 
211
                currentNode.parent = parent;
 
212
        }
 
213
}
 
214
 
 
215
 
 
216
void TreeKeyIdx::appendChild() {
 
217
        if (firstChild()) {
 
218
                append();
 
219
        }
 
220
        else {
 
221
                __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
 
222
                currentNode.firstChild = idxOffset;
 
223
                saveTreeNodeOffsets(&currentNode);
 
224
                __u32 parent = currentNode.offset;
 
225
                currentNode.clear();
 
226
                currentNode.offset = idxOffset;
 
227
                currentNode.parent = parent;
 
228
        }
 
229
}
 
230
 
 
231
 
 
232
void TreeKeyIdx::insertBefore() {
 
233
}
 
234
 
 
235
 
 
236
void TreeKeyIdx::remove() {
 
237
}
 
238
 
 
239
 
 
240
/******************************************************************************
 
241
 * TreeKeyIdx::Create   - Creates new key idx/dat files
 
242
 *
 
243
 * ENT: path    - directory to store module files
 
244
 * RET: error status
 
245
 */
 
246
 
 
247
signed char TreeKeyIdx::create(const char *ipath) {
 
248
        char *path = 0;
 
249
        char *buf = new char [ strlen (ipath) + 20 ];
 
250
        FileDesc *fd, *fd2;
 
251
 
 
252
        stdstr(&path, ipath);
 
253
 
 
254
        if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
 
255
                path[strlen(path)-1] = 0;
 
256
 
 
257
        sprintf(buf, "%s.dat", path);
 
258
        unlink(buf);
 
259
        fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
 
260
        fd->getFd();
 
261
        FileMgr::systemFileMgr.close(fd);
 
262
 
 
263
        sprintf(buf, "%s.idx", path);
 
264
        unlink(buf);
 
265
        fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
 
266
        fd2->getFd();
 
267
        FileMgr::systemFileMgr.close(fd2);
 
268
 
 
269
        TreeKeyIdx newTree(path);
 
270
        TreeKeyIdx::TreeNode root;
 
271
        stdstr(&(root.name), "");
 
272
        newTree.saveTreeNode(&root);
 
273
 
 
274
        delete [] path;
 
275
        
 
276
        return 0;
 
277
}
 
278
 
 
279
 
 
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
 
284
 *
 
285
 * ENT: ioffset - offset in dat file to lookup
 
286
 *              node            - address of pointer to allocate for storage of string
 
287
 */
 
288
 
 
289
void TreeKeyIdx::getTreeNodeFromDatOffset(long ioffset, TreeNode *node) const {
 
290
        char ch;
 
291
        __s32  tmp;
 
292
        __u16  tmp2;
 
293
 
 
294
        if (datfd > 0) {
 
295
 
 
296
                lseek(datfd->getFd(), ioffset, SEEK_SET);
 
297
 
 
298
                read(datfd->getFd(), &tmp, 4);
 
299
                node->parent = swordtoarch32(tmp);
 
300
 
 
301
                read(datfd->getFd(), &tmp, 4);
 
302
                node->next = swordtoarch32(tmp);
 
303
 
 
304
                read(datfd->getFd(), &tmp, 4);
 
305
                node->firstChild = swordtoarch32(tmp);
 
306
 
 
307
                SWBuf name;
 
308
                do {
 
309
                        read(datfd->getFd(), &ch, 1);
 
310
                        name += ch;
 
311
                } while (ch);
 
312
 
 
313
                stdstr(&(node->name), name.c_str());
 
314
 
 
315
                read(datfd->getFd(), &tmp2, 2);
 
316
                node->dsize = swordtoarch16(tmp2);
 
317
 
 
318
                if (node->dsize) {
 
319
                        if (node->userData)
 
320
                                delete [] node->userData;
 
321
                        node->userData = new char [node->dsize];
 
322
                        read(datfd->getFd(), node->userData, node->dsize);
 
323
                }
 
324
        }
 
325
}
 
326
 
 
327
 
 
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
 
332
 *
 
333
 * ENT: ioffset - offset in idx file to lookup
 
334
 *              buf             - address of pointer to allocate for storage of string
 
335
 */
 
336
 
 
337
char TreeKeyIdx::getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const {
 
338
        __u32 offset;
 
339
        char error = KEYERR_OUTOFBOUNDS;
 
340
        
 
341
        if (ioffset < 0) {
 
342
                ioffset = 0;
 
343
                error = 77;     // out of bounds but still position to 0;
 
344
        }
 
345
 
 
346
        node->offset = ioffset;
 
347
        if (idxfd > 0) {
 
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);
 
354
                        }
 
355
                        else {
 
356
                                lseek(idxfd->getFd(), -4, SEEK_END);
 
357
                                if (read(idxfd->getFd(), &offset, 4) == 4) {
 
358
                                        offset = swordtoarch32(offset);
 
359
                                        getTreeNodeFromDatOffset(offset, node);
 
360
                                }
 
361
                        }
 
362
                }
 
363
        }
 
364
        return error;
 
365
}
 
366
 
 
367
 
 
368
unsigned long TreeKeyIdx::getOffset() const {
 
369
        return currentNode.offset;
 
370
}
 
371
 
 
372
void TreeKeyIdx::setOffset(unsigned long offset) {
 
373
        error = getTreeNodeFromIdxOffset(offset, &currentNode);
 
374
}
 
375
 
 
376
 
 
377
void TreeKeyIdx::saveTreeNodeOffsets(TreeNode *node) {
 
378
        long datOffset = 0;
 
379
        __s32 tmp;
 
380
 
 
381
        if (idxfd > 0) {
 
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);
 
387
                }
 
388
                else {
 
389
                        datOffset = swordtoarch32(tmp);
 
390
                        lseek(datfd->getFd(), datOffset, SEEK_SET);
 
391
                }
 
392
 
 
393
                tmp = archtosword32(node->parent);
 
394
                write(datfd->getFd(), &tmp, 4);
 
395
 
 
396
                tmp = archtosword32(node->next);
 
397
                write(datfd->getFd(), &tmp, 4);
 
398
 
 
399
                tmp = archtosword32(node->firstChild);
 
400
                write(datfd->getFd(), &tmp, 4);
 
401
        }
 
402
}
 
403
 
 
404
 
 
405
void TreeKeyIdx::copyFrom(const TreeKeyIdx &ikey) {
 
406
 
 
407
        SWKey::copyFrom(ikey);
 
408
 
 
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;
 
415
 
 
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);
 
421
        }
 
422
        else currentNode.userData = 0;
 
423
 
 
424
        bool newFiles = true;
 
425
 
 
426
        if (path && ikey.path)
 
427
                newFiles = strcmp(path, ikey.path);
 
428
 
 
429
        if (newFiles) {
 
430
                stdstr(&path, ikey.path);
 
431
 
 
432
                if (idxfd) {
 
433
                        FileMgr::systemFileMgr.close(idxfd);
 
434
                        FileMgr::systemFileMgr.close(datfd);
 
435
                }
 
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);
 
438
        }
 
439
}
 
440
 
 
441
 
 
442
void TreeKeyIdx::saveTreeNode(TreeNode *node) {
 
443
        long datOffset = 0;
 
444
        __s32 tmp;
 
445
        if (idxfd > 0) {
 
446
 
 
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);
 
451
 
 
452
                saveTreeNodeOffsets(node);
 
453
 
 
454
                write(datfd->getFd(), node->name, strlen(node->name));
 
455
                char null = 0;
 
456
                write(datfd->getFd(), &null, 1);
 
457
 
 
458
                __u16 tmp2 = archtosword16(node->dsize);
 
459
                write(datfd->getFd(), &tmp2, 2);
 
460
 
 
461
                if (node->dsize) {
 
462
                        write(datfd->getFd(), node->userData, node->dsize);
 
463
                }
 
464
        }
 
465
}
 
466
 
 
467
 
 
468
void TreeKeyIdx::setText(const char *ikey) {
 
469
        char *buf = 0;
 
470
        stdstr(&buf, ikey);
 
471
        char *leaf = strtok(buf, "/");
 
472
        root();
 
473
        while ((leaf) && (!Error())) {
 
474
                bool ok, inChild = false;
 
475
                for (ok = firstChild(); ok; ok = nextSibling()) {
 
476
                        inChild = true;
 
477
                        if (!stricmp(leaf, getLocalName()))
 
478
                                break;
 
479
                }
 
480
                leaf = strtok(0, "/");
 
481
                if (!ok) {
 
482
                        if (inChild) {  // if we didn't find a matching child node, default to first child
 
483
                                parent();
 
484
                                firstChild();
 
485
                        }
 
486
                        if (leaf)
 
487
                                error = KEYERR_OUTOFBOUNDS;
 
488
                        break;
 
489
                }
 
490
        }
 
491
        delete [] buf;
 
492
}
 
493
 
 
494
 
 
495
 
 
496
void TreeKeyIdx::copyFrom(const SWKey &ikey) {
 
497
        SWKey::copyFrom(ikey);
 
498
}
 
499
 
 
500
void TreeKeyIdx::setPosition(SW_POSITION p) {
 
501
        switch (p) {
 
502
        case POS_TOP:
 
503
                root();
 
504
                break;
 
505
        case POS_BOTTOM:
 
506
                error = getTreeNodeFromIdxOffset(lseek(idxfd->getFd(), -4, SEEK_END), &currentNode);
 
507
                break;
 
508
        } 
 
509
        Error();        // clear error from normalize
 
510
}
 
511
 
 
512
const char *TreeKeyIdx::getText() const {
 
513
        return getFullName();
 
514
}
 
515
 
 
516
 
 
517
int TreeKeyIdx::_compare (const TreeKeyIdx & ikey) {
 
518
                return (getOffset() - ikey.getOffset());
 
519
}
 
520
 
 
521
 
 
522
int TreeKeyIdx::compare(const SWKey &ikey) {
 
523
        TreeKeyIdx *treeKey = SWDYNAMIC_CAST(TreeKeyIdx, (&ikey));
 
524
        if (treeKey)
 
525
                return _compare(*treeKey);
 
526
        return SWKey::compare(ikey);
 
527
}
 
528
 
 
529
 
 
530
void TreeKeyIdx::decrement(int steps) {
 
531
        error = getTreeNodeFromIdxOffset(currentNode.offset - (4*steps), &currentNode);
 
532
}
 
533
 
 
534
void TreeKeyIdx::increment(int steps) {
 
535
        error = getTreeNodeFromIdxOffset(currentNode.offset + (4*steps), &currentNode);
 
536
 
 
537
/*
 
538
        // assert positive
 
539
        if (steps < 0) {
 
540
                decrement(steps * -1);
 
541
                return;
 
542
        }
 
543
 
 
544
        while (steps > 0) {
 
545
                if (!firstChild()) {
 
546
                        if (!nextSibbling() {
 
547
                                error = KEYERR_OUTOFBOUNDS;
 
548
                                return;
 
549
                        }
 
550
                }
 
551
                steps--;
 
552
        }
 
553
*/
 
554
}
 
555
 
 
556
 
 
557
 
 
558
TreeKeyIdx::TreeNode::TreeNode() {
 
559
 
 
560
        name       = 0;
 
561
        stdstr(&name, "");
 
562
        userData   = 0;
 
563
 
 
564
        clear();
 
565
}
 
566
 
 
567
 
 
568
void TreeKeyIdx::TreeNode::clear() {
 
569
        offset     = 0;
 
570
        parent     = -1;
 
571
        next       = -1;
 
572
        firstChild = -1;
 
573
        dsize      = 0;
 
574
 
 
575
        if (name)
 
576
                delete [] name;
 
577
        name = 0;
 
578
        stdstr(&name, "");
 
579
 
 
580
        if (userData)
 
581
                delete [] userData;
 
582
        userData   = 0;
 
583
}
 
584
 
 
585
 
 
586
TreeKeyIdx::TreeNode::~TreeNode() {
 
587
        if (name)
 
588
                delete [] name;
 
589
        
 
590
        if (userData)
 
591
                delete [] userData;
 
592
}
 
593
 
 
594
 
 
595
SWKey *TreeKeyIdx::clone() const
 
596
{
 
597
        return new TreeKeyIdx(*this);
 
598
}
 
599
 
 
600
SWORD_NAMESPACE_END