home *** CD-ROM | disk | FTP | other *** search
- /*
- * METALBASE 5.0
- *
- * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
- * [ t-richj@microsoft.com ]
- */
-
- #define UTIL_C
- #include "mbase.h"
- #include "internal.h"
-
- extern int _started;
- extern relation *_list[MAX_REL];
-
- /****************************************************************************/
-
- #ifdef LONGARGS
- static void _dec_user (relation *);
- #else
- static void _dec_user();
- #endif
-
- void
- _seterr (err)
- mb_err err;
- {
- switch (mb_errno = err)
- {
- case MB_OKAY: mb_error="No error"; break;
- case MB_NO_ROOM: mb_error="MAX_REL is #defined to be too small"; break;
- case MB_NO_MEMORY:mb_error="Not enough memory for requested task"; break;
- case MB_NO_OPEN: mb_error="Cannot open given filename"; break;
- case MB_NO_READ: mb_error="Cannot read given filename"; break;
- case MB_FORMAT: mb_error="Relation is not in MB 5.0 format"; break;
- case MB_LOCKED: mb_error="Relation is locked by another user"; break;
- case MB_BUSY: mb_error="Relation is too busy"; break;
- case MB_BAD_REL: mb_error="Function passed bad relation struct"; break;
- case MB_NO_WRITE: mb_error="Cannot write given to relation"; break;
- case MB_TIMEOUT: mb_error="Temporary lock has not been removed"; break;
- case MB_BAD_REC: mb_error="A null rec pointer has been received"; break;
- case MB_CORRUPT: mb_error="A corrupt index has been detected"; break;
- case MB_BAD_DUP: mb_error="Addition would violate a nodups idx"; break;
- case MB_NO_CURR: mb_error="Current record required for operation";break;
- case MB_BAD_IDX: mb_error="A bad index number has been received"; break;
- case MB_NO_SUCH: mb_error="The specified record can't be found"; break;
- case MB_UNKNOWN: mb_error="Search command invalid"; break;
- case MB_NO_FIELDS: mb_error="The new relation has no fields"; break;
- case MB_NO_INDICES: mb_error="The new relation has no indices"; break;
- case MB_BAD_INDEX: mb_error="The new index has no fields"; break;
- case MB_DISKFULL: mb_error="There is not enough free space left"; break;
- case MB_BAD_SERIAL: mb_error="The record's serial number changed"; break;
- case MB_TMPDIR: mb_error="You must define a TMP directory"; break;
- case MB_TMPERR: mb_error="Cannot work with TMP directory"; break;
- default: mb_error="Undefined error--rebuild and pray"; break;
- }
- }
-
- relation *
- _fill_info (rel, fld, idx)
- relation *rel;
- long fld, idx;
- {
- register int i, j;
- int s, e;
- char temp[4], buf[128];
- short tshort;
- #ifdef STRUCT_4
- int done = 0;
- #endif
-
- rel->iser = rel->num_f; /* Until we find otherwise */
-
- for (i=rel->rec_len=0; i<rel->num_f; i++)
- {
- if (lseek (rel->relcode, fld, 0) != fld)
- {
- _clr_lck (rel); free (rel);
- relerr (MB_FORMAT, RNULL);
- }
-
- readx (rel->relcode, buf, 1); rel->type[i] = (ftype)buf[0];
- readx (rel->relcode, &tshort, 2);
- switch (rel->type[i])
- {
- case T_SHORT:
- case T_USHORT: rel->siz[i] = 2; /* sizeof(short) */ break;
- case T_FLOAT: rel->siz[i] = 4; /* sizeof(float) */ break;
- case T_DOUBLE:
- case T_MONEY: rel->siz[i] = 8; /* sizeof(double) */ break;
- case T_TIME:
- case T_LONG:
- case T_ULONG: rel->siz[i] = 4; /* sizeof(long) */ break;
- case T_DATE: rel->siz[i] = 4; /* sizeof(long) */ break;
- case T_PHONE: rel->siz[i] = 20; /* char[20] */ break;
- case T_SERIAL: rel->siz[i] = 4; /* sizeof(long) */
- rel->iser = i;
- break;
- default: rel->siz[i] = (int)tshort; break;
- }
-
- #ifdef STRUCT_1
- if (rel->type[i] != T_CHAR && rel->type[i] != T_PHONE)
- {
- if (rel->siz[i] == 8) rel->rec_len = round8(rel->rec_len);
- else if (rel->siz[i] == 4) rel->rec_len = round4(rel->rec_len);
- else rel->rec_len = round2(rel->rec_len);
- }
- #endif
-
- #ifdef STRUCT_3
- if (rel->type[i] != T_CHAR && rel->type[i] != T_PHONE)
- {
- if (rel->siz[i] == 2) rel->rec_len = round2(rel->rec_len);
- else rel->rec_len = round4(rel->rec_len);
- }
- #endif
-
- #ifdef STRUCT_4
- if (rel->type[i] != T_CHAR && rel->type[i] != T_PHONE)
- {
- done=1;
- rel->rec_len = round2(rel->rec_len);
- }
- #endif
-
- rel->start[i] = rel->rec_len;
- rel->rec_len += rel->siz[i];
-
- readx (rel->relcode, buf, 20);
-
- for (j=0; buf[j]!='|'; j++)
- ;
- fld += (long)j+4; /* Advance to next field */
-
- buf[j] = 0; strcpy (rel->name[i], buf);
- }
-
- #ifdef STRUCT_1
- rel->rec_len = round8(rel->rec_len);
- #endif
-
- #ifdef STRUCT_3
- rel->rec_len = round4(rel->rec_len);
- #endif
-
- #ifdef STRUCT_4
- if (done)
- rel->rec_len = round2(rel->rec_len);
- #endif
-
- if (lseek (rel->relcode, idx, 0) != idx)
- {
- _clr_lck (rel);
- free (rel);
- relerr (MB_FORMAT, RNULL);
- }
-
- for (i=0; i<rel->num_i; i++)
- {
- readx (rel->relcode, buf, 1); e=(int)buf[0]; /* Dups/NoDups */
- readx (rel->relcode, buf, 1); s=(int)buf[0]; /* Num/Fields */
- readx (rel->relcode, buf, 20);
-
- for (j=0; buf[j]!=':'; j++)
- ;
-
- idx += (long)j + 3L;
- lseek (rel->relcode, idx, 0); /* Advance to index' fields */
-
- buf[j] = 0;
- strcpy (rel->iname[i], buf);
- rel->itype[i]=e; sprintf (rel->idxs[i], "%03d", s);
-
- for (j=0; j<s; j++)
- {
- readx (rel->relcode, &tshort, 2);
- sprintf (temp, "%03d", tshort);
- strcat (rel->idxs[i], temp);
- }
-
- idx = lseek (rel->relcode, 0L, 1); /* Get current position */
- }
-
- rel->hack = idx; /* Current position == reserved segment */
-
- if (rel->ver == verCURRENT && ! rel->rdonly)
- {
- lseek (rel->lckcode, lckPOS_USERS, 0);
- readx (rel->lckcode, buf, 1);
- buf[0] = (char)((unsigned int)buf[0] +1); /* Increment the */
- lseek (rel->lckcode, lckPOS_USERS, 0); /* number of users */
- writx (rel->lckcode, buf, 1);
-
- _clr_lck (rel);
- }
-
- relerr (MB_OKAY, rel);
- }
-
- void
- _close_proc (rel)
- relation *rel;
- {
- if (rel->ver == verCURRENT)
- {
- (void)mb_unl (rel);
- _dec_user (rel);
- }
-
- close (rel->relcode);
- free (rel);
- }
-
- void
- _divine_mask (rel, key)
- relation *rel;
- int key;
- {
- rel->mask = (char)(
- ((key & (int)0x04) << 5) | /* 00000100 -> 10000000 */
- ((key & (int)0x30) << 1) | /* 00110000 -> 01100000 */
- ((key & (int)0x80) >> 3) | /* 10000000 -> 00010000 */
- ((key & (int)0x03) << 2) | /* 00000011 -> 00001100 */
- ((key & (int)0x40) >> 5) | /* 01000000 -> 00000010 */
- ((key & (int)0x08) >> 3)); /* 00001000 -> 00000001 */
- }
-
- int
- _identify (rel)
- relation *rel;
- {
- register int i;
- if (rel == RNULL || !_started) return -1;
- for (i=0; i<MAX_REL; i++)
- if (_list[i] == rel) break;
- if (i == MAX_REL) return -1;
- if (rel->ver != verCURRENT) return -2;
- return i;
- }
-
- mb_err
- _format (rel, rec, stage)
- relation *rel;
- dataptr rec;
- int stage;
- {
- register int i;
- double tdbl;
- long nexts, tlong;
- int a;
- long ac,pre,num,ext;
- char *pch, temp[25];
-
- if (! rec) baderr (MB_BAD_REC);
-
- if (stage == 2)
- { GO_NEXTS (rel);
- readx (rel->relcode, &nexts, 4);
- }
-
- for (i=a=0; i<rel->num_f; i++)
- {
- if (stage == 1)
- {
- if (rel->type[i] == T_PHONE)
- {
- pch = (char *)rec + rel->start[i];
- scn_phone (&ac,&pre,&num,&ext, pch);
- strcpy (temp, fmt_phone (ac,pre,num,ext, -1));
- strncpy (pch, temp, 20);
- }
- if (rel->type[i] == T_MONEY)
- {
- tdbl = *(double *)((char *)rec+rel->start[i]);
- tlong = (long)(tdbl * 100.0); tdbl = (double)tlong / 100.0;
- *(double *)((char *)rec+rel->start[i]) = tdbl;
- }
- }
- else
- {
- if (rel->type[i] == T_SERIAL)
- {
- *(long *)((char *)rec+rel->start[i]) = nexts;
- rel->serial = nexts;
- _cryptf ((dataptr)((char *)rec+rel->start[i]), 4, rel->mask);
- a = 1;
- }
- }
- }
-
- if (a)
- {
- GO_NEXTS (rel); nexts++;
- writx (rel->relcode, &nexts, 4);
- }
-
- return MB_OKAY;
- }
-
- void
- _crypt (rel, rec)
- relation *rel;
- dataptr rec;
- {
- #ifndef NOENCRYPT
- register int i;
-
- if (rel->mask)
- for (i=0; i<rel->num_f; i++)
- _cryptf ((char *)rec+rel->start[i], rel->siz[i], rel->mask);
- #else
- ; /* Some compilers complain about null-functions */
- #endif
- }
-
- void
- _cryptf (rec, siz, mask)
- dataptr rec;
- int siz, mask;
- {
- #ifndef NOENCRYPT
- register int i;
- register char *c;
-
- if (mask != 0)
- for (i=0,c=rec; i<siz; i++,c++)
- { *c ^= mask;
- mask = (mask + 1) & (int)0xFF;
- }
- #else
- ; /* Some compilers complain about null-functions */
- #endif
- }
-
- mb_err
- _check_dup (rel, rec, idx, ign)
- relation *rel;
- dataptr rec;
- int idx;
- long ign;
- {
- dataptr mem;
- long pos;
- int dir;
-
- if (rel->itype[idx] == 1) reterr (MB_OKAY, 0);
-
- GO_TOP (rel, idx);
- readx (rel->relcode, &pos, 4);
- if (pos==0L)
- reterr (MB_OKAY, 0);
-
- if ((mem = (dataptr)malloc (1+ rel->rec_len)) == NULL)
- reterr (MB_NO_MEMORY, -1);
-
- for (;;)
- {
- dir = _compare (rel, rec, _memrec(rel,pos,mem), idx);
-
- if (dir == 0)
- {
- if (pos == ign) break; /* If we're about to change the rec, okay */
- free (mem);
-
- reterr (MB_BAD_DUP, -1);
- }
-
- GO_POINT (rel, pos, idx, dir);
- readx (rel->relcode, &pos, 4);
-
- if (pos == 0L) break;
- }
- free (mem);
-
- reterr (MB_OKAY, MB_OKAY);
- }
-
- long
- _append (rel, rec)
- relation *rel;
- dataptr rec;
- {
- long rcd, temp;
- register int i;
- char buf[2];
-
- lseek (rel->relcode, POS_NUMREC, 0);
- readx (rel->relcode, &rcd, 4); rcd++;
- lseek (rel->relcode, POS_NUMREC, 0);
- writx (rel->relcode, &rcd, 4);
-
- GO_START (rel, rcd);
-
- for (i=0,temp=0L,buf[0]=BAL_EV; i<rel->num_i; i++)
- {
- writx (rel->relcode, &temp, 4);
- writx (rel->relcode, &temp, 4);
- writx (rel->relcode, &temp, 4);
- writx (rel->relcode, buf, 1);
- }
- writx (rel->relcode, rec, rel->rec_len);
-
- return rcd;
- }
-
- void
- _remove (rel, bad)
- relation *rel;
- long bad;
- {
- int i, dir;
- long rep, tmp;
- char temp[5];
- dataptr buf;
-
- lseek (rel->relcode, POS_NUMREC, 0);
- readx (rel->relcode, &rep, 4); rep--;
- lseek (rel->relcode, POS_NUMREC, 0);
- writx (rel->relcode, &rep, 4); rep++; /* Find replacement record */
-
- if (rep == bad) return;
-
- if ((buf=(dataptr)malloc (rel->rec_len +13*rel->num_i +1)) == NULL) return;
-
- GO_START (rel, rep);
- readx (rel->relcode, buf, rel->rec_len +13*rel->num_i);
- GO_START (rel, bad);
- writx (rel->relcode, buf, rel->rec_len +13*rel->num_i);
-
- for (i = 0; i < rel->num_i; i++)
- {
- GO_POINT (rel, rep, i, 0);
- readx (rel->relcode, &tmp, 4);
- GO_BAL (rel, rep, i);
- readx (rel->relcode, temp, 1); dir = (temp[0] & PARDIR);
-
- if (tmp == 0L)
- GO_TOP (rel, i);
- else
- GO_POINT (rel, tmp, i, (dir ? 1 : -1));
- writx (rel->relcode, &bad, 4);
-
- GO_POINT (rel, rep, i, -1);
- readx (rel->relcode, &tmp, 4);
- if (tmp != 0L)
- {
- GO_POINT (rel, tmp, i, 0);
- writx (rel->relcode, &bad, 4);
- }
-
- GO_POINT (rel, rep, i, 1);
- readx (rel->relcode, &tmp, 4);
- if (tmp != 0L)
- {
- GO_POINT (rel, tmp, i, 0);
- writx (rel->relcode, &bad, 4);
- }
- }
-
- free (buf);
- }
-
- mb_err
- _link (rel, rcd) /* CACHED */
- relation *rel;
- long rcd;
- {
- register int i;
-
- _free_cache ();
-
- for (i=0; i<rel->num_i; i++)
- {
- _drop (rel, rcd, i, 0L);
- if (_check (rel, rcd, 0L, i))
- {
- _flush_cache (rel, i);
- return mb_errno;
- }
- _flush_cache (rel, i);
- }
- return MB_OKAY;
- }
-
- void
- _drop (rel, rcd, idx, top) /* CACHED */
- relation *rel;
- long rcd, top;
- int idx;
- {
- long pos, par;
- int dir;
- char temp[5];
- dataptr a, b;
- cache *ptr;
-
- ptr = _read_cache (rel, top, idx);
- if (top == 0L)
- {
- pos = ptr->num;
- par = 0L;
- }
- else
- {
- par = ptr->parent;
- pos = top;
- }
-
- a = (dataptr)malloc (1+ rel->rec_len);
- b = (dataptr)malloc (1+ rel->rec_len);
-
- for ( ; pos != 0L; )
- {
- ptr = _read_cache (rel, pos, idx);
- temp[0] = ptr->parbal;
-
- dir = _compare (rel, _memrec(rel,rcd,a), b=_memrec(rel,pos,b), idx );
- /*
- * POSSIBLE ERROR POINT -- _memrec is being used twice in one
- * function call. If it's going to be a problem, it'll show up after
- * the second add, delete or update.... if it doesn't, this isn't
- * the cause of your trouble.
- *
- */
-
- if (dir == 0)
- {
- dir = ((temp[0] & BAL) == BAL_RT || (temp[0] & BAL) == BAL_FR) ? -1:1;
- }
- temp[0] += dir;
-
- _change_cache (ptr, parbal, temp[0]);
-
- par = pos;
- pos = _cache_field (ptr, dir);
- }
-
- free (a); free (b);
-
- if (par == 0L)
- {
- ptr = _read_cache (rel, 0L, idx);
- _change_cache (ptr, num, rcd);
- }
- else
- {
- temp[0] = (char)(((dir==1) ? PARDIR:0) | BAL_EV);
-
- ptr = _read_cache (rel, rcd, idx);
- _change_cache (ptr, parbal, temp[0]);
-
- ptr = _read_cache (rel, par, idx);
- if (dir == -1) _changeqcache (ptr, left, rcd);
- else if (dir == 0) _changeqcache (ptr, parent, rcd);
- else _changeqcache (ptr, right, rcd);
- ptr->changed = 1;
- }
-
- ptr = _read_cache (rel, rcd, idx);
- _change_cache (ptr, parent, par);
- }
-
- mb_err
- _check (rel, st, ed, idx) /* CACHED */
- relation *rel;
- long st, ed;
- int idx;
- {
- long pos, tmp;
- cache *ptr;
-
- for (pos = st; pos != ed; )
- {
- if (pos == 0L) break;
-
- ptr = _read_cache (rel, pos, idx);
- tmp = ptr->parent;
-
- if (! BALANCED ( (ptr->parbal & BAL) ))
- if (_balance (rel, pos, idx, (int)(ptr->parbal & BAL)))
- return mb_errno;
- pos = tmp;
- }
-
- return MB_OKAY;
- }
-
- /****************************************************************************/
-
- int
- compare (rel, ptra, ptrb, idx) /* -1 == ptra < ptrb */
- relation *rel;
- dataptr ptra, ptrb;
- int idx;
- {
- int i;
- if (_identify (rel) < 0) interr (MB_BAD_REL, -1);
- if (idx < 0 || idx >= rel->num_i) interr (MB_BAD_IDX, -1);
- if (ptra == ptrb) interr (MB_OKAY, 0);
-
- _crypt (rel, ptra);
- _crypt (rel, ptrb);
- i = _compare (rel, ptra, ptrb, idx);
- _crypt (rel, ptra);
- _crypt (rel, ptrb);
- interr (MB_OKAY, i);
- }
-
- int
- idxnum (rel, name)
- relation *rel;
- char *name;
- {
- int i;
-
- if (_identify (rel) < 0) interr (MB_BAD_REL, -1);
-
- for (i = 0; i < rel->num_i; i++)
- if (! strcmp (name, rel->iname[i]))
- break;
- if (i == rel->num_i) interr (MB_BAD_IDX, -1);
-
- interr (MB_OKAY, i);
- }
-
- static void
- _dec_user (rel)
- relation *rel;
- {
- char buf[2];
-
- lseek (rel->lckcode, lckPOS_USERS, 0);
- readx (rel->lckcode, buf, 1);
- buf[0] = (char)((unsigned int)buf[0] -1);
- if ((uchar)buf[0] > 254) buf[0] = 0;
- lseek (rel->lckcode, lckPOS_USERS, 0); writx (rel->lckcode, buf, 1);
- }
-
-