ARC for BSD4.2 (part 2 of 5)

turner at imagen.UUCP turner at imagen.UUCP
Tue Aug 5 08:40:33 AEST 1986


This is my hacked version of the arc program that was posted to the net, I
have modified it to run under Unix BSD4.2. if you want it to run under 
SVR2 you probably will have to change the opendir, scandir, and closedir
calls, I don't really know System 5. IMPORTANT: this is a BETA test version
i doubt severly that there are no bugs, please report any that you find to me.

1) I don't have a PC handy so i have no idea if it still works on the PC; to
	compile it for the PC edit arc.h and arcs.c and change the #defines,
	the define ST is for the Atari 520ST and with luck that will be done
	shortly. If you compile it for the PC you will need the routines for 
	opendir etc. that are in shar part 5, otherwise you can ignore that 
	shar file.
2) the Makefile is configured to compile for debugging (-g) (shows ya what 
	kind of faith i have in my code (:-)
3) everything seems to work for both arc files created on the PC and on BSD4.2
	with the exception of the t (test) option which gives strange results,
	i suspect the problem is in the code not the archive
4) there is one bug that i know of, if you archive a 0 length file, arc will
	blow up (floating point exception) when you try to extract it; the
	question is should the check happen when you add the file, extract
	it, or should if create a 0 length file ? you decide.
5) send flames etc. to me, because of the way postnews works here my signature
	will probably be at the end of each shar file, if not its:
----
Name:	James M. Turner
Mail:	Imagen Corp. 2650 San Tomas Expressway, P.O. Box 58101
        Santa Clara, CA 95052-8101
AT&T:	(408) 986-9400
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner
CompuServe: 76327,1575
GEnie     : D-ARCANGEL
----

