[comp.binaries.ibm.pc] ARC for SYS V: Part 3 of 5

boneill@hawk.ulowell.edu (SoftXc Coordinator) (03/26/88)

Article 3347 of net.sources:
Path: brl-smoke!brl-adm!rutgers!clyde!burl!codas!cpsc6a!cpsc6b!crs
From: crs@cpsc6b.cpsc6a.ATT.COM (C. R. Seaman)
Newsgroups: net.sources
Subject: System V ARC Ver. 1.1, Part 3 of 3
Message-ID: <249@cpsc6b.cpsc6a.ATT.COM>
Date: 30 Mar 87 23:46:42 GMT
Distribution: usa
Organization: AT&T (CPSC), Oakland, CA
Lines: 1135
Keywords: arc


[Hello, Line eater.  NICE Line eater.  ARGHHHHHH!!!!]

This is part 3 of System V ARC. see part 1 for details

---------------------------- CUT HERE!! ----------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	arcsq.c
#	arcsvc.c
#	arctst.c
#	arcunp.c
#	arcusq.c
# This archive created: Sun Mar 22 10:47:39 1987
# By:	C. R. Seaman ()
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'arcsq.c'" '(16916 characters)'
if test -f 'arcsq.c'
then
	echo shar: "will not over-write existing file 'arcsq.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arcsq.c'
	X/*
	X *	arcsq.c	1.1
	X *
	X *	Author: Thom Henderson
	X *	Original System V port: Mike Stump
	X *	Enhancements, Bug fixes, and cleanup: Chris Seaman
	X *	Date: Fri Mar 20 09:57:02 1987
	X *	Last Mod.	3/21/87
	X *
	X */
	X
	X/*
	X * ARC - Archive utility - ARCSQ
	X * 
	X * Version 3.10, created on 01/30/86 at 20:10:46
	X * 
	X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
	X * 
	X *     Description:
	X *          This file contains the routines used to squeeze a file
	X *          when placing it in an archive.
	X * 
	X *     Programming notes:
	X *          Most of the routines used for the Huffman squeezing algorithm
	X *          were lifted from the SQ program by Dick Greenlaw, as adapted
	X *          to CI-C86 by Robert J. Beilstein.
	X */
	X
	X#include "arc.h"
	X
	X/* stuff for Huffman squeezing */
	X
	X#define TRUE 1
	X#define FALSE 0
	X#define ERROR (-1)
	X#define SPEOF 256                      /* special endfile token */
	X#define NOCHILD (-1)                   /* marks end of path through tree */
	X#define NUMVALS 257                    /* 256 data values plus SPEOF*/
	X#define NUMNODES (NUMVALS+NUMVALS-1)   /* number of nodes */
	X#define MAXCOUNT (unsigned INT) 65535  /* biggest unsigned integer */
	X
	X/*
	X * The following array of structures are the nodes of the
	X * binary trees. The first NUMVALS nodes become the leaves of the
	X * final tree and represent the values of the data bytes being
	X * encoded and the special endfile, SPEOF.
	X * The remaining nodes become the internal nodes of the final tree.
	X */
	X
	Xstruct nd {                            /* shared by unsqueezer */
	X unsigned INT weight;                  /* number of appearances */
	X INT tdepth;                           /* length on longest path in tree */
	X INT lchild, rchild;                   /* indices to next level */
	X}   node[NUMNODES];                    /* use large buffer */
	X
	Xstatic INT dctreehd;                   /* index to head of final tree */
	X
	X/*
	X * This is the encoding table:
	X * The bit strings have first bit in low bit.
	X * Note that counts were scaled so code fits unsigned integer.
	X */
	X
	Xstatic INT codelen[NUMVALS];           /* number of bits in code */
	Xstatic unsigned INT code[NUMVALS];     /* code itself, right adjusted */
	Xstatic unsigned INT tcode;             /* temporary code value */
	Xstatic long valcount[NUMVALS];         /* actual count of times seen */
	X
	X/* Variables used by encoding process */
	X
	Xstatic INT curin;                      /* value currently being encoded */
	Xstatic INT cbitsrem;                   /* # of code string bits left */
	Xstatic unsigned INT ccode;             /* current code right justified */
	X
	XINT init_sq()                          /* prepare for scanning pass */
	X{
	X    INT i;                             /* node index */
	X
	X    /*
	X     * Initialize all nodes to single element binary trees
	X     * with zero weight and depth.
	X     */
	X
	X    for (i=0; i<NUMNODES; ++i)
	X    {
	X        node[i].weight = 0;
	X        node[i].tdepth = 0;
	X        node[i].lchild = NOCHILD;
	X        node[i].rchild = NOCHILD;
	X    }
	X
	X    for (i=0; i<NUMVALS; i++)
	X        valcount[i] = 0;
	X}
	X
	XINT scan_sq(c)                         /* add a byte to the tables */
	XINT c;                                 /* byte to add */
	X{
	X    unsigned INT *wp;                  /* speeds up weight counting */
	X
	X    /* Build frequency info in tree */
	X
	X    if (c == EOF)                      /* it's traditional */
	X        c = SPEOF;                     /* dumb, but traditional */
	X
	X    if (*(wp = &node[c].weight) !=  MAXCOUNT)
	X        ++(*wp);                       /* bump weight counter */
	X
	X    valcount[c]++;                     /* bump byte counter */
	X}
	X
	Xlong pred_sq()                         /* predict size of squeezed file */
	X{
	X    INT i;
	X    INT btlist[NUMVALS];               /* list of intermediate b-trees */
	X    INT listlen;                       /* length of btlist */
	X    unsigned INT ceiling;              /* limit for scaling */
	X    long size = 0;                     /* predicted size */
	X    INT numnodes;                      /* # of nodes in simplified tree */
	X    INT scale();
	X    INT heap();
	X    INT bld_tree();
	X    INT buildenc();
	X    INT init_enc();
	X
	X    scan_sq(EOF);                      /* signal end of input */
	X
	X    ceiling = MAXCOUNT;
	X
	X    /* Keep trying to scale and encode */
	X
	X    do
	X    {
	X        scale(ceiling);
	X        ceiling /= 2;                  /* in case we rescale */
	X
	X        /*
	X         * Build list of single node binary trees having
	X         * leaves for the input values with non-zero counts
	X         */
	X
	X        for (i=listlen=0; i<NUMVALS; ++i)
	X        {
	X            if (node[i].weight != 0)
	X            {
	X                node[i].tdepth = 0;
	X                btlist[listlen++] = i;
	X            }
	X        }
	X
	X        /*
	X         * Arrange list of trees into a heap with the entry
	X         * indexing the node with the least weight at the top.
	X         */
	X
	X        heap(btlist,listlen);
	X
	X        /* Convert the list of trees to a single decoding tree */
	X
	X        bld_tree(btlist,listlen);
	X
	X        /* Initialize the encoding table */
	X
	X        init_enc();
	X
	X        /*
	X         * Try to build encoding table.
	X         * Fail if any code is > 16 bits long.
	X         */
	X    }
	X    while (buildenc(0,dctreehd) == ERROR);
	X
	X    /* Initialize encoding variables */
	X
	X    cbitsrem = 0;                      /* force initial read */
	X    curin = 0;                         /* anything but endfile */
	X
	X    for (i=0; i<NUMVALS; i++)          /* add bits for each code */
	X        size += valcount[i] * codelen[i];
	X
	X    size = (size+7)/8;                 /* reduce to number of bytes */
	X
	X    numnodes = dctreehd<NUMVALS ? 0 : dctreehd-(NUMVALS-1);
	X
	X    size += sizeof(INT) + 2*numnodes*sizeof(INT);
	X
	X    return(size);
	X}
	X
	X/*
	X * The count of number of occurrances of each input value
	X * have already been prevented from exceeding MAXCOUNT.
	X * Now we must scale them so that their sum doesn't exceed
	X * ceiling and yet no non-zero count can become zero.
	X * This scaling prevents errors in the weights of the
	X * interior nodes of the Huffman tree and also ensures that
	X * the codes will fit in an unsigned integer. Rescaling is
	X * used if necessary to limit the code length.
	X */
	X
	Xstatic INT scale(ceil)
	Xunsigned INT ceil;                     /* upper limit on total weight */
	X{
	X    register INT i;
	X    INT ovflw, divisor;
	X    unsigned INT w, sum;
	X    unsigned char increased;           /* flag */
	X
	X    do
	X    {
	X        for (i=sum=ovflw=0; i<NUMVALS; ++i)
	X        {
	X            if (node[i].weight > (ceil-sum))
	X                ++ovflw;
	X            sum += node[i].weight;
	X        }
	X
	X        divisor = ovflw + 1;
	X
	X        /* Ensure no non-zero values are lost */
	X
	X        increased = FALSE;
	X        for (i=0; i<NUMVALS; ++i)
	X        {
	X            w = node[i].weight;
	X            if (w<divisor && w!=0)
	X            {
	X                /* Don't fail to provide a code if it's used at all */
	X
	X                node[i].weight = divisor;
	X                increased = TRUE;
	X            }
	X        }
	X    }
	X    while (increased);
	X
	X    /* Scaling factor choosen, now scale */
	X
	X    if (divisor>1)
	X        for (i=0; i<NUMVALS; ++i)
	X            node[i].weight /= divisor;
	X}
	X
	X/*
	X * heap() and adjust() maintain a list of binary trees as a
	X * heap with the top indexing the binary tree on the list
	X * which has the least weight or, in case of equal weights,
	X * least depth in its longest path. The depth part is not
	X * strictly necessary, but tends to avoid long codes which
	X * might provoke rescaling.
	X */
	X
	Xstatic INT heap(list,length)
	XINT list[], length;
	X{
	X    register INT i;
	X    INT adjust();
	X
	X    for (i=(length-2)/2; i>=0; --i)
	X        adjust(list,i,length-1);
	X}
	X
	X/* Make a heap from a heap with a new top */
	X
	Xstatic INT adjust(list,top,bottom)
	XINT list[], top, bottom;
	X{
	X    register INT k, temp;
	X    INT cmptrees();
	X
	X    k = 2 * top + 1;                   /* left child of top */
	X    temp = list[top];                  /* remember root node of top tree */
	X
	X    if (k<=bottom)
	X    {
	X        if (k<bottom && cmptrees(list[k],list[k+1]))
	X            ++k;
	X
	X        /* k indexes "smaller" child (in heap of trees) of top */
	X        /* now make top index "smaller" of old top and smallest child */
	X
	X        if (cmptrees(temp,list[k]))
	X        {
	X            list[top] = list[k];
	X            list[k] = temp;
	X
	X            /* Make the changed list a heap */
	X
	X            adjust(list,k,bottom);     /* recursive */
	X        }
	X    }
	X}
	X
	X/*
	X * Compare two trees, if a > b return true, else return false.
	X * Note comparison rules in previous comments.
	X */
	X
	Xstatic INT cmptrees(a,b)
	XINT a, b;                              /* root nodes of trees */
	X{
	X    if (node[a].weight > node[b].weight)
	X        return(TRUE);
	X    if (node[a].weight == node[b].weight)
	X        if (node[a].tdepth > node[b].tdepth)
	X            return(TRUE);
	X    return(FALSE);
	X}
	X
	X/*
	X * HUFFMAN ALGORITHM: develops the single element trees
	X * into a single binary tree by forming subtrees rooted in
	X * interior nodes having weights equal to the sum of weights of all
	X * their descendents and having depth counts indicating the
	X * depth of their longest paths.
	X *
	X * When all trees have been formed into a single tree satisfying
	X * the heap property (on weight, with depth as a tie breaker)
	X * then the binary code assigned to a leaf (value to be encoded)
	X * is then the series of left (0) and right (1)
	X * paths leading from the root to the leaf.
	X * Note that trees are removed from the heaped list by
	X * moving the last element over the top element and
	X * reheaping the shorter list.
	X */
	X
	Xstatic INT bld_tree(list,len)
	XINT list[];
	XINT len;
	X{
	X    register INT freenode;             /* next free node in tree */
	X    register struct nd *frnp;          /* free node pointer */
	X    INT lch, rch;                      /* temps for left, right children */
	X    INT maxchar();
	X
	X    /*
	X     * Initialize index to next available (non-leaf) node.
	X     * Lower numbered nodes correspond to leaves (data values).
	X     */
	X
	X    freenode = NUMVALS;
	X
	X    while (len>1)
	X    {
	X        /*
	X         * Take from list two btrees with least weight
	X         * and build an interior node pointing to them.
	X         * This forms a new tree.
	X         */
	X
	X        lch = list[0];                 /* This one will be left child */
	X
	X        /* delete top (least) tree from the list of trees */
	X
	X        list[0] = list[--len];
	X        adjust(list,0,len-1);
	X
	X        /* Take new top (least) tree. Reuse list slot later */
	X
	X        rch = list[0];                 /* This one will be right child */
	X
	X        /*
	X         * Form new tree from the two least trees using
	X         * a free node as root. Put the new tree in the list.
	X         */
	X
	X        frnp = &node[freenode];        /* address of next free node */
	X        list[0] = freenode++;          /* put at top for now */
	X        frnp->lchild = lch;
	X        frnp->rchild = rch;
	X        frnp->weight = node[lch].weight + node[rch].weight;
	X        frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth);
	X
	X        /* reheap list  to get least tree at top */
	X
	X        adjust(list,0,len-1);
	X    }
	X    dctreehd = list[0];                /* head of final tree */
	X}
	X
	Xstatic INT maxchar(a,b)
	X{
	X    return(a>b ? a : b);
	X}
	X
	Xstatic INT init_enc()
	X{
	X    register INT i;
	X
	X    for (i=0; i<NUMVALS; ++i)          /* Initialize encoding table */
	X        codelen[i] = 0;
	X}
	X
	X/*
	X * Recursive routine to walk the indicated subtree and level
	X * and maintain the current path code in bstree. When a leaf
	X * is found the entire code string and length are put into
	X * the encoding table entry for the leaf's data value .
	X *
	X * Returns ERROR if codes are too long.
	X */
	X
	Xstatic INT buildenc(level,root)
	XINT level;                             /* level being examined */
	XINT root;                              /* root of subtree/data value if leaf*/
	X{
	X    register INT l, r;
	X
	X    l = node[root].lchild;
	X    r = node[root].rchild;
	X
	X    if (l==NOCHILD && r==NOCHILD)
	X    {
	X        /*
	X         * Leaf. Previous path determines bit string
	X         * code of length level (bits 0 to level - 1).
	X         * Ensures unused code bits are zero.
	X         */
	X
	X        codelen[root] = level;
	X        code[root] = tcode & (((unsigned INT)~0) >> (16-level));
	X        return((level>16) ? ERROR : NULL);
	X    }
	X    else
	X    {
	X        if (l!=NOCHILD)
	X        {
	X            /* Clear path bit and continue deeper */
	X
	X            tcode &= ~(1 << level);
	X            if (buildenc(level+1,l)==ERROR)
	X                return(ERROR);         /* pass back bad statuses */
	X        }
	X        if (r!=NOCHILD)
	X        {
	X            /* Set path bit and continue deeper */
	X
	X            tcode |= 1 << level;
	X            if (buildenc(level+1,r)==ERROR)
	X                return(ERROR);         /* pass back bad statuses */
	X        }
	X    }
	X    return(NULL);                      /* it worked if we reach here */
	X}
	X
	Xstatic INT put_int(n,f)                /* output an integer */
	XINT n;                                 /* integer to output */
	XFILE *f;                               /* file to put it to */
	X{
	X    putc_pak(n&0xff,f);                /* first the low byte */
	X    putc_pak(n>>8,f);                  /* then the high byte */
	X}
	X
	X/* Write out the header of the compressed file */
	X
	Xstatic long wrt_head(ob)
	XFILE *ob;
	X{
	X    register INT l,r;
	X    INT i, k;
	X    INT numnodes;                      /* # of nodes in simplified tree */
	X
	X    /*
	X     * Write out a simplified decoding tree. Only the interior
	X     * nodes are written. When a child is a leaf index
	X     * (representing a data value) it is recoded as
	X     * -(index + 1) to distinguish it from interior indexes
	X     * which are recoded as positive indexes in the new tree.
	X     *
	X     * Note that this tree will be empty for an empty file.
	X     */
	X
	X    numnodes = dctreehd<NUMVALS ? 0 : dctreehd-(NUMVALS-1);
	X    put_int(numnodes,ob);
	X
	X    for (k=0, i=dctreehd; k<numnodes; ++k, --i)
	X    {
	X        l = node[i].lchild;
	X        r = node[i].rchild;
	X        l = l<NUMVALS ? -(l+1) : dctreehd-l;
	X        r = r<NUMVALS ? -(r+1) : dctreehd-r;
	X        put_int(l,ob);
	X        put_int(r,ob);
	X    }
	X
	X    return(sizeof(INT) + numnodes*2*sizeof(INT));
	X}
	X
	X/*
	X * Get an encoded byte or EOF. Reads from specified stream AS NEEDED.
	X *
	X * There are two unsynchronized bit-byte relationships here.
	X * The input stream bytes are converted to bit strings of
	X * various lengths via the static variables named c...
	X * These bit strings are concatenated without padding to
	X * become the stream of encoded result bytes, which this
	X * function returns one at a time. The EOF (end of file) is
	X * converted to SPEOF for convenience and encoded like any
	X * other input value. True EOF is returned after that.
	X */
	X
	Xstatic INT gethuff(ib)                 /* Returns bytes except for EOF */
	XFILE *ib;
	X{
	X    INT rbyte;                         /* Result byte value */
	X    INT need;                          /* numbers of bits */
	X
	X    rbyte = 0;
	X    need = 8;                          /* build one byte per call */
	X
	X    /*
	X     * Loop to build a byte of encoded data.
	X     * Initialization forces read the first time.
	X     */
	X
	X    while (1)
	X    {
	X        if (cbitsrem>=need)            /* if current code is big enough */
	X        {
	X            if (need==0)
	X                return(rbyte);
	X
	X            rbyte |= ccode << (8-need);/* take what we need */
	X            ccode >>= need;            /* and leave the rest */
	X            cbitsrem -= need;
	X            return(rbyte & 0xff);
	X        }
	X
	X        /* We need more than current code */
	X
	X        if (cbitsrem>0)
	X        {
	X            rbyte |= ccode << (8-need);/* take what there is */
	X            need -= cbitsrem;
	X        }
	X
	X        /* No more bits in current code string */
	X
	X        if (curin==SPEOF)
	X        {
	X            /*
	X             * The end of file token has been encoded. If
	X             * result byte has data return it and do EOF next time.
	X             */
	X
	X            cbitsrem = 0;
	X            return((need==8) ? EOF : rbyte + 0);
	X        }
	X
	X        /* Get an input byte */
	X
	X        if ((curin=getc_ncr(ib)) == EOF)
	X            curin = SPEOF;             /* convenient for encoding */
	X
	X        ccode = code[curin];           /* get the new byte's code */
	X        cbitsrem = codelen[curin];
	X    }
	X}
	X
	X/*
	X *  This routine is used to perform the actual squeeze operation.  It can
	X *  only be called after the file has been scanned.  It returns the true
	X *  length of the squeezed entry.
	X */
	X
	Xlong file_sq(f,t)                      /* squeeze a file into an archive */
	XFILE *f;                               /* file to squeeze */
	XFILE *t;                               /* archive to receive file */
	X{
	X    INT c;                             /* one byte of squeezed data */
	X    long size;                         /* size after squeezing */
	X
	X    size = wrt_head(t);                /* write out the decode tree */
	X
	X    while ((c=gethuff(f))!=EOF)
	X    {
	X        putc_pak(c,t);
	X        size++;
	X    }
	X
	X    return(size);                      /* report true size */
	X}
