home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / b+tree_mjr / part03 < prev    next >
Encoding:
Text File  |  1990-01-19  |  51.8 KB  |  2,040 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v10i029: B+tree library, part03 of 5
  3. from: mjr@umiacs.UMD.EDU (Marcus J. Ranum)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 10, Issue 29
  7. Submitted-by: mjr@umiacs.UMD.EDU (Marcus J. Ranum)
  8. Archive-name: b+tree_mjr/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 5)."
  17. # Contents:  b+tree/btdbmlib/stfree.c b+tree/btlib/btinsert.c
  18. #   b+tree/btlib/btintern.h b+tree/btlib/btio.c b+tree/btlib/btoopen.c
  19. #   b+tree/btlib/btpage1.c b+tree/doc/btdbm.3 b+tree/utils/dbtest.c
  20. # Wrapped by mjr@atreus on Fri Jan 19 10:34:58 1990
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'b+tree/btdbmlib/stfree.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'b+tree/btdbmlib/stfree.c'\"
  24. else
  25. echo shar: Extracting \"'b+tree/btdbmlib/stfree.c'\" \(5404 characters\)
  26. sed "s/^X//" >'b+tree/btdbmlib/stfree.c' <<'END_OF_FILE'
  27. X#include    <sys/types.h>
  28. X#include    "stoconf.h"
  29. X#include    "store.h"
  30. X#include    "stointern.h"
  31. X
  32. X
  33. X/*
  34. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  35. X                    All rights reserved
  36. X
  37. X
  38. X          This software, its documentation,  and  supporting
  39. X          files  are  copyrighted  material  and may only be
  40. X          distributed in accordance with the terms listed in
  41. X          the COPYRIGHT document.
  42. X*/
  43. X
  44. X
  45. X#ifndef    lint
  46. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/btdbmlib/RCS/stfree.c,v 1.1 89/10/24 10:09:14 mjr Rel $";
  47. X#endif
  48. X
  49. X/*
  50. X    free list management and creation. the free list is maintained as a
  51. X    stored record using the library's own internal routines. when a 
  52. X    request is made to free something, the order of operations is:
  53. X
  54. X    1) if the record is the free list, refuse to free it !!!
  55. X    2)if there is more than one reference to the record, just
  56. X    decrement the reference count and return.
  57. X    3) if there is not a currently defined free list:
  58. X        a)one is allocated via store_alloc(), which can actually
  59. X        be safely called because it will not look at the nonexistent
  60. X        free list. if the free-list management is changed, this will
  61. X        probably get very weird.
  62. X        b)make a free list entry and paste it into the new free list
  63. X        c)update the superblock
  64. X        d)return - done.
  65. X    4) if there WAS a free list, 
  66. X        a)if the whole allocated block of the free list is not in
  67. X        currently marked as in-use, just paste the new free list entry
  68. X        at the end of the free list block and return.
  69. X    - or -
  70. X        b)scan through the allocated block looking for an empty slot
  71. X        and if one is found, paste it directly in. this operation is
  72. X        less inefficient than it may seem because the scan is buffered
  73. X        pretty intelligently.
  74. X    - if 'b' fails -
  75. X        c)we know we now have a full free list block with no empty
  76. X        slots, so we bite the bullet, and allocate a bigger free
  77. X        list block at the end of file, and copy the old one into
  78. X        it. we then have enough free space to paste the new free
  79. X        list entry directly at the end of the block, as in '3'
  80. X        above. this should presumably happen fairly rarely. it
  81. X        costs some, but the copy is pretty well buffered.
  82. X*/
  83. X
  84. Xstore_free(r,rec)
  85. XSTORE    *r;
  86. Xsto_ptr        rec;
  87. X{
  88. X    struct    sto_freeent    fry;
  89. X    struct    sto_freeent    *freep;
  90. X    struct    sto_hdr    rbuf;
  91. X    struct    sto_hdr    nbuf;
  92. X    sto_ptr    newf;
  93. X    int        fcnt;
  94. X    int        junk;
  95. X    int        byts;
  96. X
  97. X    /* may as well make sure everything is OK before we do work */
  98. X    if(store_gethdr(r,rec,&rbuf) == STO_ERR)
  99. X        return(STO_ERR);
  100. X
  101. X    /* sneaky dog ! */
  102. X    if(rec == r->sblk.free) {
  103. X        store_errno(r) = STO_NOREC;
  104. X        return(STO_ERR);
  105. X    }
  106. X
  107. X    /* if there are is than one reference to this record, just decrement */
  108. X    /* it and we are happy-like, even though it could be bad */
  109. X    if(--rbuf.refs > 0) {
  110. X        return(store_puthdr(r,rec,&rbuf));
  111. X    }
  112. X
  113. X    /* if it is linked to siblinks, unlink them */
  114. X    if(rbuf.next != STO_NULL || rbuf.prev != STO_NULL) {
  115. X        if(store_unlink(r,rec) == STO_ERR)
  116. X            return(STO_ERR);
  117. X
  118. X        /* one flaw in the design: we have to re-read the header */
  119. X        /* since the call to unlink changes pointers and all that */
  120. X        if(store_gethdr(r,rec,&rbuf) == STO_ERR)
  121. X            return(STO_ERR);
  122. X    }
  123. X
  124. X    fry.addr = rec;
  125. X    fry.size = rbuf.size;
  126. X
  127. X    /* if there is not existing free page, create one */
  128. X    if(r->sblk.free == STO_NULL) {
  129. X        r->sblk.free = store_alloc(r,STO_BUFSIZ);
  130. X        if(r->sblk.free == STO_NULL)
  131. X            return(STO_ERR);
  132. X        STO_FREENXT(store_buffer(r)) = STO_NULL;
  133. X        STO_FREECNT(store_buffer(r)) = 0;
  134. X
  135. X        if(store_write(r,r->sblk.free,0L,store_buffer(r),2 * sizeof(off_t)) != STO_OK ||
  136. X            store_wsuper(r) != STO_OK)
  137. X                return(STO_ERR);
  138. X    }
  139. X
  140. X    /* now grab the free record header */
  141. X    if(store_gethdr(r,r->sblk.free,&rbuf) == STO_ERR)
  142. X        return(STO_ERR);
  143. X
  144. X    /* is there room for a simple insert, or do we need to get mean ? */
  145. X    if(rbuf.used + STO_FSIZ < rbuf.size) {
  146. X        if(store_write(r,r->sblk.free,(off_t)rbuf.used,(unsigned char *)&fry,STO_FSIZ) == STO_ERR)
  147. X            return(STO_ERR);
  148. X        return(STO_OK);
  149. X    } else {
  150. X        off_t    currof;
  151. X
  152. X        currof = (off_t)(2 * sizeof(off_t));
  153. X        while(1) {
  154. X            int    ismore;
  155. X
  156. X            ismore = store_read(r,r->sblk.free,currof,store_buffer(r),store_bufsiz(r),&byts);
  157. X            if(ismore == STO_ERR)
  158. X                return(STO_ERR);
  159. X
  160. X            if(currof == 0L) {
  161. X                freep = STO_FREEBUF(store_buffer(r));
  162. X                fcnt = ((byts - (2 * sizeof(off_t))) / STO_FSIZ); 
  163. X            } else {
  164. X                freep = (struct sto_freeent *)store_buffer(r);
  165. X                fcnt = byts / STO_FSIZ; 
  166. X            }
  167. X
  168. X            currof += (off_t)byts;
  169. X
  170. X            for(junk = 0; junk < fcnt; junk++) {
  171. X                if(freep->addr == STO_NULL) {
  172. X                    if(store_write(r,r->sblk.free,(off_t)(2 * sizeof(off_t) + (junk * STO_FSIZ)),(unsigned char *)&fry,sizeof(fry)) == STO_ERR)
  173. X                        return(STO_ERR);
  174. X                }
  175. X                freep++;
  176. X            }
  177. X            if(ismore != STO_MORE)
  178. X                break;
  179. X        }
  180. X    }
  181. X
  182. X    /* brutal but effective. Allocate a bigger free block at EOF */
  183. X    nbuf.size = rbuf.size * 2; 
  184. X    newf = r->sblk.high;
  185. X    r->sblk.high += nbuf.size + STO_HSIZ;
  186. X    nbuf.magic = STO_DFLTMAGIC; 
  187. X    nbuf.used = rbuf.used; 
  188. X    nbuf.refs = 1; 
  189. X    nbuf.next = nbuf.prev = STO_NULL;
  190. X
  191. X    if(store_puthdr(r,newf,&nbuf) == STO_ERR)
  192. X        return(STO_ERR);
  193. X
  194. X    if(store_copy(r,r->sblk.free,newf) == STO_ERR)
  195. X        return(STO_ERR);
  196. X
  197. X    if(store_write(r,newf,(off_t)nbuf.used,(unsigned char *)&fry,sizeof(fry)) == STO_ERR)
  198. X        return(STO_ERR);
  199. X
  200. X    /* kludge #2 - free the old free page */
  201. X    fry.addr = r->sblk.free;
  202. X    fry.size = rbuf.size;
  203. X
  204. X    if(store_write(r,newf,(off_t)nbuf.used,(unsigned char *)&fry,sizeof(fry)) == STO_ERR)
  205. X        return(STO_ERR);
  206. X
  207. X    r->sblk.free = newf;
  208. X
  209. X    return(store_wsuper(r));
  210. X}
  211. END_OF_FILE
  212. if test 5404 -ne `wc -c <'b+tree/btdbmlib/stfree.c'`; then
  213.     echo shar: \"'b+tree/btdbmlib/stfree.c'\" unpacked with wrong size!
  214. fi
  215. # end of 'b+tree/btdbmlib/stfree.c'
  216. fi
  217. if test -f 'b+tree/btlib/btinsert.c' -a "${1}" != "-c" ; then 
  218.   echo shar: Will not clobber existing file \"'b+tree/btlib/btinsert.c'\"
  219. else
  220. echo shar: Extracting \"'b+tree/btlib/btinsert.c'\" \(7136 characters\)
  221. sed "s/^X//" >'b+tree/btlib/btinsert.c' <<'END_OF_FILE'
  222. X#include    <sys/types.h>
  223. X#include    <stdio.h>
  224. X#include    "btconf.h"
  225. X#include    "btree.h"
  226. X#include    "btintern.h"
  227. X
  228. X/*
  229. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  230. X                    All rights reserved
  231. X
  232. X
  233. X          This software, its documentation,  and  supporting
  234. X          files  are  copyrighted  material  and may only be
  235. X          distributed in accordance with the terms listed in
  236. X          the COPYRIGHT document.
  237. X*/
  238. X
  239. X
  240. X#ifndef    lint
  241. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/btlib/RCS/btinsert.c,v 1.1 89/10/24 10:08:58 mjr Rel $";
  242. X#endif
  243. X
  244. X
  245. Xbt_insert(b,key,len,rrn,dupflg)
  246. XBT_INDEX    *b;
  247. Xbt_chrp        key;
  248. Xint        len;
  249. Xoff_t        rrn;
  250. Xint        dupflg;
  251. X{
  252. X    struct    bt_cache *kp;    /* scratch buffer for promoted keys */
  253. X    struct    bt_cache *op;    /* old page */
  254. X    int    staklev;
  255. X    off_t    ipag;        /* page to insert into */
  256. X    off_t    ival;        /* index value to insert */
  257. X    int    keyat;        /* key # at which to insert */
  258. X    bt_chrp    kp1;        /* rotating key buffer pointers */
  259. X    bt_chrp    kp2;
  260. X    off_t    ptj;        /* junk */
  261. X    int    sr;
  262. X
  263. X    if(len > BT_MAXK(b)) {
  264. X        bt_errno(b) = BT_KTOOBIG;
  265. X        return(BT_ERR);
  266. X    }
  267. X
  268. X    if(len <= 0) {
  269. X        bt_errno(b) = BT_ZEROKEY;
  270. X        return(BT_ERR);
  271. X    }
  272. X
  273. X    if(bt_seekdown(b,key,len) == BT_ERR)
  274. X        return(BT_ERR);
  275. X
  276. X    /* set current stack level */
  277. X    staklev = b->sblk.levs - 1;
  278. X    ipag = b->stack[staklev].pg;
  279. X
  280. X    /* allocate a scratch buffer for the key and promoted key */
  281. X    /* since all keys will be < pagesiz/2, "split" the buffer */
  282. X    if((kp = bt_rpage(b,BT_NULL)) == NULL)
  283. X        return(BT_ERR);
  284. X
  285. X    /* set promotion key ptrs */
  286. X    kp1 = kp->p;
  287. X    /* split buffers MUST be aligned! */
  288. X    kp2 = kp->p + DOALIGN(bt_pagesiz(b) / 2);
  289. X
  290. X    /* *THIS* bullshit should not be necessary */
  291. X#ifdef    USE_BCOPY
  292. X    (void)bcopy((char *)key,(char *)kp1,len);
  293. X#endif
  294. X#ifdef    USE_MEMCPY
  295. X    (void)memcpy((char *)key,(char *)kp1,len);
  296. X#endif
  297. X#ifdef    USE_MOVEMEM
  298. X    (void)movemem((char *)key,(char *)kp1,len);
  299. X#endif
  300. X    ival = rrn;
  301. X
  302. X    /* invalidate current notion of where we are in the tree */
  303. X    b->cpag = BT_NULL;
  304. X
  305. X    /* set up key location for first page insert */
  306. X    if((op = bt_rpage(b,ipag)) == NULL)
  307. X        goto bombout;
  308. X
  309. X    /* locate insert point, check if duplicate */
  310. X    /* this has the side-effect of setting keyat for the first */
  311. X    /* run of insert. after the first insert, subsequent key */
  312. X    /* positions are gotten from the stack, rather than searching */
  313. X    sr = bt_srchpg(kp1,len,bt_dtype(b),b->cmpfn,&ptj,&keyat,op->p);
  314. X    if(sr == BT_ERR) {
  315. X        bt_errno(b) = BT_PAGESRCH;
  316. X        return(BT_ERR);
  317. X    }
  318. X
  319. X    /* if the search returned OK, we have a duplicate key and */
  320. X    /* check to see if dupflg is set - if so, we slam a new */
  321. X    /* copy of the rrn in, and return immediately. */
  322. X    if(sr == BT_OK && HIPT(op->p) == BT_NULL) {
  323. X        /* handle dup keys */
  324. X        if(dupflg == 0) {
  325. X            bt_errno(b) = BT_DUPKEY;
  326. X            goto bombout;
  327. X        } else {
  328. X            /* paste new data ptr in page */
  329. X            /* and write it out again. */
  330. X            off_t    *p;
  331. X            p = (off_t *)KEYCLD(op->p);
  332. X            *(p + keyat) = rrn;
  333. X            op->flags = BT_CHE_DIRTY;
  334. X            if(bt_wpage(b,op) == BT_ERR ||
  335. X                bt_wpage(b,kp) == BT_ERR)
  336. X                return(BT_ERR);
  337. X
  338. X            /* mark all as well with tree */
  339. X            bt_clearerr(b);
  340. X            return(BT_OK);
  341. X        }
  342. X    }
  343. X
  344. X
  345. X    /* this loop should be comfortably repeated until we perform a */
  346. X    /* simple insert without a split, which will clean everything up */
  347. X    /* and return correctly. breaking out indicates a fatal problem */
  348. X    while(1) {
  349. X
  350. X        /* here is where we figure out if we need to split, or */
  351. X        /* if we can just perform a simple insert instead */
  352. X        if((int)KEYUSE(op->p) + len + sizeof(int) + sizeof(off_t) < bt_pagesiz(b)) {
  353. X            struct    bt_cache *tp;
  354. X
  355. X            if((tp = bt_rpage(b,BT_NULL)) == NULL)
  356. X                goto bombout;
  357. X;
  358. X            bt_inspg(kp1,len,&ival,keyat,op->p,tp->p);
  359. X            /* swap the page numbers, invalidate the old, */
  360. X            /* mark the new as dirty to force a write */
  361. X            tp->num = op->num;
  362. X            tp->flags = BT_CHE_DIRTY;
  363. X            op->num = BT_NULL;
  364. X
  365. X            if(bt_wpage(b,op) == BT_ERR ||
  366. X                bt_wpage(b,tp) == BT_ERR ||
  367. X                bt_wpage(b,kp) == BT_ERR)
  368. X                return(BT_ERR);
  369. X
  370. X            /* mark all as well with tree */
  371. X            bt_clearerr(b);
  372. X            return(BT_OK);
  373. X        } else {
  374. X            struct    bt_cache *lp;    /* new page to hold low keys */
  375. X            struct    bt_cache *hp;    /* new page to hold hi keys */
  376. X            off_t    savlft;        /* saved left sib page # */
  377. X            off_t    npag;        /* new page # */
  378. X
  379. X            /* allocate new page for low keys */
  380. X            if((npag = bt_newpage(b)) == BT_NULL)
  381. X                goto bombout;
  382. X
  383. X            /* allocate new scratch page for low keys */
  384. X            if((lp = bt_rpage(b,BT_NULL)) == NULL)
  385. X                goto bombout;
  386. X            /* allocate new scratch page for low keys */
  387. X            if((hp = bt_rpage(b,BT_NULL)) == NULL)
  388. X                goto bombout;
  389. X
  390. X            /* and do the thing */
  391. X            bt_splpg(kp1,len,&ival,keyat,bt_pagesiz(b)/2,op->p,lp->p,hp->p,kp2,&len);
  392. X
  393. X
  394. X            /* patch sibs */
  395. X            LSIB(hp->p) = npag;
  396. X            RSIB(hp->p) = RSIB(op->p);
  397. X            LSIB(lp->p) = LSIB(op->p);
  398. X            savlft = LSIB(op->p);
  399. X            RSIB(lp->p) = ipag;
  400. X
  401. X            /* mark newly split pages as real */
  402. X            lp->num = npag;
  403. X            lp->flags = BT_CHE_DIRTY;
  404. X            hp->num = ipag;
  405. X            hp->flags = BT_CHE_DIRTY;
  406. X
  407. X            op->num = BT_NULL;
  408. X
  409. X            if(bt_wpage(b,op) == BT_ERR ||
  410. X                bt_wpage(b,lp) == BT_ERR ||
  411. X                bt_wpage(b,hp) == BT_ERR)
  412. X                goto bombout;
  413. X
  414. X            /* patch right sib ptr of low pages left sib */
  415. X            if(savlft != BT_NULL) {
  416. X                if((op = bt_rpage(b,savlft)) == NULL)
  417. X                    goto bombout;
  418. X                RSIB(op->p) = npag;
  419. X                op->flags = BT_CHE_DIRTY;
  420. X                if(bt_wpage(b,op) == BT_ERR)
  421. X                    goto bombout;
  422. X            }
  423. X
  424. X            /* since we are not done, the new value */
  425. X            /* ptr to insert at the next level is that */
  426. X            /* of the new page we just allocated */
  427. X            ival = npag;
  428. X
  429. X
  430. X            /* if current page was root, make new root */
  431. X            if(ipag == b->sblk.root) {
  432. X                off_t    nr;
  433. X
  434. X                /* get new page # */
  435. X                if((nr = bt_newpage(b)) == BT_NULL)
  436. X                    goto bombout;
  437. X
  438. X                /* two scratch pages */
  439. X                if((op = bt_rpage(b,BT_NULL)) == NULL)
  440. X                    goto bombout;
  441. X                if((lp = bt_rpage(b,BT_NULL)) == NULL)
  442. X                    goto bombout;
  443. X
  444. X                /* prime empty root page */
  445. X                LSIB(op->p) = RSIB(op->p) = BT_NULL;
  446. X                KEYCNT(op->p) = 0;
  447. X                KEYLEN(op->p) = 0;
  448. X                HIPT(op->p) = ipag;
  449. X
  450. X                /* we already know where to insert */
  451. X                bt_inspg(kp2,len,&npag,0,op->p,lp->p);
  452. X
  453. X                /* fix cache stuff and requeue */
  454. X                op->num = BT_NULL;
  455. X                lp->flags = BT_CHE_DIRTY;
  456. X                lp->num = nr;
  457. X                
  458. X
  459. X                if(bt_wpage(b,lp) == BT_ERR ||
  460. X                    bt_wpage(b,kp) == BT_ERR ||
  461. X                    bt_wpage(b,op) == BT_ERR)
  462. X                    goto bombout;
  463. X
  464. X                /* finally, sync up root */
  465. X                b->sblk.root = nr;
  466. X                b->sblk.levs++;
  467. X                b->dirt++;
  468. X                if(bt_wsuper(b) == BT_ERR)
  469. X                    goto bombout;
  470. X
  471. X                /* mark all as well with tree */
  472. X                bt_clearerr(b);
  473. X
  474. X                /* return - we are done */
  475. X                return(BT_OK);
  476. X            }
  477. X        }
  478. X
  479. X        /* still going, pop stack level */
  480. X        staklev--;
  481. X        keyat = b->stack[staklev].ky;
  482. X
  483. X        /* current insert page is read from stack */
  484. X        ipag = b->stack[staklev].pg;
  485. X
  486. X        if((op = bt_rpage(b,ipag)) == NULL)
  487. X            goto bombout;
  488. X
  489. X        /* flip key buffer ptrs */
  490. X        if(kp1 != kp->p) {
  491. X            kp1 = kp->p;
  492. X            kp2 = kp->p + DOALIGN(bt_pagesiz(b) / 2);
  493. X        } else {
  494. X            kp1 = kp->p + DOALIGN(bt_pagesiz(b) / 2);
  495. X            kp2 = kp->p;
  496. X        }
  497. X    }
  498. X
  499. Xbombout:
  500. X    /* if we reach this point, some fatal error has doubtless occurred */
  501. X    /* try to bail out, though the tree is almost certainly toast */
  502. X    if(op != NULL)
  503. X        (void)bt_wpage(b,op);
  504. X    if(kp != NULL)
  505. X        (void)bt_wpage(b,kp);
  506. X    return(BT_ERR);
  507. X}
  508. END_OF_FILE
  509. if test 7136 -ne `wc -c <'b+tree/btlib/btinsert.c'`; then
  510.     echo shar: \"'b+tree/btlib/btinsert.c'\" unpacked with wrong size!
  511. fi
  512. # end of 'b+tree/btlib/btinsert.c'
  513. fi
  514. if test -f 'b+tree/btlib/btintern.h' -a "${1}" != "-c" ; then 
  515.   echo shar: Will not clobber existing file \"'b+tree/btlib/btintern.h'\"
  516. else
  517. echo shar: Extracting \"'b+tree/btlib/btintern.h'\" \(4753 characters\)
  518. sed "s/^X//" >'b+tree/btlib/btintern.h' <<'END_OF_FILE'
  519. X#ifndef    _DEF_BT_INTERN_H
  520. X
  521. X/*
  522. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  523. X                    All rights reserved
  524. X
  525. X
  526. X          This software, its documentation,  and  supporting
  527. X          files  are  copyrighted  material  and may only be
  528. X          distributed in accordance with the terms listed in
  529. X          the COPYRIGHT document.
  530. X*/
  531. X
  532. X
  533. X/*
  534. X    $Header: /atreus/mjr/hacks/btree/btlib/RCS/btintern.h,v 1.1 89/10/24 10:09:08 mjr Rel $
  535. X    THIS SHOULD NOT BE INCLUDED BY USER-LEVEL PROGRAMS
  536. X*/
  537. X
  538. X#define    BT_NULL    ((off_t)-1L)
  539. X#define    BT_FREE    ((off_t)-2L)
  540. X
  541. X/* make life easier with function pointers */
  542. Xtypedef    int    (*FUNCP)();
  543. X
  544. X/* cache flags - not needed by user code */
  545. X#define    BT_CHE_CLEAN    0
  546. X#define    BT_CHE_DIRTY    1
  547. X#define    BT_CHE_LOCKD    2
  548. X
  549. X/* forward decls for internal funcs only */
  550. Xextern    struct bt_cache *bt_rpage();
  551. Xextern    off_t        bt_newpage();
  552. Xextern    void        bt_inspg();
  553. Xextern    void        bt_splpg();
  554. X
  555. X#ifndef    NO_BT_DEBUG
  556. Xextern    void        bt_dump();
  557. X#endif
  558. X
  559. X/*
  560. Xminumum allowable page cache. since page sizes are variable,
  561. Xthe cache is also used to provide buffers for insertion and
  562. Xdeletion, or splitting. if there are not enough, nothing works
  563. Xthis value was determined from intimate knowledge of the code
  564. X*/
  565. X#define    BT_MINCACHE    4
  566. X
  567. X
  568. X/*
  569. X Macros used in manipulating btree pages.
  570. X
  571. X this stuff is the machine specific part - if these macros are
  572. X not right, you are guaranteed to know about it right away when
  573. X this code is run. If you know exact values, you can plug them
  574. X in directly, otherwise, we guess. getting it wrong will waste
  575. X some space, is all. note that the off_ts are clustered at the
  576. X beginning of the page, so that there is less likely to be a
  577. X problem with the ints following. this may cause trouble in some
  578. X odd architectures, and if so, fix it, and let me know.
  579. X
  580. X debugging a page is hard to do, by its very nature, and it is
  581. X equally hard to build consistency checks into the code to
  582. X validate pages as they are read and written. there is some
  583. X code in bt_rpage() and bt_wpage() that looks for glaringly hosed
  584. X pages, but if something gets past them, serious problems are
  585. X sure to follow.
  586. X
  587. X    Don't even *THINK* about running this past "lint -h" !!!!!
  588. X
  589. X    These macros wind up nesting ~5 layers deep and get pretty
  590. X    hairy. If your c-preprocessor is not gutsy enough, have fun
  591. X    with the cut and paste !
  592. X
  593. X    Makeup of a page:
  594. X    a page is an unstructured mess stuffed into a character buffer
  595. X    with all locations being determined via pointer arithmetic.
  596. X    this structure is loosely based on Zoellic and Folk's text
  597. X    "File Structures: a conceptual toolkit". further, there is
  598. X    no distinction between internal pages and leaf pages except
  599. X    that the value in the high pointer will be BT_NULL
  600. X
  601. X    fields are (in order)
  602. X    - how many -- data type (size) ---------value/description-----
  603. X    1    |    off_t    |    page left sibling
  604. X    1    |    off_t    |    page right sibling
  605. X    1    |    off_t    |    page "high" (overflow) ptr
  606. X    1    |    int    |    count of keys in page - keycnt
  607. X    1    |    int    |    total length of keys in page
  608. X    keycnt    |    int    |    length index (one per key)
  609. X    keycnt    |    off_t    |    child/data ptrs (one per key)
  610. X
  611. X    Ideally, pages should be flagged depending on type, and if
  612. X    the page contains fixed-size objects (structs, or ints, etc)
  613. X    the length index should be left out, saving sizeof(int) 
  614. X    bytes/key, which would be susbstantial improvement. This is
  615. X    an enhancement considered for release 2.0 if ever, or is
  616. X    left as an exercise for the reader.
  617. X
  618. X    --mjr();
  619. X*/
  620. X
  621. X/* alignment boundary for off_ts */
  622. X#define    ALIGN    sizeof(off_t)
  623. X/*
  624. X#define    ALIGN    (sizeof(off_t)/sizeof(char))
  625. X*/
  626. X
  627. X/*
  628. Xthe actual alignments - the bit with the u_long may break on
  629. Xsome systems. Whatever, it needs to be a size that can give a valid
  630. Xmodulo operator on an address (Suns don't like modulo of pointers)
  631. X*/
  632. X#define    DOALIGN(s)    (s + (ALIGN - ((u_long)s % ALIGN)))
  633. X
  634. X/* page siblings */
  635. X#define    LSIB(p)        (*(off_t *)(p))
  636. X#define    RSIB(p)        (*(off_t *)(p + sizeof(off_t)))
  637. X#define    HIPT(p)        (*(off_t *)(p + (2 * sizeof(off_t))))
  638. X
  639. X/* count of keys in page, stored in first integer value */
  640. X#define    KEYCNT(p)    (*(int *)(p + (3 * sizeof(off_t))))
  641. X
  642. X/* length of keys in page, stored in second integer value */
  643. X#define    KEYLEN(p)    (*(int *)(p + sizeof(int) + (3 * sizeof(off_t))))
  644. X
  645. X/* address of key string (pointer to char) */
  646. X#define    KEYADR(p)    (p + (2 * sizeof(int)) + (3 * sizeof(off_t)))
  647. X
  648. X/* address of first (int) key index value */
  649. X#define    KEYIND(p)    DOALIGN((KEYADR(p) + KEYLEN(p)))
  650. X
  651. X/* address of first (off_t) child pointer value */
  652. X#define    KEYCLD(p)    (KEYIND(p) + (KEYCNT(p) * sizeof(int)))
  653. X
  654. X/* # of bytes used by page pointers, sibs, etc */
  655. X#define PTRUSE        ((2 * sizeof(int)) + (4 * sizeof(off_t)))
  656. X
  657. X/* # of bytes used out of a page */
  658. X#define KEYUSE(p)    ((KEYCNT(p) * (sizeof(off_t) + sizeof(int))) + PTRUSE + KEYLEN(p))
  659. X
  660. X#define    _DEF_BT_INTERN_H
  661. X#endif
  662. END_OF_FILE
  663. if test 4753 -ne `wc -c <'b+tree/btlib/btintern.h'`; then
  664.     echo shar: \"'b+tree/btlib/btintern.h'\" unpacked with wrong size!
  665. fi
  666. # end of 'b+tree/btlib/btintern.h'
  667. fi
  668. if test -f 'b+tree/btlib/btio.c' -a "${1}" != "-c" ; then 
  669.   echo shar: Will not clobber existing file \"'b+tree/btlib/btio.c'\"
  670. else
  671. echo shar: Extracting \"'b+tree/btlib/btio.c'\" \(8052 characters\)
  672. sed "s/^X//" >'b+tree/btlib/btio.c' <<'END_OF_FILE'
  673. X#include    <sys/types.h>
  674. X#include    <sys/file.h>
  675. X#include    <stdio.h>
  676. X#include    "btconf.h"
  677. X#include    "btree.h"
  678. X#include    "btintern.h"
  679. X
  680. X/*
  681. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  682. X                    All rights reserved
  683. X
  684. X
  685. X          This software, its documentation,  and  supporting
  686. X          files  are  copyrighted  material  and may only be
  687. X          distributed in accordance with the terms listed in
  688. X          the COPYRIGHT document.
  689. X*/
  690. X
  691. X
  692. X#ifndef    lint
  693. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/btlib/RCS/btio.c,v 1.1 89/10/24 10:08:59 mjr Rel $";
  694. X#endif
  695. X
  696. Xextern    off_t    lseek();
  697. X
  698. X/*
  699. X    all read/write operations are in this file, as well as cache
  700. X    management stuff. the only exception to this is in btopen,
  701. X    where we write an initial page if creating a tree
  702. X
  703. X    how caching is done in the btree routines: in case you care.
  704. X    ------------------------------------------------------------
  705. X    the bt_rpage and bt_wpage functions do NOT fill a buffer for
  706. X    other btree functions to call - they return a pointer to a
  707. X    filled cache buffer, which can be operated on and then written
  708. X    back out. if an internal function requests page #BT_NULL, that
  709. X    tells bt_rpage to just get the least recently used page, OR
  710. X    any other scratch pages it has hanging around. preference is
  711. X    to re-use a scribbled-on page rather than having to flush a
  712. X    real page to disk and (possibly) have to read it right back.
  713. X    a flag is raised to mark scratch page buffers as in use, since
  714. X    there can be more than one page #BT_NULL and they are always
  715. X    maintained at the least-recently used end of the queue.
  716. X    writing is done just the opposite: if the page is not BT_NULL
  717. X    the page may be synced to disk (depending on cache flags)
  718. X    and will be re-inserted at the most-recently used end of the
  719. X    cache. if the page IS BT_NULL, any misc. flags get cleared
  720. X    (such as the 'this scratch page is in use' flag) and the
  721. X    buffer is re-enqueued at the least-recently used.
  722. X    the goal of all this stuff is to allow a calling function
  723. X    to grab a page in a buffer, request 2 scratch pages, split the
  724. X    first into the two scratches, mark the first (original) as
  725. X    junk (since the page is now invalidated) and to 'write' it as
  726. X    BT_NULL, while 'write'ing the 2 former scratch buffers as real
  727. X    pages. All without doing a damn thing but juggling pointers.
  728. X*/
  729. X
  730. X
  731. Xbt_wsuper(b)
  732. XBT_INDEX    *b;
  733. X{
  734. X    /* write a superblock to disk if and only if it is dirty */
  735. X    /* keeps files opened O_RDONLY from choking up blood */
  736. X    if(b->dirt &&
  737. X        lseek(bt_fileno(b),0L,SEEK_SET) != 0L ||
  738. X        write(bt_fileno(b),(char *)&b->sblk,sizeof(struct bt_super)) != sizeof(struct bt_super))
  739. X            return(BT_ERR);
  740. X    b->dirt = 0;
  741. X
  742. X    return(BT_OK);
  743. X}
  744. X
  745. X
  746. Xbt_sync(b)
  747. XBT_INDEX    *b;
  748. X{
  749. X    struct    bt_cache *p1;
  750. X
  751. X    /* flip through the cache and flush any pages marked dirty to disk */
  752. X
  753. X    for(p1 = b->lru; p1 != NULL;) {
  754. X        if(p1->flags == BT_CHE_DIRTY && p1->num != BT_NULL) {
  755. X            if(lseek(bt_fileno(b),p1->num,SEEK_SET) != p1->num ||
  756. X                write(bt_fileno(b),(char *)p1->p,bt_pagesiz(b)) != bt_pagesiz(b))
  757. X                return(BT_ERR);
  758. X        }
  759. X        p1 = p1->next;
  760. X    }
  761. X    return(BT_OK);
  762. X}
  763. X
  764. X
  765. Xstatic void
  766. Xbt_requeue(b,p)
  767. XBT_INDEX    *b;
  768. Xstruct bt_cache    *p;
  769. X{
  770. X    /* re-assign the cache buffer to a new (or possibly the same) */
  771. X    /* location in the queue. buffers that have been stolen for */
  772. X    /* scrap will have a BT_NULL number, and should just go at the */
  773. X    /* least-recently used part of the cache, since they are junk. */
  774. X    /* buffers with legit values get moved to the most-recently. */
  775. X    /* this could all be inlined where appropriate, but gimme a */
  776. X    /* break! call it, uh, modular programming. this is still */
  777. X    /* plenty quick, I expect. */
  778. X
  779. X    /* if the element is where it already belongs, waste no time */
  780. X    if((p->num == BT_NULL && p == b->lru) ||
  781. X        (p->num != BT_NULL && p == b->mru))
  782. X            return;
  783. X
  784. X    /* unlink */
  785. X    if(p->prev != NULL)
  786. X        p->prev->next = p->next;
  787. X    if(p->next != NULL)
  788. X        p->next->prev = p->prev;
  789. X    if(p == b->lru)
  790. X        b->lru = p->next;
  791. X    if(p == b->mru)
  792. X        b->mru = p->prev;
  793. X
  794. X    /* relink depending on number of page this buffer contains */
  795. X    if(p->num == BT_NULL) {
  796. X        b->lru->prev = p;
  797. X        p->next = b->lru;
  798. X        p->prev = NULL;
  799. X        b->lru = p;
  800. X    } else {
  801. X        b->mru->next = p;
  802. X        p->prev = b->mru;
  803. X        p->next = NULL;
  804. X        b->mru = p;
  805. X    }
  806. X}
  807. X
  808. X
  809. Xstruct bt_cache *
  810. Xbt_rpage(b,num)
  811. XBT_INDEX    *b;
  812. Xoff_t        num;
  813. X{
  814. X    struct bt_cache    *p;
  815. X
  816. X    /* sanity check - only BT_NULL is allowed to be a page less */
  817. X    /* than 0 and no pages are allowed to be read past EOF. */
  818. X    if(num == 0L || num >= b->sblk.high || (num < 0L && num != BT_NULL) || (num != BT_NULL && (num % bt_pagesiz(b)) != 0)) {
  819. X        bt_errno(b) = BT_PTRINVAL;
  820. X        return(NULL);
  821. X    }
  822. X    
  823. X    /* scan the cache for the desired page. if it is not there, */
  824. X    /* load the desired stuff into the lru. if the requested page */
  825. X    /* is BT_NULL we could probably cheat by just using the lru, */
  826. X    /* but keeping the code smaller and cleaner is probably nicer */
  827. X    for(p = b->mru; p != NULL; p = p->prev) {
  828. X
  829. X        /* if the page number matches and the buffer is not */
  830. X        /* marked as an allocated scratch buffer, return it */
  831. X        if(num == p->num && p->flags != BT_CHE_LOCKD) {
  832. X            /* if it is a scratch buffer, lock it */
  833. X            if(p->num == BT_NULL)
  834. X                p->flags = BT_CHE_LOCKD;
  835. X
  836. X            /* recache the page (moves it to mru) */
  837. X            bt_requeue(b,p);
  838. X            return(p);
  839. X        }
  840. X    }
  841. X    
  842. X    /* obviously, we didnt find it, so flush the lru and read */
  843. X    /* one complication is to make sure we dont clobber allocated */
  844. X    /* scratch page buffers. we have to seek backwards until we */
  845. X    /* get a page that is not locked */
  846. X    for(p = b->lru; p != NULL; p = p->next)
  847. X        if(p->flags != BT_CHE_LOCKD)
  848. X            break;
  849. X    
  850. X    /* sanity check */
  851. X    if(p == NULL) {
  852. X        bt_errno(b) = BT_NOBUFFERS;
  853. X        return(NULL);
  854. X    }
  855. X
  856. X    /* flush if the page is dirty and not a scratch buffer */
  857. X    if(p->num != BT_NULL && p->flags == BT_CHE_DIRTY) {
  858. X        if(lseek(bt_fileno(b),p->num,SEEK_SET) != p->num ||
  859. X            write(bt_fileno(b),(char *)p->p,bt_pagesiz(b)) != bt_pagesiz(b))
  860. X            return(NULL);
  861. X    }
  862. X
  863. X    /* read new data if not a scratch buffer */
  864. X    if(num != BT_NULL) {
  865. X        int    ku;
  866. X
  867. X        if(lseek(bt_fileno(b),num,SEEK_SET) != num ||
  868. X            read(bt_fileno(b),(char *)p->p,bt_pagesiz(b)) != bt_pagesiz(b))
  869. X            return(NULL);
  870. X        p->flags = BT_CHE_CLEAN;
  871. X        p->num = num;
  872. X
  873. X        /* sanity check */
  874. X        ku = KEYUSE(p->p);
  875. X        if(ku > bt_pagesiz(b) || ku < 0 || KEYLEN(p->p) < 0) {
  876. X            bt_errno(b) = BT_BADPAGE;
  877. X            return(NULL);
  878. X        }
  879. X    } else {
  880. X        p->flags = BT_CHE_LOCKD;
  881. X        p->num = BT_NULL;
  882. X    }
  883. X
  884. X    bt_requeue(b,p);
  885. X    return(p);
  886. X}
  887. X
  888. X
  889. X
  890. Xbt_wpage(b,p)
  891. XBT_INDEX    *b;
  892. Xstruct bt_cache    *p;
  893. X{
  894. X
  895. X    if(p->num != BT_NULL) {
  896. X        int    ku;
  897. X
  898. X        /* sanity check */
  899. X        ku = KEYUSE(p->p);
  900. X        if(ku > bt_pagesiz(b) || ku < 0 || KEYLEN(p->p) < 0) {
  901. X            bt_errno(b) = BT_BADPAGE;
  902. X            return(BT_ERR);
  903. X        }
  904. X
  905. X        if(b->cflg != BT_RWCACHE && p->flags == BT_CHE_DIRTY) {
  906. X            if(lseek(bt_fileno(b),p->num,SEEK_SET) != p->num ||
  907. X                write(bt_fileno(b),(char *)p->p,bt_pagesiz(b)) != bt_pagesiz(b))
  908. X                return(BT_ERR);
  909. X            p->flags = BT_CHE_CLEAN;
  910. X        }
  911. X    } else {
  912. X        /* unlock scratch buffer */
  913. X        p->flags = BT_CHE_CLEAN;
  914. X    }
  915. X
  916. X    bt_requeue(b,p);
  917. X    return(BT_OK);
  918. X}
  919. X
  920. X
  921. X
  922. Xbt_freepage(b,pag)
  923. XBT_INDEX    *b;
  924. Xoff_t        pag;
  925. X{
  926. X    /* simple free page management is done with a linked */
  927. X    /* list linked to the left sibling of each page */
  928. X    struct    bt_cache *p;
  929. X
  930. X    if((p = bt_rpage(b,pag)) == NULL)
  931. X        return(BT_ERR);
  932. X    
  933. X    LSIB(p->p) = b->sblk.free;
  934. X
  935. X    /* note - this value is SET but never checked. Why ? because the */
  936. X    /* in-order insert can't be bothered to reset all the free pointers */
  937. X    /* in the free list. this could be useful, however, if someone ever */
  938. X    /* writes a tree-patcher program, or something like that. */
  939. X    HIPT(p->p) = BT_FREE;
  940. X
  941. X    p->flags = BT_CHE_DIRTY;
  942. X    if(bt_wpage(b,p) == BT_ERR)
  943. X        return(BT_ERR);
  944. X
  945. X    b->sblk.free = pag;
  946. X    b->dirt = 1;
  947. X    return(bt_wsuper(b));
  948. X}
  949. X
  950. X
  951. Xoff_t
  952. Xbt_newpage(b)
  953. XBT_INDEX    *b;
  954. X{
  955. X    off_t    ret = BT_NULL;
  956. X    struct    bt_cache *p;
  957. X
  958. X    if(b->sblk.free == BT_NULL) {
  959. X        ret = b->sblk.high;
  960. X        b->sblk.high += bt_pagesiz(b);
  961. X    } else {
  962. X        if((p = bt_rpage(b,b->sblk.free)) != NULL) {
  963. X            ret = b->sblk.free;
  964. X            b->sblk.free = LSIB(p->p);
  965. X        } else {
  966. X            return(BT_NULL);
  967. X        }
  968. X    }
  969. X    b->dirt = 1;
  970. X    if(bt_wsuper(b) == BT_ERR)
  971. X        return(BT_ERR);
  972. X    return(ret);
  973. X}
  974. END_OF_FILE
  975. if test 8052 -ne `wc -c <'b+tree/btlib/btio.c'`; then
  976.     echo shar: \"'b+tree/btlib/btio.c'\" unpacked with wrong size!
  977. fi
  978. # end of 'b+tree/btlib/btio.c'
  979. fi
  980. if test -f 'b+tree/btlib/btoopen.c' -a "${1}" != "-c" ; then 
  981.   echo shar: Will not clobber existing file \"'b+tree/btlib/btoopen.c'\"
  982. else
  983. echo shar: Extracting \"'b+tree/btlib/btoopen.c'\" \(4634 characters\)
  984. sed "s/^X//" >'b+tree/btlib/btoopen.c' <<'END_OF_FILE'
  985. X#include    <sys/types.h>
  986. X#include    <sys/file.h>
  987. X#include    <sys/stat.h>
  988. X#include    <varargs.h>
  989. X#include    <stdio.h>
  990. X#include    "btconf.h"
  991. X#include    "btree.h"
  992. X#include    "btintern.h"
  993. X
  994. X/*
  995. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  996. X                    All rights reserved
  997. X
  998. X
  999. X          This software, its documentation,  and  supporting
  1000. X          files  are  copyrighted  material  and may only be
  1001. X          distributed in accordance with the terms listed in
  1002. X          the COPYRIGHT document.
  1003. X*/
  1004. X
  1005. X
  1006. X#ifndef    lint
  1007. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/btlib/RCS/btoopen.c,v 1.1 89/10/24 10:09:01 mjr Rel $";
  1008. X#endif
  1009. X
  1010. X/*    this way of handling opening and configuration is probably    */
  1011. X/*    unnecessarily large and awkward, but I think it gives a pretty    */
  1012. X/*    high degree of #ifdefability to make it portable across OS     */
  1013. X/*    types, as well as giving a lot of flexibility for those who    */
  1014. X/*    never trust default options.                     */
  1015. X
  1016. Xextern    char    *malloc();
  1017. Xextern    off_t    lseek();
  1018. X
  1019. X
  1020. XBT_INDEX    *
  1021. Xbt_optopen(va_alist)
  1022. Xva_dcl
  1023. X{
  1024. X    va_list        ap;
  1025. X    BT_INDEX    *ret;
  1026. X    struct bt_cache *cp1;
  1027. X    struct bt_cache *cp2;
  1028. X    int        dtyp = BT_DFLTDTYPE;
  1029. X    int        csiz = BT_DFLTCACHE;
  1030. X    int        cflg = BT_DFLTCFLAG;
  1031. X    int        psiz = BT_DFLTPSIZ;
  1032. X    int        operm = S_IREAD|S_IWRITE;
  1033. X    int        omode = O_RDWR;
  1034. X    off_t        magic = BT_DFLTMAGIC;
  1035. X    bt_chrp        labp = NULL;
  1036. X    int        labl;
  1037. X    int        r;
  1038. X    char        *path = NULL;
  1039. X
  1040. X    if((ret = (BT_INDEX *)malloc(sizeof(BT_INDEX))) == NULL)
  1041. X        return(NULL);
  1042. X
  1043. X    /* clear error */
  1044. X    bt_errno(ret) = BT_NOERROR;
  1045. X
  1046. X    /* zero this just in case */
  1047. X    bt_cmpfn(ret) = 0;
  1048. X
  1049. X    va_start(ap);
  1050. X    while((r = va_arg(ap,int)) != 0) {
  1051. X        switch(r) {
  1052. X            case    BT_PATH:
  1053. X                path = va_arg(ap,char *);
  1054. X                break;
  1055. X
  1056. X            case    BT_PSIZE:
  1057. X                psiz = va_arg(ap,int);
  1058. X                if(psiz < sizeof(struct bt_super))
  1059. X                    psiz = sizeof(struct bt_super);
  1060. X                break;
  1061. X
  1062. X            case    BT_CACHE:
  1063. X                csiz = va_arg(ap,int);
  1064. X                if(csiz < 0)
  1065. X                    csiz = 0;
  1066. X                break;
  1067. X
  1068. X            case    BT_CFLAG:
  1069. X                cflg = va_arg(ap,int);
  1070. X                break;
  1071. X
  1072. X            case    BT_OMODE:
  1073. X                omode = va_arg(ap,int) | O_RDWR;
  1074. X                break;
  1075. X
  1076. X            case    BT_OPERM:
  1077. X                operm = va_arg(ap,int);
  1078. X                break;
  1079. X
  1080. X            case    BT_MAGIC:
  1081. X                magic = va_arg(ap,off_t);
  1082. X                break;
  1083. X
  1084. X            case    BT_LABEL:
  1085. X                labp = va_arg(ap,bt_chrp);
  1086. X                labl = va_arg(ap,int);
  1087. X                break;
  1088. X
  1089. X            case    BT_DTYPE:
  1090. X                dtyp = va_arg(ap,int);
  1091. X                /* next arg BETTER be a valid funcp ! */
  1092. X                if(dtyp == BT_USRDEF)
  1093. X                    bt_cmpfn(ret) = va_arg(ap,FUNCP);
  1094. X                break;
  1095. X
  1096. X            default:
  1097. X                goto bombout;
  1098. X        }
  1099. X    }
  1100. X
  1101. X    if(path == NULL || (bt_fileno(ret) = open(path,omode,operm)) < 0)
  1102. X        goto bombout;
  1103. X
  1104. X    r = read(bt_fileno(ret),(char *)&ret->sblk,sizeof(struct bt_super));
  1105. X
  1106. X    /* failure to read anything - initialize tree */
  1107. X    if(r == 0) {
  1108. X        char    *jnk;
  1109. X        if((jnk = malloc((unsigned)psiz)) != NULL) {
  1110. X            ret->sblk.magic = magic;
  1111. X            bt_pagesiz(ret) = psiz;
  1112. X            bt_dtype(ret) = dtyp;
  1113. X            ret->sblk.levs = 1;
  1114. X            ret->sblk.root = (off_t)psiz;
  1115. X            ret->sblk.free = BT_NULL;
  1116. X            ret->sblk.high = (off_t)(2 * psiz);
  1117. X
  1118. X            /* mark super block as dirty and sync */
  1119. X            ret->dirt = 1;
  1120. X
  1121. X            /* write and pretend we read a legit superblock */
  1122. X            if(bt_wsuper(ret) == BT_OK)
  1123. X                r = sizeof(struct bt_super);
  1124. X
  1125. X            /* now make jnk into an empty first page */
  1126. X            KEYCNT(jnk) = 0;
  1127. X            KEYLEN(jnk) = 0;
  1128. X            LSIB(jnk) = RSIB(jnk) = BT_NULL;
  1129. X            HIPT(jnk) = BT_NULL;
  1130. X
  1131. X            /* now, since the cache is not set up yet, we */
  1132. X            /* must directly write the page. */
  1133. X            if(lseek(bt_fileno(ret),(off_t)psiz,SEEK_SET) != (off_t)psiz ||
  1134. X                write(bt_fileno(ret),jnk,psiz) != psiz)
  1135. X                r = 0;
  1136. X            (void)free(jnk);
  1137. X        }
  1138. X    }
  1139. X
  1140. X    /* yet another sanity check */
  1141. X    if(r != sizeof(struct bt_super) || ret->sblk.magic != magic)
  1142. X        goto bombout;
  1143. X
  1144. X    /* label it if we are supposed to */
  1145. X    if(labp && bt_wlabel(ret,labp,labl) == BT_ERR)
  1146. X        goto bombout;
  1147. X
  1148. X    /* initialize locator stack */
  1149. X    ret->shih = ret->sblk.levs + 2;
  1150. X    ret->stack = (struct bt_stack *)malloc((unsigned)(ret->shih * sizeof(struct bt_stack)));
  1151. X    if(ret->stack == NULL)
  1152. X        goto bombout;
  1153. X
  1154. X    /* initialize cache */
  1155. X    cp2 = ret->lru = NULL;
  1156. X    csiz += BT_MINCACHE;
  1157. X
  1158. X    /* just in case some bonehead asks for tons of unused cache */
  1159. X    if(cflg == BT_NOCACHE)
  1160. X        csiz = BT_MINCACHE;
  1161. X
  1162. X    while(csiz--) {
  1163. X        cp1 = (struct bt_cache *)malloc(sizeof(struct bt_cache)); 
  1164. X        if(cp1 == NULL)
  1165. X            goto bombout;
  1166. X
  1167. X        if(ret->lru == NULL)
  1168. X            ret->lru = cp1;
  1169. X        cp1->prev = cp2;
  1170. X        cp1->num = BT_NULL;
  1171. X        cp1->next = NULL;
  1172. X        cp1->flags = BT_CHE_CLEAN;
  1173. X        if((cp1->p = (bt_chrp)malloc((unsigned)bt_pagesiz(ret))) == NULL)
  1174. X            goto bombout;
  1175. X        if(cp2 != NULL)
  1176. X            cp2->next = cp1;
  1177. X
  1178. X        cp2 = cp1;
  1179. X    }
  1180. X    ret->mru = cp1;
  1181. X
  1182. X    /* set cache type flag */
  1183. X    ret->cflg = cflg;
  1184. X
  1185. X    /* no valid current key */
  1186. X    ret->cpag = BT_NULL;
  1187. X
  1188. X    /* all is well */
  1189. X    return(ret);
  1190. X
  1191. Xbombout:
  1192. X    (void)bt_close(ret);
  1193. X    return(NULL);
  1194. X}
  1195. END_OF_FILE
  1196. if test 4634 -ne `wc -c <'b+tree/btlib/btoopen.c'`; then
  1197.     echo shar: \"'b+tree/btlib/btoopen.c'\" unpacked with wrong size!
  1198. fi
  1199. # end of 'b+tree/btlib/btoopen.c'
  1200. fi
  1201. if test -f 'b+tree/btlib/btpage1.c' -a "${1}" != "-c" ; then 
  1202.   echo shar: Will not clobber existing file \"'b+tree/btlib/btpage1.c'\"
  1203. else
  1204. echo shar: Extracting \"'b+tree/btlib/btpage1.c'\" \(5063 characters\)
  1205. sed "s/^X//" >'b+tree/btlib/btpage1.c' <<'END_OF_FILE'
  1206. X#include    <sys/types.h>
  1207. X
  1208. X#include    <stdio.h>
  1209. X#include    "btconf.h"
  1210. X#include    "btree.h"
  1211. X#include    "btintern.h"
  1212. X
  1213. X/*
  1214. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  1215. X                    All rights reserved
  1216. X
  1217. X
  1218. X          This software, its documentation,  and  supporting
  1219. X          files  are  copyrighted  material  and may only be
  1220. X          distributed in accordance with the terms listed in
  1221. X          the COPYRIGHT document.
  1222. X*/
  1223. X
  1224. X
  1225. X#ifndef    lint
  1226. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/b+tree/btlib/RCS/btpage1.c,v 1.1 89/10/24 10:09:02 mjr Rel $";
  1227. X#endif
  1228. X
  1229. Xbt_srchpg(k,kl,dtyp,cmpf,ptr,num,s)
  1230. Xbt_chrp    k;
  1231. Xint    kl;
  1232. Xint    dtyp;
  1233. XFUNCP    cmpf;
  1234. Xoff_t    *ptr;
  1235. Xint    *num;
  1236. Xbt_chrp    s;
  1237. X{
  1238. X    int    lo = 0, m, hi;        /* low, mid, high ptrs for binsrch */
  1239. X    int    *ip;            /* offset/beginning of key index */
  1240. X    off_t    *cl;            /* offset/beginning of child index */
  1241. X    bt_chrp    cp;            /* offset/beginning of keys */
  1242. X    REGISTER int    cmpval;        /* returned value of comparison */
  1243. X    REGISTER bt_chrp    kp1;    /* tmp key pointer */
  1244. X    REGISTER bt_chrp    kp2;
  1245. X    REGISTER int    l1;        /* key lengths */
  1246. X    REGISTER int    l2;
  1247. X
  1248. X    /* this value is decremented by one to keep from */
  1249. X    /* looking past the top of the key list */
  1250. X    hi = KEYCNT(s) - 1;
  1251. X
  1252. X    /* save effort if this is an empty page */
  1253. X    /* also saves from binary search where hi < lo! */
  1254. X    if(KEYCNT(s) == 0) {
  1255. X        *num = 0;
  1256. X        *ptr = HIPT(s);
  1257. X        return(BT_NF);
  1258. X    }
  1259. X
  1260. X    /* beginning of key index */
  1261. X    ip = (int *)KEYIND(s);
  1262. X
  1263. X    /* beginning of key string */
  1264. X    cp = KEYADR(s);
  1265. X
  1266. X    /* beginning of the child pointers */
  1267. X    cl = (off_t *)KEYCLD(s);
  1268. X
  1269. X    /* hold onto your cerebellums, folks !! */
  1270. X    while(lo <= hi) {
  1271. X
  1272. X        /* if the first key is the one we want, its length */
  1273. X        /* is not calculated using the subtracted offsets, */
  1274. X        /* but is rather calculated by using the offset */
  1275. X        /* to the beginning of key #2, which starts where */
  1276. X        /* the first key ends, by definition */
  1277. X
  1278. X        /* actual comparison is done over len bytes from */
  1279. X        /* the offset that is extracted out of the index */
  1280. X
  1281. X        /* set up pointers for the compare */
  1282. X        kp1 = k;
  1283. X        l1 = kl;
  1284. X        if((m = (lo + hi) >> 1) == 0) {
  1285. X            kp2 = cp;
  1286. X            l2 = *ip;
  1287. X        } else {
  1288. X            kp2 = cp + *(ip + m - 1);
  1289. X            l2 = (*(ip + m) - *(ip + (m - 1)));
  1290. X        }
  1291. X
  1292. X        /* do the compare based on data type */
  1293. X        if(dtyp == BT_STRING) {
  1294. X                while(l1 != 0 && l2 != 0) {
  1295. X                    if(*kp1 != *kp2) {
  1296. X                        cmpval = *kp1 - *kp2;
  1297. X                        goto endcmp;
  1298. X                    }
  1299. X                    kp1++;
  1300. X                    kp2++;
  1301. X                    l1--;
  1302. X                    l2--;
  1303. X                }
  1304. X
  1305. X                if(l1 != l2)
  1306. X                    cmpval = l1 - l2;
  1307. X                else
  1308. X                    cmpval = 0;
  1309. X        } else if(dtyp == BT_INT) {
  1310. X                cmpval = *(int *)kp1 - *(int *)kp2;
  1311. X        } else if(dtyp == BT_LONG) {
  1312. X                cmpval = *(long *)kp1 - *(long *)kp2;
  1313. X        } else if(dtyp == BT_FLOAT) {
  1314. X                cmpval = 0;
  1315. X                 if(*(float *)kp1 > *(float *)kp2)
  1316. X                    cmpval = 1;
  1317. X                else
  1318. X                    if(*(float *)kp1 < *(float *)kp2)
  1319. X                        cmpval = -1;
  1320. X        } else if(dtyp == BT_USRDEF) {
  1321. X            if(cmpf == 0)
  1322. X                return(BT_ERR);
  1323. X            cmpval = (*cmpf)(kp1,l1,kp2,l2);
  1324. X        } else
  1325. X            return(BT_ERR);
  1326. Xendcmp:
  1327. X        if(cmpval < 0) {
  1328. X            hi = m - 1;
  1329. X            *num = m;
  1330. X        } else {
  1331. X            if(cmpval > 0) {
  1332. X                lo = m + 1;
  1333. X                *num = m + 1;
  1334. X            } else {
  1335. X                /* return current key # in num */
  1336. X                *num = m;
  1337. X                *ptr = *(cl + m);
  1338. X                return(BT_OK);
  1339. X            }
  1340. X        }
  1341. X    }
  1342. X
  1343. X    if(*num == KEYCNT(s))
  1344. X        *ptr = HIPT(s);
  1345. X    else
  1346. X        *ptr = *(cl + *num);
  1347. X    return(BT_NF);
  1348. X}
  1349. X
  1350. X
  1351. Xvoid
  1352. Xbt_inspg(key,len,ptr,at,in,out)
  1353. Xbt_chrp    key;
  1354. Xint    len;
  1355. Xoff_t    *ptr;
  1356. Xint    at;
  1357. Xbt_chrp    in;
  1358. Xbt_chrp    out;
  1359. X{
  1360. X    REGISTER int    *iin;        /* index/length ptr to old page */
  1361. X    REGISTER int    *iout;        /* index/length ptr to new page */
  1362. X    REGISTER off_t    *lin;        /* child ptr to old page */
  1363. X    REGISTER off_t    *lout;        /* child ptr to new page */
  1364. X    REGISTER bt_chrp    kin;        /* key ptr to old page */
  1365. X    REGISTER bt_chrp    kout;        /* key ptr to new page */
  1366. X    REGISTER int    t;        /* iterator */
  1367. X    int    iky;            /* key number in old page */
  1368. X    int    oky;            /* key number in new page */
  1369. X    int    copied = 0;        /* used as flag AND shift of lengths */
  1370. X
  1371. X    /* fix key count in new page */
  1372. X    KEYCNT(out) = KEYCNT(in) + 1;
  1373. X
  1374. X    /* fix key length in new page */
  1375. X    KEYLEN(out) = KEYLEN(in) + len;
  1376. X
  1377. X    /* left and right sibs */
  1378. X    LSIB(out) = LSIB(in);
  1379. X    RSIB(out) = RSIB(in);
  1380. X
  1381. X    /* and high pointer */
  1382. X    HIPT(out) = HIPT(in);
  1383. X
  1384. X    /* set the key start pointers, index and child pointers */
  1385. X    kin = KEYADR(in);
  1386. X    kout = KEYADR(out);
  1387. X
  1388. X    iin = (int *)KEYIND(in);
  1389. X    iout = (int *)KEYIND(out);
  1390. X
  1391. X    lin = (off_t *)KEYCLD(in);
  1392. X    lout = (off_t *)KEYCLD(out);
  1393. X
  1394. X    for(oky = iky = 0; oky < KEYCNT(out); oky++) {
  1395. X
  1396. X        /* insert the key at this point in the page */
  1397. X        /* copied is used later to calculate lenght offsets */
  1398. X        if(at == iky && copied == 0) {
  1399. X
  1400. X            /* copy the key into the key space */
  1401. X            for(t = 0; t < len; t++)
  1402. X                *kout++ = *key++;
  1403. X
  1404. X            /* fix up index lengths if key is first out */
  1405. X            if(oky == 0)
  1406. X                *iout = len;
  1407. X            else
  1408. X                *iout = *(iout - 1) + len;
  1409. X
  1410. X            iout++;
  1411. X
  1412. X            /* offset any more index lengths by this much */
  1413. X            copied = len;
  1414. X
  1415. X            /* copy ptrs */
  1416. X            *lout++ = *ptr;
  1417. X
  1418. X        } else {
  1419. X            if(iky == 0)
  1420. X                for(t = 0; t < *iin; t++)
  1421. X                    *kout++ = *kin++;
  1422. X            else
  1423. X                for(t = 0; t < (*iin - *(iin - 1)); t++)
  1424. X                    *kout++ = *kin++;
  1425. X            iky++;
  1426. X            *iout++ = *iin + copied;
  1427. X            iin++;
  1428. X            *lout++ = *lin++;
  1429. X        }
  1430. X    }
  1431. X    lout--;
  1432. X}
  1433. END_OF_FILE
  1434. if test 5063 -ne `wc -c <'b+tree/btlib/btpage1.c'`; then
  1435.     echo shar: \"'b+tree/btlib/btpage1.c'\" unpacked with wrong size!
  1436. fi
  1437. # end of 'b+tree/btlib/btpage1.c'
  1438. fi
  1439. if test -f 'b+tree/doc/btdbm.3' -a "${1}" != "-c" ; then 
  1440.   echo shar: Will not clobber existing file \"'b+tree/doc/btdbm.3'\"
  1441. else
  1442. echo shar: Extracting \"'b+tree/doc/btdbm.3'\" \(5510 characters\)
  1443. sed "s/^X//" >'b+tree/doc/btdbm.3' <<'END_OF_FILE'
  1444. X.\"
  1445. X.\"         (C) Copyright, 1988, 1989 Marcus J. Ranum
  1446. X.\"                    All rights reserved
  1447. X.\"
  1448. X.\"
  1449. X.\"          This software, its documentation,  and  supporting
  1450. X.\"          files  are  copyrighted  material  and may only be
  1451. X.\"          distributed in accordance with the terms listed in
  1452. X.\"          the COPYRIGHT document.
  1453. X.\"
  1454. X.\" $Header: /atreus/mjr/hacks/btree/doc/RCS/btdbm.3,v 1.2 89/10/23 18:31:00 mjr Rel $
  1455. X.\"
  1456. X.TH BTDBM 3 "18 October 1989"
  1457. X.SH NAME
  1458. Xbtdbm \- ndbm-like library with a b+tree index
  1459. X.SH SYNOPSIS
  1460. X.B #include <sys/types.h>
  1461. X.br
  1462. X.B #include <btdbm.h>
  1463. X.sp
  1464. X.LP
  1465. X.B "int btdbm_close(db)"
  1466. X.br
  1467. X.B "BTDBM *db;"
  1468. X.LP
  1469. X.B "int btdbm_delete(db,key)"
  1470. X.br
  1471. X.B "BTDBM *db;"
  1472. X.br
  1473. X.B "btdatum key;"
  1474. X.LP
  1475. X.B "btdatum btdbm_fetch(db,key)"
  1476. X.br
  1477. X.B "BTDBM *db;"
  1478. X.br
  1479. X.B "btdatum key;"
  1480. X.LP
  1481. X.B "btdatum btdbm_firstkey(db)"
  1482. X.br
  1483. X.B "BTDBM *db;"
  1484. X.LP
  1485. X.B "btdatum btdbm_nextkey(db)"
  1486. X.br
  1487. X.B "BTDBM *db;"
  1488. X.LP
  1489. X.B "BTDBM *btdbm_open(path,type,flags,mode)"
  1490. X.br
  1491. X.B "char *path;"
  1492. X.br
  1493. X.B "int type; /* from btree.h b+tree types */"
  1494. X.br
  1495. X.B "int flags;"
  1496. X.br
  1497. X.B "int mode;"
  1498. X.LP
  1499. X.B "int btdbm_store(db,key,data,flag)"
  1500. X.br
  1501. X.B "BTDBM *db;"
  1502. X.br
  1503. X.B "btdatum key;"
  1504. X.br
  1505. X.B "btdatum data;"
  1506. X.br
  1507. X.B "int flag;"
  1508. X.SH DESCRIPTION
  1509. X.LP
  1510. XThe
  1511. X.B btdbm
  1512. Xlibrary is a rough emulation of the 
  1513. X.B "ndbm(3)"
  1514. Xlibrary built on top of the
  1515. X.B "b+tree(3)"
  1516. Xand
  1517. X.B "store(3)"
  1518. Xlibraries. The functions are intended to be as close to plug-compatible as
  1519. Xpossible, except for the
  1520. X.B btdbm_open
  1521. Xfunction, which requires a data type flag to maintain order of the keys.
  1522. XUnlike the hash table library, the
  1523. X.B btdbm
  1524. Xallows ordered access of the data by key, however the performance of the
  1525. X.B btdbm
  1526. Xlibrary will be inferior to that of the
  1527. X.B "ndbm(3)"
  1528. Xlibrary, due to both the speed of hash tables, and the fact that the
  1529. X.B "store(3)"
  1530. Xlibrary is not optimized for speed. The typedef
  1531. X.B btdatum
  1532. Xis provided, which is analogous to the 
  1533. X.B dbm
  1534. X.B datum
  1535. Xtypedef.
  1536. X.SH FUNCTIONS
  1537. X.LP
  1538. X.B "int btdbm_close(db)"
  1539. X.br
  1540. XThis function closes and deallocates a 
  1541. X.B BTDBM
  1542. Xpointer, closing the storage file and b+tree index.
  1543. X.LP
  1544. X.B "int btdbm_delete(db,key)"
  1545. X.br
  1546. XThis function deletes the key from the database.
  1547. X.LP
  1548. X.B "btdatum btdbm_fetch(db,key)"
  1549. X.bt
  1550. XThis function looks up the datum stored under
  1551. X.B key
  1552. Xand returns the result in a
  1553. X.B btdatum.
  1554. XIf the key is not located in the tree, the value
  1555. X.B "btdatum.size"
  1556. Xof the returned datum will be zero.
  1557. X.LP
  1558. X.B "btdatum btdbm_firstkey(db)"
  1559. X.br
  1560. XThis function returns the first data record from the database, in sort
  1561. Xorder according to the type of data stored in the b+tree index.
  1562. X.LP
  1563. X.B "btdatum btdbm_nextkey(db)"
  1564. X.br
  1565. XThis function returns the next key in order from the database. The next
  1566. Xkey will be the key following either the key returned from the last call
  1567. Xto
  1568. X.B btdbm_firstkey,
  1569. Xor
  1570. X.B btdbm_fetch.
  1571. X.LP
  1572. X.B "BTDBM *btdbm_open(path,type,flags,mode)"
  1573. X.br
  1574. XThis function opens a database and index. The file name is specified 
  1575. Xin
  1576. X.B path
  1577. Xwith the data file automatically having a \fB".dat"\fR extension added,
  1578. Xand the b+tree index having a \fB".ndx"\fR added. The value in
  1579. X.B type
  1580. Xis passed to the underlying b+tree to indicate the type of key used
  1581. Xfor sorting. It must be one of:
  1582. X.B BT_STRING,
  1583. X.B BT_INT,
  1584. X.B BT_LONG,
  1585. X.B BT_FLOAT.
  1586. XThe
  1587. X.B flags
  1588. Xargument is passed to
  1589. X.B "open(2)"
  1590. Xand the
  1591. X.B mode
  1592. Xargument is used as the creation mode for the file, if it does not
  1593. Xalready exist.
  1594. X.LP
  1595. X.B "int btdbm_store(db,key,data,flag)"
  1596. X.br
  1597. XThis function stores the data in
  1598. X.B data
  1599. Xkeyed with the datum in
  1600. X.B key.
  1601. XIf the value of
  1602. X.B flag
  1603. Xis
  1604. X.B BTDBM_INSERT
  1605. Xand the key already exists, and error is returned. If the value of
  1606. X.B flag
  1607. Xis
  1608. X.B BTDBM_REPLACE
  1609. Xany existing data stored under
  1610. X.B key
  1611. Xis overwritten with the new data.
  1612. X.SH "MACROS"
  1613. X.LP
  1614. XSince these values are all macros, they should be used only with
  1615. Xcaution, to avoid side-effects. Mostly these should not be used by
  1616. Xuser-level code, but providing a common interface seemed better
  1617. Xthan the alternative.
  1618. X.LP
  1619. X.B "(int) btdbm_error(db)"
  1620. X.br
  1621. Xpoints to the error number associated with the database.
  1622. X.LP
  1623. X.B "(void) btdbm_clearerror(db)"
  1624. X.br
  1625. Xclears any error number associated with the database.
  1626. X.LP
  1627. X.B "(BT_INDEX *) btdbm_btree(db)"
  1628. X.br
  1629. XPoints to the underlying b+tree handle used to store the keys. See
  1630. X.B "b+tree(3)".
  1631. X.LP
  1632. X.B "(STORE *) btdbm_storefile(db)"
  1633. X.br
  1634. XPoints to the underlying store file handle used to store the data. See
  1635. X.B "store(3)".
  1636. X.SH "SEE ALSO"
  1637. X.LP
  1638. X.B "ndbm(3)"
  1639. X.br
  1640. X.B "b+tree(3)"
  1641. X.br
  1642. X.B "store(3)"
  1643. X.SH DIAGNOSTICS
  1644. X.LP
  1645. XThe value
  1646. X.B 0
  1647. Xis returned whenever a function is successful.
  1648. X.LP
  1649. XThe value
  1650. X.SM
  1651. X.B 1
  1652. Xis returned to indicate some form of failure in any operation.
  1653. XThere is no provision for a more complete means of returning
  1654. Xerror codes, however, the error values in the store file and
  1655. Xb+tree can be accessed through their respective pointers using
  1656. X.B btdbm_btree
  1657. Xand
  1658. X.B btdbm_storefile.
  1659. X.LP
  1660. XA failed call to 
  1661. X.B btdbm_open
  1662. Xreturns NULL. Failed calls to the functions that return a
  1663. Xbtdatum return a btdatum with size value set equal to zero.
  1664. X.SH BUGS
  1665. X.SH LIMITATIONS
  1666. X.LP
  1667. XData stored under a key can be arbitrarily large, subject to the limits
  1668. Xof the underlying store file. Since the store file's internal buffer will
  1669. Xstretch to accomodate large data, reasonably large amounts of data can
  1670. Xbe successfully stored and retrieved fairly efficiently. Keys stored in
  1671. Xthe b+tree index are subject to limits in the b+tree library. An individual
  1672. Xkey cannot be longer than permitted by the underlying page size of the
  1673. Xb+tree (typically a fairly large value).
  1674. X.SH AUTHOR
  1675. X.LP
  1676. XMarcus J. Ranum
  1677. END_OF_FILE
  1678. if test 5510 -ne `wc -c <'b+tree/doc/btdbm.3'`; then
  1679.     echo shar: \"'b+tree/doc/btdbm.3'\" unpacked with wrong size!
  1680. fi
  1681. chmod +x 'b+tree/doc/btdbm.3'
  1682. # end of 'b+tree/doc/btdbm.3'
  1683. fi
  1684. if test -f 'b+tree/utils/dbtest.c' -a "${1}" != "-c" ; then 
  1685.   echo shar: Will not clobber existing file \"'b+tree/utils/dbtest.c'\"
  1686. else
  1687. echo shar: Extracting \"'b+tree/utils/dbtest.c'\" \(5674 characters\)
  1688. sed "s/^X//" >'b+tree/utils/dbtest.c' <<'END_OF_FILE'
  1689. X#include    <stdio.h>
  1690. X#include    <ctype.h>
  1691. X#include    <sys/types.h>
  1692. X#include    <sys/file.h>
  1693. X#include    "btdbm.h"
  1694. X
  1695. X/*
  1696. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  1697. X                    All rights reserved
  1698. X
  1699. X
  1700. X          This software, its documentation,  and  supporting
  1701. X          files  are  copyrighted  material  and may only be
  1702. X          distributed in accordance with the terms listed in
  1703. X          the COPYRIGHT document.
  1704. X*/
  1705. X
  1706. X
  1707. X#ifndef    lint
  1708. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/utils/RCS/dbtest.c,v 1.1 89/10/24 10:09:28 mjr Rel $";
  1709. X#endif
  1710. X
  1711. X
  1712. XBTDBM    *globf = NULL;
  1713. X
  1714. X#define    MAXARG    40
  1715. Xchar    *globargv[MAXARG];        /* args for commands */
  1716. Xint    globargc;
  1717. Xchar    globname[500];
  1718. X
  1719. Xextern    char    *strcpy();
  1720. Xextern    char    *malloc();
  1721. Xextern    char    *rindex();
  1722. Xextern    long    atol();
  1723. Xextern    float    atof();
  1724. X
  1725. Xvoid do_open(), do_close(), do_quit(), do_help();
  1726. Xvoid do_store(), do_fetch(), do_delete(), do_first();
  1727. Xvoid do_next();
  1728. X
  1729. Xvoid    enargv();    /* function to parse user args into strings */
  1730. Xvoid    doit();        /* dispatch function */
  1731. X
  1732. Xstruct    cmd {
  1733. X    char    *name;
  1734. X    char    *usage;
  1735. X    void    (*func)();
  1736. X    int    narg;        /* # of args req'd */
  1737. X    int    op;        /* needs an open index to call */
  1738. X};
  1739. X
  1740. Xstatic    char    *prompt = "btdbmtest-> ";
  1741. X
  1742. X/* command dispatch table */
  1743. Xstruct    cmd    cmds[] = {
  1744. X"close",    "close",            do_close,    1,    1,
  1745. X"delete",    "delete key",            do_delete,    2,    0,
  1746. X"fetch",    "fetch key",            do_fetch,    2,    0,
  1747. X"first",    "first",            do_first,    1,    0,
  1748. X"next",        "next",                do_next,    1,    0,
  1749. X"open",        "open database",        do_open,    2,    0,
  1750. X"quit",        "quit",                do_quit,    1,    0,
  1751. X"store",    "store key data",        do_store,    3,    1,
  1752. X"?",        "?",                do_help,    1,    0,
  1753. X0,        0,                0,        0,    0
  1754. X};
  1755. X
  1756. X
  1757. Xmain(ac,av)
  1758. Xint    ac;
  1759. Xchar    **av;
  1760. X{
  1761. X    int    x;
  1762. X    char    buf[BUFSIZ];
  1763. X
  1764. X    /* enargv() makes a string look like an arg. vector. */
  1765. X    /* doit dispatches the stuff, calls functions, etc */
  1766. X    /* functions must have at least the given # of args */
  1767. X    /* last flag in a command if not zero means an index */
  1768. X    /* must be open in order to call that function */
  1769. X    
  1770. X    if(ac > 1) {
  1771. X        char    **gap = globargv;
  1772. X    
  1773. X        globargc = ac - 1;
  1774. X        while(*++av)
  1775. X            *gap++ = *av;
  1776. X        doit();
  1777. X    } else {
  1778. X        (void)printf(prompt);
  1779. X        while(gets(buf)) {
  1780. X            enargv(buf);
  1781. X            if(globargv[0] != NULL)
  1782. X                doit();
  1783. X
  1784. X            for(x = 0; x < globargc; x++)
  1785. X                (void)free(globargv[x]);
  1786. X
  1787. X            (void)printf(prompt);
  1788. X        }
  1789. X        (void)printf("EOF.\n");
  1790. X    }
  1791. X    do_quit();
  1792. X}
  1793. X
  1794. X
  1795. Xvoid
  1796. Xdoit()
  1797. X{
  1798. X    struct    cmd    *c = cmds;
  1799. X
  1800. X    /* main dispatcher */
  1801. X    while(c->name != 0) {
  1802. X        if(strncmp(c->name,globargv[0],strlen(globargv[0])) == 0) {
  1803. X            if(globargc < c->narg) {
  1804. X                (void)printf("usage:\"%s\"\n",c->usage);
  1805. X                return;
  1806. X            } else {
  1807. X                if(c->op != 0 && globf == NULL) {
  1808. X                    (void)printf("no store file open.\n");
  1809. X                    return;
  1810. X                }
  1811. X                (*c->func)();
  1812. X                return;
  1813. X            }
  1814. X        }
  1815. X        c++;
  1816. X    }
  1817. X    (void)printf("unknown command: \"%s\"\n",globargv[0]);
  1818. X    return;
  1819. X}
  1820. X
  1821. X
  1822. Xchar *
  1823. Xwordparse(line,word,delim)
  1824. Xchar    *line,    *word;
  1825. Xint    delim;
  1826. X{
  1827. X    int    quot =0;
  1828. X
  1829. X    /* parse a word, or quoted string into a buffer. */
  1830. X    while (*line && (isspace(*line) || *line == delim))
  1831. X        line++;
  1832. X
  1833. X    if(*line == '\n')
  1834. X        line++;
  1835. X
  1836. X    if (!*line) {
  1837. X        *word = '\0';
  1838. X        return(0);
  1839. X    }
  1840. X
  1841. X    while (*line)
  1842. X    {
  1843. X        if(!quot && (*line == '\"' || *line == '\''))
  1844. X            quot = *line++;
  1845. X
  1846. X        if((isspace(*line) || *line == delim) && !quot) {
  1847. X            break;
  1848. X        } else {
  1849. X            if(quot && *line == quot) {
  1850. X                quot = 0;
  1851. X                line++;
  1852. X            } else {
  1853. X                *word++ = *line++;
  1854. X            }
  1855. X        }
  1856. X    }
  1857. X    *word = '\0';
  1858. X    return(line);
  1859. X}
  1860. X
  1861. X
  1862. Xvoid
  1863. Xenargv(buf)
  1864. Xchar    *buf;
  1865. X{
  1866. X    char    *bufptr;
  1867. X    char    pbuf[BUFSIZ];
  1868. X    
  1869. X    globargc =0;
  1870. X    bufptr = buf;
  1871. X
  1872. X    /* this is kinda gross, but the easiest way to handle */
  1873. X    /* quoted strings, since I already had wordparse() written */
  1874. X    while(bufptr = wordparse(bufptr,pbuf,0)) {
  1875. X        globargv[globargc] = malloc((unsigned)(strlen(pbuf) + 1));
  1876. X        (void)strcpy(globargv[globargc++],pbuf);
  1877. X    }
  1878. X    globargv[globargc] = NULL;
  1879. X}
  1880. X
  1881. Xvoid
  1882. Xdo_open()
  1883. X{
  1884. X    if(globf != NULL) {
  1885. X        (void)printf("try closing %s first, ok ?\n",globname);
  1886. X        return;
  1887. X    }
  1888. X
  1889. X    globf = btdbm_open(globargv[1],BT_STRING,O_CREAT,0600);
  1890. X
  1891. X    if(globf == NULL) {
  1892. X        (void)printf("error opening database");
  1893. X        perror(globargv[1]);
  1894. X    } else {
  1895. X        (void)printf("opened %s\n",globargv[1]);
  1896. X        (void)strcpy(globname,globargv[1]);
  1897. X    }
  1898. X}
  1899. X
  1900. X
  1901. Xvoid
  1902. Xdo_close()
  1903. X{
  1904. X    if(globf != NULL) {
  1905. X        if(btdbm_close(globf)) {
  1906. X            (void)printf("error closing\n");
  1907. X        } else {
  1908. X            (void)printf("closed OK\n");
  1909. X            globf = NULL;
  1910. X        }
  1911. X    } else {
  1912. X        (void)printf("nothing open\n");
  1913. X    }
  1914. X}
  1915. X
  1916. X
  1917. Xvoid
  1918. Xdo_quit()
  1919. X{
  1920. X    if(globf != NULL) {
  1921. X        (void)printf("closing %s\n",globname);
  1922. X        if(btdbm_close(globf)) {
  1923. X            (void)printf("problems closing %s\n",globname);
  1924. X            exit(1);
  1925. X        }
  1926. X    }
  1927. X    exit(0);
  1928. X}
  1929. X
  1930. X
  1931. Xvoid
  1932. Xdo_help()
  1933. X{
  1934. X    struct    cmd    *c = cmds;
  1935. X    (void)printf("short list of commands::\n------------------------\n");
  1936. X    while(c->name != 0) {
  1937. X        (void)printf("%s\n",c->usage);
  1938. X        c++;
  1939. X    }
  1940. X}
  1941. X
  1942. X
  1943. Xvoid
  1944. Xdo_store()
  1945. X{
  1946. X    btdatum    key;
  1947. X    btdatum    data;
  1948. X
  1949. X    key.dptr = (bt_chrp)globargv[1];
  1950. X    key.dsize = strlen(globargv[1]);
  1951. X
  1952. X    data.dptr = (bt_chrp)globargv[2];
  1953. X    data.dsize = strlen(globargv[2]) + 1;
  1954. X
  1955. X    if(btdbm_store(globf,key,data,BTDBM_REPLACE))
  1956. X        printf("could not store\n");
  1957. X}
  1958. X
  1959. X
  1960. Xvoid
  1961. Xdo_fetch()
  1962. X{
  1963. X    btdatum    key;
  1964. X    btdatum    data;
  1965. X
  1966. X    key.dptr = (bt_chrp)globargv[1];
  1967. X    key.dsize = strlen(globargv[1]);
  1968. X
  1969. X    data = btdbm_fetch(globf,key);
  1970. X    if(data.dptr == 0)
  1971. X        printf("could not fetch\n");
  1972. X    else
  1973. X        printf("%s\n",data.dptr);
  1974. X}
  1975. X
  1976. X
  1977. Xvoid
  1978. Xdo_delete()
  1979. X{
  1980. X    btdatum    key;
  1981. X
  1982. X    key.dptr = (bt_chrp)globargv[1];
  1983. X    key.dsize = strlen(globargv[1]);
  1984. X
  1985. X    if(btdbm_delete(globf,key) != 0)
  1986. X        printf("could not delete\n");
  1987. X    else
  1988. X        printf("deleted.\n");
  1989. X}
  1990. X
  1991. X
  1992. Xvoid
  1993. Xdo_first()
  1994. X{
  1995. X    btdatum    key;
  1996. X
  1997. X    key = btdbm_firstkey(globf);
  1998. X    if(key.dsize == 0)
  1999. X        printf("no first key\n");
  2000. X    else
  2001. X        printf("%s\n",key.dptr);
  2002. X}
  2003. X
  2004. X
  2005. Xvoid
  2006. Xdo_next()
  2007. X{
  2008. X    btdatum    key;
  2009. X
  2010. X    key = btdbm_nextkey(globf);
  2011. X    if(key.dsize == 0)
  2012. X        printf("no next key\n");
  2013. X    else
  2014. X        printf("%s\n",key.dptr);
  2015. X}
  2016. END_OF_FILE
  2017. if test 5674 -ne `wc -c <'b+tree/utils/dbtest.c'`; then
  2018.     echo shar: \"'b+tree/utils/dbtest.c'\" unpacked with wrong size!
  2019. fi
  2020. # end of 'b+tree/utils/dbtest.c'
  2021. fi
  2022. echo shar: End of archive 3 \(of 5\).
  2023. cp /dev/null ark3isdone
  2024. MISSING=""
  2025. for I in 1 2 3 4 5 ; do
  2026.     if test ! -f ark${I}isdone ; then
  2027.     MISSING="${MISSING} ${I}"
  2028.     fi
  2029. done
  2030. if test "${MISSING}" = "" ; then
  2031.     echo You have unpacked all 5 archives.
  2032.     rm -f ark[1-9]isdone
  2033. else
  2034.     echo You still need to unpack the following archives:
  2035.     echo "        " ${MISSING}
  2036. fi
  2037. ##  End of shell archive.
  2038. exit 0
  2039.  
  2040.