#! /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:
#	arcext.c
#	arcio.c
#	arclst.c
#	arclzw.c
#	arcmatch.c
#	arcmisc.c
#	arconvt.c
# This archive created: Mon Aug  4 14:44:49 1986
# By:	D'arc Angel (The Houses of the Holy)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'arcext.c'" '(6059 characters)'
if test -f 'arcext.c'
then
	echo shar: "will not over-write existing file 'arcext.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arcext.c'
	X/*
	X$define(arc,$ifdef(xarc,off,on))#      macro switch for ARC only code
	X$define(xarc,$ifdef(xarc,on,off))#     macro switch for XARC only code
	X */
	X/*  ARC - Archive utility - ARCEXT
	X
	X$define(tag,$$segment(@1,$$index(@1,=)+1))#
	X$define(version,Version $tag(
	XTED_VERSION DB =2.18), created on $tag(
	XTED_DATE DB =02/03/86) at $tag(
	XTED_TIME DB =22:55:19))#
	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 extract files from
	X         an archive.
	X
	X    Language:
	X         Computer Innovations Optimizing C86
	X*/
	X#include <stdio.h>
	X#include "arc.h"
	X#if ARC					/* $emit($arc)# */
	Xextarc(num,arg,prt)                    /* extract files from archive */
	Xint num;                               /* number of arguments */
	Xchar *arg[];                           /* pointers to arguments */
	Xint prt;                               /* true if printing */
	X#endif					/* $emit($xarc)# */
	X#if XARC
	Xextarc()                               /* extract files from archive */
	X#endif					/* $emit(on)# */
	X{
	X    struct heads hdr;                  /* file header */
	X#if ARC					/* $emit($arc)# */
	X int save;                          /* true to save current file */
	X int did[MAXARG];                  /* true when argument was used */
	X    char *i, *rindex();                /* string index */
	X    char **name, *malloc();             /* name pointer list, allocator */
	X int n;                             /* index */
	X
	X#if MSDOS
	X    name = malloc(num*sizeof(char *));  /* get storage for name pointers */
	X#endif
	X#if BSD
	X    name = (char **)malloc(num*sizeof(char *));  /* get storage for name pointers */
	X#endif
	X
	X    for(n=0; n<num; n++)               /* for each argument */
	X    {    did[n] = 0;                   /* reset usage flag */
	X         if(!(i=rindex(arg[n],'\\')))  /* find start of name */
	X              if(!(i=rindex(arg[n],'/')))
	X                   if(!(i=rindex(arg[n],':')))
	X                        i = arg[n]-1;
	X         name[n] = i+1;
	X    }
	X
	X#endif					/* $emit(on)# */
	X
	X    openarc(0);                        /* open archive for reading */
	X
	X#if ARC					/* $emit($arc)# */
	X    if(num)                            /* if files were named */
	X    {    while(readhdr(&hdr,arc))      /* while more files to check */
	X         {    save = 0;                /* reset save flag */
	X              for(n=0; n<num; n++)     /* for each template given */
	X              {    if(match(hdr.name,name[n]))
	X                   {    save = 1;      /* turn on save flag */
	X                        did[n] = 1;    /* turn on usage flag */
	X                        break;         /* stop looking */
	X                   }
	X              }
	X
	X              if(save)                 /* extract if desired, else skip */
	X                   extfile(&hdr,arg[n],prt);
	X              else fseek(arc,hdr.size,1);
	X         }
	X    }
	X
	X    else while(readhdr(&hdr,arc))      /* else extract all files */
	X         extfile(&hdr,"",prt);
	X#endif					/* $emit($xarc)# */
	X#if XARC
	X    while(readhdr(&hdr,arc))           /* extract all files */
	X         extfile(&hdr);
	X#endif					/* $emit(on)# */
	X
	X    closearc(0);                       /* close archive after reading */
	X#if ARC					/* $emit($arc)# */
	X
	X    if(note)
	X    {    for(n=0; n<num; n++)          /* report unused args */
	X         {    if(!did[n])
	X              {    printf("File not found: %s\n",arg[n]);
	X                   nerrs++;
	X              }
	X         }
	X    }
	X
	X    free(name);
	X#endif					/* $emit(on)# */
	X}
	X
	X#if ARC					/* $emit($arc)# */
	Xstatic extfile(hdr,path,prt)           /* extract a file */
	Xstruct heads *hdr;                     /* pointer to header data */
	Xchar *path;                            /* pointer to path name */
	Xint prt;                               /* true if printing */
	X#endif					/* $emit($xarc)# */
	X#if XARC
	Xstatic extfile(hdr)                    /* extract a file */
	X#endif					/* $emit(on)# */
	X			/* $define(use,$ife($arc,on,fix,hdr->name))# */
	X#if ARC
	X#define USE fix
	X#else
	X#define USE hdr->name
	X#endif
	X
	X{
	X    FILE *f, *fopen();                 /* extracted file, opener */
	X    char buf[STRLEN];                 /* input buffer */
	X#if ARC					/* $emit($arc)# */
	X    char fix[STRLEN];                 /* fixed name buffer */
	X    char *i, *rindex();                /* string index */
	X
	X    if(prt)                            /* printing is much easier */
	X    {    unpack(arc,stdout,hdr);       /* unpack file from archive */
	X         printf("\f");                 /* eject the form */
	X         return;                       /* see? I told you! */
	X    }
	X
	X    strcpy(fix,path);                  /* note path name template */
	X    if(!(i=rindex(fix,'\\')))          /* find start of name */
	X         if(!(i=rindex(fix,'/')))
	X              if(!(i=rindex(fix,':')))
	X                   i = fix-1;
	X    strcpy(i+1,hdr->name);             /* replace template with name */
	X#endif					/* $emit(on)# */
	X
	X    if(note)
	X         printf("Extracting file: %s\n",USE);
	X
	X    if(warn)
	X    {    if(f=fopen(USE,"rb"))        /* see if it exists */
	X         {    fclose(f);
	X              printf("WARNING: File %s already exists!",USE);
	X              while(1)
	X              {    printf("  Overwrite it (y/n)? ");
	X                   fgets(buf,STRLEN,stdin);
	X                   *buf = toupper(*buf);
	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,"wb")))
	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}
SHAR_EOF
if test 6059 -ne "`wc -c < 'arcext.c'`"
then
	echo shar: "error transmitting 'arcext.c'" '(should have been 6059 characters)'
