mirror of
https://github.com/antoinevignau/source.git
synced 2024-10-31 22:06:40 +00:00
1 line
21 KiB
C
Executable File
1 line
21 KiB
C
Executable File
/***********************************************************************\
|
||
|
||
Filename: clam.c
|
||
|
||
\***********************************************************************/
|
||
|
||
#include <memory.h>
|
||
#include <intmath.h>
|
||
#include "string.h"
|
||
#include "language.h"
|
||
#include "spmemory.h"
|
||
#include "clam.h"
|
||
#include "environ.h"
|
||
#include "sp.h"
|
||
#include "spdef.h"
|
||
#include <prodos.h>
|
||
|
||
unsigned clamfree();
|
||
static int clfetch();
|
||
static int clbinret();
|
||
|
||
/* storage structure for one word in a CLAM */
|
||
|
||
typedef struct
|
||
{
|
||
short ib_info; /* flags, or "block to descend to" */
|
||
char ib_bs; /* backspace of word from last word */
|
||
char ib_delta[1]; /* delta of word */
|
||
} INFOBSD;
|
||
|
||
#define ib(x) ((INFOBSD *)(x))
|
||
|
||
/* block information structure, at top of every block */
|
||
|
||
typedef struct
|
||
{
|
||
short st_nextb; /* index of next block on this level */
|
||
short st_used; /* bytes occupied by BLKSTATS and INFOBSDs */
|
||
} BLKSTATS;
|
||
|
||
#define bs(x) ((BLKSTATS *)(x))
|
||
|
||
char Cldecomp[LONGWORD+2]; /* The CLAM decompression buffer. */
|
||
static int Clinfo; /* The info for the CLAM word. */
|
||
static int Clused; /* The amount of space in the block. */
|
||
static char *Clwsave; /* The start of the current word. */
|
||
static char Clbin[3]; /* The bin characters */
|
||
|
||
#define Curclam ((CLAM *)Sccurlist) /* The current CLAM. */
|
||
#define CL_DATABIT 0x8000 /* bit for a data block. */
|
||
#define CL_NOBLK (-1) /* "no next block" indicator */
|
||
#define MAXDEPTH 6 /* maximum CLAM depth */
|
||
|
||
/* Read a block from the CLAM. */
|
||
|
||
static int clblock(block, flags)
|
||
int block; /* The block number to read. */
|
||
int flags;
|
||
{
|
||
extern char *memread();
|
||
register CLAM *cp = Curclam;
|
||
|
||
/* Read the block. */
|
||
|
||
if ((cp->cl_blk0 = memread(block, cp->cl_file, flags +
|
||
(block ? MM_PR1 : MM_PR0))) == NULL)
|
||
{
|
||
Scerror = ERR_CLAM | ERR_IO;
|
||
return (FALSE);
|
||
}
|
||
/* Initialize the decompression variables. */
|
||
|
||
Clused = bs(cp->cl_blk0)->st_used & (CL_DATABIT - 1);
|
||
cp->cl_blkptr = cp->cl_blk0 + sizeof(BLKSTATS);
|
||
Scendptr = Cldecomp;
|
||
return (TRUE);
|
||
}
|
||
|
||
/* Decompress the next word from a CLAM block. */
|
||
|
||
static int clgetword()
|
||
{
|
||
register char *ptr;
|
||
register char *dest;
|
||
register CLAM *cp = Curclam;
|
||
char *ptr0;
|
||
|
||
ptr = cp->cl_blkptr;
|
||
Clwsave = ptr;
|
||
|
||
/* If at end, set Clinfo to zero so clfindbin() will go to the
|
||
next. */
|
||
|
||
if (ptr - cp->cl_blk0 >= Clused)
|
||
{
|
||
Clinfo = 0;
|
||
return (FALSE);
|
||
}
|
||
Clinfo = ib(ptr)->ib_info;
|
||
dest = Scendptr - ib(ptr)->ib_bs;
|
||
ptr0 = ptr = ib(ptr)->ib_delta;
|
||
while (*dest++ = *ptr++)
|
||
;
|
||
Scendptr = dest - 1;
|
||
if (((ptr - ptr0) & 1) == 0) {
|
||
++ptr;
|
||
}
|
||
cp->cl_blkptr = ptr;
|
||
return (TRUE);
|
||
}
|
||
|
||
/* Advance the CLAM to the next word with non-zero flags. */
|
||
|
||
static int cladvance()
|
||
{
|
||
while (1) {
|
||
/* Decompress one word. */
|
||
|
||
while (clgetword()) {
|
||
if (Clinfo) {
|
||
return (TRUE);
|
||
}
|
||
}
|
||
/* Link to the next block. */
|
||
|
||
if (Sccurblk == 0 || (Sccurblk = bs(Curclam->cl_blk0)->st_nextb)
|
||
== CL_NOBLK)
|
||
return (FALSE);
|
||
|
||
/* And read it. */
|
||
|
||
if (!clblock(Sccurblk, MM_READ))
|
||
return (FALSE);
|
||
}
|
||
}
|
||
|
||
/* Return non-zero if the current block is a data block. */
|
||
|
||
static int clisdata()
|
||
{
|
||
return (bs(Curclam->cl_blk0)->st_used & CL_DATABIT);
|
||
}
|
||
|
||
/* Encode a word for CLAM lookup. */
|
||
|
||
static int clencode(word, peword)
|
||
char *word; /* The word to encode */
|
||
char *peword; /* The encoded word */
|
||
{
|
||
extern VOID phfull();
|
||
|
||
/* Check the word length. */
|
||
|
||
if (!word[0] || strlen((char *) word) >= LONGWORD)
|
||
{
|
||
Scerror = ERR_CLAM | ERR_WLEN;
|
||
return (FALSE);
|
||
}
|
||
|
||
/* Phoneticallly encode the word. */
|
||
|
||
phfull(word, peword, FALSE);
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
/* Form an INFOBSD out of the arguments and write it to ibptr. */
|
||
|
||
static char *
|
||
makeib(ibptr, info, prev, word)
|
||
char *ibptr;
|
||
int info;
|
||
char *prev;
|
||
char *word;
|
||
{
|
||
int bsval;
|
||
|
||
ib(ibptr)->ib_info = info;
|
||
if (!prev)
|
||
bsval = 0;
|
||
else
|
||
{
|
||
bsval = strdiff((char *)prev, (char *)word);
|
||
word += bsval;
|
||
bsval = strlen((char *)prev) - bsval;
|
||
}
|
||
ib(ibptr)->ib_bs = bsval;
|
||
|
||
ibptr = ib(ibptr)->ib_delta;
|
||
prev = word;
|
||
while (*ibptr++ = *word++)
|
||
;
|
||
if (((word - prev) & 1) == 0) {
|
||
*ibptr++ = 0;
|
||
}
|
||
return (ibptr);
|
||
}
|
||
|
||
/* Open a CLAM file. `fname' is the name of the file to open. The flags
|
||
argument can contain CL_INIT to create a new CLAM, CL_READONLY to open a
|
||
CLAM that is not to be modified, and CL_REORG to allow block splitting at
|
||
the end of a block instead of the middle.
|
||
|
||
Returns a pointer to the structure for the CLAM, or NULL on error.
|
||
|
||
Every clamalloc() call without CL_READONLY must have a corresponding
|
||
clamclose() call in order to make all CLAM updates be written to disk.
|
||
*/
|
||
|
||
CLAM *clamalloc(fname, flags, ftype, atype)
|
||
char *fname;
|
||
int flags;
|
||
int ftype; /* File type if new clam */
|
||
long atype; /* Auxtype if new clam */
|
||
{
|
||
CLAM *cp; /* location of new CLAM structure */
|
||
long bytes; /* size of the file in bytes. */
|
||
char firstword[3]; /* empty word to insert first */
|
||
/* Don't need these... <20><>MSL 7/25/89
|
||
struct PrefixRec prec;
|
||
char pbuf[30];
|
||
*/
|
||
/* allocate the new structure */
|
||
|
||
if (!(cp = (CLAM *) zalloc(_SPID, sizeof(CLAM))))
|
||
{
|
||
Scerror = ERR_CLAM | ERR_ALLOC;
|
||
return (NULL);
|
||
}
|
||
Sccurlist = (char *) cp;
|
||
|
||
/* ok here... */
|
||
|
||
/* Initialize the CLAM if the user specifies this. */
|
||
|
||
if (flags & CL_INIT)
|
||
{
|
||
/* create the CLAM file. */
|
||
|
||
if ((cp->cl_file = stdcreate(fname, ftype, atype)) == H_ERROR)
|
||
{
|
||
clamfree(cp);
|
||
return (NULL);
|
||
}
|
||
|
||
/* Get a buffer for the first block of the file. */
|
||
|
||
if (!clblock(0, MM_WRITE))
|
||
{
|
||
clamfree(cp);
|
||
return (NULL);
|
||
}
|
||
|
||
/* initialize first block's BLKSTATS structure */
|
||
|
||
cp->cl_screv = CL_REV;
|
||
cp->cl_nblks = 1;
|
||
cp->cl_blk0[0] = CL_REV;
|
||
|
||
/* Initialize the CLAM data with a null word. */
|
||
|
||
firstword[0] = firstword[1] = MINALPH;
|
||
firstword[2] = 0;
|
||
bs(cp->cl_blk0)->st_used = (makeib(cp->cl_blk0 + sizeof(BLKSTATS),
|
||
0, (char *)0, firstword) - cp->cl_blk0) | CL_DATABIT;
|
||
}
|
||
else
|
||
{
|
||
/* open the file */
|
||
|
||
/* ok here */
|
||
|
||
/* Why should we do a GetPrefix? <20><>MSL 7/25/89
|
||
prec.prefixNum = 1;
|
||
prec.prefix = pbuf;
|
||
GET_PREFIX(&prec);
|
||
*/
|
||
|
||
if ((cp->cl_file = stdopen(fname, (flags & CL_READONLY) ? H_RDONLY : H_RDWR)) == H_ERROR)
|
||
{
|
||
Scerror = ERR_CLAM | ERR_ACCESS;
|
||
clamfree(cp);
|
||
return (NULL);
|
||
}
|
||
|
||
/* NOT OK HERE!!! */
|
||
|
||
/* Get the size of the file. */
|
||
|
||
if ((bytes = stdend(cp->cl_file)) < 0)
|
||
{
|
||
Scerror = ERR_CLAM | ERR_IO;
|
||
clamfree(cp);
|
||
return (NULL);
|
||
}
|
||
|
||
cp->cl_nblks = (int)(bytes / MM_BLKSIZE);
|
||
|
||
/* Get the first block of the file. */
|
||
|
||
if (!clblock(0, MM_READ))
|
||
{
|
||
clamfree(cp);
|
||
return (NULL);
|
||
}
|
||
}
|
||
cp->cl_flags = flags & ~CL_LATEST;
|
||
cp->cl_searchb = CL_NOBLK;
|
||
|
||
/* not ok here */
|
||
|
||
return (cp);
|
||
}
|
||
|
||
/* Close the CLAM file and free the memory for the CLAM structure. */
|
||
|
||
unsigned clamfree(cp)
|
||
CLAM *cp;
|
||
{
|
||
unsigned err=OKAY;
|
||
|
||
if (cp->cl_file != H_ERROR)
|
||
{
|
||
err = memflush(cp->cl_file);
|
||
stdclose(cp->cl_file);
|
||
}
|
||
nzfree(cp);
|
||
return err;
|
||
}
|
||
|
||
/* Look for a word in a CLAM; if it is found, returned its flags otherwise
|
||
return IW_NOTFOUND. */
|
||
|
||
clamword(word, cp)
|
||
char *word;
|
||
CLAM *cp;
|
||
{
|
||
int tmp;
|
||
char peword[2*MAXWORD]; /* phonetic form of input word */
|
||
|
||
if (!clencode(word, peword))
|
||
return (IW_NOTFOUND);
|
||
|
||
if (!clfetch(peword, FALSE))
|
||
return (IW_NOTFOUND);
|
||
|
||
return (Clinfo);
|
||
}
|
||
|
||
/* Fetch a word from a CLAM. If this word is not in the CLAM, the CLAM
|
||
decompression pointers will point to the smallest word greater than or
|
||
equal to the argument. */
|
||
|
||
static int clfetch(peword, find)
|
||
char *peword; /* The word to look for */
|
||
int find; /* Find the data block. */
|
||
{
|
||
int tmp;
|
||
|
||
/* Look through the index blocks for the data block with could
|
||
contain the word. */
|
||
|
||
tmp = 0;
|
||
while (1)
|
||
{
|
||
/* Read an index or data block. */
|
||
|
||
if (!clblock(tmp, MM_READ))
|
||
return (FALSE);
|
||
|
||
/* Stop the loop if this is a data block. */
|
||
|
||
if (clisdata())
|
||
break;
|
||
|
||
/* The index block consists of a sequence of words, each
|
||
associated with a block number. The block associated
|
||
with a given index word contains words greater than or
|
||
equal to the index word and less than the next index
|
||
word. */
|
||
|
||
tmp = 0;
|
||
while (clgetword() && strcmp(peword, Cldecomp) >= 0)
|
||
tmp = Clinfo;
|
||
|
||
/* if word comes before first word in the current block, we
|
||
know it isn't in the clam. */
|
||
|
||
if (!find && tmp == 0)
|
||
return (FALSE);
|
||
}
|
||
Sccurblk = tmp;
|
||
|
||
/* Decompress the block until a word is found greater than or equal
|
||
to the query. */
|
||
|
||
while (clgetword() && (tmp = strcmp(peword, Cldecomp)) >= 0)
|
||
if (tmp == 0)
|
||
return (TRUE);
|
||
|
||
/* The word is not in the CLAM. */
|
||
|
||
return (FALSE);
|
||
}
|
||
|
||
/* Read words from a CLAM. If init is TRUE, the first word of the CLAM is
|
||
returned. If init is FALSE, the next word is returned. The words are
|
||
sorted by their internal coding. The return values are: OKAY, CL_EOF,
|
||
and ERROR. Cl_EOF is returned when there are no more words in the CLAM.
|
||
*/
|
||
|
||
clamnext(buffer, flagsptr, init, cp)
|
||
char *buffer; /* The buffer to return the word in. */
|
||
int *flagsptr; /* Where to return the word's info. */
|
||
int init; /* Return first word flag. */
|
||
CLAM *cp; /* The CLAM to look in. */
|
||
{
|
||
int phonchr;
|
||
char *src;
|
||
int prevchr;
|
||
char firstword[3];
|
||
|
||
if (init)
|
||
{
|
||
/* This is the dummy word at the start of the CLAM. */
|
||
|
||
firstword[0] = firstword[1] = MINALPH;
|
||
firstword[2] = 0;
|
||
|
||
/* Position to that word. */
|
||
|
||
if (!clfetch(firstword, TRUE))
|
||
return (ERROR);
|
||
}
|
||
else
|
||
{
|
||
/* Restore the decompression state from the CLAM structure. */
|
||
|
||
if (cp->cl_searchb < 0 || !clblock(cp->cl_searchb, MM_READ))
|
||
return (ERROR);
|
||
cp->cl_blkptr = cp->cl_blk0 + cp->cl_blksav;
|
||
Scendptr = strecpy(Cldecomp, cp->cl_word);
|
||
Sccurblk = cp->cl_searchb;
|
||
}
|
||
|
||
/* Find the next word. */
|
||
|
||
if (!cladvance())
|
||
{
|
||
cp->cl_searchb = CL_NOBLK;
|
||
return (CL_EOF);
|
||
}
|
||
|
||
/* Save the decompression information in the clam structure. */
|
||
|
||
cp->cl_searchb = Sccurblk;
|
||
cp->cl_blksav = cp->cl_blkptr - cp->cl_blk0;
|
||
strecpy(cp->cl_word, Cldecomp);
|
||
|
||
/* Return the info stored with the word. */
|
||
|
||
*flagsptr = Clinfo;
|
||
|
||
/* If the word is a special, return just the special part. */
|
||
|
||
if (Clinfo & IW_SPECIAL)
|
||
{
|
||
strecpy(buffer, strchr(Cldecomp + 2, E_LRIND) + 1);
|
||
return (OKAY);
|
||
}
|
||
|
||
/* The word is not a special; decode the phonetics. */
|
||
|
||
src = Cldecomp + 2;
|
||
while (*src)
|
||
{
|
||
switch (phonchr = Engphtab[*src++][0])
|
||
{
|
||
case E_FILL:
|
||
break;
|
||
case E_REPEAT:
|
||
*buffer++ = prevchr;
|
||
break;
|
||
default:
|
||
prevchr = *buffer++ = phonchr;
|
||
}
|
||
}
|
||
*buffer = 0;
|
||
return (OKAY);
|
||
}
|
||
|
||
/* Locate first word of a CLAM bin. The word found is returned in
|
||
Scdecomp. */
|
||
|
||
clfindbin(binstr)
|
||
char *binstr;
|
||
{
|
||
Clbin[0] = binstr[0];
|
||
Clbin[1] = binstr[1];
|
||
Clbin[2] = 0;
|
||
|
||
if (clfetch(Clbin, TRUE) || Clinfo == 0)
|
||
return (clbinnext());
|
||
return (clbinret(Clbin));
|
||
}
|
||
|
||
/* Using the last decompressed word at lastptr, decompress next word from
|
||
CLAM bin, putting it in clword. At bin boundary, return NULL, otherwise
|
||
return new lastptr. */
|
||
|
||
clbinnext()
|
||
{
|
||
/* Next, advance to the next word; stop if not in the same bin. */
|
||
|
||
if (!cladvance())
|
||
return (FALSE);
|
||
|
||
/* Check the word and return it. */
|
||
|
||
return (clbinret(Clbin));
|
||
}
|
||
|
||
static int clbinret(bin)
|
||
char *bin; /* The bin the word must be in. */
|
||
{
|
||
char *source;
|
||
char *dest;
|
||
|
||
/* Return if the word is not in the desired bin. */
|
||
|
||
if (bin[0] != Cldecomp[0] || bin[1] != Cldecomp[1])
|
||
return (FALSE);
|
||
|
||
/* Store the flags. */
|
||
|
||
Scfdecomp[0] = Clinfo;
|
||
Scfdecomp[1] = 0;
|
||
Sctag = 0;
|
||
|
||
/* Remove the hyphenation characters and put the word into
|
||
Scdecomp. */
|
||
|
||
source = Cldecomp;
|
||
dest = Scdecomp;
|
||
while (*source)
|
||
{
|
||
if (*source == E_LRIND)
|
||
{
|
||
strecpy(dest, source);
|
||
return (TRUE);
|
||
}
|
||
else
|
||
*dest++ = *source;
|
||
++source;
|
||
}
|
||
*dest = 0;
|
||
return (TRUE);
|
||
}
|
||
|
||
/* Add a word to the CLAM. */
|
||
|
||
clamadd(word, flags, cp)
|
||
char *word; /* The word to add. */
|
||
int flags; /* The word's flags. */
|
||
CLAM *cp; /* The CLAM to add to. */
|
||
{
|
||
char *bptr;
|
||
int len;
|
||
char *dptr;
|
||
int tmp;
|
||
char *wptr;
|
||
int level;
|
||
int isdata;
|
||
int block[MAXDEPTH]; /* block numbers */
|
||
char peword[2*MAXWORD]; /* phonetically encoded word */
|
||
char *buffer;
|
||
|
||
buffer = zalloc(_SPID, MM_BLKSIZE + sizeof(INFOBSD) + LONGWORD + 3);
|
||
|
||
Sccurlist = (char *) cp;
|
||
|
||
/* Encode the word. */
|
||
|
||
if (!clencode(word, peword))
|
||
{
|
||
nzfree(buffer);
|
||
return (ERROR);
|
||
}
|
||
|
||
/* Find the data block which the word is to be put into. When this
|
||
loop is done, level will be the depth of the tree,
|
||
block[0:level-1] will contain the block numbers traversed. */
|
||
|
||
level = block[0] = 0;
|
||
while (1)
|
||
{
|
||
if (!clblock(block[level], MM_READ))
|
||
{
|
||
nzfree(buffer);
|
||
return (ERROR);
|
||
}
|
||
if (clisdata())
|
||
break;
|
||
len = 0;
|
||
while (clgetword() && strcmp(peword, Cldecomp) >= 0)
|
||
len = Clinfo;
|
||
block[++level] = len;
|
||
}
|
||
|
||
/* Insert the data; split blocks as necessary. If the root block is
|
||
split, the program breaks out from the loop, otherwise it returns
|
||
when a block does not need splitting. At the top of the loop
|
||
block[level] is the block to insert into, peword is the word to
|
||
insert, and flags is the info to be associated with it. */
|
||
|
||
while (level >= 0)
|
||
{
|
||
/* Read an index or data block. */
|
||
|
||
if (!clblock(block[level], MM_READ|MM_WRITE))
|
||
{
|
||
nzfree(buffer);
|
||
return (ERROR);
|
||
}
|
||
isdata = clisdata();
|
||
|
||
/* Decompress the block until a word is found greater than
|
||
or equal to the word to be inserted. If the word is
|
||
equal to the word to be inserted then this will be a data
|
||
block; the word's flags will be updated. When this code
|
||
exits, dptr is the insertion point, Scdecomp contains the
|
||
word before the insertion. If the insertion is at the
|
||
end of the block, tmp is -1; otherwise, Cldecomp contains
|
||
the word at the insertion and tmp is its info.
|
||
Clamptr->cl_blkptr points to the data after the word at
|
||
the insertion. */
|
||
|
||
Cldecomp[0] = 0;
|
||
while (1)
|
||
{
|
||
strecpy(Scdecomp, Cldecomp);
|
||
if (!clgetword())
|
||
{
|
||
len = -1;
|
||
break;
|
||
}
|
||
if ((len = strcmp(peword, Cldecomp)) == 0)
|
||
{
|
||
ib(Clwsave)->ib_info = flags;
|
||
nzfree(buffer);
|
||
return (OKAY);
|
||
}
|
||
if (len < 0)
|
||
{
|
||
len = Clinfo;
|
||
break;
|
||
}
|
||
}
|
||
dptr = Clwsave;
|
||
tmp = len;
|
||
|
||
/* Construct in `buffer' the entry for the word that is
|
||
being inserted. bptr will point to the end of the
|
||
entry. */
|
||
|
||
bptr = makeib(buffer, flags, Scdecomp, peword);
|
||
|
||
/* If the insertion was not at the end of the block, add the
|
||
word at the insertion point and then copy the reaminder
|
||
of the block into the buffer. */
|
||
|
||
if (tmp >= 0)
|
||
{
|
||
/* Construct the word after the inserted word. */
|
||
|
||
bptr = makeib(bptr, tmp, peword, Cldecomp);
|
||
|
||
/* Copy the remainder of the block. */
|
||
|
||
len = Clused - (cp->cl_blkptr - cp->cl_blk0);
|
||
scmove(bptr, cp->cl_blkptr, len);
|
||
bptr += len;
|
||
}
|
||
|
||
/* Now, the new block exists in two parts: from blk0 to
|
||
dptr, and from buffer to bptr. If the total is smaller
|
||
than one block, construct the new block from the data and
|
||
return. */
|
||
|
||
len = (dptr - cp->cl_blk0) + (bptr - buffer);
|
||
bs(cp->cl_blk0)->st_used = len | isdata;
|
||
if (len <= MM_BLKSIZE)
|
||
{
|
||
scmove(dptr, buffer, bptr - buffer);
|
||
nzfree(buffer);
|
||
return (OKAY);
|
||
}
|
||
|
||
/* The block has to be split: first, create the whole block
|
||
in the buffer. Bptr is the end of data in the buffer. */
|
||
|
||
len = dptr - cp->cl_blk0;
|
||
scmove(buffer + len, buffer, bptr - buffer);
|
||
scmove(buffer, cp->cl_blk0, len);
|
||
bptr += len;
|
||
|
||
/* Now, find the place to split. If the reorg flag is on
|
||
and the word was added to the end of the block then
|
||
split near the end; otherwise, split near the middle. */
|
||
|
||
len = MM_BLKSIZE;
|
||
if (tmp >= 0 || !(cp->cl_flags & CL_REORG))
|
||
len = MM_BLKSIZE / 2;
|
||
dptr = buffer + len;
|
||
|
||
/* Find the last word in the buffer whose start is before
|
||
the split position. Wptr will point to the word that is
|
||
to go in the second block. Scdecomp will contain the
|
||
first word of the first block. This will be used if this
|
||
is the root block. Cldecomp and Clinfo define the first
|
||
word for the second block. Clamptr->cl_blkptr points to
|
||
the rest of the words to be put in the second block. */
|
||
|
||
wptr = cp->cl_blk0;
|
||
Clused = MM_BLKSIZE + 1;
|
||
cp->cl_blk0 = buffer;
|
||
cp->cl_blkptr = buffer + sizeof(BLKSTATS);
|
||
Scendptr = Cldecomp;
|
||
clgetword();
|
||
strecpy(Scdecomp, Cldecomp);
|
||
do
|
||
clgetword();
|
||
while (cp->cl_blkptr <= dptr);
|
||
cp->cl_blk0 = wptr;
|
||
wptr = cp->cl_blkptr;
|
||
|
||
/* Now, make the first block. Tmp returns the next block,
|
||
this is stored in the second block. Wptr is the
|
||
info after the word being inserted before. */
|
||
|
||
len = Clwsave - buffer;
|
||
dptr = cp->cl_blk0;
|
||
scmove(dptr + sizeof(BLKSTATS), buffer + sizeof(BLKSTATS),
|
||
len - sizeof(BLKSTATS));
|
||
bs(dptr)->st_used = len | isdata;
|
||
tmp = level ? bs(dptr)->st_nextb : CL_NOBLK;
|
||
bs(dptr)->st_nextb = cp->cl_nblks;
|
||
|
||
/* Get a block to put the second part into. */
|
||
|
||
if (!clblock(cp->cl_nblks, MM_WRITE))
|
||
{
|
||
nzfree(buffer);
|
||
return (ERROR);
|
||
}
|
||
|
||
/* Put the first word into the buffer. */
|
||
|
||
dptr = makeib(cp->cl_blk0 + sizeof(BLKSTATS), Clinfo, (char *)0,
|
||
Cldecomp);
|
||
|
||
/* Copy the remaining words and set up the block header. */
|
||
|
||
len = bptr - wptr;
|
||
scmove(dptr, wptr, len);
|
||
bptr = cp->cl_blk0;
|
||
bs(bptr)->st_nextb = tmp;
|
||
bs(bptr)->st_used = (dptr + len - bptr) | isdata;
|
||
|
||
/* Set up info for the next iteration of the loop. */
|
||
|
||
strecpy(peword, Cldecomp);
|
||
flags = cp->cl_nblks++;
|
||
--level;
|
||
}
|
||
|
||
/* Put the old root block at the end of the CLAM. */
|
||
|
||
if (!memswitch(cp->cl_file, 0, cp->cl_nblks++))
|
||
{
|
||
nzfree(buffer);
|
||
return (ERROR);
|
||
}
|
||
|
||
/* Get the root block. */
|
||
|
||
if (!clblock(0, MM_WRITE))
|
||
{
|
||
nzfree(buffer);
|
||
return (ERROR);
|
||
}
|
||
|
||
/* Construct the words of the block. */
|
||
|
||
dptr = makeib(cp->cl_blkptr, cp->cl_nblks-1, (char *) 0, Scdecomp);
|
||
dptr = makeib(dptr, cp->cl_nblks - 2, Scdecomp, Cldecomp);
|
||
|
||
/* Set up the block header. */
|
||
|
||
bptr = cp->cl_blk0;
|
||
bptr[0] = CL_REV;
|
||
bs(bptr)->st_used = dptr - bptr;
|
||
|
||
/* All done. */
|
||
|
||
nzfree(buffer);
|
||
return (OKAY);
|
||
}
|