182bf8890SDavid du Colombier /*
282bf8890SDavid du Colombier * compress - File compression ala IEEE Computer, June 1984.
382bf8890SDavid du Colombier *
482bf8890SDavid du Colombier * Algorithm from "A Technique for High Performance Data Compression",
582bf8890SDavid du Colombier * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
682bf8890SDavid du Colombier *
782bf8890SDavid du Colombier * Usage: compress [-dfvc] [-b bits] [file ...]
882bf8890SDavid du Colombier * Inputs:
982bf8890SDavid du Colombier * -b: limit the max number of bits/code.
1082bf8890SDavid du Colombier * -c: write output on stdout, don't remove original.
1182bf8890SDavid du Colombier * -d: decompress instead.
1282bf8890SDavid du Colombier * -f: Forces output file to be generated, even if one already
1382bf8890SDavid du Colombier * exists, and even if no space is saved by compressing.
1482bf8890SDavid du Colombier * If -f is not used, the user will be prompted if stdin is
1582bf8890SDavid du Colombier * a tty, otherwise, the output file will not be overwritten.
1682bf8890SDavid du Colombier * -v: Write compression statistics
1782bf8890SDavid du Colombier *
1882bf8890SDavid du Colombier * file ...: Files to be compressed. If none specified, stdin is used.
1982bf8890SDavid du Colombier * Outputs:
2082bf8890SDavid du Colombier * file.Z: Compressed form of file with same mode, owner, and utimes
2182bf8890SDavid du Colombier * or stdout (if stdin used as input)
2282bf8890SDavid du Colombier *
2382bf8890SDavid du Colombier * Assumptions:
2482bf8890SDavid du Colombier * When filenames are given, replaces with the compressed version
2582bf8890SDavid du Colombier * (.Z suffix) only if the file decreases in size.
2682bf8890SDavid du Colombier * Algorithm:
2782bf8890SDavid du Colombier * Modified Lempel-Ziv method (LZW). Basically finds common
2882bf8890SDavid du Colombier * substrings and replaces them with a variable size code. This is
2982bf8890SDavid du Colombier * deterministic, and can be done on the fly. Thus, the decompression
3082bf8890SDavid du Colombier * procedure needs no input table, but tracks the way the table was built.
3182bf8890SDavid du Colombier
3282bf8890SDavid du Colombier * Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
3382bf8890SDavid du Colombier * Jim McKie (decvax!mcvax!jim)
3482bf8890SDavid du Colombier * Steve Davies (decvax!vax135!petsd!peora!srd)
3582bf8890SDavid du Colombier * Ken Turkowski (decvax!decwrl!turtlevax!ken)
3682bf8890SDavid du Colombier * James A. Woods (decvax!ihnp4!ames!jaw)
3782bf8890SDavid du Colombier * Joe Orost (decvax!vax135!petsd!joe)
3882bf8890SDavid du Colombier */
3982bf8890SDavid du Colombier #define _PLAN9_SOURCE
40*14f51593SDavid du Colombier #define _BSD_EXTENSION
41*14f51593SDavid du Colombier #define _POSIX_SOURCE
4282bf8890SDavid du Colombier
4382bf8890SDavid du Colombier #include <u.h>
4482bf8890SDavid du Colombier #include <stdio.h>
4582bf8890SDavid du Colombier #include <ctype.h>
4682bf8890SDavid du Colombier #include <stdlib.h>
47*14f51593SDavid du Colombier #include <unistd.h>
4882bf8890SDavid du Colombier #include <string.h>
4982bf8890SDavid du Colombier #include <signal.h>
50*14f51593SDavid du Colombier #include <utime.h>
5182bf8890SDavid du Colombier #include <sys/types.h>
5282bf8890SDavid du Colombier #include <sys/stat.h>
5382bf8890SDavid du Colombier
5482bf8890SDavid du Colombier #define min(a,b) ((a>b) ? b : a)
5582bf8890SDavid du Colombier
5682bf8890SDavid du Colombier #define BITS 16
5782bf8890SDavid du Colombier #define HSIZE 69001 /* 95% occupancy */
5882bf8890SDavid du Colombier
5982bf8890SDavid du Colombier /*
6082bf8890SDavid du Colombier * a code_int must be able to hold 2**BITS values of type int, and also -1
6182bf8890SDavid du Colombier */
6282bf8890SDavid du Colombier typedef long code_int;
6382bf8890SDavid du Colombier typedef long count_int;
6482bf8890SDavid du Colombier
6582bf8890SDavid du Colombier static char rcs_ident[] = "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
6682bf8890SDavid du Colombier
6782bf8890SDavid du Colombier uchar magic_header[] = { 0x1F, 0x9D }; /* 1F 9D */
6882bf8890SDavid du Colombier
6982bf8890SDavid du Colombier /* Defines for third byte of header */
7082bf8890SDavid du Colombier #define BIT_MASK 0x1f
7182bf8890SDavid du Colombier #define BLOCK_MASK 0x80
7282bf8890SDavid du Colombier /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
7382bf8890SDavid du Colombier a fourth header byte (for expansion).
7482bf8890SDavid du Colombier */
7582bf8890SDavid du Colombier #define INIT_BITS 9 /* initial number of bits/code */
7682bf8890SDavid du Colombier
7782bf8890SDavid du Colombier #define ARGVAL() (*++(*argv) || (--argc && *++argv))
7882bf8890SDavid du Colombier
7982bf8890SDavid du Colombier int n_bits; /* number of bits/code */
8082bf8890SDavid du Colombier int maxbits = BITS; /* user settable max # bits/code */
8182bf8890SDavid du Colombier code_int maxcode; /* maximum code, given n_bits */
8282bf8890SDavid du Colombier code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */
8382bf8890SDavid du Colombier
8482bf8890SDavid du Colombier #define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
8582bf8890SDavid du Colombier
8682bf8890SDavid du Colombier count_int htab[HSIZE];
8782bf8890SDavid du Colombier ushort codetab[HSIZE];
8882bf8890SDavid du Colombier
8982bf8890SDavid du Colombier #define htabof(i) htab[i]
9082bf8890SDavid du Colombier #define codetabof(i) codetab[i]
9182bf8890SDavid du Colombier
9282bf8890SDavid du Colombier code_int hsize = HSIZE; /* for dynamic table sizing */
9382bf8890SDavid du Colombier count_int fsize;
9482bf8890SDavid du Colombier
9582bf8890SDavid du Colombier /*
9682bf8890SDavid du Colombier * To save much memory, we overlay the table used by compress() with those
9782bf8890SDavid du Colombier * used by decompress(). The tab_prefix table is the same size and type
9882bf8890SDavid du Colombier * as the codetab. The tab_suffix table needs 2**BITS characters. We
9982bf8890SDavid du Colombier * get this from the beginning of htab. The output stack uses the rest
10082bf8890SDavid du Colombier * of htab, and contains characters. There is plenty of room for any
10182bf8890SDavid du Colombier * possible stack (stack used to be 8000 characters).
10282bf8890SDavid du Colombier */
10382bf8890SDavid du Colombier
10482bf8890SDavid du Colombier #define tab_prefixof(i) codetabof(i)
10582bf8890SDavid du Colombier #define tab_suffixof(i) ((uchar *)(htab))[i]
10682bf8890SDavid du Colombier #define de_stack ((uchar *)&tab_suffixof(1<<BITS))
10782bf8890SDavid du Colombier
10882bf8890SDavid du Colombier code_int free_ent = 0; /* first unused entry */
10982bf8890SDavid du Colombier int exit_stat = 0;
11082bf8890SDavid du Colombier
111*14f51593SDavid du Colombier void cl_block(void);
112*14f51593SDavid du Colombier void cl_hash(count_int);
113*14f51593SDavid du Colombier void compress(void);
114*14f51593SDavid du Colombier void copystat(char *, char *);
115*14f51593SDavid du Colombier void decompress(void);
116*14f51593SDavid du Colombier int foreground(void);
117*14f51593SDavid du Colombier code_int getcode(void);
118*14f51593SDavid du Colombier void onintr(int);
119*14f51593SDavid du Colombier void oops(int);
120*14f51593SDavid du Colombier void output(code_int);
121*14f51593SDavid du Colombier void prratio(FILE *, long, long);
122*14f51593SDavid du Colombier void version(void);
123*14f51593SDavid du Colombier void writeerr(void);
12482bf8890SDavid du Colombier
125*14f51593SDavid du Colombier void
Usage(void)126*14f51593SDavid du Colombier Usage(void)
12782bf8890SDavid du Colombier {
12882bf8890SDavid du Colombier #ifdef DEBUG
12982bf8890SDavid du Colombier fprintf(stderr,"Usage: compress [-cdfDV] [-b maxbits] [file ...]\n");
13082bf8890SDavid du Colombier #else
13182bf8890SDavid du Colombier fprintf(stderr,"Usage: compress [-cdfvV] [-b maxbits] [file ...]\n");
13282bf8890SDavid du Colombier #endif /* DEBUG */
13382bf8890SDavid du Colombier }
13482bf8890SDavid du Colombier
13582bf8890SDavid du Colombier int debug = 0;
13682bf8890SDavid du Colombier int nomagic = 0; /* Use a 3-byte magic number header, unless old file */
13782bf8890SDavid du Colombier int zcat_flg = 0; /* Write output on stdout, suppress messages */
13882bf8890SDavid du Colombier int quiet = 1; /* don't tell me about compression */
13982bf8890SDavid du Colombier
14082bf8890SDavid du Colombier /*
14182bf8890SDavid du Colombier * block compression parameters -- after all codes are used up,
14282bf8890SDavid du Colombier * and compression rate changes, start over.
14382bf8890SDavid du Colombier */
14482bf8890SDavid du Colombier int block_compress = BLOCK_MASK;
14582bf8890SDavid du Colombier int clear_flg = 0;
14682bf8890SDavid du Colombier long ratio = 0;
14782bf8890SDavid du Colombier #define CHECK_GAP 10000 /* ratio check interval */
14882bf8890SDavid du Colombier count_int checkpoint = CHECK_GAP;
14982bf8890SDavid du Colombier /*
15082bf8890SDavid du Colombier * the next two codes should not be changed lightly, as they must not
15182bf8890SDavid du Colombier * lie within the contiguous general code space.
15282bf8890SDavid du Colombier */
15382bf8890SDavid du Colombier #define FIRST 257 /* first free entry */
15482bf8890SDavid du Colombier #define CLEAR 256 /* table clear output code */
15582bf8890SDavid du Colombier
15682bf8890SDavid du Colombier int force = 0;
15782bf8890SDavid du Colombier char ofname [100];
15882bf8890SDavid du Colombier #ifdef DEBUG
15982bf8890SDavid du Colombier int verbose = 0;
16082bf8890SDavid du Colombier #endif /* DEBUG */
16182bf8890SDavid du Colombier void (*bgnd_flag)(int);
16282bf8890SDavid du Colombier
16382bf8890SDavid du Colombier int do_decomp = 0;
16482bf8890SDavid du Colombier
main(argc,argv)16582bf8890SDavid du Colombier main(argc, argv)
16682bf8890SDavid du Colombier int argc;
16782bf8890SDavid du Colombier char **argv;
16882bf8890SDavid du Colombier {
16982bf8890SDavid du Colombier int overwrite = 0; /* Do not overwrite unless given -f flag */
17082bf8890SDavid du Colombier char tempname[512];
17182bf8890SDavid du Colombier char **filelist, **fileptr;
17282bf8890SDavid du Colombier char *cp;
17382bf8890SDavid du Colombier struct stat statbuf;
17482bf8890SDavid du Colombier
17582bf8890SDavid du Colombier if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
17682bf8890SDavid du Colombier signal(SIGINT, onintr);
17782bf8890SDavid du Colombier signal(SIGSEGV, oops);
17882bf8890SDavid du Colombier }
17982bf8890SDavid du Colombier
18082bf8890SDavid du Colombier filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
18182bf8890SDavid du Colombier *filelist = NULL;
18282bf8890SDavid du Colombier
18382bf8890SDavid du Colombier if((cp = strrchr(argv[0], '/')) != 0)
18482bf8890SDavid du Colombier cp++;
18582bf8890SDavid du Colombier else
18682bf8890SDavid du Colombier cp = argv[0];
18782bf8890SDavid du Colombier if(strcmp(cp, "uncompress") == 0)
18882bf8890SDavid du Colombier do_decomp = 1;
18982bf8890SDavid du Colombier else if(strcmp(cp, "zcat") == 0) {
19082bf8890SDavid du Colombier do_decomp = 1;
19182bf8890SDavid du Colombier zcat_flg = 1;
19282bf8890SDavid du Colombier }
19382bf8890SDavid du Colombier
19482bf8890SDavid du Colombier /*
19582bf8890SDavid du Colombier * Argument Processing
19682bf8890SDavid du Colombier * All flags are optional.
19782bf8890SDavid du Colombier * -C generate output compatible with compress 2.0.
19882bf8890SDavid du Colombier * -D debug
19982bf8890SDavid du Colombier * -V print Version; debug verbose
20082bf8890SDavid du Colombier * -b maxbits maxbits. If -b is specified, then maxbits MUST be
20182bf8890SDavid du Colombier * given also.
20282bf8890SDavid du Colombier * -c cat all output to stdout
20382bf8890SDavid du Colombier * -d do_decomp
20482bf8890SDavid du Colombier * -f force overwrite of output file
20582bf8890SDavid du Colombier * -n no header: useful to uncompress old files
20682bf8890SDavid du Colombier * -v unquiet
20782bf8890SDavid du Colombier * if a string is left, must be an input filename.
20882bf8890SDavid du Colombier */
20982bf8890SDavid du Colombier for (argc--, argv++; argc > 0; argc--, argv++) {
21082bf8890SDavid du Colombier if (**argv == '-') { /* A flag argument */
21182bf8890SDavid du Colombier while (*++(*argv)) { /* Process all flags in this arg */
21282bf8890SDavid du Colombier switch (**argv) {
21382bf8890SDavid du Colombier case 'C':
21482bf8890SDavid du Colombier block_compress = 0;
21582bf8890SDavid du Colombier break;
21682bf8890SDavid du Colombier #ifdef DEBUG
21782bf8890SDavid du Colombier case 'D':
21882bf8890SDavid du Colombier debug = 1;
21982bf8890SDavid du Colombier break;
22082bf8890SDavid du Colombier case 'V':
22182bf8890SDavid du Colombier verbose = 1;
22282bf8890SDavid du Colombier version();
22382bf8890SDavid du Colombier break;
22482bf8890SDavid du Colombier #else
22582bf8890SDavid du Colombier case 'V':
22682bf8890SDavid du Colombier version();
22782bf8890SDavid du Colombier break;
22882bf8890SDavid du Colombier #endif
22982bf8890SDavid du Colombier case 'b':
23082bf8890SDavid du Colombier if (!ARGVAL()) {
23182bf8890SDavid du Colombier fprintf(stderr, "Missing maxbits\n");
23282bf8890SDavid du Colombier Usage();
23382bf8890SDavid du Colombier exit(1);
23482bf8890SDavid du Colombier }
23582bf8890SDavid du Colombier maxbits = atoi(*argv);
23682bf8890SDavid du Colombier goto nextarg;
23782bf8890SDavid du Colombier case 'c':
23882bf8890SDavid du Colombier zcat_flg = 1;
23982bf8890SDavid du Colombier break;
24082bf8890SDavid du Colombier case 'd':
24182bf8890SDavid du Colombier do_decomp = 1;
24282bf8890SDavid du Colombier break;
24382bf8890SDavid du Colombier case 'f':
24482bf8890SDavid du Colombier case 'F':
24582bf8890SDavid du Colombier overwrite = 1;
24682bf8890SDavid du Colombier force = 1;
24782bf8890SDavid du Colombier break;
24882bf8890SDavid du Colombier case 'n':
24982bf8890SDavid du Colombier nomagic = 1;
25082bf8890SDavid du Colombier break;
25182bf8890SDavid du Colombier case 'q':
25282bf8890SDavid du Colombier quiet = 1;
25382bf8890SDavid du Colombier break;
25482bf8890SDavid du Colombier case 'v':
25582bf8890SDavid du Colombier quiet = 0;
25682bf8890SDavid du Colombier break;
25782bf8890SDavid du Colombier default:
25882bf8890SDavid du Colombier fprintf(stderr, "Unknown flag: '%c'; ", **argv);
25982bf8890SDavid du Colombier Usage();
26082bf8890SDavid du Colombier exit(1);
26182bf8890SDavid du Colombier }
26282bf8890SDavid du Colombier }
26382bf8890SDavid du Colombier } else { /* Input file name */
26482bf8890SDavid du Colombier *fileptr++ = *argv; /* Build input file list */
26582bf8890SDavid du Colombier *fileptr = NULL;
26682bf8890SDavid du Colombier /* process nextarg; */
26782bf8890SDavid du Colombier }
26882bf8890SDavid du Colombier nextarg:
26982bf8890SDavid du Colombier continue;
27082bf8890SDavid du Colombier }
27182bf8890SDavid du Colombier
27282bf8890SDavid du Colombier if(maxbits < INIT_BITS) maxbits = INIT_BITS;
27382bf8890SDavid du Colombier if (maxbits > BITS) maxbits = BITS;
27482bf8890SDavid du Colombier maxmaxcode = 1 << maxbits;
27582bf8890SDavid du Colombier
27682bf8890SDavid du Colombier if (*filelist != NULL) {
27782bf8890SDavid du Colombier for (fileptr = filelist; *fileptr; fileptr++) {
27882bf8890SDavid du Colombier exit_stat = 0;
27982bf8890SDavid du Colombier if (do_decomp != 0) { /* DECOMPRESSION */
28082bf8890SDavid du Colombier /* Check for .Z suffix */
28182bf8890SDavid du Colombier if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
28282bf8890SDavid du Colombier /* No .Z: tack one on */
28382bf8890SDavid du Colombier strcpy(tempname, *fileptr);
28482bf8890SDavid du Colombier strcat(tempname, ".Z");
28582bf8890SDavid du Colombier *fileptr = tempname;
28682bf8890SDavid du Colombier }
28782bf8890SDavid du Colombier /* Open input file */
28882bf8890SDavid du Colombier if ((freopen(*fileptr, "r", stdin)) == NULL) {
28982bf8890SDavid du Colombier perror(*fileptr);
29082bf8890SDavid du Colombier continue;
29182bf8890SDavid du Colombier }
29282bf8890SDavid du Colombier /* Check the magic number */
29382bf8890SDavid du Colombier if (nomagic == 0) {
29482bf8890SDavid du Colombier if ((getchar() != (magic_header[0] & 0xFF))
29582bf8890SDavid du Colombier || (getchar() != (magic_header[1] & 0xFF))) {
29682bf8890SDavid du Colombier fprintf(stderr, "%s: not in compressed format\n",
29782bf8890SDavid du Colombier *fileptr);
29882bf8890SDavid du Colombier continue;
29982bf8890SDavid du Colombier }
30082bf8890SDavid du Colombier maxbits = getchar(); /* set -b from file */
30182bf8890SDavid du Colombier block_compress = maxbits & BLOCK_MASK;
30282bf8890SDavid du Colombier maxbits &= BIT_MASK;
30382bf8890SDavid du Colombier maxmaxcode = 1 << maxbits;
30482bf8890SDavid du Colombier if(maxbits > BITS) {
30582bf8890SDavid du Colombier fprintf(stderr,
30682bf8890SDavid du Colombier "%s: compressed with %d bits, can only handle %d bits\n",
30782bf8890SDavid du Colombier *fileptr, maxbits, BITS);
30882bf8890SDavid du Colombier continue;
30982bf8890SDavid du Colombier }
31082bf8890SDavid du Colombier }
31182bf8890SDavid du Colombier /* Generate output filename */
31282bf8890SDavid du Colombier strcpy(ofname, *fileptr);
31382bf8890SDavid du Colombier ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
31482bf8890SDavid du Colombier } else { /* COMPRESSION */
31582bf8890SDavid du Colombier if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
31682bf8890SDavid du Colombier fprintf(stderr,
31782bf8890SDavid du Colombier "%s: already has .Z suffix -- no change\n",
31882bf8890SDavid du Colombier *fileptr);
31982bf8890SDavid du Colombier continue;
32082bf8890SDavid du Colombier }
32182bf8890SDavid du Colombier /* Open input file */
32282bf8890SDavid du Colombier if ((freopen(*fileptr, "r", stdin)) == NULL) {
32382bf8890SDavid du Colombier perror(*fileptr);
32482bf8890SDavid du Colombier continue;
32582bf8890SDavid du Colombier }
32682bf8890SDavid du Colombier (void) stat(*fileptr, &statbuf);
32782bf8890SDavid du Colombier fsize = (long) statbuf.st_size;
32882bf8890SDavid du Colombier /*
32982bf8890SDavid du Colombier * tune hash table size for small files -- ad hoc,
33082bf8890SDavid du Colombier * but the sizes match earlier #defines, which
33182bf8890SDavid du Colombier * serve as upper bounds on the number of output codes.
33282bf8890SDavid du Colombier */
33382bf8890SDavid du Colombier hsize = HSIZE;
33482bf8890SDavid du Colombier if (fsize < (1 << 12))
33582bf8890SDavid du Colombier hsize = min(5003, HSIZE);
33682bf8890SDavid du Colombier else if (fsize < (1 << 13))
33782bf8890SDavid du Colombier hsize = min(9001, HSIZE);
33882bf8890SDavid du Colombier else if (fsize < (1 << 14))
33982bf8890SDavid du Colombier hsize = min (18013, HSIZE);
34082bf8890SDavid du Colombier else if (fsize < (1 << 15))
34182bf8890SDavid du Colombier hsize = min (35023, HSIZE);
34282bf8890SDavid du Colombier else if (fsize < 47000)
34382bf8890SDavid du Colombier hsize = min (50021, HSIZE);
34482bf8890SDavid du Colombier
34582bf8890SDavid du Colombier /* Generate output filename */
34682bf8890SDavid du Colombier strcpy(ofname, *fileptr);
34782bf8890SDavid du Colombier #ifndef BSD4_2
34882bf8890SDavid du Colombier if ((cp=strrchr(ofname,'/')) != NULL)
34982bf8890SDavid du Colombier cp++;
35082bf8890SDavid du Colombier else
35182bf8890SDavid du Colombier cp = ofname;
35282bf8890SDavid du Colombier /*
35382bf8890SDavid du Colombier *** changed 12 to 25; should be NAMELEN-3, but I don't want
35482bf8890SDavid du Colombier * to fight the headers. ehg 5 Nov 92 **
35582bf8890SDavid du Colombier */
35682bf8890SDavid du Colombier if (strlen(cp) > 25) {
35782bf8890SDavid du Colombier fprintf(stderr, "%s: filename too long to tack on .Z\n",
35882bf8890SDavid du Colombier cp);
35982bf8890SDavid du Colombier continue;
36082bf8890SDavid du Colombier }
36182bf8890SDavid du Colombier #endif
36282bf8890SDavid du Colombier strcat(ofname, ".Z");
36382bf8890SDavid du Colombier }
36482bf8890SDavid du Colombier /* Check for overwrite of existing file */
36582bf8890SDavid du Colombier if (overwrite == 0 && zcat_flg == 0 &&
36682bf8890SDavid du Colombier stat(ofname, &statbuf) == 0) {
36782bf8890SDavid du Colombier char response[2];
36882bf8890SDavid du Colombier
36982bf8890SDavid du Colombier response[0] = 'n';
37082bf8890SDavid du Colombier fprintf(stderr, "%s already exists;", ofname);
37182bf8890SDavid du Colombier if (foreground()) {
37282bf8890SDavid du Colombier fprintf(stderr,
37382bf8890SDavid du Colombier " do you wish to overwrite %s (y or n)? ",
37482bf8890SDavid du Colombier ofname);
37582bf8890SDavid du Colombier fflush(stderr);
37682bf8890SDavid du Colombier (void) read(2, response, 2);
37782bf8890SDavid du Colombier while (response[1] != '\n')
37882bf8890SDavid du Colombier if (read(2, response+1, 1) < 0) {
37982bf8890SDavid du Colombier /* Ack! */
38082bf8890SDavid du Colombier perror("stderr");
38182bf8890SDavid du Colombier break;
38282bf8890SDavid du Colombier }
38382bf8890SDavid du Colombier }
38482bf8890SDavid du Colombier if (response[0] != 'y') {
38582bf8890SDavid du Colombier fprintf(stderr, "\tnot overwritten\n");
38682bf8890SDavid du Colombier continue;
38782bf8890SDavid du Colombier }
38882bf8890SDavid du Colombier }
38982bf8890SDavid du Colombier if(zcat_flg == 0) { /* Open output file */
39082bf8890SDavid du Colombier if (freopen(ofname, "w", stdout) == NULL) {
39182bf8890SDavid du Colombier perror(ofname);
39282bf8890SDavid du Colombier continue;
39382bf8890SDavid du Colombier }
39482bf8890SDavid du Colombier if(!quiet)
39582bf8890SDavid du Colombier fprintf(stderr, "%s: ", *fileptr);
39682bf8890SDavid du Colombier }
39782bf8890SDavid du Colombier
39882bf8890SDavid du Colombier /* Actually do the compression/decompression */
39982bf8890SDavid du Colombier if (do_decomp == 0)
40082bf8890SDavid du Colombier compress();
40182bf8890SDavid du Colombier #ifndef DEBUG
40282bf8890SDavid du Colombier else
40382bf8890SDavid du Colombier decompress();
40482bf8890SDavid du Colombier #else
40582bf8890SDavid du Colombier else if (debug == 0)
40682bf8890SDavid du Colombier decompress();
40782bf8890SDavid du Colombier else
40882bf8890SDavid du Colombier printcodes();
40982bf8890SDavid du Colombier if (verbose)
41082bf8890SDavid du Colombier dump_tab();
41182bf8890SDavid du Colombier #endif /* DEBUG */
41282bf8890SDavid du Colombier if(zcat_flg == 0) {
41382bf8890SDavid du Colombier copystat(*fileptr, ofname); /* Copy stats */
41482bf8890SDavid du Colombier if (exit_stat == 1 || !quiet)
41582bf8890SDavid du Colombier putc('\n', stderr);
41682bf8890SDavid du Colombier }
41782bf8890SDavid du Colombier }
41882bf8890SDavid du Colombier } else { /* Standard input */
41982bf8890SDavid du Colombier if (do_decomp == 0) {
42082bf8890SDavid du Colombier compress();
42182bf8890SDavid du Colombier #ifdef DEBUG
42282bf8890SDavid du Colombier if(verbose)
42382bf8890SDavid du Colombier dump_tab();
42482bf8890SDavid du Colombier #endif
42582bf8890SDavid du Colombier if(!quiet)
42682bf8890SDavid du Colombier putc('\n', stderr);
42782bf8890SDavid du Colombier } else {
42882bf8890SDavid du Colombier /* Check the magic number */
42982bf8890SDavid du Colombier if (nomagic == 0) {
43082bf8890SDavid du Colombier if ((getchar()!=(magic_header[0] & 0xFF))
43182bf8890SDavid du Colombier || (getchar()!=(magic_header[1] & 0xFF))) {
43282bf8890SDavid du Colombier fprintf(stderr, "stdin: not in compressed format\n");
43382bf8890SDavid du Colombier exit(1);
43482bf8890SDavid du Colombier }
43582bf8890SDavid du Colombier maxbits = getchar(); /* set -b from file */
43682bf8890SDavid du Colombier block_compress = maxbits & BLOCK_MASK;
43782bf8890SDavid du Colombier maxbits &= BIT_MASK;
43882bf8890SDavid du Colombier maxmaxcode = 1 << maxbits;
43982bf8890SDavid du Colombier fsize = 100000; /* assume stdin large for USERMEM */
44082bf8890SDavid du Colombier if(maxbits > BITS) {
44182bf8890SDavid du Colombier fprintf(stderr,
44282bf8890SDavid du Colombier "stdin: compressed with %d bits, can only handle %d bits\n",
44382bf8890SDavid du Colombier maxbits, BITS);
44482bf8890SDavid du Colombier exit(1);
44582bf8890SDavid du Colombier }
44682bf8890SDavid du Colombier }
44782bf8890SDavid du Colombier #ifndef DEBUG
44882bf8890SDavid du Colombier decompress();
44982bf8890SDavid du Colombier #else
45082bf8890SDavid du Colombier if (debug == 0)
45182bf8890SDavid du Colombier decompress();
45282bf8890SDavid du Colombier else
45382bf8890SDavid du Colombier printcodes();
45482bf8890SDavid du Colombier if (verbose)
45582bf8890SDavid du Colombier dump_tab();
45682bf8890SDavid du Colombier #endif /* DEBUG */
45782bf8890SDavid du Colombier }
45882bf8890SDavid du Colombier }
45982bf8890SDavid du Colombier exit(exit_stat);
460*14f51593SDavid du Colombier return 0;
46182bf8890SDavid du Colombier }
46282bf8890SDavid du Colombier
46382bf8890SDavid du Colombier static int offset;
46482bf8890SDavid du Colombier long in_count = 1; /* length of input */
46582bf8890SDavid du Colombier long bytes_out; /* length of compressed output */
46682bf8890SDavid du Colombier long out_count = 0; /* # of codes output (for debugging) */
46782bf8890SDavid du Colombier
46882bf8890SDavid du Colombier /*
46982bf8890SDavid du Colombier * compress stdin to stdout
47082bf8890SDavid du Colombier *
47182bf8890SDavid du Colombier * Algorithm: use open addressing double hashing (no chaining) on the
47282bf8890SDavid du Colombier * prefix code / next character combination. We do a variant of Knuth's
47382bf8890SDavid du Colombier * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
47482bf8890SDavid du Colombier * secondary probe. Here, the modular division first probe is gives way
47582bf8890SDavid du Colombier * to a faster exclusive-or manipulation. Also do block compression with
47682bf8890SDavid du Colombier * an adaptive reset, whereby the code table is cleared when the compression
47782bf8890SDavid du Colombier * ratio decreases, but after the table fills. The variable-length output
47882bf8890SDavid du Colombier * codes are re-sized at this point, and a special CLEAR code is generated
47982bf8890SDavid du Colombier * for the decompressor. Late addition: construct the table according to
48082bf8890SDavid du Colombier * file size for noticeable speed improvement on small files. Please direct
48182bf8890SDavid du Colombier * questions about this implementation to ames!jaw.
48282bf8890SDavid du Colombier */
483*14f51593SDavid du Colombier void
compress(void)484*14f51593SDavid du Colombier compress(void)
48582bf8890SDavid du Colombier {
48682bf8890SDavid du Colombier code_int ent, hsize_reg;
487*14f51593SDavid du Colombier code_int i;
48882bf8890SDavid du Colombier int c, disp, hshift;
48982bf8890SDavid du Colombier long fcode;
49082bf8890SDavid du Colombier
49182bf8890SDavid du Colombier if (nomagic == 0) {
49282bf8890SDavid du Colombier putchar(magic_header[0]);
49382bf8890SDavid du Colombier putchar(magic_header[1]);
49482bf8890SDavid du Colombier putchar((char)(maxbits | block_compress));
49582bf8890SDavid du Colombier if(ferror(stdout))
49682bf8890SDavid du Colombier writeerr();
49782bf8890SDavid du Colombier }
49882bf8890SDavid du Colombier offset = 0;
49982bf8890SDavid du Colombier bytes_out = 3; /* includes 3-byte header mojo */
50082bf8890SDavid du Colombier out_count = 0;
50182bf8890SDavid du Colombier clear_flg = 0;
50282bf8890SDavid du Colombier ratio = 0;
50382bf8890SDavid du Colombier in_count = 1;
50482bf8890SDavid du Colombier checkpoint = CHECK_GAP;
50582bf8890SDavid du Colombier maxcode = MAXCODE(n_bits = INIT_BITS);
50682bf8890SDavid du Colombier free_ent = (block_compress? FIRST: 256);
50782bf8890SDavid du Colombier
50882bf8890SDavid du Colombier ent = getchar ();
50982bf8890SDavid du Colombier
51082bf8890SDavid du Colombier hshift = 0;
51182bf8890SDavid du Colombier for (fcode = (long)hsize; fcode < 65536L; fcode *= 2)
51282bf8890SDavid du Colombier hshift++;
51382bf8890SDavid du Colombier hshift = 8 - hshift; /* set hash code range bound */
51482bf8890SDavid du Colombier
51582bf8890SDavid du Colombier hsize_reg = hsize;
51682bf8890SDavid du Colombier cl_hash( (count_int) hsize_reg); /* clear hash table */
51782bf8890SDavid du Colombier
51882bf8890SDavid du Colombier while ((c = getchar()) != EOF) {
51982bf8890SDavid du Colombier in_count++;
52082bf8890SDavid du Colombier fcode = (long) (((long) c << maxbits) + ent);
52182bf8890SDavid du Colombier i = ((c << hshift) ^ ent); /* xor hashing */
52282bf8890SDavid du Colombier
52382bf8890SDavid du Colombier if (htabof (i) == fcode) {
52482bf8890SDavid du Colombier ent = codetabof(i);
52582bf8890SDavid du Colombier continue;
52682bf8890SDavid du Colombier } else if ((long)htabof(i) < 0 ) /* empty slot */
52782bf8890SDavid du Colombier goto nomatch;
52882bf8890SDavid du Colombier disp = hsize_reg - i; /* secondary hash (after G. Knott) */
52982bf8890SDavid du Colombier if (i == 0)
53082bf8890SDavid du Colombier disp = 1;
53182bf8890SDavid du Colombier probe:
53282bf8890SDavid du Colombier if ((i -= disp) < 0)
53382bf8890SDavid du Colombier i += hsize_reg;
53482bf8890SDavid du Colombier
53582bf8890SDavid du Colombier if (htabof (i) == fcode) {
53682bf8890SDavid du Colombier ent = codetabof(i);
53782bf8890SDavid du Colombier continue;
53882bf8890SDavid du Colombier }
53982bf8890SDavid du Colombier if ((long)htabof(i) > 0)
54082bf8890SDavid du Colombier goto probe;
54182bf8890SDavid du Colombier nomatch:
54282bf8890SDavid du Colombier output((code_int)ent);
54382bf8890SDavid du Colombier out_count++;
54482bf8890SDavid du Colombier ent = c;
54582bf8890SDavid du Colombier if (free_ent < maxmaxcode) {
54682bf8890SDavid du Colombier codetabof(i) = free_ent++; /* code -> hashtable */
54782bf8890SDavid du Colombier htabof(i) = fcode;
54882bf8890SDavid du Colombier } else if ((count_int)in_count >= checkpoint && block_compress)
54982bf8890SDavid du Colombier cl_block ();
55082bf8890SDavid du Colombier }
55182bf8890SDavid du Colombier /*
55282bf8890SDavid du Colombier * Put out the final code.
55382bf8890SDavid du Colombier */
55482bf8890SDavid du Colombier output( (code_int)ent );
55582bf8890SDavid du Colombier out_count++;
55682bf8890SDavid du Colombier output( (code_int)-1 );
55782bf8890SDavid du Colombier
55882bf8890SDavid du Colombier /*
55982bf8890SDavid du Colombier * Print out stats on stderr
56082bf8890SDavid du Colombier */
56182bf8890SDavid du Colombier if(zcat_flg == 0 && !quiet) {
56282bf8890SDavid du Colombier #ifdef DEBUG
56382bf8890SDavid du Colombier fprintf( stderr,
56482bf8890SDavid du Colombier "%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
56582bf8890SDavid du Colombier in_count, out_count, bytes_out );
56682bf8890SDavid du Colombier prratio( stderr, in_count, bytes_out );
56782bf8890SDavid du Colombier fprintf( stderr, "\n");
56882bf8890SDavid du Colombier fprintf( stderr, "\tCompression as in compact: " );
56982bf8890SDavid du Colombier prratio( stderr, in_count-bytes_out, in_count );
57082bf8890SDavid du Colombier fprintf( stderr, "\n");
57182bf8890SDavid du Colombier fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
57282bf8890SDavid du Colombier free_ent - 1, n_bits );
57382bf8890SDavid du Colombier #else /* !DEBUG */
57482bf8890SDavid du Colombier fprintf( stderr, "Compression: " );
57582bf8890SDavid du Colombier prratio( stderr, in_count-bytes_out, in_count );
57682bf8890SDavid du Colombier #endif /* DEBUG */
57782bf8890SDavid du Colombier }
57882bf8890SDavid du Colombier if(bytes_out > in_count) /* exit(2) if no savings */
57982bf8890SDavid du Colombier exit_stat = 2;
58082bf8890SDavid du Colombier }
58182bf8890SDavid du Colombier
58282bf8890SDavid du Colombier /*
58382bf8890SDavid du Colombier * TAG( output )
58482bf8890SDavid du Colombier *
58582bf8890SDavid du Colombier * Output the given code.
58682bf8890SDavid du Colombier * Inputs:
58782bf8890SDavid du Colombier * code: A n_bits-bit integer. If == -1, then EOF. This assumes
58882bf8890SDavid du Colombier * that n_bits =< (long)wordsize - 1.
58982bf8890SDavid du Colombier * Outputs:
59082bf8890SDavid du Colombier * Outputs code to the file.
59182bf8890SDavid du Colombier * Assumptions:
59282bf8890SDavid du Colombier * Chars are 8 bits long.
59382bf8890SDavid du Colombier * Algorithm:
59482bf8890SDavid du Colombier * Maintain a BITS character long buffer (so that 8 codes will
59582bf8890SDavid du Colombier * fit in it exactly). When the buffer fills up empty it and start over.
59682bf8890SDavid du Colombier */
59782bf8890SDavid du Colombier
59882bf8890SDavid du Colombier static char buf[BITS];
59982bf8890SDavid du Colombier
60082bf8890SDavid du Colombier uchar lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
60182bf8890SDavid du Colombier uchar rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
60282bf8890SDavid du Colombier
603*14f51593SDavid du Colombier void
output(code)60482bf8890SDavid du Colombier output( code )
60582bf8890SDavid du Colombier code_int code;
60682bf8890SDavid du Colombier {
60782bf8890SDavid du Colombier #ifdef DEBUG
60882bf8890SDavid du Colombier static int col = 0;
60982bf8890SDavid du Colombier #endif
61082bf8890SDavid du Colombier int r_off = offset, bits= n_bits;
61182bf8890SDavid du Colombier char *bp = buf;
61282bf8890SDavid du Colombier
61382bf8890SDavid du Colombier #ifdef DEBUG
61482bf8890SDavid du Colombier if (verbose)
61582bf8890SDavid du Colombier fprintf(stderr, "%5d%c", code,
61682bf8890SDavid du Colombier (col+=6) >= 74? (col = 0, '\n'): ' ');
61782bf8890SDavid du Colombier #endif
61882bf8890SDavid du Colombier if (code >= 0) {
61982bf8890SDavid du Colombier /*
62082bf8890SDavid du Colombier * byte/bit numbering on the VAX is simulated by the
62182bf8890SDavid du Colombier * following code
62282bf8890SDavid du Colombier */
62382bf8890SDavid du Colombier /*
62482bf8890SDavid du Colombier * Get to the first byte.
62582bf8890SDavid du Colombier */
62682bf8890SDavid du Colombier bp += (r_off >> 3);
62782bf8890SDavid du Colombier r_off &= 7;
62882bf8890SDavid du Colombier /*
62982bf8890SDavid du Colombier * Since code is always >= 8 bits, only need to mask the first
63082bf8890SDavid du Colombier * hunk on the left.
63182bf8890SDavid du Colombier */
63282bf8890SDavid du Colombier *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
63382bf8890SDavid du Colombier bp++;
63482bf8890SDavid du Colombier bits -= 8 - r_off;
63582bf8890SDavid du Colombier code >>= 8 - r_off;
63682bf8890SDavid du Colombier /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
63782bf8890SDavid du Colombier if ( bits >= 8 ) {
63882bf8890SDavid du Colombier *bp++ = code;
63982bf8890SDavid du Colombier code >>= 8;
64082bf8890SDavid du Colombier bits -= 8;
64182bf8890SDavid du Colombier }
64282bf8890SDavid du Colombier /* Last bits. */
64382bf8890SDavid du Colombier if(bits)
64482bf8890SDavid du Colombier *bp = code;
64582bf8890SDavid du Colombier
64682bf8890SDavid du Colombier offset += n_bits;
64782bf8890SDavid du Colombier if ( offset == (n_bits << 3) ) {
64882bf8890SDavid du Colombier bp = buf;
64982bf8890SDavid du Colombier bits = n_bits;
65082bf8890SDavid du Colombier bytes_out += bits;
65182bf8890SDavid du Colombier do {
65282bf8890SDavid du Colombier putchar(*bp++);
65382bf8890SDavid du Colombier } while(--bits);
65482bf8890SDavid du Colombier offset = 0;
65582bf8890SDavid du Colombier }
65682bf8890SDavid du Colombier
65782bf8890SDavid du Colombier /*
65882bf8890SDavid du Colombier * If the next entry is going to be too big for the code size,
65982bf8890SDavid du Colombier * then increase it, if possible.
66082bf8890SDavid du Colombier */
66182bf8890SDavid du Colombier if ( free_ent > maxcode || (clear_flg > 0)) {
66282bf8890SDavid du Colombier /*
66382bf8890SDavid du Colombier * Write the whole buffer, because the input side won't
66482bf8890SDavid du Colombier * discover the size increase until after it has read it.
66582bf8890SDavid du Colombier */
66682bf8890SDavid du Colombier if ( offset > 0 ) {
66782bf8890SDavid du Colombier if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
66882bf8890SDavid du Colombier writeerr();
66982bf8890SDavid du Colombier bytes_out += n_bits;
67082bf8890SDavid du Colombier }
67182bf8890SDavid du Colombier offset = 0;
67282bf8890SDavid du Colombier
67382bf8890SDavid du Colombier if ( clear_flg ) {
67482bf8890SDavid du Colombier maxcode = MAXCODE (n_bits = INIT_BITS);
67582bf8890SDavid du Colombier clear_flg = 0;
67682bf8890SDavid du Colombier } else {
67782bf8890SDavid du Colombier n_bits++;
67882bf8890SDavid du Colombier if ( n_bits == maxbits )
67982bf8890SDavid du Colombier maxcode = maxmaxcode;
68082bf8890SDavid du Colombier else
68182bf8890SDavid du Colombier maxcode = MAXCODE(n_bits);
68282bf8890SDavid du Colombier }
68382bf8890SDavid du Colombier #ifdef DEBUG
68482bf8890SDavid du Colombier if ( debug ) {
68582bf8890SDavid du Colombier fprintf(stderr,
68682bf8890SDavid du Colombier "\nChange to %d bits\n", n_bits);
68782bf8890SDavid du Colombier col = 0;
68882bf8890SDavid du Colombier }
68982bf8890SDavid du Colombier #endif
69082bf8890SDavid du Colombier }
69182bf8890SDavid du Colombier } else {
69282bf8890SDavid du Colombier /*
69382bf8890SDavid du Colombier * At EOF, write the rest of the buffer.
69482bf8890SDavid du Colombier */
69582bf8890SDavid du Colombier if ( offset > 0 )
69682bf8890SDavid du Colombier fwrite( buf, 1, (offset + 7) / 8, stdout );
69782bf8890SDavid du Colombier bytes_out += (offset + 7) / 8;
69882bf8890SDavid du Colombier offset = 0;
69982bf8890SDavid du Colombier fflush( stdout );
70082bf8890SDavid du Colombier #ifdef DEBUG
70182bf8890SDavid du Colombier if ( verbose )
70282bf8890SDavid du Colombier fprintf( stderr, "\n" );
70382bf8890SDavid du Colombier #endif
70482bf8890SDavid du Colombier if( ferror( stdout ) )
70582bf8890SDavid du Colombier writeerr();
70682bf8890SDavid du Colombier }
70782bf8890SDavid du Colombier }
70882bf8890SDavid du Colombier
70982bf8890SDavid du Colombier /*
71082bf8890SDavid du Colombier * Decompress stdin to stdout. This routine adapts to the codes in the
71182bf8890SDavid du Colombier * file building the "string" table on-the-fly; requiring no table to
71282bf8890SDavid du Colombier * be stored in the compressed file. The tables used herein are shared
71382bf8890SDavid du Colombier * with those of the compress() routine. See the definitions above.
71482bf8890SDavid du Colombier */
715*14f51593SDavid du Colombier void
decompress(void)716*14f51593SDavid du Colombier decompress(void)
71782bf8890SDavid du Colombier {
71882bf8890SDavid du Colombier int finchar;
71982bf8890SDavid du Colombier code_int code, oldcode, incode;
72082bf8890SDavid du Colombier uchar *stackp;
72182bf8890SDavid du Colombier
72282bf8890SDavid du Colombier /*
72382bf8890SDavid du Colombier * As above, initialize the first 256 entries in the table.
72482bf8890SDavid du Colombier */
72582bf8890SDavid du Colombier maxcode = MAXCODE(n_bits = INIT_BITS);
72682bf8890SDavid du Colombier for (code = 255; code >= 0; code--) {
72782bf8890SDavid du Colombier tab_prefixof(code) = 0;
72882bf8890SDavid du Colombier tab_suffixof(code) = (uchar)code;
72982bf8890SDavid du Colombier }
73082bf8890SDavid du Colombier free_ent = (block_compress? FIRST: 256);
73182bf8890SDavid du Colombier
73282bf8890SDavid du Colombier finchar = oldcode = getcode();
73382bf8890SDavid du Colombier if(oldcode == -1) /* EOF already? */
73482bf8890SDavid du Colombier return; /* Get out of here */
73582bf8890SDavid du Colombier putchar((char)finchar); /* first code must be 8 bits = char */
73682bf8890SDavid du Colombier if(ferror(stdout)) /* Crash if can't write */
73782bf8890SDavid du Colombier writeerr();
73882bf8890SDavid du Colombier stackp = de_stack;
73982bf8890SDavid du Colombier
74082bf8890SDavid du Colombier while ((code = getcode()) > -1) {
74182bf8890SDavid du Colombier if ((code == CLEAR) && block_compress) {
74282bf8890SDavid du Colombier for (code = 255; code >= 0; code--)
74382bf8890SDavid du Colombier tab_prefixof(code) = 0;
74482bf8890SDavid du Colombier clear_flg = 1;
74582bf8890SDavid du Colombier free_ent = FIRST - 1;
74682bf8890SDavid du Colombier if ((code = getcode()) == -1) /* O, untimely death! */
74782bf8890SDavid du Colombier break;
74882bf8890SDavid du Colombier }
74982bf8890SDavid du Colombier incode = code;
75082bf8890SDavid du Colombier /*
75182bf8890SDavid du Colombier * Special case for KwKwK string.
75282bf8890SDavid du Colombier */
75382bf8890SDavid du Colombier if (code >= free_ent) {
75482bf8890SDavid du Colombier *stackp++ = finchar;
75582bf8890SDavid du Colombier code = oldcode;
75682bf8890SDavid du Colombier }
75782bf8890SDavid du Colombier
75882bf8890SDavid du Colombier /*
75982bf8890SDavid du Colombier * Generate output characters in reverse order
76082bf8890SDavid du Colombier */
76182bf8890SDavid du Colombier while (code >= 256) {
76282bf8890SDavid du Colombier *stackp++ = tab_suffixof(code);
76382bf8890SDavid du Colombier code = tab_prefixof(code);
76482bf8890SDavid du Colombier }
76582bf8890SDavid du Colombier *stackp++ = finchar = tab_suffixof(code);
76682bf8890SDavid du Colombier
76782bf8890SDavid du Colombier /*
76882bf8890SDavid du Colombier * And put them out in forward order
76982bf8890SDavid du Colombier */
77082bf8890SDavid du Colombier do {
77182bf8890SDavid du Colombier putchar(*--stackp);
77282bf8890SDavid du Colombier } while (stackp > de_stack);
77382bf8890SDavid du Colombier
77482bf8890SDavid du Colombier /*
77582bf8890SDavid du Colombier * Generate the new entry.
77682bf8890SDavid du Colombier */
77782bf8890SDavid du Colombier if ( (code=free_ent) < maxmaxcode ) {
77882bf8890SDavid du Colombier tab_prefixof(code) = (ushort)oldcode;
77982bf8890SDavid du Colombier tab_suffixof(code) = finchar;
78082bf8890SDavid du Colombier free_ent = code+1;
78182bf8890SDavid du Colombier }
78282bf8890SDavid du Colombier /*
78382bf8890SDavid du Colombier * Remember previous code.
78482bf8890SDavid du Colombier */
78582bf8890SDavid du Colombier oldcode = incode;
78682bf8890SDavid du Colombier }
78782bf8890SDavid du Colombier fflush(stdout);
78882bf8890SDavid du Colombier if(ferror(stdout))
78982bf8890SDavid du Colombier writeerr();
79082bf8890SDavid du Colombier }
79182bf8890SDavid du Colombier
79282bf8890SDavid du Colombier /*
79382bf8890SDavid du Colombier * TAG( getcode )
79482bf8890SDavid du Colombier *
79582bf8890SDavid du Colombier * Read one code from the standard input. If EOF, return -1.
79682bf8890SDavid du Colombier * Inputs:
79782bf8890SDavid du Colombier * stdin
79882bf8890SDavid du Colombier * Outputs:
79982bf8890SDavid du Colombier * code or -1 is returned.
80082bf8890SDavid du Colombier */
80182bf8890SDavid du Colombier code_int
getcode()80282bf8890SDavid du Colombier getcode()
80382bf8890SDavid du Colombier {
80482bf8890SDavid du Colombier int r_off, bits;
80582bf8890SDavid du Colombier code_int code;
80682bf8890SDavid du Colombier static int offset = 0, size = 0;
80782bf8890SDavid du Colombier static uchar buf[BITS];
80882bf8890SDavid du Colombier uchar *bp = buf;
80982bf8890SDavid du Colombier
81082bf8890SDavid du Colombier if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
81182bf8890SDavid du Colombier /*
81282bf8890SDavid du Colombier * If the next entry will be too big for the current code
81382bf8890SDavid du Colombier * size, then we must increase the size. This implies reading
81482bf8890SDavid du Colombier * a new buffer full, too.
81582bf8890SDavid du Colombier */
81682bf8890SDavid du Colombier if ( free_ent > maxcode ) {
81782bf8890SDavid du Colombier n_bits++;
81882bf8890SDavid du Colombier if ( n_bits == maxbits )
81982bf8890SDavid du Colombier maxcode = maxmaxcode; /* won't get any bigger now */
82082bf8890SDavid du Colombier else
82182bf8890SDavid du Colombier maxcode = MAXCODE(n_bits);
82282bf8890SDavid du Colombier }
82382bf8890SDavid du Colombier if ( clear_flg > 0) {
82482bf8890SDavid du Colombier maxcode = MAXCODE(n_bits = INIT_BITS);
82582bf8890SDavid du Colombier clear_flg = 0;
82682bf8890SDavid du Colombier }
82782bf8890SDavid du Colombier size = fread(buf, 1, n_bits, stdin);
82882bf8890SDavid du Colombier if (size <= 0)
82982bf8890SDavid du Colombier return -1; /* end of file */
83082bf8890SDavid du Colombier offset = 0;
83182bf8890SDavid du Colombier /* Round size down to integral number of codes */
83282bf8890SDavid du Colombier size = (size << 3) - (n_bits - 1);
83382bf8890SDavid du Colombier }
83482bf8890SDavid du Colombier r_off = offset;
83582bf8890SDavid du Colombier bits = n_bits;
83682bf8890SDavid du Colombier /*
83782bf8890SDavid du Colombier * Get to the first byte.
83882bf8890SDavid du Colombier */
83982bf8890SDavid du Colombier bp += (r_off >> 3);
84082bf8890SDavid du Colombier r_off &= 7;
84182bf8890SDavid du Colombier /* Get first part (low order bits) */
84282bf8890SDavid du Colombier code = (*bp++ >> r_off);
84382bf8890SDavid du Colombier bits -= (8 - r_off);
84482bf8890SDavid du Colombier r_off = 8 - r_off; /* now, offset into code word */
84582bf8890SDavid du Colombier /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
84682bf8890SDavid du Colombier if (bits >= 8) {
84782bf8890SDavid du Colombier code |= *bp++ << r_off;
84882bf8890SDavid du Colombier r_off += 8;
84982bf8890SDavid du Colombier bits -= 8;
85082bf8890SDavid du Colombier }
85182bf8890SDavid du Colombier /* high order bits. */
85282bf8890SDavid du Colombier code |= (*bp & rmask[bits]) << r_off;
85382bf8890SDavid du Colombier offset += n_bits;
85482bf8890SDavid du Colombier return code;
85582bf8890SDavid du Colombier }
85682bf8890SDavid du Colombier
85782bf8890SDavid du Colombier #ifdef DEBUG
printcodes()85882bf8890SDavid du Colombier printcodes()
85982bf8890SDavid du Colombier {
86082bf8890SDavid du Colombier /*
86182bf8890SDavid du Colombier * Just print out codes from input file. For debugging.
86282bf8890SDavid du Colombier */
86382bf8890SDavid du Colombier code_int code;
86482bf8890SDavid du Colombier int col = 0, bits;
86582bf8890SDavid du Colombier
86682bf8890SDavid du Colombier bits = n_bits = INIT_BITS;
86782bf8890SDavid du Colombier maxcode = MAXCODE(n_bits);
86882bf8890SDavid du Colombier free_ent = ((block_compress) ? FIRST : 256 );
86982bf8890SDavid du Colombier while ( ( code = getcode() ) >= 0 ) {
87082bf8890SDavid du Colombier if ( (code == CLEAR) && block_compress ) {
87182bf8890SDavid du Colombier free_ent = FIRST - 1;
87282bf8890SDavid du Colombier clear_flg = 1;
87382bf8890SDavid du Colombier }
87482bf8890SDavid du Colombier else if ( free_ent < maxmaxcode )
87582bf8890SDavid du Colombier free_ent++;
87682bf8890SDavid du Colombier if ( bits != n_bits ) {
87782bf8890SDavid du Colombier fprintf(stderr, "\nChange to %d bits\n", n_bits );
87882bf8890SDavid du Colombier bits = n_bits;
87982bf8890SDavid du Colombier col = 0;
88082bf8890SDavid du Colombier }
88182bf8890SDavid du Colombier fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
88282bf8890SDavid du Colombier }
88382bf8890SDavid du Colombier putc( '\n', stderr );
88482bf8890SDavid du Colombier exit( 0 );
88582bf8890SDavid du Colombier }
88682bf8890SDavid du Colombier
88782bf8890SDavid du Colombier code_int sorttab[1<<BITS]; /* sorted pointers into htab */
88882bf8890SDavid du Colombier
88982bf8890SDavid du Colombier #define STACK_SIZE 15000
89082bf8890SDavid du Colombier
dump_tab()89182bf8890SDavid du Colombier dump_tab() /* dump string table */
89282bf8890SDavid du Colombier {
89382bf8890SDavid du Colombier int i, first, c, ent;
89482bf8890SDavid du Colombier int stack_top = STACK_SIZE;
89582bf8890SDavid du Colombier
89682bf8890SDavid du Colombier if(do_decomp == 0) { /* compressing */
89782bf8890SDavid du Colombier int flag = 1;
89882bf8890SDavid du Colombier
89982bf8890SDavid du Colombier for(i=0; i<hsize; i++) { /* build sort pointers */
90082bf8890SDavid du Colombier if((long)htabof(i) >= 0) {
90182bf8890SDavid du Colombier sorttab[codetabof(i)] = i;
90282bf8890SDavid du Colombier }
90382bf8890SDavid du Colombier }
90482bf8890SDavid du Colombier first = block_compress ? FIRST : 256;
90582bf8890SDavid du Colombier for(i = first; i < free_ent; i++) {
90682bf8890SDavid du Colombier fprintf(stderr, "%5d: \"", i);
90782bf8890SDavid du Colombier de_stack[--stack_top] = '\n';
90882bf8890SDavid du Colombier de_stack[--stack_top] = '"';
90982bf8890SDavid du Colombier stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff,
91082bf8890SDavid du Colombier stack_top);
91182bf8890SDavid du Colombier for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
91282bf8890SDavid du Colombier ent > 256;
91382bf8890SDavid du Colombier ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
91482bf8890SDavid du Colombier stack_top = in_stack(htabof(sorttab[ent]) >> maxbits,
91582bf8890SDavid du Colombier stack_top);
91682bf8890SDavid du Colombier }
91782bf8890SDavid du Colombier stack_top = in_stack(ent, stack_top);
91882bf8890SDavid du Colombier fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
91982bf8890SDavid du Colombier stack_top = STACK_SIZE;
92082bf8890SDavid du Colombier }
92182bf8890SDavid du Colombier } else if(!debug) { /* decompressing */
92282bf8890SDavid du Colombier
92382bf8890SDavid du Colombier for ( i = 0; i < free_ent; i++ ) {
92482bf8890SDavid du Colombier ent = i;
92582bf8890SDavid du Colombier c = tab_suffixof(ent);
92682bf8890SDavid du Colombier if ( isascii(c) && isprint(c) )
92782bf8890SDavid du Colombier fprintf( stderr, "%5d: %5d/'%c' \"",
92882bf8890SDavid du Colombier ent, tab_prefixof(ent), c );
92982bf8890SDavid du Colombier else
93082bf8890SDavid du Colombier fprintf( stderr, "%5d: %5d/\\%03o \"",
93182bf8890SDavid du Colombier ent, tab_prefixof(ent), c );
93282bf8890SDavid du Colombier de_stack[--stack_top] = '\n';
93382bf8890SDavid du Colombier de_stack[--stack_top] = '"';
93482bf8890SDavid du Colombier for ( ; ent != NULL;
93582bf8890SDavid du Colombier ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
93682bf8890SDavid du Colombier stack_top = in_stack(tab_suffixof(ent), stack_top);
93782bf8890SDavid du Colombier }
93882bf8890SDavid du Colombier fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
93982bf8890SDavid du Colombier stack_top = STACK_SIZE;
94082bf8890SDavid du Colombier }
94182bf8890SDavid du Colombier }
94282bf8890SDavid du Colombier }
94382bf8890SDavid du Colombier
94482bf8890SDavid du Colombier int
in_stack(int c,int stack_top)94582bf8890SDavid du Colombier in_stack(int c, int stack_top)
94682bf8890SDavid du Colombier {
94782bf8890SDavid du Colombier if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
94882bf8890SDavid du Colombier de_stack[--stack_top] = c;
94982bf8890SDavid du Colombier } else {
95082bf8890SDavid du Colombier switch( c ) {
95182bf8890SDavid du Colombier case '\n': de_stack[--stack_top] = 'n'; break;
95282bf8890SDavid du Colombier case '\t': de_stack[--stack_top] = 't'; break;
95382bf8890SDavid du Colombier case '\b': de_stack[--stack_top] = 'b'; break;
95482bf8890SDavid du Colombier case '\f': de_stack[--stack_top] = 'f'; break;
95582bf8890SDavid du Colombier case '\r': de_stack[--stack_top] = 'r'; break;
95682bf8890SDavid du Colombier case '\\': de_stack[--stack_top] = '\\'; break;
95782bf8890SDavid du Colombier default:
95882bf8890SDavid du Colombier de_stack[--stack_top] = '0' + c % 8;
95982bf8890SDavid du Colombier de_stack[--stack_top] = '0' + (c / 8) % 8;
96082bf8890SDavid du Colombier de_stack[--stack_top] = '0' + c / 64;
96182bf8890SDavid du Colombier break;
96282bf8890SDavid du Colombier }
96382bf8890SDavid du Colombier de_stack[--stack_top] = '\\';
96482bf8890SDavid du Colombier }
96582bf8890SDavid du Colombier return stack_top;
96682bf8890SDavid du Colombier }
96782bf8890SDavid du Colombier #endif /* DEBUG */
96882bf8890SDavid du Colombier
969*14f51593SDavid du Colombier void
writeerr(void)970*14f51593SDavid du Colombier writeerr(void)
97182bf8890SDavid du Colombier {
97282bf8890SDavid du Colombier perror(ofname);
97382bf8890SDavid du Colombier unlink(ofname);
97482bf8890SDavid du Colombier exit(1);
97582bf8890SDavid du Colombier }
97682bf8890SDavid du Colombier
977*14f51593SDavid du Colombier void
copystat(ifname,ofname)97882bf8890SDavid du Colombier copystat(ifname, ofname)
97982bf8890SDavid du Colombier char *ifname, *ofname;
98082bf8890SDavid du Colombier {
98182bf8890SDavid du Colombier int mode;
982*14f51593SDavid du Colombier time_t timep[2]; /* should be struct utimbuf */
98382bf8890SDavid du Colombier struct stat statbuf;
98482bf8890SDavid du Colombier
98582bf8890SDavid du Colombier fclose(stdout);
98682bf8890SDavid du Colombier if (stat(ifname, &statbuf)) { /* Get stat on input file */
98782bf8890SDavid du Colombier perror(ifname);
98882bf8890SDavid du Colombier return;
98982bf8890SDavid du Colombier }
99082bf8890SDavid du Colombier if (!S_ISREG(statbuf.st_mode)) {
99182bf8890SDavid du Colombier if (quiet)
99282bf8890SDavid du Colombier fprintf(stderr, "%s: ", ifname);
99382bf8890SDavid du Colombier fprintf(stderr, " -- not a regular file: unchanged");
99482bf8890SDavid du Colombier exit_stat = 1;
995e9b61b2aSDavid du Colombier } else if (exit_stat == 2 && !force) {
99682bf8890SDavid du Colombier /* No compression: remove file.Z */
99782bf8890SDavid du Colombier if (!quiet)
99882bf8890SDavid du Colombier fprintf(stderr, " -- file unchanged");
99982bf8890SDavid du Colombier } else { /* Successful Compression */
100082bf8890SDavid du Colombier exit_stat = 0;
1001e9b61b2aSDavid du Colombier mode = statbuf.st_mode & 0777;
100282bf8890SDavid du Colombier if (chmod(ofname, mode)) /* Copy modes */
100382bf8890SDavid du Colombier perror(ofname);
100482bf8890SDavid du Colombier /* Copy ownership */
100582bf8890SDavid du Colombier chown(ofname, statbuf.st_uid, statbuf.st_gid);
100682bf8890SDavid du Colombier timep[0] = statbuf.st_atime;
100782bf8890SDavid du Colombier timep[1] = statbuf.st_mtime;
100882bf8890SDavid du Colombier /* Update last accessed and modified times */
1009*14f51593SDavid du Colombier utime(ofname, (struct utimbuf *)timep);
101082bf8890SDavid du Colombier // if (unlink(ifname)) /* Remove input file */
101182bf8890SDavid du Colombier // perror(ifname);
1012e9b61b2aSDavid du Colombier return; /* success */
101382bf8890SDavid du Colombier }
101482bf8890SDavid du Colombier
101582bf8890SDavid du Colombier /* Unsuccessful return -- one of the tests failed */
101682bf8890SDavid du Colombier if (unlink(ofname))
101782bf8890SDavid du Colombier perror(ofname);
101882bf8890SDavid du Colombier }
101982bf8890SDavid du Colombier
102082bf8890SDavid du Colombier /*
102182bf8890SDavid du Colombier * This routine returns 1 if we are running in the foreground and stderr
102282bf8890SDavid du Colombier * is a tty.
102382bf8890SDavid du Colombier */
1024*14f51593SDavid du Colombier int
foreground(void)1025*14f51593SDavid du Colombier foreground(void)
102682bf8890SDavid du Colombier {
102782bf8890SDavid du Colombier if(bgnd_flag) /* background? */
102882bf8890SDavid du Colombier return 0;
102982bf8890SDavid du Colombier else /* foreground */
103082bf8890SDavid du Colombier return isatty(2); /* and stderr is a tty */
103182bf8890SDavid du Colombier }
103282bf8890SDavid du Colombier
103382bf8890SDavid du Colombier void
onintr(int x)103482bf8890SDavid du Colombier onintr(int x)
103582bf8890SDavid du Colombier {
1036*14f51593SDavid du Colombier USED(x);
103782bf8890SDavid du Colombier unlink(ofname);
103882bf8890SDavid du Colombier exit(1);
103982bf8890SDavid du Colombier }
104082bf8890SDavid du Colombier
104182bf8890SDavid du Colombier void
oops(int x)104282bf8890SDavid du Colombier oops(int x) /* wild pointer -- assume bad input */
104382bf8890SDavid du Colombier {
1044*14f51593SDavid du Colombier USED(x);
104582bf8890SDavid du Colombier if (do_decomp == 1)
104682bf8890SDavid du Colombier fprintf(stderr, "uncompress: corrupt input\n");
104782bf8890SDavid du Colombier unlink(ofname);
104882bf8890SDavid du Colombier exit(1);
104982bf8890SDavid du Colombier }
105082bf8890SDavid du Colombier
1051*14f51593SDavid du Colombier void
cl_block(void)1052*14f51593SDavid du Colombier cl_block(void) /* table clear for block compress */
105382bf8890SDavid du Colombier {
105482bf8890SDavid du Colombier long rat;
105582bf8890SDavid du Colombier
105682bf8890SDavid du Colombier checkpoint = in_count + CHECK_GAP;
105782bf8890SDavid du Colombier #ifdef DEBUG
105882bf8890SDavid du Colombier if ( debug ) {
105982bf8890SDavid du Colombier fprintf ( stderr, "count: %ld, ratio: ", in_count );
106082bf8890SDavid du Colombier prratio ( stderr, in_count, bytes_out );
106182bf8890SDavid du Colombier fprintf ( stderr, "\n");
106282bf8890SDavid du Colombier }
106382bf8890SDavid du Colombier #endif /* DEBUG */
106482bf8890SDavid du Colombier
106582bf8890SDavid du Colombier if (in_count > 0x007fffff) { /* shift will overflow */
106682bf8890SDavid du Colombier rat = bytes_out >> 8;
106782bf8890SDavid du Colombier if (rat == 0) /* Don't divide by zero */
106882bf8890SDavid du Colombier rat = 0x7fffffff;
106982bf8890SDavid du Colombier else
107082bf8890SDavid du Colombier rat = in_count / rat;
107182bf8890SDavid du Colombier } else
107282bf8890SDavid du Colombier rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
107382bf8890SDavid du Colombier if (rat > ratio)
107482bf8890SDavid du Colombier ratio = rat;
107582bf8890SDavid du Colombier else {
107682bf8890SDavid du Colombier ratio = 0;
107782bf8890SDavid du Colombier #ifdef DEBUG
107882bf8890SDavid du Colombier if (verbose)
107982bf8890SDavid du Colombier dump_tab(); /* dump string table */
108082bf8890SDavid du Colombier #endif
108182bf8890SDavid du Colombier cl_hash((count_int)hsize);
108282bf8890SDavid du Colombier free_ent = FIRST;
108382bf8890SDavid du Colombier clear_flg = 1;
108482bf8890SDavid du Colombier output((code_int)CLEAR);
108582bf8890SDavid du Colombier #ifdef DEBUG
108682bf8890SDavid du Colombier if (debug)
108782bf8890SDavid du Colombier fprintf(stderr, "clear\n");
108882bf8890SDavid du Colombier #endif /* DEBUG */
108982bf8890SDavid du Colombier }
109082bf8890SDavid du Colombier }
109182bf8890SDavid du Colombier
1092*14f51593SDavid du Colombier void
cl_hash(count_int hsize)1093*14f51593SDavid du Colombier cl_hash(count_int hsize) /* reset code table */
109482bf8890SDavid du Colombier {
109582bf8890SDavid du Colombier count_int *htab_p = htab+hsize;
109682bf8890SDavid du Colombier long i;
109782bf8890SDavid du Colombier long m1 = -1;
109882bf8890SDavid du Colombier
109982bf8890SDavid du Colombier i = hsize - 16;
110082bf8890SDavid du Colombier do { /* might use Sys V memset(3) here */
110182bf8890SDavid du Colombier *(htab_p-16) = m1;
110282bf8890SDavid du Colombier *(htab_p-15) = m1;
110382bf8890SDavid du Colombier *(htab_p-14) = m1;
110482bf8890SDavid du Colombier *(htab_p-13) = m1;
110582bf8890SDavid du Colombier *(htab_p-12) = m1;
110682bf8890SDavid du Colombier *(htab_p-11) = m1;
110782bf8890SDavid du Colombier *(htab_p-10) = m1;
110882bf8890SDavid du Colombier *(htab_p-9) = m1;
110982bf8890SDavid du Colombier *(htab_p-8) = m1;
111082bf8890SDavid du Colombier *(htab_p-7) = m1;
111182bf8890SDavid du Colombier *(htab_p-6) = m1;
111282bf8890SDavid du Colombier *(htab_p-5) = m1;
111382bf8890SDavid du Colombier *(htab_p-4) = m1;
111482bf8890SDavid du Colombier *(htab_p-3) = m1;
111582bf8890SDavid du Colombier *(htab_p-2) = m1;
111682bf8890SDavid du Colombier *(htab_p-1) = m1;
111782bf8890SDavid du Colombier htab_p -= 16;
111882bf8890SDavid du Colombier } while ((i -= 16) >= 0);
111982bf8890SDavid du Colombier for ( i += 16; i > 0; i-- )
112082bf8890SDavid du Colombier *--htab_p = m1;
112182bf8890SDavid du Colombier }
112282bf8890SDavid du Colombier
1123*14f51593SDavid du Colombier void
prratio(stream,num,den)112482bf8890SDavid du Colombier prratio(stream, num, den)
112582bf8890SDavid du Colombier FILE *stream;
112682bf8890SDavid du Colombier long num, den;
112782bf8890SDavid du Colombier {
112882bf8890SDavid du Colombier int q; /* Doesn't need to be long */
112982bf8890SDavid du Colombier
113082bf8890SDavid du Colombier if(num > 214748L) /* 2147483647/10000 */
113182bf8890SDavid du Colombier q = num / (den / 10000L);
113282bf8890SDavid du Colombier else
113382bf8890SDavid du Colombier q = 10000L * num / den; /* Long calculations, though */
113482bf8890SDavid du Colombier if (q < 0) {
113582bf8890SDavid du Colombier putc('-', stream);
113682bf8890SDavid du Colombier q = -q;
113782bf8890SDavid du Colombier }
113882bf8890SDavid du Colombier fprintf(stream, "%d.%02d%%", q / 100, q % 100);
113982bf8890SDavid du Colombier }
114082bf8890SDavid du Colombier
1141*14f51593SDavid du Colombier void
version(void)1142*14f51593SDavid du Colombier version(void)
114382bf8890SDavid du Colombier {
114482bf8890SDavid du Colombier fprintf(stderr, "%s\n", rcs_ident);
114582bf8890SDavid du Colombier fprintf(stderr, "Options: ");
114682bf8890SDavid du Colombier #ifdef DEBUG
114782bf8890SDavid du Colombier fprintf(stderr, "DEBUG, ");
114882bf8890SDavid du Colombier #endif
114982bf8890SDavid du Colombier #ifdef BSD4_2
115082bf8890SDavid du Colombier fprintf(stderr, "BSD4_2, ");
115182bf8890SDavid du Colombier #endif
115282bf8890SDavid du Colombier fprintf(stderr, "BITS = %d\n", BITS);
115382bf8890SDavid du Colombier }
115482bf8890SDavid du Colombier
115582bf8890SDavid du Colombier /*
115682bf8890SDavid du Colombier * The revision-history novel:
115782bf8890SDavid du Colombier *
115882bf8890SDavid du Colombier * $Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $
115982bf8890SDavid du Colombier * $Log: compress.c,v $
116082bf8890SDavid du Colombier * Revision 4.0 85/07/30 12:50:00 joe
116182bf8890SDavid du Colombier * Removed ferror() calls in output routine on every output except first.
116282bf8890SDavid du Colombier * Prepared for release to the world.
116382bf8890SDavid du Colombier *
116482bf8890SDavid du Colombier * Revision 3.6 85/07/04 01:22:21 joe
116582bf8890SDavid du Colombier * Remove much wasted storage by overlaying hash table with the tables
116682bf8890SDavid du Colombier * used by decompress: tab_suffix[1<<BITS], stack[8000]. Updated USERMEM
116782bf8890SDavid du Colombier * computations. Fixed dump_tab() DEBUG routine.
116882bf8890SDavid du Colombier *
116982bf8890SDavid du Colombier * Revision 3.5 85/06/30 20:47:21 jaw
117082bf8890SDavid du Colombier * Change hash function to use exclusive-or. Rip out hash cache. These
117182bf8890SDavid du Colombier * speedups render the megamemory version defunct, for now. Make decoder
117282bf8890SDavid du Colombier * stack global. Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
117382bf8890SDavid du Colombier *
117482bf8890SDavid du Colombier * Revision 3.4 85/06/27 12:00:00 ken
117582bf8890SDavid du Colombier * Get rid of all floating-point calculations by doing all compression ratio
117682bf8890SDavid du Colombier * calculations in fixed point.
117782bf8890SDavid du Colombier *
117882bf8890SDavid du Colombier * Revision 3.3 85/06/24 21:53:24 joe
117982bf8890SDavid du Colombier * Incorporate portability suggestion for M_XENIX. Got rid of text on #else
118082bf8890SDavid du Colombier * and #endif lines. Cleaned up #ifdefs for vax and interdata.
118182bf8890SDavid du Colombier *
118282bf8890SDavid du Colombier * Revision 3.2 85/06/06 21:53:24 jaw
118382bf8890SDavid du Colombier * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
118482bf8890SDavid du Colombier * Default to "quiet" output (no compression statistics).
118582bf8890SDavid du Colombier *
118682bf8890SDavid du Colombier * Revision 3.1 85/05/12 18:56:13 jaw
118782bf8890SDavid du Colombier * Integrate decompress() stack speedups (from early pointer mods by McKie).
118882bf8890SDavid du Colombier * Repair multi-file USERMEM gaffe. Unify 'force' flags to mimic semantics
118982bf8890SDavid du Colombier * of SVR2 'pack'. Streamline block-compress table clear logic. Increase
119082bf8890SDavid du Colombier * output byte count by magic number size.
119182bf8890SDavid du Colombier *
119282bf8890SDavid du Colombier * Revision 3.0 84/11/27 11:50:00 petsd!joe
119382bf8890SDavid du Colombier * Set HSIZE depending on BITS. Set BITS depending on USERMEM. Unrolled
119482bf8890SDavid du Colombier * loops in clear routines. Added "-C" flag for 2.0 compatibility. Used
119582bf8890SDavid du Colombier * unsigned compares on Perkin-Elmer. Fixed foreground check.
119682bf8890SDavid du Colombier *
119782bf8890SDavid du Colombier * Revision 2.7 84/11/16 19:35:39 ames!jaw
119882bf8890SDavid du Colombier * Cache common hash codes based on input statistics; this improves
119982bf8890SDavid du Colombier * performance for low-density raster images. Pass on #ifdef bundle
120082bf8890SDavid du Colombier * from Turkowski.
120182bf8890SDavid du Colombier *
120282bf8890SDavid du Colombier * Revision 2.6 84/11/05 19:18:21 ames!jaw
120382bf8890SDavid du Colombier * Vary size of hash tables to reduce time for small files.
120482bf8890SDavid du Colombier * Tune PDP-11 hash function.
120582bf8890SDavid du Colombier *
120682bf8890SDavid du Colombier * Revision 2.5 84/10/30 20:15:14 ames!jaw
120782bf8890SDavid du Colombier * Junk chaining; replace with the simpler (and, on the VAX, faster)
120882bf8890SDavid du Colombier * double hashing, discussed within. Make block compression standard.
120982bf8890SDavid du Colombier *
121082bf8890SDavid du Colombier * Revision 2.4 84/10/16 11:11:11 ames!jaw
121182bf8890SDavid du Colombier * Introduce adaptive reset for block compression, to boost the rate
121282bf8890SDavid du Colombier * another several percent. (See mailing list notes.)
121382bf8890SDavid du Colombier *
121482bf8890SDavid du Colombier * Revision 2.3 84/09/22 22:00:00 petsd!joe
121582bf8890SDavid du Colombier * Implemented "-B" block compress. Implemented REVERSE sorting of tab_next.
121682bf8890SDavid du Colombier * Bug fix for last bits. Changed fwrite to putchar loop everywhere.
121782bf8890SDavid du Colombier *
121882bf8890SDavid du Colombier * Revision 2.2 84/09/18 14:12:21 ames!jaw
121982bf8890SDavid du Colombier * Fold in news changes, small machine typedef from thomas,
122082bf8890SDavid du Colombier * #ifdef interdata from joe.
122182bf8890SDavid du Colombier *
122282bf8890SDavid du Colombier * Revision 2.1 84/09/10 12:34:56 ames!jaw
122382bf8890SDavid du Colombier * Configured fast table lookup for 32-bit machines.
122482bf8890SDavid du Colombier * This cuts user time in half for b <= FBITS, and is useful for news batching
122582bf8890SDavid du Colombier * from VAX to PDP sites. Also sped up decompress() [fwrite->putc] and
122682bf8890SDavid du Colombier * added signal catcher [plus beef in writeerr()] to delete effluvia.
122782bf8890SDavid du Colombier *
122882bf8890SDavid du Colombier * Revision 2.0 84/08/28 22:00:00 petsd!joe
122982bf8890SDavid du Colombier * Add check for foreground before prompting user. Insert maxbits into
123082bf8890SDavid du Colombier * compressed file. Force file being uncompressed to end with ".Z".
123182bf8890SDavid du Colombier * Added "-c" flag and "zcat". Prepared for release.
123282bf8890SDavid du Colombier *
123382bf8890SDavid du Colombier * Revision 1.10 84/08/24 18:28:00 turtlevax!ken
123482bf8890SDavid du Colombier * Will only compress regular files (no directories), added a magic number
123582bf8890SDavid du Colombier * header (plus an undocumented -n flag to handle old files without headers),
123682bf8890SDavid du Colombier * added -f flag to force overwriting of possibly existing destination file,
123782bf8890SDavid du Colombier * otherwise the user is prompted for a response. Will tack on a .Z to a
123882bf8890SDavid du Colombier * filename if it doesn't have one when decompressing. Will only replace
123982bf8890SDavid du Colombier * file if it was compressed.
124082bf8890SDavid du Colombier *
124182bf8890SDavid du Colombier * Revision 1.9 84/08/16 17:28:00 turtlevax!ken
124282bf8890SDavid du Colombier * Removed scanargs(), getopt(), added .Z extension and unlimited number of
124382bf8890SDavid du Colombier * filenames to compress. Flags may be clustered (-Ddvb12) or separated
124482bf8890SDavid du Colombier * (-D -d -v -b 12), or combination thereof. Modes and other status is
124582bf8890SDavid du Colombier * copied with copystat(). -O bug for 4.2 seems to have disappeared with
124682bf8890SDavid du Colombier * 1.8.
124782bf8890SDavid du Colombier *
124882bf8890SDavid du Colombier * Revision 1.8 84/08/09 23:15:00 joe
124982bf8890SDavid du Colombier * Made it compatible with vax version, installed jim's fixes/enhancements
125082bf8890SDavid du Colombier *
125182bf8890SDavid du Colombier * Revision 1.6 84/08/01 22:08:00 joe
125282bf8890SDavid du Colombier * Sped up algorithm significantly by sorting the compress chain.
125382bf8890SDavid du Colombier *
125482bf8890SDavid du Colombier * Revision 1.5 84/07/13 13:11:00 srd
125582bf8890SDavid du Colombier * Added C version of vax asm routines. Changed structure to arrays to
125682bf8890SDavid du Colombier * save much memory. Do unsigned compares where possible (faster on
125782bf8890SDavid du Colombier * Perkin-Elmer)
125882bf8890SDavid du Colombier *
125982bf8890SDavid du Colombier * Revision 1.4 84/07/05 03:11:11 thomas
126082bf8890SDavid du Colombier * Clean up the code a little and lint it. (Lint complains about all
126182bf8890SDavid du Colombier * the regs used in the asm, but I'm not going to "fix" this.)
126282bf8890SDavid du Colombier *
126382bf8890SDavid du Colombier * Revision 1.3 84/07/05 02:06:54 thomas
126482bf8890SDavid du Colombier * Minor fixes.
126582bf8890SDavid du Colombier *
126682bf8890SDavid du Colombier * Revision 1.2 84/07/05 00:27:27 thomas
126782bf8890SDavid du Colombier * Add variable bit length output.
126882bf8890SDavid du Colombier */
1269