fi
fi
echo shar: "extracting 'arcio.c'" '(5382 characters)'
if test -f 'arcio.c'
then
	echo shar: "will not over-write existing file 'arcio.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arcio.c'
	Xstatic char *RCSid = "$Header: arcio.c,v 1.2 86/07/15 07:53:11 turner Exp $";
	X
	X/*
	X * $Log:	arcio.c,v $
	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 BSD | ST
	X        unsigned char dummy[28];
	X	int 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.",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 int),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	fread(hdr,sizeof(struct heads),1,f);
	X#endif
	X#if BSD | ST
	X	fread(dummy,27,1,f);
	X
	X	for(i=0;i<13;hdr->name[i]=dummy[i],i++);
	X	hdr->size = (long)((dummy[16]<<24) + (dummy[15]<<16) + (dummy[14]<<8)
	X	    + dummy[13]);
	X	hdr->date = (short)((dummy[18]<<8) + dummy[17]);
	X	hdr->time = (short)((dummy[20]<<8) + dummy[19]);
	X	hdr->crc  = (short)((dummy[22]<<8) + dummy[21]);
	X	hdr->length = (long)((dummy[26]<<24) + (dummy[25]<<16)
	X	    + (dummy[24]<<8) + dummy[23]);
	X#endif
	X    }
	X
	X    first = 0; return 1;               /* we read something */
	X}
	X
	Xwritehdr(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 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
	Xfilecopy(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
	X    while(size--)                      /* while more bytes to move */
	X         putc_tst(fgetc(f),t);
	X}
	X
	Xputc_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 MSODS | ST
	X         if(fputc(c,t)==EOF)
	X              abort("Write fail (disk full?)");
	X#endif
	X#if BSD
	X/*
	X * for reasons beyond me BSD unix returns EOF 
	X */
	X	fputc(c,t);
	X#endif
	X}
SHAR_EOF
if test 5382 -ne "`wc -c < 'arcio.c'`"
then
	echo shar: "error transmitting 'arcio.c'" '(should have been 5382 characters)'
