Arc v5.21 (4 of 6)
egray at fthood.UUCP
egray at fthood.UUCP
Tue Jan 3 09:53:00 AEST 1989
This is part 4 (of 6) to the Arc v5.21 distribution package.
Emmet P. Gray US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
Directorate of Engineering & Housing
Environmental Management Office
Fort Hood, TX 76544-5057
------------------------------------------------------------------------------
#! /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:
# arclzw.c
# arcmatch.c
# arcmisc.c
# arcpack.c
# arcrun.c
# arcs.h
# This archive created: Sun Jan 1 12:48:23 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'arclzw.c'" '(22114 characters)'
if test -f 'arclzw.c'
then
echo shar: "will not over-write existing file 'arclzw.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arclzw.c'
X/*
X * $Header: arclzw.c,v 1.6 88/07/31 18:49:49 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCLZW
X *
X * Version 2.03, created on 10/24/86 at 11:46:22
X *
X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
X *
X * By: Thom Henderson
X *
X * Description: This file contains the routines used to implement Lempel-Zev
X * data compression, which calls for building a coding table on the fly.
X * This form of compression is especially good for encoding files which
X * contain repeated strings, and can often give dramatic improvements over
X * traditional Huffman SQueezing.
X *
X * Language: Computer Innovations Optimizing C86
X *
X * Programming notes: In this section I am drawing heavily on the COMPRESS
X * program from UNIX. The basic method is taken from "A Technique for High
X * Performance Data Compression", Terry A. Welch, IEEE Computer Vol 17, No 6
X * (June 1984), pp 8-19. Also see "Knuth's Fundamental Algorithms", Donald
X * Knuth, Vol 3, Section 6.4.
X *
X * As best as I can tell, this method works by tracing down a hash table of code
X * strings where each entry has the property:
X *
X * if <string> <char> is in the table then <string> is in the table.
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid putc_pak(), abort(), putc_ncr();
Xint getc_unp();
X#if MSDOS
Xchar *setmem();
X#else
Xchar *memset();
X#endif
X
Xstatic void putcode();
X/* definitions for older style crunching */
X
X#define FALSE 0
X#define TRUE !FALSE
X#define TABSIZE 4096
X#define NO_PRED 0xFFFF
X#define EMPTY 0xFFFF
X#define NOT_FND 0xFFFF
X
Xstatic unsigned short inbuf; /* partial input code storage */
Xstatic int sp; /* current stack pointer */
X
Xstruct entry { /* string table entry format */
X char used; /* true when this entry is in use */
X unsigned char follower; /* char following string */
X unsigned short next; /* ptr to next in collision list */
X unsigned short predecessor; /* code for preceeding string */
X}; /* string_tab[TABSIZE]; the code string table */
X
X
X/* definitions for the new dynamic Lempel-Zev crunching */
X
X#define BITS 12 /* maximum bits per code */
X#define HSIZE 5003 /* 80% occupancy */
X#define INIT_BITS 9 /* initial number of bits/code */
X
Xstatic int n_bits; /* number of bits/code */
Xstatic int maxcode; /* maximum code, given n_bits */
X#define MAXCODE(n) ((1<<(n)) - 1) /* maximum code calculation */
Xstatic int maxcodemax = 1 << BITS; /* largest possible code (+1) */
X
Xstatic char buf[BITS]; /* input/output buffer */
X
Xstatic unsigned char lmask[9] = /* left side masks */
X{
X 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00
X};
Xstatic unsigned char rmask[9] = /* right side masks */
X{
X 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
X};
X
Xstatic int offset; /* byte offset for code output */
Xstatic long in_count; /* length of input */
Xstatic long bytes_out; /* length of compressed output */
Xstatic long bytes_ref; /* output quality reference */
Xstatic long bytes_last; /* output size at last checkpoint */
Xstatic unsigned short ent;
X
X/*
X * To save much memory (which we badly need at this point), we overlay the
X * table used by the previous version of Lempel-Zev with those used by the
X * new version. Since no two of these routines will be used together, we can
X * safely do this.
X */
X
Xextern long htab[HSIZE]; /* hash code table (crunch) */
Xextern unsigned short codetab[HSIZE]; /* string code table (crunch) */
Xstatic struct entry *string_tab=(struct entry *)htab; /* old crunch string table */
X
Xstatic unsigned short *prefix=codetab; /* prefix code table (uncrunch) */
Xstatic unsigned char *suffix=(unsigned char *)htab; /* suffix table (uncrunch) */
X
Xstatic int free_ent; /* first unused entry */
Xstatic int firstcmp; /* true at start of compression */
Xextern unsigned char stack[HSIZE]; /* local push/pop stack */
X
X/*
X * block compression parameters -- after all codes are used up, and
X * compression rate changes, start over.
X */
X
Xstatic int clear_flg;
X#define CHECK_GAP 2048 /* ratio check interval */
Xstatic long checkpoint;
Xvoid upd_tab();
X
X/*
X * the next two codes should not be changed lightly, as they must not lie
X * within the contiguous general code space.
X */
X#define FIRST 257 /* first free entry */
X#define CLEAR 256 /* table clear output code */
X
X/*
X * The cl_block() routine is called at each checkpoint to determine if
X * compression would likely improve by resetting the code table. The method
X * chosen to determine this is based on empirical observation that, in
X * general, every 2k of input data should compress at least as well as the
X * first 2k of input.
X */
X
Xstatic void
Xcl_block(t) /* table clear for block compress */
X FILE *t; /* our output file */
X{
X checkpoint = in_count + CHECK_GAP;
X
X if (bytes_ref) {
X if (bytes_out - bytes_last > bytes_ref) {
X setmem(htab, HSIZE * sizeof(long), 0xff);
X free_ent = FIRST;
X clear_flg = 1;
X putcode(CLEAR, t);
X bytes_ref = 0;
X }
X } else
X bytes_ref = bytes_out - bytes_last;
X
X bytes_last = bytes_out; /* remember where we were */
X}
X
X/*****************************************************************
X *
X * Output a given code.
X * Inputs:
X * code: A n_bits-bit integer. If == -1, then EOF. This assumes
X * that n_bits =< (LONG)wordsize - 1.
X * Outputs:
X * Outputs code to the file.
X * Assumptions:
X * Chars are 8 bits long.
X * Algorithm:
X * Maintain a BITS character long buffer (so that 8 codes will
X * fit in it exactly). When the buffer fills up empty it and start over.
X */
X
Xstatic void
Xputcode(code, t) /* output a code */
X int code; /* code to output */
X FILE *t; /* where to put it */
X{
X int r_off = offset; /* right offset */
X int bits = n_bits; /* bits to go */
X char *bp = buf; /* buffer pointer */
X int n; /* index */
X
X register int ztmp;
X
X if (code >= 0) { /* if a real code *//* Get to the first byte. */
X bp += (r_off >> 3);
X r_off &= 7;
X
X /*
X * Since code is always >= 8 bits, only need to mask the
X * first hunk on the left.
X */
X ztmp = (code << r_off) & lmask[r_off];
X *bp = (*bp & rmask[r_off]) | ztmp;
X bp++;
X bits -= (8 - r_off);
X code >>= (8 - r_off);
X
X /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X if (bits >= 8) {
X *bp++ = code;
X code >>= 8;
X bits -= 8;
X }
X /* Last bits. */
X if (bits)
X *bp = code;
X offset += n_bits;
X
X if (offset == (n_bits << 3)) {
X bp = buf;
X bits = n_bits;
X bytes_out += bits;
X do
X putc_pak(*bp++, t);
X while (--bits);
X offset = 0;
X }
X /*
X * If the next entry is going to be too big for the code
X * size, then increase it, if possible.
X */
X if (free_ent > maxcode || clear_flg > 0) {
X /*
X * Write the whole buffer, because the input side
X * won't discover the size increase until after
X * it has read it.
X */
X if (offset > 0) {
X bp = buf; /* reset pointer for writing */
X bytes_out += n = n_bits;
X while (n--)
X putc_pak(*bp++, t);
X }
X offset = 0;
X
X if (clear_flg) { /* reset if clearing */
X maxcode = MAXCODE(n_bits = INIT_BITS);
X clear_flg = 0;
X } else {/* else use more bits */
X n_bits++;
X if (n_bits == BITS)
X maxcode = maxcodemax;
X else
X maxcode = MAXCODE(n_bits);
X }
X }
X } else { /* dump the buffer on EOF */
X bytes_out += n = (offset + 7) / 8;
X
X if (offset > 0)
X while (n--)
X putc_pak(*bp++, t);
X offset = 0;
X }
X}
X
X/*****************************************************************
X *
X * Read one code from the standard input. If EOF, return -1.
X * Inputs:
X * cmpin
X * Outputs:
X * code or -1 is returned.
X */
X
Xstatic int
Xgetcode(f) /* get a code */
X FILE *f; /* file to get from */
X{
X int code;
X static int loffset = 0, size = 0;
X int r_off, bits;
X unsigned char *bp = (unsigned char *) buf;
X
X if (clear_flg > 0 || loffset >= size || free_ent > maxcode) {
X /*
X * If the next entry will be too big for the current code
X * size, then we must increase the size. This implies
X * reading a new buffer full, too.
X */
X if (free_ent > maxcode) {
X n_bits++;
X if (n_bits == BITS)
X maxcode = maxcodemax; /* won't get any bigger
X * now */
X else
X maxcode = MAXCODE(n_bits);
X }
X if (clear_flg > 0) {
X maxcode = MAXCODE(n_bits = INIT_BITS);
X clear_flg = 0;
X }
X for (size = 0; size < n_bits; size++) {
X if ((code = getc_unp(f)) == EOF)
X break;
X else
X buf[size] = (char) code;
X }
X if (size <= 0)
X return -1; /* end of file */
X
X loffset = 0;
X /* Round size down to integral number of codes */
X size = (size << 3) - (n_bits - 1);
X }
X r_off = loffset;
X bits = n_bits;
X
X /*
X * Get to the first byte.
X */
X bp += (r_off >> 3);
X r_off &= 7;
X
X /* Get first part (low order bits) */
X code = (*bp++ >> r_off);
X bits -= 8 - r_off;
X r_off = 8 - r_off; /* now, offset into code word */
X
X /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X if (bits >= 8) {
X code |= *bp++ << r_off;
X r_off += 8;
X bits -= 8;
X }
X /* high order bits. */
X code |= (*bp & rmask[bits]) << r_off;
X loffset += n_bits;
X
X return code & MAXCODE(BITS);
X}
X
X/*
X * compress a file
X *
X * Algorithm: use open addressing double hashing (no chaining) on the prefix
X * code / next character combination. We do a variant of Knuth's algorithm D
X * (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
X * Here, the modular division first probe is gives way to a faster
X * exclusive-or manipulation. Also do block compression with an adaptive
X * reset, where the code table is cleared when the compression ratio
X * decreases, but after the table fills. The variable-length output codes
X * are re-sized at this point, and a special CLEAR code is generated for the
X * decompressor.
X */
X
Xvoid
Xinit_cm(t) /* initialize for compression */
X FILE *t; /* where compressed file goes */
X{
X offset = 0;
X bytes_out = bytes_last = 1;
X bytes_ref = 0;
X clear_flg = 0;
X in_count = 1;
X checkpoint = CHECK_GAP;
X maxcode = MAXCODE(n_bits = INIT_BITS);
X free_ent = FIRST;
X setmem(htab, HSIZE * sizeof(long), 0xff);
X n_bits = INIT_BITS; /* set starting code size */
X
X putc_pak(BITS, t); /* note our max code length */
X
X firstcmp = 1; /* next byte will be first */
X}
X
Xvoid
Xputc_cm(c, t) /* compress a character */
X unsigned char c; /* character to compress */
X FILE *t; /* where to put it */
X{
X static long fcode;
X static int hshift;
X int i;
X int disp;
X
X if (firstcmp) { /* special case for first byte */
X ent = c; /* remember first byte */
X
X hshift = 0;
X for (fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L)
X hshift++;
X hshift = 8 - hshift; /* set hash code range bound */
X
X firstcmp = 0; /* no longer first */
X return;
X }
X in_count++;
X
X fcode = (long) (((long) c << BITS) + ent);
X i = (c << hshift) ^ ent;/* xor hashing */
X
X if (htab[i] == fcode) {
X ent = codetab[i];
X return;
X } else if (htab[i] < 0) /* empty slot */
X goto nomatch;
X disp = HSIZE - i; /* secondary hash (after G.Knott) */
X if (i == 0)
X disp = 1;
X
Xprobe:
X if ((i -= disp) < 0)
X i += HSIZE;
X
X if (htab[i] == fcode) {
X ent = codetab[i];
X return;
X }
X if (htab[i] > 0)
X goto probe;
X
Xnomatch:
X putcode(ent, t);
X ent = c;
X if (free_ent < maxcodemax) {
X codetab[i] = free_ent++; /* code -> hashtable */
X htab[i] = fcode;
X }
X if (in_count >= checkpoint)
X cl_block(t); /* check for adaptive reset */
X}
X
Xlong
Xpred_cm(t) /* finish compressing a file */
X FILE *t; /* where to put it */
X{
X putcode(ent, t); /* put out the final code */
X putcode(-1, t); /* tell output we are done */
X
X return bytes_out; /* say how big it got */
X}
X
X/*
X * Decompress a file. This routine adapts to the codes in the file building
X * the string table on-the-fly; requiring no table to be stored in the
X * compressed file. The tables used herein are shared with those of the
X * compress() routine. See the definitions above.
X */
X
Xvoid
Xdecomp(f, t) /* decompress a file */
X FILE *f; /* file to read codes from */
X FILE *t; /* file to write text to */
X{
X unsigned char *stackp;
X int finchar;
X int code, oldcode, incode;
X
X if ((code = getc_unp(f)) != BITS)
X abort("File packed with %d bits, I can only handle %d", code, BITS);
X
X n_bits = INIT_BITS; /* set starting code size */
X clear_flg = 0;
X
X /*
X * As above, initialize the first 256 entries in the table.
X */
X maxcode = MAXCODE(n_bits = INIT_BITS);
X setmem(prefix, 256 * sizeof(short), 0); /* reset decode string table */
X for (code = 255; code >= 0; code--)
X suffix[code] = (unsigned char) code;
X
X free_ent = FIRST;
X
X finchar = oldcode = getcode(f);
X if (oldcode == -1) /* EOF already? */
X return; /* Get out of here */
X putc_ncr((unsigned char) finchar, t); /* first code must be 8 bits=char */
X stackp = stack;
X
X while ((code = getcode(f)) > -1) {
X if (code == CLEAR) { /* reset string table */
X setmem(prefix, 256 * sizeof(short), 0);
X clear_flg = 1;
X free_ent = FIRST - 1;
X if ((code = getcode(f)) == -1) /* O, untimely death! */
X break;
X }
X incode = code;
X /*
X * Special case for KwKwK string.
X */
X if (code >= free_ent) {
X if (code > free_ent) {
X if (warn) {
X printf("Corrupted compressed file.\n");
X printf("Invalid code %d when max is %d.\n",
X code, free_ent);
X }
X nerrs++;
X return;
X }
X *stackp++ = finchar;
X code = oldcode;
X }
X /*
X * Generate output characters in reverse order
X */
X while (code >= 256) {
X *stackp++ = suffix[code];
X code = prefix[code];
X }
X *stackp++ = finchar = suffix[code];
X
X /*
X * And put them out in forward order
X */
X do
X putc_ncr(*--stackp, t);
X while (stackp > stack);
X
X /*
X * Generate the new entry.
X */
X if ((code = free_ent) < maxcodemax) {
X prefix[code] = (unsigned short) oldcode;
X suffix[code] = finchar;
X free_ent = code + 1;
X }
X /*
X * Remember previous code.
X */
X oldcode = incode;
X }
X}
X
X
X/*************************************************************************
X * Please note how much trouble it can be to maintain upwards *
X * compatibility. All that follows is for the sole purpose of unpacking *
X * files which were packed using an older method. *
X *************************************************************************/
X
X
X/*
X * The h() pointer points to the routine to use for calculating a hash value.
X * It is set in the init routines to point to either of oldh() or newh().
X *
X * oldh() calculates a hash value by taking the middle twelve bits of the square
X * of the key.
X *
X * newh() works somewhat differently, and was tried because it makes ARC about
X * 23% faster. This approach was abandoned because dynamic Lempel-Zev
X * (above) works as well, and packs smaller also. However, inadvertent
X * release of a developmental copy forces us to leave this in.
X */
X
Xstatic unsigned short(*h) (); /* pointer to hash function */
X
Xstatic unsigned short
Xoldh(pred, foll) /* old hash function */
X unsigned short pred; /* code for preceeding string */
X unsigned char foll; /* value of following char */
X{
X long local; /* local hash value */
X
X local = ((pred + foll) | 0x0800) & 0xFFFF; /* create the hash key */
X local *= local; /* square it */
X return (local >> 6) & 0x0FFF; /* return the middle 12 bits */
X}
X
Xstatic unsigned short
Xnewh(pred, foll) /* new hash function */
X unsigned short pred; /* code for preceeding string */
X unsigned char foll; /* value of following char */
X{
X return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; /* faster hash */
X}
X
X/*
X * The eolist() function is used to trace down a list of entries with
X * duplicate keys until the last duplicate is found.
X */
X
Xstatic unsigned short
Xeolist(index) /* find last duplicate */
X unsigned short index;
X{
X int temp;
X
X while (temp = string_tab[index].next) /* while more duplicates */
X index = temp;
X
X return index;
X}
X
X/*
X * The hash() routine is used to find a spot in the hash table for a new
X * entry. It performs a "hash and linear probe" lookup, using h() to
X * calculate the starting hash value and eolist() to perform the linear
X * probe. This routine DOES NOT detect a table full condition. That MUST be
X * checked for elsewhere.
X */
X
Xstatic unsigned short
Xhash(pred, foll) /* find spot in the string table */
X unsigned short pred; /* code for preceeding string */
X unsigned char foll; /* char following string */
X{
X unsigned short local, tempnext; /* scratch storage */
X struct entry *ep; /* allows faster table handling */
X
X local = (*h) (pred, foll); /* get initial hash value */
X
X if (!string_tab[local].used) /* if that spot is free */
X return local; /* then that's all we need */
X
X else { /* else a collision has occured */
X local = eolist(local); /* move to last duplicate */
X
X /*
X * We must find an empty spot. We start looking 101 places
X * down the table from the last duplicate.
X */
X
X tempnext = (local + 101) & 0x0FFF;
X ep = &string_tab[tempnext]; /* initialize pointer */
X
X while (ep->used) { /* while empty spot not found */
X if (++tempnext == TABSIZE) { /* if we are at the end */
X tempnext = 0; /* wrap to beginning of table */
X ep = string_tab;
X } else
X ++ep; /* point to next element in table */
X }
X
X /*
X * local still has the pointer to the last duplicate, while
X * tempnext has the pointer to the spot we found. We use
X * this to maintain the chain of pointers to duplicates.
X */
X
X string_tab[local].next = tempnext;
X
X return tempnext;
X }
X}
X
X/*
X * The init_tab() routine is used to initialize our hash table. You realize,
X * of course, that "initialize" is a complete misnomer.
X */
X
Xstatic void
Xinit_tab()
X{ /* set ground state in hash table */
X unsigned int i; /* table index */
X
X setmem((char *) string_tab, sizeof(string_tab), 0);
X
X for (i = 0; i < 256; i++) /* list all single byte strings */
X upd_tab(NO_PRED, i);
X
X inbuf = EMPTY; /* nothing is in our buffer */
X}
X
X/*
X * The upd_tab routine is used to add a new entry to the string table. As
X * previously stated, no checks are made to ensure that the table has any
X * room. This must be done elsewhere.
X */
X
Xvoid
Xupd_tab(pred, foll) /* add an entry to the table */
X unsigned short pred; /* code for preceeding string */
X unsigned short foll; /* character which follows string */
X{
X struct entry *ep; /* pointer to current entry */
X
X /* calculate offset just once */
X
X ep = &string_tab[hash(pred, foll)];
X
X ep->used = TRUE; /* this spot is now in use */
X ep->next = 0; /* no duplicates after this yet */
X ep->predecessor = pred; /* note code of preceeding string */
X ep->follower = foll; /* note char after string */
X}
X
X/*
X * This algorithm encoded a file into twelve bit strings (three nybbles). The
X * gocode() routine is used to read these strings a byte (or two) at a time.
X */
X
Xstatic int
Xgocode(fd) /* read in a twelve bit code */
X FILE *fd; /* file to get code from */
X{
X unsigned short localbuf, returnval;
X int temp;
X
X if (inbuf == EMPTY) { /* if on a code boundary */
X if ((temp = getc_unp(fd)) == EOF) /* get start of next
X * code */
X return EOF; /* pass back end of file status */
X localbuf = temp & 0xFF; /* mask down to true byte value */
X if ((temp = getc_unp(fd)) == EOF)
X /* get end of code, * start of next */
X return EOF; /* this should never happen */
X inbuf = temp & 0xFF; /* mask down to true byte value */
X
X returnval = ((localbuf << 4) & 0xFF0) + ((inbuf >> 4) & 0x00F);
X inbuf &= 0x000F;/* leave partial code pending */
X } else { /* buffer contains first nybble */
X if ((temp = getc_unp(fd)) == EOF)
X return EOF;
X localbuf = temp & 0xFF;
X
X returnval = localbuf + ((inbuf << 8) & 0xF00);
X inbuf = EMPTY; /* note no hanging nybbles */
X }
X return returnval; /* pass back assembled code */
X}
X
Xstatic void
Xpush(c) /* push char onto stack */
X int c; /* character to push */
X{
X stack[sp] = ((char) c); /* coerce integer into a char */
X
X if (++sp >= TABSIZE)
X abort("Stack overflow\n");
X}
X
Xstatic int
Xpop()
X{ /* pop character from stack */
X if (sp > 0)
X return ((int) stack[--sp]); /* leave ptr at next empty
X * slot */
X
X else
X return EMPTY;
X}
X
X/***** LEMPEL-ZEV DECOMPRESSION *****/
X
Xstatic int code_count; /* needed to detect table full */
Xstatic int firstc; /* true only on first character */
X
Xvoid
Xinit_ucr(inew) /* get set for uncrunching */
X int inew; /* true to use new hash function */
X{
X if (inew) /* set proper hash function */
X h = newh;
X else
X h = oldh;
X
X sp = 0; /* clear out the stack */
X init_tab(); /* set up atomic code definitions */
X code_count = TABSIZE - 256; /* note space left in table */
X firstc = 1; /* true only on first code */
X}
X
Xint
Xgetc_ucr(f) /* get next uncrunched byte */
X FILE *f; /* file containing crunched data */
X{
X int code, newcode;
X static int oldcode, finchar;
X struct entry *ep; /* allows faster table handling */
X
X if (firstc) { /* first code is always known */
X firstc = FALSE; /* but next will not be first */
X oldcode = gocode(f);
X return finchar = string_tab[oldcode].follower;
X }
X if (!sp) { /* if stack is empty */
X if ((code = newcode = gocode(f)) == EOF)
X return EOF;
X
X ep = &string_tab[code]; /* initialize pointer */
X
X if (!ep->used) {/* if code isn't known */
X code = oldcode;
X ep = &string_tab[code]; /* re-initialize pointer */
X push(finchar);
X }
X while (ep->predecessor != NO_PRED) {
X push(ep->follower); /* decode string backwards */
X code = ep->predecessor;
X ep = &string_tab[code];
X }
X
X push(finchar = ep->follower); /* save first character also */
X
X /*
X * The above loop will terminate, one way or another, with
X * string_tab[code].follower equal to the first character in
X * the string.
X */
X
X if (code_count) { /* if room left in string table */
X upd_tab(oldcode, finchar);
X --code_count;
X }
X oldcode = newcode;
X }
X return pop(); /* return saved character */
X}
SHAR_EOF
if test 22114 -ne "`wc -c < 'arclzw.c'`"
then
echo shar: "error transmitting 'arclzw.c'" '(should have been 22114 characters)'
fi
fi
echo shar: "extracting 'arcmatch.c'" '(3257 characters)'
if test -f 'arcmatch.c'
then
echo shar: "will not over-write existing file 'arcmatch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcmatch.c'
X/*
X * $Header: arcmatch.c,v 1.6 88/07/31 18:50:18 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCMATCH
X *
X * Version 2.17, created on 12/17/85 at 20:32:18
X *
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X *
X * By: Thom Henderson
X *
X * Description: This file contains service routines needed to maintain an
X * archive.
X *
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xint strcmp(), strlen();
Xvoid abort();
Xchar *strcpy();
X
Xint
Xmatch(n, t) /* test name against template */
X char *n; /* name to test */
X char *t; /* template to test against */
X{
X#ifdef LOCAL
X extern int unix_names;
X#endif /* LOCAL */
X#if MTS
X fortran patbuild(), patmatch(), patfree();
X static int patlen = (-1);
X static int patwork = 0;
X static int patswch = 0;
X char patccid[4];
X static char patchar[2] = "?";
X static char oldtemp[16] = 0;
X int namlen, RETCODE;
X
X if (strcmp(t, oldtemp)) {
X if (patwork)
X patfree(&patwork);
X strcpy(oldtemp, t);
X patlen = strlen(oldtemp);
X patbuild(oldtemp, &patlen, &patwork, &patswch, patccid, patchar, _retcode RETCODE);
X if (RETCODE > 8) {
X printf("MTS: patbuild returned %d\n", RETCODE);
X abort("bad wildcard in filename");
X }
X }
X namlen = strlen(n);
X patmatch(n, &namlen, &patwork, _retcode RETCODE);
X switch (RETCODE) {
X case 0:
X return (1);
X case 4:
X return (0);
X default:
X abort("wildcard pattern match failed");
X }
X}
X
X#else
X#if !UNIX
X upper(n);
X upper(t); /* avoid case problems */
X#endif /* UNIX */
X#if GEMDOS
X char *strstr(), *i; /* allow "*.*" to mean '*' */
X if (i=strstr(t,"*.*")) {
X i++;
X *i='\0';
X }
X return(pnmatch(n, t, 0));
X#else
X /* first match name part */
X
X#ifdef LOCAL
X if (!unix_names) {
X upper(n);
X upper(t);
X }
X#endif /* LOCAL */
X
X while ((*n && *n != '.') || (*t && *t != '.')) {
X if (*n != *t && *t != '?') { /* match fail? */
X if (*t != '*') /* wildcard fail? */
X return 0; /* then no match */
X else { /* else jump over wildcard */
X while (*n && *n != '.')
X n++;
X while (*t && *t != '.')
X t++;
X break; /* name part matches wildcard */
X }
X } else { /* match good for this char */
X n++; /* advance to next char */
X t++;
X }
X }
X
X if (*n && *n == '.')
X n++; /* skip extension delimiters */
X if (*t && *t == '.')
X t++;
X
X /* now match name part */
X
X while (*n || *t) {
X if (*n != *t && *t != '?') { /* match fail? */
X if (*t != '*') /* wildcard fail? */
X return 0; /* then no match */
X else
X return 1; /* else good enough */
X } else { /* match good for this char */
X n++; /* advance to next char */
X t++;
X }
X }
X
X return 1; /* match worked */
X#endif /* GEMDOS */
X}
X#endif
X
Xvoid
Xrempath(nargs, arg) /* remove paths from filenames */
X int nargs; /* number of names */
X char *arg[]; /* pointers to names */
X{
X char *i, *rindex(); /* string index, reverse indexer */
X int n; /* index */
X
X for (n = 0; n < nargs; n++) { /* for each supplied name */
X if (!(i = rindex(arg[n], '\\'))) /* search for end of
X * path */
X if (!(i = rindex(arg[n], '/')))
X i = rindex(arg[n], ':');
X if (i) /* if path was found */
X arg[n] = i + 1; /* then skip it */
X }
X}
SHAR_EOF
if test 3257 -ne "`wc -c < 'arcmatch.c'`"
then
echo shar: "error transmitting 'arcmatch.c'" '(should have been 3257 characters)'
fi
fi
echo shar: "extracting 'arcmisc.c'" '(8946 characters)'
if test -f 'arcmisc.c'
then
echo shar: "will not over-write existing file 'arcmisc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcmisc.c'
X/*
X * Miscellaneous routines to get ARC running on non-MSDOS systems...
X * $Header: arcmisc.c,v 1.8 88/07/31 18:50:56 hyc Exp $
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "arc.h"
X
X#if MSDOS
X#include <dir.h>
X#include <stat.h>
X#endif
X
X#if GEMDOS
X#include <osbind.h>
X#include <stat.h>
Xchar *index(), *rindex();
X
Xvoid
Xexitpause()
X{
X while (Cconis())
X Cnecin();
X fprintf(stderr, "Press any key to continue: ");
X fflush(stderr);
X Cnecin();
X fprintf(stderr, "\n");
X}
X
Xint
Xchdir(dirname)
X char *dirname;
X{
X char *i;
X int drv;
X
X i = dirname;
X if ((i = index(dirname, ':')) != NULL) {
X drv = i[-1];
X i++; /* Move past device spec */
X if (drv > '\'')
X drv -= 'a';
X else
X drv -= 'A';
X if (drv >= 0 && drv < 16)
X Dsetdrv(drv);
X }
X if (*i != '\0')
X return (Dsetpath(i));
X}
X#endif
X
X#if UNIX
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/stat.h>
X int rename(), unlink();
X#endif
X
X#if 0
X#include <dirent.h>
X#define DIRECT dirent
X#else
X#define DIRECT direct
X#endif
X
X#if BSD
Xchar *
Xmemset(s, c, n) /* oops. Thought it was standard BSD, but my Sun */
X char *s; /* fooled me again. -- hyc */
X int c, n;
X{
X register int i;
X for(i=0;i<n;i++)
X s[i]=c;
X return(s);
X}
X#endif
X
Xchar *strcpy(), *strcat(), *malloc();
Xint strlen(), strcmp(), match();
X
Xint
Xmove(oldnam, newnam)
X char *oldnam, *newnam;
X{
X FILE *fopen(), *old, *mnew;
X#if !MTS
X struct stat oldstat;
X#endif
X char *strcpy();
X void filecopy();
X#if GEMDOS
X if (Frename(0, oldnam, newnam))
X#else
X if (rename(oldnam, newnam))
X#endif
X#if !MTS
X {
X if (stat(oldnam, &oldstat)) /* different partition? */
X return (-1);
X old = fopen(oldnam, OPEN_R);
X if (old == NULL)
X return (-1);
X mnew = fopen(newnam, OPEN_W);
X if (mnew == NULL)
X return (-1);
X filecopy(old, mnew, oldstat.st_size);
X return(unlink(oldnam));
X }
X return 0;
X#else
X return(-1);
X#endif
X}
X
Xstatic void
X_makefn(source, dest)
X char *source;
X char *dest;
X{
X int j;
X#if MSDOS
X char *setmem();
X#else
X char *memset();
X#endif
X
X setmem(dest, 17, 0); /* clear result field */
X for (j = 0; *source && *source != '.'; ++source)
X if (j < 8)
X dest[j++] = *source;
X for (j = 9; *source; ++source)
X if (j < 13)
X dest[j++] = *source;
X}
X/*
X * make a file name using a template
X */
X
Xchar *
Xmakefnam(rawfn, template, result)
X char *rawfn; /* the original file name */
X char *template; /* the template data */
X char *result; /* where to place the result */
X{
X char et[17], er[17], rawbuf[STRLEN], *i, *rindex();
X
X *rawbuf = 0;
X strcpy(rawbuf, rawfn);
X#if MTS
X i = rawbuf;
X if (rawbuf[0] == tmpchr[0]) {
X i++;
X strcpy(rawfn, i);
X } else
X#endif
X if ((i = rindex(rawbuf, CUTOFF))) {
X i++;
X strcpy(rawfn, i);
X }
X#if DOS
X else if ((i = rindex(rawbuf, ':'))) {
X i++;
X strcpy(rawfn, i);
X }
X#endif
X if (i)
X *i = 0;
X else
X *rawbuf = 0;
X
X _makefn(template, et);
X _makefn(rawfn, er);
X *result = 0; /* assure no data */
X strcat(result, rawbuf);
X strcat(result, er[0] ? er : et);
X strcat(result, er[9] ? er + 9 : et + 9);
X return ((char *) &result[0]);
X}
X
X#if MSDOS || SYSV
X
Xint
Xalphasort(dirptr1, dirptr2)
X struct DIRECT **dirptr1, **dirptr2;
X{
X return (strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
X}
X
X#endif
X
X#ifdef LOCAL
Xvoid
Xlower(string)
X char *string;
X{
X char *p;
X
X for (p = string; *p; p++)
X if (isupper(*p))
X *p = tolower(*p);
X}
X#endif /* LOCAL */
X
Xvoid
Xupper(string)
X char *string;
X{
X char *p;
X
X for (p = string; *p; p++)
X if (islower(*p))
X *p = toupper(*p);
X}
X/* VARARGS1 */
Xvoid
Xabort(s, arg1, arg2, arg3)
X char *s;
X{
X fprintf(stderr, "ARC: ");
X fprintf(stderr, s, arg1, arg2, arg3);
X fprintf(stderr, "\n");
X#if UNIX
X perror("UNIX");
X#endif
X#if GEMDOS
X exitpause();
X#endif
X exit(1);
X}
X
X#if !MTS
X
Xchar *
Xgcdir(dirname)
X char *dirname;
X
X{
X char *getwd();
X#if GEMDOS
X int drv;
X char *buf;
X#endif
X if (dirname == NULL || strlen(dirname) == 0)
X dirname = (char *) malloc(1024);
X
X#if !GEMDOS
X getwd(dirname);
X#else
X buf = dirname;
X *buf++ = (drv = Dgetdrv()) + 'A';
X *buf++ = ':';
X Dgetpath(buf, 0);
X#endif
X return (dirname);
X}
X
X#if UNIX
Xchar *pattern; /* global so that fmatch can use it */
X#endif
X
Xchar *
Xdir(filename) /* get files, one by one */
X char *filename; /* template, or NULL */
X{
X#if GEMDOS
X static int Nnum = 0;
X static DMABUFFER dbuf, *saved;
X char *name;
X
X if (Nnum == 0) { /* first call */
X saved = (DMABUFFER *) Fgetdta();
X Fsetdta(&dbuf);
X if (Fsfirst(filename, 0) == 0) {
X name = malloc(FNLEN);
X strcpy(name, dbuf.d_fname);
X Nnum++;
X return (name);
X } else {
X Fsetdta(saved);
X return (NULL);
X }
X } else {
X if (Fsnext() == 0) {
X name = malloc(FNLEN);
X strcpy(name, dbuf.d_fname);
X return (name);
X } else {
X Nnum = 0;
X Fsetdta(saved);
X return (NULL);
X }
X }
X}
X#else
X static struct DIRECT **namelist;
X static char **NameList;
X static char namecopy[STRLEN], *dirname;
X#if UNIX
X int alphasort();
X int scandir();
X#endif /* UNIX */
X int fmatch(), free();
X static int Nnum = 0, ii;
X char *rindex();
X
X
X if (Nnum == 0) { /* first call */
X strcpy(namecopy,filename);
X if(pattern=rindex(namecopy,CUTOFF)) {
X *pattern = 0;
X pattern++;
X dirname = namecopy;
X } else {
X pattern = filename;
X dirname = ".";
X }
X Nnum = scandir(dirname, &namelist, fmatch, alphasort);
X NameList = (char **) malloc(Nnum * sizeof(char *));
X for (ii = 0; ii < Nnum; ii++) {
X (NameList)[ii] = malloc(strlen(namelist[ii]->d_name) + 1);
X strcpy((NameList)[ii], namelist[ii]->d_name);
X }
X ii = 0;
X }
X if (ii >= Nnum) { /* all out of files */
X if (Nnum) { /* there were some files found */
X for (ii = 0; ii < Nnum; ii++)
X free(namelist[ii]);
X free(namelist);
X }
X Nnum = 0;
X return (NULL);
X } else {
X return ((NameList)[ii++]);
X }
X}
X
X/*
X * Filename match - here, * matches everything
X */
X
Xint
Xfmatch(direntry)
X struct DIRECT *direntry;
X{
X char *string;
X
X string = direntry->d_name;
X
X if (!strcmp(pattern, "") || !strcmp(pattern, "*.*") || !strcmp(pattern, "*"))
X return (1);
X#if UNIX
X return(!strcmp(pattern, string));
X#else
X return (match(string, pattern));
X#endif
X}
X#endif /* GEMDOS */
X#else
X/* dir code for MTS under Bell Labs C... */
X
Xchar *
Xdir(filepattern)
X char *filepattern; /* template or NULL */
X{
X char *malloc(), *index();
X#if USECATSCAN
X fortran void catscan(), fileinfo();
X
X struct catname {
X short len;
X char name[257];
X } pattern;
X
X struct catval {
X int maxlen;
X int actlen;
X char name[257];
X } catreturn;
X
X char *i;
X int j, RETCODE;
X
X static int catptr = 0;
X static int catflag = 0x200;
X static int cattype = 1;
X static int patflag = 0;
X
X catreturn.maxlen = 256;
X
X if (patflag) {
X patflag = 0;
X catptr = 0;
X return (NULL);
X }
X if (filepattern) {
X strcpy(pattern.name, filepattern);
X pattern.len = strlen(filepattern);
X if (!index(filepattern, '?'))
X patflag = 1;
X }
X if (patflag) {
X fileinfo(&pattern, &cattype, "CINAME ", &catreturn, _retcode RETCODE);
X catptr = RETCODE ? 0 : 1;
X } else
X catscan(&pattern, &catflag, &cattype, &catreturn, &catptr);
X
X if (!catptr)
X return (NULL);
X else {
X char *k;
X
X k = index(catreturn.name, ' ');
X if (k)
X *k = 0;
X else {
X j = catreturn.actlen;
X catreturn.name[j] = 0;
X }
X k = catreturn.name;
X if (catreturn.name[0] == tmpchr[0])
X k++;
X else if ((k = index(catreturn.name, sepchr[0])))
X k++;
X else
X k = catreturn.name;
X j = strlen(k);
X i = malloc(++j);
X strcpy(i, k);
X return (i);
X }
X#else
X fortran void gfinfo();
X static char gfname[24];
X static char pattern[20];
X static int gfdummy[2] = {
X 0, 0
X }, gfflags;
X int i, RETCODE;
X char *j, *k;
X
X if (filepattern) {
X strcpy(pattern, filepattern);
X strcat(pattern, " ");
X for (i = 20; i < 24; i++)
X gfname[i] = '\0';
X if (index(pattern, '?'))
X gfflags = 0x0C;
X else
X gfflags = 0x09;
X } else if (gfflags == 0x09)
X return (NULL);
X
X gfinfo(pattern, gfname, &gfflags, gfdummy, gfdummy, gfdummy, _retcode RETCODE);
X if (RETCODE)
X return (NULL);
X else {
X k = index(gfname, ' ');
X *k = '\0';
X k = gfname;
X if (gfname[0] == tmpchr[0])
X k++;
X else if ((k = index(gfname, sepchr[0])))
X k++;
X else
X k = gfname;
X i = strlen(k);
X j = malloc(++i);
X strcpy(j, k);
X return (j);
X }
X#endif
X}
X
Xint
Xunlink(path)
X char *path; /* name of file to delete */
X{
X fortran void destroy();
X int RETCODE;
X
X char name[258];
X
X strcpy(name, path);
X strcat(name, " ");
X destroy(name, _retcode RETCODE);
X if (RETCODE)
X return (-1);
X else
X return (0);
X}
X#endif
SHAR_EOF
if test 8946 -ne "`wc -c < 'arcmisc.c'`"
then
echo shar: "error transmitting 'arcmisc.c'" '(should have been 8946 characters)'
fi
fi
echo shar: "extracting 'arcpack.c'" '(7438 characters)'
if test -f 'arcpack.c'
then
echo shar: "will not over-write existing file 'arcpack.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcpack.c'
X/*
X * $Header: arcpack.c,v 1.12 88/11/16 17:18:06 hyc Exp $
X */
X
X/* ARC - Archive utility - ARCPACK
X
X Version 3.49, created on 04/21/87 at 11:26:51
X
X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X By: Thom Henderson
X
X Description:
X This file contains the routines used to compress a file
X when placing it in an archive.
X
X Language:
X Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X#if MTS
X#include <ctype.h>
X#endif
X
Xvoid setcode(), sqinit_cm(), sqputc_cm(), init_cm(), putc_cm();
Xvoid filecopy(), abort(), putc_tst(), init_sq(), scan_sq();
Xint getch(), addcrc();
X
X/* stuff for non-repeat packing */
X
X#define DLE 0x90 /* repeat sequence marker */
X
Xstatic unsigned char state; /* current packing state */
X
X/* non-repeat packing states */
X
X#define NOHIST 0 /* don't consider previous input */
X#define SENTCHAR 1 /* lastchar set, no lookahead yet */
X#define SENDNEWC 2 /* run over, send new char next */
X#define SENDCNT 3 /* newchar set, send count next */
X
X/* packing results */
X
Xstatic long stdlen; /* length for standard packing */
Xstatic short crcval; /* CRC check value */
X
Xvoid
Xpack(f, t, hdr) /* pack file into an archive */
X FILE *f, *t; /* source, destination */
X struct heads *hdr; /* pointer to header data */
X{
X int c; /* one character of stream */
X long ncrlen; /* length after packing */
X long huflen; /* length after squeezing */
X long lzwlen; /* length after crunching */
X long pred_sq(), file_sq(); /* stuff for squeezing */
X long pred_cm(), sqpred_cm(); /* dynamic crunching cleanup */
X long tloc, ftell(); /* start of output */
X int getch();
X int getc_ncr();
X void putc_pak();
X
X /* first pass - see which method is best */
X
X tloc = ftell(t); /* note start of output */
X
X if (!nocomp) { /* if storage kludge not active */
X if (note) {
X printf(" analyzing, ");
X fflush(stdout);
X }
X state = NOHIST; /* initialize ncr packing */
X stdlen = ncrlen = 0; /* reset size counters */
X crcval = 0; /* initialize CRC check value */
X setcode(); /* initialize encryption */
X init_sq(); /* initialize for squeeze scan */
X
X if (dosquash) {
X sqinit_cm();
X while ((c = getch(f)) != EOF) { /* for each byte of file */
X ncrlen++; /* one more packed byte */
X scan_sq(c); /* see what squeezing can do */
X sqputc_cm(c, t); /* see what squashing
X * can do */
X }
X lzwlen = sqpred_cm(t);
X } else {
X init_cm(t); /* initialize for crunching */
X
X while ((c = getc_ncr(f)) != EOF) { /* for each byte of file */
X ncrlen++; /* one more packed byte */
X scan_sq(c); /* see what squeezing can do */
X putc_cm(c, t); /* see what crunching can do */
X }
X lzwlen = pred_cm(t); /* finish up after crunching */
X }
X huflen = pred_sq(); /* finish up after squeezing */
X } else { /* else kludge the method */
X stdlen = 0; /* make standard look best */
X ncrlen = huflen = lzwlen = 1;
X }
X
X /* standard set-ups common to all methods */
X
X fseek(f, 0L, 0); /* rewind input */
X hdr->crc = crcval; /* note CRC check value */
X hdr->length = stdlen; /* set actual file length */
X state = NOHIST; /* reinitialize ncr packing */
X setcode(); /* reinitialize encryption */
X
X /* choose and use the shortest method */
X
X if (kludge && note)
X printf("\n\tS:%ld P:%ld S:%ld C:%ld,\t ",
X stdlen, ncrlen, huflen, lzwlen);
X
X if (stdlen <= ncrlen && stdlen <= huflen && stdlen <= lzwlen) {
X if (note) {
X printf("storing, "); /* store without compression */
X fflush(stdout);
X }
X hdrver = 2; /* note packing method */
X fseek(t, tloc, 0); /* reset output for new method */
X stdlen = crcval = 0; /* recalc these for kludge */
X while ((c = getch(f)) != EOF) /* store it straight */
X putc_pak(c, t);
X hdr->crc = crcval;
X hdr->length = hdr->size = stdlen;
X } else if (ncrlen < lzwlen && ncrlen < huflen) {
X if (note) {
X printf("packing, "); /* pack with repeat */
X fflush(stdout); /* suppression */
X }
X hdrver = 3; /* note packing method */
X hdr->size = ncrlen; /* set data length */
X fseek(t, tloc, 0); /* reset output for new method */
X while ((c = getc_ncr(f)) != EOF)
X putc_pak(c, t);
X } else if (huflen < lzwlen) {
X if (note) {
X printf("squeezing, ");
X fflush(stdout);
X }
X hdrver = 4; /* note packing method */
X fseek(t, tloc, 0); /* reset output for new method */
X hdr->size = file_sq(f, t); /* note final size */
X } else {
X if (note)
X printf(dosquash ? "squashed, " : "crunched, ");
X hdrver = dosquash ? 9 : 8;
X hdr->size = lzwlen; /* size should not change */
X }
X
X /* standard cleanups common to all methods */
X
X if (note)
X printf("done. (%ld%%)\n",hdr->length == 0 ?
X 0L : 100L - (100L*hdr->size)/hdr->length);
X}
X
X/*
X * Non-repeat compression - text is passed through normally, except that a
X * run of more than two is encoded as:
X *
X * <char> <DLE> <count>
X *
X * Special case: a count of zero indicates that the DLE is really a DLE, not a
X * repeat marker.
X */
X
Xint
Xgetc_ncr(f) /* get bytes with collapsed runs */
X FILE *f; /* file to get from */
X{
X static int lastc; /* value returned on last call */
X static int repcnt; /* repetition counter */
X static int c; /* latest value seen */
X
X switch (state) { /* depends on our state */
X case NOHIST: /* no relevant history */
X state = SENTCHAR;
X return lastc = getch(f); /* remember the value next
X * time */
X
X case SENTCHAR: /* char was sent. look ahead */
X switch (lastc) {/* action depends on char */
X case DLE: /* if we sent a real DLE */
X state = NOHIST; /* then start over again */
X return 0; /* but note that the DLE was real */
X
X case EOF: /* EOF is always a special case */
X return EOF;
X
X default: /* else test for a repeat */
X for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++);
X /* find end of run */
X
X switch (repcnt) { /* action depends on run size */
X case 1:/* not a repeat */
X return lastc = c; /* but remember value
X * next time */
X
X case 2:/* a repeat, but too short */
X state = SENDNEWC; /* send the second one
X * next time */
X return lastc;
X
X default: /* a run - compress it */
X state = SENDCNT; /* send repeat count
X * next time */
X return DLE; /* send repeat marker this
X * time */
X }
X }
X
X case SENDNEWC: /* send second char of short run */
X state = SENTCHAR;
X return lastc = c;
X
X case SENDCNT: /* sent DLE, now send count */
X state = SENDNEWC;
X return repcnt;
X
X default:
X abort("Bug - bad ncr state\n");
X }
X return 0;
X}
X
Xint
Xgetch(f) /* special get char for packing */
X FILE *f; /* file to get from */
X{
X int c; /* a char from the file */
X#if !DOS
X static int cr = 0; /* add \r before \n ? */
X
X if (cr) {
X c = '\n';
X#if MTS
X c = toascii(c);
X#endif
X crcval = addcrc(crcval, c);
X stdlen++;
X cr = 0;
X return (c);
X }
X#endif
X
X if ((c = fgetc(f)) != EOF) { /* if not the end of file */
X#if !DOS
X if (!image && (c == '\n')) {
X c = '\r';
X cr = 1;
X }
X#endif
X#if MTS
X if (!image)
X c = toascii(c);
X#endif
X crcval = addcrc(crcval, c); /* then update CRC check
X * value */
X stdlen++; /* and bump length counter */
X }
X return c;
X}
X
Xvoid
Xputc_pak(c, f) /* put a packed byte into archive */
X char c; /* byte to put */
X FILE *f; /* archive to put it in */
X{
X unsigned char code();
X putc_tst(code(c), f); /* put encoded byte, with checks */
X}
SHAR_EOF
if test 7438 -ne "`wc -c < 'arcpack.c'`"
then
echo shar: "error transmitting 'arcpack.c'" '(should have been 7438 characters)'
fi
fi
echo shar: "extracting 'arcrun.c'" '(3859 characters)'
if test -f 'arcrun.c'
then
echo shar: "will not over-write existing file 'arcrun.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcrun.c'
X/*
X * $Header: arcrun.c,v 1.4 88/07/31 18:52:50 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCRUN
X *
X * Version 1.20, created on 03/24/86 at 19:34:31
X *
X * (C) COPYRIGHT 1985,85 by System Enhancement Associates; ALL RIGHTS RESERVED
X *
X * By: Thom Henderson
X *
X * Description: This file contains the routines used to "run" a file which is
X * stored in an archive. At present, all we really do is (a) extract a
X * temporary file, (b) give its name as a system command, and then (c) delete
X * the file.
X *
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid rempath(), openarc(), closearc(), abort();
Xint readhdr(), match(), unpack();
Xstatic void runfile();
Xchar *strcat();
X
Xvoid
Xrunarc(num, arg) /* run file from archive */
X int num; /* number of arguments */
X char *arg[]; /* pointers to arguments */
X{
X struct heads hdr; /* file header */
X char *makefnam(); /* filename fixer */
X char buf[STRLEN]; /* filename buffer */
X FILE *fopen();/* file opener */
X char *dummy[2];
X
X dummy[0]="dummy";
X dummy[1]=NULL;
X rempath(num, arg); /* strip off paths */
X
X openarc(0); /* open archive for reading */
X
X if (num) { /* if files were named */
X while (readhdr(&hdr, arc)) { /* while more files to check */
X if (match(hdr.name, makefnam(arg[0], ".*", buf)))
X runfile(&hdr, num, arg);
X else
X fseek(arc, hdr.size, 1);
X }
X } else
X while (readhdr(&hdr, arc)) /* else run all files */
X runfile(&hdr, 1, dummy);
X
X closearc(0); /* close archive after changes */
X}
X
Xstatic void
Xrunfile(hdr, num, arg) /* run a file */
X struct heads *hdr; /* pointer to header data */
X int num; /* number of arguments */
X char *arg[]; /* pointers to arguments */
X{
X FILE *tmp, *fopen(); /* temporary file */
X char *dir, *gcdir(); /* directory stuff */
X char buf[STRLEN], *makefnam(); /* temp file name, fixer */
X#if DOS
X char nbuf[64], *i, *rindex();
X#endif
X#if !GEMDOS
X int n; /* index */
X char sys[STRLEN]; /* invocation command buffer */
X#endif
X
X /* makefnam("$ARCTEMP",hdr->name,buf); */
X#if UNIX
X sprintf(buf, "%s.RUN", arctemp);
X strcpy(sys, buf);
X#else
X strcpy(nbuf, arctemp);
X makefnam(nbuf,hdr->name,buf);
X i = rindex(buf,'.');
X#endif
X#if MSDOS
X if (!strcmp(i, ".BAS")) {
X strcpy(sys, "BASICA ");
X strcat(sys, buf);
X }
X else if (!strcmp(i, ".BAT")
X || !strcmp(i, ".COM")
X || !strcmp(i, ".EXE"))
X strcpy(sys, buf);
X
X else {
X if (warn) {
X printf("File %s is not a .BAS, .BAT, .COM, or .EXE\n",
X hdr->name);
X nerrs++;
X }
X fseek(arc, hdr->size, 1); /* skip this file */
X return;
X }
X#endif
X#if GEMDOS
X if (strcmp(i, ".PRG")
X && strcmp(i, ".TTP")
X && strcmp(i, ".TOS"))
X {
X if (warn) {
X printf("File %s is not a .PRG, .TOS, or .TTP\n",
X hdr->name);
X nerrs++;
X }
X fseek(arc, hdr->size, 1); /* skip this file */
X return;
X }
X#endif
X
X if (warn)
X if (tmp = fopen(buf, "r"))
X abort("Temporary file %s already exists", buf);
X if (!(tmp = fopen(buf, OPEN_W)))
X abort("Unable to create temporary file %s", buf);
X
X if (note)
X printf("Invoking file: %s\n", hdr->name);
X
X dir = gcdir(""); /* see where we are */
X unpack(arc, tmp, hdr); /* unpack the entry */
X fclose(tmp); /* release the file */
X chmod(buf, "700"); /* make it executable */
X#if GEMDOS
X execve(buf, arg, NULL);
X#else
X for (n = 1; n < num; n++) { /* add command line arguments */
X strcat(sys, " ");
X strcat(sys, arg[n]);
X }
X system(buf); /* try to invoke it */
X#endif
X chdir(dir);
X free(dir); /* return to whence we started */
X if (unlink(buf) && warn) {
X printf("Cannot unsave temporary file %s\n", buf);
X nerrs++;
X }
X}
SHAR_EOF
if test 3859 -ne "`wc -c < 'arcrun.c'`"
then
echo shar: "error transmitting 'arcrun.c'" '(should have been 3859 characters)'
fi
fi
echo shar: "extracting 'arcs.h'" '(1645 characters)'
if test -f 'arcs.h'
then
echo shar: "will not over-write existing file 'arcs.h'"
else
sed 's/^X//' << \SHAR_EOF > 'arcs.h'
X/*
X * $Header: arcs.h,v 1.2 88/04/17 18:53:19 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - Archive file header format
X *
X * Version 2.12, created on 12/17/85 at 14:40:26
X *
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X *
X * By: Thom Henderson
X *
X * Description: This file defines the format of an archive file header,
X * excluding the archive marker and the header version number.
X *
X * Each entry in an archive begins with a one byte archive marker, which is set
X * to 26. The marker is followed by a one byte header type code, from zero
X * to 7.
X *
X * If the header type code is zero, then it is an end marker, and no more data
X * should be read from the archive.
X *
X * If the header type code is in the range 2 to 7, then it is followed by a
X * standard archive header, which is defined below.
X *
X * If the header type code is one, then it is followed by an older format
X * archive header. The older format header does not contain the true length.
X * A header should be read for a length of sizeof(struct heads)-sizeof(long).
X * Then set length equal to size and change the header version to 2.
X *
X * Programming note: The crc value given in the header is based on the unpacked
X * data.
X *
X * Language: Computer Innovations Optimizing C86
X */
X
Xstruct heads { /* archive entry header format */
X char name[FNLEN]; /* file name */
X long size; /* size of file, in bytes */
X unsigned short date; /* creation date */
X unsigned short time; /* creation time */
X short crc; /* cyclic redundancy check */
X long length; /* true file length */
X};
SHAR_EOF
if test 1645 -ne "`wc -c < 'arcs.h'`"
then
echo shar: "error transmitting 'arcs.h'" '(should have been 1645 characters)'
fi
fi
exit 0
# End of shell archive
More information about the Unix-pc.sources
mailing list