SHAR_EOF
if test 16916 -ne "`wc -c < 'arcsq.c'`"
then
	echo shar: "error transmitting 'arcsq.c'" '(should have been 16916 characters)'
fi
fi
echo shar: "extracting 'arcsvc.c'" '(4943 characters)'
if test -f 'arcsvc.c'
then
	echo shar: "will not over-write existing file 'arcsvc.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arcsvc.c'
	X/*
	X *	arcsvc.c	1.1
	X *
	X *	Author: Thom Henderson
	X *	Original System V port: Mike Stump
	X *	Enhancements, Bug fixes, and cleanup: Chris Seaman
	X *	Date: Fri Mar 20 09:57:02 1987
	X *	Last Mod.	3/21/87
	X *
	X */
	X
	X/*
	X * ARC - Archive utility - ARCSVC
	X * 
	X * Version 2.15, created on 12/17/85 at 15:17:16
	X * 
	X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
	X * 
	X *     Description:
	X *          This file contains service routines needed to maintain an archive.
	X */
	X
	X#include "arc.h"
	X
	XINT openarc(chg)                       /* open archive */
	XINT chg;                               /* true to open for changes */
	X{
	X    FILE *fopen();                     /* file opener */
	X
	X    if(!(arc=fopen(arcname,"r")))
	X    {
	X        if(chg)
	X            printf("Creating new archive: %s\n",arcname);
	X        else
	X            abort("Cannot read archive: %s",arcname);
	X    }
	X
	X    if(chg)                            /* if opening for changes */
	X        if(!(new=fopen(newname,"w")))
	X            abort("Cannot create archive copy: %s",newname);
	X}
	X
	XINT closearc(chg)                      /* close an archive */
	XINT chg;                               /* true if archive was changed */
	X{
	X    signal(SIGINT,SIG_IGN);            /* We are now committed, so trap */
	X    signal(SIGQUIT,SIG_IGN);           /* for all normal signals */
	X
	X    if(arc)                            /* if we had an initial archive */
	X        fclose(arc);                   /* then close it */
	X
	X    if(chg)                            /* if things have changed */
	X    {
	X        fclose(new);                   /* close the new copy */
	X
	X        if(arc)                        /* if we had an original archive */
	X        {
	X            if(keepbak)                /* if a backup is wanted */
	X            {
	X                unlink(bakname);       /* erase any old copies */
	X                if(rename(arcname,bakname))
	X                    abort("Cannot rename %s to %s",arcname,bakname);
	X                printf("Keeping backup archive: %s\n",bakname);
	X            }
	X            else if(unlink(arcname))
	X                abort("Cannot delete old archive: %s",arcname);
	X        }
	X
	X        if(rename(newname,arcname))
	X            abort("Cannot rename %s to %s",newname,arcname);
	X    }
	X}
	X
	X/*
	X * CRC computation logic
	X * The logic for this method of calculating the CRC 16 bit polynomial
	X * is taken from an article by David Schwaderer in the April 1985
	X * issue of PC Tech Journal.
	X */
	X
	Xstatic INT crctab[] = {                /* CRC lookup table */
	X    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
	X    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
	X    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
	X    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
	X    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
	X    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
	X    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
	X    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
	X    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
	X    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
	X    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
	X    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
	X    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
	X    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
	X    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
	X    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
	X    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
	X    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
	X    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
	X    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
	X    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
	X    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
	X    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
	X    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
	X    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
	X    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
	X    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
	X    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
	X    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
	X    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
	X    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
	X    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
	X};
	X
	XINT addcrc(crc,c)                      /* update a CRC check */
	XINT crc;                               /* running CRC value */
	Xunsigned char c;                       /* character to add */
	X{
	X    return((((crc>>8)&0x00ff) ^ crctab[(crc^c)&0x00ff]) & 0x0000ffff);
	X}