fi
fi
echo shar: "extracting 'arclst.c'" '(5517 characters)'
if test -f 'arclst.c'
then
	echo shar: "will not over-write existing file 'arclst.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arclst.c'
	Xstatic char *RCSid = "$Header: arclst.c,v 1.2 86/07/15 07:53:15 turner Exp $";
	X
	X/*
	X * $Log:	arclst.c,v $
	X * Revision 1.2  86/07/15  07:53:15  turner
	X * 
	X * 
	X * Revision 1.1  86/06/26  15:00:23  turner
	X * initial version
	X * 
	X * 
	X */
	X
	X/*  ARC - Archive utility - ARCLST
	X
	X$define(tag,$$segment(@1,$$index(@1,=)+1))#
	X$define(version,Version $tag(
	XTED_VERSION DB =2.34), created on $tag(
	XTED_DATE DB =02/03/86) at $tag(
	XTED_TIME DB =22:56:57))#
	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 list the contents
	X         of an archive.
	X
	X    Language:
	X         Computer Innovations Optimizing C86
	X*/
	X#include <stdio.h>
	X#include "arc.h"
	X
	Xlstarc(num,arg)                        /* list files in archive */
	Xint num;                               /* number of arguments */
	Xchar *arg[];                           /* pointers to arguments */
	X{
	X    struct heads hdr;                  /* header data */
	X int list;                          /* true to list a file */
	X int did[MAXARG];                  /* true when argument was used */
	X    long tnum, tlen, tsize;            /* totals */
	X int n;                             /* index */
	X
	X    tnum = tlen = tsize = 0;           /* reset totals */
	X
	X    for(n=0; n<num; n++)               /* for each argument */
	X         did[n] = 0;                   /* reset usage flag */
	X    rempath(num,arg);                  /* strip off paths */
	X
	X    if(!kludge)
	X    {    printf("Name          Length  ");
	X         if(bose)
	X              printf("  Stowage    SF   Size now");
	X         printf("  Date     ");
	X         if(bose)
	X              printf("  Time    CRC");
	X         printf("\n");
	X
	X         printf("============  ========");
	X         if(bose)
	X              printf("  ========  ====  ========");
	X         printf("  =========");
	X         if(bose)
	X              printf("  ======  ====");
	X         printf("\n");
	X    }
	X
	X    openarc(0);                        /* open archive for reading */
	X
	X    if(num)                            /* if files were named */
	X    {    while(readhdr(&hdr,arc))      /* process all archive files */
	X         {    list = 0;                /* reset list flag */
	X              for(n=0; n<num; n++)     /* for each template given */
	X              {    if(match(hdr.name,arg[n]))
	X                   {    list = 1;      /* turn on list flag */
	X                        did[n] = 1;    /* turn on usage flag */
	X                        break;         /* stop looking */
	X                   }
	X              }
	X
	X              if(list)                 /* if this file is wanted */
	X              {    if(!kludge)
	X                        lstfile(&hdr); /* then tell about it */
	X                   tnum++;             /* update totals */
	X                   tlen += hdr.length;
	X                   tsize += hdr.size;
	X              }
	X
	X              fseek(arc,hdr.size,1);   /* move to next header */
	X         }
	X    }
	X
	X    else while(readhdr(&hdr,arc))      /* else report on all files */
	X    {    if(!kludge)
	X              lstfile(&hdr);
	X         tnum++;                       /* update totals */
	X         tlen += hdr.length;
	X         tsize += hdr.size;
	X         fseek(arc,hdr.size,1);        /* skip to next header */
	X    }
	X
	X    closearc(0);                       /* close archive after reading */
	X
	X    if(!kludge)
	X    {    printf("        ====  ========");
	X         if(bose)
	X              printf("            ====  ========");
	X         printf("\n");
	X    }
	X
	X    printf("Total %6ld  %8ld  ",tnum,tlen);
	X    if(bose)
	X         printf("          %3ld%%  %8ld  ",100L - (100L*tsize)/tlen,tsize);
	X    printf("\n");
	X
	X    if(note)
	X    {    for(n=0; n<num; n++)          /* report unused args */
	X         {    if(!did[n])
	X              {    printf("File not found: %s\n",arg[n]);
	X                   nerrs++;
	X              }
	X         }
	X    }
	X}
	X
	Xstatic lstfile(hdr)                    /* tell about a file */
	Xstruct heads *hdr;                     /* pointer to header data */
	X{
	X int yr, mo, dy;                    /* parts of a date */
	X int hh, mm, ss;                    /* parts of a time */
	X
	X    static char *mon[] =               /* month abbreviations */
	X    {    "Jan",    "Feb",    "Mar",    "Apr",
	X         "May",    "Jun",    "Jul",    "Aug",
	X         "Sep",    "Oct",    "Nov",    "Dec"
	X    };
	X
	X    yr = (hdr->date >> 9) & 0x7f;      /* dissect the date */
	X    mo = (hdr->date >> 5) & 0x0f;
	X    dy = hdr->date & 0x1f;
	X
	X    hh = (hdr->time >> 11) & 0x1f;     /* dissect the time */
	X    mm = (hdr->time >> 5) & 0x3f;
	X    ss = (hdr->time & 0x1f) * 2;
	X
	X    printf("%-12s  %8ld  ",hdr->name,hdr->length);
	X
	X    if(bose)
	X    {    switch(hdrver)
	X         {
	X         case 1:
	X         case 2:
	X              printf("   --   ");
	X              break;
	X         case 3:
	X              printf(" Packed ");
	X              break;
	X         case 4:
	X              printf("Squeezed");
	X              break;
	X         case 5:
	X         case 6:
	X         case 7:
	X              printf("crunched");
	X              break;
	X         case 8:
	X              printf("Crunched");
	X              break;
	X         default:
	X              printf("Unknown!");
	X         }
	X
	X         printf("  %3d%%",100L - (100L*hdr->size)/hdr->length);
	X         printf("  %8ld  ",hdr->size);
	X    }
	X
	X    printf("%2d %3s %02d", dy, mon[mo-1], (yr+80)%100);
	X
	X    if(bose)
	X         printf("  %2d:%02d%c  %04x",
	X              (hh>12?hh-12:hh), mm, (hh>12?'p':'a'),
	X              hdr->crc);
	X
	X    printf("\n");
	X}
SHAR_EOF
if test 5517 -ne "`wc -c < 'arclst.c'`"
then
	echo shar: "error transmitting 'arclst.c'" '(should have been 5517 characters)'
