home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / APPS / DATABASE / MBASE.ZIP / MBASE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-11  |  29.1 KB  |  1,060 lines

  1. /*   ********************************************************************   *
  2.   ***                                                    unix compatible ***
  3.  *    MetalBase 3.0.....................................................    *
  4.  *                                                                          *
  5.  *    Multi-user simultaneous use of relations (On multi-user hardware)     *
  6.  *    Users may have many relations open at once, even the same one!        *
  7.  *    Unlimited length records (Really!  Just redefine BUF_LEN!)            *
  8.  *    Up to 20 indicies per relation, 5 fields max per composite index      *
  9.  *    Up to 4.2 billion records per relation                                *
  10.  *    Bizzare intermittent bugs, just like the expensive programs           *
  11.  *    And, unless they're weird, your kids will eat it                      *
  12.  *                                                               /\         *
  13.  *    Written starting August 1989, by Huan-Ti               rj /  \        *
  14.  *                                                             /    \       *
  15.  *   "Ye hath mushrooms for $1.99 a pound.  Ye art             \    /       *
  16.  *    truly a Calvinist."                                       \  / tp     *
  17.  *                       -- II Calvin 7:1                        \/         *
  18.  *                                                                          *
  19.  *          713/630-8962 <-----= May 26, 1996 =-----> 615/494-0220          *
  20.   ***                                                                    ***
  21.  *   ********************************************************************   */
  22.  
  23. #include "stdinc.h"
  24.  
  25. #define BUF_LEN 256       /* Record_length + 13*number_of_indicies          */
  26. #define MAX_REL 5         /* For this user.  DOES NOT CHANGE STDIO'S # !    */
  27. #define MAX_FLDS 30       /* Fields/rel. If you need more than 30, redefine */
  28.  
  29. #define OKAY                  0   /* Generic no-problem number.  Thank IBM. */
  30. #define NOT_ENOUGH_ROOM   -1000   /* Too many files are open at once        */
  31. #define CANNOT_OPEN_REL   -1001   /* Can't open FILE.REL                    */
  32. #define RELATION_HUNG     -1002   /* User left during add/del/upd.  See dox */
  33. #define CANNOT_READ_REL   -1003   /* FILE.REL is protected (Need rw access) */
  34. #define RELATION_BUSY     -1004   /* 120 users on one relation=max (Hah!)   */
  35. #define RELATION_LOCKED   -1005   /* Someone has locked the relation        */
  36. #define LOCK_DENIED       -1006   /* Can't lock with other users.  See dox  */
  37. #define ILLEGAL_DUPLICATE -1007   /* Record would violate a nodups index    */
  38. #define CORRUPT_INDEX     -1008   /* Means you're fucked.  Probly not used  */
  39. #define INVALID_FILE_CODE -1009   /* You've passed an unreal relation numb  */
  40. #define NOT_OPEN          -1010   /* You've tried to work with a closed rel */
  41. #define RCD_INVALID       -1011   /* Bad-size or # of flds given to add/upd */
  42. #define INVALID_COMP      -1012   /* SELECT's record for comparison is bad  */
  43. #define UNKNOWN_ACTION    -1013   /* You'll probly never get this one.      */
  44. #define NOT_FOUND         -1014   /* Generic.  Can't find the record U want */
  45. #define NO_CURRENT_RECORD -1015   /* Must select a record before del/upd    */
  46. #define INVALID_INDEX     -1016   /* A bad index # has been sent to mb_sel  */
  47.  
  48. #define CURR                  1   /* Re-read the current record (4 mb_sel)  */
  49. #define EQUL                  2   /* Get rec that matches exactly (see dox) */
  50. #define FRST                  3   /* Get the first record, sequentially     */
  51. #define GTEQ                  4   /* If not exact, get the one right after  */
  52. #define GTHN                  5   /* Like GTEQ, but won't accept exact one  */
  53. #define LAST                  6   /* Get the last record, sequentially      */
  54. #define LTEQ                  7   /* If not exact, get the one right before */
  55. #define LTHN                  8   /* Like LTEQ, but won't accept exact one  */
  56. #define NEXT                  9   /* Get the next record, sequentially      */
  57. #define PREV                 10   /* Get the previous record, sequentially  */
  58.  
  59. #define CURRENT            CURR   /* These are included to reduce errors    */
  60. #define EQUAL              EQUL   /* due to stupid humans who insist on     */
  61. #define FIRST              FRST   /* using long words instead of short ones */
  62. #define GTHAN              GTHN   /*                                        */
  63. #define LTHAN              LTHN   /* Gee, I'm considerate.                  */
  64. #define PREVIOUS           PREV   /*                                        */
  65.  
  66. #define ZEROES "\001\001\001\001\001\001\001\001\001\001\001\001."
  67.  
  68. /****************************************************************************/
  69. /*                                                                          */
  70. /* A reminder of the single rule that applies to EVERYTHING in this file:   */
  71. /*                                                                          */
  72. /* If you don't understand it, DON'T SCREW WITH IT.                         */
  73. /*                                                                          */
  74. /* I'd like to emphasize that this rule is _most_important_ in viewing the  */
  75. /* follow section of definitions.  If you wanna change the internal         */
  76. /* structure of the relations, and think you can (successfully, that is),   */
  77. /* go right ahead.  And send me a copy of the "better" MetalBase when you   */
  78. /* think you're finished... I'd like to see it.  (smiley-face)              */
  79. /*                                                                          */
  80. /****************************************************************************/
  81.  
  82. #define _t_top(f,i)    4 +  4*i
  83. #define _idxs(f)           13*(_list[f].num_idx)
  84. #define _num_recs(f)   5 +  4*(_list[f].num_idx)
  85.  
  86. #define _block(f)      11+(4*_list[f].num_idx)
  87. #define _base(f,r)     _block(f)+_list[f].relbase+(r-1)*((13*_list[f].num_idx)+\
  88.                           2+(_list[f].rec_len))
  89. #define _l_ptr(f,i,r)  _base  (f, r)    + 13*i
  90. #define _r_ptr(f,i,r)  _l_ptr (f, i, r) +  4
  91. #define _b_ptr(f,i,r)  _r_ptr (f, i, r) +  4
  92. #define _rec(f,r)      _base  (f, r)    + (13*_list[f].num_idx) + 1
  93.  
  94. #define _len(f)        2 + _idxs (f) + _list[f].rec_len
  95.  
  96. char   buffer [BUF_LEN];
  97.  
  98. extern int  _Started;
  99.  
  100. struct
  101.  { long  int   pos,      relbase;
  102.          int   relcode;
  103.          int   num_idx,  rec_len;
  104.          char  alpha,    beta,     gamma;
  105.  
  106.          int   idx_dups  [20];
  107.          int   idx_just  [MAX_FLDS];
  108.          int   idx_num   [20][6];
  109.          int   idx_start [20][6];
  110.          int   idx_stop  [20][5];
  111.  
  112.          char  filename  [80];     } _list [MAX_REL];
  113.  
  114. /****************************************************************************/
  115.  
  116. #define hash(a,o,g) ((a + o) & g)
  117.  
  118. void breakkey (n, key)
  119. int            n;
  120. int               key;
  121. {
  122.    _list[n].alpha = (key &  48) >> 4;
  123.    _list[n].beta  = (key &  63);
  124.    _list[n].gamma = (key & 192) >> 6;
  125. }
  126.  
  127. void _encrypt (temp, n)
  128. char          *temp;
  129. int                  n;
  130. {
  131.    register int len;
  132.    char         old;
  133.  
  134.    for (len = 0, old=_list[n].beta; temp[len] != 0; len++)
  135.       old = temp[len] = 127 - temp[len] ^ hash (_list[n].alpha, old, _list[n].gamma);
  136. }
  137.  
  138. void _decrypt (temp, n)
  139. char          *temp;
  140. int                  n;
  141. {
  142.    register int len;
  143.    char         old, oold;
  144.  
  145.    for (len = 0, old=_list[n].beta; temp[len] != 0; len++, old=oold)
  146.       temp[len] = (127 - (oold = temp[len])) ^ hash (_list[n].alpha, old, _list[n].gamma);
  147. }
  148.  
  149. _diff   (one,  two, use_sp, num)
  150. char    *one, *two;
  151. int                 use_sp, num;
  152. {
  153.    register int  i;
  154.    char          lold, rold, l, r;
  155.    int           x, sp, vl, a, g;
  156.  
  157.    a           = _list[num].alpha;
  158.    lold = rold = _list[num].beta;
  159.    g           = _list[num].gamma;
  160.  
  161.    x = 0;
  162.  
  163.    do
  164.     { vl = 0;  sp = 1-use_sp;
  165.  
  166.       for (i = x; one[i] != 0 && one[i] != '|'; i++)
  167.        { if (use_sp == 1 && one[i] != ' ')  sp = 1;
  168.  
  169.          if (vl == 0)
  170.           { l = (127 - (lold = one[i])) ^ hash (a, lold, g);
  171.             r = (127 - (rold = two[i])) ^ hash (a, rold, g);
  172.  
  173.             if (l > r)  vl = -1;
  174.             if (l < r)  vl =  1;
  175.           };
  176.  
  177.          if (one[i] == '|')  lold = rold = _list[num].beta;
  178.        };
  179.  
  180.       if (sp != 0 && vl != 0)  return vl;
  181.  
  182.       x = i+1;
  183.     } while (one[i] != 0);
  184.  
  185.    return 0;
  186. }
  187.  
  188. /****************************************************************************/
  189.  
  190. char *repeat (ch, nm)
  191. int           ch, nm;
  192. {
  193.    char  buf [MAX_RPT];
  194.  
  195.    buf[(nm = (nm < 0) ? 0 : nm)] = 0;
  196.  
  197.    for (nm--; nm >= 0; nm--)  buf[nm] = ch;
  198.  
  199.    return buf;
  200. }
  201.  
  202. char *_next_line (file)
  203. int               file;
  204. {
  205.    register int   i;
  206.    int            j;
  207.  
  208.    j = 0;
  209.  
  210.    do     i = read (file, &buffer[j++], 1);
  211.    while (i != 0 && buffer[j-1] != '\n' && buffer[j-1] != 0);
  212.  
  213.    buffer[j-1] = 0;
  214.  
  215.    return buffer;
  216. }
  217.  
  218. char *_rcd (file, rec)
  219. int         file, rec;
  220. {
  221.    static char temp[BUF_LEN];
  222.  
  223.    lseek (_list[file].relcode, _rec (file, rec), 0);
  224.  
  225.    read  (_list[file].relcode, temp, _list[file].rec_len);
  226.  
  227.    temp[_list[file].rec_len] = 0;
  228.  
  229.    return temp;
  230. }
  231.  
  232. char *_skey (file,  index,  str)
  233. int          file,  index;
  234. char                       *str;
  235. {
  236.    register int   j, s, i;
  237.    static   char  temp[BUF_LEN];
  238.  
  239.    for (i = s = 0; _list[file].idx_start[index][i] != -1; i++)
  240.     {
  241.       for (j = _list[file].idx_start[index][i];
  242.            j < _list[file].idx_stop [index][i]; j++)  temp[s++] = str[j];
  243.  
  244.       temp[s++] = '|';
  245.     };
  246.  
  247.    temp[s] = 0;
  248.  
  249.    return temp;
  250. }
  251.  
  252. char *_key (file, index, rec)
  253. int         file, index, rec;
  254. {
  255.    static char temp[BUF_LEN];
  256.  
  257.    strcpy (temp, _skey (file, index, _rcd (file, rec)));
  258.  
  259.    return temp;
  260. }
  261.  
  262. char *cut (str, num)
  263. char      *str;
  264. int             num;
  265. {
  266.    static char buff [MAX_CUT];
  267.  
  268.    if (num == 0)
  269.       sprintf (buff, "");
  270.    else
  271.       for (buff[num] = 0; num > 0; num--)  buff[num-1] = str[num-1];
  272.  
  273.    return buff;
  274. }
  275.  
  276. char *_spc (file, index,  str, enc)
  277. int         file, index,       enc;
  278. char                     *str;
  279. {
  280.    register int   i, a;
  281.    int            x, b;
  282.    static   char  temp[BUF_LEN];
  283.  
  284.    i = b = temp[0] = 0;
  285.  
  286.    do
  287.     { x = (index == -1) ? b : _list[file].idx_num[index][b];
  288.  
  289.       if ((index == -1) ? (_list[file].idx_just[x] != 0) : (x != -1))
  290.        { for (a = 0; str[i] != '|' && str[i] != 0; i++, a++);
  291.  
  292.          if (_list[file].idx_just[x] > 0)
  293.             sprintf (buffer, "%s%s", repeat (' ', _list[file].idx_just[x]-a),
  294.                                     cut (&str[i-a], a));
  295.          else
  296.             sprintf (buffer, "%s%s", cut (&str[i-a], a),
  297.                                     repeat (' ', 0-_list[file].idx_just[x]-a));
  298.  
  299.          if (enc == -1)  _decrypt (buffer, file);
  300.          if (enc ==  1)  _encrypt (buffer, file);
  301.  
  302.          strcat (temp, buffer);
  303.          strcat (temp, "|");
  304.        };
  305.  
  306.       i = (str[i] == 0) ? i : i+1;
  307.       b++;
  308.     } while ((index == -1) ? (_list[file].idx_just[x] != 0) : (x != -1));
  309.  
  310.    return temp;
  311. }
  312.  
  313. pattern (whole,  match, skip)
  314. char    *whole, *match;
  315. int                     skip;
  316. {
  317.    int  i, j, m, w;
  318.  
  319.    m = strlen (match);  w = strlen (whole);
  320.  
  321.    for (i = 0; i <= w-m; i++)
  322.     {
  323.       for (j = 0; match [j] != 0 && whole[i+j] == match[j]; j++)
  324.        ;
  325.  
  326.       if (match[j] == 0)  if (skip-- == 0)  return i;
  327.     };
  328.  
  329.    return -1;
  330. }
  331.  
  332. /*  Encode and Eval perform base 10 to base 255 conversion, with a bottom
  333.     value of 1 (As opposed to 0) for the base-255 numbers.  Perfect for
  334.     encoding BIG numbers (See chart) and storing them in 5 bytes on disk, eh?
  335.  
  336.     # of characters used______________Maximum integer representable
  337.     1                                          254
  338.     2                                        65024
  339.     3                                     16581374
  340.     4                                   4228250624
  341.     5                                 107820390900.... etc.                  */
  342.  
  343. long _eval (st, x)
  344. char       *st;
  345. int             x;
  346. {
  347.    long int  j;
  348.    long int  n;
  349.    int       a;
  350.  
  351.    j = 0;  n = 1;
  352.  
  353.    while (x > 0) { a = st[--x];  a = fix (a);  j += n * (a - 1);  n *= 255; };
  354.  
  355.    return j;
  356. }
  357.  
  358. char *_encode (num, len)
  359. long int       num;
  360. int                 len;
  361. {
  362.    register int  i;
  363.             int  a;
  364.    static   char buf[10];
  365.  
  366.    len = (len < 9) ? len : 9;
  367.  
  368.    for (i = len-1; i >= 0; i--)
  369.     { a = num % 255;
  370.  
  371.       num = (num - a) / 255;
  372.  
  373.       buf[i] = a + 1;
  374.     };
  375.  
  376.    buf[len] = 0;
  377.  
  378.    return buf;
  379. }
  380.  
  381. mb_lck (file)
  382. int     file;
  383. {
  384.    if (file < 0 || file > MAX_REL)  return INVALID_FILE_CODE;
  385.    if (_list[file].pos == -1)       return NOT_OPEN;
  386.  
  387.    lseek (_list[file].relcode, 0L, 0);  read  (_list[file].relcode, buffer, 1);
  388.  
  389.    if (fix (buffer[0]) == 127)  return OKAY;
  390.    if (fix (buffer[0]) != 2)    return LOCK_DENIED;
  391.  
  392.    buffer[0] = 127;
  393.  
  394.    lseek (_list[file].relcode, 0L, 0);  write (_list[file].relcode, buffer, 1);
  395.  
  396.    return OKAY;
  397. }
  398.  
  399. mb_unl (file)
  400. int     file;
  401. {
  402.    if (file < 0 || file > MAX_REL)  return INVALID_FILE_CODE;
  403.    if (_list[file].pos == -1)       return NOT_OPEN;
  404.  
  405.    lseek (_list[file].relcode, 0L, 0);  read  (_list[file].relcode, buffer, 1);
  406.  
  407.    if (buffer[0] != 127)  return OKAY;
  408.  
  409.    buffer[0] = 2;
  410.  
  411.    lseek (_list[file].relcode, 0L, 0);  write (_list[file].relcode, buffer, 1);
  412.  
  413.    return OKAY;
  414. }
  415.  
  416. mb_rst (filename)
  417. char   *filename;
  418. {
  419.    int   relcode;
  420.  
  421.    sprintf (buffer, "%s.rel", filename);
  422.  
  423.    if ((relcode = open (buffer, O_RDWR)) == -1)
  424.       return CANNOT_OPEN_REL;
  425.  
  426.    if (read (relcode, buffer, 4) != 4)
  427.       return CANNOT_READ_REL;
  428.  
  429.    sprintf (buffer, "%c", '\001');
  430.  
  431.    lseek (relcode, 0L, 0);  write (relcode, buffer, 1);
  432.  
  433.    return OKAY;
  434. }
  435.  
  436. mb_inc (filename, key)
  437. char   *filename, key;
  438. {
  439.    char  temp[5];
  440.    int   i, place, relcode, n;
  441.  
  442.    place = -1;
  443.  
  444.    if (_Started == -1)
  445.     { _Started = 0;
  446.  
  447.       for (i = 0; i < MAX_REL; i++)  _list[i].pos = -1;
  448.     };
  449.  
  450.    for (i = 0; i < MAX_REL; i++)
  451.       if (_list[i].pos == -1)
  452.          place = (place == -1) ? i : place;
  453.  
  454.    if (place == -1)  return NOT_ENOUGH_ROOM;
  455.  
  456.    sprintf (buffer, "%s.rel", filename);
  457.  
  458.    if ((relcode = _list[place].relcode = open (buffer, O_RDWR)) == -1)
  459.       return CANNOT_OPEN_REL;
  460.  
  461.    if (read (relcode, buffer, 4) != 4)
  462.       return CANNOT_READ_REL;
  463.  
  464.    n = fix (buffer[0]);
  465.  
  466.    if (n == 121 || n == 249)  return RELATION_BUSY;
  467.    if (n == 127)              return RELATION_LOCKED;
  468.  
  469.    sprintf (temp, "%c", n+1);
  470.  
  471.    lseek (relcode, 0L, 0);  write (relcode, temp, 1);
  472.  
  473.    _list[place].num_idx = _eval (&buffer[1], 1);
  474.    _list[place].rec_len = _eval (&buffer[2], 2);
  475.  
  476.    if (_fill_idx (place) == -1)  return CORRUPT_INDEX;
  477.  
  478.    strcpy (_list[place].filename, filename);
  479.  
  480.    _list[place].pos = 0;
  481.  
  482.    breakkey (place, key);
  483.  
  484.    return place;
  485. }
  486.  
  487. _fill_idx (file)
  488. int        file;
  489. {
  490.    register int  j;
  491.             int  acc, i, k;
  492.             char temp[BUF_LEN];
  493.  
  494.    acc = _list[file].relcode;
  495.  
  496.    _list[file].relbase = 0 - lseek (acc, _block(file), 0);  _next_line (acc);
  497.  
  498.    for (i = 0; i < _list[file].num_idx; i++)
  499.     { strcpy (temp, _next_line (acc));
  500.  
  501.       for (j = 0; temp[4*j] != 0 && temp[4*j] != 'd'; j++)
  502.          _list[file].idx_num[i][j] = atoi (cut (&temp[4*j], 3)) - 1;
  503.  
  504.       _list[file].idx_num[i][j] = -1;
  505.  
  506.       _list[file].idx_dups[i] = (temp[4*j] == 'd') ? 1 : 0;
  507.     };
  508.  
  509.    _list[file].relbase += lseek (acc, 0L, 1);
  510.  
  511.    lseek (acc, _block(file), 0);
  512.  
  513.    strcpy (temp, _next_line (acc));
  514.  
  515.    for (i = 0; i < _list[file].num_idx; i++)
  516.     {
  517.       for (k = 0; _list[file].idx_num[i][k] != -1; k++)
  518.        { _list[file].idx_start[i][k] = 0;
  519.  
  520.          for (j = 0; j < _list[file].idx_num[i][k]; j++)
  521.             _list[file].idx_start[i][k] += 1 + atoi (cut (&temp[5*j], 3));
  522.  
  523.          _list[file].idx_stop[i][k] = _list[file].idx_start[i][k] +
  524.                                         atoi (cut (&temp[5*j], 3));
  525.        };
  526.  
  527.       _list[file].idx_num[i][k] = _list[file].idx_start[i][k] = -1;
  528.     };
  529.  
  530.    for (j = 0; temp[5*j] != 0; _list[file].idx_just[j] = ((temp[5*j+3] == 'r')
  531.            ? atoi (cut (&temp[5*j], 3)) : (0 - atoi (cut(&temp[5*j], 3)))), j++);
  532.  
  533.    _list[file].idx_just[j] = 0;
  534.  
  535.    return OKAY;
  536. }
  537.  
  538.  
  539. mb_rmv (file)
  540. int     file;
  541. {
  542.    int     n;
  543.  
  544.    if (file < 0 || file > MAX_REL)  return INVALID_FILE_CODE;
  545.    if (_list[file].pos == -1)       return NOT_OPEN;
  546.  
  547.    _list[file].pos = -1;
  548.  
  549.    lseek (_list[file].relcode, 0L, 0);  read  (_list[file].relcode, buffer, 1);
  550.    n=fix (buffer[0]);  n=((n == 127) ? 1 : n-1);  buffer[0]=((n < 1) ? 1 : n);
  551.    lseek (_list[file].relcode, 0L, 0);  write (_list[file].relcode, buffer, 1);
  552.  
  553.    close (_list[file].relcode);
  554.  
  555.    return OKAY;
  556. }
  557.  
  558. mb_upd (file,  string)
  559. int     file;
  560. char          *string;
  561. {
  562.    register int   i;
  563.    long     int   pos;
  564.    int            acc;
  565.    char           temp[BUF_LEN];
  566.  
  567.    strcpy (buffer, _spc (file, -1, string, 1));
  568.  
  569.    if (file < 0 || file > MAX_REL)              return INVALID_FILE_CODE;
  570.    if (_list[file].pos == -1)                   return NOT_OPEN;
  571.    if ((pos = _list[file].pos) == 0)            return NO_CURRENT_RECORD;
  572.    if (strlen (buffer) != _list[file].rec_len)  return RCD_INVALID;
  573.  
  574.    if (_set_lck ((acc = _list[file].relcode), 1) != 0)  return RELATION_HUNG;
  575.  
  576.    for (i = 0; i < _list[file].num_idx; i++)
  577.     { if (_list[file].idx_dups[i] == 0)
  578.        { strcpy (temp, _skey (file, i, buffer));
  579.  
  580.          if (_search (file, i, EQUL, temp, _find_top (file, i)) != 0)
  581.           { _clr_lck (acc);
  582.  
  583.             return ILLEGAL_DUPLICATE;
  584.           };
  585.        };
  586.     };
  587.  
  588.    lseek (acc, _rec (file, pos), 0);  read  (acc, temp,   _list[file].rec_len);
  589.    lseek (acc, _rec (file, pos), 0);  write (acc, buffer, _list[file].rec_len);
  590.  
  591.    for (i = 0; i < _list[file].num_idx; i++)
  592.     { _disconnect (file, i, pos);
  593.       _drop       (file, i, pos);
  594.     };
  595.  
  596.    _clr_lck (acc);
  597.  
  598.    return OKAY;
  599. }
  600.  
  601. mb_add (file,  string)
  602. int     file;
  603. char          *string;
  604. {
  605.    register int   i;
  606.    int            r_o,      acc;
  607.    char           temp[BUF_LEN], tmp2[5];
  608.  
  609.    strcpy (buffer, _spc (file, -1, string, 1));
  610.  
  611.    if (file < 0 || file > MAX_REL)              return INVALID_FILE_CODE;
  612.    if (_list[file].pos == -1)                   return NOT_OPEN;
  613.    if (strlen (buffer) != _list[file].rec_len)  return RCD_INVALID;
  614.  
  615.    if (_set_lck ((acc = _list[file].relcode), 1) != 0)  return RELATION_HUNG;
  616.  
  617.    for (i = 0; i < _list[file].num_idx; i++)
  618.     { if (_list[file].idx_dups[i] == 0)
  619.        { strcpy (temp, _skey (file, i, buffer));
  620.  
  621.          if (_search (file, i, EQUL, temp, _find_top (file, i)) != 0)
  622.           { _clr_lck (acc);
  623.  
  624.             return ILLEGAL_DUPLICATE;
  625.           };
  626.        };
  627.     };
  628.  
  629.    lseek (acc, _num_recs(file), 0);  read (acc, tmp2, 4);
  630.  
  631.    r_o = _eval (tmp2, 4) + 1;
  632.  
  633.    lseek (acc, _base (file, r_o), 0);
  634.  
  635.    for (i = 0; i < _list[file].num_idx; i++)  write (acc, ZEROES, 13);
  636.  
  637.    write (acc, "\n",    1);
  638.    write (acc, buffer, _list[file].rec_len);
  639.    write (acc, "\n",    1);
  640.  
  641.    for (i = 0; i < _list[file].num_idx; i++)  _drop (file, i, r_o);
  642.  
  643.    lseek (acc, _num_recs (file), 0);  write (acc, _encode (r_o, 4), 4);
  644.  
  645.    _clr_lck (acc);
  646.  
  647.    return OKAY;
  648. }
  649.  
  650. long _find_top (file, index)
  651. int             file, index;
  652. {
  653.    char   temp [5];
  654.  
  655.    lseek (_list[file].relcode, _t_top (file, index), 0);
  656.    read  (_list[file].relcode, temp,                 4);
  657.  
  658.    return (_eval (temp, 4));
  659. }
  660.  
  661. _drop (file, index, rec)
  662. int    file, index, rec;
  663. {
  664.    int    acc, a, off;
  665.    char   temp  [BUF_LEN];
  666.    char   temp2 [14];
  667.  
  668.    acc =     _list[file].relcode;
  669.    off = a = _find_top (file, index);
  670.  
  671.    if (a == 0)
  672.     { lseek (acc, _t_top  (file, index), 0);
  673.       write (acc, _encode (rec,  4),     4);  }
  674.    else
  675.     { strcpy (temp, _key (file, index, rec));
  676.  
  677.       do
  678.        { off = a;
  679.  
  680.          lseek (acc, _l_ptr (file, index, off), 0);  read (acc, temp2, 8);
  681.  
  682.          if (_diff (_key (file, index, off), temp, 0, file) == -1)
  683.           { if ((a = _eval (&temp2[0], 4)) == 0)
  684.                sprintf (temp2, "%-4.4s%-4.4s", _encode (rec, 4), &temp2[4]);
  685.           }
  686.          else
  687.           { if ((a = _eval (&temp2[4], 4)) == 0)
  688.                sprintf (temp2, "%-4.4s%-4.4s", temp2, _encode (rec, 4));
  689.           };
  690.        } while (a != 0);
  691.  
  692.       lseek (acc, _l_ptr (file, index, off), 0);  write (acc, temp2, 8);
  693.     };
  694.  
  695.    sprintf (temp, "%-8.8s%-4.4s", ZEROES, _encode (off, 4));
  696.  
  697.    lseek (acc, _l_ptr (file, index, rec), 0);  write (acc, temp, 12);
  698.  
  699.    return;
  700. }
  701.  
  702. mb_sel (file, index, str, action, comp)
  703. int     file, index,      action;
  704. char                *str,        *comp;
  705. {
  706.    long   off;
  707.  
  708.    if (file < 0 || file > MAX_REL)                   return INVALID_FILE_CODE;
  709.    if (_list[file].pos == -1)                        return NOT_OPEN;
  710.    if (_set_lck (_list[file].relcode, 0) != 0)       return RELATION_HUNG;
  711.    if (action != CURRENT)
  712.       if (index < 1 || index > _list[file].num_idx)  return INVALID_INDEX;
  713.  
  714.    strcpy (buffer, (comp[0] == 0) ? "" : _spc (file, index-1, comp, 1));
  715.  
  716.    if (_list[file].pos == 0)
  717.     { if (action == NEXT)  action = FRST;
  718.       if (action == PREV)  action = LAST;
  719.     };
  720.  
  721.    switch (action)
  722.     { case FRST:
  723.       case LAST:  off = _get_ends (file, index-1, action);
  724.                  break;
  725.       case CURR:  off = _list[file].pos;
  726.                  break;
  727.       case NEXT:
  728.       case PREV:  off = _get_sides (file, index-1, action);
  729.                  break;
  730.       case GTEQ:
  731.       case GTHN:
  732.       case LTEQ:
  733.       case LTHN:
  734.       case EQUL:  off = _search (file, index-1, action, buffer,
  735.                                                  _find_top (file, index-1));
  736.                  break;
  737.       default  :  return UNKNOWN_ACTION;
  738.     };
  739.  
  740.    if (off == 0)  return NOT_FOUND;
  741.    if (off <  0)  return off;
  742.  
  743.    strcpy (str, _spc (file, -1, _rcd (file, (_list[file].pos = off)), -1));
  744.  
  745.    return OKAY;
  746. }
  747.  
  748. _get_ends (file, index, action)
  749. int        file, index, action;
  750. {
  751.    long    go, off;
  752.    int     acc;
  753.    char    buf[10];
  754.  
  755.    acc = _list[file].relcode;
  756.  
  757.    if ((go = off = _find_top (file, index)) == 0)  return NOT_FOUND;
  758.  
  759.    while (go != 0)
  760.     { lseek (acc, _l_ptr (file, index, off), 0);  read  (acc, buf, 8);
  761.  
  762.       off = ((go = _eval (&buf[(action == LAST) ? 4 : 0], 4)) == 0) ? off : go;
  763.     };
  764.  
  765.    return off;
  766. }
  767.  
  768. _get_sides (file, index, action)
  769. int         file, index, action;
  770. {
  771.    long  pos;
  772.    int   acc, same, go, off;
  773.    char  buf[13];
  774.  
  775.    acc = _list[file].relcode;
  776.    pos = _list[file].pos;
  777.  
  778.    same = (action == NEXT) ? 4 : 0;
  779.  
  780.    lseek (acc, _l_ptr (file, index, pos), 0);  read (acc, buf, 12);
  781.  
  782.    if ((go = off = _eval (&buf[same], 4)) == 0)
  783.     { go = pos;
  784.  
  785.       for (;;)
  786.        { if ((off = _eval (&buf[8], 4)) == 0)  return NOT_FOUND;
  787.  
  788.          lseek (acc, _l_ptr (file, index, off), 0);  read (acc, buf, 12);
  789.  
  790.          if (go == _eval (&buf[4-same], 4))    return off;
  791.  
  792.          go = off;
  793.        };
  794.     };
  795.  
  796.    while (go != 0)
  797.     { lseek (acc, _l_ptr (file, index, off), 0);  read (acc, buf, 8);
  798.  
  799.       off = ((go = _eval (&buf[4-same], 4)) == 0) ? off : go;
  800.     };
  801.  
  802.    return off;
  803. }
  804.  
  805. _search (file, index, action, comp, pos)
  806. int      file, index, action,       pos;
  807. char                         *comp;
  808. {
  809.    long   x;
  810.    int    flag, r, dir;
  811.    char   temp[9];
  812.  
  813.    if (pos == 0)  return 0;
  814.  
  815.    lseek (_list[file].relcode, _l_ptr (file, index, pos), 0);
  816.  
  817.    read  (_list[file].relcode, temp, 8);
  818.  
  819.    flag = ((r = _diff (comp, _key (file, index, pos), 1, file)) == 0) ? 1 : 0;
  820.  
  821.    if (r == -1)  dir = 4;
  822.    if (r ==  1)  dir = 0;
  823.    if (r ==  0)
  824.     { if (action == GTHN || action == LTEQ)                    dir = 4;
  825.       if (action == GTEQ || action == LTHN || action == EQUL)  dir = 0;
  826.     };
  827.  
  828.    if ((x = _search (file, index, action, comp, _eval (&temp[dir], 4))) != 0)
  829.       return x;
  830.  
  831.    if  (action != GTHN && action != LTHN  && flag == 1)  return pos;
  832.    if ((action == GTEQ || action == GTHN) && dir  == 0)  return pos;
  833.    if ((action == LTEQ || action == LTHN) && dir  == 4)  return pos;
  834.  
  835.    return 0;
  836. }
  837.  
  838. mb_del (file, verify)  /* 'verify' is ignored--only used so programs won't */
  839. int     file, verify;  /* compile if mb_del is confused with mb_rmv        */
  840. {
  841.    long     int  to_die,   last,  pos;
  842.    int           i,        acc;
  843.    char          temp[13], sidx[13];
  844.  
  845.    if (file < 0 || file > MAX_REL)       return INVALID_FILE_CODE;
  846.    if (_list[file].pos == -1)            return NOT_OPEN;
  847.  
  848.    lseek ((acc = _list[file].relcode), _num_recs (file), 0);
  849.    read  (acc, temp, 4);
  850.  
  851.    if ((to_die = _list[file].pos) <= 0)  return NO_CURRENT_RECORD;
  852.    if ((last   = _eval (temp, 4)) == 0)  return NO_CURRENT_RECORD;
  853.    if (_set_lck (acc, 1) != 0)           return RELATION_HUNG;
  854.  
  855.    for (i = 0; i < _list[file].num_idx; i++)  _disconnect (file, i, to_die);
  856.  
  857.    if (last != to_die)
  858.     { lseek (acc, _base (file, last),   0);  read  (acc, buffer, _len (file));
  859.       lseek (acc, _base (file, to_die), 0);  write (acc, buffer, _len (file));
  860.  
  861.       strcpy (sidx, _encode (to_die, 4));
  862.  
  863.       for (i = 0; i < _list[file].num_idx; i++)
  864.        { if ((pos = _eval (&buffer[13*i+8], 4)) == 0)
  865.             lseek (acc, _t_top (file, i), 0);
  866.          else
  867.           { lseek (acc, _l_ptr (file, i, pos), 0);  read (acc, temp, 4);
  868.  
  869.             if (_eval (temp, 4) == last)  lseek (acc, -4L, 1);
  870.           };
  871.          write (acc, sidx, 4);
  872.  
  873.          if ((pos = _eval (&buffer[13*i],   4)) != 0)
  874.           { lseek (acc, _b_ptr (file, i, pos), 0);  write (acc, sidx, 4); };
  875.          if ((pos = _eval (&buffer[13*i+4], 4)) != 0)
  876.           { lseek (acc, _b_ptr (file, i, pos), 0);  write (acc, sidx, 4); };
  877.        };
  878.     };
  879.  
  880.    strcpy (temp, _encode (last-1, 4));
  881.  
  882.    lseek  (acc, _num_recs (file), 0);  write (acc, temp, 4);
  883.  
  884.    _clr_lck (acc);
  885.  
  886.    _list[file].pos = 0;
  887.  
  888.    return OKAY;
  889. }
  890.  
  891. _move (file, i, self, targ, child, dad, dch, dir, sidx)
  892. int    file, i,                         dch, dir;
  893. long            self, targ, child, dad;
  894. char                                             *sidx;
  895. {
  896.    long int  pos;
  897.    int       acc;
  898.    char      temp[13], ltgt[5];
  899.  
  900.    acc = _list[file].relcode;
  901.  
  902.    sprintf (temp, "%-12.12s", sidx);
  903.  
  904.    if (dch == 1)
  905.       change (&temp[dir], _encode (child, 4), 4);
  906.    else
  907.     { if (child != 0)
  908.        { lseek (acc, _b_ptr  (file, i, child), 0);
  909.          write (acc, _encode (dad,  4),        4);
  910.        };
  911.  
  912.       if (dad != 0)  lseek (acc, _l_ptr (file, i, dad) + 4 - dir, 0);
  913.       else           lseek (acc, _t_top (file, i),                0);
  914.  
  915.       write (acc, _encode (child, 4), 4);
  916.     };
  917.  
  918.    lseek (acc, _l_ptr (file, i, targ), 0);  write (acc, temp, 12);
  919.  
  920.    if ((pos = _eval (&temp[8], 4)) == 0)
  921.       lseek (acc, _t_top (file, i), 0);
  922.    else
  923.     { lseek (acc, _l_ptr (file, i, pos), 0);  read (acc, ltgt, 4);
  924.  
  925.       if (_eval (ltgt, 4) == self)  lseek (acc, -4L, 1);
  926.     };
  927.  
  928.    strcpy (ltgt, _encode (targ, 4));  write (acc, ltgt, 4);
  929.  
  930.    if ((pos = _eval (&temp[0], 4)) != 0)
  931.     { lseek (acc, _b_ptr (file, i, pos), 0);  write (acc, ltgt, 4); };
  932.  
  933.    if ((pos = _eval (&temp[4], 4)) != 0)
  934.     { lseek (acc, _b_ptr (file, i, pos), 0);  write (acc, ltgt, 4); };
  935. }
  936.  
  937. _disconnect (file, i, to_die)
  938. int          file, i;
  939. long int              to_die;
  940. {
  941.    int           acc;
  942.    int           level_n,  dch_n,   level_p,  dch_p;
  943.    long     int  rch,      pos,     targ_n,  targ_p, lch;
  944.    long     int  dad_n,    dad_p;
  945.    char          sidx[13], temp[13];
  946.  
  947.    acc = _list[file].relcode;
  948.  
  949.    lseek (acc, _l_ptr (file, i, to_die), 0);  read (acc, sidx, 12);
  950.  
  951.    level_n = level_p = 0;
  952.  
  953.    for (pos = targ_n = _eval (&sidx[4], 4); pos != 0; level_n++)
  954.     { lseek (acc, _l_ptr (file, i, pos), 0);  read (acc, temp, 4);
  955.  
  956.       targ_n = pos;  pos = _eval (temp, 4);
  957.     };
  958.  
  959.    if (level_n != 0)
  960.     { lseek (acc, _l_ptr (file, i, targ_n), 0);  read (acc, temp, 12);
  961.  
  962.       rch   = _eval (&temp[4], 4);
  963.       dad_n = _eval (&temp[8], 4);
  964.       dch_n = (level_n == 1) ? 1 : 0;
  965.  
  966.       for (pos = rch; pos != 0; level_n++)
  967.        { lseek (acc, _r_ptr (file, i, pos), 0);  read (acc, temp, 4);
  968.  
  969.          pos = _eval (temp, 4);
  970.        };
  971.     };
  972.  
  973.    for (pos = targ_p = _eval (&sidx[0], 4); pos != 0; level_p++)
  974.     { lseek (acc, _r_ptr (file, i, pos), 0);  read (acc, temp, 4);
  975.  
  976.       targ_p = pos;  pos = _eval (temp, 4);
  977.     };
  978.  
  979.    if (level_p != 0)
  980.     { lseek (acc, _l_ptr (file, i, targ_p), 0);  read (acc, temp, 12);
  981.  
  982.       lch   = _eval (&temp[0], 4);
  983.       dad_p = _eval (&temp[8], 4);
  984.       dch_p = (level_p == 1) ? 1 : 0;
  985.  
  986.       for (pos = lch; pos != 0; level_p++)
  987.        { lseek (acc, _l_ptr (file, i, pos), 0);  read (acc, temp, 4);
  988.  
  989.          pos = _eval (temp, 4);
  990.        };
  991.     };
  992.  
  993.    if (level_n == 0 && level_p == 0)
  994.     { if ((pos = _eval (&sidx[8], 4)) == 0)
  995.          lseek (acc, _t_top (file, i), 0);
  996.       else
  997.        { lseek (acc, _l_ptr (file, i, pos), 0);  read (acc, temp, 4);
  998.  
  999.          if (_eval (temp, 4) == to_die)  lseek (acc, -4L, 1);
  1000.        };
  1001.  
  1002.       write (acc, ZEROES, 4);
  1003.     }
  1004.    else
  1005.     { if (level_n >= level_p)
  1006.          _move (file, i, to_die, targ_n, rch, dad_n, dch_n, 4, sidx);
  1007.       else
  1008.          _move (file, i, to_die, targ_p, lch, dad_p, dch_p, 0, sidx);
  1009.     };
  1010. }
  1011.  
  1012. _clr_lck (acc)
  1013. int       acc;
  1014. {
  1015.    char   t[3];
  1016.    int    n;
  1017.  
  1018.    lseek   (acc, 0L, 0);  read  (acc, t, 1);
  1019.    n = fix (t[0]);        n = ((n > 127) ? (n-127) : n);  t[0] = n;
  1020.    lseek   (acc, 0L, 0);  write (acc, t, 1);
  1021. }
  1022.  
  1023. _set_lck (acc, set)
  1024. int       acc, set;
  1025. {
  1026.    char          t[3];
  1027.    int           n;
  1028.    register int  i;
  1029.  
  1030.    n = 0;
  1031.  
  1032.    do
  1033.     { lseek (acc, 0L, 0);  read (acc, t, 1);
  1034.  
  1035.       if (fix (t[0]) > 127)
  1036.        { if (n == 200)           return -1;
  1037.  
  1038.          for (i = 0, n++; i < 6000; i++);
  1039.        };
  1040.     } while (fix (t[0]) > 127);
  1041.  
  1042.    if (set == 1)
  1043.     { sprintf (t, "%c", fix (t[0]) + 127);
  1044.  
  1045.       lseek (acc, 0L, 0);  write (acc, t, 1);
  1046.     };
  1047.  
  1048.    return 0;
  1049. }
  1050.  
  1051. change  (one,  two,  num)
  1052. char    *one, *two;
  1053. int                  num;
  1054. {
  1055.    register int  i;
  1056.  
  1057.    for (i = num-1; i >= 0; i--)  one[i] = two[i];
  1058. }
  1059.  
  1060.