SHAR_EOF
if test 4943 -ne "`wc -c < 'arcsvc.c'`"
then
	echo shar: "error transmitting 'arcsvc.c'" '(should have been 4943 characters)'
fi
fi
echo shar: "extracting 'arctst.c'" '(1606 characters)'
if test -f 'arctst.c'
then
	echo shar: "will not over-write existing file 'arctst.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arctst.c'
	X/*
	X *	arctst.c	1.1
	X *
	X *	Author: Thom Henderson
	X *	Original System V port: Mike Stump
	X *	Enhancements, Bug fixes, and cleanup: Chris Seaman
	X *	Date: Fri Mar 20 09:57:02 1987
	X *	Last Mod.	3/21/87
	X *
	X */
	X
	X/*
	X * ARC - Archive utility - ARCTST
	X * 
	X * Version 2.12, created on 02/03/86 at 23:00:40
	X * 
	X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
	X * 
	X *     Description:
	X *          This file contains the routines used to test archive integrity.
	X */
	X
	X#include "arc.h"
	X
	XINT tstarc()                           /* test integrity of an archive */
	X{
	X    struct heads hdr;                  /* file header */
	X    long arcsize, ftell();             /* archive size */
	X
	X    openarc(0);                        /* open archive for reading */
	X    fseek(arc,0L,2);                   /* move to end of archive */
	X    arcsize = ftell(arc);              /* see how big it is */
	X    fseek(arc,0L,0);                   /* return to top of archive */
	X
	X    printf("Testing archive...\n");
	X    while (readhdr(&hdr,arc))
	X    {
	X        if (ftell(arc)+hdr.size>arcsize)
	X        {
	X            printf("Archive truncated in file %s\n",hdr.name);
	X            nerrs++;
	X            break;
	X        }
	X        else
	X        {
	X            printf("    File: %-14s  ",hdr.name);
	X            fflush(stdout);
	X            if (unpack(arc,NULL,&hdr))
	X                nerrs++;
	X            else
	X                printf("okay\n");
	X        }
	X    }
	X
	X    if (nerrs<1)
	X        printf("No errors detected\n");
	X    else if (nerrs==1)
	X        printf("One error detected\n");
	X    else
	X        printf("%d errors detected\n",nerrs);
	X}