fi
fi
echo shar: "extracting 'arclzw.c'" '(27190 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'
	Xstatic char *RCSid = "$Header: arclzw.c,v 1.2 86/07/15 07:53:20 turner Exp $";
	X
	X/*
	X * $Log:	arclzw.c,v $
	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 MSODS
	Xstatic long *htab = string_tab;        /* hash code table   (crunch) */
	X#endif
	X#if 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 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 cl_block(t)                     /* table clear for block compress */
	XFILE *t;                               /* our output file */
	X{
	X    long int rat;
	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	(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 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;
	X         }
	X
	X         /*
	X          * If the next entry is going to be too big for the code size,
	X          * then increase it, if possible.
	X          */
	X         if(free_ent>maxcode || clear_flg>0)
	X         {    /*
	X               * Write the whole buffer, because the input side won't
	X               * discover the size increase until after 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              }
	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    }
	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 getcode(f)                  /* get a code */
	XFILE *f;                               /* file to get from */
	X{
	X int code;
	X    static int offset = 0, size = 0;
	X int r_off, bits;
	X    unsigned char *bp = buf;
	X
	X    if(clear_flg > 0 || offset >= 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 reading
	X          * 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 now */
	X              else maxcode = MAXCODE(n_bits);
	X         }
	X         if(clear_flg > 0)
	X         {    maxcode = MAXCODE(n_bits = INIT_BITS);
	X              clear_flg = 0;
	X         }
	X
	X         for(size=0; size<n_bits; size++)
	X         {    if((code=getc_unp(f))==EOF)
	X                   break;
	X              else buf[size] = code;
	X         }
	X         if(size <= 0)
	X              return -1;               /* end of file */
	X
	X         offset = 0;
	X         /* Round size down to integral number of codes */
	X         size = (size << 3)-(n_bits - 1);
	X    }
	X    r_off = offset;
	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    offset += n_bits;
	X
	X    return code;
	X}
	X
	X/*
	X * compress a file
	X *
	X * Algorithm:  use open addressing double hashing (no chaining) on the
	X * prefix code / next character combination.  We do a variant of Knuth's
	X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
	X * secondary probe.  Here, the modular division first probe is gives way
	X * to a faster exclusive-or manipulation.  Also do block compression with
	X * an adaptive reset, where the code table is cleared when the compression
	X * ratio decreases, but after the table fills.  The variable-length output
	X * codes are re-sized at this point, and a special CLEAR code is generated
	X * for the decompressor.
	X */
	X
	Xinit_cm(f,t)                           /* initialize for compression */
	XFILE *f;                               /* file we will be compressing */
	XFILE *t;                               /* where we will put it */
	X{
	X    offset = 0;
	X    bytes_out = 1;
	X    clear_flg = 0;
	X    ratio = 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
	Xputc_cm(c,t)                           /* compress a character */
	Xunsigned char c;                       /* character to compress */
	XFILE *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 bund */
	X
	X         firstcmp = 0;                 /* no longer first */
	X         return;
	X    }
	X
	X    in_count++;
	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    }
	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    else if((long int)in_count >= checkpoint)
	X         cl_block(t);
	X}
	X
	Xlong pred_cm(t)                        /* finish compressing a file */
	XFILE *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
	X * building the string table on-the-fly; requiring no table to be stored
	X * in the compressed file.  The tables used herein are shared with those of
	X * the compress() routine.  See the definitions above.
	X */
	X
	Xdecomp(f,t)                            /* decompress a file */
	XFILE *f;                               /* file to read codes from */
	XFILE *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    for(code = 255; code >= 0; code--)
	X    {    prefix[code] = 0;
	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((char)finchar,t);         /* first code must be 8 bits=char */
	X    stackp = stack;
	X
	X    while((code = getcode(f))> -1)
	X    {    if(code==CLEAR)
	X         {    for(code = 255; code >= 0; code--)
	X                   prefix[code] = 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         {    *stackp++ = finchar;
	X              code = oldcode;
	X         }
	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/*  The h() pointer points to the routine to use for calculating a hash
	X    value.  It is set in the init routines to point to either of oldh()
	X    or newh().
	X
	X    oldh() calculates a hash value by taking the middle twelve bits
	X    of the square of the key.
	X
	X    newh() works somewhat differently, and was tried because it makes
	X    ARC about 23% faster.  This approach was abandoned because dynamic
	X    Lempel-Zev (above) works as well, and packs smaller also.  However,
	X    inadvertent release of a developmental copy forces us to leave this in.
	X*/
	X
	Xstatic unsigned (*h)();                /* pointer to hash function */
	X
	Xstatic unsigned oldh(pred,foll)        /* old hash function */
	Xunsigned int pred;                     /* code for preceeding string */
	Xunsigned char foll;                    /* value of following char */
	X{
	X    long local;                        /* local hash value */
	X
	X    local = (pred + foll) | 0x0800;    /* create the hash key */
	X    local *= local;                    /* square it */
	X    return (local >> 6) & 0x0FFF;      /* return the middle 12 bits */
	X}
	X
	Xstatic unsigned newh(pred,foll)        /* new hash function */
	Xunsigned int pred;                     /* code for preceeding string */
	Xunsigned char foll;                    /* value of following char */
	X{
	X    return ((pred+foll)*15073)&0xFFF;  /* faster hash */
	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 eolist(index)          /* find last duplicate */
	Xunsigned int 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/*  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
	X    MUST be checked for elsewhere.
	X*/
	X
	Xstatic unsigned hash(pred,foll)        /* find spot in the string table */
	Xunsigned int pred;                     /* code for preceeding string */
	Xunsigned char foll;                    /* char following string */
	X{
	X    unsigned int 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         /*   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              }
	X              else ++ep;               /* point to next element in table */
	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/*  The unhash() function is used to search the hash table for a given key.
	X    Like hash(), it performs a hash and linear probe search.  It returns
	X    either the number of the entry (if found) or NOT_FND (if not found).
	X*/
	X
	Xstatic unsigned unhash(pred,foll)      /* search string table for a key */
	Xunsigned int pred;                     /* code of preceeding string */
	Xunsigned char foll;                    /* character following string */
	X{
	X    unsigned int local, offset;        /* scratch storage */
	X    struct entry *ep;                  /* this speeds up access */
	X
	X    local = (*h)(pred,foll);           /* initial hash */
	X
	X    while(1)
	X    {    ep = &string_tab[local];      /* speed up table access */
	X
	X         if((ep->predecessor==pred) && (ep->follower==foll))
	X              return local;            /* we have a match */
	X
	X         if(!ep->next)                 /* if no more duplicates */
	X              return NOT_FND;          /* then key is not listed */
	X
	X         local = ep->next;             /* move on to next duplicate */
	X    }
	X}
	X
	X/*  The init_tab() routine is used to initialize our hash table.
	X    You realize, of course, that "initialize" is a complete misnomer.
	X*/
	X
	Xstatic init_tab()                      /* set ground state in hash table */
	X{
	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/*  The upd_tab routine is used to add a new entry to the string table.
	X    As previously stated, no checks are made to ensure that the table
	X    has any room.  This must be done elsewhere.
	X*/
	X
	Xupd_tab(pred,foll)                     /* add an entry to the table */
	Xunsigned int pred;                     /* code for preceeding string */
	Xunsigned int 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/*  This algorithm encoded a file into twelve bit strings (three nybbles).
	X    The gocode() routine is used to read these strings a byte (or two)
	X    at a time.
	X*/
	X
	Xstatic gocode(fd)                      /* read in a twelve bit code */
	XFILE *fd;                              /* file to get code from */
	X{
	X    unsigned int localbuf, returnval;
	X
	X    if(inbuf==EMPTY)                   /* if on a code boundary */
	X    {    if((localbuf=getc_unp(fd))==EOF)   /* get start of next code */
	X              return EOF;              /* pass back end of file status */
	X         localbuf &= 0xFF;             /* mask down to true byte value */
	X         if((inbuf=getc_unp(fd))==EOF) /* get end of code, start of next */
	X              return EOF;              /* this should never happen */
	X         inbuf &= 0xFF;                /* mask down to true byte value */
	X
	X         returnval = ((localbuf<<4)&0xFF0) + ((inbuf>>4)&0x00F);
	X         inbuf &= 0x000F;              /* leave partial code pending */
	X    }
	X
	X    else                               /* buffer contains first nybble */
	X    {    if((localbuf=getc_unp(fd))==EOF)
	X              return EOF;
	X         localbuf &= 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 push(c)                         /* push char onto stack */
	Xint 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 pop()                       /* pop character from stack */
	X{
	X    if(sp>0)
	X         return ((int) stack[--sp]);   /* leave ptr at next empty slot */
	X
	X    else return EMPTY;
	X}
	X
	X/***** LEMPEL-ZEV DECOMPRESSION *****/
	X
	Xstatic int code_count;                 /* needed to detect table full */
	Xstatic unsigned code;                  /* where we are so far */
	Xstatic int firstc;                     /* true only on first character */
	X
	Xinit_ucr(new)                          /* get set for uncrunching */
	Xint new;                               /* true to use new hash function */
	X{
	X    if(new)                            /* set proper hash function */
	X         h = newh;
	X    else 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 getc_ucr(f)                        /* get next uncrunched byte */
	XFILE *f;                               /* file containing crunched data */
	X{
	X    unsigned int c;                    /* a character of input */
	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
	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
	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         /*   The above loop will terminate, one way or another,
	X              with string_tab[code].follower equal to the first
	X              character in the string.
	X         */
	X
	X         if(code_count)                /* if room left in string table */
	X         {    upd_tab(oldcode,finchar);
	X              --code_count;
	X         }
	X
	X         oldcode = newcode;
	X    }
	X
	X    return pop();                      /* return saved character */
	X}
SHAR_EOF
if test 27190 -ne "`wc -c < 'arclzw.c'`"
then
	echo shar: "error transmitting 'arclzw.c'" '(should have been 27190 characters)'
fi
fi
echo shar: "extracting 'arcmatch.c'" '(3092 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'
	Xstatic char *RCSid = "$Header: arcmatch.c,v 1.2 86/07/15 07:53:42 turner Exp $";
	X
	X/*
	X * $Log:	arcmatch.c,v $
	X * Revision 1.2  86/07/15  07:53:42  turner
	X * 
	X * 
	X * Revision 1.1  86/06/26  15:00:34  turner
	X * initial version
	X * 
	X * 
	X */
	X
	X/*  ARC - Archive utility - ARCMATCH
	X
	X$define(tag,$$segment(@1,$$index(@1,=)+1))#
	X$define(version,Version $tag(
	XTED_VERSION DB =2.17), created on $tag(
	XTED_DATE DB =12/17/85) at $tag(
	XTED_TIME DB =20:32:18))#
	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 service routines needed to maintain an archive.
	X
	X    Language:
	X         Computer Innovations Optimizing C86
	X*/
	X#include <stdio.h>
	X#include "arc.h"
	X
	Xint match(n,t)                         /* test name against template */
	Xchar *n;                               /* name to test */
	Xchar *t;                               /* template to test against */
	X{
	X
	X#if MSDOS
	X    upper(n); upper(t);                /* avoid case problems */
	X#endif
	X
	X    /* first match name part */
	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         }
	X         else                          /* match good for this char */
	X         {    n++;                     /* advance to next char */
	X              t++;
	X         }
	X    }
	X
	X    if(*n && *n=='.') n++;             /* skip extension delimiters */
	X    if(*t && *t=='.') 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 return 1;           /* else good enough */
	X         }
	X         else                          /* match good for this char */
	X         {    n++;                     /* advance to next char */
	X              t++;
	X         }
	X    }
	X
	X    return 1;                          /* match worked */
	X}
	X
	Xrempath(nargs,arg)                     /* remove paths from filenames */
	Xint nargs;                             /* number of names */
	Xchar *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 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 3092 -ne "`wc -c < 'arcmatch.c'`"
then
	echo shar: "error transmitting 'arcmatch.c'" '(should have been 3092 characters)'
fi
fi
echo shar: "extracting 'arcmisc.c'" '(1348 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#include <stdio.h>
	X#include "arc.h"
	X
	X/*	split up a file name (subroutine for makefnam)
	X*/
	X
	Xstatic _makefn(source,dest)
	Xunsigned char *source;
	Xunsigned char *dest;
	X{
	X int j;
	X
	X    setmem (dest, 17, 0);	/* clear result field */
	X    if (strlen (source) > 1 && source[1] == ':')
	X	for (j = 0; j < 2;)
	X	    dest[j++] = *source++;
	X    for (j = 3; *source && *source != '.'; ++source)
	X	if (j < 11)
	X	    dest[j++] = *source;
	X    for (j = 12; *source; ++source)
	X	if (j < 16)
	X	    dest[j++] = *source;
	X}
	X/*	make a file name using a template
	X*/
	X
	Xchar *makefnam(rawfn,template,result)
	Xunsigned char *rawfn;			/* the original file name */
	Xunsigned char *template;		/* the template data */
	Xunsigned char *result;			/* where to place the result */
	X{
	X  unsigned char et[17],er[17];
	X
	X  _makefn(template,et);
	X  _makefn(rawfn,er);
	X  *result=0;			/* assure no data */
	X  strcat(result,er[0]?er:et);
	X  strcat(result,er[3]?er+3:et+3);
	X  strcat(result,er[12]?er+12:et+12);
	X  return (&result[0]);
	X}
	X
	Xfreedir(dirs)
	Xregister struct direct **dirs;
	X{
	X	register int ii;
	X
	X	if(dirs == (struct direct **)0)
	X		return(-1);
	X	for(ii = 0; dirs[ii] != (struct direct *)0; ii++)
	X		free(dirs[ii]);
	X	free(dirs);
	X	return(0);
	X}
	X
	X#if MSDOS
	X#include <dir.h>
	X
	Xint alphasort(dirptr1, dirptr2)
	Xstruct direct **dirptr1, **dirptr2;
	X{
	X	return(strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
	X}
	X
	X#endif
SHAR_EOF
if test 1348 -ne "`wc -c < 'arcmisc.c'`"
then
	echo shar: "error transmitting 'arcmisc.c'" '(should have been 1348 characters)'
fi
fi
echo shar: "extracting 'arconvt.c'" '(4350 characters)'
if test -f 'arconvt.c'
then
	echo shar: "will not over-write existing file 'arconvt.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'arconvt.c'
	X#define BSD
	X#include <stdio.h>
	X#include "arc.h"
	X
	Xmain(argc,argv)
	Xint argc;
	Xchar *argv[];
	X{
	X    int i,j,k;
	X    FILE *infile,*outfile,*fopen();
	X    char *inbuf;
	X    struct heads inhdr,outhdr;
	X
	X    if(argc < 3) {
	X	fprintf(stderr,"Usage is: arconvt infile outfile\n");
	X	exit(1);
	X    }
	X
	X    infile = fopen(argv[1],"r");
	X    if(infile == NULL) {
	X	fprintf(stderr,"Cannot open input file '%s'\n",argv[0]);
	X	exit(1);
	X    }
	X
	X    outfile = fopen(argv[2],"w");
	X    if(outfile == NULL) {
	X	fprintf(stderr,"Cannot open output file '%s'\n",argv[1]);
	X	exit(1);
	X    }
	X
	X    inbuf = NULL;
	X
	X    while(readhdr(&inhdr,infile)) {
	X	strcpy(outhdr.name,inhdr.name);
	X	outhdr.size = inhdr.size;
	X	outhdr.date = inhdr.date;
	X	outhdr.time = inhdr.time;
	X	outhdr.crc  = inhdr.crc;
	X	outhdr.length = inhdr.length;
	X	writehdr(&outhdr,outfile);
	X	if(inbuf)
	X	    free(inbuf);
	X	inbuf=(char *)malloc(outhdr.size);
	X	fread(inbuf,sizeof(char),outhdr.size,infile);
	X	fwrite(inbuf,sizeof(char),outhdr.size,outfile);
	X    }
	X}
	Xwritehdr(hdr,f)                        /* write a header to an archive */
	Xstruct heads *hdr;                     /* header to write */
	XFILE *f;                               /* archive to write to */
	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    fwrite(hdr,sizeof(struct heads),1,f);
	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}
	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    char name[FNLEN];                 /* filename buffer */
	X    int try = 0;                       /* retry counter */
	X    static int first = 1;              /* true only on first read */
	X    char dummy[28];
	X    int i,j,k;
	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.",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 int),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	fread(dummy,27,1,f);
	X	for(i=0;i<13;hdr->name[i]=dummy[i],i++);
	X	hdr->size = (long)((dummy[16]<<24) + (dummy[15]<<16) + (dummy[14]<<8)
	X	    + dummy[13]);
	X	hdr->date = (unsigned short)((dummy[18]<<8) + dummy[17]);
	X	hdr->time = (unsigned short)((dummy[20]<<8) + dummy[19]);
	X	hdr->crc  = (short)((dummy[22]<<8) + dummy[21]);
	X	hdr->length = (long)((dummy[26]<<24) + (dummy[25]<<16)
	X	    + (dummy[24]<<8) + dummy[23]);
	X	}
	X
	X    first = 0; return 1;               /* we read something */
	X}
SHAR_EOF
if test 4350 -ne "`wc -c < 'arconvt.c'`"
then
	echo shar: "error transmitting 'arconvt.c'" '(should have been 4350 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
----
	"I ain't gay, but there are sure times when i wish i could say
		that i wasn't straight"

Name:	James M. Turner
Mail:	Imagen Corp. 2650 San Tomas Expressway, P.O. Box 58101
        Santa Clara, CA 95052-8101
AT&T:	(408) 986-9400
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner
CompuServe: 76327,1575
GEnie     : D-ARCANGEL



More information about the Comp.sources.unix mailing list