hyc@umix.cc.umich.edu (Howard Chu) (04/14/88)
XX } catreturn; XX XX char *i; XX int j, RETCODE; XX XX static int catptr = 0; XX static int catflag = 0x200; XX static int cattype = 1; XX static int patflag = 0; XX XX catreturn.maxlen = 256; XX XX if (patflag) { XX patflag = 0; XX catptr = 0; XX return (NULL); XX } XX if (filepattern) { XX strcpy(pattern.name, filepattern); XX pattern.len = strlen(filepattern); XX if (!index(filepattern, '?')) XX patflag = 1; XX } XX if (patflag) { XX fileinfo(&pattern, &cattype, "CINAME ", &catreturn, _retcode RETCODE); XX catptr = RETCODE ? 0 : 1; XX } else XX catscan(&pattern, &catflag, &cattype, &catreturn, &catptr); XX XX if (!catptr) XX return (NULL); XX else { XX char *k; XX XX k = index(catreturn.name, ' '); XX if (k) XX *k = 0; XX else { XX j = catreturn.actlen; XX catreturn.name[j] = 0; XX } XX k = catreturn.name; XX if (catreturn.name[0] == tmpchr[0]) XX k++; XX else if ((k = index(catreturn.name, sepchr[0]))) XX k++; XX else XX k = catreturn.name; XX j = strlen(k); XX i = malloc(++j); XX strcpy(i, k); XX return (i); XX } XX#else XX fortran gfinfo(); XX static char gfname[24]; XX static char pattern[20]; XX static int gfdummy[2] = { XX 0, 0 XX }, gfflags; XX int i, RETCODE; XX char *j, *k; XX XX if (filepattern) { XX strcpy(pattern, filepattern); XX strcat(pattern, " "); XX for (i = 20; i < 24; i++) XX gfname[i] = '\0'; XX if (index(pattern, '?')) XX gfflags = 0x0C; XX else XX gfflags = 0x09; XX } else if (gfflags == 0x09) XX return (NULL); XX XX gfinfo(pattern, gfname, &gfflags, gfdummy, gfdummy, gfdummy, _retcode RETCODE); XX if (RETCODE) XX return (NULL); XX else { XX k = index(gfname, ' '); XX *k = '\0'; XX k = gfname; XX if (gfname[0] == tmpchr[0]) XX k++; XX else if ((k = index(gfname, sepchr[0]))) XX k++; XX else XX k = gfname; XX i = strlen(k); XX j = malloc(++i); XX strcpy(j, k); XX return (j); XX } XX#endif XX} XX XXunlink(path) XX char *path; /* name of file to delete */ XX{ XX fortran destroy(); XX int RETCODE; XX XX char name[258]; XX XX strcpy(name, path); XX strcat(name, " "); XX destroy(name, _retcode RETCODE); XX if (RETCODE) XX return (-1); XX else XX return (0); XX} XX#endif SHAR_EOF if test 11060 -ne "`wc -c arcmisc.c`" then echo shar: error transmitting arcmisc.c '(should have been 11060 characters)' fi echo shar: extracting arcpack.c '(7219 characters)' sed 's/^XX//' << \SHAR_EOF > arcpack.c XX/* XX * $Log: arcpack.c,v $ XX * Revision 1.3 88/04/11 18:57:00 hyc XX * fixed a typo... XX * XX * Revision 1.2 88/04/11 18:38:15 hyc XX * added support for squashing, re-synch with MTS XX * XX * Revision 1.1 88/04/11 18:27:10 hyc XX * Initial revision XX * XX * Revision 1.1 87/12/19 04:05:16 hyc XX * Initial revision XX * XX * Revision 1.3 87/08/13 17:05:11 hyc XX * Run thru indent, fixed some signed vs. unsigned problems XX * with bp <-> buf, and inbuf and localbuf... XX * Revision 1.2 87/07/21 08:57:19 hyc *** empty XX * log message *** XX * XX */ XX XX/* XX * ARC - Archive utility - ARCPACK XX * XX * Version 3.46, created on 10/23/86 at 17:47:06 XX * XX * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED XX * XX * By: Thom Henderson XX * XX * Description: This file contains the routines used to compress a file when XX * placing it in an archive. XX * XX * Language: Computer Innovations Optimizing C86 XX */ XX#include <stdio.h> XX#include "arc.h" XX#ifdef MTS XX#include <ctype.h> XX#endif XX XX/* stuff for non-repeat packing */ XX XX#define DLE 0x90 /* repeat sequence marker */ XX XXstatic unsigned char state; /* current packing state */ XX XX/* non-repeat packing states */ XX XX#define NOHIST 0 /* don't consider previous input */ XX#define SENTCHAR 1 /* lastchar set, no lookahead yet */ XX#define SENDNEWC 2 /* run over, send new char next */ XX#define SENDCNT 3 /* newchar set, send count next */ XX XX/* packing results */ XX XXstatic LONG stdlen; /* length for standard packing */ XXstatic INT crcval; /* CRC check value */ XX XXINT XXpack(f, t, hdr) /* pack file into an archive */ XX FILE *f, *t; /* source, destination */ XX struct heads *hdr; /* pointer to header data */ XX{ XX INT c; /* one character of stream */ XX LONG ncrlen; /* length after packing */ XX LONG lzwlen; /* length after crunching */ XX LONG pred_cm(), sqpred_cm(); /* dynamic crunching cleanup */ XX LONG tloc, ftell(); /* start of output */ XX INT getch(); XX INT getc_ncr(); XX INT putc_pak(); XX XX /* first pass - see which method is best */ XX XX tloc = ftell(t); /* note start of output */ XX XX if (!nocomp) { /* if storage kludge not active */ XX if (note) { XX printf(" analyzing, "); XX fflush(stdout); XX } XX state = NOHIST; /* initialize ncr packing */ XX stdlen = ncrlen = 0; /* reset size counters */ XX crcval = 0; /* initialize CRC check value */ XX setcode(); /* initialize encryption */ XX XX if (dosquash) { XX sqinit_cm(f, t); XX while ((c = getch(f)) != EOF) { /* for each byte of file */ XX ncrlen++; /* one more packed byte */ XX sqputc_cm(c, t); /* see what squashing XX * can do */ XX } XX lzwlen = sqpred_cm(t); XX } else { XX init_cm(f, t); /* initialize for crunching */ XX XX while ((c = getc_ncr(f)) != EOF) { /* for each byte of file */ XX ncrlen++; /* one more packed byte */ XX putc_cm(c, t); /* see what crunching can do */ XX } XX lzwlen = pred_cm(t); /* finish up after crunching */ XX } XX } else { /* else kludge the method */ XX stdlen = 0; /* make standard look best */ XX ncrlen = lzwlen = 1; XX } XX XX /* standard set-ups common to all methods */ XX XX fseek(f, 0L, 0); /* rewind input */ XX hdr->crc = crcval; /* note CRC check value */ XX hdr->length = stdlen; /* set actual file length */ XX state = NOHIST; /* reinitialize ncr packing */ XX setcode(); /* reinitialize encryption */ XX XX /* choose and use the shortest method */ XX XX if (kludge && note) XX printf("\n\tS:%ld P:%ld C:%ld,\t ", stdlen, ncrlen, lzwlen); XX XX if (stdlen <= ncrlen && stdlen <= lzwlen) { XX if (note) { XX printf("storing, "); /* store without compression */ XX fflush(stdout); XX } XX hdrver = 2; /* note packing method */ XX fseek(t, tloc, 0); /* reset output for new method */ XX if (nocomp) { /* store only kludge skips things */ XX stdlen = crcval = 0; /* recalc these for kludge */ XX while ((c = getch(f)) != EOF) /* store it straight */ XX putc_pak(c, t); XX } else XX filecopy(f, t, stdlen); /* else use fast file copier */ XX hdr->crc = crcval; XX hdr->length = hdr->size = stdlen; XX } else if (ncrlen < lzwlen) { XX if (note) XX printf("packing, "); /* pack with repeat XX * suppression */ XX hdrver = 3; /* note packing method */ XX hdr->size = ncrlen; /* set data length */ XX fseek(t, tloc, 0); /* reset output for new method */ XX while ((c = getc_ncr(f)) != EOF) XX putc_pak(c, t); XX } else { XX if (note) XX printf(dosquash ? "squashed, " : "crunched, "); XX hdrver = dosquash ? 9 : 8; XX hdr->size = lzwlen; /* size should not change */ XX } XX XX /* standard cleanups common to all methods */ XX XX if (note) XX printf("done.\n"); XX} XX XX/* XX * Non-repeat compression - text is passed through normally, except that a XX * run of more than two is encoded as: XX * XX * <char> <DLE> <count> XX * XX * Special case: a count of zero indicates that the DLE is really a DLE, not a XX * repeat marker. XX */ XX XXINT XXgetc_ncr(f) /* get bytes with collapsed runs */ XX FILE *f; /* file to get from */ XX{ XX static INT lastc; /* value returned on last call */ XX static INT repcnt; /* repetition counter */ XX static INT c; /* latest value seen */ XX XX switch (state) { /* depends on our state */ XX case NOHIST: /* no relevant history */ XX state = SENTCHAR; XX return lastc = getch(f); /* remember the value next XX * time */ XX XX case SENTCHAR: /* char was sent. look ahead */ XX switch (lastc) {/* action depends on char */ XX case DLE: /* if we sent a real DLE */ XX state = NOHIST; /* then start over again */ XX return 0; /* but note that the DLE was real */ XX XX case EOF: /* EOF is always a special case */ XX return EOF; XX XX default: /* else test for a repeat */ XX for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++); XX /* find end of run */ XX XX switch (repcnt) { /* action depends on run size */ XX case 1:/* not a repeat */ XX return lastc = c; /* but remember value XX * next time */ XX XX case 2:/* a repeat, but too short */ XX state = SENDNEWC; /* send the second one XX * next time */ XX return lastc; XX XX default: /* a run - compress it */ XX state = SENDCNT; /* send repeat count XX * next time */ XX return DLE; /* send repeat marker this XX * time */ XX } XX } XX XX case SENDNEWC: /* send second char of short run */ XX state = SENTCHAR; XX return lastc = c; XX XX case SENDCNT: /* sent DLE, now send count */ XX state = SENDNEWC; XX return repcnt; XX XX default: XX abort("Bug - bad ncr state\n"); XX } XX} XX XXINT XXgetch(f) /* special get char for packing */ XX FILE *f; /* file to get from */ XX{ XX INT c; /* a char from the file */ XX#ifndef MSDOS XX static INT cr = 0; /* add \r before \n ? */ XX XX if (cr) { XX c = '\n'; XX#ifdef MTS XX c = toascii(c); XX#endif XX crcval = addcrc(crcval, c); XX stdlen++; XX cr = 0; XX return (c); XX } XX#endif XX XX if ((c = fgetc(f)) != EOF) { /* if not the end of file */ XX#ifndef MSDOS XX if (!image && (c == '\n')) { XX c = '\r'; XX cr = 1; XX } XX#endif XX#ifdef MTS XX if (!image) XX c = toascii(c); XX#endif XX crcval = addcrc(crcval, c); /* then update CRC check XX * value */ XX stdlen++; /* and bump length counter */ XX } XX return c; XX} XX XXINT XXputc_pak(c, f) /* put a packed byte into archive */ XX char c; /* byte to put */ XX FILE *f; /* archive to put it in */ XX{ XX putc_tst(code(c), f); /* put encoded byte, with checks */ XX} SHAR_EOF if test 7219 -ne "`wc -c arcpack.c`" then echo shar: error transmitting arcpack.c '(should have been 7219 characters)' fi echo shar: extracting arcrun.c '(3287 characters)' sed 's/^XX//' << \SHAR_EOF > arcrun.c XX/* XX * $Log: arcrun.c,v $ XX * Revision 1.3 87/08/13 17:05:51 hyc XX * Run thru indent, fixed some signed vs. unsigned problems XX * with bp <-> buf, and inbuf and localbuf... XX * Revision 1.2 87/07/21 09:08:37 hyc *** empty XX * log message *** XX * XX */ XX XX/* XX * ARC - Archive utility - ARCRUN XX * XX * Version 1.20, created on 03/24/86 at 19:34:31 XX * XX * (C) COPYRIGHT 1985,85 by System Enhancement Associates; ALL RIGHTS RESERVED XX * XX * By: Thom Henderson XX * XX * Description: This file contains the routines used to "run" a file which is XX * stored in an archive. At present, all we really do is (a) extract a XX * temporary file, (b) give its name as a system command, and then (c) delete XX * the file. XX * XX * Language: Computer Innovations Optimizing C86 XX */ XX#include <stdio.h> XX#include "arc.h" XX XXINT XXrunarc(num, arg) /* run file from archive */ XX INT num; /* number of arguments */ XX char *arg[]; /* pointers to arguments */ XX{ XX struct heads hdr; /* file header */ XX char *makefnam(); /* filename fixer */ XX char buf[100]; /* filename buffer */ XX FILE *fopen();/* file opener */ XX INT runfile(); XX XX rempath(num, arg); /* strip off paths */ XX XX openarc(0); /* open archive for reading */ XX XX if (num) { /* if files were named */ XX while (readhdr(&hdr, arc)) { /* while more files to check */ XX if (match(hdr.name, makefnam(arg[0], ".*", buf))) XX runfile(&hdr, num, &arg[1]); XX else XX fseek(arc, hdr.size, 1); XX } XX } else XX while (readhdr(&hdr, arc)) /* else run all files */ XX runfile(&hdr, 0, NULL); XX XX closearc(0); /* close archive after changes */ XX} XX XXstatic INT XXrunfile(hdr, num, arg) /* run a file */ XX struct heads *hdr; /* pointer to header data */ XX INT num; /* number of arguments */ XX char *arg[]; /* pointers to arguments */ XX{ XX FILE *tmp, *fopen(); /* temporary file */ XX char buf[100], *makefnam(); /* temp file name, fixer */ XX char sys[100]; /* invocation command buffer */ XX char *dir, *gcdir(); /* directory stuff */ XX INT n; /* index */ XX XX /* makefnam("$ARCTEMP",hdr->name,buf); */ XX sprintf(buf, "%s.RUN", arctemp); XX XX#ifdef MSDOS XX if (!strcmp(buf, "$ARCTEMP.BAS")) XX strcpy(sys, "BASICA $ARCTEMP"); XX XX else if (!strcmp(buf, "$ARCTEMP.BAT") XX || !strcmp(buf, "$ARCTEMP.COM") XX || !strcmp(buf, "$ARCTEMP.EXE")) XX strcpy(sys, "$ARCTEMP"); XX XX else { XX if (warn) { XX printf("File %s is not a .BAS, .BAT, .COM, or .EXE\n", XX hdr->name); XX nerrs++; XX } XX fseek(arc, hdr->size, 1); /* skip this file */ XX return; XX } XX#endif XX XX if (warn) XX if (tmp = fopen(buf, "r")) XX abort("Temporary file %s already exists", buf); XX if (!(tmp = fopen(buf, "w"))) XX abort("Unable to create temporary file %s", buf); XX XX if (note) XX printf("Invoking file: %s\n", hdr->name); XX XX for (n = 0; n < num; n++) { /* add command line arguments */ XX strcat(buf, " "); XX strcat(buf, arg[n]); XX } XX XX dir = gcdir(""); /* see where we are */ XX unpack(arc, tmp, hdr); /* unpack the entry */ XX fclose(tmp); /* release the file */ XX chmod(buf, "700"); /* make it executable */ XX system(buf); /* try to invoke it */ XX chdir(dir); XX free(dir); /* return to whence we started */ XX if (unlink(buf) && warn) { XX printf("Cannot unsave temporary file %s\n", buf); XX nerrs++; XX } XX} SHAR_EOF if test 3287 -ne "`wc -c arcrun.c`" then echo shar: error transmitting arcrun.c '(should have been 3287 characters)' fi echo shar: extracting arcs.h '(1832 characters)' sed 's/^XX//' << \SHAR_EOF > arcs.h XX/* XX * $Log: arcs.h,v $ XX * Revision 1.3 87/08/13 17:05:55 hyc XX * Run thru indent, fixed some signed vs. unsigned problems XX * with bp <-> buf, and inbuf and localbuf... XX * Revision 1.2 87/07/21 09:09:47 hyc *** empty XX * log message *** XX * XX */ XX XX/* XX * ARC - Archive utility - Archive file header format XX * XX * Version 2.12, created on 12/17/85 at 14:40:26 XX * XX * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED XX * XX * By: Thom Henderson XX * XX * Description: This file defines the format of an archive file header, XX * excluding the archive marker and the header version number. XX * XX * Each entry in an archive begins with a one byte archive marker, which is set XX * to 26. The marker is followed by a one byte header type code, from zero XX * to 7. XX * XX * If the header type code is zero, then it is an end marker, and no more data XX * should be read from the archive. XX * XX * If the header type code is in the range 2 to 7, then it is followed by a XX * standard archive header, which is defined below. XX * XX * If the header type code is one, then it is followed by an older format XX * archive header. The older format header does not contain the true length. XX * A header should be read for a length of sizeof(struct heads)-sizeof(long). XX * Then set length equal to size and change the header version to 2. XX * XX * Programming note: The crc value given in the header is based on the unpacked XX * data. XX * XX * Language: Computer Innovations Optimizing C86 XX */ XX XXstruct heads { /* archive entry header format */ XX char name[13]; /* file name */ XX LONG size; /* size of file, in bytes */ XX unsigned INT date; /* creation date */ XX unsigned INT time; /* creation time */ XX INT crc; /* cyclic redundancy check */ XX LONG length; /* true file length */ XX}; SHAR_EOF if test 1832 -ne "`wc -c arcs.h`" then echo shar: error transmitting arcs.h '(should have been 1832 characters)' fi echo shar: extracting arcsqs.c '(11224 characters)' sed 's/^XX//' << \SHAR_EOF > arcsqs.c XX/* ARC - Archive utility - SQUASH XX XX(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED XX XX This is a quick hack to ARCLZW to make it handle squashed archives. XX Dan Lanciani (ddl@harvard.*) July 87 XX XX*/ XX#include <stdio.h> XX#include "arc.h" XX XX/* definitions for the new dynamic Lempel-Zev crunching */ XX XX#define BITS 13 /* maximum bits per code */ XX#define HSIZE 10007 /* 80% occupancy */ XX#define INIT_BITS 9 /* initial number of bits/code */ XXstatic INT n_bits; /* number of bits/code */ XXstatic INT maxcode; /* maximum code, given n_bits */ XX#define MAXCODE(n) ((1<<(n)) - 1) /* maximum code calculation */ XXstatic INT maxcodemax = 1 << BITS; /* largest possible code (+1) */ XX XXstatic unsigned char buf[BITS]; /* input/output buffer */ XX XXstatic unsigned char lmask[9] = /* left side masks */ XX{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; XXstatic unsigned char rmask[9] = /* right side masks */ XX{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; XX XXstatic INT offset; /* byte offset for code output */ XXstatic long in_count; /* length of input */ XXstatic long bytes_out; /* length of compressed output */ XXstatic unsigned INT ent; XX XXstatic long htab[HSIZE]; /* hash code table (crunch) */ XXstatic unsigned INT codetab[HSIZE]; /* string code table (crunch) */ XX XXstatic unsigned INT *prefix = codetab; /* prefix code table (uncrunch) */ XX XXstatic unsigned char suffix[HSIZE]; /* suffix table (uncrunch) */ XXstatic INT free_ent; /* first unused entry */ XXstatic INT firstcmp; /* true at start of compression */ XXstatic unsigned char stack[HSIZE]; /* local push/pop stack */ XX XX/* XX * block compression parameters -- after all codes are used up, XX * and compression rate changes, start over. XX */ XX XXstatic INT clear_flg; XXstatic long ratio; XX#define CHECK_GAP 10000 /* ratio check interval */ XXstatic long checkpoint; XXstatic INT putcode(); XX XX/* XX * the next two codes should not be changed lightly, as they must not XX * lie within the contiguous general code space. XX */ XX#define FIRST 257 /* first free entry */ XX#define CLEAR 256 /* table clear output code */ XX XXstatic INT XXcl_block(t) /* table clear for block compress */ XX FILE *t; /* our output file */ XX{ XX long rat; XX XX checkpoint = in_count + CHECK_GAP; XX XX if (in_count > 0x007fffff) { /* shift will overflow */ XX rat = bytes_out >> 8; XX if (rat == 0) /* Don't divide by zero */ XX rat = 0x7fffffff; XX else XX rat = in_count / rat; XX } else XX rat = (in_count << 8) / bytes_out; /* 8 fractional bits */ XX XX if (rat > ratio) XX ratio = rat; XX else { XX ratio = 0; XX setmem(htab, HSIZE * sizeof(long), 0xff); XX free_ent = FIRST; XX clear_flg = 1; XX putcode(CLEAR, t); XX } XX} XX XX/***************************************************************** XX * XX * Output a given code. XX * Inputs: XX * code: A n_bits-bit integer. If == -1, then EOF. This assumes XX * that n_bits =< (long)wordsize - 1. XX * Outputs: XX * Outputs code to the file. XX * Assumptions: XX * Chars are 8 bits long. XX * Algorithm: XX * Maintain a BITS character long buffer (so that 8 codes will XX * fit in it exactly). When the buffer fills up empty it and start over. XX */ XX XXstatic INT XXputcode(code, t) /* output a code */ XX INT code; /* code to output */ XX FILE *t; /* where to put it */ XX{ XX INT r_off = offset; /* right offset */ XX INT bits = n_bits; /* bits to go */ XX unsigned char *bp = buf; /* buffer pointer */ XX INT n; /* index */ XX XX if (code >= 0) { /* if a real code *//* Get to the first byte. */ XX bp += (r_off >> 3); XX r_off &= 7; XX XX /* XX * Since code is always >= 8 bits, only need to mask the XX * first hunk on the left. XX */ XX *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off]; XX bp++; XX bits -= (8 - r_off); XX code >>= (8 - r_off); XX XX /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ XX if (bits >= 8) { XX *bp++ = code; XX code >>= 8; XX bits -= 8; XX } XX /* Last bits. */ XX if (bits) XX *bp = code; XX XX offset += n_bits; XX XX if (offset == (n_bits << 3)) { XX bp = buf; XX bits = n_bits; XX bytes_out += bits; XX do XX putc_pak(*bp++, t); XX while (--bits); XX offset = 0; XX } XX /* XX * If the next entry is going to be too big for the code XX * size, then increase it, if possible. XX */ XX if (free_ent > maxcode || clear_flg > 0) { /* Write the whole XX * buffer, because the XX * input side won't XX * discover the size XX * increase until after XX * it has read it. */ XX if (offset > 0) { XX bp = buf; /* reset pointer for writing */ XX bytes_out += n = n_bits; XX while (n--) XX putc_pak(*bp++, t); XX } XX offset = 0; XX XX if (clear_flg) { /* reset if clearing */ XX maxcode = MAXCODE(n_bits = INIT_BITS); XX clear_flg = 0; XX } else {/* else use more bits */ XX n_bits++; XX if (n_bits == BITS) XX maxcode = maxcodemax; XX else XX maxcode = MAXCODE(n_bits); XX } XX } XX } else { /* dump the buffer on EOF */ XX bytes_out += n = (offset + 7) / 8; XX XX if (offset > 0) XX while (n--) XX putc_pak(*bp++, t); XX offset = 0; XX } XX} XX XX/***************************************************************** XX * XX * Read one code from the standard input. If EOF, return -1. XX * Inputs: XX * cmpin XX * Outputs: XX * code or -1 is returned. XX */ XX XXstatic INT XXgetcode(f) /* get a code */ XX FILE *f; /* file to get from */ XX{ XX INT code; XX static INT offset = 0, size = 0; XX INT r_off, bits; XX unsigned char *bp = buf; XX XX if (clear_flg > 0 || offset >= size || free_ent > maxcode) { /* If the next entry XX * will be too big for XX * the current code XX * size, then we must XX * increase the size. XX * This implies reading XX * a new buffer full, XX * too. */ XX if (free_ent > maxcode) { XX n_bits++; XX if (n_bits == BITS) XX maxcode = maxcodemax; /* won't get any bigger XX * now */ XX else XX maxcode = MAXCODE(n_bits); XX } XX if (clear_flg > 0) { XX maxcode = MAXCODE(n_bits = INIT_BITS); XX clear_flg = 0; XX } XX for (size = 0; size < n_bits; size++) { XX if ((code = getc_unp(f)) == EOF) XX break; XX else XX buf[size] = code; XX } XX if (size <= 0) XX return -1; /* end of file */ XX XX offset = 0; XX /* Round size down to integral number of codes */ XX size = (size << 3) - (n_bits - 1); XX } XX r_off = offset; XX bits = n_bits; XX XX /* XX * Get to the first byte. XX */ XX bp += (r_off >> 3); XX r_off &= 7; XX XX /* Get first part (low order bits) */ XX code = (*bp++ >> r_off); XX bits -= 8 - r_off; XX r_off = 8 - r_off; /* now, offset into code word */ XX XX /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ XX if (bits >= 8) { XX code |= *bp++ << r_off; XX r_off += 8; XX bits -= 8; XX } XX /* high order bits. */ XX code |= (*bp & rmask[bits]) << r_off; XX offset += n_bits; XX XX return code; XX} XX XX/* XX * compress a file XX * XX * Algorithm: use open addressing double hashing (no chaining) on the XX * prefix code / next character combination. We do a variant of Knuth's XX * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime XX * secondary probe. Here, the modular division first probe is gives way XX * to a faster exclusive-or manipulation. Also do block compression with XX * an adaptive reset, where the code table is cleared when the compression XX * ratio decreases, but after the table fills. The variable-length output XX * codes are re-sized at this point, and a special CLEAR code is generated XX * for the decompressor. XX */ XX XXINT XXsqinit_cm(f, t) /* initialize for compression */ XX FILE *f; /* file we will be compressing */ XX FILE *t; /* where we will put it */ XX{ XX offset = 0; XX bytes_out = 0; XX clear_flg = 0; XX ratio = 0; XX in_count = 1; XX checkpoint = CHECK_GAP; XX maxcode = MAXCODE(n_bits = INIT_BITS); XX free_ent = FIRST; XX setmem(htab, HSIZE * sizeof(long), 0xff); XX n_bits = INIT_BITS; /* set starting code size */ XX XX firstcmp = 1; /* next byte will be first */ XX} XX XXINT XXsqputc_cm(c, t) /* compress a character */ XX unsigned char c; /* character to compress */ XX FILE *t; /* where to put it */ XX{ XX static long fcode; XX static INT hshift; XX INT i; XX INT disp; XX XX if (firstcmp) { /* special case for first byte */ XX ent = c; /* remember first byte */ XX XX hshift = 0; XX for (fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L) XX hshift++; XX hshift = 8 - hshift; /* set hash code range bund */ XX XX firstcmp = 0; /* no longer first */ XX return; XX } XX in_count++; XX fcode = (long) (((long) c << BITS) + ent); XX i = (c << hshift) ^ ent;/* xor hashing */ XX XX if (htab[i] == fcode) { XX ent = codetab[i]; XX return; XX } else if (htab[i] < 0) /* empty slot */ XX goto nomatch; XX disp = HSIZE - i; /* secondary hash (after G.Knott) */ XX if (i == 0) XX disp = 1; XX XXprobe: XX if ((i -= disp) < 0) XX i += HSIZE; XX XX if (htab[i] == fcode) { XX ent = codetab[i]; XX return; XX } XX if (htab[i] > 0) XX goto probe; XX XXnomatch: XX putcode(ent, t); XX ent = c; XX if (free_ent < maxcodemax) { XX codetab[i] = free_ent++; /* code -> hashtable */ XX htab[i] = fcode; XX } else if ((long) in_count >= checkpoint) XX cl_block(t); XX} XX XXlong XXsqpred_cm(t) /* finish compressing a file */ XX FILE *t; /* where to put it */ XX{ XX putcode(ent, t); /* put out the final code */ XX putcode(-1, t); /* tell output we are done */ XX XX return bytes_out; /* say how big it got */ XX} XX XX/* XX * Decompress a file. This routine adapts to the codes in the file XX * building the string table on-the-fly; requiring no table to be stored XX * in the compressed file. The tables used herein are shared with those of XX * the compress() routine. See the definitions above. XX */ XX XXINT XXsqdecomp(f, t) /* decompress a file */ XX FILE *f; /* file to read codes from */ XX FILE *t; /* file to write text to */ XX{ XX unsigned char *stackp; XX INT finchar; XX INT code, oldcode, incode; XX XX n_bits = INIT_BITS; /* set starting code size */ XX clear_flg = 0; XX XX /* XX * As above, initialize the first 256 entries in the table. XX */ XX maxcode = MAXCODE(n_bits = INIT_BITS); XX for (code = 255; code >= 0; code--) { XX prefix[code] = 0; XX suffix[code] = (unsigned char) code; XX } XX free_ent = FIRST; XX XX finchar = oldcode = getcode(f); XX if (oldcode == -1) /* EOF already? */ XX return; /* Get out of here */ XX putc_unp((char) finchar, t); /* first code must be 8 bits=char */ XX stackp = stack; XX XX while ((code = getcode(f)) > -1) { XX if (code == CLEAR) { XX for (code = 255; code >= 0; code--) XX prefix[code] = 0; XX clear_flg = 1; XX free_ent = FIRST - 1; XX if ((code = getcode(f)) == -1) /* O, untimely death! */ XX break; XX } XX incode = code; XX /* XX * Special case for KwKwK string. XX */ XX if (code >= free_ent) { XX *stackp++ = finchar; XX code = oldcode; XX } XX /*