home *** CD-ROM | disk | FTP | other *** search
- /*
- * METALBASE 5.1
- *
- * Released January 1st, 1993 by Huan-Ti [ t-richj@microsoft.com ]
- *
- */
-
- #include <mbase.h>
- #include "internal.h"
-
-
- /*
- * COMPILE-TIME OPTIONS -------------------------------------------------------
- *
- * MIN_SIZE is the smallest free-block for which we'll create a header; because
- * we only keep headers for each free segment, this helps keep down the length
- * of the chain we'll have to follow later. Too large and you waste space; too
- * small and you'll get a fragmented heap, which will damage performance. You
- * must keep this at eight or more, or the header we write may overwrite the
- * next block of text.
- *
- */
-
- #define MIN_SIZE 128
-
- /*
- * PROTOTYPES -----------------------------------------------------------------
- *
- */
-
- static void _fieldFree XARGS( (relation *, dataptr, int) );
-
- static void _recStore XARGS( (relation *, dataptr) );
- static void _recRestore XARGS( (relation *, dataptr) );
-
- static mb_err _remove_fld XARGS( (relation *, dataptr, int) );
- static mb_err _append_fld XARGS( (relation *, dataptr, int) );
-
-
- /*
- * VARIABLES ------------------------------------------------------------------
- *
- */
-
- mchar aMulti [MAX_MULTI];
-
-
- /*
- * FIELD ROUTINES -------------------------------------------------------------
- *
- */
-
- mb_err
- fieldInit (rel, rec, fld, name)
- relation *rel;
- dataptr rec;
- int fld;
- char *name;
- {
- mchar *ptr;
- int num;
- file fh;
-
-
- if ( (rel->fldType[fld] != T_MCHAR) && (rel->fldType[fld] != T_MBYTE) )
- {
- Error (MB_BAD_ARG);
- }
-
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- num = (name && *name) ? (1+strlen(name)) : 128;
-
- ptr->pos = 0L;
-
-
- /*
- * First see if this record pointer has been used before. If so, remove any
- * temporary file and free the memory used for it...
- *
- */
-
- _fieldFree (rel, rec, fld);
-
-
- /*
- * Now pick a name (unless one was given) and open the file.
- *
- */
-
- if ( (ptr->name = (char *)malloc (num)) == NULL )
- {
- Error (MB_NO_MEMORY);
- }
-
- if (! name || ! *name) /* If we didn't get a name, choose one. */
- {
- if (! *( GetTmpName(ptr->name) ))
- {
- Error_2 (MB_TMPDIR);
- }
- }
-
- if ( (fh = creatx (ptr->name)) <= 0 )
- {
- Error_2 (MB_TMPERR);
- }
- close (fh);
-
- SetError (MB_OKAY);
- return MB_OKAY;
-
-
- lblERROR_2:
- free ( ((mchar *)ptr)->name );
- ((mchar *)ptr)->name = NULL;
-
- lblERROR:
- return mb_errno;
- }
-
-
- char *
- fieldFile (rel, rec, fld)
- relation *rel;
- dataptr rec;
- int fld;
- {
- if (rel->fldType[fld] != T_MCHAR && rel->fldType[fld] != T_MBYTE)
- {
- Error (MB_BAD_ARG);
- }
- SetError (MB_OKAY);
-
- return ((mchar *)( (char *)rec + rel->cbStart[fld] ))->name;
-
- lblERROR:
- return NULL;
- }
-
-
- file
- fieldOpen (rel, rec, fld)
- relation *rel;
- dataptr rec;
- int fld;
- {
- mchar *ptr;
- file fh;
-
- if (rel->fldType[fld] != T_MCHAR && rel->fldType[fld] != T_MBYTE)
- {
- Error (MB_BAD_ARG);
- }
- SetError (MB_OKAY);
-
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- if ((fh = openx (ptr->name, OPENMODE)) <= 0)
- {
- SetError (MB_TMPERR);
- fh = -1;
- }
-
- return fh;
-
- lblERROR:
- return -1;
- }
-
-
- /*
- * Free chain:
- *
- * 4 bytes: Length of this free block (including 8-byte header)
- * 4 bytes: Pointer to next free block
- *
- * Used header:
- *
- * 4 bytes: Length of this block (compressed, excluding 4-byte header)
- * variable: Compressed data
- *
- */
-
- mb_err
- _fieldFill (rel, rec, fld)
- relation *rel;
- dataptr rec;
- int fld;
- {
- mchar *ptr;
- long len;
- file fh;
-
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
-
- if (ptr->pos == 0L)
- Error (MB_OKAY);
-
- if ((fh = openx (ptr->name, OPENMODE)) <= 0)
- {
- Error (MB_TMPERR);
- }
-
- lseek (rel->fhDat, ptr->pos + 4L, 0); /* Skip the first four bytes */
-
- while ((len = _fhDecompress (fh, rel->fhDat)) > 0L) /* len== amt of data */
- ;
- Assert_Dat (len == 0L); /* Anything else indicates a corrupt datafile */
-
- close (fh);
-
- SetError (MB_OKAY);
-
- lblERROR:
- return mb_errno;
- }
-
-
- static void
- _fieldFree (rel, rec, fld)
- relation *rel;
- dataptr rec;
- int fld;
- {
- mchar *ptr;
-
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
-
- if (ptr->name != NULL)
- {
- if (access (ptr->name, 0) != -1)
- unlink (ptr->name);
-
- free (ptr->name);
- ptr->name = NULL;
- }
- }
-
-
- /*
- * RECORD ROUTINES ------------------------------------------------------------
- *
- */
-
- mb_err
- recClean (rel, rec)
- relation *rel;
- dataptr rec;
- {
- mchar *ptr;
- file fh;
- int fld;
-
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- ptr->pos = 0L;
-
- if (! ptr->name)
- {
- if (fieldInit (rel, rec, fld, NULL) != MB_OKAY)
- {
- Error (mb_errno);
- }
- }
- else
- {
- if (access (ptr->name, 0) != -1)
- {
- unlink (ptr->name);
- }
- if ( (fh = creatx (ptr->name)) <= 0 )
- {
- Error (MB_TMPERR);
- }
- close (fh);
- }
- }
- }
-
- SetError (MB_OKAY);
-
- lblERROR:
- return mb_errno;
- }
-
- mb_err
- recInit (rel, rec)
- relation *rel;
- dataptr rec;
- {
- mchar *ptr;
- int fld;
-
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- ptr->name = NULL;
-
- if (fieldInit (rel, rec, fld, NULL) != MB_OKAY)
- {
- Error (mb_errno);
- }
- }
- }
-
- SetError (MB_OKAY);
-
- lblERROR:
- return mb_errno;
- }
-
- dataptr
- _memrec (rel, rec, rcd)
- relation *rel;
- dataptr rec;
- long rcd;
- {
- _recStore (rel, rec);
-
- GO_RECID (rel, rcd);
- readx (rel->fhRel, rec, rel->cbRecord);
-
- _recRestore (rel, rec);
-
- return rec;
- }
-
- mb_err
- _recWrite (rel, rec, rcd)
- relation *rel;
- dataptr rec;
- long rcd;
- {
- int fld;
-
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- if (_append_fld (rel, rec, fld) != MB_OKAY)
- return mb_errno;
- }
- }
-
- GO_RECID (rel, rcd);
- writx (rel->fhRel, rec, rel->cbRecord);
-
- return MB_OKAY;
- }
-
-
- mb_err
- _recFill (rel, rec)
- relation *rel;
- dataptr rec;
- {
- int fld;
-
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ((rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE))
- {
- if (_fieldFill (rel, rec, fld) != MB_OKAY)
- {
- return mb_errno;
- }
- }
- }
-
- return MB_OKAY;
- }
-
-
- void
- recFree (rel, rec)
- relation *rel;
- dataptr rec;
- {
- int fld;
-
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- _fieldFree (rel, rec, fld);
- }
- }
- }
-
-
- /*
- * If we were to simply read the record directly into "rec", we'd erase the
- * filehandles and names we made for each multi-length field. So, in the
- * interests of speed (we don't wanna read just sections of the record), we
- * store and restore the vital information.
- *
- */
-
- static void
- _recRestore (rel, rec)
- relation *rel;
- dataptr rec;
- {
- mchar *ptr;
- int fld, i;
-
- i = 0;
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- ptr->name = aMulti[i].name;
- i++;
- }
- }
- }
-
- static void
- _recStore (rel, rec)
- relation *rel;
- dataptr rec;
- {
- mchar *ptr;
- int fld, i;
-
- i = 0;
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- aMulti[i].name = ptr->name;
- i++;
- }
- }
- }
-
-
- /*
- * THREADED-HEAP ROUTINES -----------------------------------------------------
- *
- */
-
- mb_err
- _remove_m (rel, rcd)
- relation *rel;
- long rcd;
- {
- dataptr rec;
- int fld;
-
- if ((rec = (dataptr)malloc (rel->cbRecord +1)) == (dataptr)0)
- {
- Error (mb_errno);
- }
-
- _memrec (rel, rec, rcd);
-
- for (fld = 0; fld < rel->nFld; fld++)
- {
- if ( (rel->fldType[fld] == T_MCHAR) || (rel->fldType[fld] == T_MBYTE) )
- {
- if (_remove_fld (rel, rec, fld) != MB_OKAY)
- {
- Error_2 (mb_errno);
- }
- }
- }
-
- SetError (MB_OKAY);
-
- lblERROR_2:
- free (rec);
-
- lblERROR:
- return mb_errno;
- }
-
-
- static mb_err
- _remove_fld (rel, rec, fld)
- relation *rel;
- dataptr rec;
- int fld;
- {
- mchar *ptr;
- long pos, lastPos, nextPos, lastLen;
- long len, n;
- bool fIsBefore;
- bool fIsAfter;
-
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
- pos = ptr->pos;
-
- lseek (rel->fhDat, pos, 0);
- readx (rel->fhDat, &len, 4);
-
- /*
- * First, we figure out where the links in the free chain are that surround the
- * current position.
- *
- */
-
- lastPos = 1L;
- lseek (rel->fhDat, lastPos, 0);
- readx (rel->fhDat, &nextPos, 4);
-
- for (;;)
- {
- Assert_Dat (nextPos != 0L && nextPos != pos);
-
- if (nextPos > pos)
- break;
-
- lastPos = nextPos;
- lseek (rel->fhDat, lastPos, 0);
- readx (rel->fhDat, &nextPos, 4);
- readx (rel->fhDat, &lastLen, 4);
-
- Assert_Dat (nextPos > lastPos);
- }
-
- fIsAfter = ( (lastPos > 1L) && (lastPos +lastLen == pos) ) ? TRUE : FALSE;
- fIsBefore = (pos +len == nextPos) ? TRUE : FALSE;
-
- /*
- * Here, we have to deal with one of four cases:
- * 1- This block is the only one between two free blocks
- * last->next = next->next;
- * last->size += next->size + len;
- * 2- This block is the last before a free block
- * last->next = this;
- * this->size = next->size + len;
- * this->next = next->next;
- * 3- This block is the first after a free block
- * last->size += len;
- * 4- This block is surrounded by other blocks
- * last->next = this;
- * this->size = len;
- * this->next = next;
- *
- */
-
- lseek (rel->fhDat, nextPos, 0);
- readx (rel->fhDat, &pos, 4); /* pos = next->next */
- readx (rel->fhDat, &n, 4); /* n = next->size */
-
- n += len;
-
- if (fIsAfter && fIsBefore)
- {
- lseek (rel->fhDat, lastPos, 0);
- writx (rel->fhDat, &pos, 4);
- readx (rel->fhDat, &len, 4);
- len += n;
- lseek (rel->fhDat, -4L, 1);
- writx (rel->fhDat, &n, 4);
- }
- else if (fIsBefore)
- {
- lseek (rel->fhDat, lastPos, 0);
- writx (rel->fhDat, &(ptr->pos), 4);
- lseek (rel->fhDat, ptr->pos, 0);
- writx (rel->fhDat, &pos, 4);
- writx (rel->fhDat, &n, 4);
- }
- else if (fIsAfter)
- {
- lseek (rel->fhDat, 4L+ lastPos, 0);
- readx (rel->fhDat, &n, 4);
- n += len;
- lseek (rel->fhDat, 4L+ lastPos, 0);
- writx (rel->fhDat, &n, 4);
- }
- else
- {
- lseek (rel->fhDat, lastPos, 0);
- writx (rel->fhDat, &(ptr->pos), 4);
- lseek (rel->fhDat, ptr->pos, 0);
- writx (rel->fhDat, &nextPos, 4);
- writx (rel->fhDat, &len, 4);
- }
-
- ptr->pos = 0L;
-
- SetError (MB_OKAY);
-
- lblERROR:
- return mb_errno;
- }
-
-
- static mb_err
- _append_fld (rel, rec, fld)
- relation *rel;
- dataptr rec;
- int fld;
- {
- mchar *ptr;
- char name[128];
- long len, n;
- file fh, fhOrg;
- long lastPos;
- long thisPos, thisLen;
- long nextPos;
- long dataLen;
-
-
- ptr = (mchar *)( (char *)rec + rel->cbStart[fld] );
-
- if ( (fhOrg = openx (ptr->name, OPENMODE)) <= 0 )
- {
- Error (MB_TMPERR);
- }
-
- /*
- * We can't just pick a place in the .DAT file and compress directly into it,
- * because it might not fit. Instead, we create a second temporary file,
- * compress the field's temp file into it, and copy it into the .DAT file
- * where it fits best.
- *
- */
-
- if (! *( GetTmpName(name) ))
- {
- Error (MB_TMPDIR);
- }
-
- if ( (fh = creatx (name)) <= 0 )
- {
- Error (MB_TMPERR);
- }
- close (fh);
- if ( (fh = openx (name, OPENMODE)) <= 0 )
- {
- unlink (name);
- Error (MB_TMPERR);
- }
-
- lseek (fh, 4L, 0); /* Skip over the first four bytes... */
-
- for (len = n = 0L; n != 4L; len += n)
- {
- n = _fhCompress (fh, fhOrg);
- }
-
- len += 4;
- lseek (fh, 0L, 0);
- writx (fh, &len, 4);
-
- /*
- * Find the first slot in the .DAT file which fits length LEN, leaving either
- * zero bytes extra, or 128 bytes or more free.
- *
- */
-
- dataLen = lseek (rel->fhDat, 0L, 2); /* Size of .DAT file */
-
- lastPos = 1L;
- lseek (rel->fhDat, lastPos, 0);
- readx (rel->fhDat, &thisPos, 4);
-
- for (;;)
- {
- lseek (rel->fhDat, thisPos, 0);
- readx (rel->fhDat, &nextPos, 4);
- readx (rel->fhDat, &thisLen, 4);
-
- Assert_Dat ((nextPos == 0L || nextPos > thisPos) && (nextPos < dataLen));
-
- if ((nextPos == 0L) || (thisLen == len) || (thisLen > len+MIN_SIZE))
- break;
-
- lastPos = thisPos;
- thisPos = nextPos;
- }
-
- /*
- * Write data to 'thisPos'
- *
- */
-
- ptr->pos = thisPos; /* This is where the data will be found later */
-
- lseek (rel->fhDat, thisPos, 0);
- lseek (fh, 0L, 0);
-
- while (_fhCopy (rel->fhDat, fh, MAX_CBUF) != 0L)
- ;
-
- thisPos = lseek (rel->fhDat, 0L, 1); /* set thisPos == current position */
-
- if (nextPos != 0L && len == thisLen)
- {
- lseek (rel->fhDat, lastPos, 0);
- writx (rel->fhDat, &nextPos, 4);
- }
- else
- {
- /*
- * Here, we need to insert a header between 'lastPos' and 'nextPos', at
- * 'thisPos'.
- *
- */
- n = (nextPos == 0L) ? 0L : (thisLen -len); /* Amount left over */
-
- Assert_Dat (nextPos == 0L || n >= MIN_SIZE);
-
- writx (rel->fhDat, &nextPos, 4);
- writx (rel->fhDat, &n, 4);
- lseek (rel->fhDat, lastPos, 0);
- writx (rel->fhDat, &thisPos, 4);
- }
-
- close (fh);
- unlink (name);
-
- SetError (MB_OKAY);
-
- lblERROR:
- if (fhOrg > 0)
- {
- close (fhOrg);
- }
-
- return mb_errno;
- }
-
-