SHAR_EOF
if test 1606 -ne "`wc -c < 'arctst.c'`"
then
	echo shar: "error transmitting 'arctst.c'" '(should have been 1606 characters)'
fi
fi
echo shar: "extracting 'arcunp.c'" '(6134 characters)'
if test -f 'arcunp.c'
then
	echo shar: "will not over-write existing file 'arcunp.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arcunp.c'
	X/*
	X *	arcunp.c	1.1
	X *
	X *	Author: Thom Henderson
	X *	Original System V port: Mike Stump
	X *	Enhancements, Bug fixes, and cleanup: Chris Seaman
	X *	Date: Fri Mar 20 09:57:02 1987
	X *	Last Mod.	3/21/87
	X *
	X */
	X
	X/*
	X * ARC - Archive utility - ARCUNP
	X * 
	X * Version 3.16, created on 02/03/86 at 23:01:16
	X * 
	X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
	X * 
	X *     Description:
	X *          This file contains the routines used to expand a file
	X *          when taking it out of an archive.
	X */
	X
	X#include "arc.h"
	X
	X/* stuff for repeat unpacking */
	X
	X#define DLE 0x90                       /* repeat byte flag */
	X
	Xstatic INT state;                      /* repeat unpacking state */
	X
	X/* repeat unpacking states */
	X
	X#define NOHIST 0                       /* no relevant history */
	X#define INREP 1                        /* sending a repeated value */
	X
	Xstatic INT crcval;                     /* CRC check value */
	Xstatic long size;                      /* bytes to read */
	X
	XINT unpack(f,t,hdr)                    /* unpack an archive entry */
	XFILE *f, *t;                           /* source, destination */
	Xstruct heads *hdr;                     /* pointer to file header data */
	X{
	X    INT c;                             /* one char of stream */
	X    INT putc_unp();
	X    INT putc_ncr();
	X    INT getc_unp();
	X
	X    /* setups common to all methods */
	X
	X    crcval = 0;                        /* reset CRC check value */
	X    size = hdr->size;                  /* set input byte counter */
	X    state = NOHIST;                    /* initial repeat unpacking state */
	X    setcode();                         /* set up for decoding */
	X
	X    /* use whatever method is appropriate */
	X
	X    switch(hdrver)                     /* choose proper unpack method */
	X    {
	X    case 1:                            /* standard packing */
	X    case 2:
	X        while ((c=getc_unp(f))!=EOF)
	X            putc_unp(c,t);
	X        break;
	X    case 3:                            /* non-repeat packing */
	X        while ((c=getc_unp(f))!=EOF)
	X            putc_ncr(c,t);
	X        break;
	X    case 4:                            /* Huffman squeezing */
	X        init_usq(f);
	X        while ((c=getc_usq(f))!=EOF)
	X            putc_ncr(c,t);
	X        break;
	X    case 5:                            /* Lempel-Zev compression */
	X        init_ucr(0);
	X        while ((c=getc_ucr(f))!=EOF)
	X            putc_unp(c,t);
	X        break;
	X    case 6:                            /* Lempel-Zev plus non-repeat */
	X        init_ucr(0);
	X        while ((c=getc_ucr(f))!=EOF)
	X            putc_ncr(c,t);
	X        break;
	X    case 7:                            /* L-Z plus ncr with new hash */
	X        init_ucr(1);
	X        while ((c=getc_ucr(f))!=EOF)
	X            putc_ncr(c,t);
	X        break;
	X    case 8:                            /* dynamic Lempel-Zev */
	X        decomp(f,t);
	X        break;
	X    default:                           /* unknown method */
	X        if (warn)
	X        {
	X            printf("I don't know how to unpack file %s\n",hdr->name);
	X            printf("I think you need a newer version of ARC\n");
	X            nerrs++;
	X        }
	X        fseek(f,hdr->size,1);          /* skip over bad file */
	X        return(1);                     /* note defective file */
	X    }
	X
	X    /* cleanups common to all methods */
	X
	X    if ((crcval&0xffff)!=(hdr->crc&0x0000ffff))
	X    {
	X        if (warn)
	X        {
	X            printf("WARNING: File %s fails CRC check\n",hdr->name);
	X            nerrs++;
	X        }
	X        return(1);                     /* note defective file */
	X    }
	X    return(0);                         /* file is okay */
	X}
	X
	X/*
	X *  This routine is used to put bytes in the output file.  It also
	X *  performs various housekeeping functions, such as maintaining the
	X *  CRC check value.
	X */
	X
	Xstatic INT putc_unp(c,t)               /* output an unpacked byte */
	Xchar c;                                /* byte to output */
	XFILE *t;                               /* file to output to */
	X{
	X    crcval = addcrc(crcval,c);         /* update the CRC check value */
	X    putc_tst(c,t);
	X}
	X
	X/*
	X *  This routine is used to decode non-repeat compression.  Bytes are
	X *  passed one at a time in coded format, and are written out uncoded.
	X *  The data is stored normally, except that runs of more than two
	X *  characters are represented as:
	X *
	X *       <char> <DLE> <count>
	X *
	X *  With a special case that a count of zero indicates a DLE as data,
	X *  not as a repeat marker.
	X */
	X
	XINT putc_ncr(c,t)                      /* put NCR coded bytes */
	Xunsigned char c;                       /* next byte of stream */
	XFILE *t;                               /* file to receive data */
	X{
	X    static INT lastc;                  /* last character seen */
	X
	X    switch(state)                      /* action depends on our state */
	X    {
	X    case NOHIST:                       /* no previous history */
	X        if (c==DLE)                    /* if starting a series */
	X            state = INREP;             /* then remember it next time */
	X        else
	X            putc_unp(lastc=c,t);       /* else nothing unusual */
	X        return;
	X    case INREP:                        /* in a repeat */
	X        if (c)                         /* if count is nonzero */
	X            while (--c)                /* then repeatedly ... */
	X                putc_unp(lastc,t);     /* ... output the byte */
	X        else
	X            putc_unp(DLE,t);           /* else output DLE as data */
	X        state = NOHIST;                /* back to no history */
	X        return;
	X    default:
	X        abort("Bad NCR unpacking state (%d)",state);
	X    }
	X}
	X
	X/*
	X *  This routine provides low-level byte input from an archive.  This
	X *  routine MUST be used, as end-of-file is simulated at the end of
	X *  the archive entry.
	X */
	X
	XINT getc_unp(f)                        /* get a byte from an archive */
	XFILE *f;                               /* archive file to read */
	X{
	X    if (!size)                         /* if no data left */
	X        return(EOF);                   /* then pretend end of file */
	X
	X    size--;                            /* deduct from input counter */
	X    return(code(fgetc(f)));            /* and return next decoded byte */
	X}
