home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / CONTRIB / MBASE / MBASE51.TAR / mbase51 / src / mb_misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-04  |  26.0 KB  |  1,201 lines

  1. /*
  2.  * METALBASE 5.1
  3.  *
  4.  * Released January 1st, 1993 by Huan-Ti [ t-richj@microsoft.com ]
  5.  *
  6.  */
  7.  
  8. #include <mbase.h>
  9. #include "internal.h"
  10.  
  11.  
  12. /*
  13.  * PROTOTYPES -----------------------------------------------------------------
  14.  *
  15.  */
  16.  
  17.    static long   _append     XARGS( (relation *, dataptr, bool) );
  18.    static mb_err _check_dup  XARGS( (relation *, dataptr, int, long) );
  19.    static mb_err _queue_dup  XARGS( (relation *, dataptr, int, long) );
  20.    static mb_err _delete     XARGS( (relation *, long) );
  21.    static long   _find_ends  XARGS( (relation *, int, int) );
  22.    static mb_err _format     XARGS( (relation *, dataptr, int) );
  23.    static mb_err _link       XARGS( (relation *, long) );
  24.    static mb_err _remove     XARGS( (relation *, long) );
  25.    static mb_err _remove_q   XARGS( (relation *, long) );
  26.    static long   _search     XARGS( (relation *, int, mb_action, dataptr) );
  27.    static long   _find_que   XARGS( (relation *, mb_action) );
  28.    static bool   _isqueue    XARGS( (relation *) );
  29.    static mb_err _roll_queue XARGS( (relation *, bool) );
  30.  
  31.  
  32. /*
  33.  * ROUTINES -------------------------------------------------------------------
  34.  *
  35.  */
  36.  
  37. void
  38. SetError (err)
  39. mb_err    err;
  40. {
  41.    bool  fNotify = FALSE;
  42.  
  43. /*
  44.  * Only send the message if we're initializing the error code--we may run
  45.  * through this routine more than once if we're just propogating an error
  46.  * message up to the top level.
  47.  *
  48.  */
  49.  
  50.    if (err != MB_OKAY && err != mb_errno)
  51.       {
  52.       fNotify = TRUE;
  53.       }
  54.  
  55.    switch (mb_errno = err)
  56.       {
  57.       case MB_OKAY:     mb_error="no error";                             break;
  58.       case MB_NO_ROOM:  mb_error="MAX_REL is #defined to be too small";  break;
  59.       case MB_NO_MEMORY:mb_error="not enough memory for requested task"; break;
  60.       case MB_NO_OPEN:  mb_error="cannot open given filename";           break;
  61.       case MB_NO_READ:  mb_error="cannot read given filename";           break;
  62.       case MB_FORMAT:   mb_error="relation is not in MB 5.0+ format";    break;
  63.       case MB_LOCKED:   mb_error="relation is locked by another user";   break;
  64.       case MB_BUSY:     mb_error="relation is too busy";                 break;
  65.       case MB_BAD_REL:  mb_error="function passed bad relation struct";  break;
  66.       case MB_NO_WRITE: mb_error="cannot write to given relation";       break;
  67.       case MB_BAD_ARG:  mb_error="one or more arguments are not valid";  break;
  68.       case MB_BAD_REC:  mb_error="a null rec pointer has been received"; break;
  69.       case MB_CORRUPT:  mb_error="a corrupt index has been detected";    break;
  70.       case MB_BAD_DUP:  mb_error="addition would violate a nodups index";break;
  71.       case MB_NO_CURR:  mb_error="current record required for operation";break;
  72.       case MB_BAD_IDX:  mb_error="the specified index does not exist";   break;
  73.       case MB_BAD_FLD:  mb_error="the specified field does not exist";   break;
  74.       case MB_NO_SUCH:  mb_error="the specified record can't be found";  break;
  75.       case MB_UNKNOWN:  mb_error="search command invalid";               break;
  76.       case MB_NO_FIELDS:  mb_error="the new relation has no fields";     break;
  77.       case MB_NO_INDICES: mb_error="the new relation has no indices";    break;
  78.       case MB_BAD_INDEX:  mb_error="the new index is invalid";           break;
  79.       case MB_BAD_FIELD:  mb_error="the new field is invalid";           break;
  80.       case MB_BAD_SERIAL: mb_error="the record's serial number changed"; break;
  81.       case MB_DUP_SERIAL: mb_error="only one serial field allowed";      break;
  82.       case MB_DISKFULL: mb_error="there is not enough free space left";  break;
  83.       case MB_TMPDIR:   mb_error="you must define a TMP directory";      break;
  84.       case MB_TMPERR:   mb_error="cannot work with temporary file";      break;
  85.       case MB_STRUCT:   mb_error="unrecognized structure alignment";     break;
  86.       case MB_ABORTED:  mb_error="operation aborted by request";         break;
  87.       case MB_NO_QUEUE: mb_error="there are no records in queue";        break;
  88.       case MB_NO_DATA:  mb_error="the relation's .DAT file is missing";  break;
  89.       case MB_ASSERT:   mb_error="a logical assertion has failed!";      break;
  90.       case MB_BAD_DATA: mb_error="a corrupt datafile has been detected"; break;
  91.       case MB_ENCRYPT:  mb_error="the encryption key used is invalid";   break;
  92.       case MB_BAD_LEN:  mb_error="the new field must have a length";     break;
  93.       default:          mb_error="undefined error--rebuild and pray";    break;
  94.       }
  95.  
  96.    if (fNotify)
  97.       {
  98.       CallService (svcERROR);
  99.       }
  100. }
  101.  
  102.  
  103. /*
  104.  * SERVICE ROUTINES -----------------------------------------------------------
  105.  *
  106.  */
  107.  
  108. static mb_err
  109. _link    (rel, rcd)   /* CACHED */
  110. relation *rel;
  111. long           rcd;
  112. {
  113.    register int  idx;
  114.  
  115.    _free_cache ();
  116.  
  117.    if (_isqueue (rel))
  118.       {
  119.       Error (MB_OKAY);
  120.       }
  121.  
  122.    for (idx = 0; idx < rel->nIdx; idx++)
  123.       {
  124.       if (_drop (rel, rcd, idx, 0L))
  125.          {
  126.          Error (mb_errno);
  127.          }
  128.       if (_check (rel, rcd, 0L, idx))
  129.          {
  130.          _flush_cache (rel, idx);
  131.          Error (mb_errno);
  132.          }
  133.  
  134.       _flush_cache (rel, idx);
  135.       }
  136.  
  137.    SetError (MB_OKAY);
  138.  
  139. lblERROR:
  140.    return mb_errno;
  141. }
  142.  
  143. static mb_err
  144. _remove  (rel, bad)
  145. relation *rel;
  146. long           bad;
  147. {
  148.    int      idx, dir;
  149.    long     rep, tmp;
  150.    char     bal;
  151.    dataptr  dat;
  152.  
  153.  
  154. /*
  155.  * This routine simply moves the last record in the primary heap over the
  156.  * record which is to be deleted, and adjusts all pointers to that replacement
  157.  * record's new position.  Thus, if the record to be deleted is already at
  158.  * the end of the heap, there's nothing to do.
  159.  *
  160.  */
  161.  
  162.    lseek (rel->fhRel, POS_NUMREC, 0);
  163.    readx (rel->fhRel, &rep, 4);
  164.  
  165.    if (rep == bad)
  166.       {
  167.       Error_2 (MB_OKAY);
  168.       }
  169.    if ((dat = (dataptr)malloc (rel->cbRecord + cbINDEX* rel->nIdx +1)) == NULL)
  170.       {
  171.       Error (MB_NO_MEMORY);
  172.       }
  173.  
  174.    GO_START (rel, rep);
  175.    readx (rel->fhRel, dat, rel->cbRecord + cbINDEX* rel->nIdx);
  176.  
  177.    GO_START (rel, bad);
  178.    writx (rel->fhRel, dat, rel->cbRecord + cbINDEX* rel->nIdx);
  179.  
  180.    free (dat);
  181.  
  182.    for (idx = 0; idx < rel->nIdx; idx++)
  183.       {
  184.  
  185. /*
  186.  * On each index, first check for a parent record, and update it:
  187.  *
  188.  */
  189.  
  190.       GO_POINT (rel, rep, idx, 0);
  191.       readx (rel->fhRel, &tmp, 4);  /* Record # of this record's parent      */
  192.  
  193.       GO_BAL (rel, rep, idx);
  194.       readx (rel->fhRel, &bal, 1);  /* Balance and parent direction          */
  195.       dir = (bal & PARDIR);         /* (interested in parent direction only) */
  196.  
  197.       if (tmp == 0L)
  198.          GO_TOP (rel, idx);
  199.       else
  200.          GO_POINT (rel, tmp, idx, (dir ? 1 : -1));
  201.  
  202.       writx (rel->fhRel, &bad, 4);
  203.  
  204. /*
  205.  * Then check for a left-child:
  206.  *
  207.  */
  208.  
  209.       GO_POINT (rel, rep, idx, -1);
  210.       readx (rel->fhRel, &tmp, 4);
  211.       if (tmp != 0L)
  212.          {
  213.          GO_POINT (rel, tmp, idx, 0);
  214.          writx (rel->fhRel, &bad, 4);
  215.          }
  216.  
  217. /*
  218.  * Finally check for a right-child:
  219.  *
  220.  */
  221.  
  222.       GO_POINT (rel, rep, idx, 1);
  223.       readx (rel->fhRel, &tmp, 4);
  224.       if (tmp != 0L)
  225.          {
  226.          GO_POINT (rel, tmp, idx, 0);
  227.          writx (rel->fhRel, &bad, 4);
  228.          }
  229.       }
  230.  
  231.    SetError (MB_OKAY);
  232.  
  233.  
  234. lblERROR_2:
  235.    if (_roll_queue (rel, FALSE) != MB_OKAY)   /* Move queue inward, over rec */
  236.       {
  237.       Error (mb_errno)
  238.       }
  239.  
  240.    rep--;
  241.    lseek (rel->fhRel, POS_NUMREC, 0);
  242.    writx (rel->fhRel, &rep, 4);
  243.  
  244. lblERROR:
  245.    return mb_errno;
  246. }
  247.  
  248. static long
  249. _append  (rel, rec, fIndex)
  250. relation *rel;
  251. dataptr        rec;
  252. bool                fIndex;
  253. {
  254.    register int   idx;
  255.    long           rcd, temp;
  256.    char           bal;
  257.  
  258.  
  259.    if (fIndex)              /* Placing record before secondary (queue) heap? */
  260.       {
  261.       if (_roll_queue (rel, TRUE) != MB_OKAY)     /* Then move queue outward */
  262.          {
  263.          return 0L;
  264.          }
  265.       }
  266.  
  267.    lseek (rel->fhRel, (fIndex) ? POS_NUMREC : POS_NUMQUE, 0);
  268.    readx (rel->fhRel, &temp, 4);  temp++;
  269.    lseek (rel->fhRel, (fIndex) ? POS_NUMREC : POS_NUMQUE, 0);
  270.    writx (rel->fhRel, &temp, 4);
  271.  
  272.    if (fIndex)
  273.       rcd = temp;
  274.    else
  275.       {
  276.       lseek (rel->fhRel, POS_NUMREC, 0);
  277.       readx (rel->fhRel, &rcd, 4);
  278.       rcd += temp;
  279.       }
  280.  
  281.    GO_START (rel, rcd);
  282.  
  283.    temp = 0L;
  284.    bal = BAL_EV;
  285.  
  286.    for (idx = 0; idx < rel->nIdx; idx++)
  287.       {
  288.       writx (rel->fhRel, &temp, 4);  /* Write left-child as 0 (none)         */
  289.       writx (rel->fhRel, &temp, 4);  /* Write right-child as 0 (none)        */
  290.       writx (rel->fhRel, &temp, 4);  /* Write parent as 0 (top of tree)      */
  291.       writx (rel->fhRel, &bal,  1);  /* Write parent as right, balanced even */
  292.       }
  293.  
  294.    if (_recWrite (rel, rec, rcd) != MB_OKAY)      /* Write the record's data */
  295.       {
  296.       return 0L;
  297.       }
  298.  
  299.    return rcd;
  300. }
  301.  
  302. static mb_err
  303. _check_dup (rel, rec, idx, ign)
  304. relation   *rel;
  305. dataptr          rec;
  306. int                   idx;
  307. long                       ign;   /* ign == "ignore"--we'll skip this record */
  308. {
  309.    dataptr  mem;
  310.    long     pos;
  311.    int      dir;
  312.  
  313.    if (rel->fDups[idx] == TRUE || fSerialIdx(rel,idx))
  314.       {
  315.       Error (MB_OKAY);
  316.       }
  317.  
  318.    GO_TOP (rel, idx);
  319.    readx (rel->fhRel, &pos, 4);
  320.  
  321.    if ((mem = (dataptr)malloc (rel->cbRecord +1)) == (dataptr)0)
  322.       {
  323.       Error (mb_errno);
  324.       }
  325.  
  326.    for ( ; pos != 0L; )
  327.       {
  328.       dir = _compare (rel, rec, _memrec(rel,mem,pos), idx);
  329.  
  330.       if (dir == 0)       /* Found a matching record?  It might be a problem */
  331.          {
  332.          if (pos == ign)  /* (unless, of course, we just found the record    */
  333.             break;        /* that we're about to update.  Then it's okay).   */
  334.  
  335.          Error_2 (MB_BAD_DUP);
  336.          }
  337.  
  338.       GO_POINT (rel, pos, idx, dir);
  339.       readx (rel->fhRel, &pos, 4);
  340.       }
  341.  
  342.    SetError (MB_OKAY);
  343.  
  344. lblERROR_2:
  345.    free (mem);
  346.  
  347. lblERROR:
  348.    return mb_errno;
  349. }
  350.  
  351. static mb_err
  352. _format  (rel, rec, stage)
  353. relation *rel;
  354. dataptr        rec;
  355. int                 stage;
  356. {
  357.    register int fld;
  358.    charptr      pch;
  359.    long         nexts;
  360.  
  361.  
  362.    if (! rec)
  363.       {
  364.       Error (MB_BAD_REC);
  365.       }
  366.  
  367.    for (fld = 0; fld < rel->nFld; fld++)
  368.       {
  369.       pch = (char *)rec + rel->cbStart[fld];
  370.  
  371.       switch (stage)
  372.          {
  373.  
  374. /*
  375.  * During stage 1, we've just received a record structure from the user, and
  376.  * have to process it to ensure it's in the correct format to be stored
  377.  * permanently.
  378.  *
  379.  */
  380.  
  381.          case 1:  switch (rel->fldType[fld])
  382.                      {
  383.                      case T_MONEY:
  384.                         *(double *)pch = tomoney( *(double *)pch );
  385.                        break;
  386.                      }
  387.                  break;
  388.  
  389. /*
  390.  * During stage 2, the entire record is already encrypted, and we're sure that
  391.  * the add is going to take place (stage 2 is only called for add operations).
  392.  * So after we set the serial field, we have to reencrypt just that field.
  393.  * Note that, as always, we expect there to be no more than one serial field...
  394.  *
  395.  */
  396.  
  397.          case 2:  switch (rel->fldType[fld])
  398.                      {
  399.                      case T_SERIAL:
  400.                         GO_NEXTS (rel);
  401.                         readx    (rel->fhRel, &nexts, 4);
  402.  
  403.                         *(long *)pch = rel->serial = nexts;
  404.                         _encryptf (pch, 4, rel->mask);
  405.  
  406.                         nexts++;
  407.                         GO_NEXTS (rel);
  408.                         writx    (rel->fhRel, &nexts, 4);
  409.                        break;
  410.                      }
  411.                  break;
  412.          }
  413.       }
  414.  
  415.    SetError (MB_OKAY);
  416.  
  417. lblERROR:
  418.    return mb_errno;
  419. }
  420.  
  421. static mb_err
  422. _delete  (rel, bad)  /* CACHED */
  423. relation *rel;
  424. long           bad;
  425. {
  426.    static   int  lastmove = -1;
  427.    register int  idx;
  428.    long          bp, rep, rp;
  429.    int           bal;
  430.    cache        *ptr;
  431.  
  432.  
  433.    if (rel->fMulti)
  434.       {
  435.       if (_remove_m (rel, bad) != MB_OKAY)
  436.          {
  437.          Error (mb_errno);
  438.          }
  439.       }
  440.  
  441. /*
  442.  * This routine removes the given record from the index tree; its parents
  443.  * and children are reassigned and the tree rebalanced.  Of course, if the
  444.  * record being deleted is in the queue, there's no reason to do this at
  445.  * all...
  446.  *
  447.  */
  448.  
  449.    if (_isqueue (rel))
  450.       {
  451.       Error (MB_OKAY);
  452.       }
  453.  
  454.    _free_cache ();
  455.  
  456.    for (idx = 0; idx < rel->nIdx; idx++)
  457.       {
  458.       ptr = _read_cache (rel, bad, idx);
  459.       bp  = ptr->parent;
  460.       bal = ptr->parbal & BAL;
  461.  
  462.       if (bal != BAL_EV)
  463.          rep = _find_seq (rel, bad, bad, idx, NUM_BAL(bal));
  464.       else
  465.          {
  466.          lastmove = 0 - lastmove;
  467.          if (! (rep = _find_seq (rel, bad, bad, idx, lastmove)))
  468.             {
  469.             lastmove = 0 - lastmove;
  470.             rep = _find_seq (rel, bad, bad, idx, lastmove);
  471.             }
  472.          }
  473.  
  474.       if (! rep)
  475.          {
  476.          _dislink (rel, bad, idx, 0L);
  477.          }
  478.       else
  479.          {
  480.          ptr = _read_cache (rel, rep, idx);
  481.          rp = ptr->parent;
  482.  
  483.          _dislink (rel, rep, idx, 0L);
  484.          _replace (rel, bad, rep, idx);
  485.  
  486.          if (rp != bad)
  487.             {
  488.             if (_check (rel, rp, bp, idx))
  489.                {
  490.                _flush_cache (rel, idx);
  491.                Error (mb_errno);
  492.                }
  493.             }
  494.          }
  495.  
  496.       if (_check (rel, bp, 0L, idx))
  497.          {
  498.          _flush_cache (rel, idx);
  499.          Error (mb_errno);
  500.          }
  501.  
  502.       _flush_cache (rel, idx);
  503.       }
  504.  
  505.    SetError (MB_OKAY);
  506.  
  507. lblERROR:
  508.    return mb_errno;
  509. }
  510.  
  511. static long
  512. _search  (rel, idx, act, comp)  /* CACHED */
  513. relation *rel;
  514. int            idx;
  515. mb_action           act;
  516. dataptr                  comp;
  517. {
  518.    long     pos, last;
  519.    dataptr  rec;
  520.    cache   *ptr;
  521.    int      dir;
  522.  
  523.  
  524.    if ((rec = (dataptr)malloc (rel->cbRecord +1)) == NULL)
  525.       {
  526.       return 0L;   /* Appropriate error has been already set */
  527.       }
  528.  
  529.    _strobe  (rel, 0);
  530.  
  531.    ptr = _read_cache (rel, 0L, idx);
  532.    pos = ptr->num;
  533.  
  534.    for (last = 0L; pos != 0L; )
  535.       {
  536.       _strobe (rel, 0);                 /* Don't let anyone think we're dead */
  537.  
  538.       ptr = _read_cache (rel, pos, idx);
  539.       _memrec (rel, rec, pos);
  540.  
  541.       dir = _compare (rel, rec, comp, idx);  /* -1 == look right */
  542.  
  543. /*
  544.  * Is it a valid record?  If so, set {last} to the record number.
  545.  *
  546.  */
  547.       switch (act)
  548.          {
  549.          case LTHN:  if (dir <   0)  last = pos;   break;
  550.          case LTEQ:  if (dir <=  0)  last = pos;   break;
  551.          case EQUL:  if (dir ==  0)  last = pos;   break;
  552.          case GTEQ:  if (dir >=  0)  last = pos;   break;
  553.          case GTHN:  if (dir >   0)  last = pos;   break;
  554.          }
  555.  
  556. /*
  557.  * Which way should we look if we found a matches-the-comparison-record record?
  558.  * This is to ensure clean handling of duplicate values (otherwise we'd just
  559.  * return now, instead of setting 'last' and continuing the search.
  560.  *
  561.  */
  562.       if (dir == 0)
  563.          {
  564.          if (act == GTHN || act == LTEQ)                 dir = -1;
  565.          if (act == GTEQ || act == LTHN || act == EQUL)  dir =  1;
  566.          }
  567.  
  568.       pos = (dir == -1) ? ptr->right : ptr->left;
  569.       }
  570.  
  571.    free (rec);
  572.  
  573.    return last;
  574. }
  575.  
  576. static long
  577. _find_ends (rel, idx, dir)  /* CACHED */
  578. relation   *rel;
  579. int              idx, dir;
  580. {
  581.    long    pos, tmp;
  582.    cache  *ptr;
  583.  
  584.    ptr = _read_cache (rel, 0L, idx);
  585.  
  586.    if ((pos = ptr->num) == 0L)
  587.       {
  588.       return 0L;
  589.       }
  590.  
  591.    for (tmp = pos; ; pos = tmp)
  592.       {
  593.       _strobe (rel, 0);  /* Don't let anyone think we're dead */
  594.  
  595.       ptr = _read_cache (rel, tmp, idx);
  596.       tmp = _cache_field (ptr, dir);
  597.  
  598.       if (tmp == 0L)  return pos;
  599.       }
  600. }
  601.  
  602.  
  603. /*
  604.  * PRIMARY ROUTINES -----------------------------------------------------------
  605.  *
  606.  */
  607.  
  608. mb_err
  609. mb_addfn (rel, rec, fIndex)
  610. relation *rel;
  611. dataptr        rec;
  612. bool                fIndex;
  613. {
  614.    int     idx;
  615.    long    rcd;
  616.  
  617.  
  618.    if (_identify (rel) < 0)    Error (MB_BAD_REL);
  619.  
  620.    if (rel->fReadOnly)         Error (MB_NO_WRITE);
  621.  
  622.    if (_format (rel, rec, 1))  Error (mb_errno);
  623.  
  624.    if (_set_lck (rel))         Error (mb_errno);
  625.  
  626.    if (_chk_elck (rel, TRUE))  Error_2 (mb_errno);
  627.  
  628.  
  629.    _encrypt (rel, rec);
  630.  
  631.    for (idx = 0; idx < rel->nIdx; idx++)
  632.       {
  633.       if (_check_dup (rel, rec, idx, 0L))
  634.          {
  635.          Error_3 (mb_errno);
  636.          }
  637.       if (_queue_dup (rel, rec, idx, 0L))
  638.          {
  639.          Error_3 (mb_errno);
  640.          }
  641.       }
  642.  
  643.  
  644.    (void)_format (rel, rec, 2);          /* Set serial number (if necessary) */
  645.  
  646.    if (! (rcd = _append (rel, rec, fIndex)))
  647.       {
  648.       Error_3 (mb_errno);
  649.       }
  650.  
  651.    if (fIndex)
  652.       {
  653.       if (_link (rel, rcd) != MB_OKAY)
  654.          {
  655.          Error_3 (mb_errno);
  656.          }
  657.       }
  658.  
  659.    rel->pos = rcd;
  660.  
  661.    SetError (MB_OKAY);
  662.  
  663. lblERROR_3:
  664.    _decrypt (rel, rec);
  665.  
  666. lblERROR_2:
  667.    _clr_lck (rel);
  668.  
  669. lblERROR:
  670.    return mb_errno;
  671. }
  672.  
  673. mb_err
  674. mb_upd   (rel, rec)
  675. relation *rel;
  676. dataptr        rec;
  677. {
  678.    int     idx;
  679.    long    rcd;
  680.  
  681.  
  682.    if (_identify (rel) < 0)     Error (MB_BAD_REL);
  683.  
  684.    if (rel->fReadOnly)          Error (MB_NO_WRITE);
  685.  
  686.    if (_format (rel, rec, 1))   Error (mb_errno);
  687.  
  688.    if (_set_lck (rel))          Error (mb_errno);
  689.  
  690.    if (_chk_elck (rel, TRUE))   Error_2 (mb_errno);
  691.  
  692.    if ((rcd = rel->pos) == 0L)  Error_2 (MB_NO_CURR);
  693.  
  694.  
  695.    if (rel->iSerial < rel->nFld)
  696.       {
  697.       if (*(long *)((char *)rec + rel->cbStart [rel->iSerial]) != rel->serial)
  698.          {
  699.          Error_2 (MB_BAD_SERIAL);
  700.          }
  701.       }
  702.  
  703.    _encrypt (rel, rec);
  704.  
  705.    for (idx = 0; idx < rel->nIdx; idx++)
  706.       {
  707.       if (_check_dup (rel, rec, idx, rcd))
  708.          {
  709.          Error_3 (mb_errno);
  710.          }
  711.       if (_queue_dup (rel, rec, idx, rcd))
  712.          {
  713.          Error_3 (mb_errno);
  714.          }
  715.       }
  716.  
  717.    if (_delete (rel, rcd) != MB_OKAY)
  718.       {
  719.       Error_3 (mb_errno);
  720.       }
  721.  
  722.    _recWrite (rel, rec, rcd);
  723.  
  724.    if (_link (rel, rcd))
  725.       {
  726.       Error_3 (mb_errno);
  727.       }
  728.  
  729.    SetError (MB_OKAY);
  730.  
  731. lblERROR_3:
  732.    _decrypt (rel, rec);
  733.  
  734. lblERROR_2:
  735.    _clr_lck (rel);
  736.  
  737. lblERROR:
  738.    return mb_errno;
  739. }
  740.  
  741. mb_err
  742. mb_del   (rel)
  743. relation *rel;
  744. {
  745.    if (_identify (rel) < 0)    Error (MB_BAD_REL);
  746.  
  747.    if (rel->fReadOnly)         Error (MB_NO_WRITE);
  748.  
  749.    if (rel->pos == 0L)         Error (MB_NO_CURR);
  750.  
  751.    if (_set_lck (rel))         Error (mb_errno);
  752.  
  753.    if (_chk_elck (rel, TRUE))  Error_2 (mb_errno);
  754.  
  755.  
  756.    if (_delete (rel, rel->pos) != MB_OKAY)
  757.       {
  758.       Error_2 (mb_errno);
  759.       }
  760.  
  761.    if (_isqueue (rel))
  762.       {
  763.       if (_remove_q (rel, rel->pos) != MB_OKAY)
  764.          {
  765.          Error_2 (mb_errno);
  766.          }
  767.       }
  768.    else
  769.       {
  770.       if (_remove (rel, rel->pos) != MB_OKAY)
  771.          {
  772.          Error_2 (mb_errno);
  773.          }
  774.       }
  775.  
  776.    rel->pos = 0L;
  777.  
  778.    SetError (MB_OKAY);
  779.  
  780. lblERROR_2:
  781.    _clr_lck (rel);
  782.  
  783. lblERROR:
  784.    return mb_errno;
  785. }
  786.  
  787. mb_err
  788. mb_sel   (rel, idx, buf, act, comp)
  789. relation *rel;
  790. int            idx;
  791. mb_action                act;
  792. dataptr             buf,      comp;
  793. {
  794.    dataptr rec = NULL;  /* Comparison record (==comp if comp!=NULL) */
  795.    long    off;
  796.    bool    fComplex = FALSE;
  797.  
  798.  
  799.    if (_identify (rel) < 0)          Error (MB_BAD_REL);
  800.  
  801.    if (idx < 0 || idx >= rel->nIdx)  Error (MB_BAD_IDX);
  802.  
  803.    if (_set_lck (rel))               Error (mb_errno);
  804.  
  805.    if (_chk_elck (rel, FALSE))       Error_2 (mb_errno);
  806.  
  807. /*
  808.  * Determine the comparison record to use...
  809.  *
  810.  */
  811.  
  812.    if ( (act == GTEQ) || (act == GTHN) ||
  813.         (act == LTEQ) || (act == LTHN) || (act == EQUL) )
  814.       {
  815.       fComplex = TRUE;
  816.  
  817.       if (comp != NULL)
  818.          {
  819.          rec = comp;
  820.          }
  821.       else
  822.          {
  823.          if ((rec = (dataptr)malloc (rel->cbRecord +1)) == (dataptr)0)
  824.             {
  825.             Error_2 (mb_errno);
  826.             }
  827.  
  828.          numcpy (rec, buf, rel->cbRecord);
  829.          }
  830.       }
  831.  
  832.    if (fComplex)
  833.       {
  834.       _encrypt (rel, rec);  /* The comparison buffer must be encrypted */
  835.       }
  836.  
  837.  
  838. /*
  839.  * And then determine the requested action.
  840.  *
  841.  */
  842.  
  843.    if (rel->pos == 0L)
  844.       {
  845.       if (act == NEXT)  act = FRST;
  846.       if (act == PREV)  act = LAST;
  847.       }
  848.  
  849.    _free_cache ();
  850.  
  851.    if (_isqueue (rel))
  852.       {
  853.       switch (act)
  854.          {
  855.          case NEXT:  act = NQUE;  break;
  856.          case PREV:  act = PQUE;  break;
  857.          }
  858.       }
  859.  
  860.    switch (act)
  861.       {
  862.       case FRST:
  863.       case LAST:  off = _find_ends (rel, idx, (act == FRST) ? -1 : 1);
  864.                  break;
  865.  
  866.       case CURR:  off = rel->pos;
  867.                  break;
  868.  
  869.       case NEXT:
  870.       case PREV:  off = _find_seq (rel, 0L, rel->pos, idx, (act == NEXT)?1:-1);
  871.                  break;
  872.  
  873.       case NQUE:
  874.       case PQUE:
  875.       case FQUE:
  876.       case LQUE:  off = _find_que (rel, act);
  877.                  break;
  878.  
  879.       case GTEQ:
  880.       case GTHN:
  881.       case LTEQ:
  882.       case LTHN:
  883.       case EQUL:  off = _search (rel, idx, act, rec);
  884.                  break;
  885.  
  886.       default  :  Error_3 (MB_UNKNOWN);
  887.                  break;
  888.       }
  889.  
  890.    if (mb_errno != MB_OKAY)  Error_3 (mb_errno);
  891.  
  892.    if (off == 0L)            Error_3 (MB_NO_SUCH);
  893.  
  894.  
  895.    if (recClean (rel, buf) != MB_OKAY)     /* Ensure we will have a place to */
  896.       Error_3 (mb_errno);                  /* put multi-length fields        */
  897.  
  898.  
  899.    rel->pos = off;
  900.  
  901.    _memrec  (rel, buf, rel->pos);    /* Read in the output buffer, encrypted */
  902.    _decrypt (rel, buf);              /* Decrypt the output buffer            */
  903.  
  904.    if (_recFill (rel, buf) != MB_OKAY)
  905.       {
  906.       Error_3 (mb_errno);
  907.       }
  908.  
  909.    if (rel->pos && rel->iSerial < rel->nFld)
  910.       {
  911.       rel->serial = *(long *)((char *)buf + rel->cbStart[rel->iSerial]);
  912.       }
  913.  
  914.    SetError (MB_OKAY);
  915.  
  916.  
  917. lblERROR_3:
  918.    if (fComplex && comp != NULL)
  919.       {
  920.       _decrypt (rel, comp);   /* Re-decrypt the compare buffer, if given one */
  921.       }
  922.  
  923. lblERROR_2:
  924.    if (fComplex && comp == NULL && rec)
  925.       {
  926.       free (rec);          /* otherwise, free the comp buffer we created     */
  927.       }
  928.  
  929.    _clr_lck (rel);
  930.  
  931. lblERROR:
  932.    return mb_errno;
  933. }
  934.  
  935. long
  936. mb_num   (rel)
  937. relation *rel;
  938. {
  939.    long    x, y;
  940.  
  941.    if (_identify (rel) < 0)  Error (MB_BAD_REL);
  942.  
  943.    lseek (rel->fhRel, POS_NUMREC, 0);
  944.    readx (rel->fhRel, &x, 4);            /* Doesn't include non-indexed recs */
  945.    lseek (rel->fhRel, POS_NUMQUE, 0);
  946.    readx (rel->fhRel, &y, 4);
  947.  
  948.    SetError (MB_OKAY);
  949.  
  950. lblERROR:
  951.    return (mb_errno == MB_OKAY) ? (x+y) : -1L;
  952. }
  953.  
  954.  
  955. /*
  956.  * DEFERRED-INDEXING ROUTINES -------------------------------------------------
  957.  *
  958.  */
  959.  
  960. long
  961. mb_num_q (rel)
  962. relation *rel;
  963. {
  964.    long    x;
  965.  
  966.    if (_identify (rel) < 0)  Error (MB_BAD_REL);
  967.  
  968.    lseek (rel->fhRel, POS_NUMQUE, 0);
  969.    readx (rel->fhRel, &x, 4);
  970.  
  971.    SetError (MB_OKAY);
  972.  
  973. lblERROR:
  974.    return (mb_errno == MB_OKAY) ? x : -1L;
  975. }
  976.  
  977. static long
  978. _find_que (rel, act)
  979. relation  *rel;
  980. mb_action       act;
  981. {
  982.    long   numrec, numque, targ;
  983.  
  984.    lseek (rel->fhRel, POS_NUMREC, 0);
  985.    readx (rel->fhRel, &numrec, 4);       /* Doesn't include non-indexed recs */
  986.    lseek (rel->fhRel, POS_NUMQUE, 0);
  987.    readx (rel->fhRel, &numque, 4);
  988.  
  989.    switch (act)
  990.       {
  991.       case FQUE:  targ = numrec +1;        break;
  992.       case LQUE:  targ = numrec + numque;  break;
  993.       case NQUE:  targ = rel->pos +1;      break;
  994.       case PQUE:  targ = rel->pos -1;      break;
  995.       }
  996.  
  997.    if ((targ <= numrec) || (targ > numrec+numque))
  998.       return 0L;
  999.  
  1000.    return targ;
  1001. }
  1002.  
  1003. static mb_err
  1004. _remove_q (rel, trg)
  1005. relation  *rel;
  1006. long            trg;
  1007. {
  1008.    dataptr dat;
  1009.    long    numrec, numque, org;
  1010.  
  1011.    lseek (rel->fhRel, POS_NUMREC, 0);
  1012.    readx (rel->fhRel, &numrec, 4);
  1013.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1014.    readx (rel->fhRel, &numque, 4);
  1015.  
  1016.    org = numrec +numque;
  1017.  
  1018.    numque--;
  1019.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1020.    writx (rel->fhRel, &numque, 4);
  1021.  
  1022.    if ( (trg <= numrec) || (trg >= org) )
  1023.       {
  1024.       Error (MB_OKAY);
  1025.       }
  1026.  
  1027.    if (! (dat = (dataptr)malloc (rel->cbRecord + cbINDEX* rel->nIdx +1)) )
  1028.       {
  1029.       Error (MB_NO_MEMORY);
  1030.       }
  1031.  
  1032.    GO_START (rel, org);
  1033.    readx (rel->fhRel, dat, rel->cbRecord + cbINDEX* rel->nIdx);
  1034.    GO_START (rel, trg);
  1035.    writx (rel->fhRel, dat, rel->cbRecord + cbINDEX* rel->nIdx);
  1036.  
  1037.    free (dat);
  1038.  
  1039.    SetError (MB_OKAY);
  1040.  
  1041. lblERROR:
  1042.    return mb_errno;
  1043. }
  1044.  
  1045. static bool
  1046. _isqueue (rel)
  1047. relation *rel;
  1048. {
  1049.    long  num;
  1050.  
  1051.    lseek (rel->fhRel, POS_NUMREC, 0);
  1052.    readx (rel->fhRel, &num, 4);
  1053.  
  1054.    return (rel->pos > num) ? TRUE : FALSE;
  1055. }
  1056.  
  1057. static mb_err
  1058. _roll_queue (rel, fOutward)
  1059. relation    *rel;
  1060. bool              fOutward;
  1061. {
  1062.    dataptr dat;
  1063.    long    numrec, numque, org, trg;
  1064.  
  1065.    lseek (rel->fhRel, POS_NUMREC, 0);
  1066.    readx (rel->fhRel, &numrec, 4);
  1067.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1068.    readx (rel->fhRel, &numque, 4);
  1069.  
  1070.    if (fOutward)
  1071.       {
  1072.       org = numrec +1;
  1073.       trg = numrec +numque +1;
  1074.       }
  1075.    else
  1076.       {
  1077.       org = numrec +numque;
  1078.       trg = numrec;
  1079.       }
  1080.  
  1081.    if (org != trg)
  1082.       {
  1083.       if (! (dat = (dataptr)malloc (rel->cbRecord + cbINDEX* rel->nIdx +1)) )
  1084.          {
  1085.          Error (MB_NO_MEMORY);
  1086.          }
  1087.  
  1088.       GO_START (rel, org);
  1089.       readx (rel->fhRel, dat, rel->cbRecord + cbINDEX* rel->nIdx);
  1090.  
  1091.       GO_START (rel, trg);
  1092.       writx (rel->fhRel, dat, rel->cbRecord + cbINDEX* rel->nIdx);
  1093.  
  1094.       free (dat);
  1095.       }
  1096.  
  1097.    SetError (MB_OKAY);
  1098.  
  1099. lblERROR:
  1100.    return mb_errno;
  1101. }
  1102.  
  1103. static mb_err
  1104. _queue_dup (rel, rec, idx, ign)
  1105. relation   *rel;
  1106. dataptr          rec;
  1107. int                   idx;
  1108. long                       ign;
  1109. {
  1110.    dataptr  mem;
  1111.    long     pos, num;
  1112.  
  1113.  
  1114.    lseek (rel->fhRel, POS_NUMREC, 0);
  1115.    readx (rel->fhRel, &pos, 4);
  1116.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1117.    readx (rel->fhRel, &num, 4);
  1118.  
  1119.    if (rel->fDups[idx] == TRUE || fSerialIdx(rel,idx))
  1120.       {
  1121.       Error (MB_OKAY);
  1122.       }
  1123.  
  1124.    if ((mem = (dataptr)malloc (rel->cbRecord +1)) == NULL)
  1125.       {
  1126.       Error (mb_errno);
  1127.       }
  1128.  
  1129.    for (pos++; num; num--,pos++)
  1130.       {
  1131.       if (_compare (rel, rec, _memrec(rel,mem,pos), idx) == 0)
  1132.          {
  1133.          if (pos == ign)
  1134.             break;
  1135.  
  1136.          Error_2 (MB_BAD_DUP);
  1137.          }
  1138.       }
  1139.  
  1140.    SetError (MB_OKAY);
  1141.  
  1142. lblERROR_2:
  1143.    free (mem);
  1144.  
  1145. lblERROR:
  1146.    return mb_errno;
  1147. }
  1148.  
  1149. mb_err
  1150. mb_xfer  (rel)
  1151. relation *rel;
  1152. {
  1153.    long   num;
  1154.  
  1155.  
  1156.    if (_identify (rel) < 0)     Error (MB_BAD_REL);
  1157.  
  1158.    if (rel->fReadOnly)          Error (MB_NO_WRITE);
  1159.  
  1160.    if (_set_lck (rel))          Error (mb_errno);
  1161.  
  1162.    if (_chk_elck (rel, TRUE))   Error_2 (mb_errno);
  1163.  
  1164.  
  1165.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1166.    readx (rel->fhRel, &num, 4);
  1167.  
  1168.    if (! num)
  1169.       {
  1170.       Error_2 (MB_NO_QUEUE);
  1171.       }
  1172.  
  1173.    lseek (rel->fhRel, POS_NUMREC, 0);
  1174.    readx (rel->fhRel, &num, 4);
  1175.    num++;
  1176.  
  1177.    if (_link (rel, num))
  1178.       {
  1179.       Error_2 (mb_errno);
  1180.       }
  1181.  
  1182.    rel->pos = num;
  1183.  
  1184.    lseek (rel->fhRel, POS_NUMREC, 0);
  1185.    writx (rel->fhRel, &num, 4);
  1186.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1187.    readx (rel->fhRel, &num, 4); num--;
  1188.    lseek (rel->fhRel, POS_NUMQUE, 0);
  1189.    writx (rel->fhRel, &num, 4);
  1190.  
  1191.    SetError (MB_OKAY);
  1192.  
  1193.  
  1194. lblERROR_2:
  1195.    _clr_lck (rel);
  1196.  
  1197. lblERROR:
  1198.    return mb_errno;
  1199. }
  1200.  
  1201.