home *** CD-ROM | disk | FTP | other *** search
- /*
- * add key
- *
- * This program is the CONFIDENTIAL and PROPRIETARY property
- * of FairCom(R) Corporation. Any unauthorized use, reproduction or
- * transfer of this program is strictly prohibited.
- *
- * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989 FairCom Corporation
- * (Subject to limited distribution and
- * restricted disclosure only.)
- * *** ALL RIGHTS RESERVED ***
- *
- * 4006 West Broadway
- * Columbia, MO 65203
- *
- *
- * c-tree(R) Version 4.3
- * Release C
- * February 7, 1989 17:30
- *
- */
-
- #include "ctstdr.h" /* standard i/o header */
- #include "ctoptn.h" /* c-tree configuration options */
- #include "cterrc.h" /* c-tree error codes */
- #include "ctstrc.h" /* c-tree data structures */
- #include "ctgvar.h" /* c-tree global variables */
-
- #ifdef VARLDATA
- #include "ctvrec.h"
- #endif
-
- COUNT uerr(),putnod(),LOCK(),UNLOCK();
-
- LOCAL TEXT hghbuf[MAXLEN];
-
- /* --------------------------------------------------------------------
- ADDKEY enters the key value pointed to by target into the index file
- specified by keyno and associates the value of recbyt with the key value.
- if successful, ADDKEY returns a value of zero. if the index already
- contains the key value, then a value of 2 (two) is returned and no
- change is made to the index file. values greater than 2 indicate an error
- has occurred.
- */
-
- COUNT ADDKEY(keyno,target,recbyt,typadd)
-
- COUNT keyno;
- TEXT *target;
- POINTER recbyt;
- COUNT typadd;
-
- {
- TEXT *idxval;
- FAST KEYFILE *knum;
- FAST TREEBUFF *buffer;
- COUNT npoint;
- LOCAL LONG node;
-
- VOID prpdup();
- COUNT nodser(),insert(),adroot(),tstupd(),hdrupd();
- KEYFILE *tstfnm();
- TREEBUFF *getnod();
- TREEBUFF *movrgt();
- LONG gtroot(),nodpnt();
-
- uerr_cod = 0; /* set user error cod to zero */
- if ((knum = tstfnm(keyno)) == NULL) /* test for leagl keyno */
- return(uerr_cod);
- if (chkredf(knum))
- return(uerr_cod);
- if (!recbyt)
- return(uerr(ZDRN_ERR));
-
- cpybuf((idxval = ct_dupkey),target,knum->length);
- if (knum->autodup == DUPKEY)
- prpdup(idxval,knum,&recbyt);
-
- ct_lnode = btlev = 0;
-
- #ifndef FPUTFGET
- if (!(node = gtroot(knum))) { /* tree may be empty or gtroot err */
- if (uerr_cod || tstupd(knum) ||
- adroot(knum,recbyt,DRNZERO,idxval) ||
- hdrupd(knum,(POINTER) 1))
- return(uerr_cod);
- return(NO_ERROR);
- }
- #else
- if (!(node = gtroot(knum))) {
- if (uerr_cod || tstupd(knum))
- return(uerr_cod);
- else if ((npoint = adroot(knum,recbyt,DRNZERO,idxval)) == -1)
- node = gtroot(knum);
- else if (npoint || hdrupd(knum,(POINTER) 1))
- return(uerr_cod);
- else
- return(NO_ERROR);
- }
-
- #endif
-
- while (node) { /* walk down or across tree until leaf node found */
- ct_lnode = node;
- if ((buffer = getnod(node,knum)) == NULL)
- return(uerr_cod);
- if (buffer->leaf == LEAF)
- break;
-
- if ((npoint = nodser(buffer,idxval,'L')) != -1) {
- if (npoint == -2)
- terr(218);
- if (++btlev >= MAXLEV)
- terr(240);
- ct_npath[btlev] = node;
- node = nodpnt(buffer,npoint);
- } else
- node = buffer->sucesr;
- }
-
- if (!node) /* => no leaf node found */
- terr(219);
-
- #ifdef FPUTFGET
- if (LOCK(node,knum) ||
- (buffer = movrgt(idxval,knum,getnod(node,knum))) == NULL)
- #else
- if (LOCK(node,knum) ||
- (buffer = movrgt(idxval,knum,buffer)) == NULL)
- #endif
- return(uerr_cod);
- if (!ct_tky) {
- if (UNLOCK(buffer->nodeid,knum))
- return(uerr_cod);
- return(uerr(KDUP_ERR)); /* ct_key already exists */
- }
-
- if (tstupd(knum) || insert(buffer,knum,idxval,recbyt,typadd) ||
- hdrupd(knum,(POINTER) 1))
- return(uerr_cod);
- return(NO_ERROR);
- }
-
- /* --------------------------------------------------------------------
- insert key value & backtrack as necessary
- */
-
- COUNT insert(buffer,knum,idxval,pntr,typadd)
-
- PFAST TREEBUFF *buffer;
- PFAST KEYFILE *knum;
- TEXT *idxval;
- POINTER pntr;
- COUNT typadd;
-
- {
- COUNT temp,spltel;
- UCOUNT tempb;
- LONG node,oldnode;
- FAST TREEBUFF *new;
- TEXT *tp;
-
- TREEBUFF *getnod(),*newnod();
- TREEBUFF *movrgt();
- COUNT adroot();
- TEXT *hghpnt(),*valpnt();
- LONG nodpnt();
- POINTER drnpnt();
- VOID insexp();
-
- again:
- temp = buffer->nkv + 1;
-
- /* for leaf nodes, if node already full, then must save high key.
- (note that leaf holds maxkv-1 keys (besides high key))
- */
-
- if (buffer->leaf == LEAF)
- cpybuf(hghbuf,hghpnt(buffer),buffer->klen);
-
- if (!ct_elm || ct_elm > buffer->nkv)
- ct_tky = 0;
- insexp(buffer,idxval,pntr);
- tempb = buffer->nkb;
-
- if (tempb <= buffer->maxb) {
- node = buffer->nodeid;
- if (putnod(buffer,temp) || UNLOCK(node,knum))
- return(uerr_cod);
- return(NO_ERROR);
- }
-
- if ((new = newnod(knum,&ct_nwnod,NO)) == NULL)
- return(uerr_cod);
- if (buffer->leaf == LEAF) {
- new->maxkv = knum->maxkvl;
- new->maxb = knum->maxkbl;
- if (knum->autodup == DUPKEY)
- new->confg = DUPLEAF;
- else
- new->confg = REGULAR;
- } else {
- new->maxkv = knum->maxkvn;
- new->maxb = knum->maxkbn;
- if (knum->autodup == DUPKEY)
- new->confg = DUPNONL;
- else
- new->confg = REGULAR;
- }
- if (typadd == REGADD)
- spltel = temp / 2;
- else if (typadd == INCADD)
- spltel = 6 * temp / 7;
- else
- spltel = temp / 7 + 1;
- tp = valpnt(buffer,spltel);
- /* begbyt counts to beg of split ct_key: check that split ct_key actually
- fits - INCADD with ct_key compression & keys out of order can cause
- a problem.
- */
- if ((buffer->begbyt + buffer->actlen) > buffer->maxb) {
- spltel = temp / 2;
- tp = valpnt(buffer,spltel);
- }
- cpybuf(spkey,tp,buffer->klen);
-
- pntr = drnpnt(buffer,spltel + 1);
- ct_tky = ct_tkp = tempb = 0;
- if (!buffer->ktipe)
- tp = buffer->ct_kyval + buffer->begbyt;
- #ifdef VARLKEYS
- else
- tp = buffer->keyexp;
- #endif
- if (buffer->confg & REGULAR)
- tempb = sizeof(POINTER);
- insexp(new,tp + tempb,pntr);
- tempb = buffer->begbyt + buffer->actlen;
- cpybuf(new->ct_kyval + new->nkb,buffer->ct_kyval + tempb,
- buffer->nkb - tempb);
- new->nkb += (buffer->nkb - tempb);
- buffer->nkb = buffer->begbyt;
- buffer->begbyt = buffer->actlen = buffer->lstpos = 0;
-
-
- if (buffer->leaf == LEAF) { /* set high keys */
- /* copy over high key for new node */
- cpybuf(hghpnt(new),hghbuf,buffer->klen);
-
- /* spkey holds the high key for the oldnode */
- cpybuf(hghpnt(buffer),spkey,buffer->klen);
- }
-
- new->sucesr = buffer->sucesr;
- oldnode = buffer->nodeid;
- if ((new->leaf = buffer->leaf) == LEAF)
- new->predsr = oldnode;
-
- buffer->sucesr = ct_nwnod;
- if (putnod(new,temp - spltel) || putnod(buffer,spltel))
- return(uerr_cod);
- if (new->sucesr && new->leaf == LEAF) {
- if (LOCK((LONG) new->sucesr,knum) ||
- (buffer = getnod((LONG) new->sucesr,knum)) == NULL)
- return(uerr_cod);
- buffer->predsr = ct_nwnod;
- if (putnod(buffer,buffer->nkv) || UNLOCK((LONG) new->sucesr,knum))
- return(uerr_cod);
- }
-
- idxval = spkey;
- pntr = oldnode;
- if (node = ct_npath[btlev--]) { /* parent node exists, repeat process */
- if (LOCK(node,knum) ||
- (buffer = movrgt(idxval,knum,getnod(node,knum))) == NULL)
- return(uerr_cod);
- if (nodpnt(buffer,ct_elm) != oldnode)
- /*
- * apparently we have encountered a prematurely
- * terminated node split. parent does not have
- * complete set of pointers. move right strategy
- * avoids crash.
- */
- pntr = nodpnt(buffer,ct_elm);
-
- if (UNLOCK(oldnode,knum))
- return(uerr_cod);
-
- cpybuf(buffer->ct_kyval + buffer->begbyt,&ct_nwnod,sizeof(POINTER));
- if (buffer->ktipe)
- cpybuf(buffer->keyexp,&ct_nwnod,sizeof(POINTER));
- #ifdef UNIFRMAT
- revobj(buffer->ct_kyval + buffer->begbyt,sizeof(POINTER));
- if (buffer->ktipe)
- revobj(buffer->keyexp,sizeof(POINTER));
- #endif
- goto again;
- } else { /* create new non-leaf root */
- if (UNLOCK(oldnode,knum) ||
- adroot(knum,pntr,(POINTER) ct_nwnod,spkey))
- return(uerr_cod);
- }
- return(NO_ERROR);
- }
-
-
- /* --------------------------------------------------------------------
- add new root to b-tree pointed to by knum. lpntr & rpntr are the left
- and right pointers associated with the key value pointed to by idxval.
- */
-
- COUNT adroot(knum,lpntr,rpntr,idxval)
-
- PFAST KEYFILE *knum;
- POINTER lpntr,rpntr;
- TEXT *idxval;
-
- {
- FAST TEXT *tp;
- FAST TREEBUFF *new;
- COUNT i,typ;
-
- TREEBUFF *newnod();
- TEXT *hghpnt(),*valpnt();
- COUNT redhdr(),wrthdr();
- VOID insexp();
-
- /* if last parameter in newnod == YES, the header lock
- acquired in newnod is NOT released by newnod if newnod
- is successful. If two or more processes call newnod for
- a virgin tree, then only the first will return a non-null
- value. The other calls to newnod will result in uerr_cod
- set to -1 as a signal to ADDKEY to skip regular adroot procedure.
- */
- if ((new = newnod(knum,&ct_nwnod,rpntr ? NO : YES)) == NULL)
- return(uerr_cod);
-
- if (rpntr) { /* then non-leaf root; add adjacent max high key */
- new->leaf = NOLEAF;
- new->maxkv = knum->maxkvn;
- new->maxb = knum->maxkbn;
- if (knum->autodup == DUPKEY)
- new->confg = DUPNONL;
- else
- new->confg = REGULAR;
- } else { /* leaf root (virgin tree) */
- new->leaf = LEAF;
- new->maxkv = knum->maxkvl;
- new->maxb = knum->maxkbl;
- if (knum->autodup == DUPKEY)
- new->confg = DUPLEAF;
- else
- new->confg = REGULAR;
- tp = hghpnt(new);
- }
-
- ct_tky = ct_tkp = 0;
- insexp(new,idxval,lpntr);
- if (new->leaf == NOLEAF)
- tp = hghbuf;
-
- /*
- * if additional key types are added to c-tree, then the following
- * lines of code must be expanded to properly construct the highest
- * possible key value for each type of ct_key, starting at the byte
- * pointed to by tp.
- *
- */
- i = knum->length;
- typ = knum->ktype & MSK_ALT;
-
- #ifdef FLOATKEY
- if (typ == SFLOATKEY || typ == DFLOATKEY) {
-
- /* single & double float high key based on IEEE standard. note */
- /* that some compilers will accept 7f ff ff ff ff ff ff ff */
- /* instead of 7f ef ff ff ff ff ff ff for the highest value. */
- /* we would not suggest changing to this since the index files */
- /* will be compiler dependent. */
-
- #ifdef LOW_HIGH
- for ( ; i > 0; i--)
- *tp++ = 0xff;
- if (typ == SFLOATKEY) {
- tp -= (knum->length + 1 - sizeof(float));
- *tp++ = 0x7e;
- } else {
- tp -= (knum->length + 2 - sizeof(double));
- *tp++ = 0xef;
- *tp = 0x7f;
- }
- #else
- #ifdef UNIFRMAT
- for ( ; i > 0; i--)
- *tp++ = 0xff;
- if (typ == SFLOATKEY) {
- tp -= (knum->length + 1 - sizeof(float));
- *tp++ = 0x7e;
- } else {
- tp -= (knum->length + 2 - sizeof(double));
- *tp++ = 0xef;
- *tp = 0x7f;
- }
- #else
- if (typ == SFLOATKEY) {
- *tp++ = 0x7e;
- typ = 1;
- } else {
- *tp++ = 0x7f;
- *tp++ = 0xef;
- typ = 2;
- }
- for ( ; i > typ; i--)
- *tp++ = 0xff;
- #endif
- #endif
-
- } else
- #endif
-
- for ( ; i > 0; i--)
- *tp++ = 0xff;
-
- /*
- * end of code where highest possible key value is constructed
- */
-
- if (rpntr) {
- new->nkv = i = 2;
- valpnt(new,1); /* to set last position */
- insexp(new,hghbuf,rpntr);
- } else
- i = 1;
- if (putnod(new,i))
- return(uerr_cod);
-
- #ifdef FPUTFGET
- if (rpntr && (LOCK(NODEZERO,knum) || redhdr(knum - knum->kmem)))
- return(uerr_cod);
- #endif
-
- knum->root = ct_nwnod;
-
- #ifdef NOTFORCE
- /* no action needed */
- #else
- if (wrthdr(knum))
- return(uerr_cod);
- #ifdef FPUTFGET
- if (UNLOCK(NODEZERO,knum))
- return(uerr_cod);
- #endif
- #endif
-
- return(NO_ERROR);
- }
-
-
- /* --------------------------------------------------------------------
- routine to get next available node.
- */
-
- TREEBUFF *newnod(knum,pnode,virgin)
- PFAST KEYFILE *knum;
- LONG *pnode;
- COUNT virgin; /* virgin adroot: YES or NO */
- {
- FAST TREEBUFF *buf;
-
- TREEBUFF *lrubuf(),*getnod();
- COUNT redhdr(),wrthdr();
- LONG extfil();
-
- #ifndef FPUTFGET
- CTFILE *ctnum;
- #endif
- #ifdef VARLDATA
- VHDR vrhdr;
- COUNT putvhdr();
- #endif
-
-
- #ifdef FPUTFGET
- if (LOCK(NODEZERO,knum) || redhdr(knum - knum->kmem))
- return(NULL);
- if (virgin == YES && knum->root) {
- /* someone has already added a root: send signal to adroot
- to skip virgin adroot and proceed with regular insert */
- UNLOCK(NODEZERO,knum);
- uerr_cod = -1;
- return(NULL);
- }
- #endif
-
- #ifndef FPUTFGET
- #ifdef CTSERVER
- ctnum = knum->hmem;
- #else
- ctnum = knum - knum->kmem;
- #endif
- if (*pnode = ctnum->delstk) {
- if ((buf = getnod(*pnode,ctnum)) == NULL)
- return(NULL);
- if (buf->predsr != -1L) {
- uerr_cod = KLNK_ERR;
- return(NULL);
- }
- ctnum->delstk = buf->sucesr;
- #ifdef FPUTONLY
- if (wrthdr(ctnum))
- return(NULL);
- #endif
- goto buf_return;
- }
- #endif
-
- #ifndef VARLDATA
- /* no variable length data routine support */
- if (knum->clstyp == VAT_CLOSE)
- terr(225);
- else if (!(*pnode = extfil(knum,knum->recsiz))) {
- #ifdef FPUTFGET
- UNLOCK(NODEZERO,knum);
- #endif
- return(NULL);
- }
- #else
- /* variable length data routines supported */
- if (knum->clstyp == VAT_CLOSE) {
- if (*pnode = extfil(knum,knum->recsiz + SIZVHDR)) {
- *pnode += SIZVHDR;
- vrhdr.recmrk = VNOD_FLAG;
- vrhdr.trclen = vrhdr.urclen = knum->recsiz;
- if (putvhdr(knum,*pnode,&vrhdr)) {
- #ifdef FPUTFGET
- UNLOCK(NODEZERO,knum);
- #endif
- return(NULL);
- }
- } else {
- #ifdef FPUTFGET
- UNLOCK(NODEZERO,knum);
- #endif
- return(NULL);
- }
- } else if (!(*pnode = extfil(knum,knum->recsiz))) {
- #ifdef FPUTFGET
- UNLOCK(NODEZERO,knum);
- #endif
- return(NULL);
- }
- #endif
-
- #ifdef NOTFORCE
- /* no action */
- #else
- if (wrthdr(knum))
- return(NULL);
- #ifdef FPUTFGET
- /* do not unlock header if virgin adroot in progress */
- if (virgin == NO && UNLOCK(NODEZERO,knum))
- return(NULL);
- #endif
- #endif
-
- if ((buf = lrubuf(NULL)) == NULL)
- return(NULL);
- buf_return:
- buf->nkv = buf->nkb = buf->begbyt = buf->actlen = buf->lstpos = 0;
- buf->ktipe = knum->ktype & COL_BOTH;
- buf->keyid = knum->filnum;
- buf->klen = knum->length;
- buf->nodeid = *pnode;
- buf->update = 'y';
- buf->predsr = buf->sucesr = NODEZERO;
- buf->bmem = knum->kmem;
- return(buf);
- }
-
- VOID insexp(bp,ip,pntr)
- TREEBUFF *bp;
- TEXT *ip;
- POINTER pntr;
- {
- COUNT kl,kls,movcnt,movct2,pfxcnt,pfxct2,sfxcnt,sfxct2;
- COUNT n,poff,colpfx,colpad;
- TEXT *kp;
- FAST TEXT *tp;
- FAST COUNT i;
-
- if (ct_tky > 0 || ct_tkp < 0)
- terr(235);
-
- kp = ip; /* save ip for possible latter use */
- kl = kls = bp->klen;
- colpfx = bp->ktipe & COL_PREFIX;
- colpad = bp->ktipe & COL_SUFFIX;
- if (bp->confg == DUPLEAF || bp->confg == DUPNONL)
- kls -= sizeof(POINTER);
-
- /* determine repeating suffix count */
-
- #ifdef VARLKEYS
- if (colpad) {
- sfxcnt = i = 0;
- tp = kp + kls;
- while (i++ < kls && *--tp == PADDING)
- sfxcnt++;
- } else
- sfxcnt = 0;
- #else
- sfxcnt = 0;
- #endif
-
- /* prefix count */
-
- n = kls - sfxcnt;
-
- #ifdef VARLKEYS
- if (colpfx)
- if ((pfxcnt = ct_tkp - 1) > 0) {
- if (pfxcnt > n)
- pfxcnt = n;
- if (colpad && (pfxcnt + ct_sfxctp) > kls)
- pfxcnt = kls - ct_sfxctp;
- kp += pfxcnt;
- n -= pfxcnt;
- } else
- pfxcnt = 0;
- #else
- pfxcnt = 0;
- #endif
-
- /* check for addition to end of buffer (& empty buffer ) */
-
- if (ct_tky == 0) /* assumes values for lstpos begbyt & actlen */
- tp = bp->ct_kyval + bp->begbyt + bp->actlen;
- else {
-
- /* insertion in middle or beginning of buffer */
-
- ct_tky = -ct_tky;
- movcnt = n + kl - kls;
-
- #ifdef VARLKEYS
- if (colpfx)
- movcnt++;
- if (colpad)
- movcnt++;
- #endif
-
- /* see if following value is further compressed and shift */
-
- if (bp->confg & REGULAR)
- movcnt += (poff = sizeof(POINTER));
- else
- poff = 0;
-
- tp = bp->ct_kyval + bp->begbyt;
-
- #ifdef VARLKEYS
- if (colpfx) {
- pfxct2 = *(tp + poff) & 0x00ff;
- if (colpad)
- sfxct2 = *(tp + poff + 1) & 0x00ff;
- else
- sfxct2 = 0;
-
- if (--ct_tky + sfxct2 > kls)
- ct_tky = kls - sfxct2;
- while ((ct_tky + sfxcnt) > kls)
- if (ip[ct_tky - 1] == PADDING)
- ct_tky--;
- else
- break;
- if (ct_tky <= pfxct2)
- shfrgt(movcnt,bp,bp->begbyt);
- else {
- if ((movct2 = ct_tky - pfxct2) > movcnt)
- terr(236);
- bp->actlen -= movct2;
- *(tp + movct2 + poff) = ct_tky;
- if (colpad)
- *(tp + movct2 + poff + 1) = sfxct2;
- if (poff) {
- shflft(movct2,bp,bp->begbyt + poff +
- movct2);
- bp->nkb -= movct2;
- shfrgt(movcnt,bp,bp->begbyt);
- } else {
- shfrgt(movcnt - movct2,bp,
- bp->begbyt + movct2);
- bp->nkb -= movct2;
- }
- }
- } else
- #endif
- shfrgt(movcnt,bp,bp->begbyt);
-
- tp = bp->ct_kyval + bp->begbyt;
- bp->lstpos++;
- bp->begbyt += movcnt;
- }
-
- /* stuff bytes in place */
-
- if (bp->confg & REGULAR) {
- #ifdef UNIFRMAT
- revobj(&pntr,sizeof(POINTER));
- #endif
- cpybuf(tp,&pntr,sizeof(POINTER));
- tp += sizeof(POINTER);
- bp->nkb += sizeof(POINTER);
- }
-
- #ifdef VARLKEYS
- if (colpfx) {
- bp->nkb++;
- *tp++ = pfxcnt;
- }
- if (colpad) {
- bp->nkb++;
- *tp++ = sfxcnt;
- }
- #endif
-
- cpybuf(tp,kp,n);
- bp->nkb += n;
-
- if (kls < kl) {
- bp->nkb += sizeof(POINTER);
- cpybuf(tp + n,ip + kls,sizeof(POINTER));
- }
-
- }
-
- /* end of ctaddk.c */
-