SHAR_EOF
if test 6134 -ne "`wc -c < 'arcunp.c'`"
then
	echo shar: "error transmitting 'arcunp.c'" '(should have been 6134 characters)'
fi
fi
echo shar: "extracting 'arcusq.c'" '(2992 characters)'
if test -f 'arcusq.c'
then
	echo shar: "will not over-write existing file 'arcusq.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arcusq.c'
	X/*
	X *	arcusq.c	1.1
	X *
	X *	Author: Thom Henderson
	X *	Original System V port: Mike Stump
	X *	Enhancements, Bug fixes, and cleanup: Chris Seaman
	X *	Date: Fri Mar 20 09:57:02 1987
	X *	Last Mod.	3/21/87
	X *
	X */
	X
	X/*
	X * ARC - Archive utility - ARCUSQ
	X * 
	X * Version 3.13, created on 01/30/86 at 20:11:42
	X * 
	X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
	X * 
	X *     Description:
	X *          This file contains the routines used to expand a file
	X *          which was packed using Huffman squeezing.
	X * 
	X *          Most of this code is taken from an USQ program by Richard
	X *          Greenlaw, which was adapted to CI-C86 by Robert J. Beilstein.
	X */
	X
	X#include "arc.h"
	X
	X/* stuff for Huffman unsqueezing */
	X
	X#define ERROR (-1)
	X#define SPEOF 256                      /* special endfile token */
	X#define NUMVALS 257                    /* 256 data values plus SPEOF */
	X
	Xstruct u_nd {                          /* decoding tree */
	X  INT child[2];                        /* left, right */
	X} u_node[NUMVALS];                     /* use large buffer */
	X
	Xstatic INT bpos;                       /* last bit position read */
	Xstatic INT curin;                      /* last byte value read */
	Xstatic INT numnodes;                   /* number of nodes in decode tree */
	X
	Xstatic INT get_int(f)                  /* get an integer */
	XFILE *f;                               /* file to get it from */
	X{
	X    INT i;
	X
	X    i = getc_unp(f);
	X    return((short)(i | (getc_unp(f)<<8)));
	X}
	X
	XINT init_usq(f)                        /* initialize Huffman unsqueezing */
	XFILE *f;                               /* file containing squeezed data */
	X{
	X    INT i;                             /* node index */
	X
	X    bpos = 99;                         /* force initial read */
	X
	X    numnodes = get_int(f);
	X
	X    if (numnodes<0 || numnodes>=NUMVALS)
	X        abort("File has an invalid decode tree");
	X
	X    /* initialize for possible empty tree (SPEOF only) */
	X
	X    u_node[0].child[0] = -(SPEOF + 1);
	X    u_node[0].child[1] = -(SPEOF + 1);
	X
	X    for (i=0; i<numnodes; ++i)         /* get decoding tree from file */
	X    {
	X        u_node[i].child[0] = get_int(f);
	X        u_node[i].child[1] = get_int(f);
	X    }
	X}
	X
	XINT getc_usq(f)                        /* get byte from squeezed file */
	XFILE *f;                               /* file containing squeezed data */
	X{
	X    INT i;                             /* tree index */
	X
	X    /* follow bit stream in tree to a leaf */
	X
	X    for (i=0; i>=0; )                  /* work down(up?) from root */
	X    {
	X        if (++bpos>7)
	X        {
	X            if ((curin=getc_unp(f)) == ERROR)
	X                return(ERROR);
	X            bpos = 0;
	X
	X            /* move a level deeper in tree */
	X            i = u_node[i].child[1&curin];
	X        }
	X        else
	X            i = u_node[i].child[1 & (curin >>= 1)];
	X    }
	X
	X    /* decode fake node index to original data value */
	X
	X    i = -(i + 1);
	X
	X    /* decode special endfile token to normal EOF */
	X
	X    i = (i==SPEOF) ? EOF : i;
	X    return(i);
	X}
SHAR_EOF
if test 2992 -ne "`wc -c < 'arcusq.c'`"
then
	echo shar: "error transmitting 'arcusq.c'" '(should have been 2992 characters)'
fi
fi
exit 0
#	End of shell archive