xref: /plan9/sys/src/cmd/compress/compress.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
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