home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / b+tree_mjr / part04 < prev    next >
Text File  |  1990-01-19  |  48KB  |  1,946 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v10i030: B+tree library, part04 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 30
  7. Submitted-by: mjr@umiacs.UMD.EDU (Marcus J. Ranum)
  8. Archive-name: b+tree_mjr/part04
  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 4 (of 5)."
  17. # Contents:  b+tree/btlib/btpage2.c b+tree/doc/store.3
  18. #   b+tree/utils/rectest.c b+tree/utils/testrack.c
  19. # Wrapped by mjr@atreus on Fri Jan 19 10:34:59 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'b+tree/btlib/btpage2.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'b+tree/btlib/btpage2.c'\"
  23. else
  24. echo shar: Extracting \"'b+tree/btlib/btpage2.c'\" \(9448 characters\)
  25. sed "s/^X//" >'b+tree/btlib/btpage2.c' <<'END_OF_FILE'
  26. X#include    <sys/types.h>
  27. X#include    "btconf.h"
  28. X#include    "btree.h"
  29. X#include    "btintern.h"
  30. X
  31. X/*
  32. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  33. X                    All rights reserved
  34. X
  35. X
  36. X          This software, its documentation,  and  supporting
  37. X          files  are  copyrighted  material  and may only be
  38. X          distributed in accordance with the terms listed in
  39. X          the COPYRIGHT document.
  40. X*/
  41. X
  42. X
  43. X#ifndef    lint
  44. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/btlib/RCS/btpage2.c,v 1.1 89/10/24 10:09:05 mjr Rel $";
  45. X#endif
  46. X
  47. X
  48. Xbt_delpg(at,in,out)
  49. Xint    at;
  50. Xbt_chrp    in;
  51. Xbt_chrp    out;
  52. X{
  53. X    int    iky;            /* key iterator */
  54. X    REGISTER bt_chrp    icp;    /* old key pointer */
  55. X    REGISTER bt_chrp    ocp;    /* new key pointer */
  56. X    REGISTER int    *iin;        /* old index/length pointer */
  57. X    REGISTER int    *iout;        /* new index/length pointer */
  58. X    REGISTER off_t    *lin;        /* old child ptr */
  59. X    REGISTER off_t    *lout;        /* new child ptr */
  60. X    REGISTER int    t;        /* iterator */
  61. X    int    dropd = 0;        /* flag AND count of dropped bytes */
  62. X    int    shif = 0;        /* length index shift after drop */
  63. X
  64. X    /* delete a key from a page. very similar to insert in page */
  65. X    /* except we do it in 2 steps, like a split because we are not */
  66. X    /* sure how long the key being dropped is until we get there. */
  67. X    /* since we don't know how long it is, we can't set up the */
  68. X    /* index and child ptrs, and have to do that in a second pass */
  69. X
  70. X    /* fix key count in new page */
  71. X    KEYCNT(out) = KEYCNT(in) - 1;
  72. X
  73. X    /* fix left and right sibs */
  74. X    LSIB(out) = LSIB(in);
  75. X    RSIB(out) = RSIB(in);
  76. X
  77. X    /* fix high pointer (may change later) */
  78. X    HIPT(out) = HIPT(in);
  79. X
  80. X    /* init various pointers */
  81. X    ocp = KEYADR(out);
  82. X    icp = KEYADR(in);
  83. X    iin = (int *)KEYIND(in);
  84. X
  85. X    /* start copy/drop of keys */
  86. X    for(iky = 0; iky < KEYCNT(in); iky++) {
  87. X        if(at == iky) {
  88. X            if(iky == 0)
  89. X                for(t = 0; t < *iin; t++)
  90. X                    icp++;
  91. X            else
  92. X                for(t = 0; t < (*iin - *(iin - 1)); t++)
  93. X                    icp++;
  94. X            dropd = t;
  95. X        } else {
  96. X            if(iky == 0)
  97. X                for(t = 0; t < *iin; t++)
  98. X                    *ocp++ = *icp++;
  99. X            else
  100. X                for(t = 0; t < (*iin - *(iin - 1)); t++)
  101. X                    *ocp++ = *icp++;
  102. X        }
  103. X        iin++;
  104. X    }
  105. X
  106. X    /* fix key count length new page */
  107. X    if(at == KEYCNT(in) && HIPT(in) != BT_NULL) {
  108. X        /* if we are dropping last key from an index page, */
  109. X        /* drop the last key (effectively) by decrementing */
  110. X        /* the length. kind of a kludgey way to do it... */
  111. X        KEYLEN(out) = KEYLEN(in) - t;
  112. X    } else {
  113. X        /* key length of the new page is length of old minus */
  114. X        /* the length of the key that we already dropped */
  115. X        KEYLEN(out) = KEYLEN(in) - dropd;
  116. X    }
  117. X
  118. X    /* reset pointers in prep for ptr/index copy/drop */
  119. X    iin = (int *)KEYIND(in);
  120. X    iout = (int *)KEYIND(out);
  121. X    lin = (off_t *)KEYCLD(in);
  122. X    lout = (off_t *)KEYCLD(out);
  123. X
  124. X    /* start copy/drop of ptrs */
  125. X    for(iky = 0; iky < KEYCNT(in); iky++) {
  126. X        if(at == iky) {
  127. X            shif = dropd;
  128. X        } else {
  129. X            if(iky == KEYCNT(in) - 1 && HIPT(in) != BT_NULL && at == KEYCNT(in)) {
  130. X                HIPT(out) = *lin;
  131. X            } else {
  132. X                *iout++ = *iin - shif;
  133. X                *lout++ = *lin;
  134. X            }
  135. X        }
  136. X        iin++;
  137. X        lin++;
  138. X    }
  139. X}
  140. X
  141. X
  142. Xbt_keyof(n,p,dbuf,dlen,dptr,max)
  143. Xint    n;
  144. Xbt_chrp    p;
  145. Xbt_chrp    dbuf;
  146. Xint    *dlen;
  147. Xoff_t    *dptr;
  148. Xint    max;
  149. X{
  150. X
  151. X    /* clip the numbered key out of the page and return it in */
  152. X    /* kbuf. the key length and rrv are also returned as well */
  153. X    int    *ip;
  154. X    bt_chrp    cp;
  155. X
  156. X    if(KEYCNT(p) == 0) {
  157. X        *dlen = 0;
  158. X        *dptr = BT_NULL;
  159. X        return(BT_OK);
  160. X    }
  161. X
  162. X    cp = KEYADR(p);
  163. X    ip = (int *)KEYIND(p);
  164. X
  165. X    if(n == 0) {
  166. X        *dlen = *ip;
  167. X    } else {
  168. X        *dlen = *(ip + n) - *(ip + (n - 1));
  169. X        cp += *(ip + (n - 1));
  170. X    }
  171. X
  172. X    if(*dlen > max)
  173. X        return(BT_ERR);
  174. X
  175. X    *dptr = *((off_t *)KEYCLD(p) + n);
  176. X#ifdef    USE_BCOPY
  177. X    (void)bcopy((char *)cp,(char *)dbuf,*dlen);
  178. X#endif
  179. X#ifdef    USE_MEMCPY
  180. X    (void)memcpy((char *)cp,(char *)dbuf,*dlen);
  181. X#endif
  182. X#ifdef    USE_MOVEMEM
  183. X    (void)movemem((char *)cp,(char *)dbuf,*dlen);
  184. X#endif
  185. X    return(BT_OK);
  186. X}
  187. X
  188. Xvoid
  189. Xbt_splpg(key,len,ptr,at,siz,old,lo,hi,new,nlen)
  190. Xbt_chrp    key;
  191. Xint    len;
  192. Xoff_t    *ptr;
  193. Xint    at;
  194. Xint    siz;
  195. Xbt_chrp    old;
  196. Xbt_chrp    lo;
  197. Xbt_chrp    hi;
  198. Xbt_chrp    new;
  199. Xint    *nlen;
  200. X{
  201. X    int    oky;            /* key iterator */
  202. X    int    iky;            /* key iterator */
  203. X    int    byt = 0;        /* key byte cnt for low page */
  204. X    REGISTER bt_chrp    icp;    /* old key pointer */
  205. X    REGISTER bt_chrp    ocp;    /* new key pointer */
  206. X    REGISTER int    *iin;        /* old index/length pointer */
  207. X    REGISTER int    *iout;        /* new index/length pointer */
  208. X    REGISTER off_t    *lin;        /* old child ptr */
  209. X    REGISTER off_t    *lout;        /* new child ptr */
  210. X    REGISTER int    t;        /* iterator */
  211. X    char    copied = 0;        /* flag */
  212. X    int    shif = 0;        /* length index shift after insert */
  213. X    int    dropbyt = 0;        /* bytes dropped in index split */
  214. X    int    splitat;        /* key # where we did the split */
  215. X    
  216. X    /* this is somewhat different from a simple page insert, since */
  217. X    /* we don't yet know HOW long each key block will be, and as a */
  218. X    /* result we can't copy the pointers until the keys have been */
  219. X    /* done. first we copy the keys, fix up the length and count */
  220. X    /* values, which allows us to correctly get the addresses of */
  221. X    /* the various pointer offsets, and then we copy the keys/ptrs */
  222. X    /* there are, as you would expect, tons of special cases and */
  223. X    /* so on, in this function. The MAIN special cases are: the */
  224. X    /* last key in the low page is the one that needs to be sent */
  225. X    /* up to the calling function for insertion in the parent page */
  226. X    /* after the split. This is done with a little kludgery stuck */
  227. X    /* in the logic where we switch pages during the key copy. The */
  228. X    /* second special case is when we are splitting an index page, */
  229. X    /* the low child ptr has to become "meaningful" so what needs */
  230. X    /* to happen is that the lowest key in the high page needs to */
  231. X    /* get dropped onto the floor, rather than copied. *THEN* the */
  232. X    /* pointers need to be adjusted during the pointer copy. Ick ! */
  233. X
  234. X    /* set pointers to keys prior to copy. low key first. */
  235. X    icp = KEYADR(old);
  236. X    ocp = KEYADR(lo);
  237. X
  238. X
  239. X    /* set the child ptr pointer here - it is used to tell */
  240. X    /* if this is an index page when we do the key copy */
  241. X    lin = (off_t *)KEYCLD(old);
  242. X
  243. X    /* warning! used as a temp var to tell if we have switched pages. */
  244. X    KEYLEN(lo) = 0;
  245. X
  246. X    /* set pointer to old index - output indices are unknown still */
  247. X    iin = (int *)KEYIND(old);
  248. X
  249. X    /* copy one more key than was in the old page */
  250. X    for(iky = oky = 0; oky < KEYCNT(old) + 1; oky++) {
  251. X
  252. X        /* if we are at insertion point, insert key here */
  253. X        if(at == iky && copied == 0) {
  254. X            for(t = 0; t < len; t++)
  255. X                *ocp++ = *key++;
  256. X            byt += len;
  257. X            copied++;
  258. X        } else {
  259. X            /* the usual nonsense with key #0 length */
  260. X            if(iky == 0) {
  261. X                for(t = 0; t < *iin; t++)
  262. X                    *ocp++ = *icp++;
  263. X                byt += *iin;
  264. X            } else {
  265. X                for(t = 0; t < *iin - *(iin - 1); t++)
  266. X                    *ocp++ = *icp++;
  267. X                byt += *iin - *(iin - 1);
  268. X            }
  269. X            iky++;
  270. X            iin++;
  271. X        }
  272. X
  273. X        /* when the first page is full, start on the second */
  274. X        if(KEYLEN(lo) == 0 && (PTRUSE + byt + (oky * (sizeof(int) + sizeof(off_t)))) > siz) {
  275. X
  276. X            /* set length and count for low page */
  277. X            KEYLEN(lo) = byt;
  278. X            KEYCNT(lo) = oky + 1;
  279. X
  280. X            /* remember the # of the key where we split */
  281. X            splitat = oky;
  282. X
  283. X            /* set high pointer for low page */
  284. X            /* if this is an interior page, drop the */
  285. X            /* last key and turn the last ptr into */
  286. X            /* the high pointer (done below) */
  287. X            if(HIPT(old) != BT_NULL) {
  288. X                KEYCNT(lo) = oky;
  289. X
  290. X                /* keep track of how many bytes we just */
  291. X                /* lost so we can fix key lengths later */
  292. X                dropbyt = t;
  293. X
  294. X                /* adjust length of low key */
  295. X                KEYLEN(lo) = byt - dropbyt;
  296. X            }
  297. X
  298. X            /* return the dropped or otherwise high key */
  299. X            /* in new, and set nlen, if applicable */
  300. X             if(new != (bt_chrp)0) {
  301. X                bt_chrp    tmpp;
  302. X
  303. X                 *nlen = t;
  304. X                 tmpp = new + (t - 1);
  305. X                 /* do the copy */
  306. X                 while(t--)
  307. X                     *tmpp-- = *(--ocp);
  308. X            }
  309. X
  310. X            /* now set the out pointer to point to next page */
  311. X            ocp = KEYADR(hi);
  312. X
  313. X        }
  314. X    }
  315. X
  316. X    /* set key counts - if we split an index, we dropped one */
  317. X    if(HIPT(old) == BT_NULL) {
  318. X        KEYCNT(hi) = oky - KEYCNT(lo);
  319. X    } else {
  320. X        KEYCNT(hi) = (oky - KEYCNT(lo)) - 1;
  321. X    }
  322. X
  323. X    /* set key lengths - if we split an index, adjust high value */
  324. X    KEYLEN(hi) = byt - KEYLEN(lo) - dropbyt;
  325. X
  326. X    /* set the locations of the ptrs */
  327. X    iout = (int *)KEYIND(lo);
  328. X    iin = (int *)KEYIND(old);
  329. X    lout = (off_t *)KEYCLD(lo);
  330. X
  331. X    /* copy ptrs and insert new ptr at specified location */
  332. X    copied = 0;
  333. X
  334. X    for(iky = oky = 0; oky < KEYCNT(old) + 1; oky++) {
  335. X
  336. X        if(at == iky && copied == 0) {
  337. X            copied++;
  338. X            if(oky == splitat && HIPT(old) != BT_NULL) {
  339. X                HIPT(lo) = *ptr;
  340. X
  341. X                /* since we did this, dropped bytes */
  342. X                /* dont count. ignore them */
  343. X                dropbyt = 0; 
  344. X            } else {
  345. X                *lout = *ptr;
  346. X
  347. X                /* set up length/index ptrs */
  348. X                /* do not do this if the ptr was */
  349. X                /* inserted at a dropped location */
  350. X                if(iky == 0 || oky == splitat + 1)
  351. X                    *iout = len;
  352. X                else 
  353. X                    *iout = *(iout - 1) + len;
  354. X
  355. X                /* length values now shift due to insert */
  356. X                shif += len;
  357. X            }
  358. X        } else {
  359. X            if(oky == splitat && HIPT(old) != BT_NULL) {
  360. X                /* normal ptr insert at boundary */
  361. X                HIPT(lo) = *lin++;
  362. X                iin++;
  363. X            } else {
  364. X                *lout = *lin++;
  365. X
  366. X                *iout = *iin + shif;
  367. X                iin++;
  368. X            }
  369. X
  370. X            iky++;
  371. X        }
  372. X        iout++;
  373. X        lout++;
  374. X
  375. X        if(oky == splitat) {
  376. X
  377. X            lout = (off_t *)KEYCLD(hi);
  378. X            iout = (int *)KEYIND(hi);
  379. X
  380. X            /* index/length values now shift due to split */
  381. X            shif -= (KEYLEN(lo) + dropbyt);
  382. X
  383. X            if(HIPT(old) == BT_NULL)
  384. X                HIPT(lo) = BT_NULL;
  385. X        }
  386. X
  387. X    }
  388. X
  389. X    /* the high pointer of the high page will be that of the */
  390. X    /* original page. the low pages high pointer should have */
  391. X    /* already been fixed up properly somewhere in code above */
  392. X    HIPT(hi) = HIPT(old);
  393. X}
  394. END_OF_FILE
  395. if test 9448 -ne `wc -c <'b+tree/btlib/btpage2.c'`; then
  396.     echo shar: \"'b+tree/btlib/btpage2.c'\" unpacked with wrong size!
  397. fi
  398. # end of 'b+tree/btlib/btpage2.c'
  399. fi
  400. if test -f 'b+tree/doc/store.3' -a "${1}" != "-c" ; then 
  401.   echo shar: Will not clobber existing file \"'b+tree/doc/store.3'\"
  402. else
  403. echo shar: Extracting \"'b+tree/doc/store.3'\" \(12752 characters\)
  404. sed "s/^X//" >'b+tree/doc/store.3' <<'END_OF_FILE'
  405. X.\"
  406. X.\"         (C) Copyright, 1988, 1989 Marcus J. Ranum
  407. X.\"                    All rights reserved
  408. X.\"
  409. X.\"
  410. X.\"          This software, its documentation,  and  supporting
  411. X.\"          files  are  copyrighted  material  and may only be
  412. X.\"          distributed in accordance with the terms listed in
  413. X.\"          the COPYRIGHT document.
  414. X.\"
  415. X.\" $Header: /atreus/mjr/hacks/btree/doc/RCS/store.3,v 1.2 89/10/23 16:06:04 mjr Rel $
  416. X.\"
  417. X.TH STORE 3 "18 October 1989"
  418. X.SH NAME
  419. Xstore \- variable length record storage and management routines
  420. X.SH SYNOPSIS
  421. X.B #include <sys/types.h>
  422. X.br
  423. X.B #include <store.h>
  424. X.sp
  425. X.LP
  426. X.B "sto_ptr store_alloc(st,bytes)"
  427. X.br
  428. X.B "STORE *st;"
  429. X.br
  430. X.B "int bytes;"
  431. X.LP
  432. X.B "int store_close(st)"
  433. X.br
  434. X.B "STORE *st;"
  435. X.LP
  436. X.B "int store_copy(st,record1,record2)"
  437. X.br
  438. X.B "STORE *st;"
  439. X.br
  440. X.B "sto_ptr record1;"
  441. X.br
  442. X.B "sto_ptr record2;"
  443. X.LP
  444. X.B "int store_decrefcnt(st,record)"
  445. X.br
  446. X.B "STORE *st;"
  447. X.br
  448. X.B "sto_ptr record;"
  449. X.LP
  450. X.B "int store_free(st,record)"
  451. X.br
  452. X.B "STORE *st;"
  453. X.br
  454. X.B "sto_ptr record;"
  455. X.LP
  456. X.B "int store_gethdr(st,record,hdr)"
  457. X.br
  458. X.B "STORE *st;"
  459. X.br
  460. X.B "sto_ptr record;"
  461. X.br
  462. X.B "struct sto_hdr hdr;"
  463. X.LP
  464. X.B "int store_increfcnt(st,record)"
  465. X.br
  466. X.B "STORE *st;"
  467. X.br
  468. X.B "sto_ptr record;"
  469. X.LP
  470. X.B "int store_linkafter(st,record,predecessor)"
  471. X.br
  472. X.B "STORE *st;"
  473. X.br
  474. X.B "sto_ptr record;"
  475. X.br
  476. X.B "sto_ptr predecessor;"
  477. X.LP
  478. X.B "int store_linkbefore(st,record,next)"
  479. X.br
  480. X.B "STORE *st;"
  481. X.br
  482. X.B "sto_ptr record;"
  483. X.br
  484. X.B "sto_ptr next;"
  485. X.LP
  486. X.B "STORE *store_open(file,flags,mode)"
  487. X.br
  488. X.B "char *file;"
  489. X.br
  490. X.B "int flags;"
  491. X.br
  492. X.B "int mode;"
  493. X.LP
  494. X.B "void store_perror(st,string)"
  495. X.br
  496. X.B "STORE *st;"
  497. X.br
  498. X.B "char *string;"
  499. X.LP
  500. X.B "int store_puthdr(st,record,hdr)"
  501. X.br
  502. X.B "STORE *st;"
  503. X.br
  504. X.B "sto_ptr record;"
  505. X.br
  506. X.B "struct sto_hdr hdr;"
  507. X.LP
  508. X.B "int store_read(st,record,offset,buf,siz,rsiz)"
  509. X.br
  510. X.B "STORE *st;"
  511. X.br
  512. X.B "sto_ptr record;"
  513. X.br
  514. X.B "off_t offset;"
  515. X.br
  516. X.B "unsigned char *buf;"
  517. X.br
  518. X.B "int siz;"
  519. X.br
  520. X.B "int *rsiz;"
  521. X.LP
  522. X.B "int store_realloc(st,record,newbytes)"
  523. X.br
  524. X.B "STORE *st;"
  525. X.br
  526. X.B "sto_ptr record;"
  527. X.br
  528. X.B "int newbytes;"
  529. X.LP
  530. X.B "sto_ptr store_reallocbuf(st,newsize)"
  531. X.br
  532. X.B "STORE *st;"
  533. X.br
  534. X.B "int newsize;"
  535. X.LP
  536. X.B "int store_unlink(st,record)"
  537. X.br
  538. X.B "STORE *st;"
  539. X.br
  540. X.B "sto_ptr record;"
  541. X.LP
  542. X.B "int store_write(st,record,offset,buf,bytes)"
  543. X.br
  544. X.B "STORE *st;"
  545. X.br
  546. X.B "sto_ptr record;"
  547. X.br
  548. X.B "off_t offset;"
  549. X.br
  550. X.B "unsigned char *buf;"
  551. X.br
  552. X.B "int bytes;"
  553. X.SH DESCRIPTION
  554. X.LP
  555. XThe record storage library is intended to provide a reasonably simple
  556. Xlow-level record allocation and manipulation package. Functions are
  557. Xprovided for allocating, deallocating, reallocating, copying, and linking
  558. Xrecords into lists. Basic functions are also provided for performing
  559. XI/O to records with the ability to update complete or partial records.
  560. XFree space management is based on first fit without garbage collection.
  561. X.LP
  562. XThe interface to the library is intended to somewhat evoke 
  563. X.B "malloc()"
  564. Xet. al., with a typedef'd data type
  565. X.B sto_ptr
  566. Xbeing the "address" of a storage record (in this case, the offset of
  567. Xthe record header in the disk file). The library is constructed in
  568. Xseveral layers, the lowest handling accessing and modifying the record
  569. Xheaders, stored data, and storage allocation. Another layer is built
  570. Xupon the basic routines, managing copying data, reallocation and resizing
  571. Xof records, and linked list management. The library is constructed so
  572. Xthat a minimal price is paid for features not used, so programmers can
  573. Xwork at whatever level suits their needs.
  574. X.LP
  575. XWith each record, an internal count is kept of the number of bytes in
  576. Xuse within the record (the record's size) and the actual allocated size
  577. Xof the record (the record's allocation). Reads and writes may adjust the
  578. Xrecord's size, but only allocation or reallocation can affect the
  579. Xrecord's allocation.
  580. X.SH FUNCTIONS
  581. X.LP
  582. X.B "sto_ptr store_alloc(store,bytes)"
  583. X.br
  584. XThe
  585. X.B store_alloc
  586. Xfunction allocates a record space of
  587. X.B bytes
  588. Xsize and returns the address of the record, or 
  589. X.B STO_NULL
  590. Xif the allocation failed.
  591. X.LP
  592. X.B "store_close(store)"
  593. X.br
  594. XThis function closes a store file.
  595. X.LP
  596. X.B "store_copy(store,rec1,rec2)"
  597. X.br
  598. XThis function copies the data in record
  599. X.B rec1
  600. Xinto
  601. X.B rec2,
  602. Xwhich must have been previously allocated, and must be large enough to
  603. Xcontain the contents of
  604. X.B rec1.
  605. XIf
  606. X.B rec2
  607. Xhas data already allocated in it, and
  608. X.B rec1
  609. Xdoes not completely over-write
  610. X.B rec2
  611. Xthe size of the record remains whatever size
  612. X.B rec2
  613. Xalready held. This allows a record to be "overlaid" on another, similarly
  614. Xto
  615. X.B "bcopy(3)"
  616. Xand its effect on memory. If
  617. X.B rec2
  618. Xhad not actually had any data written into it, the size of the record's
  619. Xcontents will be set as that of
  620. X.B rec1.
  621. X.LP
  622. X.B "store_decrefcnt(store,record)"
  623. X.br
  624. XThis function decrements the reference counter of the record by one.
  625. XThe reference count can go below zero. Reference counts do not currently
  626. Xhave much effect on records, however
  627. X.B "store_free()"
  628. Xwill not free a record with a reference count greater than zero, though
  629. Xit will decrement it automatically, and return as if the operation had
  630. Xcompleted correctly.
  631. X.LP
  632. X.B "store_gethdr(store,record,hdr)"
  633. X.br
  634. XThis function reads the header of the record specified in
  635. X.B record,
  636. Xand places the results in
  637. X.B hdr.
  638. XThis function performs some additional checks to try to ensure that
  639. Xthe record is a valid one, including checking a magic number stored
  640. Xin the header.
  641. X.LP
  642. X.B "store_increfcnt(store,record)"
  643. X.br
  644. XThis function increments the reference counter of the record by one.
  645. X.LP
  646. X.B "store_linkafter(store,record,predecessor)"
  647. X.br
  648. XThis function places the record
  649. X.B record
  650. Xinto a linked list after the record
  651. X.B predecessor
  652. Xand adjusts and links that may have already existed between
  653. X.B predecessor
  654. Xand any other records linked after it.
  655. XIf
  656. X.B record
  657. Xis already linked into a list, those links are \fBnot\fR broken before
  658. Xthe link-in is performed. This permits appending two chains together,
  659. Xbut also makes it possible to destroy a chain by inserting a record
  660. Xwithout unlinking it from its siblings. Careful management of the 
  661. Xlinked lists is the user's responsibility. If a call is made to
  662. X.B store_free
  663. Xor
  664. X.B store_realloc
  665. Xthe links are unlinked, or adjusted appropriately, if they exist.
  666. X.LP
  667. X.B "store_linkbefore(store,record,next)"
  668. X.br
  669. XThis function links the record before the record specified as
  670. X.B next.
  671. X.LP
  672. X.B "STORE *store_open(file,flags,mode)"
  673. X.br
  674. XThis function allocates a new store file handle, with the pathname
  675. Xspecified by
  676. X.B file.
  677. XThe flags specified in
  678. X.B flags
  679. Xand the mode specified in
  680. X.B mode
  681. Xare passed to
  682. X.B "open(2)".
  683. X.LP
  684. X.B "void store_perror(store,string)"
  685. X.br
  686. XThis function prints an error string
  687. X.B string
  688. Xassociated with store file
  689. X.B store
  690. Xon the standard error, if there is an error flag set for that store
  691. Xfile. If there is no error flag set, and a system error number is
  692. Xset in 
  693. X.B errno
  694. Xthe library call
  695. X.B "perror(3)"
  696. Xis called instead.
  697. X.LP
  698. X.B "int store_puthdr(store,record,hdr)"
  699. X.br
  700. XThis function writes the header stored in
  701. X.B hdr
  702. Xinto the record header for
  703. X.B record.
  704. X.LP
  705. X.B "int store_read(store,record,offset,buf,size,rsiz)"
  706. X.br
  707. XThis function reads the data stored in record
  708. X.B record,
  709. Xstarting from offset
  710. X.B offset
  711. Xrelative to the beginning of the record. The returned data is
  712. Xplaced in
  713. X.B buf,
  714. Xup to a maximum of
  715. X.B size, 
  716. Xand the number of bytes read is returned in
  717. X.B rsiz.
  718. XIf there was more data in the record than could fit in
  719. X.B buf,
  720. X.B size
  721. Xbytes is read into
  722. X.B buf,
  723. Xand 
  724. X.B store_read
  725. Xreturns the constant
  726. X.B STO_MORE
  727. Xto indicate that there is more data to read.
  728. X.LP
  729. X.B "sto_ptr store_realloc(store,record,newbytes)"
  730. X.bt
  731. XThis function allocates a new record of size
  732. X.B newbytes
  733. Xand copies the contents of
  734. X.B record
  735. Xinto it, returning the new record pointer, or
  736. X.B STO_NULL
  737. Xin the event of a failure.
  738. X.LP
  739. X.B "int store_reallocbuf(store,newsize)"
  740. X.br
  741. XThis function is used to manipulate the size of the internal
  742. Xbuffer used by the record store, to allocate more memory for it
  743. Xif needed. This is used in the
  744. X.B btdbm
  745. Xlibrary to stretch the buffer to adapt to user data.
  746. X.LP
  747. X.B "int store_unlink(store,record)"
  748. X.br
  749. XThis function breaks any linked list pointers for
  750. X.B record
  751. Xand re-connects them as necessary to fill the record's gap.
  752. X.LP
  753. X.B "int store_write(store,record,offset,buf,bytes)"
  754. X.br
  755. XThis function will write
  756. X.B bytes
  757. Xfrom 
  758. X.B buf
  759. Xinto record
  760. X.B record
  761. Xstarting at offset
  762. X.B offset
  763. Xrelative to the beginning of the record. If the write cannot fit into
  764. Xthe space allocated for the record,
  765. X.B STO_ERR
  766. Xis returned. If the write places more of the record's allocated space
  767. Xinto use, the record header will be adjusted appropriately. This function
  768. Xcan be used to over-write parts of a record, as well as entire records,
  769. Xso that each record can be treated somewhat like a small file in its
  770. Xown right. 
  771. X.SH "MACROS"
  772. X.LP
  773. XSince these values are all macros, they should be used only with
  774. Xcaution, to avoid side-effects. Mostly these should not be used by
  775. Xuser-level code, but providing a common interface seemed better
  776. Xthan the alternative.
  777. X.LP
  778. X.B "(int) store_errno(store)"
  779. X.br
  780. Xpoints to the error number associated with the storage file.
  781. X.LP
  782. X.B "(void) store_clearerr(store)"
  783. X.br
  784. Xclears the error number associated with the storage file.
  785. X.LP
  786. X.B "(int) store_fileno(store)"
  787. X.br
  788. Xpoints to the file descriptor of the storage file.
  789. X.LP
  790. X.B "(unsigned char *) store_buffer(store)"
  791. X.br
  792. Xpoints to the internal buffer of the storage file. This can be used
  793. X(wisely) as a buffer in which to store record data temporarily, but
  794. Xit may be changed without warning by any of the store library or
  795. Xbtdbm library functions.
  796. X.LP
  797. X.B "(int) store_bufsiz(store)"
  798. X.br
  799. Xpoints to an integer value that is the current maximum size of the
  800. Xinternal buffer.
  801. X.LP
  802. X.B "(sto_ptr) store_currec(store)"
  803. X.br
  804. Xpoints to a temporary area in which the current record can be stored.
  805. XAny calls to the btdbm library or the store library may change this
  806. Xvalue. (NOT USED CURRENTLY).
  807. X.LP
  808. X.B "(sto_ptr) store_label(store)"
  809. X.br
  810. Xpoints to a special record value that can be used to store data file
  811. Xspecific information. Currently neither the store or btdbm libraries
  812. Xuse this value. It is initially not allocated, and must be allocated
  813. Xand set before using. In all other ways, it is treated just like any
  814. Xother record. The intent is to allow a place to store static schema
  815. Xinformation, etc.
  816. X.SH EXAMPLES
  817. X.nf
  818. X.na
  819. X.ft C
  820. X    STORE    *p;
  821. X    struct    froozum    stuff;
  822. X    sto_ptr    rec;
  823. X    int    i;
  824. X
  825. X    p = store_open("foo.dat",O_CREAT,0600);
  826. X
  827. X    if(p != NULL) {
  828. X        rec = store_alloc(p,sizeof(struct froozum));
  829. X        if(rec == STO_NULL) {
  830. X            store_perror(p,"cannot allocate record");
  831. X            exit(1);
  832. X        }
  833. X
  834. X        i = store_write(p,rec,0L,(unsigned char *)&stuff,sizeof(stuff))
  835. X        if(i != STO_OK) {
  836. X            store_perror(p,"cannot store stuff");
  837. X            exit(1);
  838. X        }
  839. X    }
  840. X.ft R
  841. X.fi
  842. X.ad
  843. X.LP
  844. XThe above would open \fIfoo.dat\fR with mode 0600, and would create
  845. Xthe file if it did not already exist. A record is allocated with enough
  846. Xroom to fit a data structure, which is then stored.
  847. X.SH "SEE ALSO"
  848. X.SH "INTERNAL FUNCTIONS"
  849. X.LP
  850. XThe following functions are internal functions used by the store library.
  851. XCare should be taken to avoid declaring functions with names that clash:
  852. X.B store_wsuper
  853. X.LP
  854. XIn general, all the store library functions and macros are prefixed with
  855. X.B store_...
  856. Xand constants with
  857. X.B STO_...
  858. X.SH DIAGNOSTICS
  859. X.LP
  860. XThe value
  861. X.B STO_OK
  862. Xis returned whenever a function is successful.
  863. X.LP
  864. XThe value
  865. X.SM
  866. X.B STO_ERR
  867. Xis returned to indicate some form of failure in any operation performed on 
  868. Xa valid
  869. X.B STORE.
  870. XAll valid storage file handles contain their own error number that is set to
  871. Xindicate the cause of a failure, and can be accessed with the macro
  872. X.B "store_errno(store)"
  873. X(where
  874. X.B store
  875. Xis a valid store file). A function 
  876. X.B "store_perror(store,string)"
  877. X(where 
  878. X.B string
  879. Xis a character pointer and
  880. X.B store
  881. Xis a valid store file) is provided, which prints an appropriate error
  882. Xmessage on the standard error.
  883. XAdditionally, access to the error strings is available through the
  884. Xexternal array
  885. X.B "store_errs[]".
  886. XConstant value codes for each error are defined in
  887. X.B store.h
  888. Xfor symbolic reference.
  889. X.LP
  890. XThe value
  891. X.SM
  892. X.B NULL
  893. Xis returned to indicate that a
  894. X.SM
  895. X.B STORE
  896. Xpointer has not been initialized properly.
  897. X.SH BUGS
  898. X.LP
  899. XThe facilities for managing linked lists is very primitive. Ideally, more
  900. Xwork should be done behind the scenes by the library, rather than forcing
  901. Xthe user to handle link consistency.
  902. X.LP
  903. XA lot is left to the user's discretion.
  904. X.SH LIMITATIONS
  905. X.LP
  906. XA record can be arbitrarily large, though it will take longer to copy
  907. Xand reallocate longer records. The way in which the
  908. X.B store_read
  909. Xand 
  910. X.B store_write
  911. Xfunctions are implemented allows reasonably flexible manipulation of even
  912. Xlarge amounts of storage in a record.
  913. X.SH AUTHOR
  914. X.LP
  915. XMarcus J. Ranum
  916. END_OF_FILE
  917. if test 12752 -ne `wc -c <'b+tree/doc/store.3'`; then
  918.     echo shar: \"'b+tree/doc/store.3'\" unpacked with wrong size!
  919. fi
  920. chmod +x 'b+tree/doc/store.3'
  921. # end of 'b+tree/doc/store.3'
  922. fi
  923. if test -f 'b+tree/utils/rectest.c' -a "${1}" != "-c" ; then 
  924.   echo shar: Will not clobber existing file \"'b+tree/utils/rectest.c'\"
  925. else
  926. echo shar: Extracting \"'b+tree/utils/rectest.c'\" \(9925 characters\)
  927. sed "s/^X//" >'b+tree/utils/rectest.c' <<'END_OF_FILE'
  928. X#include    <stdio.h>
  929. X#include    <ctype.h>
  930. X#include    <sys/types.h>
  931. X#include    <sys/file.h>
  932. X#include    "store.h"
  933. X
  934. X/*
  935. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  936. X                    All rights reserved
  937. X
  938. X
  939. X          This software, its documentation,  and  supporting
  940. X          files  are  copyrighted  material  and may only be
  941. X          distributed in accordance with the terms listed in
  942. X          the COPYRIGHT document.
  943. X*/
  944. X
  945. X/*
  946. X    Test rack program for the record storage library. This allows some
  947. X    minimal interaction with record stores. All records are identified
  948. X    with the header of their offset. The only way to get a valid header
  949. X    is by alloc'ing a new record. Good luck. This is not worth documenting.
  950. X*/
  951. X
  952. X
  953. X#ifndef    lint
  954. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/utils/RCS/rectest.c,v 1.1 89/10/24 10:09:27 mjr Rel $";
  955. X#endif
  956. X
  957. X
  958. XSTORE    *globf = NULL;
  959. X
  960. X#define    MAXARG    40
  961. Xchar    *globargv[MAXARG];        /* args for commands */
  962. Xint    globargc;
  963. Xchar    globname[500];
  964. X
  965. Xextern    char    *strcpy();
  966. Xextern    char    *malloc();
  967. Xextern    char    *rindex();
  968. Xextern    long    atol();
  969. Xextern    float    atof();
  970. X
  971. Xvoid do_open(), do_close(), do_quit(), do_help();
  972. Xvoid do_read(), do_write(), do_alloc(), do_pheader();
  973. Xvoid do_increc(), do_decrec(), do_free(), do_copy();
  974. Xvoid do_realloc(), do_linkrec(), do_unlink();
  975. X
  976. Xvoid    enargv();    /* function to parse user args into strings */
  977. Xvoid    doit();        /* dispatch function */
  978. X
  979. Xstatic    char    *grokmsg = "Cannot interpret \"%s\" as a record number\n";
  980. X
  981. X
  982. Xstruct    cmd {
  983. X    char    *name;
  984. X    char    *usage;
  985. X    void    (*func)();
  986. X    int    narg;        /* # of args req'd */
  987. X    int    op;        /* needs an open index to call */
  988. X};
  989. X
  990. Xstatic    char    *prompt = "rectest-> ";
  991. X
  992. X/* command dispatch table */
  993. Xstruct    cmd    cmds[] = {
  994. X"alloc",    "alloc nbytes",            do_alloc,    1,    1,
  995. X"close",    "close",            do_close,    1,    1,
  996. X"copy",        "copy fromrec# torec#",        do_copy,    2,    1,
  997. X"decrement",    "decrement rec# (ref count)",    do_decrec,    2,    1,
  998. X"free",        "free rec#",            do_free,    2,    1,
  999. X"increment",    "increment rec# (ref count)",    do_increc,    2,    1,
  1000. X"link",        "link rec# after|before recd#",    do_linkrec,    3,    1,
  1001. X"open",        "open database",        do_open,    2,    0,
  1002. X"printheader",    "printheader rec#",        do_pheader,    2,    1,
  1003. X"quit",        "quit",                do_quit,    1,    0,
  1004. X"read",        "read rec#",            do_read,    2,    1,
  1005. X"realloc",    "realloc rec# size",        do_realloc,    3,    1,
  1006. X"unlink",    "unlink rec#",            do_unlink,    2,    1,
  1007. X"write",    "write rec#",            do_write,    2,    1,
  1008. X"?",        "?",                do_help,    1,    0,
  1009. X0,        0,                0,        0,    0
  1010. X};
  1011. X
  1012. X
  1013. Xmain(ac,av)
  1014. Xint    ac;
  1015. Xchar    **av;
  1016. X{
  1017. X    int    x;
  1018. X    char    buf[BUFSIZ];
  1019. X
  1020. X    /* enargv() makes a string look like an arg. vector. */
  1021. X    /* doit dispatches the stuff, calls functions, etc */
  1022. X    /* functions must have at least the given # of args */
  1023. X    /* last flag in a command if not zero means an index */
  1024. X    /* must be open in order to call that function */
  1025. X    
  1026. X    if(ac > 1) {
  1027. X        char    **gap = globargv;
  1028. X    
  1029. X        globargc = ac - 1;
  1030. X        while(*++av)
  1031. X            *gap++ = *av;
  1032. X        doit();
  1033. X    } else {
  1034. X        (void)printf(prompt);
  1035. X        while(gets(buf)) {
  1036. X            enargv(buf);
  1037. X            if(globargv[0] != NULL)
  1038. X                doit();
  1039. X
  1040. X            for(x = 0; x < globargc; x++)
  1041. X                (void)free(globargv[x]);
  1042. X
  1043. X            (void)printf(prompt);
  1044. X        }
  1045. X        (void)printf("EOF.\n");
  1046. X    }
  1047. X    do_quit();
  1048. X}
  1049. X
  1050. X
  1051. Xvoid
  1052. Xdoit()
  1053. X{
  1054. X    struct    cmd    *c = cmds;
  1055. X
  1056. X    /* main dispatcher */
  1057. X    while(c->name != 0) {
  1058. X        if(strncmp(c->name,globargv[0],strlen(globargv[0])) == 0) {
  1059. X            if(globargc < c->narg) {
  1060. X                (void)printf("usage:\"%s\"\n",c->usage);
  1061. X                return;
  1062. X            } else {
  1063. X                if(c->op != 0 && globf == NULL) {
  1064. X                    (void)printf("no store file open.\n");
  1065. X                    return;
  1066. X                }
  1067. X                (*c->func)();
  1068. X                return;
  1069. X            }
  1070. X        }
  1071. X        c++;
  1072. X    }
  1073. X    (void)printf("unknown command: \"%s\"\n",globargv[0]);
  1074. X    return;
  1075. X}
  1076. X
  1077. X
  1078. Xchar *
  1079. Xwordparse(line,word,delim)
  1080. Xchar    *line,    *word;
  1081. Xint    delim;
  1082. X{
  1083. X    int    quot =0;
  1084. X
  1085. X    /* parse a word, or quoted string into a buffer. */
  1086. X    while (*line && (isspace(*line) || *line == delim))
  1087. X        line++;
  1088. X
  1089. X    if(*line == '\n')
  1090. X        line++;
  1091. X
  1092. X    if (!*line) {
  1093. X        *word = '\0';
  1094. X        return(0);
  1095. X    }
  1096. X
  1097. X    while (*line)
  1098. X    {
  1099. X        if(!quot && (*line == '\"' || *line == '\''))
  1100. X            quot = *line++;
  1101. X
  1102. X        if((isspace(*line) || *line == delim) && !quot) {
  1103. X            break;
  1104. X        } else {
  1105. X            if(quot && *line == quot) {
  1106. X                quot = 0;
  1107. X                line++;
  1108. X            } else {
  1109. X                *word++ = *line++;
  1110. X            }
  1111. X        }
  1112. X    }
  1113. X    *word = '\0';
  1114. X    return(line);
  1115. X}
  1116. X
  1117. X
  1118. Xvoid
  1119. Xenargv(buf)
  1120. Xchar    *buf;
  1121. X{
  1122. X    char    *bufptr;
  1123. X    char    pbuf[BUFSIZ];
  1124. X    
  1125. X    globargc =0;
  1126. X    bufptr = buf;
  1127. X
  1128. X    /* this is kinda gross, but the easiest way to handle */
  1129. X    /* quoted strings, since I already had wordparse() written */
  1130. X    while(bufptr = wordparse(bufptr,pbuf,0)) {
  1131. X        globargv[globargc] = malloc((unsigned)(strlen(pbuf) + 1));
  1132. X        (void)strcpy(globargv[globargc++],pbuf);
  1133. X    }
  1134. X    globargv[globargc] = NULL;
  1135. X}
  1136. X
  1137. Xvoid
  1138. Xdo_open()
  1139. X{
  1140. X    if(globf != NULL) {
  1141. X        (void)printf("try closing %s first, ok ?\n",globname);
  1142. X        return;
  1143. X    }
  1144. X
  1145. X    globf = store_open(globargv[1],O_CREAT,0600);
  1146. X
  1147. X    if(globf == NULL) {
  1148. X        (void)printf("error opening store file ");
  1149. X        perror(globargv[1]);
  1150. X    } else {
  1151. X        (void)printf("opened %s\n",globargv[1]);
  1152. X        (void)strcpy(globname,globargv[1]);
  1153. X    }
  1154. X}
  1155. X
  1156. X
  1157. Xvoid
  1158. Xdo_close()
  1159. X{
  1160. X    if(globf != NULL) {
  1161. X        if(store_close(globf) == STO_OK) {
  1162. X            (void)printf("closed OK\n");
  1163. X            globf = NULL;
  1164. X        } else
  1165. X            (void)printf("error closing\n");
  1166. X    } else {
  1167. X        (void)printf("nothing open\n");
  1168. X    }
  1169. X}
  1170. X
  1171. X
  1172. Xvoid
  1173. Xdo_alloc()
  1174. X{
  1175. X    int    siz;
  1176. X    sto_ptr    ret;
  1177. X
  1178. X    if((siz = atoi(globargv[1])) == 0) {
  1179. X        (void)printf(grokmsg,globargv[1]);
  1180. X        return;
  1181. X    }
  1182. X
  1183. X    ret = store_alloc(globf,siz);
  1184. X    if(ret != STO_NULL) {
  1185. X        (void)printf("allocated record #%ld\n",ret);
  1186. X    } else {
  1187. X        store_perror(globf,"cannot allocate record");
  1188. X    }
  1189. X}
  1190. X
  1191. X
  1192. Xvoid
  1193. Xdo_quit()
  1194. X{
  1195. X    if(globf != NULL) {
  1196. X        (void)printf("closing %s\n",globname);
  1197. X        if(store_close(globf) != STO_OK) {
  1198. X            (void)printf("problems closing %s\n",globname);
  1199. X            exit(1);
  1200. X        }
  1201. X    }
  1202. X    exit(0);
  1203. X}
  1204. X
  1205. X
  1206. Xvoid
  1207. Xdo_help()
  1208. X{
  1209. X    struct    cmd    *c = cmds;
  1210. X    (void)printf("short list of commands::\n------------------------\n");
  1211. X    while(c->name != 0) {
  1212. X        (void)printf("%s\n",c->usage);
  1213. X        c++;
  1214. X    }
  1215. X}
  1216. X
  1217. X
  1218. Xvoid
  1219. Xdo_read()
  1220. X{
  1221. X    char    buf[BUFSIZ];
  1222. X    int    rv;
  1223. X    int    byts;
  1224. X    off_t    offset =0L;
  1225. X    sto_ptr    r;
  1226. X
  1227. X    if((r = atol(globargv[1])) == 0L) {
  1228. X        (void)printf(grokmsg,globargv[1]);
  1229. X        return;
  1230. X    }
  1231. X
  1232. X    if(globargc > 2) {
  1233. X        if((offset = atol(globargv[2])) == 0L) {
  1234. X            (void)printf(grokmsg,globargv[1]);
  1235. X            return;
  1236. X        } else {
  1237. X            (void)printf("offset is %ld\n",offset);
  1238. X        }
  1239. X    }
  1240. X
  1241. X    while(1) {
  1242. X        rv = store_read(globf,r,offset,(unsigned char *)buf,sizeof(buf),&byts);
  1243. X        switch(rv) {
  1244. X            case STO_OK:
  1245. X                (void)printf("got %d bytes:\n",byts);
  1246. X                buf[byts] = '\0';
  1247. X                (void)printf("%s\n",buf);
  1248. X                return;
  1249. X
  1250. X            case STO_MORE:
  1251. X                (void)printf("got %d bytes:\n",byts);
  1252. X                buf[byts] = '\0';
  1253. X                (void)printf("%s\n---(press return for more)---",buf);
  1254. X                (void)gets(buf);
  1255. X            
  1256. X            case STO_ERR:
  1257. X                store_perror(globf,"cannot read record");
  1258. X                return;
  1259. X        }
  1260. X    }
  1261. X}
  1262. X
  1263. X
  1264. Xvoid
  1265. Xdo_write()
  1266. X{
  1267. X    char    buf[BUFSIZ];
  1268. X    int    rv;
  1269. X    off_t    offset =0L;
  1270. X    sto_ptr    r;
  1271. X
  1272. X    if((r = atol(globargv[1])) == 0L) {
  1273. X        (void)printf(grokmsg,globargv[1]);
  1274. X        return;
  1275. X    }
  1276. X
  1277. X    if(globargc > 2) {
  1278. X        if((offset = atol(globargv[2])) == 0L) {
  1279. X            (void)printf(grokmsg,globargv[1]);
  1280. X            return;
  1281. X        } else {
  1282. X            (void)printf("offset is %ld\n",offset);
  1283. X        }
  1284. X    }
  1285. X
  1286. X    (void)printf("\tinput-> ");
  1287. X    if(fgets(buf,BUFSIZ,stdin) != NULL) {
  1288. X        rv = store_write(globf,r,offset,(unsigned char *)buf,strlen(buf));
  1289. X        if(rv != STO_OK) {
  1290. X            store_perror(globf,"cannot store record");
  1291. X        }
  1292. X    }
  1293. X}
  1294. X
  1295. Xvoid
  1296. Xdo_pheader()
  1297. X{
  1298. X    struct    sto_hdr    rbuf;
  1299. X    sto_ptr    r;
  1300. X
  1301. X    if((r = atol(globargv[1])) == 0L) {
  1302. X        (void)printf(grokmsg,globargv[1]);
  1303. X        return;
  1304. X    }
  1305. X
  1306. X    if(store_gethdr(globf,r,&rbuf) == STO_ERR) {
  1307. X        store_perror(globf,"cannot get record header");
  1308. X        return;
  1309. X    }
  1310. X    (void)printf("struct\tsto_hdr {\n\toff_t\tmagic = %ld\n",rbuf.magic);
  1311. X    (void)printf("\tint\tsize = %d\n\tint\tused = %d\n",rbuf.size,rbuf.used);
  1312. X    (void)printf("\tint\trefs = %d\n\tsto_ptr\tnext = %d\n",rbuf.refs,rbuf.next);
  1313. X    (void)printf("\tsto_ptr\tprev = %d\n};\n",rbuf.prev);
  1314. X}
  1315. X
  1316. X
  1317. Xvoid
  1318. Xdo_increc()
  1319. X{
  1320. X    sto_ptr    r;
  1321. X
  1322. X    if((r = atol(globargv[1])) == 0L) {
  1323. X        (void)printf(grokmsg,globargv[1]);
  1324. X        return;
  1325. X    }
  1326. X
  1327. X    if(store_increfcnt(globf,r) == STO_ERR) {
  1328. X        store_perror(globf,"cannot increment record header");
  1329. X        return;
  1330. X    }
  1331. X}
  1332. X
  1333. X
  1334. Xvoid
  1335. Xdo_decrec()
  1336. X{
  1337. X    sto_ptr    r;
  1338. X
  1339. X    if((r = atol(globargv[1])) == 0L) {
  1340. X        (void)printf(grokmsg,globargv[1]);
  1341. X        return;
  1342. X    }
  1343. X
  1344. X    if(store_decrefcnt(globf,r) == STO_ERR) {
  1345. X        store_perror(globf,"cannot decrement record header");
  1346. X        return;
  1347. X    }
  1348. X}
  1349. X
  1350. X
  1351. Xvoid
  1352. Xdo_free()
  1353. X{
  1354. X    sto_ptr    r;
  1355. X
  1356. X    if((r = atol(globargv[1])) == 0L) {
  1357. X        (void)printf(grokmsg,globargv[1]);
  1358. X        return;
  1359. X    }
  1360. X
  1361. X    if(store_free(globf,r) == STO_ERR) {
  1362. X        store_perror(globf,"cannot free record");
  1363. X        return;
  1364. X    }
  1365. X}
  1366. X
  1367. X
  1368. Xvoid
  1369. Xdo_copy()
  1370. X{
  1371. X    sto_ptr    r1;
  1372. X    sto_ptr    r2;
  1373. X
  1374. X    if((r1 = atol(globargv[1])) == 0L) {
  1375. X        (void)printf(grokmsg,globargv[1]);
  1376. X        return;
  1377. X    }
  1378. X    if((r2 = atol(globargv[2])) == 0L) {
  1379. X        (void)printf(grokmsg,globargv[2]);
  1380. X        return;
  1381. X    }
  1382. X
  1383. X    if(store_copy(globf,r1,r2) == STO_ERR) {
  1384. X        store_perror(globf,"cannot copy record");
  1385. X        return;
  1386. X    }
  1387. X}
  1388. X
  1389. X
  1390. Xvoid
  1391. Xdo_realloc()
  1392. X{
  1393. X    sto_ptr    rec;
  1394. X    int    nsize;
  1395. X
  1396. X    if((rec = atol(globargv[1])) == 0L) {
  1397. X        (void)printf(grokmsg,globargv[1]);
  1398. X        return;
  1399. X    }
  1400. X    if((nsize = atoi(globargv[2])) == 0L) {
  1401. X        (void)printf(grokmsg,globargv[2]);
  1402. X        return;
  1403. X    }
  1404. X    if((rec = store_realloc(globf,rec,nsize)) == STO_NULL) {
  1405. X        store_perror(globf,"realloc failed");
  1406. X        return;
  1407. X    }
  1408. X    (void)printf("new record is %ld\n",rec);
  1409. X}
  1410. X
  1411. X
  1412. Xvoid
  1413. Xdo_linkrec()
  1414. X{
  1415. X    sto_ptr    rec;
  1416. X    sto_ptr    rec2;
  1417. X    int    after = 1;
  1418. X    int    ret;
  1419. X
  1420. X    if((rec = atol(globargv[1])) == 0L) {
  1421. X        (void)printf(grokmsg,globargv[1]);
  1422. X        return;
  1423. X    }
  1424. X
  1425. X    if(strncmp(globargv[2],"after",strlen(globargv[2])))
  1426. X        if(strncmp(globargv[2],"before",strlen(globargv[2]))) {
  1427. X            (void)printf("specify \"before\" or \"after\"\n");
  1428. X            return;
  1429. X        } else
  1430. X            after = 0;
  1431. X
  1432. X    if((rec2 = atol(globargv[3])) == 0L) {
  1433. X        (void)printf(grokmsg,globargv[3]);
  1434. X        return;
  1435. X    }
  1436. X
  1437. X    if(after)
  1438. X        ret = store_linkafter(globf,rec,rec2);
  1439. X    else
  1440. X        ret = store_linkbefore(globf,rec,rec2);
  1441. X    if(ret == STO_ERR) {
  1442. X        store_perror(globf,"relink failed");
  1443. X        return;
  1444. X    }
  1445. X}
  1446. X
  1447. X
  1448. Xvoid
  1449. Xdo_unlink()
  1450. X{
  1451. X    sto_ptr    rec;
  1452. X
  1453. X    if((rec = atol(globargv[1])) == 0L) {
  1454. X        (void)printf(grokmsg,globargv[1]);
  1455. X        return;
  1456. X    }
  1457. X
  1458. X    
  1459. X    if(store_unlink(globf,rec) == STO_ERR) {
  1460. X        store_perror(globf,"unlink failed");
  1461. X        return;
  1462. X    }
  1463. X}
  1464. END_OF_FILE
  1465. if test 9925 -ne `wc -c <'b+tree/utils/rectest.c'`; then
  1466.     echo shar: \"'b+tree/utils/rectest.c'\" unpacked with wrong size!
  1467. fi
  1468. # end of 'b+tree/utils/rectest.c'
  1469. fi
  1470. if test -f 'b+tree/utils/testrack.c' -a "${1}" != "-c" ; then 
  1471.   echo shar: Will not clobber existing file \"'b+tree/utils/testrack.c'\"
  1472. else
  1473. echo shar: Extracting \"'b+tree/utils/testrack.c'\" \(11151 characters\)
  1474. sed "s/^X//" >'b+tree/utils/testrack.c' <<'END_OF_FILE'
  1475. X#include    <stdio.h>
  1476. X#include    <sys/file.h>
  1477. X#include    <sys/types.h>
  1478. X#include    "btree.h"
  1479. X
  1480. X/*
  1481. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  1482. X                    All rights reserved
  1483. X
  1484. X
  1485. X          This software, its documentation,  and  supporting
  1486. X          files  are  copyrighted  material  and may only be
  1487. X          distributed in accordance with the terms listed in
  1488. X          the COPYRIGHT document.
  1489. X*/
  1490. X
  1491. X
  1492. X#ifndef    lint
  1493. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/utils/RCS/testrack.c,v 1.1 89/10/24 10:09:25 mjr Rel $";
  1494. X#endif
  1495. X
  1496. Xextern    char    *index();
  1497. X
  1498. X/*
  1499. X    about this program:
  1500. X    This program slams the btree index routines repeatedly on thier
  1501. X    heads in an attempt to break them, or detect problems. rather
  1502. X    than make the checks rely on information about the internal
  1503. X    structures of the tree itself, these checks verify the BEHAVIOUR
  1504. X    of the library. that is to say, if 1000 keys are inserted, it
  1505. X    should be possible to find them all. if 1000 keys are deleted,
  1506. X    there should be no more keys left, etc. really, the only aspect
  1507. X    of the functions that is not given a pretty harsh going-over is
  1508. X    the reverse traversing function. this is mainly because I cant
  1509. X    think of a nice way to scan an ascii file a line at a time in
  1510. X    reverse, and didn't want to have another sorted input file.
  1511. X
  1512. X    before this code has been released, this testrack has been
  1513. X    allowed to run on a reasonable variety of page sizes for a
  1514. X    reasonable number of keys (say, 10,000) for, say, a day or
  1515. X    two, on a Sun4. if you make changes to the library internals
  1516. X    this suite can come in pretty handy, though it offers zero
  1517. X    help for debugging.
  1518. X*/
  1519. X
  1520. Xstatic    void
  1521. Xdie(b1,b2,val)
  1522. XBT_INDEX    *b1;
  1523. XBT_INDEX    *b2;
  1524. Xint        val;
  1525. X{
  1526. X    /* die is called with a sequentially higher value from each */
  1527. X    /* possible point of failure. this allows quick location of */
  1528. X    /* which check may have produced he fatal error condition */
  1529. X    if(b1 != NULL)
  1530. X        (void)bt_close(b1);
  1531. X    if(b2 != NULL)
  1532. X        (void)bt_close(b2);
  1533. X    (void)fprintf(stderr,"tests FAILED at error point %d\n",val);
  1534. X    exit(val);
  1535. X}
  1536. X
  1537. Xmain(ac, av)
  1538. Xint     ac;
  1539. Xchar   *av[];
  1540. X{
  1541. X    char           buf[BUFSIZ];
  1542. X    char           buf2[BUFSIZ];
  1543. X    FILE        *input;
  1544. X    FILE        *sorted;
  1545. X    BT_INDEX    *b = NULL;    /* main test index */
  1546. X    BT_INDEX    *d = NULL;    /* index to store deleted keys */
  1547. X    char        *p;
  1548. X    off_t          rrv = 0L;
  1549. X    int        ret;
  1550. X    int        keycnt = 0;    /* # of keys inserted */
  1551. X    int        psiz = BUFSIZ;
  1552. X    int        retlen;
  1553. X    int        junk;
  1554. X
  1555. X    /* boo ! Sun buffers stderr ! */
  1556. X    (void)setbuf(stderr,0);
  1557. X
  1558. X    if(ac < 3) {
  1559. X        (void)fprintf(stderr,"usage: %s input sorted_input [psiz]\n",av[0]);
  1560. X        die(b,d,1);
  1561. X    }
  1562. X
  1563. X    if(ac > 3) {
  1564. X        if((psiz = atoi(av[3])) == 0) {
  1565. X            (void)fprintf(stderr,"cannot grok %s as a page size\n",av[3]);
  1566. X            die(b,d,2);
  1567. X        }
  1568. X    }
  1569. X
  1570. X    if((input = fopen(av[1],"r")) == NULL) {
  1571. X        perror(av[1]);
  1572. X        die(b,d,3);
  1573. X    }
  1574. X
  1575. X    if((sorted = fopen(av[2],"r")) == NULL) {
  1576. X        perror(av[2]);
  1577. X        die(b,d,4);
  1578. X    }
  1579. X
  1580. X#ifdef    BTOPEN
  1581. X    b = bt_open("test.dat",O_CREAT|O_TRUNC,0600);
  1582. X#else
  1583. X    b = bt_optopen(BT_PATH,    "test.dat",
  1584. X            BT_OMODE,    O_CREAT|O_TRUNC,    /* clobber */
  1585. X            BT_CACHE,    2,
  1586. X            BT_PSIZE,    psiz,
  1587. X    0);
  1588. X#endif
  1589. X
  1590. X    if(b == NULL) {
  1591. X        perror("test.dat");
  1592. X        die(b,d,5);
  1593. X    }
  1594. X
  1595. X#ifdef    DEBUG
  1596. X    (void)fprintf(stderr,"Start: opened all trees OK.\n");
  1597. X#endif
  1598. X
  1599. X    /* PHASE I - insert everything from our random-ordered file */
  1600. X    /* into our newly created tree. This should return all BT_OK */
  1601. X    while(fgets(buf,BUFSIZ,input) != NULL) {
  1602. X
  1603. X        /* drop newline */
  1604. X        if((p = index(buf,'\n')) != NULL)
  1605. X            *p = '\0';
  1606. X
  1607. X        /* stuff it */
  1608. X        ret = bt_insert(b,buf,strlen(buf),++rrv,1);
  1609. X        if(ret != BT_OK) {
  1610. X            (void)fprintf(stderr,"insert \"%s\" failed: ",buf);
  1611. X            bt_perror(b,NULL);
  1612. X            die(b,d,6);
  1613. X        }
  1614. X        keycnt++;
  1615. X    }
  1616. X#ifdef    DEBUG
  1617. X    (void)fprintf(stderr,"passed phase I, inserted %d keys OK.\n",keycnt);
  1618. X#endif
  1619. X
  1620. X
  1621. X    /* PHASE II - rewind to the beginning of the input file and */
  1622. X    /* search for each key again, to make sure we can find it. */
  1623. X    if(fseek(input,0L,0)) {
  1624. X        perror("rewind random ordered input file");
  1625. X        die(b,d,7);
  1626. X    }
  1627. X    keycnt = 0;
  1628. X    while(fgets(buf,BUFSIZ,input) != NULL) {
  1629. X
  1630. X        /* drop newline */
  1631. X        if((p = index(buf,'\n')) != NULL)
  1632. X            *p = '\0';
  1633. X
  1634. X        /* find it */
  1635. X        ret = bt_find(b,buf,strlen(buf),&rrv);
  1636. X        if(ret != BT_OK) {
  1637. X            (void)fprintf(stderr,"find \"%s\" failed: ",buf);
  1638. X            bt_perror(b,NULL);
  1639. X            die(b,d,8);
  1640. X        }
  1641. X        keycnt++;
  1642. X    }
  1643. X#ifdef    DEBUG
  1644. X    (void)fprintf(stderr,"passed phase II, located %d keys OK.\n",keycnt);
  1645. X#endif
  1646. X
  1647. X
  1648. X    /* PHASE III - go to the beginning of the tree, and read each */
  1649. X    /* key in order. as we read it, compare it to the matching key */
  1650. X    /* read out of the sorted input file. they should all match */
  1651. X
  1652. X    if(fseek(sorted,0L,0)) {
  1653. X        perror("rewind ordered input file");
  1654. X        die(b,d,9);
  1655. X    }
  1656. X
  1657. X    /* goto head of tree */
  1658. X    if(bt_goto(b,BT_BOF) == BT_ERR) {
  1659. X        bt_perror(b,"rewind btree to BOF");
  1660. X        die(b,d,10);
  1661. X    }
  1662. X
  1663. X    while(fgets(buf,BUFSIZ,sorted) != NULL) {
  1664. X
  1665. X        /* drop newline */
  1666. X        if((p = index(buf,'\n')) != NULL)
  1667. X            *p = '\0';
  1668. X
  1669. X        ret = bt_traverse(b,BT_EOF,buf2,BUFSIZ,&retlen,&rrv);
  1670. X        if(ret != BT_OK) {
  1671. X            (void)fprintf(stderr,"read of next key failed.\n");
  1672. X            die(b,d,11);
  1673. X        }
  1674. X
  1675. X        /* NULL terminate buf2 */
  1676. X        buf2[retlen] = '\0';
  1677. X
  1678. X        if(strcmp(buf2,buf)) {
  1679. X            (void)fprintf(stderr,"read-back of \"%s\" and \"%s\" - do not match.\n",buf,buf2);
  1680. X            die(b,d,12);
  1681. X        }
  1682. X    }
  1683. X#ifdef    DEBUG
  1684. X    (void)fprintf(stderr,"passed phase III, ordered read-back of keys.\n");
  1685. X#endif
  1686. X
  1687. X
  1688. X    /* PHASE IV - delete half the keys from the index */
  1689. X
  1690. X    /* rewind input file */
  1691. X    if(fseek(input,0L,0)) {
  1692. X        perror("rewind input file");
  1693. X        die(b,d,13);
  1694. X    }
  1695. X
  1696. X    /* open a second index to store deleted keys */
  1697. X#ifdef    BTOPEN
  1698. X    d = bt_open("test2.dat",O_CREAT|O_TRUNC,0600);
  1699. X#else
  1700. X    d = bt_optopen(BT_PATH,    "test2.dat",
  1701. X            BT_OMODE,    O_CREAT|O_TRUNC,    /* clobber */
  1702. X            BT_CACHE,    2,
  1703. X            BT_PSIZE,    psiz,
  1704. X    0);
  1705. X#endif
  1706. X    if(d == NULL) {
  1707. X        perror("test2.dat");
  1708. X        die(b,d,14);
  1709. X    }
  1710. X    for(junk = 0; junk < keycnt/2; junk++) {
  1711. X        if(fgets(buf,BUFSIZ,input) == NULL) {
  1712. X            (void)fprintf(stderr,"EOF in read-back of initial input\n");
  1713. X            die(b,d,15);
  1714. X        }
  1715. X
  1716. X        /* drop newline */
  1717. X        if((p = index(buf,'\n')) != NULL)
  1718. X            *p = '\0';
  1719. X
  1720. X        /* see if the key is a duplicate that was already deleted */
  1721. X        /* and if so, do not try to re-delete it */
  1722. X        ret = bt_find(d,buf,strlen(buf),&rrv);
  1723. X        if(ret == BT_NF) {
  1724. X
  1725. X            /* not in the deleted index, so delete it and add it */
  1726. X            /* step 1: delete from real index */
  1727. X            if(bt_delete(b,buf,strlen(buf)) != BT_OK) {
  1728. X                bt_perror(b,"delete failed\n");
  1729. X                die(b,d,16);
  1730. X            }
  1731. X            /* step 2: add it to the deleted index */
  1732. X            if(bt_insert(d,buf,strlen(buf),-1L,1) != BT_OK) {
  1733. X                bt_perror(d,"insert in deleted failed\n");
  1734. X                die(b,d,17);
  1735. X            }
  1736. X        } else {
  1737. X            if(ret != BT_OK) {
  1738. X                bt_perror(d,"search for deleted failed\n");
  1739. X                die(b,d,18);
  1740. X            }
  1741. X        }
  1742. X    }
  1743. X#ifdef    DEBUG
  1744. X    (void)fprintf(stderr,"passed phase IV, delete half of keys.\n");
  1745. X#endif
  1746. X
  1747. X
  1748. X    /* PHASE V - go to the beginning of the tree, and read each */
  1749. X    /* key in order. as we read it, compare it to the matching key */
  1750. X    /* read out of the sorted input file. they should all match */
  1751. X    /* OR it should be in the deleted index, its an error */
  1752. X
  1753. X    if(fseek(sorted,0L,0)) {
  1754. X        perror("rewind ordered input file");
  1755. X        die(b,d,19);
  1756. X    }
  1757. X
  1758. X    /* goto head of tree */
  1759. X    if(bt_goto(b,BT_BOF) == BT_ERR) {
  1760. X        bt_perror(b,"rewind btree to BOF");
  1761. X        die(b,d,20);
  1762. X    }
  1763. X
  1764. X    while(fgets(buf,BUFSIZ,sorted) != NULL) {
  1765. X
  1766. X        /* drop newline */
  1767. X        if((p = index(buf,'\n')) != NULL)
  1768. X            *p = '\0';
  1769. X
  1770. X        ret = bt_find(d,buf,strlen(buf),&rrv);
  1771. X        if(ret == BT_NF) {
  1772. X            ret = bt_traverse(b,BT_EOF,buf2,BUFSIZ,&retlen,&rrv);
  1773. X
  1774. X            /* NULL terminate buf2 */
  1775. X            buf2[retlen] = '\0';
  1776. X
  1777. X
  1778. X            if(strcmp(buf2,buf)) {
  1779. X                (void)fprintf(stderr,"read-back of \"%s\" and \"%s\" - do not match.\n",buf,buf2);
  1780. X                die(b,d,21);
  1781. X            }
  1782. X        } else {
  1783. X            if(ret != BT_OK) {
  1784. X                (void)fprintf(stderr,"search deleted for \"%s\":",buf);
  1785. X                bt_perror(d,NULL);
  1786. X                die(b,d,22);
  1787. X            }
  1788. X        }
  1789. X    }
  1790. X#ifdef    DEBUG
  1791. X    (void)fprintf(stderr,"passed phase V, ordered read-back of keys.\n");
  1792. X#endif
  1793. X
  1794. X
  1795. X    /* PHASE VI - delete the rest of the keys in the input file */
  1796. X
  1797. X    /* at this point the FILE pointer should still be where we left */
  1798. X    /* it when we were done deleteing the first half of the keys in */
  1799. X    /* the index. */
  1800. X    while(fgets(buf,BUFSIZ,input) != NULL) {
  1801. X
  1802. X        /* drop newline */
  1803. X        if((p = index(buf,'\n')) != NULL)
  1804. X            *p = '\0';
  1805. X
  1806. X        /* see if the key is a duplicate that was already deleted */
  1807. X        /* and if so, do not try to re-delete it */
  1808. X        ret = bt_find(d,buf,strlen(buf),&rrv);
  1809. X        if(ret == BT_NF) {
  1810. X
  1811. X            /* not in the deleted index, so delete it and add it */
  1812. X            /* step 1: delete from real index */
  1813. X            if(bt_delete(b,buf,strlen(buf)) != BT_OK) {
  1814. X                bt_perror(b,"delete failed\n");
  1815. X                die(b,d,23);
  1816. X            }
  1817. X            /* step 2: add it to the deleted index */
  1818. X            if(bt_insert(d,buf,strlen(buf),-1L,1) != BT_OK) {
  1819. X                bt_perror(d,"insert in deleted failed\n");
  1820. X                die(b,d,24);
  1821. X            }
  1822. X        } else {
  1823. X            if(ret != BT_OK) {
  1824. X                bt_perror(d,"search for deleted failed\n");
  1825. X                die(b,d,25);
  1826. X            }
  1827. X        }
  1828. X    }
  1829. X#ifdef    DEBUG
  1830. X    (void)fprintf(stderr,"passed phase VI, delete rest of keys.\n");
  1831. X#endif
  1832. X
  1833. X    /* PHASE VII - make sure there are no more keys in original index */
  1834. X    /* seek to beginning of index and try to traverse. it should give */
  1835. X    /* an EOF immediately. any other result is an error */
  1836. X    /* goto head of tree */
  1837. X    if(bt_goto(b,BT_BOF) == BT_ERR) {
  1838. X        bt_perror(b,"rewind btree to BOF");
  1839. X        die(b,d,26);
  1840. X    }
  1841. X    ret = bt_traverse(b,BT_EOF,buf2,BUFSIZ,&retlen,&rrv);
  1842. X    if(ret != BT_EOF) {
  1843. X        if(ret == BT_ERR) {
  1844. X            bt_perror(b,"traverse to EOF");
  1845. X            die(b,d,27);
  1846. X        }
  1847. X        (void)fprintf(stderr,"expected EOF, but didn't get it\n");
  1848. X        die(b,d,28);
  1849. X    } 
  1850. X#ifdef    DEBUG
  1851. X    (void)fprintf(stderr,"passed phase VII, tree is empty!\n");
  1852. X#endif
  1853. X
  1854. X    /* PHASE VIII - do an optimal reverse load of the deleted tree */
  1855. X    /* back into the original tree */
  1856. X    if(bt_goto(d,BT_EOF) == BT_ERR) {
  1857. X        bt_perror(b,"rewind deleted btree to EOF");
  1858. X        die(b,d,29);
  1859. X    }
  1860. X
  1861. X    /* inform the old tree we are going to bt_load it */
  1862. X    if(bt_load(b,0,0,0L,BT_BOF)== BT_ERR) {
  1863. X        bt_perror(b,"initialize load");
  1864. X        die(b,d,30);
  1865. X    }
  1866. X
  1867. X    while((ret = bt_traverse(d,BT_BOF,buf,BUFSIZ,&retlen,&rrv)) == BT_OK) {
  1868. X        if(bt_load(b,buf,retlen,rrv,BT_OK)== BT_ERR) {
  1869. X            bt_perror(b,"bt_load failed!");
  1870. X            die(b,d,31);
  1871. X        }
  1872. X    }
  1873. X
  1874. X    if(ret != BT_BOF) {
  1875. X        (void)fprintf(stderr,"deleted tree traverse did not complete at BOF!\n");
  1876. X        die(b,d,32);
  1877. X    }
  1878. X
  1879. X    /* a final call to bt_load with BT_EOF tells it to stop */
  1880. X    if(bt_load(b,0,0,0L,BT_EOF) == BT_ERR) {
  1881. X        bt_perror(b,"shut down bt_load");
  1882. X        die(b,d,33);
  1883. X    }
  1884. X
  1885. X#ifdef    DEBUG
  1886. X    (void)fprintf(stderr,"passed phase VIII, optimal load\n");
  1887. X#endif
  1888. X
  1889. X    /* PHASE IX - rewind to the beginning of the input file and */
  1890. X    /* search for each key again, to make sure we can find it. */
  1891. X    if(fseek(input,0L,0)) {
  1892. X        perror("rewind random ordered input file");
  1893. X        die(b,d,34);
  1894. X    }
  1895. X    keycnt = 0;
  1896. X    while(fgets(buf,BUFSIZ,input) != NULL) {
  1897. X
  1898. X        /* drop newline */
  1899. X        if((p = index(buf,'\n')) != NULL)
  1900. X            *p = '\0';
  1901. X
  1902. X        /* find it */
  1903. X        ret = bt_find(b,buf,strlen(buf),&rrv);
  1904. X        if(ret != BT_OK) {
  1905. X            (void)fprintf(stderr,"find \"%s\" failed: ",buf);
  1906. X            bt_perror(b,NULL);
  1907. X            die(b,d,35);
  1908. X        }
  1909. X        keycnt++;
  1910. X    }
  1911. X#ifdef    DEBUG
  1912. X    (void)fprintf(stderr,"passed phase IX, located %d keys OK.\n",keycnt);
  1913. X#endif
  1914. X
  1915. X    (void)bt_close(b);
  1916. X    (void)bt_close(d);
  1917. X#ifdef    DEBUG
  1918. X    (void)fprintf(stderr,"passed all tests OK.\n");
  1919. X#endif
  1920. X    exit(0);
  1921. X}
  1922. END_OF_FILE
  1923. if test 11151 -ne `wc -c <'b+tree/utils/testrack.c'`; then
  1924.     echo shar: \"'b+tree/utils/testrack.c'\" unpacked with wrong size!
  1925. fi
  1926. # end of 'b+tree/utils/testrack.c'
  1927. fi
  1928. echo shar: End of archive 4 \(of 5\).
  1929. cp /dev/null ark4isdone
  1930. MISSING=""
  1931. for I in 1 2 3 4 5 ; do
  1932.     if test ! -f ark${I}isdone ; then
  1933.     MISSING="${MISSING} ${I}"
  1934.     fi
  1935. done
  1936. if test "${MISSING}" = "" ; then
  1937.     echo You have unpacked all 5 archives.
  1938.     rm -f ark[1-9]isdone
  1939. else
  1940.     echo You still need to unpack the following archives:
  1941.     echo "        " ${MISSING}
  1942. fi
  1943. ##  End of shell archive.
  1944. exit 0
  1945.  
  1946.