From:	CSBVAX::MRGATE!A.Harper@OAK.CC.KCL.AC.UK@SMTP 10-SEP-1988 06:02
To:	ARISIA::EVERHART
Subj:	Arc mods pt 4


Received: from UKACRL.BITNET by CUNYVM.CUNY.EDU (IBM VM SMTP R1.1) with BSMTP id 3687; Fri, 09 Sep 88 07:15:59 EDT
Received: from RL.IB by UKACRL.BITNET (Mailer X1.25) with BSMTP id 0173; Fri,
 09 Sep 88 12:10:48 BST
Received: from RL.IB by UK.AC.RL.IB (Mailer X1.25) with BSMTP id 0028; Fri, 09
          Sep 88 12:10:45 BS
Via:      UK.AC.KCL.CC.OAK;  9 SEP 88 12:06:49 BST
Date:     9-SEP-1988 12:07:33 GMT
From:     UDAA055%OAK.CC.KCL.AC.UK@CUNYVM.CUNY.EDU
To:       everhart%arisia.decnet@GE-CRD.ARPA
Subject:  Arc mods pt 4
Sender:   Andy Harper, Kings College London <A.Harper%OAK.CC.KCL.AC.UK@CUNYVM.CUNY.EDU>

Here is pt 4 of the arc mods, as requested.

Regards,

Andy Harper
kings College london

From:    OAK::UDAA055      "Andy, Systems Manager"  1-SEP-1988 13:58
To:    EARN%"info-vax@com.sri.kl",UDAA055
Subj:    ARC mods 4/7

