xref: /onnv-gate/usr/src/cmd/compress/compress.c (revision 5331:3047ad28a67b)
1212Scf46844 /*
24774Sas145665  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3212Scf46844  * Use is subject to license terms.
4212Scf46844  */
5212Scf46844 
60Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate 
100Sstevel@tonic-gate /*
110Sstevel@tonic-gate  * Copyright (c) 1986 Regents of the University of California.
120Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
130Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
140Sstevel@tonic-gate  */
150Sstevel@tonic-gate 
160Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
170Sstevel@tonic-gate 
180Sstevel@tonic-gate /*
190Sstevel@tonic-gate  * Compress - data compression program
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate #define	min(a, b)	((a > b) ? b : a)
220Sstevel@tonic-gate 
230Sstevel@tonic-gate /*
240Sstevel@tonic-gate  * machine variants which require cc -Dmachine:  pdp11, z8000, pcxt
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Set USERMEM to the maximum amount of physical user memory available
290Sstevel@tonic-gate  * in bytes.  USERMEM is used to determine the maximum BITS that can be used
300Sstevel@tonic-gate  * for compression.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * SACREDMEM is the amount of physical memory saved for others; compress
330Sstevel@tonic-gate  * will hog the rest.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate #ifndef SACREDMEM
360Sstevel@tonic-gate #define	SACREDMEM	0
370Sstevel@tonic-gate #endif
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #ifndef USERMEM
400Sstevel@tonic-gate #define	USERMEM 	450000	/* default user memory */
410Sstevel@tonic-gate #endif
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #ifdef USERMEM
440Sstevel@tonic-gate #if USERMEM >= (433484+SACREDMEM)
450Sstevel@tonic-gate #define	PBITS	16
460Sstevel@tonic-gate #else
470Sstevel@tonic-gate #if USERMEM >= (229600+SACREDMEM)
480Sstevel@tonic-gate #define	PBITS	15
490Sstevel@tonic-gate #else
500Sstevel@tonic-gate #if USERMEM >= (127536+SACREDMEM)
510Sstevel@tonic-gate #define	PBITS	14
520Sstevel@tonic-gate #else
530Sstevel@tonic-gate #if USERMEM >= (73464+SACREDMEM)
540Sstevel@tonic-gate #define	PBITS	13
550Sstevel@tonic-gate #else
560Sstevel@tonic-gate #define	PBITS	12
570Sstevel@tonic-gate #endif
580Sstevel@tonic-gate #endif
590Sstevel@tonic-gate #endif
600Sstevel@tonic-gate #endif
610Sstevel@tonic-gate #undef USERMEM
620Sstevel@tonic-gate #endif /* USERMEM */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #ifdef PBITS		/* Preferred BITS for this memory size */
650Sstevel@tonic-gate #ifndef BITS
660Sstevel@tonic-gate #define	BITS PBITS
670Sstevel@tonic-gate #endif /* BITS */
680Sstevel@tonic-gate #endif /* PBITS */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #if BITS == 16
710Sstevel@tonic-gate #define	HSIZE	69001		/* 95% occupancy */
720Sstevel@tonic-gate #endif
730Sstevel@tonic-gate #if BITS == 15
740Sstevel@tonic-gate #define	HSIZE	35023		/* 94% occupancy */
750Sstevel@tonic-gate #endif
760Sstevel@tonic-gate #if BITS == 14
770Sstevel@tonic-gate #define	HSIZE	18013		/* 91% occupancy */
780Sstevel@tonic-gate #endif
790Sstevel@tonic-gate #if BITS == 13
800Sstevel@tonic-gate #define	HSIZE	9001		/* 91% occupancy */
810Sstevel@tonic-gate #endif
820Sstevel@tonic-gate #if BITS <= 12
830Sstevel@tonic-gate #define	HSIZE	5003		/* 80% occupancy */
840Sstevel@tonic-gate #endif
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #define	OUTSTACKSIZE	(2<<BITS)
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * a code_int must be able to hold 2**BITS values of type int, and also -1
900Sstevel@tonic-gate  */
910Sstevel@tonic-gate #if BITS > 15
920Sstevel@tonic-gate typedef long int	code_int;
930Sstevel@tonic-gate #else
940Sstevel@tonic-gate typedef int		code_int;
950Sstevel@tonic-gate #endif
960Sstevel@tonic-gate 
970Sstevel@tonic-gate typedef long int	count_int;
980Sstevel@tonic-gate typedef long long	count_long;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate typedef	unsigned char	char_type;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static char_type magic_header[] = { "\037\235" }; /* 1F 9D */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /* Defines for third byte of header */
1050Sstevel@tonic-gate #define	BIT_MASK	0x1f
1060Sstevel@tonic-gate #define	BLOCK_MASK	0x80
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
1090Sstevel@tonic-gate  * a fourth header byte(for expansion).
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate #define	INIT_BITS 9			/* initial number of bits/code */
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * compress.c - File compression ala IEEE Computer, June 1984.
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate static char rcs_ident[] =
1170Sstevel@tonic-gate 	"$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate #include <ctype.h>
1200Sstevel@tonic-gate #include <signal.h>
1210Sstevel@tonic-gate #include <sys/param.h>
1220Sstevel@tonic-gate #include <locale.h>
1230Sstevel@tonic-gate #include <langinfo.h>
1240Sstevel@tonic-gate #include <sys/acl.h>
1250Sstevel@tonic-gate #include <utime.h>
1260Sstevel@tonic-gate #include <libgen.h>
1270Sstevel@tonic-gate #include <setjmp.h>
128789Sahrens #include <aclutils.h>
129*5331Samw #include <libcmdutils.h>
1304774Sas145665 #include "getresponse.h"
1310Sstevel@tonic-gate 
132*5331Samw 
1330Sstevel@tonic-gate static int n_bits;			/* number of bits/code */
1340Sstevel@tonic-gate static int maxbits = BITS;	/* user settable max # bits/code */
1350Sstevel@tonic-gate static code_int maxcode;	/* maximum code, given n_bits */
1360Sstevel@tonic-gate 			/* should NEVER generate this code */
1370Sstevel@tonic-gate static code_int maxmaxcode = 1 << BITS;
1380Sstevel@tonic-gate #define	MAXCODE(n_bits)	((1 << (n_bits)) - 1)
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate static count_int htab [OUTSTACKSIZE];
1410Sstevel@tonic-gate static unsigned short codetab [OUTSTACKSIZE];
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate #define	htabof(i)	htab[i]
1440Sstevel@tonic-gate #define	codetabof(i)	codetab[i]
1450Sstevel@tonic-gate static code_int hsize = HSIZE; /* for dynamic table sizing */
1460Sstevel@tonic-gate static off_t	fsize;	/* file size of input file */
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * To save much memory, we overlay the table used by compress() with those
1500Sstevel@tonic-gate  * used by decompress().  The tab_prefix table is the same size and type
1510Sstevel@tonic-gate  * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
1520Sstevel@tonic-gate  * get this from the beginning of htab.  The output stack uses the rest
1530Sstevel@tonic-gate  * of htab, and contains characters.  There is plenty of room for any
1540Sstevel@tonic-gate  * possible stack (stack used to be 8000 characters).
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate #define	tab_prefixof(i)		codetabof(i)
1580Sstevel@tonic-gate #define	tab_suffixof(i)		((char_type *)(htab))[i]
1590Sstevel@tonic-gate #define	de_stack		((char_type *)&tab_suffixof(1<<BITS))
1600Sstevel@tonic-gate #define	stack_max		((char_type *)&tab_suffixof(OUTSTACKSIZE))
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static code_int free_ent = 0; /* first unused entry */
1630Sstevel@tonic-gate static int newline_needed = 0;
1640Sstevel@tonic-gate static int didnt_shrink = 0;
1650Sstevel@tonic-gate static int perm_stat = 0;	/* permanent status */
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate static code_int getcode();
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/* Use a 3-byte magic number header, unless old file */
1700Sstevel@tonic-gate static int nomagic = 0;
1710Sstevel@tonic-gate 	/* Write output on stdout, suppress messages */
1720Sstevel@tonic-gate static int zcat_flg = 0;	/* use stdout on all files */
1730Sstevel@tonic-gate static int zcat_cmd = 0;	/* zcat cmd */
1740Sstevel@tonic-gate static int use_stdout = 0;	/* set for each file processed */
1750Sstevel@tonic-gate 	/* Don't unlink output file on interrupt */
1760Sstevel@tonic-gate static int precious = 1;
1770Sstevel@tonic-gate static int quiet = 1;	/* don't tell me about compression */
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * block compression parameters -- after all codes are used up,
1810Sstevel@tonic-gate  * and compression rate changes, start over.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate static int block_compress = BLOCK_MASK;
1840Sstevel@tonic-gate static int clear_flg = 0;
1850Sstevel@tonic-gate static long int ratio = 0;
1860Sstevel@tonic-gate #define	CHECK_GAP 10000	/* ratio check interval */
1870Sstevel@tonic-gate static count_long checkpoint = CHECK_GAP;
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * the next two codes should not be changed lightly, as they must not
1900Sstevel@tonic-gate  * lie within the contiguous general code space.
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate #define	FIRST	257	/* first free entry */
1930Sstevel@tonic-gate #define	CLEAR	256	/* table clear output code */
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate static int force = 0;
1960Sstevel@tonic-gate static char ofname [MAXPATHLEN];
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate static int Vflg = 0;
1990Sstevel@tonic-gate static int vflg = 0;
2000Sstevel@tonic-gate static int qflg = 0;
2010Sstevel@tonic-gate static int bflg = 0;
2020Sstevel@tonic-gate static int Fflg = 0;
2030Sstevel@tonic-gate static int dflg = 0;
2040Sstevel@tonic-gate static int cflg = 0;
2050Sstevel@tonic-gate static int Cflg = 0;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate #ifdef DEBUG
2080Sstevel@tonic-gate int verbose = 0;
2090Sstevel@tonic-gate int debug = 0;
2100Sstevel@tonic-gate #endif /* DEBUG */
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate static void (*oldint)();
2130Sstevel@tonic-gate static int bgnd_flag;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static int do_decomp = 0;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate static char *progname;
2180Sstevel@tonic-gate static char *optstr;
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate  * Fix lint errors
2210Sstevel@tonic-gate  */
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate static char *local_basename(char *);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate static int  addDotZ(char *, size_t);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate static void Usage(void);
2280Sstevel@tonic-gate static void cl_block(count_long);
2290Sstevel@tonic-gate static void cl_hash(count_int);
2300Sstevel@tonic-gate static void compress(void);
2310Sstevel@tonic-gate static void copystat(char *, struct stat *, char *);
2320Sstevel@tonic-gate static void decompress(void);
2330Sstevel@tonic-gate static void ioerror(void);
2340Sstevel@tonic-gate static void onintr();
2350Sstevel@tonic-gate static void oops();
2360Sstevel@tonic-gate static void output(code_int);
2370Sstevel@tonic-gate static void prratio(FILE *, count_long, count_long);
2380Sstevel@tonic-gate static void version(void);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate #ifdef DEBUG
2410Sstevel@tonic-gate static int in_stack(int, int);
2420Sstevel@tonic-gate static void dump_tab(void);
2430Sstevel@tonic-gate static void printcodes(void);
2440Sstevel@tonic-gate #endif
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /* For error-handling */
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate static jmp_buf env;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /* For input and ouput */
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate static FILE *inp;		/* the current input file */
2530Sstevel@tonic-gate static FILE *infile;		/* disk-based input stream */
2540Sstevel@tonic-gate static FILE *outp;		/* current output file */
2550Sstevel@tonic-gate static FILE *outfile;		/* disk-based output stream */
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /* For output() */
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate static char buf[BITS];
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate static char_type lmask[9] =
2620Sstevel@tonic-gate 	{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
2630Sstevel@tonic-gate static char_type rmask[9] =
2640Sstevel@tonic-gate 	{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate /* For compress () */
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate static int offset;
2690Sstevel@tonic-gate static count_long bytes_out;	/* length of compressed output */
2700Sstevel@tonic-gate 	/* # of codes output (for debugging) */
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /* For dump_tab() */
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate #define	STACK_SIZE	15000
2750Sstevel@tonic-gate #ifdef DEBUG
2760Sstevel@tonic-gate code_int sorttab[1<<BITS];	/* sorted pointers into htab */
2770Sstevel@tonic-gate #endif
2780Sstevel@tonic-gate 
279*5331Samw /* Extended system attribute support */
280*5331Samw 
281*5331Samw static int saflg = 0;
282*5331Samw 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * *************************************************************
2850Sstevel@tonic-gate  * TAG( main )
2860Sstevel@tonic-gate  *
2870Sstevel@tonic-gate  * Algorithm from "A Technique for High Performance Data Compression",
2880Sstevel@tonic-gate  * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
2890Sstevel@tonic-gate  *
290*5331Samw  * Usage: compress [-dfvc/] [-b bits] [file ...]
2910Sstevel@tonic-gate  * Inputs:
2920Sstevel@tonic-gate  *	-d:	    If given, decompression is done instead.
2930Sstevel@tonic-gate  *
2940Sstevel@tonic-gate  *	-c:	    Write output on stdout, don't remove original.
2950Sstevel@tonic-gate  *
2960Sstevel@tonic-gate  *	-b:	    Parameter limits the max number of bits/code.
2970Sstevel@tonic-gate  *
2980Sstevel@tonic-gate  *	-f:	    Forces output file to be generated, even if one already
2990Sstevel@tonic-gate  *		    exists, and even if no space is saved by compressing.
3000Sstevel@tonic-gate  *		    If -f is not used, the user will be prompted if stdin is
3010Sstevel@tonic-gate  *		    a tty, otherwise, the output file will not be overwritten.
3020Sstevel@tonic-gate  *
303*5331Samw  *	-/	    Copies extended attributes and extended system attributes.
304*5331Samw  *
3050Sstevel@tonic-gate  *  -v:	    Write compression statistics
3060Sstevel@tonic-gate  *
3070Sstevel@tonic-gate  * 	file ...:   Files to be compressed.  If none specified, stdin
3080Sstevel@tonic-gate  *		    is used.
3090Sstevel@tonic-gate  * Outputs:
3100Sstevel@tonic-gate  *	file.Z:	    Compressed form of file with same mode, owner, and utimes
3110Sstevel@tonic-gate  * 	or stdout   (if stdin used as input)
3120Sstevel@tonic-gate  *
3130Sstevel@tonic-gate  * Assumptions:
3140Sstevel@tonic-gate  * When filenames are given, replaces with the compressed version
3150Sstevel@tonic-gate  * (.Z suffix) only if the file decreases in size.
3160Sstevel@tonic-gate  * Algorithm:
3170Sstevel@tonic-gate  * Modified Lempel-Ziv method (LZW).  Basically finds common
3180Sstevel@tonic-gate  * substrings and replaces them with a variable size code.  This is
3190Sstevel@tonic-gate  * deterministic, and can be done on the fly.  Thus, the decompression
3200Sstevel@tonic-gate  * procedure needs no input table, but tracks the way the table was built.
3210Sstevel@tonic-gate  */
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate int
main(int argc,char * argv[])3240Sstevel@tonic-gate main(int argc, char *argv[])
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 	int overwrite = 0;	/* Do not overwrite unless given -f flag */
3270Sstevel@tonic-gate 	char tempname[MAXPATHLEN];
3280Sstevel@tonic-gate 	char line[LINE_MAX];
3290Sstevel@tonic-gate 	char **filelist, **fileptr;
3300Sstevel@tonic-gate 	char *cp;
3310Sstevel@tonic-gate 	struct stat statbuf;
3320Sstevel@tonic-gate 	struct stat ostatbuf;
3330Sstevel@tonic-gate 	int ch;				/* XCU4 */
3344774Sas145665 	char	*p;
3350Sstevel@tonic-gate 	extern int optind, optopt;
3360Sstevel@tonic-gate 	extern char *optarg;
3370Sstevel@tonic-gate 	int dash_count = 0;		/* times "-" is on cmdline */
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/* XCU4 changes */
3400Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3410Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
3420Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
3430Sstevel@tonic-gate #endif
3440Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3450Sstevel@tonic-gate 
3464774Sas145665 	if (init_yes() < 0) {
3474774Sas145665 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
3484774Sas145665 		    strerror(errno));
3494774Sas145665 		exit(1);
3504774Sas145665 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/* This bg check only works for sh. */
3530Sstevel@tonic-gate 	if ((oldint = signal(SIGINT, SIG_IGN)) != SIG_IGN) {
3540Sstevel@tonic-gate 		(void) signal(SIGINT, onintr);
3550Sstevel@tonic-gate 		(void) signal(SIGSEGV, oops);
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 	bgnd_flag = oldint != SIG_DFL;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/* Allocate room for argv + "-" (if stdin needs to be added) */
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	filelist = fileptr = (char **)(malloc((argc + 1) * sizeof (*argv)));
3620Sstevel@tonic-gate 	*filelist = NULL;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if ((cp = rindex(argv[0], '/')) != 0) {
3650Sstevel@tonic-gate 		cp++;
3660Sstevel@tonic-gate 	} else {
3670Sstevel@tonic-gate 		cp = argv[0];
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (strcmp(cp, "uncompress") == 0) {
3710Sstevel@tonic-gate 		do_decomp = 1;
3720Sstevel@tonic-gate 	} else if (strcmp(cp, "zcat") == 0) {
3730Sstevel@tonic-gate 		do_decomp = 1;
3740Sstevel@tonic-gate 		zcat_cmd = zcat_flg = 1;
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	progname = local_basename(argv[0]);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	/*
3800Sstevel@tonic-gate 	 * Argument Processing
3810Sstevel@tonic-gate 	 * All flags are optional.
3820Sstevel@tonic-gate 	 * -D = > debug
3830Sstevel@tonic-gate 	 * -V = > print Version; debug verbose
3840Sstevel@tonic-gate 	 * -d = > do_decomp
3850Sstevel@tonic-gate 	 * -v = > unquiet
3860Sstevel@tonic-gate 	 * -f = > force overwrite of output file
3870Sstevel@tonic-gate 	 * -n = > no header: useful to uncompress old files
3880Sstevel@tonic-gate 	 * -b	  maxbits => maxbits.  If -b is specified,
3890Sstevel@tonic-gate 	 *	  then maxbits MUST be given also.
3900Sstevel@tonic-gate 	 * -c = > cat all output to stdout
3910Sstevel@tonic-gate 	 * -C = > generate output compatible with compress 2.0.
3920Sstevel@tonic-gate 	 * if a string is left, must be an input filename.
3930Sstevel@tonic-gate 	 */
3940Sstevel@tonic-gate #ifdef DEBUG
395*5331Samw 	optstr = "b:cCdDfFnqvV/";
3960Sstevel@tonic-gate #else
397*5331Samw 	optstr = "b:cCdfFnqvV/";
3980Sstevel@tonic-gate #endif
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	while ((ch = getopt(argc, argv, optstr)) != EOF) {
4010Sstevel@tonic-gate 		/* Process all flags in this arg */
4020Sstevel@tonic-gate 		switch (ch) {
4030Sstevel@tonic-gate #ifdef DEBUG
4040Sstevel@tonic-gate 			case 'D':
4050Sstevel@tonic-gate 				debug = 1;
4060Sstevel@tonic-gate 				break;
4070Sstevel@tonic-gate 			case 'V':
4080Sstevel@tonic-gate 				verbose = 1;
4090Sstevel@tonic-gate 				version();
4100Sstevel@tonic-gate 				break;
4110Sstevel@tonic-gate #else
4120Sstevel@tonic-gate 			case 'V':
4130Sstevel@tonic-gate 				version();
4140Sstevel@tonic-gate 				Vflg++;
4150Sstevel@tonic-gate 				break;
4160Sstevel@tonic-gate #endif /* DEBUG */
4170Sstevel@tonic-gate 			case 'v':
4180Sstevel@tonic-gate 				quiet = 0;
4190Sstevel@tonic-gate 				vflg++;
4200Sstevel@tonic-gate 				break;
4210Sstevel@tonic-gate 			case 'd':
4220Sstevel@tonic-gate 				do_decomp = 1;
4230Sstevel@tonic-gate 				dflg++;
4240Sstevel@tonic-gate 				break;
4250Sstevel@tonic-gate 			case 'f':
4260Sstevel@tonic-gate 			case 'F':
4270Sstevel@tonic-gate 				Fflg++;
4280Sstevel@tonic-gate 				overwrite = 1;
4290Sstevel@tonic-gate 				force = 1;
4300Sstevel@tonic-gate 				break;
4310Sstevel@tonic-gate 			case 'n':
4320Sstevel@tonic-gate 				nomagic = 1;
4330Sstevel@tonic-gate 				break;
4340Sstevel@tonic-gate 			case 'C':
4350Sstevel@tonic-gate 				Cflg++;
4360Sstevel@tonic-gate 				block_compress = 0;
4370Sstevel@tonic-gate 				break;
4380Sstevel@tonic-gate 			case 'b':
4390Sstevel@tonic-gate 				bflg++;
4400Sstevel@tonic-gate 				p = optarg;
4410Sstevel@tonic-gate 				if (!p) {
4420Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
4434774Sas145665 					    "Missing maxbits\n"));
4440Sstevel@tonic-gate 					Usage();
4450Sstevel@tonic-gate 					exit(1);
4460Sstevel@tonic-gate 				}
4470Sstevel@tonic-gate 				maxbits = strtoul(optarg, &p, 10);
4480Sstevel@tonic-gate 				if (*p) {
4490Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
4504774Sas145665 					    "Missing maxbits\n"));
4510Sstevel@tonic-gate 					Usage();
4520Sstevel@tonic-gate 					exit(1);
4530Sstevel@tonic-gate 				}
4540Sstevel@tonic-gate 				break;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 			case 'c':
4570Sstevel@tonic-gate 				cflg++;
4580Sstevel@tonic-gate 				zcat_flg = 1;
4590Sstevel@tonic-gate 				break;
4600Sstevel@tonic-gate 			case 'q':
4610Sstevel@tonic-gate 				qflg++;
4620Sstevel@tonic-gate 				quiet = 1;
4630Sstevel@tonic-gate 				break;
464*5331Samw 			case '/':
465*5331Samw 				saflg++;
466*5331Samw 				break;
4670Sstevel@tonic-gate 			default:
4680Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
4694774Sas145665 				    "Unknown flag: '%c'\n"), optopt);
4700Sstevel@tonic-gate 				Usage();
4710Sstevel@tonic-gate 				exit(1);
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 	} /* while */
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/*
4760Sstevel@tonic-gate 	 * Validate zcat syntax
4770Sstevel@tonic-gate 	 */
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	if (zcat_cmd && (Fflg | Cflg | cflg |
4800Sstevel@tonic-gate 	    bflg | qflg | dflg | nomagic)) {
4810Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
4824774Sas145665 		    "Invalid Option\n"));
4830Sstevel@tonic-gate 		Usage();
4840Sstevel@tonic-gate 		exit(1);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/*
4880Sstevel@tonic-gate 	 * Process the file list
4890Sstevel@tonic-gate 	 */
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	for (; optind < argc; optind++) {
4920Sstevel@tonic-gate 		if (strcmp(argv[optind], "-") == 0) {
4930Sstevel@tonic-gate 			dash_count++;
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		*fileptr++ = argv[optind];	/* Build input file list */
4970Sstevel@tonic-gate 		*fileptr = NULL;
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	if (dash_count > 1) {
5010Sstevel@tonic-gate 		(void) fprintf(stderr,
5024774Sas145665 		    gettext("%s may only appear once in the file"
5034774Sas145665 		    " list\n"), "\"-\"");
5040Sstevel@tonic-gate 		exit(1);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (fileptr - filelist == 0) {
5080Sstevel@tonic-gate 		*fileptr++ = "-";
5090Sstevel@tonic-gate 		*fileptr = NULL;
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if (fileptr - filelist > 1 && cflg && !do_decomp) {
5130Sstevel@tonic-gate 		(void) fprintf(stderr,
5144774Sas145665 		    gettext("compress: only one file may be compressed"
5154774Sas145665 		    " to stdout\n"));
5160Sstevel@tonic-gate 		exit(1);
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	if (maxbits < INIT_BITS)
5200Sstevel@tonic-gate 		maxbits = INIT_BITS;
5210Sstevel@tonic-gate 	if (maxbits > BITS)
5220Sstevel@tonic-gate 		maxbits = BITS;
5230Sstevel@tonic-gate 	maxmaxcode = 1 << maxbits;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	/* Need to open something to close with freopen later */
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	if ((infile = fopen("/dev/null", "r")) == NULL) {
5280Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error opening /dev/null for "
5294774Sas145665 		    "input\n"));
5300Sstevel@tonic-gate 		exit(1);
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	if ((outfile = fopen("/dev/null", "w")) == NULL) {
5340Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error opening /dev/null for "
5354774Sas145665 		    "output\n"));
5360Sstevel@tonic-gate 		exit(1);
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	for (fileptr = filelist; *fileptr; fileptr++) {
5400Sstevel@tonic-gate 		int jmpval = 0;
5410Sstevel@tonic-gate 		didnt_shrink = 0;
5420Sstevel@tonic-gate 		newline_needed = 0;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		if (do_decomp) {
5450Sstevel@tonic-gate 			/* DECOMPRESSION */
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 			if (strcmp(*fileptr, "-") == 0) {
5480Sstevel@tonic-gate 				/* process stdin */
5490Sstevel@tonic-gate 				inp = stdin;
5500Sstevel@tonic-gate 				outp = stdout;
5510Sstevel@tonic-gate 				use_stdout = 1;
5520Sstevel@tonic-gate 				*fileptr = "stdin"; /* for error messages */
5530Sstevel@tonic-gate 			} else {
5540Sstevel@tonic-gate 				/* process the named file */
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 				inp = infile;
5570Sstevel@tonic-gate 				outp = outfile;
5580Sstevel@tonic-gate 				use_stdout = 0;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 				if (zcat_flg) {
5610Sstevel@tonic-gate 					use_stdout = 1;
5620Sstevel@tonic-gate 					outp = stdout;
5630Sstevel@tonic-gate 				}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 				/* Check for .Z suffix */
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 				if (strcmp(*fileptr +
5680Sstevel@tonic-gate 				    strlen(*fileptr) - 2, ".Z") != 0) {
5690Sstevel@tonic-gate 					/* No .Z: tack one on */
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 					if (strlcpy(tempname, *fileptr,
5724774Sas145665 					    sizeof (tempname)) >=
5734774Sas145665 					    sizeof (tempname)) {
5740Sstevel@tonic-gate 						(void) fprintf(stderr,
5750Sstevel@tonic-gate 						    gettext("%s: filename "
5764774Sas145665 						    "too long\n"),
5774774Sas145665 						    *fileptr);
5780Sstevel@tonic-gate 						perm_stat = 1;
5790Sstevel@tonic-gate 						continue;
5800Sstevel@tonic-gate 					}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 					if (addDotZ(tempname,
5830Sstevel@tonic-gate 					    sizeof (tempname)) < 0) {
5840Sstevel@tonic-gate 						perm_stat = 1;
5850Sstevel@tonic-gate 						continue;
5860Sstevel@tonic-gate 					}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 					*fileptr = tempname;
5890Sstevel@tonic-gate 				}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 				/* Open input file */
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 				if (stat(*fileptr, &statbuf) < 0) {
5940Sstevel@tonic-gate 					perror(*fileptr);
5950Sstevel@tonic-gate 					perm_stat = 1;
5960Sstevel@tonic-gate 					continue;
5970Sstevel@tonic-gate 				}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 				if ((freopen(*fileptr, "r", inp)) == NULL) {
6000Sstevel@tonic-gate 					perror(*fileptr);
6010Sstevel@tonic-gate 					perm_stat = 1;
6020Sstevel@tonic-gate 					continue;
6030Sstevel@tonic-gate 				}
6040Sstevel@tonic-gate 			}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 			/* Check the magic number */
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			if (nomagic == 0) {
6090Sstevel@tonic-gate 				if ((getc(inp) !=
6100Sstevel@tonic-gate 				    (magic_header[0] & 0xFF)) ||
6110Sstevel@tonic-gate 				    (getc(inp) !=
6120Sstevel@tonic-gate 				    (magic_header[1] & 0xFF))) {
6130Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
6144774Sas145665 					    "%s: not in compressed "
6154774Sas145665 					    "format\n"),
6164774Sas145665 					    *fileptr);
6170Sstevel@tonic-gate 					perm_stat = 1;
6180Sstevel@tonic-gate 					continue;
6190Sstevel@tonic-gate 				}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 				/* set -b from file */
6220Sstevel@tonic-gate 				if ((maxbits = getc(inp)) == EOF &&
6230Sstevel@tonic-gate 				    ferror(inp)) {
6240Sstevel@tonic-gate 					perror(*fileptr);
6250Sstevel@tonic-gate 					perm_stat = 1;
6260Sstevel@tonic-gate 					continue;
6270Sstevel@tonic-gate 				}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 				block_compress = maxbits & BLOCK_MASK;
6300Sstevel@tonic-gate 				maxbits &= BIT_MASK;
6310Sstevel@tonic-gate 				maxmaxcode = 1 << maxbits;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 				if (maxbits > BITS) {
6340Sstevel@tonic-gate 					(void) fprintf(stderr,
6354774Sas145665 					    gettext("%s: compressed "
6364774Sas145665 					    "with %d bits, "
6374774Sas145665 					    "can only handle"
6384774Sas145665 					    " %d bits\n"),
6394774Sas145665 					    *fileptr, maxbits, BITS);
6400Sstevel@tonic-gate 					perm_stat = 1;
6410Sstevel@tonic-gate 					continue;
6420Sstevel@tonic-gate 				}
6430Sstevel@tonic-gate 			}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 			if (!use_stdout) {
6460Sstevel@tonic-gate 				/* Generate output filename */
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 				if (strlcpy(ofname, *fileptr,
6494774Sas145665 				    sizeof (ofname)) >=
6500Sstevel@tonic-gate 				    sizeof (ofname)) {
6510Sstevel@tonic-gate 					(void) fprintf(stderr,
6524774Sas145665 					    gettext("%s: filename "
6534774Sas145665 					    "too long\n"),
6544774Sas145665 					    *fileptr);
6550Sstevel@tonic-gate 					perm_stat = 1;
6560Sstevel@tonic-gate 					continue;
6570Sstevel@tonic-gate 				}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 				/* Strip off .Z */
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 				ofname[strlen(*fileptr) - 2] = '\0';
6620Sstevel@tonic-gate 			}
6630Sstevel@tonic-gate 		} else {
6640Sstevel@tonic-gate 			/* COMPRESSION */
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 			if (strcmp(*fileptr, "-") == 0) {
6670Sstevel@tonic-gate 				/* process stdin */
6680Sstevel@tonic-gate 				inp = stdin;
6690Sstevel@tonic-gate 				outp = stdout;
6700Sstevel@tonic-gate 				use_stdout = 1;
6710Sstevel@tonic-gate 				*fileptr = "stdin"; /* for error messages */
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 				/* Use the largest possible hash table */
6740Sstevel@tonic-gate 				hsize =  HSIZE;
6750Sstevel@tonic-gate 			} else {
6760Sstevel@tonic-gate 				/* process the named file */
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 				inp = infile;
6790Sstevel@tonic-gate 				outp = outfile;
6800Sstevel@tonic-gate 				use_stdout = 0;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 				if (zcat_flg) {
6830Sstevel@tonic-gate 					use_stdout = 1;
6840Sstevel@tonic-gate 					outp = stdout;
6850Sstevel@tonic-gate 				}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 				if (strcmp(*fileptr +
6880Sstevel@tonic-gate 				    strlen(*fileptr) - 2, ".Z") == 0) {
6890Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
6904774Sas145665 					    "%s: already has .Z "
6914774Sas145665 					    "suffix -- no change\n"),
6924774Sas145665 					    *fileptr);
6930Sstevel@tonic-gate 					perm_stat = 1;
6940Sstevel@tonic-gate 					continue;
6950Sstevel@tonic-gate 				}
6960Sstevel@tonic-gate 				/* Open input file */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 				if (stat(*fileptr, &statbuf) < 0) {
6990Sstevel@tonic-gate 					perror(*fileptr);
7000Sstevel@tonic-gate 					perm_stat = 1;
7010Sstevel@tonic-gate 					continue;
7020Sstevel@tonic-gate 				}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 				if ((freopen(*fileptr, "r", inp)) == NULL) {
7050Sstevel@tonic-gate 					perror(*fileptr);
7060Sstevel@tonic-gate 					perm_stat = 1;
7070Sstevel@tonic-gate 					continue;
7080Sstevel@tonic-gate 				}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 				fsize = (off_t)statbuf.st_size;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 				/*
7130Sstevel@tonic-gate 				 * tune hash table size for small
7140Sstevel@tonic-gate 				 * files -- ad hoc,
7150Sstevel@tonic-gate 				 * but the sizes match earlier #defines, which
7160Sstevel@tonic-gate 				 * serve as upper bounds on the number of
7170Sstevel@tonic-gate 				 * output codes.
7180Sstevel@tonic-gate 				 */
7190Sstevel@tonic-gate 				hsize = HSIZE;
7200Sstevel@tonic-gate 				if (fsize < (1 << 12))
7210Sstevel@tonic-gate 					hsize = min(5003, HSIZE);
7220Sstevel@tonic-gate 				else if (fsize < (1 << 13))
7230Sstevel@tonic-gate 					hsize = min(9001, HSIZE);
7240Sstevel@tonic-gate 				else if (fsize < (1 << 14))
7250Sstevel@tonic-gate 					hsize = min(18013, HSIZE);
7260Sstevel@tonic-gate 				else if (fsize < (1 << 15))
7270Sstevel@tonic-gate 					hsize = min(35023, HSIZE);
7280Sstevel@tonic-gate 				else if (fsize < 47000)
7290Sstevel@tonic-gate 					hsize = min(50021, HSIZE);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 				if (!use_stdout) {
7320Sstevel@tonic-gate 					/* Generate output filename */
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 					if (strlcpy(ofname, *fileptr,
7354774Sas145665 					    sizeof (ofname)) >=
7364774Sas145665 					    sizeof (ofname)) {
7370Sstevel@tonic-gate 						(void) fprintf(stderr,
7380Sstevel@tonic-gate 						    gettext("%s: filename "
7394774Sas145665 						    "too long\n"),
7404774Sas145665 						    *fileptr);
7410Sstevel@tonic-gate 						perm_stat = 1;
7420Sstevel@tonic-gate 						continue;
7430Sstevel@tonic-gate 					}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 					if (addDotZ(ofname,
7464774Sas145665 					    sizeof (ofname)) < 0) {
7470Sstevel@tonic-gate 						perm_stat = 1;
7480Sstevel@tonic-gate 						continue;
7490Sstevel@tonic-gate 					}
7500Sstevel@tonic-gate 				}
7510Sstevel@tonic-gate 			}
7520Sstevel@tonic-gate 		}	/* if (do_decomp) */
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 		/* Check for overwrite of existing file */
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		if (!overwrite && !use_stdout) {
7570Sstevel@tonic-gate 			if (stat(ofname, &ostatbuf) == 0) {
7580Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
7594774Sas145665 				    "%s already exists;"), ofname);
7600Sstevel@tonic-gate 				if (bgnd_flag == 0 && isatty(2)) {
7610Sstevel@tonic-gate 					int cin;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
7644774Sas145665 					    " do you wish to overwr"
7654774Sas145665 					    "ite %s (%s or %s)? "),
7664774Sas145665 					    ofname, yesstr, nostr);
7670Sstevel@tonic-gate 					(void) fflush(stderr);
7684774Sas145665 					for (cin = 0; cin < LINE_MAX; cin++)
7690Sstevel@tonic-gate 						line[cin] = 0;
7700Sstevel@tonic-gate 					(void) read(2, line, LINE_MAX);
7710Sstevel@tonic-gate 
7724774Sas145665 					if (yes_check(line) == 0) {
7730Sstevel@tonic-gate 						(void) fprintf(stderr,
7744774Sas145665 						    gettext(
7754774Sas145665 						    "\tnot overwri"
7764774Sas145665 						    "tten\n"));
7770Sstevel@tonic-gate 						continue;
7780Sstevel@tonic-gate 					}
7790Sstevel@tonic-gate 				} else {
7800Sstevel@tonic-gate 					/*
7810Sstevel@tonic-gate 					 * XPG4: Assertion 1009
7820Sstevel@tonic-gate 					 * Standard input is not
7830Sstevel@tonic-gate 					 * terminal, and no '-f',
7840Sstevel@tonic-gate 					 * and file exists.
7850Sstevel@tonic-gate 					 */
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
7884774Sas145665 					    "%s: File exists, -f not"
7894774Sas145665 					    " specified, and ru"
7904774Sas145665 					    "nning in the backgro"
7914774Sas145665 					    "und.\n"), *fileptr);
7920Sstevel@tonic-gate 					perm_stat = 1;
7930Sstevel@tonic-gate 					continue;
7940Sstevel@tonic-gate 				}
7950Sstevel@tonic-gate 			}
7960Sstevel@tonic-gate 		}
7970Sstevel@tonic-gate 		if (!use_stdout) {
798*5331Samw 			if ((pathconf(ofname, _PC_XATTR_EXISTS) == 1) ||
799*5331Samw 			    (saflg && sysattr_support(ofname,
800*5331Samw 			    _PC_SATTR_EXISTS) == 1)) {
8010Sstevel@tonic-gate 				(void) unlink(ofname);
8020Sstevel@tonic-gate 			}
8030Sstevel@tonic-gate 			/* Open output file */
8040Sstevel@tonic-gate 			if (freopen(ofname, "w", outp) == NULL) {
8050Sstevel@tonic-gate 				perror(ofname);
8060Sstevel@tonic-gate 				perm_stat = 1;
8070Sstevel@tonic-gate 				continue;
8080Sstevel@tonic-gate 			}
8090Sstevel@tonic-gate 			precious = 0;
8100Sstevel@tonic-gate 			if (!quiet) {
8110Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: ",
8124774Sas145665 				    *fileptr);
8130Sstevel@tonic-gate 				newline_needed = 1;
8140Sstevel@tonic-gate 			}
8150Sstevel@tonic-gate 		} else if (!quiet && !do_decomp) {
8160Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ",
8174774Sas145665 			    *fileptr);
8180Sstevel@tonic-gate 				newline_needed = 1;
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 		/* Actually do the compression/decompression */
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 		if ((jmpval = setjmp(env)) == 0) {
8240Sstevel@tonic-gate 			/* We'll see how things go */
8250Sstevel@tonic-gate #ifndef DEBUG
8260Sstevel@tonic-gate 			if (do_decomp == 0)  {
8270Sstevel@tonic-gate 				compress();
8280Sstevel@tonic-gate 			} else {
8290Sstevel@tonic-gate 				decompress();
8300Sstevel@tonic-gate 			}
8310Sstevel@tonic-gate #else
8320Sstevel@tonic-gate 			if (do_decomp == 0)  {
8330Sstevel@tonic-gate 				compress();
8340Sstevel@tonic-gate 			} else if (debug == 0)  {
8350Sstevel@tonic-gate 				decompress();
8360Sstevel@tonic-gate 			} else {
8370Sstevel@tonic-gate 				printcodes();
8380Sstevel@tonic-gate 			}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 			if (verbose) {
8410Sstevel@tonic-gate 				dump_tab();
8420Sstevel@tonic-gate 			}
8430Sstevel@tonic-gate #endif
8440Sstevel@tonic-gate 		} else {
8450Sstevel@tonic-gate 			/*
8460Sstevel@tonic-gate 			 * Things went badly - clean up and go on.
8470Sstevel@tonic-gate 			 * jmpval's values break down as follows:
8480Sstevel@tonic-gate 			 *   1 == message determined by ferror() values.
8490Sstevel@tonic-gate 			 *   2 == input problem message needed.
8500Sstevel@tonic-gate 			 *   3 == output problem message needed.
8510Sstevel@tonic-gate 			 */
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 			if (ferror(inp) || jmpval == 2) {
8540Sstevel@tonic-gate 				if (do_decomp) {
8550Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
8564774Sas145665 					    "uncompress: %s: corrupt"
8574774Sas145665 					    " input\n"), *fileptr);
8580Sstevel@tonic-gate 				} else {
8590Sstevel@tonic-gate 					perror(*fileptr);
8600Sstevel@tonic-gate 				}
8610Sstevel@tonic-gate 			}
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 			if (ferror(outp) || jmpval == 3) {
8640Sstevel@tonic-gate 				/* handle output errors */
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 				if (use_stdout) {
8670Sstevel@tonic-gate 					perror("");
8680Sstevel@tonic-gate 				} else {
8690Sstevel@tonic-gate 					perror(ofname);
8700Sstevel@tonic-gate 				}
8710Sstevel@tonic-gate 			}
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 			if (ofname[0] != '\0') {
8740Sstevel@tonic-gate 				if (unlink(ofname) < 0)  {
8750Sstevel@tonic-gate 					perror(ofname);
8760Sstevel@tonic-gate 				}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 				ofname[0] = '\0';
8790Sstevel@tonic-gate 			}
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 			perm_stat = 1;
8820Sstevel@tonic-gate 			continue;
8830Sstevel@tonic-gate 		}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 		/* Things went well */
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 		if (!use_stdout) {
8880Sstevel@tonic-gate 				/* Copy stats */
8890Sstevel@tonic-gate 			copystat(*fileptr, &statbuf, ofname);
8900Sstevel@tonic-gate 			precious = 1;
8910Sstevel@tonic-gate 			if (newline_needed) {
8920Sstevel@tonic-gate 				(void) putc('\n', stderr);
8930Sstevel@tonic-gate 			}
8940Sstevel@tonic-gate 			/*
8950Sstevel@tonic-gate 			 * Print the info. for unchanged file
8960Sstevel@tonic-gate 			 * when no -v
8970Sstevel@tonic-gate 			 */
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 			if (didnt_shrink) {
9000Sstevel@tonic-gate 				if (!force && perm_stat == 0) {
9010Sstevel@tonic-gate 					if (quiet) {
9020Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
9034774Sas145665 						    "%s: -- file "
9044774Sas145665 						    "unchanged\n"),
9054774Sas145665 						    *fileptr);
9060Sstevel@tonic-gate 					}
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 					perm_stat = 2;
9090Sstevel@tonic-gate 				}
9100Sstevel@tonic-gate 			}
9110Sstevel@tonic-gate 		} else {
9120Sstevel@tonic-gate 			if (didnt_shrink && !force && perm_stat == 0) {
9130Sstevel@tonic-gate 				perm_stat = 2;
9140Sstevel@tonic-gate 			}
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 			if (newline_needed) {
9170Sstevel@tonic-gate 				(void) fprintf(stderr, "\n");
9180Sstevel@tonic-gate 			}
9190Sstevel@tonic-gate 		}
9200Sstevel@tonic-gate 	}	/* for */
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	return (perm_stat);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate static void
cinterr(int hshift)9260Sstevel@tonic-gate cinterr(int hshift)
9270Sstevel@tonic-gate {
9280Sstevel@tonic-gate 	/* we have exceeded the hash table */
9290Sstevel@tonic-gate 	(void) fprintf(stderr,
9304774Sas145665 	    "internal error: hashtable exceeded - hsize = %ld\n", hsize);
9310Sstevel@tonic-gate 	(void) fprintf(stderr, "hshift = %d, %d\n", hshift, (1 << hshift) -1);
9320Sstevel@tonic-gate 	(void) fprintf(stderr, "maxbits = %d\n", maxbits);
9330Sstevel@tonic-gate 	(void) fprintf(stderr, "n_bits = %d\n", n_bits);
9340Sstevel@tonic-gate 	(void) fprintf(stderr, "maxcode = %ld\n", maxcode);
9350Sstevel@tonic-gate 	longjmp(env, 1);
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate static code_int
adjusti(code_int i,code_int hsize_reg)9390Sstevel@tonic-gate adjusti(code_int i, code_int hsize_reg)
9400Sstevel@tonic-gate {
9410Sstevel@tonic-gate 	while (i < 0) {
9420Sstevel@tonic-gate 		i += hsize_reg;
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	while (i >= hsize_reg) {
9460Sstevel@tonic-gate 		i -= hsize_reg;
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 	return (i);
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate /*
9520Sstevel@tonic-gate  * compress inp to outp
9530Sstevel@tonic-gate  *
9540Sstevel@tonic-gate  * Algorithm:  use open addressing double hashing(no chaining) on the
9550Sstevel@tonic-gate  * prefix code / next character combination.  We do a variant of Knuth's
9560Sstevel@tonic-gate  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
9570Sstevel@tonic-gate  * secondary probe.  Here, the modular division first probe is gives way
9580Sstevel@tonic-gate  * to a faster exclusive-or manipulation.  Also do block compression with
9590Sstevel@tonic-gate  * an adaptive reset, whereby the code table is cleared when the compression
9600Sstevel@tonic-gate  * ratio decreases, but after the table fills.  The variable-length output
9610Sstevel@tonic-gate  * codes are re-sized at this point, and a special CLEAR code is generated
9620Sstevel@tonic-gate  * for the decompressor.  Late addition:  construct the table according to
9630Sstevel@tonic-gate  * file size for noticeable speed improvement on small files.  Please direct
9640Sstevel@tonic-gate  * questions about this implementation to ames!jaw.
9650Sstevel@tonic-gate  */
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate static void
compress()9680Sstevel@tonic-gate compress()
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	long fcode;
9710Sstevel@tonic-gate 	code_int i = 0;
9720Sstevel@tonic-gate 	int c;
9730Sstevel@tonic-gate 	code_int ent;
9740Sstevel@tonic-gate 	int disp;
9750Sstevel@tonic-gate 	code_int hsize_reg;
9760Sstevel@tonic-gate 	int hshift;
9770Sstevel@tonic-gate 	int probecnt;
9780Sstevel@tonic-gate 	count_long in_count;
9790Sstevel@tonic-gate 	uint32_t inchi, inclo;
9800Sstevel@tonic-gate 	int maxbits_reg;
9810Sstevel@tonic-gate 	FILE *fin = inp;
9820Sstevel@tonic-gate #ifdef DEBUG
9830Sstevel@tonic-gate 	count_long out_count = 0;
9840Sstevel@tonic-gate #endif
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	if (nomagic == 0) {
9870Sstevel@tonic-gate 		if ((putc(magic_header[0], outp) == EOF ||
9880Sstevel@tonic-gate 		    putc(magic_header[1], outp) == EOF ||
9890Sstevel@tonic-gate 		    putc((char)(maxbits | block_compress),
9904774Sas145665 		    outp) == EOF) &&
9910Sstevel@tonic-gate 		    ferror(outp)) {
9920Sstevel@tonic-gate 			ioerror();
9930Sstevel@tonic-gate 		}
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	offset = 0;
9970Sstevel@tonic-gate 	bytes_out = 3;		/* includes 3-byte header mojo */
9980Sstevel@tonic-gate 	clear_flg = 0;
9990Sstevel@tonic-gate 	ratio = 0;
10000Sstevel@tonic-gate 	in_count = 1;
10010Sstevel@tonic-gate 	inchi = 0;
10020Sstevel@tonic-gate 	inclo = 1;
10030Sstevel@tonic-gate 	checkpoint = CHECK_GAP;
10040Sstevel@tonic-gate 	maxcode = MAXCODE(n_bits = INIT_BITS);
10050Sstevel@tonic-gate 	free_ent = ((block_compress) ? FIRST : 256);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if ((ent = getc(fin)) == EOF && ferror(fin)) {
10080Sstevel@tonic-gate 		ioerror();
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	hshift = 0;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	for (fcode = (long)hsize;  fcode < 65536L; fcode *= 2L)
10140Sstevel@tonic-gate 		hshift++;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	hshift = 8 - hshift;		/* set hash code range bound */
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	hsize_reg = hsize;
10190Sstevel@tonic-gate 	maxbits_reg = maxbits;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	cl_hash((count_int) hsize_reg);		/* clear hash table */
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	while ((c = getc(fin)) != EOF) {
10240Sstevel@tonic-gate 		if (++inclo == 0)
10250Sstevel@tonic-gate 			inchi++;
10260Sstevel@tonic-gate 		fcode = (long)(((long)c << maxbits_reg) + ent);
10270Sstevel@tonic-gate 		i = ((c << hshift) ^ ent);	/* xor hashing */
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 		if ((unsigned int)i >= hsize_reg)
10300Sstevel@tonic-gate 			i = adjusti(i, hsize_reg);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		if (htabof(i) == fcode) {
10330Sstevel@tonic-gate 			ent = codetabof(i);
10340Sstevel@tonic-gate 			continue;
10350Sstevel@tonic-gate 		} else if ((long)htabof(i) < 0) {
10360Sstevel@tonic-gate 			/* empty slot */
10370Sstevel@tonic-gate 			goto nomatch;
10380Sstevel@tonic-gate 		}
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 		/* secondary hash (after G. Knott) */
10410Sstevel@tonic-gate 		disp = hsize_reg - i;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 		if (i == 0) {
10440Sstevel@tonic-gate 			disp = 1;
10450Sstevel@tonic-gate 		}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		probecnt = 0;
10480Sstevel@tonic-gate 	probe:
10490Sstevel@tonic-gate 		if (++probecnt > hsize_reg)
10500Sstevel@tonic-gate 			cinterr(hshift);
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 		if ((i -= disp) < 0) {
10530Sstevel@tonic-gate 			while (i < 0)
10540Sstevel@tonic-gate 				i += hsize_reg;
10550Sstevel@tonic-gate 		}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		if (htabof(i) == fcode) {
10580Sstevel@tonic-gate 			ent = codetabof(i);
10590Sstevel@tonic-gate 			continue;
10600Sstevel@tonic-gate 		}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		if ((long)htabof(i) > 0) {
10630Sstevel@tonic-gate 			goto probe;
10640Sstevel@tonic-gate 		}
10650Sstevel@tonic-gate 	nomatch:
10660Sstevel@tonic-gate 		output((code_int) ent);
10670Sstevel@tonic-gate #ifdef DEBUG
10680Sstevel@tonic-gate 		out_count++;
10690Sstevel@tonic-gate #endif
10700Sstevel@tonic-gate 		ent = c;
10710Sstevel@tonic-gate 		if (free_ent < maxmaxcode) {
10720Sstevel@tonic-gate 			codetabof(i) = free_ent++;
10730Sstevel@tonic-gate 			/* code -> hashtable */
10740Sstevel@tonic-gate 			htabof(i) = fcode;
10750Sstevel@tonic-gate 		} else {
10760Sstevel@tonic-gate 			in_count = ((long long)inchi<<32|inclo);
10770Sstevel@tonic-gate 			if ((count_long)in_count >=
10780Sstevel@tonic-gate 			    (count_long)checkpoint && block_compress) {
10790Sstevel@tonic-gate 				cl_block(in_count);
10800Sstevel@tonic-gate 			}
10810Sstevel@tonic-gate 		}
10820Sstevel@tonic-gate 	}
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	in_count = ((long long)inchi<<32|inclo);
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	if (ferror(fin) != 0) {
10870Sstevel@tonic-gate 		ioerror();
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * Put out the final code.
10920Sstevel@tonic-gate 	 */
10930Sstevel@tonic-gate 	output((code_int)ent);
10940Sstevel@tonic-gate #ifdef DEBUG
10950Sstevel@tonic-gate 	out_count++;
10960Sstevel@tonic-gate #endif
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	output((code_int)-1);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	/*
11010Sstevel@tonic-gate 	 * Print out stats on stderr
11020Sstevel@tonic-gate 	 */
11030Sstevel@tonic-gate 	if (!quiet) {
11040Sstevel@tonic-gate #ifdef DEBUG
11050Sstevel@tonic-gate 		(void) fprintf(stderr,
11064774Sas145665 		    "%lld chars in, %lld codes (%lld bytes) out, "
11074774Sas145665 		    "compression factor: ",
11084774Sas145665 		    (count_long)in_count, (count_long)out_count,
11094774Sas145665 		    (count_long) bytes_out);
11100Sstevel@tonic-gate 		prratio(stderr, (count_long)in_count,
11114774Sas145665 		    (count_long)bytes_out);
11120Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
11130Sstevel@tonic-gate 		(void) fprintf(stderr, "\tCompression as in compact: ");
11140Sstevel@tonic-gate 		prratio(stderr,
11154774Sas145665 		    (count_long)in_count-(count_long)bytes_out,
11164774Sas145665 		    (count_long)in_count);
11170Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
11180Sstevel@tonic-gate 		(void) fprintf(stderr,
11194774Sas145665 		    "\tLargest code (of last block) was %d"
11204774Sas145665 		    " (%d bits)\n",
11214774Sas145665 		    free_ent - 1, n_bits);
11220Sstevel@tonic-gate #else /* !DEBUG */
11230Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Compression: "));
11240Sstevel@tonic-gate 		prratio(stderr,
11254774Sas145665 		    (count_long)in_count-(count_long)bytes_out,
11264774Sas145665 		    (count_long)in_count);
11270Sstevel@tonic-gate #endif /* DEBUG */
11280Sstevel@tonic-gate 	}
11290Sstevel@tonic-gate 	/* report if no savings */
11300Sstevel@tonic-gate 	if ((count_long)bytes_out > (count_long)in_count) {
11310Sstevel@tonic-gate 		didnt_shrink = 1;
11320Sstevel@tonic-gate 	}
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate /*
11360Sstevel@tonic-gate  * **************************************************************
11370Sstevel@tonic-gate  * TAG(output)
11380Sstevel@tonic-gate  *
11390Sstevel@tonic-gate  * Output the given code.
11400Sstevel@tonic-gate  * Inputs:
11410Sstevel@tonic-gate  * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
11420Sstevel@tonic-gate  *		that n_bits = < (long)wordsize - 1.
11430Sstevel@tonic-gate  * Outputs:
11440Sstevel@tonic-gate  * 	Outputs code to the file.
11450Sstevel@tonic-gate  * Assumptions:
11460Sstevel@tonic-gate  *	Chars are 8 bits long.
11470Sstevel@tonic-gate  * Algorithm:
11480Sstevel@tonic-gate  * 	Maintain a BITS character long buffer(so that 8 codes will
11490Sstevel@tonic-gate  * fit in it exactly).  Use the VAX insv instruction to insert each
11500Sstevel@tonic-gate  * code in turn.  When the buffer fills up empty it and start over.
11510Sstevel@tonic-gate  */
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate static void
output(code_int code)11540Sstevel@tonic-gate output(code_int code)
11550Sstevel@tonic-gate {
11560Sstevel@tonic-gate #ifdef DEBUG
11570Sstevel@tonic-gate 	static int col = 0;
11580Sstevel@tonic-gate #endif /* DEBUG */
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	int r_off = offset, bits = n_bits;
11610Sstevel@tonic-gate 	char *bp = buf;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate #ifdef DEBUG
11640Sstevel@tonic-gate 	if (verbose)
11650Sstevel@tonic-gate 		(void) fprintf(stderr, "%5d%c", code,
11664774Sas145665 		    (col += 6) >= 74 ? (col = 0, '\n') : ' ');
11670Sstevel@tonic-gate #endif /* DEBUG */
11680Sstevel@tonic-gate 	if (code >= 0) {
11690Sstevel@tonic-gate 		/*
11700Sstevel@tonic-gate 		 * byte/bit numbering on the VAX is simulated
11710Sstevel@tonic-gate 		 * by the following code
11720Sstevel@tonic-gate 		 */
11730Sstevel@tonic-gate 		/*
11740Sstevel@tonic-gate 		 * Get to the first byte.
11750Sstevel@tonic-gate 		 */
11760Sstevel@tonic-gate 		bp += (r_off >> 3);
11770Sstevel@tonic-gate 		r_off &= 7;
11780Sstevel@tonic-gate 		/*
11790Sstevel@tonic-gate 		 * Since code is always >= 8 bits, only need to mask the first
11800Sstevel@tonic-gate 		 * hunk on the left.
11810Sstevel@tonic-gate 		 */
11820Sstevel@tonic-gate 		*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
11830Sstevel@tonic-gate 		bp++;
11840Sstevel@tonic-gate 		bits -= (8 - r_off);
11850Sstevel@tonic-gate 		code >>= 8 - r_off;
11860Sstevel@tonic-gate 		/*
11870Sstevel@tonic-gate 		 * Get any 8 bit parts in the middle (<=1 for up to 16
11880Sstevel@tonic-gate 		 * bits).
11890Sstevel@tonic-gate 		 */
11900Sstevel@tonic-gate 		if (bits >= 8) {
11910Sstevel@tonic-gate 			*bp++ = code;
11920Sstevel@tonic-gate 			code >>= 8;
11930Sstevel@tonic-gate 			bits -= 8;
11940Sstevel@tonic-gate 		}
11950Sstevel@tonic-gate 		/* Last bits. */
11960Sstevel@tonic-gate 		if (bits)
11970Sstevel@tonic-gate 			*bp = code;
11980Sstevel@tonic-gate 		offset += n_bits;
11990Sstevel@tonic-gate 		if (offset == (n_bits << 3)) {
12000Sstevel@tonic-gate 			bp = buf;
12010Sstevel@tonic-gate 			bits = n_bits;
12020Sstevel@tonic-gate 			bytes_out += bits;
12030Sstevel@tonic-gate 			do {
12040Sstevel@tonic-gate 				if (putc(*bp, outp) == EOF &&
12050Sstevel@tonic-gate 				    ferror(outp)) {
12060Sstevel@tonic-gate 					ioerror();
12070Sstevel@tonic-gate 				}
12080Sstevel@tonic-gate 				bp++;
12090Sstevel@tonic-gate 			} while (--bits);
12100Sstevel@tonic-gate 			offset = 0;
12110Sstevel@tonic-gate 		}
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 		/*
12140Sstevel@tonic-gate 		 * If the next entry is going to be too big for the code size,
12150Sstevel@tonic-gate 		 * then increase it, if possible.
12160Sstevel@tonic-gate 		 */
12170Sstevel@tonic-gate 		if (free_ent > maxcode || (clear_flg > 0)) {
12180Sstevel@tonic-gate 			/*
12190Sstevel@tonic-gate 			 * Write the whole buffer, because the input
12200Sstevel@tonic-gate 			 * side won't discover the size increase until
12210Sstevel@tonic-gate 			 * after it has read it.
12220Sstevel@tonic-gate 			 */
12230Sstevel@tonic-gate 			if (offset > 0) {
12240Sstevel@tonic-gate 				if (fwrite(buf, 1, n_bits, outp) != n_bits) {
12250Sstevel@tonic-gate 					longjmp(env, 3);
12260Sstevel@tonic-gate 				}
12270Sstevel@tonic-gate 				bytes_out += n_bits;
12280Sstevel@tonic-gate 			}
12290Sstevel@tonic-gate 			offset = 0;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 			if (clear_flg) {
12320Sstevel@tonic-gate 				maxcode = MAXCODE(n_bits = INIT_BITS);
12330Sstevel@tonic-gate 				clear_flg = 0;
12340Sstevel@tonic-gate 			} else {
12350Sstevel@tonic-gate 				n_bits++;
12360Sstevel@tonic-gate 				if (n_bits == maxbits)
12370Sstevel@tonic-gate 					maxcode = maxmaxcode;
12380Sstevel@tonic-gate 				else
12390Sstevel@tonic-gate 					maxcode = MAXCODE(n_bits);
12400Sstevel@tonic-gate 			}
12410Sstevel@tonic-gate #ifdef DEBUG
12420Sstevel@tonic-gate 			if (debug) {
12430Sstevel@tonic-gate 				(void) fprintf(stderr,
12444774Sas145665 				    "\nChange to %d bits\n", n_bits);
12450Sstevel@tonic-gate 				col = 0;
12460Sstevel@tonic-gate 			}
12470Sstevel@tonic-gate #endif /* DEBUG */
12480Sstevel@tonic-gate 		}
12490Sstevel@tonic-gate 	} else {
12500Sstevel@tonic-gate 		/*
12510Sstevel@tonic-gate 		 * At EOF, write the rest of the buffer.
12520Sstevel@tonic-gate 		 */
12530Sstevel@tonic-gate 		if (offset > 0) {
12540Sstevel@tonic-gate 			if (fwrite(buf, 1, (offset + 7) / 8, outp) == 0 &&
12550Sstevel@tonic-gate 			    ferror(outp)) {
12560Sstevel@tonic-gate 				ioerror();
12570Sstevel@tonic-gate 			}
12580Sstevel@tonic-gate 			bytes_out += (offset + 7) / 8;
12590Sstevel@tonic-gate 		}
12600Sstevel@tonic-gate 		offset = 0;
12610Sstevel@tonic-gate 		(void) fflush(outp);
12620Sstevel@tonic-gate #ifdef DEBUG
12630Sstevel@tonic-gate 		if (verbose)
12640Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
12650Sstevel@tonic-gate #endif /* DEBUG */
12660Sstevel@tonic-gate 		if (ferror(outp))
12670Sstevel@tonic-gate 			ioerror();
12680Sstevel@tonic-gate 	}
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate /*
12720Sstevel@tonic-gate  * Decompress inp to outp.  This routine adapts to the codes in the
12730Sstevel@tonic-gate  * file building the "string" table on-the-fly; requiring no table to
12740Sstevel@tonic-gate  * be stored in the compressed file.  The tables used herein are shared
12750Sstevel@tonic-gate  * with those of the compress() routine.  See the definitions above.
12760Sstevel@tonic-gate  */
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate static void
decompress()12790Sstevel@tonic-gate decompress()
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	char_type *stackp, *stack_lim;
12820Sstevel@tonic-gate 	int finchar;
12830Sstevel@tonic-gate 	code_int code, oldcode, incode;
12840Sstevel@tonic-gate 	FILE *fout = outp;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	/*
12870Sstevel@tonic-gate 	 * As above, initialize the first 256 entries in the table.
12880Sstevel@tonic-gate 	 */
12890Sstevel@tonic-gate 	maxcode = MAXCODE(n_bits = INIT_BITS);
12900Sstevel@tonic-gate 	for (code = 255; code >= 0; code--) {
12910Sstevel@tonic-gate 		tab_prefixof(code) = 0;
12920Sstevel@tonic-gate 		tab_suffixof(code) = (char_type)code;
12930Sstevel@tonic-gate 	}
12940Sstevel@tonic-gate 	free_ent = ((block_compress) ? FIRST : 256);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	finchar = oldcode = getcode();
12970Sstevel@tonic-gate 	if (oldcode == -1)	/* EOF already? */
12980Sstevel@tonic-gate 		return;			/* Get out of here */
12990Sstevel@tonic-gate 	/* first code must be 8 bits = char */
13000Sstevel@tonic-gate 	if (putc((char)finchar, outp) == EOF && ferror(outp)) {
13010Sstevel@tonic-gate 		/* Crash if can't write */
13020Sstevel@tonic-gate 		ioerror();
13030Sstevel@tonic-gate 	}
13040Sstevel@tonic-gate 	stackp = de_stack;
13050Sstevel@tonic-gate 	stack_lim = stack_max;
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	while ((code = getcode()) > -1) {
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 		if ((code == CLEAR) && block_compress) {
13100Sstevel@tonic-gate 			for (code = 255; code >= 0; code--)
13110Sstevel@tonic-gate 			tab_prefixof(code) = 0;
13120Sstevel@tonic-gate 			clear_flg = 1;
13130Sstevel@tonic-gate 			free_ent = FIRST - 1;
13140Sstevel@tonic-gate 			if ((code = getcode()) == -1)	/* O, untimely death! */
13150Sstevel@tonic-gate 				break;
13160Sstevel@tonic-gate 		}
13170Sstevel@tonic-gate 		incode = code;
13180Sstevel@tonic-gate 		/*
13190Sstevel@tonic-gate 		 * Special case for KwKwK string.
13200Sstevel@tonic-gate 		 */
13210Sstevel@tonic-gate 		if (code >= free_ent) {
13220Sstevel@tonic-gate 			if (stackp < stack_lim) {
13230Sstevel@tonic-gate 				*stackp++ = (char_type) finchar;
13240Sstevel@tonic-gate 				code = oldcode;
13250Sstevel@tonic-gate 			} else {
13260Sstevel@tonic-gate 				/* badness */
13270Sstevel@tonic-gate 				longjmp(env, 2);
13280Sstevel@tonic-gate 			}
13290Sstevel@tonic-gate 		}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 		/*
13320Sstevel@tonic-gate 		 * Generate output characters in reverse order
13330Sstevel@tonic-gate 		 */
13340Sstevel@tonic-gate 		while (code >= 256) {
13350Sstevel@tonic-gate 			if (stackp < stack_lim) {
13360Sstevel@tonic-gate 				*stackp++ = tab_suffixof(code);
13370Sstevel@tonic-gate 				code = tab_prefixof(code);
13380Sstevel@tonic-gate 			} else {
13390Sstevel@tonic-gate 				/* badness */
13400Sstevel@tonic-gate 				longjmp(env, 2);
13410Sstevel@tonic-gate 			}
13420Sstevel@tonic-gate 		}
13430Sstevel@tonic-gate 		*stackp++ = finchar = tab_suffixof(code);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 		/*
13460Sstevel@tonic-gate 		 * And put them out in forward order
13470Sstevel@tonic-gate 		 */
13480Sstevel@tonic-gate 		do {
13490Sstevel@tonic-gate 			stackp--;
13500Sstevel@tonic-gate 			(void) putc(*stackp, fout);
13510Sstevel@tonic-gate 		} while (stackp > de_stack);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 		if (ferror(fout))
13540Sstevel@tonic-gate 			ioerror();
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 		/*
13570Sstevel@tonic-gate 		 * Generate the new entry.
13580Sstevel@tonic-gate 		 */
13590Sstevel@tonic-gate 		if ((code = free_ent) < maxmaxcode) {
13600Sstevel@tonic-gate 			tab_prefixof(code) = (unsigned short) oldcode;
13610Sstevel@tonic-gate 			tab_suffixof(code) = (char_type) finchar;
13620Sstevel@tonic-gate 			free_ent = code+1;
13630Sstevel@tonic-gate 		}
13640Sstevel@tonic-gate 		/*
13650Sstevel@tonic-gate 		 * Remember previous code.
13660Sstevel@tonic-gate 		 */
13670Sstevel@tonic-gate 		oldcode = incode;
13680Sstevel@tonic-gate 	}
13690Sstevel@tonic-gate 	(void) fflush(outp);
13700Sstevel@tonic-gate 	if (ferror(outp))
13710Sstevel@tonic-gate 		ioerror();
13720Sstevel@tonic-gate }
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate /*
13750Sstevel@tonic-gate  * **************************************************************
13760Sstevel@tonic-gate  * TAG( getcode )
13770Sstevel@tonic-gate  *
13780Sstevel@tonic-gate  * Read one code from the standard input.  If EOF, return -1.
13790Sstevel@tonic-gate  * Inputs:
13800Sstevel@tonic-gate  * 	inp
13810Sstevel@tonic-gate  * Outputs:
13820Sstevel@tonic-gate  * 	code or -1 is returned.
13830Sstevel@tonic-gate  */
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate code_int
getcode()13860Sstevel@tonic-gate getcode() {
13870Sstevel@tonic-gate 	code_int code;
13880Sstevel@tonic-gate 	static int offset = 0, size = 0;
13890Sstevel@tonic-gate 	static char_type buf[BITS];
13900Sstevel@tonic-gate 	int r_off, bits;
13910Sstevel@tonic-gate 	char_type *bp = buf;
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 	if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
13940Sstevel@tonic-gate 		/*
13950Sstevel@tonic-gate 		 * If the next entry will be too big for the current code
13960Sstevel@tonic-gate 		 * size, then we must increase the size.  This implies reading
13970Sstevel@tonic-gate 		 * a new buffer full, too.
13980Sstevel@tonic-gate 		 */
13990Sstevel@tonic-gate 		if (free_ent > maxcode) {
14000Sstevel@tonic-gate 			n_bits++;
14010Sstevel@tonic-gate 			if (n_bits == maxbits)
14020Sstevel@tonic-gate 				/* won't get any bigger now */
14030Sstevel@tonic-gate 				maxcode = maxmaxcode;
14040Sstevel@tonic-gate 			else
14050Sstevel@tonic-gate 				maxcode = MAXCODE(n_bits);
14060Sstevel@tonic-gate 		}
14070Sstevel@tonic-gate 		if (clear_flg > 0) {
14080Sstevel@tonic-gate 			maxcode = MAXCODE(n_bits = INIT_BITS);
14090Sstevel@tonic-gate 			clear_flg = 0;
14100Sstevel@tonic-gate 		}
14110Sstevel@tonic-gate 		size = fread(buf, 1, n_bits, inp);
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 		if (size <= 0) {
14140Sstevel@tonic-gate 			if (feof(inp)) {
14150Sstevel@tonic-gate 				/* end of file */
14160Sstevel@tonic-gate 				return (-1);
14170Sstevel@tonic-gate 			} else if (ferror(inp)) {
14180Sstevel@tonic-gate 				ioerror();
14190Sstevel@tonic-gate 			}
14200Sstevel@tonic-gate 		}
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 		offset = 0;
14230Sstevel@tonic-gate 		/* Round size down to integral number of codes */
14240Sstevel@tonic-gate 		size = (size << 3) - (n_bits - 1);
14250Sstevel@tonic-gate 	}
14260Sstevel@tonic-gate 	r_off = offset;
14270Sstevel@tonic-gate 	bits = n_bits;
14280Sstevel@tonic-gate 	/*
14290Sstevel@tonic-gate 	 * Get to the first byte.
14300Sstevel@tonic-gate 	 */
14310Sstevel@tonic-gate 	bp += (r_off >> 3);
14320Sstevel@tonic-gate 	r_off &= 7;
14330Sstevel@tonic-gate 	/* Get first part (low order bits) */
14340Sstevel@tonic-gate 	code = (*bp++ >> r_off);
14350Sstevel@tonic-gate 	bits -= (8 - r_off);
14360Sstevel@tonic-gate 	r_off = 8 - r_off;		/* now, offset into code word */
14370Sstevel@tonic-gate 	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
14380Sstevel@tonic-gate 	if (bits >= 8) {
14390Sstevel@tonic-gate 		code |= *bp++ << r_off;
14400Sstevel@tonic-gate 		r_off += 8;
14410Sstevel@tonic-gate 		bits -= 8;
14420Sstevel@tonic-gate 	}
14430Sstevel@tonic-gate 	/* high order bits. */
14440Sstevel@tonic-gate 	code |= (*bp & rmask[bits]) << r_off;
14450Sstevel@tonic-gate 	offset += n_bits;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	return (code);
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate #ifdef DEBUG
14510Sstevel@tonic-gate static void
printcodes()14520Sstevel@tonic-gate printcodes()
14530Sstevel@tonic-gate {
14540Sstevel@tonic-gate 	/*
14550Sstevel@tonic-gate 	 * Just print out codes from input file.  For debugging.
14560Sstevel@tonic-gate 	 */
14570Sstevel@tonic-gate 	code_int code;
14580Sstevel@tonic-gate 	int col = 0, bits;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	bits = n_bits = INIT_BITS;
14610Sstevel@tonic-gate 	maxcode = MAXCODE(n_bits);
14620Sstevel@tonic-gate 	free_ent = ((block_compress) ? FIRST : 256);
14630Sstevel@tonic-gate 	while ((code = getcode()) >= 0) {
14640Sstevel@tonic-gate 		if ((code == CLEAR) && block_compress) {
14650Sstevel@tonic-gate 			free_ent = FIRST - 1;
14660Sstevel@tonic-gate 			clear_flg = 1;
14670Sstevel@tonic-gate 		} else if (free_ent < maxmaxcode)
14680Sstevel@tonic-gate 			free_ent++;
14690Sstevel@tonic-gate 		if (bits != n_bits) {
14700Sstevel@tonic-gate 			(void) fprintf(stderr, "\nChange to %d bits\n", n_bits);
14710Sstevel@tonic-gate 			bits = n_bits;
14720Sstevel@tonic-gate 			col = 0;
14730Sstevel@tonic-gate 		}
14740Sstevel@tonic-gate 		(void) fprintf(stderr, "%5d%c",
14754774Sas145665 		    code, (col += 6) >= 74 ? (col = 0, '\n') : ' ');
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate 	(void) putc('\n', stderr);
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate #endif /* DEBUG */
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate #ifdef DEBUG
14830Sstevel@tonic-gate static void
dump_tab()14840Sstevel@tonic-gate dump_tab()	/* dump string table */
14850Sstevel@tonic-gate {
14860Sstevel@tonic-gate 	int i, first;
14870Sstevel@tonic-gate 	int ent;
14880Sstevel@tonic-gate 	int stack_top = STACK_SIZE;
14890Sstevel@tonic-gate 	int c;
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	if (do_decomp == 0) {	/* compressing */
14920Sstevel@tonic-gate 		int flag = 1;
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 		for (i = 0; i < hsize; i++) {	/* build sort pointers */
14950Sstevel@tonic-gate 			if ((long)htabof(i) >= 0) {
14960Sstevel@tonic-gate 				sorttab[codetabof(i)] = i;
14970Sstevel@tonic-gate 			}
14980Sstevel@tonic-gate 		}
14990Sstevel@tonic-gate 		first = block_compress ? FIRST : 256;
15000Sstevel@tonic-gate 		for (i = first; i < free_ent; i++) {
15010Sstevel@tonic-gate 			(void) fprintf(stderr, "%5d: \"", i);
15020Sstevel@tonic-gate 			de_stack[--stack_top] = '\n';
15030Sstevel@tonic-gate 			de_stack[--stack_top] = '"';
15040Sstevel@tonic-gate 			stack_top =
15054774Sas145665 			    in_stack((htabof(sorttab[i]) >> maxbits) & 0xff,
15064774Sas145665 			    stack_top);
15070Sstevel@tonic-gate 			for (ent = htabof(sorttab[i]) & ((1 << maxbits) -1);
15084774Sas145665 			    ent > 256;
15094774Sas145665 			    ent = htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
15100Sstevel@tonic-gate 				stack_top = in_stack(
15114774Sas145665 				    htabof(sorttab[ent]) >> maxbits,
15124774Sas145665 				    stack_top);
15130Sstevel@tonic-gate 			}
15140Sstevel@tonic-gate 			stack_top = in_stack(ent, stack_top);
15150Sstevel@tonic-gate 			(void) fwrite(&de_stack[stack_top], 1,
15164774Sas145665 			    STACK_SIZE - stack_top, stderr);
15170Sstevel@tonic-gate 			stack_top = STACK_SIZE;
15180Sstevel@tonic-gate 		}
15190Sstevel@tonic-gate 	} else if (!debug) {	/* decompressing */
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 		for (i = 0; i < free_ent; i++) {
15220Sstevel@tonic-gate 			ent = i;
15230Sstevel@tonic-gate 			c = tab_suffixof(ent);
15240Sstevel@tonic-gate 			if (isascii(c) && isprint(c))
15250Sstevel@tonic-gate 				(void) fprintf(stderr, "%5d: %5d/'%c'  \"",
15264774Sas145665 				    ent, tab_prefixof(ent), c);
15270Sstevel@tonic-gate 			else
15280Sstevel@tonic-gate 				(void) fprintf(stderr, "%5d: %5d/\\%03o \"",
15294774Sas145665 				    ent, tab_prefixof(ent), c);
15300Sstevel@tonic-gate 			de_stack[--stack_top] = '\n';
15310Sstevel@tonic-gate 			de_stack[--stack_top] = '"';
15320Sstevel@tonic-gate 			for (; ent != NULL;
15334774Sas145665 			    ent = (ent >= FIRST ? tab_prefixof(ent) :
15344774Sas145665 			    NULL)) {
15350Sstevel@tonic-gate 				stack_top = in_stack(tab_suffixof(ent),
15364774Sas145665 				    stack_top);
15370Sstevel@tonic-gate 			}
15380Sstevel@tonic-gate 			(void) fwrite(&de_stack[stack_top], 1,
15394774Sas145665 			    STACK_SIZE - stack_top, stderr);
15400Sstevel@tonic-gate 			stack_top = STACK_SIZE;
15410Sstevel@tonic-gate 		}
15420Sstevel@tonic-gate 	}
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate #endif /* DEBUG */
15460Sstevel@tonic-gate #ifdef DEBUG
15470Sstevel@tonic-gate static int
in_stack(int c,int stack_top)15480Sstevel@tonic-gate in_stack(int c, int stack_top)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate 	if ((isascii(c) && isprint(c) && c != '\\') || c == ' ') {
15510Sstevel@tonic-gate 		de_stack[--stack_top] = c;
15520Sstevel@tonic-gate 	} else {
15530Sstevel@tonic-gate 		switch (c) {
15540Sstevel@tonic-gate 		case '\n': de_stack[--stack_top] = 'n'; break;
15550Sstevel@tonic-gate 		case '\t': de_stack[--stack_top] = 't'; break;
15560Sstevel@tonic-gate 		case '\b': de_stack[--stack_top] = 'b'; break;
15570Sstevel@tonic-gate 		case '\f': de_stack[--stack_top] = 'f'; break;
15580Sstevel@tonic-gate 		case '\r': de_stack[--stack_top] = 'r'; break;
15590Sstevel@tonic-gate 		case '\\': de_stack[--stack_top] = '\\'; break;
15600Sstevel@tonic-gate 		default:
15610Sstevel@tonic-gate 			de_stack[--stack_top] = '0' + c % 8;
15620Sstevel@tonic-gate 			de_stack[--stack_top] = '0' + (c / 8) % 8;
15630Sstevel@tonic-gate 			de_stack[--stack_top] = '0' + c / 64;
15640Sstevel@tonic-gate 			break;
15650Sstevel@tonic-gate 		}
15660Sstevel@tonic-gate 		de_stack[--stack_top] = '\\';
15670Sstevel@tonic-gate 	}
15680Sstevel@tonic-gate 	return (stack_top);
15690Sstevel@tonic-gate }
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate #endif /* DEBUG */
15720Sstevel@tonic-gate static void
ioerror()15730Sstevel@tonic-gate ioerror()
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate 	longjmp(env, 1);
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate static void
copystat(char * ifname,struct stat * ifstat,char * ofname)15790Sstevel@tonic-gate copystat(char *ifname, struct stat *ifstat, char *ofname)
15800Sstevel@tonic-gate {
15810Sstevel@tonic-gate 	mode_t mode;
15820Sstevel@tonic-gate 	struct utimbuf timep;
15831620Smarks 	acl_t *aclp = NULL;
1584789Sahrens 	int error;
1585*5331Samw 	int sattr_exist = 0;
1586*5331Samw 	int xattr_exist = 0;
1587*5331Samw 
1588*5331Samw 	if (pathconf(ifname, _PC_XATTR_EXISTS) == 1)
1589*5331Samw 		xattr_exist = 1;
1590*5331Samw 	if (saflg && sysattr_support(ifname, _PC_SATTR_EXISTS) == 1)
1591*5331Samw 		sattr_exist = 1;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	if (fclose(outp)) {
15940Sstevel@tonic-gate 		perror(ofname);
15950Sstevel@tonic-gate 		if (!quiet) {
15960Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(" -- file unchanged"));
15970Sstevel@tonic-gate 			newline_needed = 1;
15980Sstevel@tonic-gate 		}
15990Sstevel@tonic-gate 		perm_stat = 1;
16000Sstevel@tonic-gate 	} else if (ifstat == NULL) {	/* Get stat on input file */
16010Sstevel@tonic-gate 		perror(ifname);
16020Sstevel@tonic-gate 		return;
16030Sstevel@tonic-gate 	} else if ((ifstat->st_mode &
16044774Sas145665 	    S_IFMT /* 0170000 */) != S_IFREG /* 0100000 */) {
16050Sstevel@tonic-gate 		if (quiet) {
16060Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", ifname);
16070Sstevel@tonic-gate 		}
16080Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
16094774Sas145665 		    " -- not a regular file: unchanged"));
16100Sstevel@tonic-gate 		newline_needed = 1;
16110Sstevel@tonic-gate 		perm_stat = 1;
16120Sstevel@tonic-gate 	} else if (ifstat->st_nlink > 1) {
16130Sstevel@tonic-gate 		if (quiet) {
16140Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", ifname);
16150Sstevel@tonic-gate 		}
16160Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
16174774Sas145665 		    " -- has %d other links: unchanged"),
16184774Sas145665 		    (uint_t)ifstat->st_nlink - 1);
16190Sstevel@tonic-gate 		newline_needed = 1;
16200Sstevel@tonic-gate 		perm_stat = 1;
16210Sstevel@tonic-gate 	} else if (didnt_shrink && !force) {
16220Sstevel@tonic-gate 		/* No compression: remove file.Z */
16230Sstevel@tonic-gate 		if (!quiet) {
16240Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
16254774Sas145665 			    " -- file unchanged"));
16260Sstevel@tonic-gate 			newline_needed = 1;
16270Sstevel@tonic-gate 		}
1628*5331Samw 	} else 	if ((xattr_exist || sattr_exist) &&
1629*5331Samw 	    (mv_xattrs(progname, ifname, ofname, sattr_exist, 0)
1630*5331Samw 	    != 0)) {
16310Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1632*5331Samw 		    "%s: -- cannot preserve extended attributes or "
1633*5331Samw 		    "system attributes, file unchanged"), ifname);
16340Sstevel@tonic-gate 		newline_needed = 1;
16350Sstevel@tonic-gate 		/* Move attributes back ... */
1636*5331Samw 		xattr_exist = 0;
1637*5331Samw 		sattr_exist = 0;
1638*5331Samw 		if (pathconf(ofname, _PC_XATTR_EXISTS) == 1)
1639*5331Samw 			xattr_exist = 1;
1640*5331Samw 		if (saflg && sysattr_support(ofname, _PC_SATTR_EXISTS) == 1)
1641*5331Samw 			sattr_exist = 1;
1642*5331Samw 		if (sattr_exist || xattr_exist)
1643*5331Samw 			(void) mv_xattrs(progname, ofname, ifname,
1644*5331Samw 			    sattr_exist, 1);
16450Sstevel@tonic-gate 		perm_stat = 1;
1646*5331Samw 	} else { /* ***** Successful Compression ***** */
16470Sstevel@tonic-gate 		mode = ifstat->st_mode & 07777;
1648*5331Samw 		if (chmod(ofname, mode)) {	 /* Copy modes */
1649*5331Samw 			if (errno == EPERM) {
1650*5331Samw 				(void) fprintf(stderr,
1651*5331Samw 				    gettext("failed to chmod %s"
1652*5331Samw 				    "- permisssion denied\n"), ofname);
1653*5331Samw 			}
16540Sstevel@tonic-gate 			perror(ofname);
1655*5331Samw 		}
1656789Sahrens 		error = acl_get(ifname, ACL_NO_TRIVIAL, &aclp);
1657789Sahrens 		if (error != 0) {
16580Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1659789Sahrens 			    "%s: failed to retrieve acl : %s\n"),
1660789Sahrens 			    ifname, acl_strerror(error));
16610Sstevel@tonic-gate 			perm_stat = 1;
16620Sstevel@tonic-gate 		}
1663789Sahrens 		if (aclp && (acl_set(ofname, aclp) < 0)) {
1664*5331Samw 			(void) fprintf(stderr,
1665*5331Samw 			    gettext("%s: failed to set acl "
1666789Sahrens 			    "entries\n"), ofname);
1667789Sahrens 			perm_stat = 1;
16680Sstevel@tonic-gate 		}
16691620Smarks 		if (aclp) {
1670789Sahrens 			acl_free(aclp);
16711620Smarks 			aclp = NULL;
16721620Smarks 		}
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 		/* Copy ownership */
16750Sstevel@tonic-gate 		(void) chown(ofname, ifstat->st_uid, ifstat->st_gid);
16760Sstevel@tonic-gate 		timep.actime = ifstat->st_atime;
16770Sstevel@tonic-gate 		timep.modtime = ifstat->st_mtime;
16780Sstevel@tonic-gate 		/* Update last accessed and modified times */
16790Sstevel@tonic-gate 		(void) utime(ofname, &timep);
1680*5331Samw 		if (unlink(ifname)) { /* Remove input file */
1681*5331Samw 			if (errno == EPERM) {
1682*5331Samw 				(void) fprintf(stderr,
1683*5331Samw 				    gettext("failed to remove %s"
1684*5331Samw 				    "- permisssion denied\n"), ifname);
1685*5331Samw 			}
16860Sstevel@tonic-gate 			perror(ifname);
1687*5331Samw 		}
16880Sstevel@tonic-gate 		if (!quiet) {
16890Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
16904774Sas145665 			    " -- replaced with %s"), ofname);
16910Sstevel@tonic-gate 			newline_needed = 1;
16920Sstevel@tonic-gate 		}
16930Sstevel@tonic-gate 		return;		/* Successful return */
16940Sstevel@tonic-gate 	}
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	/* Unsuccessful return -- one of the tests failed */
16970Sstevel@tonic-gate 	if (ofname[0] != '\0') {
16980Sstevel@tonic-gate 		if (unlink(ofname)) {
1699*5331Samw 			if (errno == EPERM) {
1700*5331Samw 				(void) fprintf(stderr,
1701*5331Samw 				    gettext("failed to remove %s"
1702*5331Samw 				    "- permisssion denied\n"), ifname);
1703*5331Samw 			}
17040Sstevel@tonic-gate 			perror(ofname);
17050Sstevel@tonic-gate 		}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 		ofname[0] = '\0';
17080Sstevel@tonic-gate 	}
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate static void
onintr()17120Sstevel@tonic-gate onintr()
17130Sstevel@tonic-gate {
17140Sstevel@tonic-gate 	if (!precious && !use_stdout && ofname[0] != '\0')
17150Sstevel@tonic-gate 		(void) unlink(ofname);
17160Sstevel@tonic-gate 	exit(1);
17170Sstevel@tonic-gate }
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate static void
oops()17200Sstevel@tonic-gate oops()	/* wild pointer -- assume bad input */
17210Sstevel@tonic-gate {
17220Sstevel@tonic-gate 	if (do_decomp) {
17230Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("uncompress: corrupt input\n"));
17240Sstevel@tonic-gate 	}
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	if (!use_stdout && ofname[0] != '\0') {
17270Sstevel@tonic-gate 		(void) unlink(ofname);
17280Sstevel@tonic-gate 	}
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	exit(1);
17310Sstevel@tonic-gate }
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate static void
cl_block(count_long in_count)17340Sstevel@tonic-gate cl_block(count_long in_count)	/* table clear for block compress */
17350Sstevel@tonic-gate {
17360Sstevel@tonic-gate 	count_long rat;
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	checkpoint = (count_long)in_count + (count_long)CHECK_GAP;
17390Sstevel@tonic-gate #ifdef DEBUG
17400Sstevel@tonic-gate 	if (debug) {
17410Sstevel@tonic-gate 		(void) fprintf(stderr, "count: %lld, ratio: ",
17424774Sas145665 		    (count_long)in_count);
17430Sstevel@tonic-gate 		prratio(stderr, (count_long)in_count, (count_long)bytes_out);
17440Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate #endif /* DEBUG */
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	/* shift will overflow */
1749212Scf46844 	if ((count_long)in_count > 0x007fffffffffffffLL) {
17500Sstevel@tonic-gate 		rat = (count_long)bytes_out >> 8;
17510Sstevel@tonic-gate 		if (rat == 0) {		/* Don't divide by zero */
1752212Scf46844 			rat = 0x7fffffffffffffffLL;
17530Sstevel@tonic-gate 		} else {
17540Sstevel@tonic-gate 			rat = (count_long)in_count / (count_long)rat;
17550Sstevel@tonic-gate 		}
17560Sstevel@tonic-gate 	} else {
17570Sstevel@tonic-gate 		/* 8 fractional bits */
17580Sstevel@tonic-gate 		rat = ((count_long)in_count << 8) /(count_long)bytes_out;
17590Sstevel@tonic-gate 	}
17600Sstevel@tonic-gate 	if (rat > ratio) {
17610Sstevel@tonic-gate 		ratio = rat;
17620Sstevel@tonic-gate 	} else {
17630Sstevel@tonic-gate 		ratio = 0;
17640Sstevel@tonic-gate #ifdef DEBUG
17650Sstevel@tonic-gate 		if (verbose)
17660Sstevel@tonic-gate 			dump_tab();	/* dump string table */
17670Sstevel@tonic-gate #endif
17680Sstevel@tonic-gate 		cl_hash((count_int) hsize);
17690Sstevel@tonic-gate 		free_ent = FIRST;
17700Sstevel@tonic-gate 		clear_flg = 1;
17710Sstevel@tonic-gate 		output((code_int) CLEAR);
17720Sstevel@tonic-gate #ifdef DEBUG
17730Sstevel@tonic-gate 		if (debug)
17740Sstevel@tonic-gate 			(void) fprintf(stderr, "clear\n");
17750Sstevel@tonic-gate #endif /* DEBUG */
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate }
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate static void
cl_hash(count_int hsize)17800Sstevel@tonic-gate cl_hash(count_int hsize)		/* reset code table */
17810Sstevel@tonic-gate {
17820Sstevel@tonic-gate 	count_int *htab_p = htab+hsize;
17830Sstevel@tonic-gate 	long i;
17840Sstevel@tonic-gate 	long m1 = -1;
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	i = hsize - 16;
17870Sstevel@tonic-gate 	do {				/* might use Sys V memset(3) here */
17880Sstevel@tonic-gate 		*(htab_p-16) = m1;
17890Sstevel@tonic-gate 		*(htab_p-15) = m1;
17900Sstevel@tonic-gate 		*(htab_p-14) = m1;
17910Sstevel@tonic-gate 		*(htab_p-13) = m1;
17920Sstevel@tonic-gate 		*(htab_p-12) = m1;
17930Sstevel@tonic-gate 		*(htab_p-11) = m1;
17940Sstevel@tonic-gate 		*(htab_p-10) = m1;
17950Sstevel@tonic-gate 		*(htab_p-9) = m1;
17960Sstevel@tonic-gate 		*(htab_p-8) = m1;
17970Sstevel@tonic-gate 		*(htab_p-7) = m1;
17980Sstevel@tonic-gate 		*(htab_p-6) = m1;
17990Sstevel@tonic-gate 		*(htab_p-5) = m1;
18000Sstevel@tonic-gate 		*(htab_p-4) = m1;
18010Sstevel@tonic-gate 		*(htab_p-3) = m1;
18020Sstevel@tonic-gate 		*(htab_p-2) = m1;
18030Sstevel@tonic-gate 		*(htab_p-1) = m1;
18040Sstevel@tonic-gate 		htab_p -= 16;
18050Sstevel@tonic-gate 	} while ((i -= 16) >= 0);
18060Sstevel@tonic-gate 		for (i += 16; i > 0; i--)
18070Sstevel@tonic-gate 			*--htab_p = m1;
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate static void
prratio(FILE * stream,count_long num,count_long den)18110Sstevel@tonic-gate prratio(FILE *stream, count_long num, count_long den)
18120Sstevel@tonic-gate {
18130Sstevel@tonic-gate 	int q;  /* store percentage */
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	q = (int)(10000LL * (count_long)num / (count_long)den);
18160Sstevel@tonic-gate 	if (q < 0) {
18170Sstevel@tonic-gate 		(void) putc('-', stream);
18180Sstevel@tonic-gate 		q = -q;
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 	(void) fprintf(stream, "%d%s%02d%%", q / 100,
18214774Sas145665 	    localeconv()->decimal_point, q % 100);
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate static void
version()18250Sstevel@tonic-gate version()
18260Sstevel@tonic-gate {
18270Sstevel@tonic-gate 	(void) fprintf(stderr, "%s, Berkeley 5.9 5/11/86\n", rcs_ident);
18280Sstevel@tonic-gate 	(void) fprintf(stderr, "Options: ");
18290Sstevel@tonic-gate #ifdef DEBUG
18300Sstevel@tonic-gate 	(void) fprintf(stderr, "DEBUG, ");
18310Sstevel@tonic-gate #endif
18320Sstevel@tonic-gate 	(void) fprintf(stderr, "BITS = %d\n", BITS);
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate static void
Usage()18360Sstevel@tonic-gate Usage()
18370Sstevel@tonic-gate {
18380Sstevel@tonic-gate #ifdef DEBUG
18390Sstevel@tonic-gate 	(void) fprintf(stderr,
1840*5331Samw 	"Usage: compress [-dDVfc/] [-b maxbits] [file ...]\n");
18410Sstevel@tonic-gate #else
18420Sstevel@tonic-gate 	if (strcmp(progname, "compress") == 0) {
18430Sstevel@tonic-gate 		(void) fprintf(stderr,
18440Sstevel@tonic-gate 		    gettext(
1845*5331Samw 		    "Usage: compress [-fv/] [-b maxbits] [file ...]\n"\
1846*5331Samw 		    "       compress c [-fv] [-b maxbits] [file]\n"));
18470Sstevel@tonic-gate 	} else if (strcmp(progname, "uncompress") == 0)
18480Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1849*5331Samw 		    "Usage: uncompress [-fv] [-c || -/] [file ...]\n"));
18500Sstevel@tonic-gate 	else if (strcmp(progname, "zcat") == 0)
18510Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: zcat [file ...]\n"));
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate #endif /* DEBUG */
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate static char *
local_basename(char * path)18570Sstevel@tonic-gate local_basename(char *path)
18580Sstevel@tonic-gate {
18590Sstevel@tonic-gate 	char *p;
18600Sstevel@tonic-gate 	char *ret = (char *)path;
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	while ((p = (char *)strpbrk(ret, "/")) != NULL)
18630Sstevel@tonic-gate 		ret = p + 1;
18640Sstevel@tonic-gate 	return (ret);
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate static int
addDotZ(char * fn,size_t fnsize)18680Sstevel@tonic-gate addDotZ(char *fn, size_t fnsize)
18690Sstevel@tonic-gate {
18700Sstevel@tonic-gate 	char *fn_dup;
18710Sstevel@tonic-gate 	char *dir;
18720Sstevel@tonic-gate 	long int max_name;
18730Sstevel@tonic-gate 	long int max_path;
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 	fn_dup = strdup(fn);
18760Sstevel@tonic-gate 	dir = dirname(fn_dup);
18770Sstevel@tonic-gate 	max_name = pathconf(dir, _PC_NAME_MAX);
18780Sstevel@tonic-gate 	max_path = pathconf(dir, _PC_PATH_MAX);
18790Sstevel@tonic-gate 	free(fn_dup);
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 	/* Check for component length too long */
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	if ((strlen(local_basename(fn)) + 2) > (size_t)max_name) {
18840Sstevel@tonic-gate 		(void) fprintf(stderr,
18854774Sas145665 		    gettext("%s: filename too long to tack on .Z:"
18864774Sas145665 		    " %s\n"), progname, fn);
18870Sstevel@tonic-gate 		return (-1);
18880Sstevel@tonic-gate 	}
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	/* Check for path length too long */
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	if ((strlen(fn) + 2) > (size_t)max_path - 1) {
18930Sstevel@tonic-gate 		(void) fprintf(stderr,
18944774Sas145665 		    gettext("%s: Pathname too long to tack on .Z:"
18954774Sas145665 		    " %s\n"), progname, fn);
18960Sstevel@tonic-gate 		return (-1);
18970Sstevel@tonic-gate 	}
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	if (strlcat(fn, ".Z", fnsize) >= fnsize) {
19000Sstevel@tonic-gate 		(void) fprintf(stderr,
19014774Sas145665 		    gettext("%s: Buffer overflow adding .Z to %s\n"),
19024774Sas145665 		    progname, fn);
19030Sstevel@tonic-gate 		return (-1);
19040Sstevel@tonic-gate 	}
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	return (0);
19070Sstevel@tonic-gate }
1908