home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / CONTRIB / MBASE / MBASE51.TAR / mbase51 / src / mb_multi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-04  |  14.4 KB  |  734 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.  * COMPILE-TIME OPTIONS -------------------------------------------------------
  14.  *
  15.  * MIN_SIZE is the smallest free-block for which we'll create a header; because
  16.  * we only keep headers for each free segment, this helps keep down the length
  17.  * of the chain we'll have to follow later.  Too large and you waste space; too
  18.  * small and you'll get a fragmented heap, which will damage performance.  You
  19.  * must keep this at eight or more, or the header we write may overwrite the
  20.  * next block of text.
  21.  *
  22.  */
  23.  
  24. #define MIN_SIZE 128
  25.  
  26. /*
  27.  * PROTOTYPES -----------------------------------------------------------------
  28.  *
  29.  */
  30.  
  31.    static void    _fieldFree    XARGS( (relation *, dataptr, int) );
  32.  
  33.    static void    _recStore     XARGS( (relation *, dataptr) );
  34.    static void    _recRestore   XARGS( (relation *, dataptr) );
  35.  
  36.    static mb_err  _remove_fld   XARGS( (relation *, dataptr, int) );
  37.    static mb_err  _append_fld   XARGS( (relation *, dataptr, int) );
  38.  
  39.  
  40. /*
  41.  * VARIABLES ------------------------------------------------------------------
  42.  *
  43.  */
  44.  
  45. mchar  aMulti [MAX_MULTI];
  46.  
  47.  
  48. /*
  49.  * FIELD ROUTINES -------------------------------------------------------------
  50.  *
  51.  */
  52.  
  53. mb_err
  54. fieldInit (rel, rec, fld, name)
  55. relation  *rel;
  56. dataptr         rec;
  57. int                  fld;
  58. char                     *name;
  59. {
  60.    mchar *ptr;
  61.    int    num;
  62.    file   fh;
  63.  
  64.  
  65.    if ( (rel->fldType[fld] != T_MCHAR) && (rel->fldType[fld] != T_MBYTE) )
  66.       {
  67.       Error (MB_BAD_ARG);
  68.       }
  69.  
  70.    ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  71.    num = (name && *name) ? (1+strlen(name)) : 128;
  72.  
  73.    ptr->pos = 0L;
  74.  
  75.  
  76. /*
  77.  * First see if this record pointer has been used before.  If so, remove any
  78.  * temporary file and free the memory used for it...
  79.  *
  80.  */
  81.  
  82.    _fieldFree (rel, rec, fld);
  83.  
  84.  
  85. /*
  86.  * Now pick a name (unless one was given) and open the file.
  87.  *
  88.  */
  89.  
  90.    if ( (ptr->name = (char *)malloc (num)) == NULL )
  91.       {
  92.       Error (MB_NO_MEMORY);
  93.       }
  94.  
  95.    if (! name || ! *name)            /* If we didn't get a name, choose one. */
  96.       {
  97.       if (! *( GetTmpName(ptr->name) ))
  98.          {
  99.          Error_2 (MB_TMPDIR);
  100.          }
  101.       }
  102.  
  103.    if ( (fh = creatx (ptr->name)) <= 0 )
  104.       {
  105.       Error_2 (MB_TMPERR);
  106.       }
  107.    close (fh);
  108.  
  109.    SetError (MB_OKAY);
  110.    return MB_OKAY;
  111.  
  112.  
  113. lblERROR_2:
  114.    free ( ((mchar *)ptr)->name );
  115.    ((mchar *)ptr)->name = NULL;
  116.  
  117. lblERROR:
  118.    return mb_errno;
  119. }
  120.  
  121.  
  122. char *
  123. fieldFile (rel, rec, fld)
  124. relation  *rel;
  125. dataptr         rec;
  126. int                  fld;
  127. {
  128.    if (rel->fldType[fld] != T_MCHAR && rel->fldType[fld] != T_MBYTE)
  129.       {
  130.       Error (MB_BAD_ARG);
  131.       }
  132.    SetError (MB_OKAY);
  133.  
  134.    return ((mchar *)( (char *)rec + rel->cbStart[fld] ))->name;
  135.  
  136. lblERROR:
  137.    return NULL;
  138. }
  139.  
  140.  
  141. file
  142. fieldOpen (rel, rec, fld)
  143. relation  *rel;
  144. dataptr         rec;
  145. int                  fld;
  146. {
  147.    mchar *ptr;
  148.    file   fh;
  149.  
  150.    if (rel->fldType[fld] != T_MCHAR && rel->fldType[fld] != T_MBYTE)
  151.       {
  152.       Error (MB_BAD_ARG);
  153.       }
  154.    SetError (MB_OKAY);
  155.  
  156.    ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  157.    if ((fh = openx (ptr->name, OPENMODE)) <= 0)
  158.       {
  159.       SetError (MB_TMPERR);
  160.       fh = -1;
  161.       }
  162.  
  163.    return fh;
  164.  
  165. lblERROR:
  166.    return -1;
  167. }
  168.  
  169.  
  170. /*
  171.  * Free chain:
  172.  *
  173.  *   4 bytes:  Length of this free block (including 8-byte header)
  174.  *   4 bytes:  Pointer to next free block
  175.  *
  176.  * Used header:
  177.  *
  178.  *   4 bytes:  Length of this block (compressed, excluding 4-byte header)
  179.  *   variable: Compressed data
  180.  *
  181.  */
  182.  
  183. mb_err
  184. _fieldFill (rel, rec, fld)
  185. relation   *rel;
  186. dataptr          rec;
  187. int                   fld;
  188. {
  189.    mchar  *ptr;
  190.    long    len;
  191.    file    fh;
  192.  
  193.    ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  194.  
  195.    if (ptr->pos == 0L)
  196.       Error (MB_OKAY);
  197.  
  198.    if ((fh = openx (ptr->name, OPENMODE)) <= 0)
  199.       {
  200.       Error (MB_TMPERR);
  201.       }
  202.  
  203.    lseek (rel->fhDat, ptr->pos + 4L, 0);  /* Skip the first four bytes */
  204.  
  205.    while ((len = _fhDecompress (fh, rel->fhDat)) > 0L)  /* len== amt of data */
  206.       ;
  207.    Assert_Dat (len == 0L);     /* Anything else indicates a corrupt datafile */
  208.  
  209.    close (fh);
  210.  
  211.    SetError (MB_OKAY);
  212.  
  213. lblERROR:
  214.    return mb_errno;
  215. }
  216.  
  217.  
  218. static void
  219. _fieldFree (rel, rec, fld)
  220. relation   *rel;
  221. dataptr          rec;
  222. int                   fld;
  223. {
  224.    mchar *ptr;
  225.  
  226.    ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  227.  
  228.    if (ptr->name != NULL)
  229.       {
  230.       if (access (ptr->name, 0) != -1)
  231.          unlink (ptr->name);
  232.  
  233.       free (ptr->name);
  234.       ptr->name = NULL;
  235.       }
  236. }
  237.  
  238.  
  239. /*
  240.  * RECORD ROUTINES ------------------------------------------------------------
  241.  *
  242.  */
  243.  
  244. mb_err
  245. recClean (rel, rec)
  246. relation *rel;
  247. dataptr        rec;
  248. {
  249.    mchar *ptr;
  250.    file   fh;
  251.    int    fld;
  252.  
  253.    for (fld = 0; fld < rel->nFld; fld++)
  254.       {
  255.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  256.          {
  257.          ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  258.          ptr->pos = 0L;
  259.  
  260.          if (! ptr->name)
  261.             {
  262.             if (fieldInit (rel, rec, fld, NULL) != MB_OKAY)
  263.                {
  264.                Error (mb_errno);
  265.                }
  266.             }
  267.          else
  268.             {
  269.             if (access (ptr->name, 0) != -1)
  270.                {
  271.                unlink (ptr->name);
  272.                }
  273.             if ( (fh = creatx (ptr->name)) <= 0 )
  274.                {
  275.                Error (MB_TMPERR);
  276.                }
  277.             close (fh);
  278.             }
  279.          }
  280.       }
  281.  
  282.    SetError (MB_OKAY);
  283.  
  284. lblERROR:
  285.    return mb_errno;
  286. }
  287.  
  288. mb_err
  289. recInit  (rel, rec)
  290. relation *rel;
  291. dataptr        rec;
  292. {
  293.    mchar *ptr;
  294.    int    fld;
  295.  
  296.    for (fld = 0; fld < rel->nFld; fld++)
  297.       {
  298.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  299.          {
  300.          ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  301.          ptr->name = NULL;
  302.  
  303.          if (fieldInit (rel, rec, fld, NULL) != MB_OKAY)
  304.             {
  305.             Error (mb_errno);
  306.             }
  307.          }
  308.       }
  309.  
  310.    SetError (MB_OKAY);
  311.  
  312. lblERROR:
  313.    return mb_errno;
  314. }
  315.  
  316. dataptr
  317. _memrec  (rel, rec, rcd)
  318. relation *rel;
  319. dataptr        rec;
  320. long                rcd;
  321. {
  322.    _recStore (rel, rec);
  323.  
  324.    GO_RECID (rel, rcd);
  325.    readx (rel->fhRel, rec, rel->cbRecord);
  326.  
  327.    _recRestore (rel, rec);
  328.  
  329.    return rec;
  330. }
  331.  
  332. mb_err
  333. _recWrite (rel, rec, rcd)
  334. relation  *rel;
  335. dataptr         rec;
  336. long                 rcd;
  337. {
  338.    int  fld;
  339.  
  340.    for (fld = 0; fld < rel->nFld; fld++)
  341.       {
  342.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  343.          {
  344.          if (_append_fld (rel, rec, fld) != MB_OKAY)
  345.             return mb_errno;
  346.          }
  347.       }
  348.  
  349.    GO_RECID (rel, rcd);
  350.    writx (rel->fhRel, rec, rel->cbRecord);
  351.  
  352.    return MB_OKAY;
  353. }
  354.  
  355.  
  356. mb_err
  357. _recFill (rel, rec)
  358. relation *rel;
  359. dataptr        rec;
  360. {
  361.    int  fld;
  362.  
  363.    for (fld = 0; fld < rel->nFld; fld++)
  364.       {
  365.       if ((rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE))
  366.          {
  367.          if (_fieldFill (rel, rec, fld) != MB_OKAY)
  368.             {
  369.             return mb_errno;
  370.             }
  371.          }
  372.       }
  373.  
  374.    return MB_OKAY;
  375. }
  376.  
  377.  
  378. void
  379. recFree  (rel, rec)
  380. relation *rel;
  381. dataptr        rec;
  382. {
  383.    int  fld;
  384.  
  385.    for (fld = 0; fld < rel->nFld; fld++)
  386.       {
  387.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  388.          {
  389.          _fieldFree (rel, rec, fld);
  390.          }
  391.       }
  392. }
  393.  
  394.  
  395. /*
  396.  * If we were to simply read the record directly into "rec", we'd erase the
  397.  * filehandles and names we made for each multi-length field.  So, in the
  398.  * interests of speed (we don't wanna read just sections of the record), we
  399.  * store and restore the vital information.
  400.  *
  401.  */
  402.  
  403. static void
  404. _recRestore (rel, rec)
  405. relation    *rel;
  406. dataptr           rec;
  407. {
  408.    mchar *ptr;
  409.    int    fld, i;
  410.  
  411.    i = 0;
  412.    for (fld = 0; fld < rel->nFld; fld++)
  413.       {
  414.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  415.          {
  416.          ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  417.          ptr->name = aMulti[i].name;
  418.          i++;
  419.          }
  420.       }
  421. }
  422.  
  423. static void
  424. _recStore (rel, rec)
  425. relation  *rel;
  426. dataptr         rec;
  427. {
  428.    mchar *ptr;
  429.    int    fld, i;
  430.  
  431.    i = 0;
  432.    for (fld = 0; fld < rel->nFld; fld++)
  433.       {
  434.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  435.          {
  436.          ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  437.          aMulti[i].name = ptr->name;
  438.          i++;
  439.          }
  440.       }
  441. }
  442.  
  443.  
  444. /*
  445.  * THREADED-HEAP ROUTINES -----------------------------------------------------
  446.  *
  447.  */
  448.  
  449. mb_err
  450. _remove_m (rel, rcd)
  451. relation  *rel;
  452. long            rcd;
  453. {
  454.    dataptr  rec;
  455.    int      fld;
  456.  
  457.    if ((rec = (dataptr)malloc (rel->cbRecord +1)) == (dataptr)0)
  458.       {
  459.       Error (mb_errno);
  460.       }
  461.  
  462.    _memrec (rel, rec, rcd);
  463.  
  464.    for (fld = 0; fld < rel->nFld; fld++)
  465.       {
  466.       if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
  467.          {
  468.          if (_remove_fld (rel, rec, fld) != MB_OKAY)
  469.             {
  470.             Error_2 (mb_errno);
  471.             }
  472.          }
  473.       }
  474.  
  475.    SetError (MB_OKAY);
  476.  
  477. lblERROR_2:
  478.    free (rec);
  479.  
  480. lblERROR:
  481.    return mb_errno;
  482. }
  483.  
  484.  
  485. static mb_err
  486. _remove_fld (rel, rec, fld)
  487. relation    *rel;
  488. dataptr           rec;
  489. int                    fld;
  490. {
  491.    mchar  *ptr;
  492.    long    pos, lastPos, nextPos, lastLen;
  493.    long    len, n;
  494.    bool    fIsBefore;
  495.    bool    fIsAfter;
  496.  
  497.    ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  498.    pos = ptr->pos;
  499.  
  500.    lseek (rel->fhDat,  pos, 0);
  501.    readx (rel->fhDat, &len, 4);
  502.  
  503. /*
  504.  * First, we figure out where the links in the free chain are that surround the
  505.  * current position.
  506.  *
  507.  */
  508.  
  509.    lastPos = 1L;
  510.    lseek (rel->fhDat,  lastPos, 0);
  511.    readx (rel->fhDat, &nextPos, 4);
  512.  
  513.    for (;;)
  514.       {
  515.       Assert_Dat (nextPos != 0L && nextPos != pos);
  516.  
  517.       if (nextPos > pos)
  518.          break;
  519.  
  520.       lastPos = nextPos;
  521.       lseek (rel->fhDat,  lastPos, 0);
  522.       readx (rel->fhDat, &nextPos, 4);
  523.       readx (rel->fhDat, &lastLen, 4);
  524.  
  525.       Assert_Dat (nextPos > lastPos);
  526.       }
  527.  
  528.    fIsAfter  = ( (lastPos > 1L) && (lastPos +lastLen == pos) ) ? TRUE : FALSE;
  529.    fIsBefore = (pos +len == nextPos) ? TRUE : FALSE;
  530.  
  531. /*
  532.  * Here, we have to deal with one of four cases:
  533.  *    1- This block is the only one between two free blocks
  534.  *          last->next  = next->next;
  535.  *          last->size += next->size + len;
  536.  *    2- This block is the last before a free block
  537.  *          last->next  = this;
  538.  *          this->size  = next->size + len;
  539.  *          this->next  = next->next;
  540.  *    3- This block is the first after a free block
  541.  *          last->size += len;
  542.  *    4- This block is surrounded by other blocks
  543.  *          last->next  = this;
  544.  *          this->size  = len;
  545.  *          this->next  = next;
  546.  *
  547.  */
  548.  
  549.    lseek (rel->fhDat, nextPos, 0);
  550.    readx (rel->fhDat, &pos, 4);         /* pos = next->next */
  551.    readx (rel->fhDat, &n, 4);           /* n   = next->size */
  552.  
  553.    n += len;
  554.  
  555.    if (fIsAfter && fIsBefore)
  556.       {
  557.       lseek (rel->fhDat, lastPos, 0);
  558.       writx (rel->fhDat, &pos, 4);
  559.       readx (rel->fhDat, &len, 4);
  560.       len += n;
  561.       lseek (rel->fhDat, -4L, 1);
  562.       writx (rel->fhDat, &n, 4);
  563.       }
  564.    else if (fIsBefore)
  565.       {
  566.       lseek (rel->fhDat, lastPos, 0);
  567.       writx (rel->fhDat, &(ptr->pos), 4);
  568.       lseek (rel->fhDat, ptr->pos, 0);
  569.       writx (rel->fhDat, &pos, 4);
  570.       writx (rel->fhDat, &n, 4);
  571.       }
  572.    else if (fIsAfter)
  573.       {
  574.       lseek (rel->fhDat, 4L+ lastPos, 0);
  575.       readx (rel->fhDat, &n, 4);
  576.       n += len;
  577.       lseek (rel->fhDat, 4L+ lastPos, 0);
  578.       writx (rel->fhDat, &n, 4);
  579.       }
  580.    else
  581.       {
  582.       lseek (rel->fhDat, lastPos, 0);
  583.       writx (rel->fhDat, &(ptr->pos), 4);
  584.       lseek (rel->fhDat, ptr->pos, 0);
  585.       writx (rel->fhDat, &nextPos, 4);
  586.       writx (rel->fhDat, &len, 4);
  587.       }
  588.  
  589.    ptr->pos = 0L;
  590.  
  591.    SetError (MB_OKAY);
  592.  
  593. lblERROR:
  594.    return mb_errno;
  595. }
  596.  
  597.  
  598. static mb_err
  599. _append_fld (rel, rec, fld)
  600. relation    *rel;
  601. dataptr           rec;
  602. int                    fld;
  603. {
  604.    mchar  *ptr;
  605.    char    name[128];
  606.    long    len, n;
  607.    file    fh,  fhOrg;
  608.    long    lastPos;
  609.    long    thisPos, thisLen;
  610.    long    nextPos;
  611.    long    dataLen;
  612.  
  613.  
  614.    ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
  615.  
  616.    if ( (fhOrg = openx (ptr->name, OPENMODE)) <= 0 )
  617.       {
  618.       Error (MB_TMPERR);
  619.       } 
  620.  
  621. /*
  622.  * We can't just pick a place in the .DAT file and compress directly into it,
  623.  * because it might not fit.  Instead, we create a second temporary file,
  624.  * compress the field's temp file into it, and copy it into the .DAT file
  625.  * where it fits best.
  626.  *
  627.  */
  628.  
  629.    if (! *( GetTmpName(name) ))
  630.       {
  631.       Error (MB_TMPDIR);
  632.       }
  633.  
  634.    if ( (fh = creatx (name)) <= 0 )
  635.       {
  636.       Error (MB_TMPERR);
  637.       }
  638.    close (fh);
  639.    if ( (fh = openx (name, OPENMODE)) <= 0 )
  640.       {
  641.       unlink (name);
  642.       Error (MB_TMPERR);
  643.       }
  644.  
  645.    lseek (fh, 4L, 0);  /* Skip over the first four bytes... */
  646.  
  647.    for (len = n = 0L; n != 4L; len += n)
  648.       {
  649.       n = _fhCompress (fh, fhOrg);
  650.       }
  651.  
  652.    len += 4;
  653.    lseek (fh, 0L, 0);
  654.    writx (fh, &len, 4);
  655.  
  656. /*
  657.  * Find the first slot in the .DAT file which fits length LEN, leaving either
  658.  * zero bytes extra, or 128 bytes or more free.
  659.  *
  660.  */
  661.  
  662.    dataLen = lseek (rel->fhDat, 0L, 2);  /* Size of .DAT file */
  663.  
  664.    lastPos = 1L;
  665.    lseek (rel->fhDat,  lastPos, 0);
  666.    readx (rel->fhDat, &thisPos, 4);
  667.  
  668.    for (;;)
  669.       {
  670.       lseek (rel->fhDat,  thisPos, 0);
  671.       readx (rel->fhDat, &nextPos, 4);
  672.       readx (rel->fhDat, &thisLen, 4);
  673.  
  674.       Assert_Dat ((nextPos == 0L || nextPos > thisPos) && (nextPos < dataLen));
  675.  
  676.       if ((nextPos == 0L) || (thisLen == len) || (thisLen > len+MIN_SIZE))
  677.          break;
  678.  
  679.       lastPos = thisPos;
  680.       thisPos = nextPos;
  681.       }
  682.  
  683. /*
  684.  * Write data to 'thisPos'
  685.  *
  686.  */
  687.  
  688.    ptr->pos = thisPos;         /* This is where the data will be found later */
  689.  
  690.    lseek (rel->fhDat, thisPos, 0);
  691.    lseek (fh, 0L, 0);
  692.  
  693.    while (_fhCopy (rel->fhDat, fh, MAX_CBUF) != 0L)
  694.       ;
  695.  
  696.    thisPos = lseek (rel->fhDat, 0L, 1);   /* set thisPos == current position */
  697.  
  698.    if (nextPos != 0L && len == thisLen)
  699.       {
  700.       lseek (rel->fhDat,  lastPos, 0);
  701.       writx (rel->fhDat, &nextPos, 4);
  702.       }
  703.    else
  704.       {
  705. /*
  706.  * Here, we need to insert a header between 'lastPos' and 'nextPos', at
  707.  * 'thisPos'.
  708.  *
  709.  */
  710.       n = (nextPos == 0L) ? 0L : (thisLen -len);  /* Amount left over */
  711.  
  712.       Assert_Dat (nextPos == 0L  ||  n >= MIN_SIZE);
  713.  
  714.       writx (rel->fhDat, &nextPos, 4);
  715.       writx (rel->fhDat, &n,       4);
  716.       lseek (rel->fhDat,  lastPos, 0);
  717.       writx (rel->fhDat, &thisPos, 4);
  718.       }
  719.  
  720.    close (fh);
  721.    unlink (name);
  722.  
  723.    SetError (MB_OKAY);
  724.  
  725. lblERROR:
  726.    if (fhOrg > 0)
  727.       {
  728.       close (fhOrg);
  729.       }
  730.  
  731.    return mb_errno;
  732. }
  733.  
  734.