+-+-+-+ Beginning of part 4 +-+-+-+
X                   if(*buf=='Y' || *buf=='N')
X                        break;
X              ‡
X              if(*buf=='N')
X              ¤    printf("%s not extracted.\n",USE);
X                   fseek(arc,hdr->size,1);
X                   return;
X              ‡
X         ‡
X    ‡
X
X    if(!(f=fopen(USE,"w")))
X    ¤    if(warn)
X         ¤    printf("Cannot create %s\n",USE);
X              nerrs++;
X         ‡
X         fseek(arc,hdr->size,1);
X         return;
X    ‡
X
X    /* now unpack the file */
X
X    unpack(arc,f,hdr);                 /* unpack file from archive */
X    setstamp(f,hdr->date,hdr->time);   /* set the proper date/time stamp */
X    fclose(f);                         /* all done writing to file */
X‡
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "ARCIO.C"
$ CHECKSUM_IS = 236777850
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
Xstatic char *RCSid = "$Header: arcio.c,v 1.2 86/07/15 07:53:11 turner Exp $";
X
X/*
X * $Log:`009arcio.c,v $
X * VAXC modifications       31-AUG-1988`009`009Andy Harper, KCL
X * Separated VAXC and BSD dependencies
X *
X * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
X * `009Bludgeoned into submission for VAX 11/780 BSD4.2
X *`009(ugly code, but fewer core dumps)
X *
X * Revision 1.2  86/07/15  07:53:11  turner
X *
X *
X * Revision 1.1  86/06/26  15:00:21  turner
X * initial version
X *
X *
X */
X
X/*  ARC - Archive utility - ARCIO
X
X$define(tag,$$segment(@1,$$index(@1,=)+1))#
X$define(version,Version $tag(
XTED_VERSION DB =2.30), created on $tag(
XTED_DATE DB =02/03/86) at $tag(
XTED_TIME DB =22:56:00))#
X$undefine(tag)#
X    $version
X
X(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:  Thom Henderson
X
X    Description:
X         This file contains the file I/O routines used to manipulate
X         an archive.
X
X    Language:
X         Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X
XINT readhdr(hdr,f)                     /* read a header from an archive */
Xstruct heads *hdr;                     /* storage for header */
XFILE *f;                               /* archive to read header from */
X¤
X#if VAXC | BSD | ST
X        unsigned char dummy[28];
X`009INT i,j,k;
X#endif
X    char name[FNLEN];                  /* filename buffer */
X    INT try = 0;                       /* retry counter */
X    static INT first = 1;              /* true only on first read */
X
X    if(!f)                             /* if archive didn't open */
X         return 0;                     /* then pretend it's the end */
X    if(feof(f))                        /* if no more data */
X         return 0;                     /* then signal end of archive */
X
X    if(fgetc(f)!=ARCMARK)             /* check archive validity */
X    ¤    if(warn)
X         ¤    printf("An entry in %s has a bad header.\n",arcname);
X              nerrs++;
X         ‡
X
X         while(!feof(f))
X         ¤    try++;
X              if(fgetc(f)==ARCMARK)
X              ¤    ungetc(hdrver=fgetc(f),f);
X                   if(hdrver>=0 && hdrver<=ARCVER)
X                        break;
X              ‡
X         ‡
X
X         if(feof(f) && first)
X              abort("%s is not an archive",arcname);
X
X         if(warn)
X              printf("  %d bytes skipped.\n",try);
X
X         if(feof(f))
X              return 0;
X    ‡
X
X    hdrver = fgetc(f);                 /* get header version */
X    if(hdrver<0)
X         abort("Invalid header in archive %s",arcname);
X    if(hdrver==0)
X         return 0;                     /* note our end of archive marker */
X    if(hdrver>ARCVER)
X    ¤    fread(name,sizeof(char),FNLEN,f);
X         printf("I don't know how to handle file %s in archive %s\n",
X              name,arcname);
X         printf("I think you need a newer version of ARC.\n");
X         exit(1);
X    ‡
X
X    /* amount to read depends on header type */
X
X    if(hdrver==1)                      /* old style is shorter */
X    ¤    fread(hdr,sizeof(struct heads)-sizeof(long),1,f);
X         hdrver = 2;                   /* convert header to new format */
X         hdr->length = hdr->size;      /* size is same when not packed */
X    ‡
X    else ¤
X#if MSDOS
X`009fread(hdr,sizeof(struct heads),1,f);
X#endif
X#if VAXC | BSD | ST
X`009fread(dummy,27,1,f);
X
X`009for(i=0;i<13;hdr->name[i]=dummy[i],i++);
X`009hdr->size = (long)((dummy[16]<<24) + (dummy[15]<<16) + (dummy[14]<<8)
X`009    + dummy[13]);
X`009hdr->date = (short)((dummy[18]<<8) + dummy[17]);
X`009hdr->time = (short)((dummy[20]<<8) + dummy[19]);
X`009hdr->crc  = (short)((dummy[22]<<8) + dummy[21]);
X`009hdr->length = (long)((dummy[26]<<24) + (dummy[25]<<16)
X`009    + (dummy[24]<<8) + dummy[23]);
X#endif
X    ‡
X
X    first = 0; return 1;               /* we read something */
X‡
X
XINT writehdr(hdr,f)                        /* write a header to an archive */
Xstruct heads *hdr;                     /* header to write */
XFILE *f;                               /* archive to write to */
X¤
X    unsigned char dummy[28];
X
X    fputc(ARCMARK,f);                 /* write out the mark of ARC */
X    fputc(hdrver,f);                   /* write out the header version */
X    if(!hdrver)                        /* if that's the end */
X         return;                       /* then write no more */
X#if MSDOS
X    fwrite(hdr,sizeof(struct heads),1,f);
X#endif
X#if VAXC | BSD | ST
X/*
X * put out the hdr in the brain damaged unaligned half back *sswards
X * way HAL does it
X */
X    fwrite(hdr->name,1,13,f);
X    fwrite(&hdr->size,sizeof(long),1,f);
X    fwrite(&hdr->date,sizeof(INT),1,f);
X    fwrite(&hdr->time,sizeof(INT),1,f);
X    fwrite(&hdr->crc ,sizeof(INT),1,f);
X    fwrite(&hdr->length,sizeof(long),1,f);
X#endif
X
X    /* note the newest file for updating the archive timestamp */
X
X    if(hdr->date>arcdate
X    ||(hdr->date==arcdate && hdr->time>arctime))
X    ¤    arcdate = hdr->date;
X         arctime = hdr->time;
X    ‡
X‡
X
XINT filecopy(f,t,size)                     /* bulk file copier */
XFILE *f, *t;                           /* from, to */
Xlong size;                             /* number of bytes */
X¤
X INT len;                           /* length of a given copy */
X INT putc_tst();
X
X    while(size--)                      /* while more bytes to move */
X         putc_tst(fgetc(f),t);
X‡
X
XINT putc_tst(c,t)                          /* put a character, with tests */
Xchar c;                                /* character to output */
XFILE *t;                               /* file to write to */
X¤
X    if(t);
X#if MSDOS | ST
X         if(fputc(c,t)==EOF)
X              abort("Write fail (disk full?)");
X#endif
X#if VAXC | BSD
X/*
X * for reasons beyond me BSD unix returns EOF
X */
X`009fputc(c,t);
X#endif
X‡
$ GOSUB UNPACK_FILE
$ FILE_IS = "ARCLZW.C"
$ CHECKSUM_IS = 826115788
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
Xstatic char *RCSid = "$Header: arclzw.c,v 1.2 86/07/15 07:53:20 turner Exp $";
X
X/*
X * $Log:`009arclzw.c,v $
X * VAXC modifications       31-AUG-1988`009`009Andy Harper, KCL
X * Separated VAXC and BSD dependencies
X *
X * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
X * `009Bludgeoned into submission for VAX 11/780 BSD4.2
X *`009(ugly code, but fewer core dumps)
X *
X * Revision 1.2  86/07/15  07:53:20  turner
X *
X *
X * Revision 1.1  86/06/26  15:00:26  turner
X * initial version
X *
X *
X */
X
X/*  ARC - Archive utility - ARCLZW
X
X$define(tag,$$segment(@1,$$index(@1,=)+1))#
X$define(version,Version $tag(
XTED_VERSION DB =1.88), created on $tag(
XTED_DATE DB =01/20/86) at $tag(
XTED_TIME DB =16:47:04))#
X$undefine(tag)#
X    $version
X
X(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:  Thom Henderson
X
X    Description:
X         This file contains the routines used to implement Lempel-Zev
X         data compression, which calls for building a coding table on
X         the fly.  This form of compression is especially good for encoding
X         files which contain repeated strings, and can often give dramatic
X         improvements over traditional Huffman SQueezing.
X
X    Language:
X         Computer Innovations Optimizing C86
X
X    Programming notes:
X         In this section I am drawing heavily on the COMPRESS program
X         from UNIX.  The basic method is taken from "A Technique for High
X         Performance Data Compression", Terry A. Welch, IEEE Computer
X         Vol 17, No 6 (June 1984), pp 8-19.  Also see "Knuth's Fundamental
X         Algorithms", Donald Knuth, Vol 3, Section 6.4.
X
X         As best as I can tell, this method works by tracing down a hash
X         table of code strings where each entry has the property:
X
X              if <string> <char> is in the table
X              then <string> is in the table.
X*/
X#include <stdio.h>
X#include "arc.h"
X
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 INT inbuf;             /* partial input code storage */
Xstatic INT sp;                         /* current stack pointer */
X
Xstatic struct entry                    /* string table entry format */
X¤   char used;                         /* true when this entry is in use */
X    unsigned INT next;                 /* ptr to next in collision list */
X    unsigned INT predecessor;          /* code for preceeding string */
X    unsigned char follower;            /* char following 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 unsigned char buf[BITS];        /* input/output buffer */
X
Xstatic unsigned char lmask[9] =        /* left side masks */
X¤   0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 ‡;
Xstatic unsigned char rmask[9] =        /* right side masks */
X¤   0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff‡;
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 unsigned INT ent;
X
X/* To save much memory (which we badly need at this point), we overlay
X * the table used by the previous version of Lempel-Zev with those used
X * by the new version.  Since no two of these routines will be used
X * together, we can safely do this.  Note that the tables used for Huffman
X * squeezing may NOT overlay these, since squeezing and crunching are done
X * in parallel.
X */
X
X#if MSDOS
Xstatic long *htab = string_tab;        /* hash code table   (crunch) */
X#endif
X#if VAXC | BSD | ST
Xstatic long htab[HSIZE];               /* hash code table   (crunch) */
X#endif
Xstatic unsigned INT codetab[HSIZE];    /* string code table (crunch) */
X
Xstatic unsigned INT *prefix = codetab; /* prefix code table (uncrunch) */
X
X#if MSDOS
Xstatic unsigned char *suffix = string_tab;  /* suffix table (uncrunch) */
X#endif
X#if VAXC | BSD | ST
Xstatic unsigned char suffix[HSIZE];    /* suffix table (uncrunch) */
X#endif
Xstatic INT free_ent;                   /* first unused entry */
Xstatic INT firstcmp;                   /* true at start of compression */
Xstatic unsigned char stack[HSIZE];     /* local push/pop stack */
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
X
Xstatic INT clear_flg;
Xstatic long ratio;
X#define CHECK_GAP 10000                /* ratio check interval */
Xstatic long checkpoint;
X
X/*
X * the next two codes should not be changed lightly, as they must not
X * lie within the contiguous general code space.
X */
X#define FIRST   257                    /* first free entry */
X#define CLEAR   256                    /* table clear output code */
X
Xstatic INT cl_block(t)                     /* table clear for block compress */
XFILE *t;                               /* our output file */
X¤
X    long rat;
X    INT putcode();
X
X    checkpoint = in_count + CHECK_GAP;
X
X    if(in_count > 0x007fffff)          /* shift will overflow */
X    ¤    rat = bytes_out >> 8;
X         if(rat == 0)                  /* Don't divide by zero */
X              rat = 0x7fffffff;
X         else rat = in_count / rat;
X    ‡
X    else rat = (in_count<<8)/bytes_out;/* 8 fractional bits */
X
X    if(rat > ratio)
X         ratio = rat;
X    else
X    ¤    ratio = 0;
X         setmem`009(htab,HSIZE*sizeof(long),0xff);
X         free_ent = FIRST;
X         clear_flg = 1;
X         putcode(CLEAR,t);
X    ‡
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 INT putcode(code,t)                 /* output a code */
XINT code;                              /* code to output */
XFILE *t;                               /* where to put it */
X¤
X INT r_off = offset;                /* right offset */
X INT bits = n_bits;                 /* bits to go */
X unsigned char *bp = buf;           /* buffer pointer */
X INT n;                             /* index */
X
X    if(code >= 0)                      /* if a real code */
X    ¤    /*
X          * Get to the first byte.
X          */
X         bp += (r_off >> 3);
X         r_off &= 7;
X
X         /*
X          * Since code is always >= 8 bits, only need to mask the first
X          * hunk on the left.
X          */
X         *bp = (*bp&rmask[r_off]) | (code<<r_off) & lmask[r_off];
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
X         /* Last bits. */
X         if(bits)
X              *bp = code;
X
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;
-+-+-+-+-+ End of part 4 +-+-+-+-+-
