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