home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 125.img / PRO-C4.ZIP / BENCH1.ZIP / BENCH / PROTREE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-28  |  68.6 KB  |  2,576 lines

  1. /***( protree.c )************************************************************
  2. *                  Internal PRO-TREE Functions (low level)                  *
  3. *****************************************************************************
  4. *                                                                           *
  5. *  PRO-TREE v1.10  -  Copyright (c) 1988, 1990 Vestronix Inc.               *
  6. *                                                                           *
  7. *  Features:                                                                *
  8. *     - Dynamic leveling                                                    *
  9. *     - Free list for data file and each key in the index file              *
  10. *     - Single-user or Multi-user with appropriate index file locking       *
  11. *     - Single record locking on the data file                              *
  12. *                                                                           *
  13. *  Original : NIG 24-Feb-88, GEO 23-Mar-88, VVA Dec-88 (indexing functs)    *
  14. *  Changed  : JZ Apr-89                                                     *
  15. *  Changed  : BRC 4-Dec-89 (dynamic levels, free space reuse)               *
  16. *                                                                           *
  17. ****************************************************************************/
  18. #include "protree.h"
  19.  
  20.  
  21. /****************************************************************************
  22. *                  PRO-TREE Internal Variable Declatations                  *
  23. ****************************************************************************/
  24. WORD16 PT_filecnt = -1;    /* file system initialization file */
  25. WORD8 *PT_Recbuf;    /* alloc'd once to prevent thrashing */
  26. WORD16 PT_Reclen = 0;    /* length of PT_Recbuf */
  27. WORD8 *PT_Nodebuf;    /* alloc'd once to prevent thrashing */
  28. WORD16 PT_Nodelen = 0;    /* length of PT_Nodebuf */
  29. AFDDEF *PT_fd;        /* file descriptor structure */
  30.  
  31.  
  32. /**************************************
  33. *  checks files and file descriptors  *
  34. **************************************/
  35. int
  36. PT_chk_open(fd_sys, function)
  37.     int fd_sys;
  38.     char *function;
  39. {
  40.     int iostat = IOERROR;
  41.  
  42.     if (PT_filecnt <= 0)
  43.         errmsg("ERROR: PRO-TREE file table not initialized (%s)", function);
  44.  
  45.     else if (fd_sys < 0 || fd_sys >= MAX_FILES ||
  46.       (PT_fd[fd_sys].fd_idx < 0 && PT_fd[fd_sys].fd_idx != -123))
  47.         errmsg("ERROR: bad PRO-TREE fd_sys (%d:[1...%d]) (%s)", fd_sys,
  48.           MAX_FILES, function);
  49.  
  50.     else
  51.         iostat = IOGOOD;
  52.  
  53.     return(iostat);
  54. }
  55.  
  56.  
  57. /***************************************************************
  58. *  This function applies the given type of lock to the B-Tree  *
  59. ***************************************************************/
  60. int
  61. PT_idxlock(fd_sys, type)
  62.     int fd_sys;
  63.     int type;
  64. {
  65.     int iostat = IOGOOD;
  66. #if MAXLOCKS > 0
  67.     AFDDEF *aptr = &PT_fd[fd_sys];
  68.     long len1, len2;
  69.     int i, cycles;
  70.  
  71.     if (aptr->ilocked)
  72.     {
  73.         errmsg("ERROR: There is already a lock in place at %d!",
  74.           aptr->ilocked);
  75.         iostat = IOERROR;
  76.     }
  77.     else
  78.     {
  79.         if (type == FILE_LOCK)
  80.             len1 = MAXLOCKS, len2 = 0;
  81.         else
  82.             len1 = 1, len2 = MAXLOCKS - 1;
  83.             
  84.         /* Suddenly Piggy grabs the conch ... */
  85.         if (lseek(aptr->fd_idx, 0L, FDIR_BEGIN) != 0L)
  86.             iostat = IOIDXSEEK;
  87.         else
  88.         {
  89.             iostat = IOILOCKED;
  90.             for (cycles = 0; !cycles || cycles < MAXLOCKTRYS; cycles++)
  91.             {
  92.                 if (lseek(aptr->fd_idx, 0L, FDIR_BEGIN) != 0L)
  93.                 {
  94.                     iostat = IOIDXSEEK;
  95.                     break;
  96.                 }
  97.                 else if (!LOCK_BLK(aptr->fd_idx, 0L, len1))
  98.                 {
  99.                     aptr->ilocked = FILE_LOCK;
  100.                     iostat = IOGOOD;
  101.                     break;
  102.                 }
  103.             }
  104.         }
  105.  
  106.         /* ... he speaks his piece ... */
  107.         if (type == READ_LOCK && len2 > 0)
  108.         {
  109.             iostat = IOILOCKED;
  110.             for (cycles = 0; !cycles || cycles < MAXLOCKTRYS; cycles++)
  111.             {
  112.                 for (i = 1; i <= len2; i++)
  113.                 {
  114.                     if (lseek(aptr->fd_idx, (long)i, FDIR_BEGIN) != (long)i)
  115.                     {
  116.                         iostat = IOIDXSEEK;
  117.                         break;
  118.                     }
  119.                     else if (!LOCK_BLK(aptr->fd_idx, (long)i, 1L))
  120.                     {
  121.                         aptr->ilocked = i;
  122.                         iostat = IOGOOD;
  123.                         break;
  124.                     }
  125.                 }
  126.                 if (iostat != IOILOCKED || aptr->ilocked)
  127.                     break;
  128.             }
  129.         }
  130.         else if (type == WRITE_LOCK && len2 > 0)
  131.         {
  132.             iostat = IOILOCKED;
  133.             for (cycles = 0; !cycles || cycles < MAXLOCKTRYS; cycles++)
  134.             {
  135.                 if (lseek(aptr->fd_idx, 1L, FDIR_BEGIN) != 1L)
  136.                 {
  137.                     iostat = IOIDXSEEK;
  138.                     break;
  139.                 }
  140.                 else if (!LOCK_BLK(aptr->fd_idx, 1L, len2))
  141.                 {
  142.                     aptr->ilocked = WRITE_LOCK;
  143.                     iostat = IOGOOD;
  144.                     break;
  145.                 }
  146.             }
  147.         }
  148.  
  149.         /* ... and he gives back the shell. */
  150.         if (type != FILE_LOCK && aptr->ilocked && len2 > 0)
  151.         {
  152.             if (lseek(aptr->fd_idx, 0L, FDIR_BEGIN) != 0L)
  153.                 iostat = IOIDXSEEK;
  154.             else if (LOCK_REL(aptr->fd_idx, 0L, len1))
  155.                 iostat = IOINOLOCK;
  156.         }
  157.     }
  158. #endif
  159.  
  160.     return(iostat);
  161. }
  162.  
  163.  
  164. /*****************************************************************
  165. *  This function removes the given type of lock from the B-Tree  *
  166. *****************************************************************/
  167. int
  168. PT_idxunlock(fd_sys, type)
  169.     int fd_sys;
  170.     int type;
  171. {
  172.     int iostat = IOGOOD;
  173. #if MAXLOCKS > 0
  174.     FDDEF *fptr = &fd[fd_sys];
  175.     AFDDEF *aptr = &PT_fd[fd_sys];
  176.     KINFO *kptr;
  177.     long pos, len;
  178.     int key, lev;
  179.  
  180.     /* get amnesia when the lock is released */
  181.     if (aptr->ilocked)
  182.     {
  183.         if (aptr->ilocked < 0)
  184.         {
  185.             iostat = PT_flush_cache(fd_sys);
  186.             for (key = 0; key < fptr->key_cnt; key++)
  187.             {
  188.                 kptr = &(aptr->keyinfo[key]);
  189.                 for (lev = 0; lev < kptr->k_levs; lev++)
  190.                     kptr->c_elt[lev] = -1;
  191.             }
  192.         }
  193.  
  194.         if (aptr->ilocked == FILE_LOCK)
  195.             pos = 0L, len = MAXLOCKS;
  196.         else if (aptr->ilocked == WRITE_LOCK)
  197.             pos = 1L, len = MAXLOCKS - 1;
  198.         else if (aptr->ilocked > 0)
  199.             pos = aptr->ilocked, len = 1;
  200.  
  201.         if (lseek(aptr->fd_idx, pos, FDIR_BEGIN) != pos)
  202.         {
  203.             if (iostat == IOGOOD)
  204.                 iostat = IOIDXSEEK;
  205.         }
  206.         else if (!LOCK_REL(aptr->fd_idx, pos, len))
  207.             aptr->ilocked = 0;
  208.         else if (iostat == IOGOOD)
  209.             iostat = IOINOLOCK;
  210.     }
  211. #endif
  212.  
  213.     return(iostat);
  214. }
  215.  
  216.  
  217. /*************************************************************************
  218. *  Write out a number, doing any neccessary byte/word/longword swapping  *
  219. *************************************************************************/
  220. int
  221. PT_writenum(fd, buf, len)
  222.     int fd;
  223.     char *buf;
  224.     int len;
  225. {
  226.     int iostat = IOGOOD;
  227.  
  228.     PT_swapper(buf, len);
  229.     if (write(fd, buf, len) != len)
  230.         iostat = IOIDXWRITE;
  231.     PT_swapper(buf, len);
  232.  
  233.     return(iostat);
  234. }
  235.  
  236.  
  237. /***********************************************************************
  238. *  Read in a number, doing any neccessary byte/word/longword swapping  *
  239. ***********************************************************************/
  240. int
  241. PT_readnum(fd, buf, len)
  242.     int fd;
  243.     char *buf;
  244.     int len;
  245. {
  246.     int iostat = IOGOOD;
  247.  
  248.     if (read(fd, buf, len) != len)
  249.         iostat = IOIDXREAD;
  250.  
  251.     PT_swapper(buf, len);
  252.  
  253.     return(iostat);
  254. }
  255.  
  256.  
  257. /****************************************************************************
  258. *  This bit here does byte/word/longword swapping for binary data types to  *
  259. *  get it into Intel form.  Since most Intel machines are running DOS the   *
  260. *  extra processing overhead is thrust upon the bigger/faster machines.     *
  261. *                                                                           *
  262. *  NOTE: warnings about unused PARAMETERS or LOCALS should be ignored here  *
  263. ****************************************************************************/
  264. void
  265. PT_swapper(buf, len)
  266.     char *buf;
  267.     int len;
  268. {
  269.     int i, j, tmp;
  270.  
  271. #ifndef SWAP_WORD8
  272.     for (i = 0; i + 1 < len; i += 2)
  273.         tmp = buf[i], buf[i] = buf[i + 1], buf[i + 1] = tmp;
  274. #endif /* !SWAP_WORD8 */
  275.  
  276. #ifndef SWAP_WORD16
  277.     for (i = 0; i + 3 < len; i += 4)
  278.         for (j = 0; j < 2; j++)
  279.             tmp = buf[i + j], buf[i + j] = buf[i + j + 2], buf[i + j + 2] = tmp;
  280. #endif /* !SWAP_WORD16 */
  281.  
  282. #ifdef SWAP_WORD32
  283.     for (i = 0; i + 7 < len; i += 8)
  284.         for (j = 0; j < 4; j++)
  285.             tmp = buf[i + j], buf[i + j] = buf[i + j + 4], buf[i + j + 4] = tmp;
  286. #endif /* SWAP_WORD32 */
  287. }
  288.  
  289.  
  290. /*****************************************************************
  291. *  Read a data record, calling PT_swapper() for all numeric fields  *
  292. *****************************************************************/
  293. int
  294. PT_readdata(fd_sys, buf)
  295.     int fd_sys;
  296.     char *buf;
  297. {
  298.     FDDEF *fptr = &fd[fd_sys];
  299.     AFDDEF *aptr = &PT_fd[fd_sys];
  300.     int i, iostat = IOGOOD;
  301.  
  302.     if (aptr->doffset == PTNOPTR)
  303.         iostat = IOERROR;
  304.     else if (lseek(fptr->fd_num, aptr->doffset, FDIR_BEGIN) != aptr->doffset)
  305.         iostat = IODATSEEK;
  306.     else if (read(fptr->fd_num, buf, (int)fptr->rec_len) != fptr->rec_len)
  307.         iostat = IODATREAD;
  308.  
  309.     /* swap any binary data */
  310.     else
  311.     {
  312.         for (i = 0; i < fptr->fld_cnt; i++)
  313.         {
  314.             switch (fptr->flds[i].fldtype)
  315.             {
  316.             case INTTYP:   /* two byte integer */
  317.             case LNGTYP:   /* four byte integer */
  318.             case FLTTYP:   /* single precision FP number (usually 4 long) */
  319.             case DBLTYP:   /* double precision FP number (usually 8 long) */
  320.                 PT_swapper(&buf[fptr->flds[i].fldstart],
  321.                   fptr->flds[i].fldlen);
  322.                 break;
  323.             }
  324.         }
  325.     }
  326.  
  327.     return(iostat);
  328. }
  329.  
  330.  
  331. /******************************************************************
  332. *  Write a data record, calling PT_swapper() for all numeric fields  *
  333. ******************************************************************/
  334. int
  335. PT_writedata(fd_sys, buf)
  336.     int fd_sys;
  337.     char *buf;
  338. {
  339.     FDDEF *fptr = &fd[fd_sys];
  340.     AFDDEF *aptr = &PT_fd[fd_sys];
  341.     int i, iostat = IOGOOD;
  342. #ifdef ANSI
  343.     extern int i_lockrec(int, char *);
  344. #else
  345.     extern int i_lockrec();
  346. #endif
  347.  
  348.     if (aptr->doffset == PTNOPTR)
  349.     {
  350.         /* try to re-cycle an old node */
  351.         if ((aptr->doffset = PT_recreuse(fd_sys)) == PTNOPTR)
  352.         {
  353.             /* nothing to re-cycle ... carve out a new one */
  354.             do
  355.             {
  356.                 aptr->doffset = lseek(fptr->fd_num, 0L, FDIR_EOF);
  357.             }
  358.             while ((iostat = i_lockrec(fd_sys, NULL)) == IOLOCKED);
  359.         }
  360.     }
  361.  
  362.     /* swap any binary data */
  363.     for (i = 0; iostat == IOGOOD && i < fptr->fld_cnt; i++)
  364.     {
  365.         switch (fptr->flds[i].fldtype)
  366.         {
  367.         case INTTYP:   /* two byte integer */
  368.         case LNGTYP:   /* four byte integer */
  369.         case FLTTYP:   /* single precision FP number (usually 4 long) */
  370.         case DBLTYP:   /* double precision FP number (usually 8 long) */
  371.             PT_swapper(&buf[fptr->flds[i].fldstart],
  372.               fptr->flds[i].fldlen);
  373.             break;
  374.         }
  375.     }
  376.  
  377.     if (lseek(fptr->fd_num, aptr->doffset, FDIR_BEGIN) != aptr->doffset)
  378.         iostat = IODATSEEK;
  379.     else if (write(fptr->fd_num, buf, (int)fptr->rec_len) != fptr->rec_len)
  380.         iostat = IODATWRITE;
  381.  
  382.     /* swap any binary data back */
  383.     for (i = 0; iostat == IOGOOD && i < fptr->fld_cnt; i++)
  384.     {
  385.         switch (fptr->flds[i].fldtype)
  386.         {
  387.         case INTTYP:   /* two byte integer */
  388.         case LNGTYP:   /* four byte integer */
  389.         case FLTTYP:   /* single precision FP number (usually 4 long) */
  390.         case DBLTYP:   /* double precision FP number (usually 8 long) */
  391.             PT_swapper(&buf[fptr->flds[i].fldstart],
  392.               fptr->flds[i].fldlen);
  393.             break;
  394.         }
  395.     }
  396.  
  397.     return(iostat);
  398. }
  399.  
  400.  
  401. /****************************************************************************
  402. *  Write a new style header, including PRO-TREE version, number of levels   *
  403. *  and elements in the tree, and all field and key information.  Old style  *
  404. *  files can still be read with this version of PRO-TREE, but it will       *
  405. *  complain about them as it cannot glean any critical info from them.      *
  406. ****************************************************************************/
  407. int
  408. PT_writehdr(fd_sys)
  409.     int fd_sys;       /* file descriptor in PT_fd table */
  410. {
  411.     FDDEF *fptr = &fd[fd_sys];
  412.     AFDDEF *aptr = &PT_fd[fd_sys];
  413.     WORD16 b2;
  414.     WORD32 b4;
  415.     int i, key, seg, iostat = IOGOOD;
  416.     char fldname[FIELD_NAME_LEN + 1];
  417.     char version[11];
  418.  
  419.     if (lseek(aptr->fd_idx, 0L, FDIR_BEGIN) != 0L)
  420.     {
  421.         iostat = IOIDXSEEK;
  422.         goto error;
  423.     }
  424.  
  425.     memcpy(version, "PROTREE", 7);
  426.     memcpy(version + 7, aptr->version, 3);
  427.     version[10] = 0;
  428.     if (write(aptr->fd_idx, version, 10) != 10)
  429.     {
  430.         iostat = IOIDXWRITE;
  431.         goto error;
  432.     }
  433.  
  434.     b2 = aptr->maxelts;
  435.     if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  436.         goto error;
  437.  
  438.     b2 = fptr->rec_len;
  439.     if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  440.         goto error;
  441.  
  442.     b2 = fptr->fld_cnt;
  443.     if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  444.         goto error;
  445.  
  446.     b2 = fptr->key_cnt;
  447.     if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  448.         goto error;
  449.  
  450.     aptr->ddatptr = (WORD32)tell(aptr->fd_idx);
  451.     b4 = PTNOPTR;
  452.     if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  453.         goto error;
  454.  
  455.     for (i = 0; i < fptr->fld_cnt; i++)
  456.     {
  457.         memset(fldname, 0, FIELD_NAME_LEN + 1);
  458.         strncpy(fldname, fptr->flds[i].fldname, FIELD_NAME_LEN);
  459.         if (write(aptr->fd_idx, fldname, FIELD_NAME_LEN) != FIELD_NAME_LEN)
  460.         {
  461.             iostat = IOIDXWRITE;
  462.             goto error;
  463.         }
  464.         b2 = fptr->flds[i].fldtype;
  465.         if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  466.             goto error;
  467.         b2 = fptr->flds[i].fldstart;
  468.         if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  469.             goto error;
  470.         b2 = fptr->flds[i].fldlen;
  471.         if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  472.             goto error;
  473.     }
  474.  
  475.     for (key = 0; key < fptr->key_cnt; key++)
  476.     {
  477.         for (seg = 0; seg < fptr->keys[key].segcount; seg++)
  478.         {
  479.             b2 = fptr->keys[key].segstart[seg];
  480.             if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  481.                 goto error;
  482.             b2 = fptr->keys[key].seglen[seg];
  483.             if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  484.                 goto error;
  485.             b2 = fptr->keys[key].keytype;
  486.             if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  487.                 goto error;
  488.             b2 = fptr->flds[fptr->keys[key].fldindex[seg]].fldtype;
  489.             if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  490.                 goto error;
  491.             b2 = seg + 1 == fptr->keys[key].segcount ? 0 : 1;
  492.             if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  493.                 goto error;
  494.         }
  495.         b4 = PTNOPTR;
  496.         if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  497.             goto error;
  498.         if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  499.             goto error;
  500.     }
  501.  
  502.     error: /* sorry folks, but this just seemed cleaner than many returns */
  503.  
  504.     if (iostat == IOGOOD)
  505.         iostat = PT_readhdr(fd_sys);
  506.  
  507.     return(iostat);
  508. }
  509.  
  510.  
  511. /****************************************************************************
  512. *  Read a PRO-TREE header, including PRO-TREE version, number of levels     *
  513. *  and elements in the tree, and all field and key information.  Old style  *
  514. *  files can still be read with this version of PRO-TREE, but it will       *
  515. *  complain about them as it cannot glean any critical info from them.      *
  516. ****************************************************************************/
  517. int
  518. PT_readhdr(fd_sys)
  519.     int fd_sys;       /* file descriptor in PT_fd table */
  520. {
  521.     int i, seg, key, levs, segkey, stuff[5], iostat = IOGOOD;
  522.     WORD16 b2;
  523.     WORD32 b4;
  524.     long pos1, pos2;
  525.     FDDEF *fptr = &fd[fd_sys];
  526.     AFDDEF *aptr = &PT_fd[fd_sys];
  527.     KINFO *kptr;
  528.     char fldname[FIELD_NAME_LEN + 1];
  529.     char version[11];
  530.  
  531.     if (lseek(aptr->fd_idx, 0L, FDIR_BEGIN) != 0L)
  532.     {
  533.         iostat = IOIDXSEEK;
  534.         goto error;
  535.     }
  536.  
  537.     if (read(aptr->fd_idx, version, 10) != 10)
  538.     {
  539.         iostat = IOIDXREAD;
  540.         goto error;
  541.     }
  542.     memcpy(aptr->version, version + 7, 3);
  543.     aptr->version[3] = 0;
  544.     if (memcmp(version, "PROTREE", 7))
  545.     {
  546.         errmsg("ERROR: %s is not a current PROTREE index!", aptr->iname);
  547.         iostat = IOBADOPEN;
  548.         goto error;
  549.     }
  550.     else if (memcmp(aptr->version, CURRENT_VERSION, 3))
  551.     {
  552.         errmsg("ERROR: PROTREE version mismatch (program:%s != %s:%s)",
  553.           CURRENT_VERSION, aptr->iname, aptr->version);
  554.         iostat = IOBADOPEN;
  555.         goto error;
  556.     }
  557.  
  558.     if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  559.         goto error;
  560.     aptr->maxelts = b2;
  561.     if (aptr->maxelts < 2)
  562.     {
  563.         errmsg("ERROR: Invalid element count: %d (min is 2) in %s", b2,
  564.           aptr->iname);
  565.         iostat = IOERROR;
  566.         goto error;
  567.     }
  568.  
  569.     if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  570.         goto error;
  571.     if (b2 != fptr->rec_len)
  572.     {
  573.         errmsg("ERROR: %s HDR is %d byte%s too %s", aptr->iname,
  574.           b2 > fptr->rec_len ? b2 - fptr->rec_len : fptr->rec_len - b2,
  575.           b2 == 1 ? "" : "s", b2 > fptr->rec_len ? "long" : "short");
  576.         iostat = IOERROR;
  577.         goto error;
  578.     }
  579.  
  580.     if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  581.         goto error;
  582.     if (b2 != fptr->fld_cnt)
  583.     {
  584.         errmsg("ERROR: Field count change: %s has %d too %s fields",
  585.           aptr->iname,
  586.           b2 > fptr->fld_cnt ? b2 - fptr->fld_cnt : fptr->fld_cnt - b2,
  587.           b2 > fptr->fld_cnt ? "many" : "few");
  588.         iostat = IOFLDDEF;
  589.         goto error;
  590.     }
  591.  
  592.     if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  593.         goto error;
  594.     if (b2 != fptr->key_cnt)
  595.     {
  596.         errmsg("ERROR: Key count change: %s has %d too %s keys", aptr->iname,
  597.           b2 > fptr->key_cnt ? b2 - fptr->key_cnt : fptr->key_cnt - b2,
  598.           b2 > fptr->key_cnt ? "many" : "few");
  599.         iostat = IOKEYDEF;
  600.         goto error;
  601.     }
  602.     aptr->keyinfo = (KINFO *)alloc(sizeof(KINFO) * fptr->key_cnt);
  603.  
  604.     aptr->ddatptr = (WORD32)tell(aptr->fd_idx);
  605.     if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  606.         goto error;
  607.  
  608.     for (i = 0; i < fptr->fld_cnt; i++)
  609.     {
  610.         if (read(aptr->fd_idx, fldname, FIELD_NAME_LEN) != FIELD_NAME_LEN)
  611.         {
  612.             iostat = IOIDXREAD;
  613.             goto error;
  614.         }
  615.         fldname[FIELD_NAME_LEN] = 0;
  616.         if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  617.             goto error;
  618.         if (b2 != fptr->flds[i].fldtype)
  619.         {
  620.             errmsg("ERROR: Field %d(%s) type change in %s", i + 1, fldname,
  621.               aptr->iname);
  622.             iostat = IOFLDDEF;
  623.             goto error;
  624.         }
  625.         if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  626.             goto error;
  627.         if (b2 != fptr->flds[i].fldstart)
  628.         {
  629.             errmsg("ERROR: Field %d(%s) offset change in %s", i + 1, fldname,
  630.               aptr->iname);
  631.             iostat = IOFLDDEF;
  632.             goto error;
  633.         }
  634.         if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  635.             goto error;
  636.         if (b2 != fptr->flds[i].fldlen)
  637.         {
  638.             errmsg("ERROR: Field %d(%s) length change in %s", i + 1, fldname,
  639.               aptr->iname);
  640.             iostat = IOFLDDEF;
  641.             goto error;
  642.         }
  643.     }
  644.  
  645.     for (key = 0; key < fptr->key_cnt; key++)
  646.     {
  647.         fptr->cur_key = key;
  648.         kptr = &(aptr->keyinfo[fptr->cur_key]);
  649.         kptr->k_leng = 0;
  650.  
  651.         for (seg = 0; seg < fptr->keys[key].segcount; seg++)
  652.         {
  653.             if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  654.                 goto error;
  655.             if ((stuff[0] = b2) != fptr->keys[key].segstart[seg])
  656.             {
  657.                 errmsg("ERROR: Offset change in key %d:%d (program:%d %s:%d) (%ld)",
  658.                   fptr->cur_key + 1, seg + 1, fptr->keys[key].segstart[seg],
  659.                   aptr->iname, (int)b2, (WORD32)tell(aptr->fd_idx));
  660.                 iostat = IOKEYDEF;
  661.                 goto error;
  662.             }
  663.             if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  664.                 goto error;
  665.             if ((stuff[1] = b2) != fptr->keys[key].seglen[seg])
  666.             {
  667.                 errmsg("ERROR: Length change in key %d:%d (program:%d %s:%d) (%ld)",
  668.                   fptr->cur_key + 1, seg + 1, fptr->keys[key].seglen[seg],
  669.                   aptr->iname, (int)b2, (WORD32)tell(aptr->fd_idx));
  670.                 iostat = IOKEYDEF;
  671.                 goto error;
  672.             }
  673.             if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  674.                 goto error;
  675.             if ((stuff[2] = b2) != fptr->keys[key].keytype)
  676.             {
  677.                 errmsg("ERROR: Uniquness change in key %d:%d (program:%d %s:%d) (%ld)",
  678.                   fptr->cur_key + 1, seg + 1, fptr->keys[key].keytype,
  679.                   aptr->iname, (int)b2, (WORD32)tell(aptr->fd_idx));
  680.                 iostat = IOKEYDEF;
  681.                 goto error;
  682.             }
  683.             if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  684.                 goto error;
  685.             if ((stuff[3] = b2) != fptr->flds[fptr->keys[key].fldindex[seg]].fldtype)
  686.             {
  687.                 errmsg("ERROR: Type change in key %d:%d (program:%d %s:%d) (%ld)",
  688.                   fptr->cur_key + 1, seg + 1,
  689.                   fptr->flds[fptr->keys[key].fldindex[seg]].fldtype,
  690.                   aptr->iname, (int)b2, (WORD32)tell(aptr->fd_idx));
  691.                 iostat = IOKEYDEF;
  692.                 goto error;
  693.             }
  694.             if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b2, 2)) != IOGOOD)
  695.                 goto error;
  696.             if ((stuff[4] = b2) != (seg + 1 == fptr->keys[key].segcount ? 0 : 1))
  697.             {
  698.                 errmsg("ERROR: Membership change in key %d:%d (program:%d %s:%d) (%ld)",
  699.                   fptr->cur_key + 1, seg + 1,
  700.                   (seg + 1 == fptr->keys[key].segcount ? 0 : 1),
  701.                   aptr->iname, (int)b2, (WORD32)tell(aptr->fd_idx));
  702.                 iostat = IOKEYDEF;
  703.                 goto error;
  704.             }
  705.  
  706.             kptr->sd[seg].s_recstart   = stuff[0];     /* record offset  */
  707.             kptr->sd[seg].s_keystart   = kptr->k_leng; /* key offset     */
  708.             kptr->k_leng              += stuff[1];     /* key length     */
  709.             kptr->sd[seg].s_leng       = stuff[1];     /* segment length */
  710.             if (!stuff[4])
  711.                 kptr->k_type            = stuff[2];     /* uniq or dup    */
  712.             kptr->sd[seg].s_vtyp       = stuff[3];     /* key type       */
  713.         }
  714.  
  715.         kptr->k_segs = fptr->keys[key].segcount;
  716.  
  717.         /* initialize duplicate segment */
  718.         if (kptr->k_type == KEY_DUPLICATE)
  719.         {
  720.             kptr->sd[DUPSEG].s_keystart  = kptr->k_leng;
  721.             kptr->sd[DUPSEG].s_leng      = sizeof(WORD32);
  722.             kptr->sd[DUPSEG].s_vtyp      = LNGTYP;
  723.             kptr->k_leng                += sizeof(WORD32);
  724.         }
  725.  
  726.         /* allocate the top level */
  727.         PT_makenodes(fd_sys, kptr, 1);
  728.  
  729.         kptr->didxptr = (WORD32)tell(aptr->fd_idx);
  730.         if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  731.             goto error;
  732.  
  733.         pos1 = (WORD32)tell(aptr->fd_idx);
  734.         if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  735.             goto error;
  736.         pos2 = (WORD32)tell(aptr->fd_idx);
  737.         if ((kptr->nodeoffset[0] = b4) == PTNOPTR)
  738.         {
  739.             kptr->nodebuff[0].level = 0;
  740.             if ((iostat = PT_writeidx(fd_sys, 0)) != IOGOOD)
  741.                 goto error;
  742.             if (lseek(aptr->fd_idx, pos1, FDIR_BEGIN) != pos1)
  743.             {
  744.                 iostat = IOIDXSEEK;
  745.                 goto error;
  746.             }
  747.             b4 = kptr->nodeoffset[0];
  748.             if ((iostat = PT_writenum(aptr->fd_idx, (char *)&b4, 4)) != IOGOOD)
  749.                 goto error;
  750.         }
  751.         else if ((iostat = PT_readidx(fd_sys, 0, 0)) != IOGOOD)
  752.             goto error;
  753.         if (lseek(aptr->fd_idx, pos2, FDIR_BEGIN) != pos2)
  754.         {
  755.             iostat = IOIDXSEEK;
  756.             goto error;
  757.         }
  758.  
  759.         if (kptr->nodebuff[0].level > 0)
  760.         {
  761.             levs = kptr->nodebuff[0].level + 1;
  762.             kptr->k_levs = -1;
  763.             if ((iostat = PT_resize(fd_sys, kptr, levs)) != IOGOOD)
  764.                 goto error;
  765.         }
  766.     }
  767.     fptr->cur_key = 0;
  768.  
  769.     error: /* sorry folks, but this just seemed cleaner than many returns */
  770.  
  771.     return(iostat);
  772. }
  773.  
  774.  
  775. /****************************************************************************
  776. *  performs lseek and reads an index node to given buffer by record offset  *
  777. ****************************************************************************/
  778. int
  779. PT_readidx(fd_sys, lev, elt)
  780.     int fd_sys;
  781.     int lev;
  782.     int elt;
  783. {
  784.     FDDEF *fptr = &fd[fd_sys];
  785.     AFDDEF *aptr = &PT_fd[fd_sys];
  786.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  787.     long offset;
  788.     int i, j, len, iostat = IOGOOD;
  789.     char *ptr, *ptr2;
  790.  
  791.     if (lev < 0 || lev > kptr->nodebuff[0].level)
  792.         abort_mess("\rDIAG: readidx( lev=%d ) [0..%d]\r\n", lev,
  793.           kptr->nodebuff[0].level);
  794.     else if (lev > 0 && (elt < 0 || elt >= kptr->nodebuff[lev - 1].num_used))
  795.         abort_mess("\rDIAG: readidx( elt=%d ) [0..%d]\r\n", elt,
  796.           kptr->nodebuff[lev - 1].num_used);
  797.  
  798.     if (lev > 0)
  799.         offset = kptr->nodebuff[lev - 1].elt[elt].offset;
  800.     else
  801.         offset = kptr->nodeoffset[0];
  802.  
  803.     if (offset <= 0L)
  804.         abort_mess("\rDIAG: readidx( offset=%ld )\r\n", offset);
  805.  
  806.     /* investigate the need to save current node and/or load a new one */
  807.     if (kptr->c_elt[lev] >= 0)
  808.     {
  809.         if (!lev || (lev > 0 && elt == kptr->c_elt[lev - 1] &&
  810.           kptr->nodeoffset[lev] == offset))
  811.             return(iostat);
  812.         else
  813.             iostat = PT_flush_node(fd_sys, lev);
  814.     }
  815.     kptr->nodeoffset[lev] = offset;
  816.  
  817.     if (lseek(aptr->fd_idx, kptr->nodeoffset[lev], FDIR_BEGIN) !=
  818.       kptr->nodeoffset[lev])
  819.         iostat = IOIDXSEEK;
  820.  
  821.     else
  822.     {
  823.         /* resize the node buffer if need be */
  824.         len =  sizeof(WORD16) * 2;
  825.         len += aptr->maxelts * (sizeof(WORD32) + kptr->k_leng);
  826.  
  827.         if (len > PT_Nodelen)
  828.         {
  829.             if (PT_Nodelen > 0)
  830.                 free(PT_Nodebuf);
  831.             PT_Nodebuf = alloc(PT_Nodelen = len);
  832.         }
  833.         ptr = PT_Nodebuf;
  834.  
  835.         /* read in the whole chunk */
  836.         if ((j = read(aptr->fd_idx, PT_Nodebuf, len)) != len)
  837.             iostat = IOIDXREAD;
  838.  
  839.         PT_swapper(ptr, sizeof(WORD16));
  840.         memcpy((char *)&(kptr->nodebuff[lev].level), ptr, sizeof(WORD16));
  841.         ptr += sizeof(WORD16);
  842.  
  843.         PT_swapper(ptr, sizeof(WORD16));
  844.         memcpy((char *)&(kptr->nodebuff[lev].num_used), ptr, sizeof(WORD16));
  845.         ptr += sizeof(WORD16);
  846.  
  847.         for (i = 0; i < aptr->maxelts; i++)
  848.         {
  849.             PT_swapper(ptr, sizeof(WORD32));
  850.             memcpy((char *)&(kptr->nodebuff[lev].elt[i].offset), ptr,
  851.               sizeof(WORD32));
  852.             ptr += sizeof(WORD32);
  853.  
  854.             ptr2 = ptr;
  855.             for (j = 0; j < kptr->k_segs; j++)
  856.             {
  857.                 switch (kptr->sd[j].s_vtyp)
  858.                 {
  859.                 case INTTYP:   /* two byte integer */
  860.                 case LNGTYP:   /* four byte integer */
  861.                 case FLTTYP:   /* single precision FP number (usually 4 long) */
  862.                 case DBLTYP:   /* double precision FP number (usually 8 long) */
  863.                     PT_swapper(ptr, kptr->sd[j].s_leng);
  864.                     break;
  865.                 }
  866.                 ptr += kptr->sd[j].s_leng;
  867.             }
  868.             if (kptr->k_type == KEY_DUPLICATE)
  869.             {
  870.                 PT_swapper(ptr, kptr->sd[DUPSEG].s_leng);
  871.                 ptr += kptr->sd[DUPSEG].s_leng;
  872.             }
  873.             memcpy(kptr->nodebuff[lev].elt[i].keyval, ptr2, kptr->k_leng);
  874.         }
  875.  
  876.         if (lev > 0)
  877.             kptr->c_elt[lev - 1] = elt;
  878.         kptr->c_elt[lev] = aptr->maxelts + 1;
  879.     }
  880.  
  881.     return(iostat);
  882. }
  883.  
  884.  
  885. /*************************************************************************
  886. *  performs lseek and writes an index node to the file by record offset  *
  887. *************************************************************************/
  888. int
  889. PT_writeidx(fd_sys, lev)
  890.     int fd_sys;
  891.     int lev;
  892. {
  893.     FDDEF *fptr = &fd[fd_sys];
  894.     AFDDEF *aptr = &PT_fd[fd_sys];
  895.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  896.     int i, j;
  897.     char *ptr;
  898.     int iostat = IOGOOD;
  899.     int len;
  900.  
  901.     if (lev < 0 || lev > kptr->k_levs)
  902.         abort_mess("\rDIAG: writeidx( lev=%d ) [0..%d]\r\n", lev, kptr->k_levs);
  903.  
  904.     if (kptr->nodeoffset[lev] == PTNOPTR)
  905.     {
  906.         /* try to re-cycle an old node */
  907.         if ((kptr->nodeoffset[lev] = PT_keyreuse(fd_sys)) == PTNOPTR)
  908.         {
  909.             /* nothing to re-cycle ... carve out a new one */
  910.             kptr->nodeoffset[lev] = lseek(PT_fd[fd_sys].fd_idx, 0L, FDIR_EOF);
  911.             if (kptr->nodeoffset[lev] < 0L)
  912.                 iostat = IOIDXSEEK;
  913.  
  914.             /* grab the spot 'cause it may get shared otherwise */
  915.             kptr->changes[lev] = FLUSH_LEVEL;
  916.         }
  917.         else
  918.             kptr->changes[lev] = 0;
  919.     }
  920.  
  921.     if (++kptr->changes[lev] < FLUSH_LEVEL)
  922.         return(iostat);
  923.  
  924.     if (iostat == IOGOOD &&
  925.       lseek(aptr->fd_idx, kptr->nodeoffset[lev], FDIR_BEGIN) !=
  926.       kptr->nodeoffset[lev])
  927.         iostat = IOIDXSEEK;
  928.  
  929.     else if (iostat == IOGOOD)
  930.     {
  931.         /* resize the node buffer if need be */
  932.         len =  sizeof(WORD16) * 2;
  933.         len += aptr->maxelts * (sizeof(WORD32) + kptr->k_leng);
  934.  
  935.         if (len > PT_Nodelen)
  936.         {
  937.             if (PT_Nodelen > 0)
  938.                 free(PT_Nodebuf);
  939.             PT_Nodebuf = alloc(PT_Nodelen = len);
  940.         }
  941.         ptr = PT_Nodebuf;
  942.  
  943.         memcpy(ptr, (char *)&(kptr->nodebuff[lev].level), sizeof(WORD16));
  944.         PT_swapper(ptr, sizeof(WORD16));
  945.         ptr += sizeof(WORD16);
  946.  
  947.         memcpy(ptr, (char *)&(kptr->nodebuff[lev].num_used), sizeof(WORD16));
  948.         PT_swapper(ptr, sizeof(WORD16));
  949.         ptr += sizeof(WORD16);
  950.  
  951.         for (i = 0; i < aptr->maxelts; i++)
  952.         {
  953.             memcpy(ptr, (char *)&(kptr->nodebuff[lev].elt[i].offset),
  954.               sizeof(WORD32));
  955.             PT_swapper(ptr, sizeof(WORD32));
  956.             ptr += sizeof(WORD32);
  957.  
  958.             if (!kptr->nodebuff[lev].elt[i].keyval)
  959.             {
  960.                 memset(ptr, 0, kptr->k_leng);
  961.                 continue;
  962.             }
  963.  
  964.             memcpy(ptr, kptr->nodebuff[lev].elt[i].keyval, kptr->k_leng);
  965.             for (j = 0; j < kptr->k_segs; j++)
  966.             {
  967.                 switch (kptr->sd[j].s_vtyp)
  968.                 {
  969.                 case INTTYP:   /* two byte integer */
  970.                 case LNGTYP:   /* four byte integer */
  971.                 case FLTTYP:   /* single precision FP number (usually 4 long) */
  972.                 case DBLTYP:   /* double precision FP number (usually 8 long) */
  973.                     PT_swapper(ptr, kptr->sd[j].s_leng);
  974.                     break;
  975.                 }
  976.                 ptr += kptr->sd[j].s_leng;
  977.             }
  978.             if (kptr->k_type == KEY_DUPLICATE)
  979.             {
  980.                 PT_swapper(ptr, kptr->sd[DUPSEG].s_leng);
  981.                 ptr += kptr->sd[DUPSEG].s_leng;
  982.             }
  983.         }
  984.  
  985.         if (write(aptr->fd_idx, PT_Nodebuf, len) != len)
  986.             iostat = IOIDXWRITE;
  987.     }
  988.  
  989.     kptr->changes[lev] = 0;
  990.     if (kptr->c_elt[lev] < 0)
  991.         kptr->c_elt[lev] = aptr->maxelts + 1;
  992.  
  993.     return(iostat);
  994. }
  995.  
  996.  
  997. #ifndef INCREMENTAL_DUP_VALUES
  998. /****************************************************************
  999. *  set up a key whose last segment contains the next available  *
  1000. *  suffix in the sequence for exact match to the target key     *
  1001. ****************************************************************/
  1002. int
  1003. PT_new_dup(fd_sys, keyval)
  1004.     int fd_sys;
  1005.     char *keyval;
  1006. {
  1007.     FDDEF *fptr = &fd[fd_sys];
  1008.     AFDDEF *aptr = &PT_fd[fd_sys];
  1009.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1010.     WORD32 dupnum;
  1011.     int iostat = IOGOOD;
  1012.  
  1013.     dupnum = aptr->doffset;
  1014.     memcpy(keyval + kptr->sd[DUPSEG].s_keystart, (char *)&dupnum,
  1015.       kptr->sd[DUPSEG].s_leng);
  1016.  
  1017.     return(iostat);
  1018. }
  1019. #endif
  1020.  
  1021.  
  1022. #ifdef INCREMENTAL_DUP_VALUES
  1023. /****************************************************************
  1024. *  set up a key whose last segment contains the next available  *
  1025. *  suffix in the sequence for exact match to the target key     *
  1026. ****************************************************************/
  1027. int
  1028. PT_new_dup(fd_sys, keyval)
  1029.     int fd_sys;
  1030.     char *keyval;
  1031. {
  1032.     AFDDEF *aptr = &PT_fd[fd_sys];
  1033.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1034.     char *tmpkey;
  1035.     WORD32 dupnum;
  1036.     int lev, elt, iostat = IOGOOD;
  1037.  
  1038.     /* prepare a key with the highest possible duplicate segment */
  1039.     tmpkey = alloc(kptr->k_leng);
  1040.     memcpy(tmpkey, keyval, kptr->k_leng);
  1041.     dupnum = 0x7fffffff;
  1042.     memcpy(tmpkey + kptr->sd[DUPSEG].s_keystart, (char *)&dupnum,
  1043.       kptr->sd[DUPSEG].s_leng);
  1044.  
  1045.     dupnum = 0L;
  1046.  
  1047.     if (PT_gteq_key(fd_sys, tmpkey, TRUE) != PTNOPTR)
  1048.         iostat = IONOKEY;
  1049.     else if (PT_prev_key(fd_sys) != PTNOPTR)
  1050.     {
  1051.         lev = kptr->nodebuff[0].level;
  1052.         elt = kptr->c_elt[lev];
  1053.         if (!PT_keycmp(fd_sys, keyval, kptr->nodebuff[lev].elt[elt].keyval,
  1054.           KEY_UNIQUE))
  1055.             memcpy((char *)&dupnum, kptr->nodebuff[lev].elt[elt].keyval +
  1056.               kptr->sd[DUPSEG].s_keystart, kptr->sd[DUPSEG].s_leng);
  1057.     }
  1058.  
  1059.     dupnum++;
  1060.     memcpy(keyval + kptr->sd[DUPSEG].s_keystart, (char *)&dupnum,
  1061.       kptr->sd[DUPSEG].s_leng);
  1062.  
  1063.     free(tmpkey);
  1064.  
  1065.     return(iostat);
  1066. }
  1067. #endif
  1068.  
  1069.  
  1070. /************************************************************************
  1071. *  Primary function for adding new key to a B-tree index.  Keys larger  *
  1072. *  or smaller than any on file are trapped for special handling,        *
  1073. *  otherwise falls through to normal keyadd function                    *
  1074. ************************************************************************/
  1075. int
  1076. PT_add_key(fd_sys, keyval)
  1077.     int fd_sys;
  1078.     char *keyval;
  1079. {
  1080.     FDDEF *fptr = &fd[fd_sys];
  1081.     AFDDEF *aptr = &PT_fd[fd_sys];
  1082.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1083.     int n, lev, iostat = IOGOOD;
  1084.     char *kval;
  1085.  
  1086.     kval = alloc(kptr->k_leng);
  1087.     memcpy(kval, keyval, kptr->k_leng);
  1088.  
  1089.     if (PT_gteq_key(fd_sys, kval, TRUE) != PTNOPTR)
  1090.         iostat = IODUP;
  1091.     else
  1092.     {
  1093.         lev = kptr->nodebuff[0].level;
  1094.  
  1095.         /* empty tree case */
  1096.         if (!lev && !kptr->nodebuff[0].num_used)
  1097.             kptr->c_elt[0] = 0;
  1098.  
  1099.         n = kptr->nodebuff[lev].level;
  1100.         if (n < 0 || n >= kptr->k_levs)
  1101.             abort_mess("\rDIAG: add_key( level[%d]=%d ) [0..%d]\r\n",
  1102.               lev, kptr->nodebuff[lev].level, kptr->k_levs);
  1103.         iostat = PT_add_elt(fd_sys, lev, aptr->doffset, kval);
  1104.         lev = kptr->nodebuff[n].level;
  1105.     }
  1106.  
  1107.     /* inform ancestors of maximum keys */
  1108.     while (iostat == IOGOOD && lev > 0)
  1109.     {
  1110.         if (kptr->c_elt[lev] + 1 == kptr->nodebuff[lev].num_used)
  1111.         {
  1112.             lev--;
  1113.             memcpy(kptr->nodebuff[lev].elt[kptr->c_elt[lev]].keyval, kval,
  1114.               kptr->k_leng);
  1115.             iostat = PT_writeidx(fd_sys, lev);
  1116.         }
  1117.         else
  1118.             break;
  1119.     }
  1120.  
  1121.     free(kval);
  1122.  
  1123.     return(iostat);
  1124. }
  1125.  
  1126.  
  1127. int
  1128. PT_add_elt(fd_sys, lev, offset, keyval)
  1129.     int fd_sys;
  1130.     int lev;
  1131.     long offset;
  1132.     char *keyval;
  1133. {
  1134.     FDDEF *fptr = &fd[fd_sys];
  1135.     AFDDEF *aptr = &PT_fd[fd_sys];
  1136.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1137.     BNODE *node;
  1138.     char *kval;
  1139.     int elt, i, iostat = IOGOOD;
  1140.  
  1141.     kval = alloc(kptr->k_leng);
  1142.     memcpy(kval, keyval, kptr->k_leng);
  1143.  
  1144.     if (lev < 0)
  1145.         abort_mess("\rDIAG: add_elt( lev=%d )\r\n", lev);
  1146.  
  1147.     elt = kptr->c_elt[lev];
  1148.     if (elt < 0 || elt > aptr->maxelts)
  1149.         abort_mess("\rDIAG: add_elt( c_elt[%d]=%d ) [0..%d]\r\n", lev, elt,
  1150.           aptr->maxelts);
  1151.  
  1152.     if (kptr->nodebuff[lev].num_used < 0)
  1153.         abort_mess("\rDIAG: add_elt( num_used[%d]=%d )\r\n", lev,
  1154.           kptr->nodebuff[lev].num_used);
  1155.     else if (kptr->nodebuff[lev].num_used == aptr->maxelts)
  1156.         iostat = PT_add_node(fd_sys, lev, offset, kval);
  1157.     else
  1158.     {
  1159.         /* higher elts up by one */
  1160.         node = &(kptr->nodebuff[lev]);
  1161.         for (i = node->num_used; i > elt; i--)
  1162.             PT_cpyelt(&(node->elt[i]), &(node->elt[i - 1]), kptr->k_leng);
  1163.         node->elt[elt].offset = offset;
  1164.         memcpy(node->elt[elt].keyval, kval, kptr->k_leng);
  1165.         node->num_used++;
  1166.  
  1167.         iostat = PT_writeidx(fd_sys, lev);
  1168.     }
  1169.  
  1170.     free(kval);
  1171.  
  1172.     return(iostat);
  1173. }
  1174.  
  1175.  
  1176. /*****************************************************************************
  1177. * - add a new btree node to the index file
  1178. * - toffset will contain the offset of the new node in the index file, and
  1179. *   this value is used on return to become the offset in its parent element
  1180. ******************************************************************************/
  1181. int
  1182. PT_add_node(fd_sys, lev, offset, keyval)
  1183.     int fd_sys;
  1184.     int lev;
  1185.     long offset;
  1186.     char *keyval;
  1187. {
  1188.     FDDEF *fptr = &fd[fd_sys];
  1189.     AFDDEF *aptr = &PT_fd[fd_sys];
  1190.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1191.     KINFO *ktmp;
  1192.     BNODE  *node_c, *node_t;
  1193.     int n, i, where, left, right, iostat = IOGOOD;
  1194.     long ltmp;
  1195.     char *kval;
  1196.  
  1197.     kval = alloc(kptr->k_leng);
  1198.     memcpy(kval, keyval, kptr->k_leng);
  1199.  
  1200.     if (kptr->nodebuff[lev].num_used != aptr->maxelts)
  1201.         abort_mess(
  1202.           "\rDIAG: add_node( num_used[%d]=%d ) [0..%d] split unneeded\r\n",
  1203.           lev, kptr->nodebuff[lev].num_used, aptr->maxelts);
  1204.  
  1205.     if (kptr->c_elt[lev] > aptr->maxelts)
  1206.         abort_mess("\rDIAG: add_node( c_elt[%d]=%d ) node marked unused\r\n",
  1207.           lev, kptr->c_elt[lev]);
  1208.  
  1209.     /* make sure we are not orphans here */
  1210.     if (lev == 0)
  1211.     {
  1212.         iostat = PT_resize(fd_sys, kptr, kptr->nodebuff[0].level + 2);
  1213.         lev++;
  1214.     }
  1215.  
  1216.     where = 0;
  1217.     for (i = lev; i >= 0; i--)
  1218.     {
  1219.         if (kptr->c_elt[i] < 0)
  1220.         {
  1221.             where = 0;
  1222.             break;
  1223.         }
  1224.         else if (kptr->c_elt[i] == 0 && where != 1)
  1225.             where = 2;
  1226.         else
  1227.         {
  1228.             n = kptr->nodebuff[i].num_used - 1;
  1229.             if (kptr->c_elt[i] + 1 >= kptr->nodebuff[i].num_used &&
  1230.               where != 2 && PT_keycmp(fd_sys, kval,
  1231.               kptr->nodebuff[i].elt[n].keyval, kptr->k_type) > 0)
  1232.                 where = 1;
  1233.             else
  1234.             {
  1235.                 where = 3;
  1236.                 break;
  1237.             }
  1238.         }
  1239.     }
  1240.  
  1241.     if (where == 1)
  1242.     {
  1243.         /* empty the node and save it as a new one */
  1244.         iostat = PT_flush_node(fd_sys, lev);
  1245.         PT_zeronode(fd_sys, &(kptr->nodebuff[lev]));
  1246.         kptr->nodeoffset[lev] = PTNOPTR;
  1247.         kptr->c_elt[lev] = 0;
  1248.         iostat = PT_add_elt(fd_sys, lev, offset, kval);
  1249.  
  1250.         /* add new element to the level above */
  1251.         if (lev > 0)
  1252.             kptr->c_elt[lev - 1]++;
  1253.         n = kptr->nodebuff[lev].level;
  1254.         iostat = PT_add_elt(fd_sys, lev - 1, kptr->nodeoffset[lev], kval);
  1255.         lev = kptr->nodebuff[n].level;
  1256.     }
  1257.     else if (where == 2)
  1258.     {
  1259.         /* empty the node and save it as a new one */
  1260.         iostat = PT_flush_node(fd_sys, lev);
  1261.         PT_zeronode(fd_sys, &(kptr->nodebuff[lev]));
  1262.         kptr->nodeoffset[lev] = PTNOPTR;
  1263.         kptr->c_elt[lev] = 0;
  1264.         iostat = PT_add_elt(fd_sys, lev, offset, kval);
  1265.  
  1266.         /* add new element to the level above */
  1267.         n = kptr->nodebuff[lev].level;
  1268.         iostat = PT_add_elt(fd_sys, lev - 1, kptr->nodeoffset[lev], kval);
  1269.         lev = kptr->nodebuff[n].level;
  1270.     }
  1271.     else if (where == 3)
  1272.     {
  1273.         right = (left = kptr->nodebuff[lev].num_used) / 2;
  1274.         left -= right;
  1275.  
  1276.         if (kptr->c_elt[lev] < left && left > right)
  1277.             left--, right++;
  1278.  
  1279.         /* save the old arrays and their contents */
  1280.         ktmp = (KINFO *)alloc(sizeof(KINFO));
  1281.         ktmp->k_leng  = kptr->k_leng;
  1282.         ktmp->k_type  = kptr->k_type;
  1283.         ktmp->k_segs  = kptr->k_segs;
  1284.         for (i = 0; i <= MAXSEGS; i++)
  1285.             ktmp->sd[i] = kptr->sd[i];
  1286.         PT_makenodes(fd_sys, ktmp, 1);
  1287.         PT_zeronode(fd_sys, &(ktmp->nodebuff[0]));
  1288.  
  1289.         node_t = &(ktmp->nodebuff[0]);
  1290.         node_c = &(kptr->nodebuff[lev]);
  1291.  
  1292.         if (kptr->c_elt[lev] < left || (kptr->c_elt[lev] == left &&
  1293.           left < right))
  1294.         {
  1295.             /* save away the left half of the node and offset */
  1296.             for (i = 0; i < left; i++)
  1297.                 PT_cpyelt(&(node_t->elt[i]), &(node_c->elt[i]), kptr->k_leng);
  1298.  
  1299.             /* shuffle the right half to the top */
  1300.             for (i = 0; i < aptr->maxelts; i++)
  1301.             {
  1302.                 if (i < right)
  1303.                     PT_cpyelt(&(node_c->elt[i]), &(node_c->elt[i + left]),
  1304.                       kptr->k_leng);
  1305.                 else
  1306.                     PT_zeroelt(fd_sys, &(node_c->elt[i]));
  1307.             }
  1308.             kptr->nodebuff[lev].num_used = right;
  1309.  
  1310.             /* write out the right node to disk */
  1311.             iostat = PT_writeidx(fd_sys, lev);
  1312.             iostat = PT_flush_node(fd_sys, lev);
  1313.  
  1314.             /* ... and the left node makes the tag ... */
  1315.             for (i = 0; i < left || i < right; i++)
  1316.             {
  1317.                 if (i < left)
  1318.                     PT_cpyelt(&(node_c->elt[i]), &(node_t->elt[i]), kptr->k_leng);
  1319.                 else
  1320.                     PT_zeroelt(fd_sys, &(node_c->elt[i]));
  1321.             }
  1322.             kptr->nodebuff[lev].num_used = left;
  1323.             kptr->nodeoffset[lev] = PTNOPTR;
  1324.             iostat = PT_add_elt(fd_sys, lev, offset, kval);
  1325.  
  1326.             /* pappa's got a baby boy! */
  1327.             n = kptr->nodebuff[lev].level;
  1328.             iostat = PT_add_elt(fd_sys, lev - 1, kptr->nodeoffset[lev],
  1329.               node_c->elt[node_c->num_used - 1].keyval);
  1330.             lev = kptr->nodebuff[n].level;
  1331.         }
  1332.         else
  1333.         {
  1334.             /* save away the right half of the node and offset */
  1335.             for (i = 0; i < aptr->maxelts; i++)
  1336.             {
  1337.                 if (i < right)
  1338.                     PT_cpyelt(&(node_t->elt[i]), &(node_c->elt[i + left]),
  1339.                       kptr->k_leng);
  1340.                 if (i >= left)
  1341.                     PT_zeroelt(fd_sys, &(node_c->elt[i]));
  1342.             }
  1343.             kptr->nodebuff[lev].num_used = left;
  1344.  
  1345.             /* flush the new left node to disk */
  1346.             ltmp = kptr->nodeoffset[lev];
  1347.             kptr->nodeoffset[lev] = PTNOPTR;
  1348.             iostat = PT_writeidx(fd_sys, lev);
  1349.             iostat = PT_flush_node(fd_sys, lev);
  1350.  
  1351.             /* pappa's got a baby boy! */
  1352.             n = kptr->nodebuff[lev].level;
  1353.             iostat = PT_add_elt(fd_sys, lev - 1, kptr->nodeoffset[lev],
  1354.               node_c->elt[left - 1].keyval);
  1355.             lev = kptr->nodebuff[n].level;
  1356.  
  1357.             /* do this in case level has changed */
  1358.             node_c = &(kptr->nodebuff[lev]);
  1359.  
  1360.             /* ... and the right node makes the tag ... */
  1361.             for (i = 0; i < left || i < right; i++)
  1362.             {
  1363.                 if (i < right)
  1364.                     PT_cpyelt(&(node_c->elt[i]), &(node_t->elt[i]), kptr->k_leng);
  1365.                 else
  1366.                     PT_zeroelt(fd_sys, &(node_c->elt[i]));
  1367.             }
  1368.             kptr->nodeoffset[lev] = ltmp;
  1369.             kptr->c_elt[lev - 1]++;
  1370.             kptr->nodebuff[lev].num_used = right;
  1371.             kptr->c_elt[lev] -= left;
  1372.             iostat = PT_add_elt(fd_sys, lev, offset, kval);
  1373.         }
  1374.  
  1375.         PT_freenodes(fd_sys, ktmp);
  1376.         free(ktmp);
  1377.     }
  1378.  
  1379.     free(kval);
  1380.  
  1381.     return(iostat);
  1382. }
  1383.  
  1384.  
  1385. /*****************************************************************************
  1386.  * - locate the element and empty it, adjusting node if needed
  1387.  * - in the case of duplicate keys, the data record offset value
  1388.  *   (fptr->offset at leaf level) is compared to the value in the index
  1389.  *   element, and must match to indicate that the correct duplicate key
  1390.  *   occurrence is the one removed from the index
  1391.  */
  1392. int
  1393. PT_del_key(fd_sys, keyval)
  1394.     int fd_sys;
  1395.     char *keyval;
  1396. {
  1397.     FDDEF *fptr = &fd[fd_sys];
  1398.     AFDDEF *aptr = &PT_fd[fd_sys];
  1399.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1400.     int iostat;
  1401.  
  1402.     if (kptr->keyval && PT_gteq_key(fd_sys, kptr->keyval, TRUE) == PTNOPTR)
  1403.         iostat = IONOKEY;
  1404.     else
  1405.         iostat = PT_del_elt(fd_sys, kptr->nodebuff[0].level);
  1406.  
  1407.     return(iostat);
  1408. }
  1409.  
  1410. /*****************************************************************************
  1411.  * - blank out element to be removed from index and adjust nodes
  1412.  * - if the element to be deleted will create an empty node, its
  1413.  *   offset is assigned to another element in the parent node if possible,
  1414.  *   to avoid having the index contain too many unreachable nodes
  1415.  * - if removed element was a link to the leaf level, the highest key element
  1416.  *   remaining in the leaf node is promoted to become the new link
  1417.  */
  1418. int
  1419. PT_del_elt(fd_sys, lev)
  1420.     int fd_sys;
  1421.     int lev;
  1422. {
  1423.     FDDEF *fptr = &fd[fd_sys];
  1424.     AFDDEF *aptr = &PT_fd[fd_sys];
  1425.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1426.     BNODE  *node = &(kptr->nodebuff[lev]);
  1427.     int iostat, i;
  1428.     char *keyval;
  1429.  
  1430.     if (node->num_used <= 0)
  1431.         abort_mess("\rDIAG: del_elt( num_used[%d]=%d )\r\n", lev,
  1432.           node->num_used);
  1433.     else if (lev > 0 && node->num_used == 1)
  1434.         iostat = PT_del_node(fd_sys, lev);
  1435.     else
  1436.     {
  1437.         /* higher elts down by one */
  1438.         node = &(kptr->nodebuff[lev]);
  1439.         for (i = kptr->c_elt[lev] + 1; i < node->num_used; i++)
  1440.             PT_cpyelt(&(node->elt[i - 1]), &(node->elt[i]), kptr->k_leng);
  1441.         PT_zeroelt(fd_sys, &(node->elt[node->num_used - 1]));
  1442.         node->num_used--;
  1443.         iostat = PT_writeidx(fd_sys, lev);
  1444.  
  1445.         if (kptr->c_elt[lev] > 0)
  1446.         {
  1447.             keyval = node->elt[--kptr->c_elt[lev]].keyval;
  1448.             while (iostat == IOGOOD && lev > 0 &&
  1449.               kptr->c_elt[lev] + 1 == kptr->nodebuff[lev].num_used)
  1450.             {
  1451.                 lev--;
  1452.                 memcpy(kptr->nodebuff[lev].elt[kptr->c_elt[lev]].keyval,
  1453.                   keyval, kptr->k_leng);
  1454.                 iostat = PT_writeidx(fd_sys, lev);
  1455.             }
  1456.         }
  1457.  
  1458.         while (iostat == IOGOOD && !lev && kptr->nodebuff[0].num_used == 1)
  1459.         {
  1460.             if (kptr->nodebuff[0].level <= 0)
  1461.                 break;
  1462.             else if (PT_first_key(fd_sys) != PTNOPTR)
  1463.                 iostat = PT_resize(fd_sys, kptr, kptr->nodebuff[0].level);
  1464.             else
  1465.                 iostat = IOERROR;
  1466.         }
  1467.     }
  1468.  
  1469.     return(iostat);
  1470. }
  1471.  
  1472.  
  1473. int
  1474. PT_del_node(fd_sys, lev)
  1475.     int fd_sys;
  1476.     int lev;
  1477. {
  1478.     FDDEF *fptr = &fd[fd_sys];
  1479.     AFDDEF *aptr = &PT_fd[fd_sys];
  1480.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1481.     int iostat = IOGOOD;
  1482.  
  1483.     if (lev < 0)
  1484.         abort_mess("\rDIAG: del_node( lev=%d )\r\n", lev);
  1485.     else if (lev > 0)
  1486.     {
  1487.         iostat = PT_keyrecycle(fd_sys, kptr->nodeoffset[lev]);
  1488.  
  1489.         PT_zeronode(fd_sys, &(kptr->nodebuff[lev]));
  1490.         kptr->nodebuff[lev].level    = -211;
  1491.         kptr->nodebuff[lev].num_used = -212;
  1492.         kptr->c_elt[lev]             = -213;
  1493.         kptr->nodeoffset[lev]        = PTNOPTR;
  1494.  
  1495.         if (iostat == IOGOOD)
  1496.             iostat = PT_del_elt(fd_sys, lev - 1);
  1497.     }
  1498.  
  1499.     return(iostat);
  1500. }
  1501.  
  1502.  
  1503. /***************************************************************************
  1504. *                  New B-tree indexing functions for IO8.C                  *
  1505. ****************************************************************************
  1506. *
  1507. *   Terminology:
  1508. *
  1509. *   node:            an array of MAXELTS index key elements
  1510. *   element:         an element in node containing one key (divided into
  1511. *                  segments), and record offset (if leaf node), or node
  1512. *                  offset (otherwise)
  1513. *   record offset:   byte offset from origin in data file of a record
  1514. *   node offset:   byte offset in index file of child node to the element
  1515. *
  1516. *   level 1:   the root node of the index tree, containing MAXELTS elements
  1517. *            each with a cnode_offset pointer to a level 2 node
  1518. *   level 2:   middle level nodes, each containing MAXELTS elements in turn,
  1519. *            each with a cnode_offset pointer to a level 3 node
  1520. *   level 3:   bottom level nodes, each containing MAXELTS elements, each
  1521. *            with the record offset (no further levels)
  1522. *
  1523. *   The capacity of the index tree is MAXELTS * MAXELTS * MAXELTS keys;
  1524. *   however, there will usually be vacant elements in each node, so that the
  1525. *   practical capacity might be about half of this.
  1526. *
  1527. *   The tree is filled from the bottom up, with elements being placed in the
  1528. *   root or middle nodes only when they are first created, or when a node
  1529. *   on the next lower level is split:  this attains a certain degree of self-
  1530. *   adjustment while keeping the number of activated nodes in the index as
  1531. *   low as possible.
  1532. *
  1533. *   For keys added in random order (that is, neither higher nor lower than
  1534. *   all others already on file), bottom and mid level nodes are split when
  1535. *   they become full, and the new key added to the newly adjusted tree.
  1536. *
  1537. *   If the new key is greater than any other already in the index, as happens
  1538. *   with auto-incrementing numerical keys, it will replace the former maximum
  1539. *   key in its rootnode position, and at levels further down; however,
  1540. *   when lower nodes are filled they are not split, rather, the element is
  1541. *   added at the end of the next level up, ensuring that the lower nodes are
  1542. *   completely filled before using up higher levels.
  1543. *
  1544. *   If the new key is smaller than any other already in the index, it will
  1545. *   always go to a child node if possible; if a lower level is filled, the
  1546. *   new minimum key will be added to the beginning of the next node up and to
  1547. *   the child nodes created from it, rather than split the lower node.
  1548. *
  1549. ***************************************************************************/
  1550.  
  1551.  
  1552. /**************************************************
  1553. *  locates the node element which is equal to or  *
  1554. *  greater than the key  --  returns -1, 0, 1     *
  1555. **************************************************/
  1556. int
  1557. PT_find_match(fd_sys, keyval, t_node, nodepos)
  1558.     int fd_sys;
  1559.     char *keyval;
  1560.     BNODE *t_node;
  1561.     int *nodepos;
  1562. {
  1563.     int hi, lo, mid, cmp;
  1564.     FDDEF *fptr = &fd[fd_sys];
  1565.     AFDDEF *aptr = &PT_fd[fd_sys];
  1566.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1567.     int type = kptr->k_type;
  1568.  
  1569.     lo = 0;
  1570.     hi = t_node->num_used;
  1571.  
  1572.     /* usual case - more than one key in node */
  1573.     while (hi - lo > 1)
  1574.     {
  1575.         mid = (hi + lo) / 2;
  1576.         cmp = PT_keycmp(fd_sys, keyval, t_node->elt[mid].keyval, type);
  1577.         if (cmp > 0)
  1578.             lo = mid;
  1579.         else if (cmp < 0)
  1580.             hi = mid;
  1581.         else
  1582.             lo = hi = mid;
  1583.     }
  1584.  
  1585.     cmp = PT_keycmp(fd_sys, keyval, t_node->elt[lo].keyval, type);
  1586.     *nodepos = (cmp <= 0) ? lo : hi;
  1587.     if (*nodepos < t_node->num_used)
  1588.         cmp = PT_keycmp(fd_sys, keyval, t_node->elt[*nodepos].keyval, type);
  1589.     else
  1590.         cmp = 1; /* greater than */
  1591.  
  1592.     return(cmp);
  1593. }
  1594.  
  1595.  
  1596. /*****************************************************************
  1597. *  compare two keys dependent on their type -- returns -1, 0, 1  *
  1598. *****************************************************************/
  1599. int
  1600. PT_keycmp(fd_sys, keyval1, keyval2, mode)
  1601.     int fd_sys;
  1602.     char *keyval1;
  1603.     char *keyval2;
  1604.     int mode;
  1605. {
  1606.     FDDEF *fptr = &fd[fd_sys];
  1607.     AFDDEF *aptr = &PT_fd[fd_sys];
  1608.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1609.     WORD16 b2_1, b2_2;
  1610.     WORD32 b4_1, b4_2;
  1611.     FLOAT32 ftmp1, ftmp2;
  1612.     FLOAT64 dtmp1, dtmp2;
  1613.     WORD32 dupnum1, dupnum2;
  1614.     int i, iostat;
  1615.  
  1616.     /* for each segment */
  1617.     for (iostat = i = 0; !iostat && i < kptr->k_segs; i++)
  1618.     {
  1619.         /* compare the segments according to type */
  1620.         switch (kptr->sd[i].s_vtyp)
  1621.         {
  1622.             case CHRTYP    :
  1623.             case LOGTYP    :
  1624.             case MEMTYP    :
  1625.             case DATTYP    :
  1626.                 iostat = memcmp(keyval1 + kptr->sd[i].s_keystart,
  1627.                   keyval2 + kptr->sd[i].s_keystart, kptr->sd[i].s_leng);
  1628.                 break;
  1629.  
  1630.             case INTTYP:   /* two byte integer */
  1631.             case LNGTYP:   /* four byte integer */
  1632.                 if (kptr->sd[i].s_leng == 2)
  1633.                 {
  1634.                     memcpy((char *)&b2_1, keyval1 + kptr->sd[i].s_keystart,
  1635.                       sizeof(b2_1));
  1636.                     memcpy((char *)&b2_2, keyval2 + kptr->sd[i].s_keystart,
  1637.                       sizeof(b2_2));
  1638.                     b4_1 = b2_1;
  1639.                     b4_2 = b2_2;
  1640.                 }
  1641.                 else
  1642.                 {
  1643.                     memcpy((char *)&b4_1, (char *)(keyval1 + kptr->sd[i].s_keystart),
  1644.                       sizeof(b4_1));
  1645.                     memcpy((char *)&b4_2, (char *)(keyval2 + kptr->sd[i].s_keystart),
  1646.                       sizeof(b4_2));
  1647.                 }
  1648.                 if (b4_1 < b4_2)
  1649.                     iostat = -1;
  1650.                 else if (b4_1 > b4_2)
  1651.                     iostat = 1;
  1652.                 break;
  1653.  
  1654.             case FLTTYP:   /* single precision FP number (usually 4 long) */
  1655.                 memcpy((char *)&ftmp1, keyval1 + kptr->sd[i].s_keystart,
  1656.                   sizeof(FLOAT32));
  1657.                 memcpy((char *)&ftmp2, keyval2 + kptr->sd[i].s_keystart,
  1658.                   sizeof(FLOAT32));
  1659.                 dtmp1 = (FLOAT64) ftmp1;
  1660.                 dtmp2 = (FLOAT64) ftmp2;
  1661.                 /*FALLTHROUGH*/
  1662.  
  1663.             case DBLTYP:   /* double precision FP number (usually 8 long) */
  1664.                 if (kptr->sd[i].s_vtyp == DBLTYP)
  1665.                 {
  1666.                     memcpy((char *)&dtmp1, keyval1 + kptr->sd[i].s_keystart,
  1667.                       sizeof(FLOAT64));
  1668.                     memcpy((char *)&dtmp2, keyval2 + kptr->sd[i].s_keystart,
  1669.                       sizeof(FLOAT64));
  1670.                 }
  1671.                 if (dtmp1 < dtmp2)
  1672.                     iostat = -1;
  1673.                 else if (dtmp1 > dtmp2)
  1674.                     iostat = 1;
  1675.                 break;
  1676.         }
  1677.     }
  1678.  
  1679.     /* check the dup suffix for a DUPLICATE key */
  1680.     if (!iostat && mode == KEY_DUPLICATE)
  1681.     {
  1682.         /* compare the segments according to type */
  1683.         memcpy((char *)&dupnum1, keyval1 + kptr->sd[DUPSEG].s_keystart,
  1684.           kptr->sd[DUPSEG].s_leng);
  1685.         memcpy((char *)&dupnum2, keyval2 + kptr->sd[DUPSEG].s_keystart,
  1686.           kptr->sd[DUPSEG].s_leng);
  1687.         if (dupnum1 < dupnum2)
  1688.             iostat = -1;
  1689.         else if (dupnum1 > dupnum2)
  1690.             iostat = 1;
  1691.     }
  1692.  
  1693.     return(iostat);
  1694. }
  1695.  
  1696.  
  1697. int
  1698. PT_flush_node(fd_sys, lev)
  1699.     int fd_sys;
  1700.     int lev;
  1701. {
  1702.     FDDEF *fptr = &fd[fd_sys];
  1703.     AFDDEF *aptr = &PT_fd[fd_sys];
  1704.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1705.     int iostat = IOGOOD;
  1706.  
  1707.     if (kptr->c_elt[lev] >= 0 && kptr->changes[lev])
  1708.     {
  1709.         kptr->changes[lev] = FLUSH_LEVEL;
  1710.         iostat = PT_writeidx(fd_sys, lev);
  1711.     }
  1712.  
  1713.     return(iostat);
  1714. }
  1715.  
  1716.  
  1717. int
  1718. PT_flush_cache(fd_sys)
  1719.     int fd_sys;
  1720. {
  1721.     FDDEF *fptr = &fd[fd_sys];
  1722.     AFDDEF *aptr = &PT_fd[fd_sys];
  1723.     int ck, lev, iostat;
  1724.  
  1725.     ck = fptr->cur_key;
  1726.  
  1727.     for (fptr->cur_key = 0; fptr->cur_key < fptr->key_cnt; fptr->cur_key++)
  1728.         for (lev = 0; lev < aptr->keyinfo[fptr->cur_key].k_levs; lev++)
  1729.             if ((iostat = PT_flush_node(fd_sys, lev)) != IOGOOD)
  1730.                 break;
  1731.  
  1732.     fptr->cur_key = ck;
  1733.  
  1734.     return(iostat);
  1735. }
  1736.  
  1737.  
  1738. /**********************************************************************
  1739. *  copies index node element structure members from oldelt to newelt  *
  1740. **********************************************************************/
  1741. void
  1742. PT_cpyelt(newelt, oldelt, keylen)
  1743.     BELT *newelt;
  1744.     BELT *oldelt;
  1745.     int keylen;
  1746. {
  1747.     newelt->offset = oldelt->offset;
  1748.     memcpy(newelt->keyval, oldelt->keyval, keylen);
  1749. }
  1750.  
  1751.  
  1752. void
  1753. PT_cpynode(fd_sys, node1, node2)
  1754.     int fd_sys;
  1755.     BNODE *node1;
  1756.     BNODE *node2;
  1757. {
  1758.     FDDEF *fptr = &fd[fd_sys];
  1759.     AFDDEF *aptr = &PT_fd[fd_sys];
  1760.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1761.     int i;
  1762.  
  1763.     node1->level = node2->level;
  1764.     node1->num_used = node2->num_used;
  1765.     for (i = 0; i < aptr->maxelts; i++)
  1766.         PT_cpyelt(&(node1->elt[i]), &(node2->elt[i]), kptr->k_leng);
  1767. }
  1768.  
  1769.  
  1770. /*********************************
  1771. *  fills an element with zeroes  *
  1772. *********************************/
  1773. void
  1774. PT_zeronode(fd_sys, nodeptr)
  1775.     int fd_sys;
  1776.     BNODE *nodeptr;
  1777. {
  1778.     AFDDEF *aptr = &PT_fd[fd_sys];
  1779.     int i;
  1780.  
  1781.     nodeptr->num_used = 0;
  1782.     for (i = 0; i < aptr->maxelts; i++)
  1783.         PT_zeroelt(fd_sys, &(nodeptr->elt[i]));
  1784. }
  1785.  
  1786.  
  1787. /*********************************
  1788. *  fills an element with zeroes  *
  1789. *********************************/
  1790. void
  1791. PT_zeroelt(fd_sys, eltp)
  1792.     int fd_sys;
  1793.     BELT *eltp;
  1794. {
  1795.     eltp->offset = 0L;
  1796.     memset(eltp->keyval, 0, PT_fd[fd_sys].keyinfo[fd[fd_sys].cur_key].k_leng);
  1797. }
  1798.  
  1799.  
  1800. /***********************************************************************
  1801. *  return data record offset of first logical record by current index  *
  1802. ***********************************************************************/
  1803. long
  1804. PT_first_key(fd_sys)
  1805.     int fd_sys;
  1806. {
  1807.     FDDEF *fptr = &fd[fd_sys];
  1808.     AFDDEF *aptr = &PT_fd[fd_sys];
  1809.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1810.     int lev;
  1811.     long offset;
  1812.  
  1813.     /* descend to leaf level on left side of btree */
  1814.     lev = -1;
  1815.     do
  1816.     {
  1817.         if (PT_readidx(fd_sys, ++lev, 0) != IOGOOD)
  1818.             offset = PTNOPTR;
  1819.         else if (kptr->nodebuff[lev].num_used <= 0)
  1820.             offset = PTNOPTR;
  1821.         else
  1822.         {
  1823.             kptr->c_elt[lev] = 0;
  1824.             offset = kptr->nodebuff[lev].elt[0].offset;
  1825.         }
  1826.     }
  1827.     while (offset != PTNOPTR && kptr->nodebuff[lev].level > 0);
  1828.  
  1829.     return(offset);
  1830. }
  1831.  
  1832.  
  1833. /**********************************************************************
  1834. *  return data record offset of last logical record by current index  *
  1835. **********************************************************************/
  1836. long
  1837. PT_last_key(fd_sys)
  1838.     int fd_sys;
  1839. {
  1840.     FDDEF *fptr = &fd[fd_sys];
  1841.     AFDDEF *aptr = &PT_fd[fd_sys];
  1842.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1843.     int lev, elt;
  1844.     long offset;
  1845.  
  1846.     /* descend to leaf level on right side of btree */
  1847.     elt = 0;
  1848.     lev = -1;
  1849.     do
  1850.     {
  1851.         if (PT_readidx(fd_sys, ++lev, elt - 1) != IOGOOD)
  1852.             offset = PTNOPTR;
  1853.         else if ((elt = kptr->nodebuff[lev].num_used) <= 0)
  1854.             offset = PTNOPTR;
  1855.         else
  1856.         {
  1857.             kptr->c_elt[lev] = elt - 1;
  1858.             offset = kptr->nodebuff[lev].elt[elt - 1].offset;
  1859.         }
  1860.     }
  1861.     while (offset != PTNOPTR && kptr->nodebuff[lev].level > 0);
  1862.  
  1863.     return(offset);
  1864. }
  1865.  
  1866.  
  1867. /**********************************************************************
  1868. *  return data record offset of next logical record by current index  *
  1869. **********************************************************************/
  1870. long
  1871. PT_next_key(fd_sys)
  1872.     int fd_sys;
  1873. {
  1874.     FDDEF *fptr = &fd[fd_sys];
  1875.     AFDDEF *aptr = &PT_fd[fd_sys];
  1876.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1877.     int lev, elt, iostat;
  1878.     long offset;
  1879.  
  1880.     /* climb the tree until there is a "backup" point */
  1881.     lev = kptr->nodebuff[0].level;
  1882.     elt = kptr->c_elt[lev];
  1883.     while (lev > 0 && elt + 1 >= kptr->nodebuff[lev].num_used)
  1884.         elt = kptr->c_elt[--lev];
  1885.  
  1886.     if (elt < 0 || elt + 1 >= kptr->nodebuff[lev].num_used)
  1887.         offset = PTNOPTR;
  1888.     else
  1889.     {
  1890.         /* backup and descend on the left-hand side */
  1891.         elt++;
  1892.         iostat = IOGOOD;
  1893.         while (kptr->nodebuff[lev].level > 0)
  1894.         {
  1895.             if ((iostat = PT_readidx(fd_sys, ++lev, elt)) != IOGOOD)
  1896.                 break;
  1897.             elt = 0;
  1898.         }
  1899.         if (iostat != IOGOOD || elt >= kptr->nodebuff[lev].num_used)
  1900.             offset = PTNOPTR;
  1901.         else
  1902.         {
  1903.             offset = kptr->nodebuff[lev].elt[elt].offset;
  1904.             kptr->c_elt[lev] = elt;
  1905.         }
  1906.     }
  1907.  
  1908.     return(offset);
  1909. }
  1910.  
  1911.  
  1912. /**************************************************************************
  1913. *  return data record offset of previous logical record by current index  *
  1914. **************************************************************************/
  1915. long
  1916. PT_prev_key(fd_sys)
  1917.     int fd_sys;
  1918. {
  1919.     FDDEF *fptr = &fd[fd_sys];
  1920.     AFDDEF *aptr = &PT_fd[fd_sys];
  1921.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1922.     int lev, elt, iostat;
  1923.     long offset;
  1924.  
  1925.     /* climb the tree until there is a "backup" point */
  1926.     lev = kptr->nodebuff[0].level;
  1927.     elt = kptr->c_elt[lev];
  1928.     while (lev > 0 && !elt)
  1929.         elt = kptr->c_elt[--lev];
  1930.  
  1931.     if (elt <= 0 || elt > kptr->nodebuff[lev].num_used)
  1932.         offset = PTNOPTR;
  1933.     else
  1934.     {
  1935.         /* backup and descend on the right-hand side */
  1936.         elt--;
  1937.         iostat = IOGOOD;
  1938.         while (kptr->nodebuff[lev].level > 0)
  1939.         {
  1940.             if ((iostat = PT_readidx(fd_sys, ++lev, elt)) != IOGOOD)
  1941.                 break;
  1942.             elt = kptr->nodebuff[lev].num_used - 1;
  1943.         }
  1944.         if (iostat != IOGOOD || elt < 0)
  1945.             offset = PTNOPTR;
  1946.         else
  1947.         {
  1948.             offset = kptr->nodebuff[lev].elt[elt].offset;
  1949.             kptr->c_elt[lev] = elt;
  1950.         }
  1951.     }
  1952.  
  1953.     return(offset);
  1954. }
  1955.  
  1956.  
  1957. /***************************************************************
  1958. *  return data record offset of first logical record matching  *
  1959. *  (or greater than) the given key, by current index           *
  1960. ***************************************************************/
  1961. long
  1962. PT_gteq_key(fd_sys, keyval, exact)
  1963.     int fd_sys;
  1964.     char *keyval;
  1965.     int exact;
  1966. {
  1967.     FDDEF *fptr = &fd[fd_sys];
  1968.     AFDDEF *aptr = &PT_fd[fd_sys];
  1969.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  1970.     int lev, elt = 0, cmp;
  1971.     long offset;
  1972.  
  1973.     lev = -1;
  1974.     for (;;)
  1975.     {
  1976.         if ((cmp = PT_readidx(fd_sys, ++lev, elt)) != IOGOOD)
  1977.         {
  1978.             abort_mess("DIAG: readidx( lev=%d , elt=%d): %s\n", lev, elt,
  1979.               io_tran(cmp));
  1980.             cmp = 1;
  1981.             break;
  1982.         }
  1983.  
  1984.         /* tree is empty */
  1985.         if (kptr->nodebuff[lev].num_used == 0)
  1986.         {
  1987.             cmp = 1;
  1988.             break;
  1989.         }
  1990.  
  1991.         /* set elt to key in node greater or equal to keyval   */
  1992.         cmp = PT_find_match(fd_sys, keyval, &(kptr->nodebuff[lev]), &elt);
  1993.         kptr->c_elt[lev] = elt;
  1994.  
  1995.         if (kptr->nodebuff[lev].level <= 0)
  1996.             break;
  1997.         else if (cmp > 0)
  1998.             kptr->c_elt[lev] = --elt;
  1999.     }
  2000.  
  2001.     if (!cmp || (cmp < 0 && !exact))
  2002.         offset = kptr->nodebuff[lev].elt[elt].offset;
  2003.     else
  2004.         offset = PTNOPTR;
  2005.  
  2006.     return(offset);
  2007. }
  2008.  
  2009.  
  2010. /***********************************************************
  2011. *  Extract the segments of a key from the data record and  *
  2012. *  combine them to form the key string.                    *
  2013. ***********************************************************/
  2014. void
  2015. PT_get_key(fd_sys, buffer, keyval)
  2016.     int fd_sys;
  2017.     char *buffer;
  2018.     char *keyval;
  2019. {
  2020.     FDDEF *fptr = &fd[fd_sys];
  2021.     AFDDEF *aptr = &PT_fd[fd_sys];
  2022.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  2023.     int i, s_leng, s_kstart;
  2024.  
  2025.     for (i = 0; i < kptr->k_segs; i++)
  2026.     {
  2027.         s_leng   = kptr->sd[i].s_leng;
  2028.         s_kstart = kptr->sd[i].s_keystart;
  2029.         memcpy(keyval + s_kstart, buffer + kptr->sd[i].s_recstart, s_leng);
  2030.     }
  2031.  
  2032.     if (kptr->k_type == KEY_DUPLICATE)
  2033.     {
  2034.         s_leng   = kptr->sd[DUPSEG].s_leng;
  2035.         s_kstart = kptr->sd[DUPSEG].s_keystart;
  2036.         memset(&keyval[s_kstart], 0, s_leng);
  2037.     }
  2038. }
  2039.  
  2040.  
  2041. char *
  2042. PT_fmtkey(kptr, keyval)
  2043.     KINFO *kptr;
  2044.     char *keyval;
  2045. {
  2046.     static char buf[81], *ptr;
  2047.     int i, s_leng, s_kstart, s_vtyp;
  2048.     WORD16 b2;
  2049.     WORD32 b4;
  2050.     FLOAT32 ftmp;
  2051.     FLOAT64 dtmp;
  2052.  
  2053.     *(ptr = buf) = 0;
  2054.     sprintf(buf, "0x%lx:", keyval);
  2055.     ptr = buf + strlen(buf);
  2056.     for (i = 0; i < kptr->k_segs; i++)
  2057.     {
  2058.         if (i)
  2059.             strcat(ptr, ":"), ptr += 2;
  2060.  
  2061.         s_leng   = kptr->sd[i].s_leng;
  2062.         s_kstart = kptr->sd[i].s_keystart;
  2063.         s_vtyp   = kptr->sd[i].s_vtyp;
  2064.  
  2065.         /* compare the segments according to type */
  2066.         switch (s_vtyp)
  2067.         {
  2068.             case CHRTYP    :
  2069.             case LOGTYP    :
  2070.             case MEMTYP    :
  2071.             case DATTYP    :
  2072.                 sprintf(ptr, "[%*.*s]", s_leng, s_leng, &keyval[s_kstart]);
  2073.                 break;
  2074.             case INTTYP:   /* two byte integer */
  2075.             case LNGTYP:   /* four byte integer */
  2076.                 if (s_leng == sizeof(WORD16))
  2077.                 {
  2078.                     memcpy((char *)&b2, &keyval[s_kstart], sizeof(WORD16));
  2079.                     b4 = (WORD32)b2;
  2080.                 }
  2081.                 else
  2082.                     memcpy((char *)&b4, &keyval[s_kstart], sizeof(WORD32));
  2083.                 sprintf(ptr, "[%5ld]", b4);
  2084.                 break;
  2085.             case FLTTYP:   /* single precision FP number (usually 4 long) */
  2086.             case DBLTYP:   /* double precision FP number (usually 8 long) */
  2087.                 if (s_vtyp == FLTTYP)
  2088.                 {
  2089.                     memcpy((char *)&ftmp, &keyval[s_kstart], sizeof(FLOAT32));
  2090.                     dtmp = (FLOAT64)ftmp;
  2091.                 }
  2092.                 else
  2093.                     memcpy((char *)&dtmp, &keyval[s_kstart], sizeof(FLOAT64));
  2094.                 sprintf(ptr, "[%lf]", dtmp);
  2095.                 break;
  2096.             default:
  2097.                 strcat(ptr, "???");
  2098.                 break;
  2099.         }
  2100.  
  2101.         ptr = buf + strlen(buf);
  2102.     }
  2103.  
  2104.     if (kptr->k_type == KEY_DUPLICATE)
  2105.     {
  2106.         s_leng   = kptr->sd[DUPSEG].s_leng;
  2107.         s_kstart = kptr->sd[DUPSEG].s_keystart;
  2108.  
  2109.         if (s_leng == sizeof(WORD16))
  2110.         {
  2111.             memcpy((char *)&b2, &keyval[s_kstart], sizeof(WORD16));
  2112.             b4 = (WORD32)b2;
  2113.         }
  2114.         else
  2115.             memcpy((char *)&b4, &keyval[s_kstart], sizeof(WORD32));
  2116.         sprintf(ptr, ":<%ld>", b4);
  2117.     }
  2118.  
  2119.     return(buf);
  2120. }
  2121.  
  2122.  
  2123. void
  2124. PT_makenodes(fd_sys, kptr, num)
  2125.     int fd_sys;
  2126.     KINFO *kptr;
  2127.     int num;
  2128. {
  2129.     AFDDEF *aptr = &PT_fd[fd_sys];
  2130.     int i, j, pt_size;
  2131.     char *ptr;
  2132.  
  2133.     kptr->k_levs     = num;
  2134.     kptr->keyval     = NULL;
  2135.     kptr->c_elt      = (WORD16 *)alloc(sizeof(WORD16) * num);
  2136.     kptr->changes    = (WORD16 *)alloc(sizeof(WORD16) * num);
  2137.     kptr->nodeoffset = (WORD32 *)alloc(sizeof(WORD32) * num);
  2138.     kptr->nodebuff   = (BNODE *)alloc(sizeof(BNODE) * num);
  2139.  
  2140.     for (i = 0; i < num ; i++)
  2141.     {
  2142.         kptr->c_elt[i]      = -1;
  2143.         kptr->changes[i]    = 0;
  2144.         kptr->nodeoffset[i] = PTNOPTR;
  2145.         kptr->nodebuff[i].elt = (BELT *)alloc(sizeof(BELT) * aptr->maxelts);
  2146.         pt_size = (kptr->k_leng + 3) / 4;
  2147.         pt_size *= 4;
  2148.         ptr = alloc(pt_size * aptr->maxelts);/*LEFTOVER*/
  2149.         for (j = 0; j < aptr->maxelts; j++)
  2150.             kptr->nodebuff[i].elt[j].keyval = ptr + j * pt_size;
  2151.         kptr->nodebuff[i].level = num - i - 1;
  2152.         if (kptr->nodebuff[i].level < 0)
  2153.             abort_mess("\rDIAG: makenodes( level[%d]=%d )\r\n", i,
  2154.               kptr->nodebuff[i].level);
  2155.         PT_zeronode(fd_sys, &(kptr->nodebuff[i]));
  2156.     }
  2157. }
  2158.  
  2159.  
  2160. int
  2161. PT_resize(fd_sys, kptr, to)
  2162.     int fd_sys;
  2163.     KINFO *kptr;
  2164.     int to;
  2165. {
  2166.     KINFO *ktmp;
  2167.     int iostat = IOGOOD, i, from, first = FALSE;
  2168.  
  2169.     if ((from = kptr->k_levs) < 0)
  2170.     {
  2171.         kptr->k_levs = from = 1;
  2172.         first = TRUE;
  2173.     }
  2174.     else if (from - to != 1 && from - to != -1)
  2175.         abort_mess("\rDIAG: resize( from=%d , to=%d )\r\n", from, to);
  2176.  
  2177.     /* save the old arrays and their contents */
  2178.     ktmp = (KINFO *)alloc(sizeof(KINFO));
  2179.    ktmp->k_leng  = kptr->k_leng;
  2180.    ktmp->k_type  = kptr->k_type;
  2181.    ktmp->k_segs  = kptr->k_segs;
  2182.    ktmp->didxptr = kptr->didxptr;
  2183.     for (i = 0; i <= MAXSEGS; i++)
  2184.         ktmp->sd[i] = kptr->sd[i];
  2185.     PT_makenodes(fd_sys, ktmp, from);
  2186.     for (i = 0; i < from; i++)
  2187.     {
  2188.         ktmp->c_elt[i]      = kptr->c_elt[i];
  2189.         ktmp->changes[i]    = kptr->changes[i];
  2190.         ktmp->nodeoffset[i] = kptr->nodeoffset[i];
  2191.         PT_cpynode(fd_sys, &(ktmp->nodebuff[i]), &(kptr->nodebuff[i]));
  2192.     }
  2193.     /* save the current key pointer in a safe place */
  2194.     ktmp->keyval = kptr->keyval;
  2195.     kptr->keyval = NULL;
  2196.  
  2197.     /* grab a new set of the appropriate dimensions */
  2198.     PT_freenodes(fd_sys, kptr);
  2199.     PT_makenodes(fd_sys, kptr, to);
  2200.  
  2201.     /* just planted */
  2202.     if (first)
  2203.     {
  2204.         kptr->c_elt[0]      = ktmp->c_elt[0];
  2205.         kptr->changes[0]    = ktmp->changes[0];
  2206.         kptr->nodeoffset[0] = ktmp->nodeoffset[0];
  2207.         PT_cpynode(fd_sys, &(kptr->nodebuff[0]), &(ktmp->nodebuff[0]));
  2208.     }
  2209.  
  2210.     /* growing */
  2211.     else if (from < to)
  2212.     {
  2213.         for (i = 1; i < to; i++)
  2214.         {
  2215.             kptr->c_elt[i]      = ktmp->c_elt[i - 1];
  2216.             kptr->changes[i]    = ktmp->changes[i - 1];
  2217.             kptr->nodeoffset[i] = ktmp->nodeoffset[i - 1];
  2218.             PT_cpynode(fd_sys, &(kptr->nodebuff[i]), &(ktmp->nodebuff[i - 1]));
  2219.         }
  2220.  
  2221.         /* save the new second level */
  2222.         kptr->nodeoffset[1] = PTNOPTR;
  2223.         iostat = PT_writeidx(fd_sys, 1);
  2224.  
  2225.         /* save the new top level */
  2226.         kptr->c_elt[0]             = 0;
  2227.         kptr->nodeoffset[0]        = ktmp->nodeoffset[0];
  2228.         kptr->nodebuff[0].level    = to - 1;
  2229.         if (kptr->nodebuff[0].level < 0)
  2230.             abort_mess("\rDIAG: resize( level[0]=%d )\r\n",
  2231.               kptr->nodebuff[0].level);
  2232.         kptr->nodebuff[0].num_used = 0;
  2233.         iostat = PT_add_elt(fd_sys, 0, kptr->nodeoffset[1],
  2234.           kptr->nodebuff[1].elt[kptr->nodebuff[1].num_used - 1].keyval);
  2235.     }
  2236.  
  2237.     /* shrinking */
  2238.     else
  2239.     {
  2240.         for (i = 0; i < to; i++)
  2241.         {
  2242.             kptr->c_elt[i]      = ktmp->c_elt[i + 1];
  2243.             kptr->changes[i]    = ktmp->changes[i + 1];
  2244.             kptr->nodeoffset[i] = ktmp->nodeoffset[i + 1];
  2245.             PT_cpynode(fd_sys, &(kptr->nodebuff[i]), &(ktmp->nodebuff[i + 1]));
  2246.         }
  2247.  
  2248.         /* save the new top level */
  2249.         kptr->nodeoffset[0] = ktmp->nodeoffset[0];
  2250.         iostat = PT_writeidx(fd_sys, 0);
  2251.  
  2252.         /* re-cycle the old top level */
  2253.         iostat = PT_keyrecycle(fd_sys, ktmp->nodeoffset[1]);
  2254.     }
  2255.  
  2256.     /* restore the current key pointer */
  2257.     kptr->keyval = ktmp->keyval;
  2258.     ktmp->keyval = NULL;
  2259.  
  2260.     PT_freenodes(fd_sys, ktmp);
  2261.     free(ktmp);
  2262.  
  2263.     return(iostat);
  2264. }
  2265.  
  2266.  
  2267. void
  2268. PT_freenodes(fd_sys, kptr)
  2269.     int fd_sys;
  2270.     KINFO *kptr;
  2271. {
  2272.     int i;
  2273.  
  2274.     if (kptr)
  2275.     {
  2276.         if (kptr->nodebuff)
  2277.         {
  2278.             for (i = 0; i < kptr->k_levs; i++)
  2279.                 if (kptr->nodebuff[i].elt)
  2280.                 {
  2281.                     if (kptr->nodebuff[i].elt[0].keyval)
  2282.                         free(kptr->nodebuff[i].elt[0].keyval);
  2283.                     free((char *)kptr->nodebuff[i].elt);
  2284.                 }
  2285.             free((char *)kptr->nodebuff);
  2286.             kptr->nodebuff = (BNODE *)0;
  2287.         }
  2288.         if (kptr->nodeoffset)
  2289.         {
  2290.             free((char *)kptr->nodeoffset);
  2291.             kptr->nodeoffset = (WORD32 *)0;
  2292.         }
  2293.         if (kptr->changes)
  2294.         {
  2295.             free((char *)kptr->changes);
  2296.             kptr->changes = (WORD16 *)0;
  2297.         }
  2298.         if (kptr->c_elt)
  2299.         {
  2300.             free((char *)kptr->c_elt);
  2301.             kptr->c_elt = (WORD16 *)0;
  2302.         }
  2303.         if (kptr->keyval)
  2304.         {
  2305.             free(kptr->keyval);
  2306.             kptr->keyval = NULL;
  2307.         }
  2308.  
  2309.         kptr->k_levs = 0;
  2310.     }
  2311. }
  2312.  
  2313.  
  2314. int
  2315. PT_recrecycle(fd_sys, offset)
  2316.     int fd_sys;
  2317.     long offset;
  2318. {
  2319.     FDDEF *fptr = &fd[fd_sys];
  2320.     AFDDEF *aptr = &PT_fd[fd_sys];
  2321.     int iostat;
  2322.     WORD32 b4;
  2323.  
  2324.     /* stack the record for re-cycling */
  2325.     if (lseek(aptr->fd_idx, aptr->ddatptr, FDIR_BEGIN) != aptr->ddatptr)
  2326.         iostat = IOIDXSEEK;
  2327.     else
  2328.         iostat = PT_readnum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2329.     if (iostat == IOGOOD)
  2330.     {
  2331.         if (lseek(fptr->fd_num, offset, FDIR_BEGIN) != offset)
  2332.             iostat = IOIDXSEEK;
  2333.         else
  2334.             iostat = PT_writenum(fptr->fd_num, (char *)&b4, sizeof(b4));
  2335.     }
  2336.     if (iostat == IOGOOD)
  2337.     {
  2338.         b4 = offset;
  2339.         if (lseek(aptr->fd_idx, aptr->ddatptr, FDIR_BEGIN) != aptr->ddatptr)
  2340.             iostat = IOIDXSEEK;
  2341.         else
  2342.             iostat = PT_writenum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2343.     }
  2344.  
  2345.     return(iostat);
  2346. }
  2347.  
  2348.  
  2349. long
  2350. PT_recreuse(fd_sys)
  2351.     int fd_sys;
  2352. {
  2353.     FDDEF *fptr = &fd[fd_sys];
  2354.     AFDDEF *aptr = &PT_fd[fd_sys];
  2355.     long offset = PTNOPTR;
  2356.     WORD32 b4;
  2357.     int iostat;
  2358.  
  2359.     /* pop the free record stack */
  2360.     if (lseek(aptr->fd_idx, aptr->ddatptr, FDIR_BEGIN) != aptr->ddatptr)
  2361.         iostat = IOIDXSEEK;
  2362.     else
  2363.     {
  2364.         iostat = PT_readnum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2365.         if (iostat == IOGOOD)
  2366.         {
  2367.             aptr->doffset = offset = b4;
  2368.             if (offset != PTNOPTR)
  2369.                 iostat = i_lockrec(fd_sys, NULL);
  2370.         }
  2371.     }
  2372.     if (iostat == IOGOOD && offset != PTNOPTR)
  2373.     {
  2374.         if (lseek(fptr->fd_num, offset, FDIR_BEGIN) != offset)
  2375.             iostat = IODATSEEK;
  2376.         else
  2377.             iostat = PT_readnum(fptr->fd_num, (char *)&b4, sizeof(b4));
  2378.     }
  2379.     if (iostat == IOGOOD && offset != PTNOPTR)
  2380.     {
  2381.         if (lseek(aptr->fd_idx, aptr->ddatptr, FDIR_BEGIN) != aptr->ddatptr)
  2382.             iostat = IOIDXSEEK;
  2383.         else
  2384.             iostat = PT_writenum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2385.     }
  2386.  
  2387.     if (iostat != IOGOOD)
  2388.         aptr->doffset = offset = PTNOPTR;
  2389.  
  2390.     return(offset);
  2391. }
  2392.  
  2393.  
  2394. int
  2395. PT_keyrecycle(fd_sys, offset)
  2396.     int fd_sys;
  2397.     long offset;
  2398. {
  2399.     FDDEF *fptr = &fd[fd_sys];
  2400.     AFDDEF *aptr = &PT_fd[fd_sys];
  2401.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  2402.     int iostat;
  2403.     WORD32 b4;
  2404.  
  2405.     /* stack the node for re-cycling */
  2406.     if (lseek(aptr->fd_idx, kptr->didxptr, FDIR_BEGIN) != kptr->didxptr)
  2407.         iostat = IOIDXSEEK;
  2408.     else
  2409.         iostat = PT_readnum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2410.     if (iostat == IOGOOD)
  2411.     {
  2412.         if (lseek(aptr->fd_idx, offset, FDIR_BEGIN) != offset)
  2413.             iostat = IOIDXSEEK;
  2414.         else
  2415.             iostat = PT_writenum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2416.     }
  2417.     if (iostat == IOGOOD)
  2418.     {
  2419.         b4 = offset;
  2420.         if (lseek(aptr->fd_idx, kptr->didxptr, FDIR_BEGIN) != kptr->didxptr)
  2421.             iostat = IOIDXSEEK;
  2422.         else
  2423.             iostat = PT_writenum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2424.     }
  2425.  
  2426.     return(iostat);
  2427. }
  2428.  
  2429.  
  2430. long
  2431. PT_keyreuse(fd_sys)
  2432.     int fd_sys;
  2433. {
  2434.     FDDEF *fptr = &fd[fd_sys];
  2435.     AFDDEF *aptr = &PT_fd[fd_sys];
  2436.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  2437.     long offset = PTNOPTR;
  2438.     WORD32 b4;
  2439.     int iostat;
  2440.  
  2441.     /* pop the free node stack */
  2442.     if (lseek(aptr->fd_idx, kptr->didxptr, FDIR_BEGIN) != kptr->didxptr)
  2443.         iostat = IOIDXSEEK;
  2444.     else
  2445.         if ((iostat = PT_readnum(aptr->fd_idx, (char *)&b4, sizeof(b4))) == IOGOOD)
  2446.             offset = b4;
  2447.     if (iostat == IOGOOD && offset != PTNOPTR)
  2448.     {
  2449.         if (lseek(aptr->fd_idx, offset, FDIR_BEGIN) != offset)
  2450.             iostat = IOIDXSEEK;
  2451.         else
  2452.             iostat = PT_readnum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2453.     }
  2454.     if (iostat == IOGOOD && offset != PTNOPTR)
  2455.     {
  2456.         if (lseek(aptr->fd_idx, kptr->didxptr, FDIR_BEGIN) != kptr->didxptr)
  2457.             iostat = IOIDXSEEK;
  2458.         else
  2459.             iostat = PT_writenum(aptr->fd_idx, (char *)&b4, sizeof(b4));
  2460.     }
  2461.  
  2462.     if (iostat != IOGOOD)
  2463.         offset = PTNOPTR;
  2464.  
  2465.     return(offset);
  2466. }
  2467.  
  2468.  
  2469. /************************************************************************
  2470. *  Position data file pointers and read a record into the local buffer  *
  2471. ************************************************************************/
  2472. int
  2473. PT_get_rec(fd_sys, buffer)
  2474.     int fd_sys;
  2475.     char *buffer;
  2476. {
  2477.     FDDEF *fptr = &fd[fd_sys];
  2478.     AFDDEF *aptr = &PT_fd[fd_sys];
  2479.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  2480.     int lev, elt, iostat;
  2481.  
  2482.     if (aptr->doffset == PTNOPTR)
  2483.         iostat = IONOKEY;
  2484.     else if ((iostat = i_lockrec(fd_sys, buffer)) != IOGOOD)
  2485.         aptr->doffset = PTNOPTR;
  2486.     else
  2487.     {
  2488.         lev = kptr->nodebuff[0].level;
  2489.         elt = kptr->c_elt[lev];
  2490.         if (!kptr->keyval)
  2491.             kptr->keyval = alloc(kptr->k_leng);
  2492.         memcpy(kptr->keyval, kptr->nodebuff[lev].elt[elt].keyval,
  2493.           kptr->k_leng);
  2494.  
  2495.         if (kptr->nodebuff[lev].elt[elt].offset != aptr->doffset)
  2496.         {
  2497.             errmsg("DIAG: record data and index out of sync");
  2498.             abort_mess("\rDIAG: get_rec( %s[%d][%d][%d]=%ld ) [%ld]\r\n",
  2499.               aptr->iname, fptr->cur_key + 1, lev, elt,
  2500.               kptr->nodebuff[lev].elt[elt].offset, aptr->doffset);
  2501.         }
  2502.         if (iostat == IOGOOD)
  2503.             iostat = PT_readdata(fd_sys, buffer);
  2504.     }
  2505.  
  2506.     return(iostat);
  2507. }
  2508.  
  2509.  
  2510. #ifndef INCREMENTAL_DUP_VALUES
  2511. int
  2512. PT_find_key(fd_sys, buf)
  2513.     int fd_sys;
  2514.     char *buf;
  2515. {
  2516.     FDDEF *fptr = &fd[fd_sys];
  2517.     AFDDEF *aptr = &PT_fd[fd_sys];
  2518.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  2519.     int iostat = IOGOOD;
  2520.  
  2521.     if (!kptr->keyval)
  2522.         kptr->keyval = alloc(kptr->k_leng);
  2523.     PT_get_key(fd_sys, buf, kptr->keyval);
  2524.  
  2525.     if (kptr->k_type == KEY_DUPLICATE)
  2526.         iostat = PT_new_dup(fd_sys, kptr->keyval);
  2527.  
  2528.     if (PT_gteq_key(fd_sys, kptr->keyval, TRUE) == PTNOPTR)
  2529.         iostat = IONOKEY;
  2530.  
  2531.     return(iostat);
  2532. }
  2533. #endif
  2534.  
  2535.  
  2536. #ifdef INCREMENTAL_DUP_VALUES
  2537. int
  2538. PT_find_key(fd_sys, buf)
  2539.     int fd_sys;
  2540.     char *buf;
  2541. {
  2542.     FDDEF *fptr = &fd[fd_sys];
  2543.     AFDDEF *aptr = &PT_fd[fd_sys];
  2544.     KINFO *kptr = &(aptr->keyinfo[fptr->cur_key]);
  2545.     long offset;
  2546.     int lev, elt, iostat = IOERROR;
  2547.  
  2548.     if (!kptr->keyval)
  2549.         kptr->keyval = alloc(kptr->k_leng);
  2550.     PT_get_key(fd_sys, buf, kptr->keyval);
  2551.  
  2552.     offset = PT_gteq_key(fd_sys, kptr->keyval, FALSE);
  2553.  
  2554.     while (offset != PTNOPTR && offset != aptr->doffset)
  2555.     {
  2556.         lev = kptr->nodebuff[0].level;
  2557.         elt = kptr->c_elt[lev];
  2558.         if (PT_keycmp(fd_sys, kptr->keyval,
  2559.           kptr->nodebuff[lev].elt[elt].keyval, KEY_UNIQUE))
  2560.             offset = PTNOPTR;
  2561.         else
  2562.             offset = PT_next_key(fd_sys);
  2563.     }
  2564.  
  2565.     if (offset != PTNOPTR)
  2566.     {
  2567.         lev = kptr->nodebuff[0].level;
  2568.         elt = kptr->c_elt[lev];
  2569.         memcpy(kptr->keyval, kptr->nodebuff[lev].elt[elt].keyval, kptr->k_leng);
  2570.         iostat = IOGOOD;
  2571.     }
  2572.  
  2573.     return(iostat);
  2574. }
  2575. #endif
  2576.