xref: /titanic_50/usr/src/cmd/compress/compress.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
2*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
3*7c478bd9Sstevel@tonic-gate 
4*7c478bd9Sstevel@tonic-gate 
5*7c478bd9Sstevel@tonic-gate /*
6*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1986 Regents of the University of California.
7*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
8*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
9*7c478bd9Sstevel@tonic-gate  */
10*7c478bd9Sstevel@tonic-gate 
11*7c478bd9Sstevel@tonic-gate /*
12*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
13*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
14*7c478bd9Sstevel@tonic-gate  */
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
17*7c478bd9Sstevel@tonic-gate 
18*7c478bd9Sstevel@tonic-gate /*
19*7c478bd9Sstevel@tonic-gate  * Compress - data compression program
20*7c478bd9Sstevel@tonic-gate  */
21*7c478bd9Sstevel@tonic-gate #define	min(a, b)	((a > b) ? b : a)
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate /*
24*7c478bd9Sstevel@tonic-gate  * machine variants which require cc -Dmachine:  pdp11, z8000, pcxt
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * Set USERMEM to the maximum amount of physical user memory available
29*7c478bd9Sstevel@tonic-gate  * in bytes.  USERMEM is used to determine the maximum BITS that can be used
30*7c478bd9Sstevel@tonic-gate  * for compression.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * SACREDMEM is the amount of physical memory saved for others; compress
33*7c478bd9Sstevel@tonic-gate  * will hog the rest.
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate #ifndef SACREDMEM
36*7c478bd9Sstevel@tonic-gate #define	SACREDMEM	0
37*7c478bd9Sstevel@tonic-gate #endif
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #ifndef USERMEM
40*7c478bd9Sstevel@tonic-gate #define	USERMEM 	450000	/* default user memory */
41*7c478bd9Sstevel@tonic-gate #endif
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #ifdef USERMEM
44*7c478bd9Sstevel@tonic-gate #if USERMEM >= (433484+SACREDMEM)
45*7c478bd9Sstevel@tonic-gate #define	PBITS	16
46*7c478bd9Sstevel@tonic-gate #else
47*7c478bd9Sstevel@tonic-gate #if USERMEM >= (229600+SACREDMEM)
48*7c478bd9Sstevel@tonic-gate #define	PBITS	15
49*7c478bd9Sstevel@tonic-gate #else
50*7c478bd9Sstevel@tonic-gate #if USERMEM >= (127536+SACREDMEM)
51*7c478bd9Sstevel@tonic-gate #define	PBITS	14
52*7c478bd9Sstevel@tonic-gate #else
53*7c478bd9Sstevel@tonic-gate #if USERMEM >= (73464+SACREDMEM)
54*7c478bd9Sstevel@tonic-gate #define	PBITS	13
55*7c478bd9Sstevel@tonic-gate #else
56*7c478bd9Sstevel@tonic-gate #define	PBITS	12
57*7c478bd9Sstevel@tonic-gate #endif
58*7c478bd9Sstevel@tonic-gate #endif
59*7c478bd9Sstevel@tonic-gate #endif
60*7c478bd9Sstevel@tonic-gate #endif
61*7c478bd9Sstevel@tonic-gate #undef USERMEM
62*7c478bd9Sstevel@tonic-gate #endif /* USERMEM */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #ifdef PBITS		/* Preferred BITS for this memory size */
65*7c478bd9Sstevel@tonic-gate #ifndef BITS
66*7c478bd9Sstevel@tonic-gate #define	BITS PBITS
67*7c478bd9Sstevel@tonic-gate #endif /* BITS */
68*7c478bd9Sstevel@tonic-gate #endif /* PBITS */
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #if BITS == 16
71*7c478bd9Sstevel@tonic-gate #define	HSIZE	69001		/* 95% occupancy */
72*7c478bd9Sstevel@tonic-gate #endif
73*7c478bd9Sstevel@tonic-gate #if BITS == 15
74*7c478bd9Sstevel@tonic-gate #define	HSIZE	35023		/* 94% occupancy */
75*7c478bd9Sstevel@tonic-gate #endif
76*7c478bd9Sstevel@tonic-gate #if BITS == 14
77*7c478bd9Sstevel@tonic-gate #define	HSIZE	18013		/* 91% occupancy */
78*7c478bd9Sstevel@tonic-gate #endif
79*7c478bd9Sstevel@tonic-gate #if BITS == 13
80*7c478bd9Sstevel@tonic-gate #define	HSIZE	9001		/* 91% occupancy */
81*7c478bd9Sstevel@tonic-gate #endif
82*7c478bd9Sstevel@tonic-gate #if BITS <= 12
83*7c478bd9Sstevel@tonic-gate #define	HSIZE	5003		/* 80% occupancy */
84*7c478bd9Sstevel@tonic-gate #endif
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	OUTSTACKSIZE	(2<<BITS)
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate /*
89*7c478bd9Sstevel@tonic-gate  * a code_int must be able to hold 2**BITS values of type int, and also -1
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate #if BITS > 15
92*7c478bd9Sstevel@tonic-gate typedef long int	code_int;
93*7c478bd9Sstevel@tonic-gate #else
94*7c478bd9Sstevel@tonic-gate typedef int		code_int;
95*7c478bd9Sstevel@tonic-gate #endif
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate typedef long int	count_int;
98*7c478bd9Sstevel@tonic-gate typedef long long	count_long;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate typedef	unsigned char	char_type;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static char_type magic_header[] = { "\037\235" }; /* 1F 9D */
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /* Defines for third byte of header */
105*7c478bd9Sstevel@tonic-gate #define	BIT_MASK	0x1f
106*7c478bd9Sstevel@tonic-gate #define	BLOCK_MASK	0x80
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
109*7c478bd9Sstevel@tonic-gate  * a fourth header byte(for expansion).
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate #define	INIT_BITS 9			/* initial number of bits/code */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /*
114*7c478bd9Sstevel@tonic-gate  * compress.c - File compression ala IEEE Computer, June 1984.
115*7c478bd9Sstevel@tonic-gate  */
116*7c478bd9Sstevel@tonic-gate static char rcs_ident[] =
117*7c478bd9Sstevel@tonic-gate 	"$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate #include <stdio.h>
120*7c478bd9Sstevel@tonic-gate #include <ctype.h>
121*7c478bd9Sstevel@tonic-gate #include <signal.h>
122*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
123*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
124*7c478bd9Sstevel@tonic-gate #include <unistd.h>
125*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
126*7c478bd9Sstevel@tonic-gate #include <stdlib.h>			/* XCU4 */
127*7c478bd9Sstevel@tonic-gate #include <limits.h>
128*7c478bd9Sstevel@tonic-gate #include <libintl.h>
129*7c478bd9Sstevel@tonic-gate #include <locale.h>
130*7c478bd9Sstevel@tonic-gate #include <langinfo.h>
131*7c478bd9Sstevel@tonic-gate #include <string.h>
132*7c478bd9Sstevel@tonic-gate #include <sys/acl.h>
133*7c478bd9Sstevel@tonic-gate #include <utime.h>
134*7c478bd9Sstevel@tonic-gate #include <libgen.h>
135*7c478bd9Sstevel@tonic-gate #include <setjmp.h>
136*7c478bd9Sstevel@tonic-gate #include <strings.h>
137*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
138*7c478bd9Sstevel@tonic-gate #include <dirent.h>
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * Multi-byte handling for 'y' or 'n'
142*7c478bd9Sstevel@tonic-gate  */
143*7c478bd9Sstevel@tonic-gate static char	*yesstr;		/* string contains int'l for "yes" */
144*7c478bd9Sstevel@tonic-gate static char	*nostr;			/* string contains int'l for "yes" */
145*7c478bd9Sstevel@tonic-gate static int	ynsize = 0;		/* # of (multi)bytes for "y" */
146*7c478bd9Sstevel@tonic-gate static char	*yesorno;		/* int'l input for 'y' */
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate static int n_bits;			/* number of bits/code */
149*7c478bd9Sstevel@tonic-gate static int maxbits = BITS;	/* user settable max # bits/code */
150*7c478bd9Sstevel@tonic-gate static code_int maxcode;	/* maximum code, given n_bits */
151*7c478bd9Sstevel@tonic-gate 			/* should NEVER generate this code */
152*7c478bd9Sstevel@tonic-gate static code_int maxmaxcode = 1 << BITS;
153*7c478bd9Sstevel@tonic-gate #define	MAXCODE(n_bits)	((1 << (n_bits)) - 1)
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate static count_int htab [OUTSTACKSIZE];
156*7c478bd9Sstevel@tonic-gate static unsigned short codetab [OUTSTACKSIZE];
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate #define	htabof(i)	htab[i]
159*7c478bd9Sstevel@tonic-gate #define	codetabof(i)	codetab[i]
160*7c478bd9Sstevel@tonic-gate static code_int hsize = HSIZE; /* for dynamic table sizing */
161*7c478bd9Sstevel@tonic-gate static off_t	fsize;	/* file size of input file */
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate /*
164*7c478bd9Sstevel@tonic-gate  * To save much memory, we overlay the table used by compress() with those
165*7c478bd9Sstevel@tonic-gate  * used by decompress().  The tab_prefix table is the same size and type
166*7c478bd9Sstevel@tonic-gate  * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
167*7c478bd9Sstevel@tonic-gate  * get this from the beginning of htab.  The output stack uses the rest
168*7c478bd9Sstevel@tonic-gate  * of htab, and contains characters.  There is plenty of room for any
169*7c478bd9Sstevel@tonic-gate  * possible stack (stack used to be 8000 characters).
170*7c478bd9Sstevel@tonic-gate  */
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate #define	tab_prefixof(i)		codetabof(i)
173*7c478bd9Sstevel@tonic-gate #define	tab_suffixof(i)		((char_type *)(htab))[i]
174*7c478bd9Sstevel@tonic-gate #define	de_stack		((char_type *)&tab_suffixof(1<<BITS))
175*7c478bd9Sstevel@tonic-gate #define	stack_max		((char_type *)&tab_suffixof(OUTSTACKSIZE))
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate static code_int free_ent = 0; /* first unused entry */
178*7c478bd9Sstevel@tonic-gate static int newline_needed = 0;
179*7c478bd9Sstevel@tonic-gate static int didnt_shrink = 0;
180*7c478bd9Sstevel@tonic-gate static int perm_stat = 0;	/* permanent status */
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate static code_int getcode();
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	/* Use a 3-byte magic number header, unless old file */
185*7c478bd9Sstevel@tonic-gate static int nomagic = 0;
186*7c478bd9Sstevel@tonic-gate 	/* Write output on stdout, suppress messages */
187*7c478bd9Sstevel@tonic-gate static int zcat_flg = 0;	/* use stdout on all files */
188*7c478bd9Sstevel@tonic-gate static int zcat_cmd = 0;	/* zcat cmd */
189*7c478bd9Sstevel@tonic-gate static int use_stdout = 0;	/* set for each file processed */
190*7c478bd9Sstevel@tonic-gate 	/* Don't unlink output file on interrupt */
191*7c478bd9Sstevel@tonic-gate static int precious = 1;
192*7c478bd9Sstevel@tonic-gate static int quiet = 1;	/* don't tell me about compression */
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate /*
195*7c478bd9Sstevel@tonic-gate  * block compression parameters -- after all codes are used up,
196*7c478bd9Sstevel@tonic-gate  * and compression rate changes, start over.
197*7c478bd9Sstevel@tonic-gate  */
198*7c478bd9Sstevel@tonic-gate static int block_compress = BLOCK_MASK;
199*7c478bd9Sstevel@tonic-gate static int clear_flg = 0;
200*7c478bd9Sstevel@tonic-gate static long int ratio = 0;
201*7c478bd9Sstevel@tonic-gate #define	CHECK_GAP 10000	/* ratio check interval */
202*7c478bd9Sstevel@tonic-gate static count_long checkpoint = CHECK_GAP;
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate  * the next two codes should not be changed lightly, as they must not
205*7c478bd9Sstevel@tonic-gate  * lie within the contiguous general code space.
206*7c478bd9Sstevel@tonic-gate  */
207*7c478bd9Sstevel@tonic-gate #define	FIRST	257	/* first free entry */
208*7c478bd9Sstevel@tonic-gate #define	CLEAR	256	/* table clear output code */
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate static int force = 0;
211*7c478bd9Sstevel@tonic-gate static char ofname [MAXPATHLEN];
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate static int Vflg = 0;
214*7c478bd9Sstevel@tonic-gate static int vflg = 0;
215*7c478bd9Sstevel@tonic-gate static int qflg = 0;
216*7c478bd9Sstevel@tonic-gate static int bflg = 0;
217*7c478bd9Sstevel@tonic-gate static int Fflg = 0;
218*7c478bd9Sstevel@tonic-gate static int dflg = 0;
219*7c478bd9Sstevel@tonic-gate static int cflg = 0;
220*7c478bd9Sstevel@tonic-gate static int Cflg = 0;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
223*7c478bd9Sstevel@tonic-gate int verbose = 0;
224*7c478bd9Sstevel@tonic-gate int debug = 0;
225*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate static void (*oldint)();
228*7c478bd9Sstevel@tonic-gate static int bgnd_flag;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate static int do_decomp = 0;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate static char *progname;
233*7c478bd9Sstevel@tonic-gate static char *optstr;
234*7c478bd9Sstevel@tonic-gate /*
235*7c478bd9Sstevel@tonic-gate  * Fix lint errors
236*7c478bd9Sstevel@tonic-gate  */
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate static char *local_basename(char *);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate static int  addDotZ(char *, size_t);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate static void Usage(void);
243*7c478bd9Sstevel@tonic-gate static void cl_block(count_long);
244*7c478bd9Sstevel@tonic-gate static void cl_hash(count_int);
245*7c478bd9Sstevel@tonic-gate static void compress(void);
246*7c478bd9Sstevel@tonic-gate static void copystat(char *, struct stat *, char *);
247*7c478bd9Sstevel@tonic-gate static void decompress(void);
248*7c478bd9Sstevel@tonic-gate static void ioerror(void);
249*7c478bd9Sstevel@tonic-gate static void onintr();
250*7c478bd9Sstevel@tonic-gate static void oops();
251*7c478bd9Sstevel@tonic-gate static void output(code_int);
252*7c478bd9Sstevel@tonic-gate static void prratio(FILE *, count_long, count_long);
253*7c478bd9Sstevel@tonic-gate static void version(void);
254*7c478bd9Sstevel@tonic-gate static int mv_xattrs(char *, char *, int);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
257*7c478bd9Sstevel@tonic-gate static int in_stack(int, int);
258*7c478bd9Sstevel@tonic-gate static void dump_tab(void);
259*7c478bd9Sstevel@tonic-gate static void printcodes(void);
260*7c478bd9Sstevel@tonic-gate #endif
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate /* For error-handling */
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate static jmp_buf env;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate /* For input and ouput */
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate static FILE *inp;		/* the current input file */
269*7c478bd9Sstevel@tonic-gate static FILE *infile;		/* disk-based input stream */
270*7c478bd9Sstevel@tonic-gate static FILE *outp;		/* current output file */
271*7c478bd9Sstevel@tonic-gate static FILE *outfile;		/* disk-based output stream */
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate /* For output() */
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate static char buf[BITS];
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate static char_type lmask[9] =
278*7c478bd9Sstevel@tonic-gate 	{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
279*7c478bd9Sstevel@tonic-gate static char_type rmask[9] =
280*7c478bd9Sstevel@tonic-gate 	{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate /* For compress () */
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate static int offset;
285*7c478bd9Sstevel@tonic-gate static count_long bytes_out;	/* length of compressed output */
286*7c478bd9Sstevel@tonic-gate 	/* # of codes output (for debugging) */
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /* For dump_tab() */
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate #define	STACK_SIZE	15000
291*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
292*7c478bd9Sstevel@tonic-gate code_int sorttab[1<<BITS];	/* sorted pointers into htab */
293*7c478bd9Sstevel@tonic-gate #endif
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate  * *************************************************************
297*7c478bd9Sstevel@tonic-gate  * TAG( main )
298*7c478bd9Sstevel@tonic-gate  *
299*7c478bd9Sstevel@tonic-gate  * Algorithm from "A Technique for High Performance Data Compression",
300*7c478bd9Sstevel@tonic-gate  * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
301*7c478bd9Sstevel@tonic-gate  *
302*7c478bd9Sstevel@tonic-gate  * Usage: compress [-dfvc] [-b bits] [file ...]
303*7c478bd9Sstevel@tonic-gate  * Inputs:
304*7c478bd9Sstevel@tonic-gate  *	-d:	    If given, decompression is done instead.
305*7c478bd9Sstevel@tonic-gate  *
306*7c478bd9Sstevel@tonic-gate  *	-c:	    Write output on stdout, don't remove original.
307*7c478bd9Sstevel@tonic-gate  *
308*7c478bd9Sstevel@tonic-gate  *	-b:	    Parameter limits the max number of bits/code.
309*7c478bd9Sstevel@tonic-gate  *
310*7c478bd9Sstevel@tonic-gate  *	-f:	    Forces output file to be generated, even if one already
311*7c478bd9Sstevel@tonic-gate  *		    exists, and even if no space is saved by compressing.
312*7c478bd9Sstevel@tonic-gate  *		    If -f is not used, the user will be prompted if stdin is
313*7c478bd9Sstevel@tonic-gate  *		    a tty, otherwise, the output file will not be overwritten.
314*7c478bd9Sstevel@tonic-gate  *
315*7c478bd9Sstevel@tonic-gate  *  -v:	    Write compression statistics
316*7c478bd9Sstevel@tonic-gate  *
317*7c478bd9Sstevel@tonic-gate  * 	file ...:   Files to be compressed.  If none specified, stdin
318*7c478bd9Sstevel@tonic-gate  *		    is used.
319*7c478bd9Sstevel@tonic-gate  * Outputs:
320*7c478bd9Sstevel@tonic-gate  *	file.Z:	    Compressed form of file with same mode, owner, and utimes
321*7c478bd9Sstevel@tonic-gate  * 	or stdout   (if stdin used as input)
322*7c478bd9Sstevel@tonic-gate  *
323*7c478bd9Sstevel@tonic-gate  * Assumptions:
324*7c478bd9Sstevel@tonic-gate  * When filenames are given, replaces with the compressed version
325*7c478bd9Sstevel@tonic-gate  * (.Z suffix) only if the file decreases in size.
326*7c478bd9Sstevel@tonic-gate  * Algorithm:
327*7c478bd9Sstevel@tonic-gate  * Modified Lempel-Ziv method (LZW).  Basically finds common
328*7c478bd9Sstevel@tonic-gate  * substrings and replaces them with a variable size code.  This is
329*7c478bd9Sstevel@tonic-gate  * deterministic, and can be done on the fly.  Thus, the decompression
330*7c478bd9Sstevel@tonic-gate  * procedure needs no input table, but tracks the way the table was built.
331*7c478bd9Sstevel@tonic-gate  */
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate int
334*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
335*7c478bd9Sstevel@tonic-gate {
336*7c478bd9Sstevel@tonic-gate 	int overwrite = 0;	/* Do not overwrite unless given -f flag */
337*7c478bd9Sstevel@tonic-gate 	char tempname[MAXPATHLEN];
338*7c478bd9Sstevel@tonic-gate 	char line[LINE_MAX];
339*7c478bd9Sstevel@tonic-gate 	char **filelist, **fileptr;
340*7c478bd9Sstevel@tonic-gate 	char *cp;
341*7c478bd9Sstevel@tonic-gate 	struct stat statbuf;
342*7c478bd9Sstevel@tonic-gate 	struct stat ostatbuf;
343*7c478bd9Sstevel@tonic-gate 	int ch;				/* XCU4 */
344*7c478bd9Sstevel@tonic-gate 	char	*p, *yptr, *nptr;
345*7c478bd9Sstevel@tonic-gate 	extern int optind, optopt;
346*7c478bd9Sstevel@tonic-gate 	extern char *optarg;
347*7c478bd9Sstevel@tonic-gate 	int dash_count = 0;		/* times "-" is on cmdline */
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	/* XCU4 changes */
350*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
351*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
352*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
353*7c478bd9Sstevel@tonic-gate #endif
354*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
355*7c478bd9Sstevel@tonic-gate 	/* Build multi-byte char for 'y' char */
356*7c478bd9Sstevel@tonic-gate 	if ((yptr = nl_langinfo(YESSTR)) == NULL)
357*7c478bd9Sstevel@tonic-gate 		yptr = "y";
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	yesstr = (char *)malloc(strlen(yptr) + 1);
360*7c478bd9Sstevel@tonic-gate 	(void) strcpy(yesstr, yptr);
361*7c478bd9Sstevel@tonic-gate 	/* Build multi-byte char for 'n' char */
362*7c478bd9Sstevel@tonic-gate 	if ((nptr = nl_langinfo(NOSTR)) == NULL)
363*7c478bd9Sstevel@tonic-gate 		nptr = "n";
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	nostr = (char *)malloc(strlen(nptr) + 1);
366*7c478bd9Sstevel@tonic-gate 	(void) strcpy(nostr, nptr);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	/* Build multi-byte char for input char */
369*7c478bd9Sstevel@tonic-gate 	yesorno = (char *)malloc((size_t)ynsize + 1);
370*7c478bd9Sstevel@tonic-gate 	ynsize = mblen(yesstr, strlen(yesstr));
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	/* This bg check only works for sh. */
373*7c478bd9Sstevel@tonic-gate 	if ((oldint = signal(SIGINT, SIG_IGN)) != SIG_IGN) {
374*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGINT, onintr);
375*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGSEGV, oops);
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate 	bgnd_flag = oldint != SIG_DFL;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/* Allocate room for argv + "-" (if stdin needs to be added) */
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	filelist = fileptr = (char **)(malloc((argc + 1) * sizeof (*argv)));
382*7c478bd9Sstevel@tonic-gate 	*filelist = NULL;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if ((cp = rindex(argv[0], '/')) != 0) {
385*7c478bd9Sstevel@tonic-gate 		cp++;
386*7c478bd9Sstevel@tonic-gate 	} else {
387*7c478bd9Sstevel@tonic-gate 		cp = argv[0];
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	if (strcmp(cp, "uncompress") == 0) {
391*7c478bd9Sstevel@tonic-gate 		do_decomp = 1;
392*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(cp, "zcat") == 0) {
393*7c478bd9Sstevel@tonic-gate 		do_decomp = 1;
394*7c478bd9Sstevel@tonic-gate 		zcat_cmd = zcat_flg = 1;
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	progname = local_basename(argv[0]);
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	/*
400*7c478bd9Sstevel@tonic-gate 	 * Argument Processing
401*7c478bd9Sstevel@tonic-gate 	 * All flags are optional.
402*7c478bd9Sstevel@tonic-gate 	 * -D = > debug
403*7c478bd9Sstevel@tonic-gate 	 * -V = > print Version; debug verbose
404*7c478bd9Sstevel@tonic-gate 	 * -d = > do_decomp
405*7c478bd9Sstevel@tonic-gate 	 * -v = > unquiet
406*7c478bd9Sstevel@tonic-gate 	 * -f = > force overwrite of output file
407*7c478bd9Sstevel@tonic-gate 	 * -n = > no header: useful to uncompress old files
408*7c478bd9Sstevel@tonic-gate 	 * -b	  maxbits => maxbits.  If -b is specified,
409*7c478bd9Sstevel@tonic-gate 	 *	  then maxbits MUST be given also.
410*7c478bd9Sstevel@tonic-gate 	 * -c = > cat all output to stdout
411*7c478bd9Sstevel@tonic-gate 	 * -C = > generate output compatible with compress 2.0.
412*7c478bd9Sstevel@tonic-gate 	 * if a string is left, must be an input filename.
413*7c478bd9Sstevel@tonic-gate 	 */
414*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
415*7c478bd9Sstevel@tonic-gate 	optstr = "b:cCdDfFnqvV";
416*7c478bd9Sstevel@tonic-gate #else
417*7c478bd9Sstevel@tonic-gate 	optstr = "b:cCdfFnqvV";
418*7c478bd9Sstevel@tonic-gate #endif
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	while ((ch = getopt(argc, argv, optstr)) != EOF) {
421*7c478bd9Sstevel@tonic-gate 		/* Process all flags in this arg */
422*7c478bd9Sstevel@tonic-gate 		switch (ch) {
423*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
424*7c478bd9Sstevel@tonic-gate 			case 'D':
425*7c478bd9Sstevel@tonic-gate 				debug = 1;
426*7c478bd9Sstevel@tonic-gate 				break;
427*7c478bd9Sstevel@tonic-gate 			case 'V':
428*7c478bd9Sstevel@tonic-gate 				verbose = 1;
429*7c478bd9Sstevel@tonic-gate 				version();
430*7c478bd9Sstevel@tonic-gate 				break;
431*7c478bd9Sstevel@tonic-gate #else
432*7c478bd9Sstevel@tonic-gate 			case 'V':
433*7c478bd9Sstevel@tonic-gate 				version();
434*7c478bd9Sstevel@tonic-gate 				Vflg++;
435*7c478bd9Sstevel@tonic-gate 				break;
436*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
437*7c478bd9Sstevel@tonic-gate 			case 'v':
438*7c478bd9Sstevel@tonic-gate 				quiet = 0;
439*7c478bd9Sstevel@tonic-gate 				vflg++;
440*7c478bd9Sstevel@tonic-gate 				break;
441*7c478bd9Sstevel@tonic-gate 			case 'd':
442*7c478bd9Sstevel@tonic-gate 				do_decomp = 1;
443*7c478bd9Sstevel@tonic-gate 				dflg++;
444*7c478bd9Sstevel@tonic-gate 				break;
445*7c478bd9Sstevel@tonic-gate 			case 'f':
446*7c478bd9Sstevel@tonic-gate 			case 'F':
447*7c478bd9Sstevel@tonic-gate 				Fflg++;
448*7c478bd9Sstevel@tonic-gate 				overwrite = 1;
449*7c478bd9Sstevel@tonic-gate 				force = 1;
450*7c478bd9Sstevel@tonic-gate 				break;
451*7c478bd9Sstevel@tonic-gate 			case 'n':
452*7c478bd9Sstevel@tonic-gate 				nomagic = 1;
453*7c478bd9Sstevel@tonic-gate 				break;
454*7c478bd9Sstevel@tonic-gate 			case 'C':
455*7c478bd9Sstevel@tonic-gate 				Cflg++;
456*7c478bd9Sstevel@tonic-gate 				block_compress = 0;
457*7c478bd9Sstevel@tonic-gate 				break;
458*7c478bd9Sstevel@tonic-gate 			case 'b':
459*7c478bd9Sstevel@tonic-gate 				bflg++;
460*7c478bd9Sstevel@tonic-gate 				p = optarg;
461*7c478bd9Sstevel@tonic-gate 				if (!p) {
462*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
463*7c478bd9Sstevel@tonic-gate 						"Missing maxbits\n"));
464*7c478bd9Sstevel@tonic-gate 					Usage();
465*7c478bd9Sstevel@tonic-gate 					exit(1);
466*7c478bd9Sstevel@tonic-gate 				}
467*7c478bd9Sstevel@tonic-gate 				maxbits = strtoul(optarg, &p, 10);
468*7c478bd9Sstevel@tonic-gate 				if (*p) {
469*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
470*7c478bd9Sstevel@tonic-gate 						"Missing maxbits\n"));
471*7c478bd9Sstevel@tonic-gate 					Usage();
472*7c478bd9Sstevel@tonic-gate 					exit(1);
473*7c478bd9Sstevel@tonic-gate 				}
474*7c478bd9Sstevel@tonic-gate 				break;
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 			case 'c':
477*7c478bd9Sstevel@tonic-gate 				cflg++;
478*7c478bd9Sstevel@tonic-gate 				zcat_flg = 1;
479*7c478bd9Sstevel@tonic-gate 				break;
480*7c478bd9Sstevel@tonic-gate 			case 'q':
481*7c478bd9Sstevel@tonic-gate 				qflg++;
482*7c478bd9Sstevel@tonic-gate 				quiet = 1;
483*7c478bd9Sstevel@tonic-gate 				break;
484*7c478bd9Sstevel@tonic-gate 			default:
485*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
486*7c478bd9Sstevel@tonic-gate 					"Unknown flag: '%c'\n"), optopt);
487*7c478bd9Sstevel@tonic-gate 				Usage();
488*7c478bd9Sstevel@tonic-gate 				exit(1);
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 	} /* while */
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	/*
493*7c478bd9Sstevel@tonic-gate 	 * Validate zcat syntax
494*7c478bd9Sstevel@tonic-gate 	 */
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	if (zcat_cmd && (Fflg | Cflg | cflg |
497*7c478bd9Sstevel@tonic-gate 	    bflg | qflg | dflg | nomagic)) {
498*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
499*7c478bd9Sstevel@tonic-gate 			"Invalid Option\n"));
500*7c478bd9Sstevel@tonic-gate 		Usage();
501*7c478bd9Sstevel@tonic-gate 		exit(1);
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	/*
505*7c478bd9Sstevel@tonic-gate 	 * Process the file list
506*7c478bd9Sstevel@tonic-gate 	 */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	for (; optind < argc; optind++) {
509*7c478bd9Sstevel@tonic-gate 		if (strcmp(argv[optind], "-") == 0) {
510*7c478bd9Sstevel@tonic-gate 			dash_count++;
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 		*fileptr++ = argv[optind];	/* Build input file list */
514*7c478bd9Sstevel@tonic-gate 		*fileptr = NULL;
515*7c478bd9Sstevel@tonic-gate 	}
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	if (dash_count > 1) {
518*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
519*7c478bd9Sstevel@tonic-gate 			gettext("%s may only appear once in the file"
520*7c478bd9Sstevel@tonic-gate 				" list\n"), "\"-\"");
521*7c478bd9Sstevel@tonic-gate 		exit(1);
522*7c478bd9Sstevel@tonic-gate 	}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	if (fileptr - filelist == 0) {
525*7c478bd9Sstevel@tonic-gate 		*fileptr++ = "-";
526*7c478bd9Sstevel@tonic-gate 		*fileptr = NULL;
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	if (fileptr - filelist > 1 && cflg && !do_decomp) {
530*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
531*7c478bd9Sstevel@tonic-gate 			gettext("compress: only one file may be compressed"
532*7c478bd9Sstevel@tonic-gate 				" to stdout\n"));
533*7c478bd9Sstevel@tonic-gate 		exit(1);
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	if (maxbits < INIT_BITS)
537*7c478bd9Sstevel@tonic-gate 		maxbits = INIT_BITS;
538*7c478bd9Sstevel@tonic-gate 	if (maxbits > BITS)
539*7c478bd9Sstevel@tonic-gate 		maxbits = BITS;
540*7c478bd9Sstevel@tonic-gate 	maxmaxcode = 1 << maxbits;
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	/* Need to open something to close with freopen later */
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	if ((infile = fopen("/dev/null", "r")) == NULL) {
545*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error opening /dev/null for "
546*7c478bd9Sstevel@tonic-gate 			"input\n"));
547*7c478bd9Sstevel@tonic-gate 		exit(1);
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if ((outfile = fopen("/dev/null", "w")) == NULL) {
551*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error opening /dev/null for "
552*7c478bd9Sstevel@tonic-gate 			"output\n"));
553*7c478bd9Sstevel@tonic-gate 		exit(1);
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	for (fileptr = filelist; *fileptr; fileptr++) {
557*7c478bd9Sstevel@tonic-gate 		int jmpval = 0;
558*7c478bd9Sstevel@tonic-gate 		didnt_shrink = 0;
559*7c478bd9Sstevel@tonic-gate 		newline_needed = 0;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 		if (do_decomp) {
562*7c478bd9Sstevel@tonic-gate 			/* DECOMPRESSION */
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 			if (strcmp(*fileptr, "-") == 0) {
565*7c478bd9Sstevel@tonic-gate 				/* process stdin */
566*7c478bd9Sstevel@tonic-gate 				inp = stdin;
567*7c478bd9Sstevel@tonic-gate 				outp = stdout;
568*7c478bd9Sstevel@tonic-gate 				use_stdout = 1;
569*7c478bd9Sstevel@tonic-gate 				*fileptr = "stdin"; /* for error messages */
570*7c478bd9Sstevel@tonic-gate 			} else {
571*7c478bd9Sstevel@tonic-gate 				/* process the named file */
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 				inp = infile;
574*7c478bd9Sstevel@tonic-gate 				outp = outfile;
575*7c478bd9Sstevel@tonic-gate 				use_stdout = 0;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 				if (zcat_flg) {
578*7c478bd9Sstevel@tonic-gate 					use_stdout = 1;
579*7c478bd9Sstevel@tonic-gate 					outp = stdout;
580*7c478bd9Sstevel@tonic-gate 				}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 				/* Check for .Z suffix */
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 				if (strcmp(*fileptr +
585*7c478bd9Sstevel@tonic-gate 				    strlen(*fileptr) - 2, ".Z") != 0) {
586*7c478bd9Sstevel@tonic-gate 					/* No .Z: tack one on */
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 					if (strlcpy(tempname, *fileptr,
589*7c478bd9Sstevel@tonic-gate 						sizeof (tempname)) >=
590*7c478bd9Sstevel@tonic-gate 						sizeof (tempname)) {
591*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
592*7c478bd9Sstevel@tonic-gate 						    gettext("%s: filename "
593*7c478bd9Sstevel@tonic-gate 							"too long\n"),
594*7c478bd9Sstevel@tonic-gate 							*fileptr);
595*7c478bd9Sstevel@tonic-gate 						perm_stat = 1;
596*7c478bd9Sstevel@tonic-gate 						continue;
597*7c478bd9Sstevel@tonic-gate 					}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 					if (addDotZ(tempname,
600*7c478bd9Sstevel@tonic-gate 					    sizeof (tempname)) < 0) {
601*7c478bd9Sstevel@tonic-gate 						perm_stat = 1;
602*7c478bd9Sstevel@tonic-gate 						continue;
603*7c478bd9Sstevel@tonic-gate 					}
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 					*fileptr = tempname;
606*7c478bd9Sstevel@tonic-gate 				}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 				/* Open input file */
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 				if (stat(*fileptr, &statbuf) < 0) {
611*7c478bd9Sstevel@tonic-gate 					perror(*fileptr);
612*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
613*7c478bd9Sstevel@tonic-gate 					continue;
614*7c478bd9Sstevel@tonic-gate 				}
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 				if ((freopen(*fileptr, "r", inp)) == NULL) {
617*7c478bd9Sstevel@tonic-gate 					perror(*fileptr);
618*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
619*7c478bd9Sstevel@tonic-gate 					continue;
620*7c478bd9Sstevel@tonic-gate 				}
621*7c478bd9Sstevel@tonic-gate 			}
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 			/* Check the magic number */
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 			if (nomagic == 0) {
626*7c478bd9Sstevel@tonic-gate 				if ((getc(inp) !=
627*7c478bd9Sstevel@tonic-gate 				    (magic_header[0] & 0xFF)) ||
628*7c478bd9Sstevel@tonic-gate 				    (getc(inp) !=
629*7c478bd9Sstevel@tonic-gate 				    (magic_header[1] & 0xFF))) {
630*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
631*7c478bd9Sstevel@tonic-gate 						"%s: not in compressed "
632*7c478bd9Sstevel@tonic-gate 						"format\n"),
633*7c478bd9Sstevel@tonic-gate 						*fileptr);
634*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
635*7c478bd9Sstevel@tonic-gate 					continue;
636*7c478bd9Sstevel@tonic-gate 				}
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 				/* set -b from file */
639*7c478bd9Sstevel@tonic-gate 				if ((maxbits = getc(inp)) == EOF &&
640*7c478bd9Sstevel@tonic-gate 				    ferror(inp)) {
641*7c478bd9Sstevel@tonic-gate 					perror(*fileptr);
642*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
643*7c478bd9Sstevel@tonic-gate 					continue;
644*7c478bd9Sstevel@tonic-gate 				}
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 				block_compress = maxbits & BLOCK_MASK;
647*7c478bd9Sstevel@tonic-gate 				maxbits &= BIT_MASK;
648*7c478bd9Sstevel@tonic-gate 				maxmaxcode = 1 << maxbits;
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 				if (maxbits > BITS) {
651*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
652*7c478bd9Sstevel@tonic-gate 						gettext("%s: compressed "
653*7c478bd9Sstevel@tonic-gate 							"with %d bits, "
654*7c478bd9Sstevel@tonic-gate 							"can only handle"
655*7c478bd9Sstevel@tonic-gate 							" %d bits\n"),
656*7c478bd9Sstevel@tonic-gate 						*fileptr, maxbits, BITS);
657*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
658*7c478bd9Sstevel@tonic-gate 					continue;
659*7c478bd9Sstevel@tonic-gate 				}
660*7c478bd9Sstevel@tonic-gate 			}
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 			if (!use_stdout) {
663*7c478bd9Sstevel@tonic-gate 				/* Generate output filename */
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 				if (strlcpy(ofname, *fileptr,
666*7c478bd9Sstevel@tonic-gate 					    sizeof (ofname)) >=
667*7c478bd9Sstevel@tonic-gate 				    sizeof (ofname)) {
668*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
669*7c478bd9Sstevel@tonic-gate 						gettext("%s: filename "
670*7c478bd9Sstevel@tonic-gate 							"too long\n"),
671*7c478bd9Sstevel@tonic-gate 						*fileptr);
672*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
673*7c478bd9Sstevel@tonic-gate 					continue;
674*7c478bd9Sstevel@tonic-gate 				}
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 				/* Strip off .Z */
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 				ofname[strlen(*fileptr) - 2] = '\0';
679*7c478bd9Sstevel@tonic-gate 			}
680*7c478bd9Sstevel@tonic-gate 		} else {
681*7c478bd9Sstevel@tonic-gate 			/* COMPRESSION */
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 			if (strcmp(*fileptr, "-") == 0) {
684*7c478bd9Sstevel@tonic-gate 				/* process stdin */
685*7c478bd9Sstevel@tonic-gate 				inp = stdin;
686*7c478bd9Sstevel@tonic-gate 				outp = stdout;
687*7c478bd9Sstevel@tonic-gate 				use_stdout = 1;
688*7c478bd9Sstevel@tonic-gate 				*fileptr = "stdin"; /* for error messages */
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 				/* Use the largest possible hash table */
691*7c478bd9Sstevel@tonic-gate 				hsize =  HSIZE;
692*7c478bd9Sstevel@tonic-gate 			} else {
693*7c478bd9Sstevel@tonic-gate 				/* process the named file */
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 				inp = infile;
696*7c478bd9Sstevel@tonic-gate 				outp = outfile;
697*7c478bd9Sstevel@tonic-gate 				use_stdout = 0;
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 				if (zcat_flg) {
700*7c478bd9Sstevel@tonic-gate 					use_stdout = 1;
701*7c478bd9Sstevel@tonic-gate 					outp = stdout;
702*7c478bd9Sstevel@tonic-gate 				}
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 				if (strcmp(*fileptr +
705*7c478bd9Sstevel@tonic-gate 				    strlen(*fileptr) - 2, ".Z") == 0) {
706*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
707*7c478bd9Sstevel@tonic-gate 						"%s: already has .Z "
708*7c478bd9Sstevel@tonic-gate 						"suffix -- no change\n"),
709*7c478bd9Sstevel@tonic-gate 						*fileptr);
710*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
711*7c478bd9Sstevel@tonic-gate 					continue;
712*7c478bd9Sstevel@tonic-gate 				}
713*7c478bd9Sstevel@tonic-gate 				/* Open input file */
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 				if (stat(*fileptr, &statbuf) < 0) {
716*7c478bd9Sstevel@tonic-gate 					perror(*fileptr);
717*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
718*7c478bd9Sstevel@tonic-gate 					continue;
719*7c478bd9Sstevel@tonic-gate 				}
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 				if ((freopen(*fileptr, "r", inp)) == NULL) {
722*7c478bd9Sstevel@tonic-gate 					perror(*fileptr);
723*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
724*7c478bd9Sstevel@tonic-gate 					continue;
725*7c478bd9Sstevel@tonic-gate 				}
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 				fsize = (off_t)statbuf.st_size;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 				/*
730*7c478bd9Sstevel@tonic-gate 				 * tune hash table size for small
731*7c478bd9Sstevel@tonic-gate 				 * files -- ad hoc,
732*7c478bd9Sstevel@tonic-gate 				 * but the sizes match earlier #defines, which
733*7c478bd9Sstevel@tonic-gate 				 * serve as upper bounds on the number of
734*7c478bd9Sstevel@tonic-gate 				 * output codes.
735*7c478bd9Sstevel@tonic-gate 				 */
736*7c478bd9Sstevel@tonic-gate 				hsize = HSIZE;
737*7c478bd9Sstevel@tonic-gate 				if (fsize < (1 << 12))
738*7c478bd9Sstevel@tonic-gate 					hsize = min(5003, HSIZE);
739*7c478bd9Sstevel@tonic-gate 				else if (fsize < (1 << 13))
740*7c478bd9Sstevel@tonic-gate 					hsize = min(9001, HSIZE);
741*7c478bd9Sstevel@tonic-gate 				else if (fsize < (1 << 14))
742*7c478bd9Sstevel@tonic-gate 					hsize = min(18013, HSIZE);
743*7c478bd9Sstevel@tonic-gate 				else if (fsize < (1 << 15))
744*7c478bd9Sstevel@tonic-gate 					hsize = min(35023, HSIZE);
745*7c478bd9Sstevel@tonic-gate 				else if (fsize < 47000)
746*7c478bd9Sstevel@tonic-gate 					hsize = min(50021, HSIZE);
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 				if (!use_stdout) {
749*7c478bd9Sstevel@tonic-gate 					/* Generate output filename */
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 					if (strlcpy(ofname, *fileptr,
752*7c478bd9Sstevel@tonic-gate 						sizeof (ofname)) >=
753*7c478bd9Sstevel@tonic-gate 						sizeof (ofname)) {
754*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
755*7c478bd9Sstevel@tonic-gate 						    gettext("%s: filename "
756*7c478bd9Sstevel@tonic-gate 							"too long\n"),
757*7c478bd9Sstevel@tonic-gate 							*fileptr);
758*7c478bd9Sstevel@tonic-gate 						perm_stat = 1;
759*7c478bd9Sstevel@tonic-gate 						continue;
760*7c478bd9Sstevel@tonic-gate 					}
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 					if (addDotZ(ofname,
763*7c478bd9Sstevel@tonic-gate 						sizeof (ofname)) < 0) {
764*7c478bd9Sstevel@tonic-gate 						perm_stat = 1;
765*7c478bd9Sstevel@tonic-gate 						continue;
766*7c478bd9Sstevel@tonic-gate 					}
767*7c478bd9Sstevel@tonic-gate 				}
768*7c478bd9Sstevel@tonic-gate 			}
769*7c478bd9Sstevel@tonic-gate 		}	/* if (do_decomp) */
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 		/* Check for overwrite of existing file */
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 		if (!overwrite && !use_stdout) {
774*7c478bd9Sstevel@tonic-gate 			if (stat(ofname, &ostatbuf) == 0) {
775*7c478bd9Sstevel@tonic-gate 				yesorno[ynsize] = (char)NULL;
776*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
777*7c478bd9Sstevel@tonic-gate 					"%s already exists;"), ofname);
778*7c478bd9Sstevel@tonic-gate 				if (bgnd_flag == 0 && isatty(2)) {
779*7c478bd9Sstevel@tonic-gate 					int cin;
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
782*7c478bd9Sstevel@tonic-gate 						" do you wish to overwr"
783*7c478bd9Sstevel@tonic-gate 						"ite %s (%s or %s)? "),
784*7c478bd9Sstevel@tonic-gate 						ofname, yesstr, nostr);
785*7c478bd9Sstevel@tonic-gate 					(void) fflush(stderr);
786*7c478bd9Sstevel@tonic-gate 					for (cin = 0; cin < LINE_MAX;
787*7c478bd9Sstevel@tonic-gate 					    cin++)
788*7c478bd9Sstevel@tonic-gate 						line[cin] = 0;
789*7c478bd9Sstevel@tonic-gate 					(void) read(2, line, LINE_MAX);
790*7c478bd9Sstevel@tonic-gate 					(void) strncpy(yesorno, line,
791*7c478bd9Sstevel@tonic-gate 						ynsize);
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 					if (!((strncmp(yesstr, yesorno,
794*7c478bd9Sstevel@tonic-gate 						ynsize) == 0) ||
795*7c478bd9Sstevel@tonic-gate 						(yesorno[0] == 'y') ||
796*7c478bd9Sstevel@tonic-gate 						(yesorno[0] == 'Y'))) {
797*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
798*7c478bd9Sstevel@tonic-gate 							gettext(
799*7c478bd9Sstevel@tonic-gate 							"\tnot overwri"
800*7c478bd9Sstevel@tonic-gate 							"tten\n"));
801*7c478bd9Sstevel@tonic-gate 						continue;
802*7c478bd9Sstevel@tonic-gate 					}
803*7c478bd9Sstevel@tonic-gate 				} else {
804*7c478bd9Sstevel@tonic-gate 					/*
805*7c478bd9Sstevel@tonic-gate 					 * XPG4: Assertion 1009
806*7c478bd9Sstevel@tonic-gate 					 * Standard input is not
807*7c478bd9Sstevel@tonic-gate 					 * terminal, and no '-f',
808*7c478bd9Sstevel@tonic-gate 					 * and file exists.
809*7c478bd9Sstevel@tonic-gate 					 */
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
812*7c478bd9Sstevel@tonic-gate 						"%s: File exists, -f not"
813*7c478bd9Sstevel@tonic-gate 						" specified, and ru"
814*7c478bd9Sstevel@tonic-gate 						"nning in the backgro"
815*7c478bd9Sstevel@tonic-gate 						"und.\n"), *fileptr);
816*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
817*7c478bd9Sstevel@tonic-gate 					continue;
818*7c478bd9Sstevel@tonic-gate 				}
819*7c478bd9Sstevel@tonic-gate 			}
820*7c478bd9Sstevel@tonic-gate 		}
821*7c478bd9Sstevel@tonic-gate 		if (!use_stdout) {
822*7c478bd9Sstevel@tonic-gate 			if (pathconf(ofname, _PC_XATTR_EXISTS) == 1) {
823*7c478bd9Sstevel@tonic-gate 				(void) unlink(ofname);
824*7c478bd9Sstevel@tonic-gate 			}
825*7c478bd9Sstevel@tonic-gate 			/* Open output file */
826*7c478bd9Sstevel@tonic-gate 			if (freopen(ofname, "w", outp) == NULL) {
827*7c478bd9Sstevel@tonic-gate 				perror(ofname);
828*7c478bd9Sstevel@tonic-gate 				perm_stat = 1;
829*7c478bd9Sstevel@tonic-gate 				continue;
830*7c478bd9Sstevel@tonic-gate 			}
831*7c478bd9Sstevel@tonic-gate 			precious = 0;
832*7c478bd9Sstevel@tonic-gate 			if (!quiet) {
833*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: ",
834*7c478bd9Sstevel@tonic-gate 					*fileptr);
835*7c478bd9Sstevel@tonic-gate 				newline_needed = 1;
836*7c478bd9Sstevel@tonic-gate 			}
837*7c478bd9Sstevel@tonic-gate 		} else if (!quiet && !do_decomp) {
838*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ",
839*7c478bd9Sstevel@tonic-gate 				*fileptr);
840*7c478bd9Sstevel@tonic-gate 				newline_needed = 1;
841*7c478bd9Sstevel@tonic-gate 		}
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 		/* Actually do the compression/decompression */
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 		if ((jmpval = setjmp(env)) == 0) {
846*7c478bd9Sstevel@tonic-gate 			/* We'll see how things go */
847*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
848*7c478bd9Sstevel@tonic-gate 			if (do_decomp == 0)  {
849*7c478bd9Sstevel@tonic-gate 				compress();
850*7c478bd9Sstevel@tonic-gate 			} else {
851*7c478bd9Sstevel@tonic-gate 				decompress();
852*7c478bd9Sstevel@tonic-gate 			}
853*7c478bd9Sstevel@tonic-gate #else
854*7c478bd9Sstevel@tonic-gate 			if (do_decomp == 0)  {
855*7c478bd9Sstevel@tonic-gate 				compress();
856*7c478bd9Sstevel@tonic-gate 			} else if (debug == 0)  {
857*7c478bd9Sstevel@tonic-gate 				decompress();
858*7c478bd9Sstevel@tonic-gate 			} else {
859*7c478bd9Sstevel@tonic-gate 				printcodes();
860*7c478bd9Sstevel@tonic-gate 			}
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 			if (verbose) {
863*7c478bd9Sstevel@tonic-gate 				dump_tab();
864*7c478bd9Sstevel@tonic-gate 			}
865*7c478bd9Sstevel@tonic-gate #endif
866*7c478bd9Sstevel@tonic-gate 		} else {
867*7c478bd9Sstevel@tonic-gate 			/*
868*7c478bd9Sstevel@tonic-gate 			 * Things went badly - clean up and go on.
869*7c478bd9Sstevel@tonic-gate 			 * jmpval's values break down as follows:
870*7c478bd9Sstevel@tonic-gate 			 *   1 == message determined by ferror() values.
871*7c478bd9Sstevel@tonic-gate 			 *   2 == input problem message needed.
872*7c478bd9Sstevel@tonic-gate 			 *   3 == output problem message needed.
873*7c478bd9Sstevel@tonic-gate 			 */
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 			if (ferror(inp) || jmpval == 2) {
876*7c478bd9Sstevel@tonic-gate 				if (do_decomp) {
877*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
878*7c478bd9Sstevel@tonic-gate 						"uncompress: %s: corrupt"
879*7c478bd9Sstevel@tonic-gate 						" input\n"), *fileptr);
880*7c478bd9Sstevel@tonic-gate 				} else {
881*7c478bd9Sstevel@tonic-gate 					perror(*fileptr);
882*7c478bd9Sstevel@tonic-gate 				}
883*7c478bd9Sstevel@tonic-gate 			}
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 			if (ferror(outp) || jmpval == 3) {
886*7c478bd9Sstevel@tonic-gate 				/* handle output errors */
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 				if (use_stdout) {
889*7c478bd9Sstevel@tonic-gate 					perror("");
890*7c478bd9Sstevel@tonic-gate 				} else {
891*7c478bd9Sstevel@tonic-gate 					perror(ofname);
892*7c478bd9Sstevel@tonic-gate 				}
893*7c478bd9Sstevel@tonic-gate 			}
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 			if (ofname[0] != '\0') {
896*7c478bd9Sstevel@tonic-gate 				if (unlink(ofname) < 0)  {
897*7c478bd9Sstevel@tonic-gate 					perror(ofname);
898*7c478bd9Sstevel@tonic-gate 				}
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 				ofname[0] = '\0';
901*7c478bd9Sstevel@tonic-gate 			}
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 			perm_stat = 1;
904*7c478bd9Sstevel@tonic-gate 			continue;
905*7c478bd9Sstevel@tonic-gate 		}
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 		/* Things went well */
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 		if (!use_stdout) {
910*7c478bd9Sstevel@tonic-gate 				/* Copy stats */
911*7c478bd9Sstevel@tonic-gate 			copystat(*fileptr, &statbuf, ofname);
912*7c478bd9Sstevel@tonic-gate 			precious = 1;
913*7c478bd9Sstevel@tonic-gate 			if (newline_needed) {
914*7c478bd9Sstevel@tonic-gate 				(void) putc('\n', stderr);
915*7c478bd9Sstevel@tonic-gate 			}
916*7c478bd9Sstevel@tonic-gate 			/*
917*7c478bd9Sstevel@tonic-gate 			 * Print the info. for unchanged file
918*7c478bd9Sstevel@tonic-gate 			 * when no -v
919*7c478bd9Sstevel@tonic-gate 			 */
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 			if (didnt_shrink) {
922*7c478bd9Sstevel@tonic-gate 				if (!force && perm_stat == 0) {
923*7c478bd9Sstevel@tonic-gate 					if (quiet) {
924*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
925*7c478bd9Sstevel@tonic-gate 							"%s: -- file "
926*7c478bd9Sstevel@tonic-gate 							"unchanged\n"),
927*7c478bd9Sstevel@tonic-gate 							*fileptr);
928*7c478bd9Sstevel@tonic-gate 					}
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 					perm_stat = 2;
931*7c478bd9Sstevel@tonic-gate 				}
932*7c478bd9Sstevel@tonic-gate 			}
933*7c478bd9Sstevel@tonic-gate 		} else {
934*7c478bd9Sstevel@tonic-gate 			if (didnt_shrink && !force && perm_stat == 0) {
935*7c478bd9Sstevel@tonic-gate 				perm_stat = 2;
936*7c478bd9Sstevel@tonic-gate 			}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 			if (newline_needed) {
939*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "\n");
940*7c478bd9Sstevel@tonic-gate 			}
941*7c478bd9Sstevel@tonic-gate 		}
942*7c478bd9Sstevel@tonic-gate 	}	/* for */
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	return (perm_stat);
945*7c478bd9Sstevel@tonic-gate }
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate static void
948*7c478bd9Sstevel@tonic-gate cinterr(int hshift)
949*7c478bd9Sstevel@tonic-gate {
950*7c478bd9Sstevel@tonic-gate 	/* we have exceeded the hash table */
951*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
952*7c478bd9Sstevel@tonic-gate 		"internal error: hashtable exceeded - hsize = %ld\n", hsize);
953*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "hshift = %d, %d\n", hshift, (1 << hshift) -1);
954*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "maxbits = %d\n", maxbits);
955*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "n_bits = %d\n", n_bits);
956*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "maxcode = %ld\n", maxcode);
957*7c478bd9Sstevel@tonic-gate 	longjmp(env, 1);
958*7c478bd9Sstevel@tonic-gate }
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate static code_int
961*7c478bd9Sstevel@tonic-gate adjusti(code_int i, code_int hsize_reg)
962*7c478bd9Sstevel@tonic-gate {
963*7c478bd9Sstevel@tonic-gate 	while (i < 0) {
964*7c478bd9Sstevel@tonic-gate 		i += hsize_reg;
965*7c478bd9Sstevel@tonic-gate 	}
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	while (i >= hsize_reg) {
968*7c478bd9Sstevel@tonic-gate 		i -= hsize_reg;
969*7c478bd9Sstevel@tonic-gate 	}
970*7c478bd9Sstevel@tonic-gate 	return (i);
971*7c478bd9Sstevel@tonic-gate }
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate /*
974*7c478bd9Sstevel@tonic-gate  * compress inp to outp
975*7c478bd9Sstevel@tonic-gate  *
976*7c478bd9Sstevel@tonic-gate  * Algorithm:  use open addressing double hashing(no chaining) on the
977*7c478bd9Sstevel@tonic-gate  * prefix code / next character combination.  We do a variant of Knuth's
978*7c478bd9Sstevel@tonic-gate  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
979*7c478bd9Sstevel@tonic-gate  * secondary probe.  Here, the modular division first probe is gives way
980*7c478bd9Sstevel@tonic-gate  * to a faster exclusive-or manipulation.  Also do block compression with
981*7c478bd9Sstevel@tonic-gate  * an adaptive reset, whereby the code table is cleared when the compression
982*7c478bd9Sstevel@tonic-gate  * ratio decreases, but after the table fills.  The variable-length output
983*7c478bd9Sstevel@tonic-gate  * codes are re-sized at this point, and a special CLEAR code is generated
984*7c478bd9Sstevel@tonic-gate  * for the decompressor.  Late addition:  construct the table according to
985*7c478bd9Sstevel@tonic-gate  * file size for noticeable speed improvement on small files.  Please direct
986*7c478bd9Sstevel@tonic-gate  * questions about this implementation to ames!jaw.
987*7c478bd9Sstevel@tonic-gate  */
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate static void
990*7c478bd9Sstevel@tonic-gate compress()
991*7c478bd9Sstevel@tonic-gate {
992*7c478bd9Sstevel@tonic-gate 	long fcode;
993*7c478bd9Sstevel@tonic-gate 	code_int i = 0;
994*7c478bd9Sstevel@tonic-gate 	int c;
995*7c478bd9Sstevel@tonic-gate 	code_int ent;
996*7c478bd9Sstevel@tonic-gate 	int disp;
997*7c478bd9Sstevel@tonic-gate 	code_int hsize_reg;
998*7c478bd9Sstevel@tonic-gate 	int hshift;
999*7c478bd9Sstevel@tonic-gate 	int probecnt;
1000*7c478bd9Sstevel@tonic-gate 	count_long in_count;
1001*7c478bd9Sstevel@tonic-gate 	uint32_t inchi, inclo;
1002*7c478bd9Sstevel@tonic-gate 	int maxbits_reg;
1003*7c478bd9Sstevel@tonic-gate 	FILE *fin = inp;
1004*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1005*7c478bd9Sstevel@tonic-gate 	count_long out_count = 0;
1006*7c478bd9Sstevel@tonic-gate #endif
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	if (nomagic == 0) {
1009*7c478bd9Sstevel@tonic-gate 		if ((putc(magic_header[0], outp) == EOF ||
1010*7c478bd9Sstevel@tonic-gate 		    putc(magic_header[1], outp) == EOF ||
1011*7c478bd9Sstevel@tonic-gate 		    putc((char)(maxbits | block_compress),
1012*7c478bd9Sstevel@tonic-gate 			outp) == EOF) &&
1013*7c478bd9Sstevel@tonic-gate 		    ferror(outp)) {
1014*7c478bd9Sstevel@tonic-gate 			ioerror();
1015*7c478bd9Sstevel@tonic-gate 		}
1016*7c478bd9Sstevel@tonic-gate 	}
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	offset = 0;
1019*7c478bd9Sstevel@tonic-gate 	bytes_out = 3;		/* includes 3-byte header mojo */
1020*7c478bd9Sstevel@tonic-gate 	clear_flg = 0;
1021*7c478bd9Sstevel@tonic-gate 	ratio = 0;
1022*7c478bd9Sstevel@tonic-gate 	in_count = 1;
1023*7c478bd9Sstevel@tonic-gate 	inchi = 0;
1024*7c478bd9Sstevel@tonic-gate 	inclo = 1;
1025*7c478bd9Sstevel@tonic-gate 	checkpoint = CHECK_GAP;
1026*7c478bd9Sstevel@tonic-gate 	maxcode = MAXCODE(n_bits = INIT_BITS);
1027*7c478bd9Sstevel@tonic-gate 	free_ent = ((block_compress) ? FIRST : 256);
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	if ((ent = getc(fin)) == EOF && ferror(fin)) {
1030*7c478bd9Sstevel@tonic-gate 		ioerror();
1031*7c478bd9Sstevel@tonic-gate 	}
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	hshift = 0;
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	for (fcode = (long)hsize;  fcode < 65536L; fcode *= 2L)
1036*7c478bd9Sstevel@tonic-gate 		hshift++;
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	hshift = 8 - hshift;		/* set hash code range bound */
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	hsize_reg = hsize;
1041*7c478bd9Sstevel@tonic-gate 	maxbits_reg = maxbits;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	cl_hash((count_int) hsize_reg);		/* clear hash table */
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 	while ((c = getc(fin)) != EOF) {
1046*7c478bd9Sstevel@tonic-gate 		if (++inclo == 0)
1047*7c478bd9Sstevel@tonic-gate 			inchi++;
1048*7c478bd9Sstevel@tonic-gate 		fcode = (long)(((long)c << maxbits_reg) + ent);
1049*7c478bd9Sstevel@tonic-gate 		i = ((c << hshift) ^ ent);	/* xor hashing */
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 		if ((unsigned int)i >= hsize_reg)
1052*7c478bd9Sstevel@tonic-gate 			i = adjusti(i, hsize_reg);
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 		if (htabof(i) == fcode) {
1055*7c478bd9Sstevel@tonic-gate 			ent = codetabof(i);
1056*7c478bd9Sstevel@tonic-gate 			continue;
1057*7c478bd9Sstevel@tonic-gate 		} else if ((long)htabof(i) < 0) {
1058*7c478bd9Sstevel@tonic-gate 			/* empty slot */
1059*7c478bd9Sstevel@tonic-gate 			goto nomatch;
1060*7c478bd9Sstevel@tonic-gate 		}
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 		/* secondary hash (after G. Knott) */
1063*7c478bd9Sstevel@tonic-gate 		disp = hsize_reg - i;
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 		if (i == 0) {
1066*7c478bd9Sstevel@tonic-gate 			disp = 1;
1067*7c478bd9Sstevel@tonic-gate 		}
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 		probecnt = 0;
1070*7c478bd9Sstevel@tonic-gate 	probe:
1071*7c478bd9Sstevel@tonic-gate 		if (++probecnt > hsize_reg)
1072*7c478bd9Sstevel@tonic-gate 			cinterr(hshift);
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 		if ((i -= disp) < 0) {
1075*7c478bd9Sstevel@tonic-gate 			while (i < 0)
1076*7c478bd9Sstevel@tonic-gate 				i += hsize_reg;
1077*7c478bd9Sstevel@tonic-gate 		}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 		if (htabof(i) == fcode) {
1080*7c478bd9Sstevel@tonic-gate 			ent = codetabof(i);
1081*7c478bd9Sstevel@tonic-gate 			continue;
1082*7c478bd9Sstevel@tonic-gate 		}
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 		if ((long)htabof(i) > 0) {
1085*7c478bd9Sstevel@tonic-gate 			goto probe;
1086*7c478bd9Sstevel@tonic-gate 		}
1087*7c478bd9Sstevel@tonic-gate 	nomatch:
1088*7c478bd9Sstevel@tonic-gate 		output((code_int) ent);
1089*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1090*7c478bd9Sstevel@tonic-gate 		out_count++;
1091*7c478bd9Sstevel@tonic-gate #endif
1092*7c478bd9Sstevel@tonic-gate 		ent = c;
1093*7c478bd9Sstevel@tonic-gate 		if (free_ent < maxmaxcode) {
1094*7c478bd9Sstevel@tonic-gate 			codetabof(i) = free_ent++;
1095*7c478bd9Sstevel@tonic-gate 			/* code -> hashtable */
1096*7c478bd9Sstevel@tonic-gate 			htabof(i) = fcode;
1097*7c478bd9Sstevel@tonic-gate 		} else {
1098*7c478bd9Sstevel@tonic-gate 			in_count = ((long long)inchi<<32|inclo);
1099*7c478bd9Sstevel@tonic-gate 			if ((count_long)in_count >=
1100*7c478bd9Sstevel@tonic-gate 			    (count_long)checkpoint && block_compress) {
1101*7c478bd9Sstevel@tonic-gate 				cl_block(in_count);
1102*7c478bd9Sstevel@tonic-gate 			}
1103*7c478bd9Sstevel@tonic-gate 		}
1104*7c478bd9Sstevel@tonic-gate 	}
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	in_count = ((long long)inchi<<32|inclo);
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	if (ferror(fin) != 0) {
1109*7c478bd9Sstevel@tonic-gate 		ioerror();
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	/*
1113*7c478bd9Sstevel@tonic-gate 	 * Put out the final code.
1114*7c478bd9Sstevel@tonic-gate 	 */
1115*7c478bd9Sstevel@tonic-gate 	output((code_int)ent);
1116*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1117*7c478bd9Sstevel@tonic-gate 	out_count++;
1118*7c478bd9Sstevel@tonic-gate #endif
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	output((code_int)-1);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	/*
1123*7c478bd9Sstevel@tonic-gate 	 * Print out stats on stderr
1124*7c478bd9Sstevel@tonic-gate 	 */
1125*7c478bd9Sstevel@tonic-gate 	if (!quiet) {
1126*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1127*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1128*7c478bd9Sstevel@tonic-gate 			"%lld chars in, %lld codes (%lld bytes) out, "
1129*7c478bd9Sstevel@tonic-gate 			"compression factor: ",
1130*7c478bd9Sstevel@tonic-gate 			(count_long)in_count, (count_long)out_count,
1131*7c478bd9Sstevel@tonic-gate 			(count_long) bytes_out);
1132*7c478bd9Sstevel@tonic-gate 		prratio(stderr, (count_long)in_count,
1133*7c478bd9Sstevel@tonic-gate 			(count_long)bytes_out);
1134*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
1135*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\tCompression as in compact: ");
1136*7c478bd9Sstevel@tonic-gate 		prratio(stderr,
1137*7c478bd9Sstevel@tonic-gate 			(count_long)in_count-(count_long)bytes_out,
1138*7c478bd9Sstevel@tonic-gate 			(count_long)in_count);
1139*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
1140*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1141*7c478bd9Sstevel@tonic-gate 			"\tLargest code (of last block) was %d"
1142*7c478bd9Sstevel@tonic-gate 			" (%d bits)\n",
1143*7c478bd9Sstevel@tonic-gate 			free_ent - 1, n_bits);
1144*7c478bd9Sstevel@tonic-gate #else /* !DEBUG */
1145*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Compression: "));
1146*7c478bd9Sstevel@tonic-gate 		prratio(stderr,
1147*7c478bd9Sstevel@tonic-gate 			(count_long)in_count-(count_long)bytes_out,
1148*7c478bd9Sstevel@tonic-gate 			(count_long)in_count);
1149*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1150*7c478bd9Sstevel@tonic-gate 	}
1151*7c478bd9Sstevel@tonic-gate 	/* report if no savings */
1152*7c478bd9Sstevel@tonic-gate 	if ((count_long)bytes_out > (count_long)in_count) {
1153*7c478bd9Sstevel@tonic-gate 		didnt_shrink = 1;
1154*7c478bd9Sstevel@tonic-gate 	}
1155*7c478bd9Sstevel@tonic-gate }
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate /*
1158*7c478bd9Sstevel@tonic-gate  * **************************************************************
1159*7c478bd9Sstevel@tonic-gate  * TAG(output)
1160*7c478bd9Sstevel@tonic-gate  *
1161*7c478bd9Sstevel@tonic-gate  * Output the given code.
1162*7c478bd9Sstevel@tonic-gate  * Inputs:
1163*7c478bd9Sstevel@tonic-gate  * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
1164*7c478bd9Sstevel@tonic-gate  *		that n_bits = < (long)wordsize - 1.
1165*7c478bd9Sstevel@tonic-gate  * Outputs:
1166*7c478bd9Sstevel@tonic-gate  * 	Outputs code to the file.
1167*7c478bd9Sstevel@tonic-gate  * Assumptions:
1168*7c478bd9Sstevel@tonic-gate  *	Chars are 8 bits long.
1169*7c478bd9Sstevel@tonic-gate  * Algorithm:
1170*7c478bd9Sstevel@tonic-gate  * 	Maintain a BITS character long buffer(so that 8 codes will
1171*7c478bd9Sstevel@tonic-gate  * fit in it exactly).  Use the VAX insv instruction to insert each
1172*7c478bd9Sstevel@tonic-gate  * code in turn.  When the buffer fills up empty it and start over.
1173*7c478bd9Sstevel@tonic-gate  */
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate static void
1176*7c478bd9Sstevel@tonic-gate output(code_int code)
1177*7c478bd9Sstevel@tonic-gate {
1178*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1179*7c478bd9Sstevel@tonic-gate 	static int col = 0;
1180*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 	int r_off = offset, bits = n_bits;
1183*7c478bd9Sstevel@tonic-gate 	char *bp = buf;
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1186*7c478bd9Sstevel@tonic-gate 	if (verbose)
1187*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%5d%c", code,
1188*7c478bd9Sstevel@tonic-gate 			(col += 6) >= 74 ? (col = 0, '\n') : ' ');
1189*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1190*7c478bd9Sstevel@tonic-gate 	if (code >= 0) {
1191*7c478bd9Sstevel@tonic-gate 		/*
1192*7c478bd9Sstevel@tonic-gate 		 * byte/bit numbering on the VAX is simulated
1193*7c478bd9Sstevel@tonic-gate 		 * by the following code
1194*7c478bd9Sstevel@tonic-gate 		 */
1195*7c478bd9Sstevel@tonic-gate 		/*
1196*7c478bd9Sstevel@tonic-gate 		 * Get to the first byte.
1197*7c478bd9Sstevel@tonic-gate 		 */
1198*7c478bd9Sstevel@tonic-gate 		bp += (r_off >> 3);
1199*7c478bd9Sstevel@tonic-gate 		r_off &= 7;
1200*7c478bd9Sstevel@tonic-gate 		/*
1201*7c478bd9Sstevel@tonic-gate 		 * Since code is always >= 8 bits, only need to mask the first
1202*7c478bd9Sstevel@tonic-gate 		 * hunk on the left.
1203*7c478bd9Sstevel@tonic-gate 		 */
1204*7c478bd9Sstevel@tonic-gate 		*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
1205*7c478bd9Sstevel@tonic-gate 		bp++;
1206*7c478bd9Sstevel@tonic-gate 		bits -= (8 - r_off);
1207*7c478bd9Sstevel@tonic-gate 		code >>= 8 - r_off;
1208*7c478bd9Sstevel@tonic-gate 		/*
1209*7c478bd9Sstevel@tonic-gate 		 * Get any 8 bit parts in the middle (<=1 for up to 16
1210*7c478bd9Sstevel@tonic-gate 		 * bits).
1211*7c478bd9Sstevel@tonic-gate 		 */
1212*7c478bd9Sstevel@tonic-gate 		if (bits >= 8) {
1213*7c478bd9Sstevel@tonic-gate 			*bp++ = code;
1214*7c478bd9Sstevel@tonic-gate 			code >>= 8;
1215*7c478bd9Sstevel@tonic-gate 			bits -= 8;
1216*7c478bd9Sstevel@tonic-gate 		}
1217*7c478bd9Sstevel@tonic-gate 		/* Last bits. */
1218*7c478bd9Sstevel@tonic-gate 		if (bits)
1219*7c478bd9Sstevel@tonic-gate 			*bp = code;
1220*7c478bd9Sstevel@tonic-gate 		offset += n_bits;
1221*7c478bd9Sstevel@tonic-gate 		if (offset == (n_bits << 3)) {
1222*7c478bd9Sstevel@tonic-gate 			bp = buf;
1223*7c478bd9Sstevel@tonic-gate 			bits = n_bits;
1224*7c478bd9Sstevel@tonic-gate 			bytes_out += bits;
1225*7c478bd9Sstevel@tonic-gate 			do {
1226*7c478bd9Sstevel@tonic-gate 				if (putc(*bp, outp) == EOF &&
1227*7c478bd9Sstevel@tonic-gate 				    ferror(outp)) {
1228*7c478bd9Sstevel@tonic-gate 					ioerror();
1229*7c478bd9Sstevel@tonic-gate 				}
1230*7c478bd9Sstevel@tonic-gate 				bp++;
1231*7c478bd9Sstevel@tonic-gate 			} while (--bits);
1232*7c478bd9Sstevel@tonic-gate 			offset = 0;
1233*7c478bd9Sstevel@tonic-gate 		}
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 		/*
1236*7c478bd9Sstevel@tonic-gate 		 * If the next entry is going to be too big for the code size,
1237*7c478bd9Sstevel@tonic-gate 		 * then increase it, if possible.
1238*7c478bd9Sstevel@tonic-gate 		 */
1239*7c478bd9Sstevel@tonic-gate 		if (free_ent > maxcode || (clear_flg > 0)) {
1240*7c478bd9Sstevel@tonic-gate 			/*
1241*7c478bd9Sstevel@tonic-gate 			 * Write the whole buffer, because the input
1242*7c478bd9Sstevel@tonic-gate 			 * side won't discover the size increase until
1243*7c478bd9Sstevel@tonic-gate 			 * after it has read it.
1244*7c478bd9Sstevel@tonic-gate 			 */
1245*7c478bd9Sstevel@tonic-gate 			if (offset > 0) {
1246*7c478bd9Sstevel@tonic-gate 				if (fwrite(buf, 1, n_bits, outp) != n_bits) {
1247*7c478bd9Sstevel@tonic-gate 					longjmp(env, 3);
1248*7c478bd9Sstevel@tonic-gate 				}
1249*7c478bd9Sstevel@tonic-gate 				bytes_out += n_bits;
1250*7c478bd9Sstevel@tonic-gate 			}
1251*7c478bd9Sstevel@tonic-gate 			offset = 0;
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 			if (clear_flg) {
1254*7c478bd9Sstevel@tonic-gate 				maxcode = MAXCODE(n_bits = INIT_BITS);
1255*7c478bd9Sstevel@tonic-gate 				clear_flg = 0;
1256*7c478bd9Sstevel@tonic-gate 			} else {
1257*7c478bd9Sstevel@tonic-gate 				n_bits++;
1258*7c478bd9Sstevel@tonic-gate 				if (n_bits == maxbits)
1259*7c478bd9Sstevel@tonic-gate 					maxcode = maxmaxcode;
1260*7c478bd9Sstevel@tonic-gate 				else
1261*7c478bd9Sstevel@tonic-gate 					maxcode = MAXCODE(n_bits);
1262*7c478bd9Sstevel@tonic-gate 			}
1263*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1264*7c478bd9Sstevel@tonic-gate 			if (debug) {
1265*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1266*7c478bd9Sstevel@tonic-gate 					"\nChange to %d bits\n", n_bits);
1267*7c478bd9Sstevel@tonic-gate 				col = 0;
1268*7c478bd9Sstevel@tonic-gate 			}
1269*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1270*7c478bd9Sstevel@tonic-gate 		}
1271*7c478bd9Sstevel@tonic-gate 	} else {
1272*7c478bd9Sstevel@tonic-gate 		/*
1273*7c478bd9Sstevel@tonic-gate 		 * At EOF, write the rest of the buffer.
1274*7c478bd9Sstevel@tonic-gate 		 */
1275*7c478bd9Sstevel@tonic-gate 		if (offset > 0) {
1276*7c478bd9Sstevel@tonic-gate 			if (fwrite(buf, 1, (offset + 7) / 8, outp) == 0 &&
1277*7c478bd9Sstevel@tonic-gate 			    ferror(outp)) {
1278*7c478bd9Sstevel@tonic-gate 				ioerror();
1279*7c478bd9Sstevel@tonic-gate 			}
1280*7c478bd9Sstevel@tonic-gate 			bytes_out += (offset + 7) / 8;
1281*7c478bd9Sstevel@tonic-gate 		}
1282*7c478bd9Sstevel@tonic-gate 		offset = 0;
1283*7c478bd9Sstevel@tonic-gate 		(void) fflush(outp);
1284*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1285*7c478bd9Sstevel@tonic-gate 		if (verbose)
1286*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
1287*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1288*7c478bd9Sstevel@tonic-gate 		if (ferror(outp))
1289*7c478bd9Sstevel@tonic-gate 			ioerror();
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate }
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate /*
1294*7c478bd9Sstevel@tonic-gate  * Decompress inp to outp.  This routine adapts to the codes in the
1295*7c478bd9Sstevel@tonic-gate  * file building the "string" table on-the-fly; requiring no table to
1296*7c478bd9Sstevel@tonic-gate  * be stored in the compressed file.  The tables used herein are shared
1297*7c478bd9Sstevel@tonic-gate  * with those of the compress() routine.  See the definitions above.
1298*7c478bd9Sstevel@tonic-gate  */
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate static void
1301*7c478bd9Sstevel@tonic-gate decompress()
1302*7c478bd9Sstevel@tonic-gate {
1303*7c478bd9Sstevel@tonic-gate 	char_type *stackp, *stack_lim;
1304*7c478bd9Sstevel@tonic-gate 	int finchar;
1305*7c478bd9Sstevel@tonic-gate 	code_int code, oldcode, incode;
1306*7c478bd9Sstevel@tonic-gate 	FILE *fout = outp;
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	/*
1309*7c478bd9Sstevel@tonic-gate 	 * As above, initialize the first 256 entries in the table.
1310*7c478bd9Sstevel@tonic-gate 	 */
1311*7c478bd9Sstevel@tonic-gate 	maxcode = MAXCODE(n_bits = INIT_BITS);
1312*7c478bd9Sstevel@tonic-gate 	for (code = 255; code >= 0; code--) {
1313*7c478bd9Sstevel@tonic-gate 		tab_prefixof(code) = 0;
1314*7c478bd9Sstevel@tonic-gate 		tab_suffixof(code) = (char_type)code;
1315*7c478bd9Sstevel@tonic-gate 	}
1316*7c478bd9Sstevel@tonic-gate 	free_ent = ((block_compress) ? FIRST : 256);
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	finchar = oldcode = getcode();
1319*7c478bd9Sstevel@tonic-gate 	if (oldcode == -1)	/* EOF already? */
1320*7c478bd9Sstevel@tonic-gate 		return;			/* Get out of here */
1321*7c478bd9Sstevel@tonic-gate 	/* first code must be 8 bits = char */
1322*7c478bd9Sstevel@tonic-gate 	if (putc((char)finchar, outp) == EOF && ferror(outp)) {
1323*7c478bd9Sstevel@tonic-gate 		/* Crash if can't write */
1324*7c478bd9Sstevel@tonic-gate 		ioerror();
1325*7c478bd9Sstevel@tonic-gate 	}
1326*7c478bd9Sstevel@tonic-gate 	stackp = de_stack;
1327*7c478bd9Sstevel@tonic-gate 	stack_lim = stack_max;
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 	while ((code = getcode()) > -1) {
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 		if ((code == CLEAR) && block_compress) {
1332*7c478bd9Sstevel@tonic-gate 			for (code = 255; code >= 0; code--)
1333*7c478bd9Sstevel@tonic-gate 			tab_prefixof(code) = 0;
1334*7c478bd9Sstevel@tonic-gate 			clear_flg = 1;
1335*7c478bd9Sstevel@tonic-gate 			free_ent = FIRST - 1;
1336*7c478bd9Sstevel@tonic-gate 			if ((code = getcode()) == -1)	/* O, untimely death! */
1337*7c478bd9Sstevel@tonic-gate 				break;
1338*7c478bd9Sstevel@tonic-gate 		}
1339*7c478bd9Sstevel@tonic-gate 		incode = code;
1340*7c478bd9Sstevel@tonic-gate 		/*
1341*7c478bd9Sstevel@tonic-gate 		 * Special case for KwKwK string.
1342*7c478bd9Sstevel@tonic-gate 		 */
1343*7c478bd9Sstevel@tonic-gate 		if (code >= free_ent) {
1344*7c478bd9Sstevel@tonic-gate 			if (stackp < stack_lim) {
1345*7c478bd9Sstevel@tonic-gate 				*stackp++ = (char_type) finchar;
1346*7c478bd9Sstevel@tonic-gate 				code = oldcode;
1347*7c478bd9Sstevel@tonic-gate 			} else {
1348*7c478bd9Sstevel@tonic-gate 				/* badness */
1349*7c478bd9Sstevel@tonic-gate 				longjmp(env, 2);
1350*7c478bd9Sstevel@tonic-gate 			}
1351*7c478bd9Sstevel@tonic-gate 		}
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 		/*
1354*7c478bd9Sstevel@tonic-gate 		 * Generate output characters in reverse order
1355*7c478bd9Sstevel@tonic-gate 		 */
1356*7c478bd9Sstevel@tonic-gate 		while (code >= 256) {
1357*7c478bd9Sstevel@tonic-gate 			if (stackp < stack_lim) {
1358*7c478bd9Sstevel@tonic-gate 				*stackp++ = tab_suffixof(code);
1359*7c478bd9Sstevel@tonic-gate 				code = tab_prefixof(code);
1360*7c478bd9Sstevel@tonic-gate 			} else {
1361*7c478bd9Sstevel@tonic-gate 				/* badness */
1362*7c478bd9Sstevel@tonic-gate 				longjmp(env, 2);
1363*7c478bd9Sstevel@tonic-gate 			}
1364*7c478bd9Sstevel@tonic-gate 		}
1365*7c478bd9Sstevel@tonic-gate 		*stackp++ = finchar = tab_suffixof(code);
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 		/*
1368*7c478bd9Sstevel@tonic-gate 		 * And put them out in forward order
1369*7c478bd9Sstevel@tonic-gate 		 */
1370*7c478bd9Sstevel@tonic-gate 		do {
1371*7c478bd9Sstevel@tonic-gate 			stackp--;
1372*7c478bd9Sstevel@tonic-gate 			(void) putc(*stackp, fout);
1373*7c478bd9Sstevel@tonic-gate 		} while (stackp > de_stack);
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 		if (ferror(fout))
1376*7c478bd9Sstevel@tonic-gate 			ioerror();
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 		/*
1379*7c478bd9Sstevel@tonic-gate 		 * Generate the new entry.
1380*7c478bd9Sstevel@tonic-gate 		 */
1381*7c478bd9Sstevel@tonic-gate 		if ((code = free_ent) < maxmaxcode) {
1382*7c478bd9Sstevel@tonic-gate 			tab_prefixof(code) = (unsigned short) oldcode;
1383*7c478bd9Sstevel@tonic-gate 			tab_suffixof(code) = (char_type) finchar;
1384*7c478bd9Sstevel@tonic-gate 			free_ent = code+1;
1385*7c478bd9Sstevel@tonic-gate 		}
1386*7c478bd9Sstevel@tonic-gate 		/*
1387*7c478bd9Sstevel@tonic-gate 		 * Remember previous code.
1388*7c478bd9Sstevel@tonic-gate 		 */
1389*7c478bd9Sstevel@tonic-gate 		oldcode = incode;
1390*7c478bd9Sstevel@tonic-gate 	}
1391*7c478bd9Sstevel@tonic-gate 	(void) fflush(outp);
1392*7c478bd9Sstevel@tonic-gate 	if (ferror(outp))
1393*7c478bd9Sstevel@tonic-gate 		ioerror();
1394*7c478bd9Sstevel@tonic-gate }
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate /*
1397*7c478bd9Sstevel@tonic-gate  * **************************************************************
1398*7c478bd9Sstevel@tonic-gate  * TAG( getcode )
1399*7c478bd9Sstevel@tonic-gate  *
1400*7c478bd9Sstevel@tonic-gate  * Read one code from the standard input.  If EOF, return -1.
1401*7c478bd9Sstevel@tonic-gate  * Inputs:
1402*7c478bd9Sstevel@tonic-gate  * 	inp
1403*7c478bd9Sstevel@tonic-gate  * Outputs:
1404*7c478bd9Sstevel@tonic-gate  * 	code or -1 is returned.
1405*7c478bd9Sstevel@tonic-gate  */
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate code_int
1408*7c478bd9Sstevel@tonic-gate getcode() {
1409*7c478bd9Sstevel@tonic-gate 	code_int code;
1410*7c478bd9Sstevel@tonic-gate 	static int offset = 0, size = 0;
1411*7c478bd9Sstevel@tonic-gate 	static char_type buf[BITS];
1412*7c478bd9Sstevel@tonic-gate 	int r_off, bits;
1413*7c478bd9Sstevel@tonic-gate 	char_type *bp = buf;
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
1416*7c478bd9Sstevel@tonic-gate 		/*
1417*7c478bd9Sstevel@tonic-gate 		 * If the next entry will be too big for the current code
1418*7c478bd9Sstevel@tonic-gate 		 * size, then we must increase the size.  This implies reading
1419*7c478bd9Sstevel@tonic-gate 		 * a new buffer full, too.
1420*7c478bd9Sstevel@tonic-gate 		 */
1421*7c478bd9Sstevel@tonic-gate 		if (free_ent > maxcode) {
1422*7c478bd9Sstevel@tonic-gate 			n_bits++;
1423*7c478bd9Sstevel@tonic-gate 			if (n_bits == maxbits)
1424*7c478bd9Sstevel@tonic-gate 				/* won't get any bigger now */
1425*7c478bd9Sstevel@tonic-gate 				maxcode = maxmaxcode;
1426*7c478bd9Sstevel@tonic-gate 			else
1427*7c478bd9Sstevel@tonic-gate 				maxcode = MAXCODE(n_bits);
1428*7c478bd9Sstevel@tonic-gate 		}
1429*7c478bd9Sstevel@tonic-gate 		if (clear_flg > 0) {
1430*7c478bd9Sstevel@tonic-gate 			maxcode = MAXCODE(n_bits = INIT_BITS);
1431*7c478bd9Sstevel@tonic-gate 			clear_flg = 0;
1432*7c478bd9Sstevel@tonic-gate 		}
1433*7c478bd9Sstevel@tonic-gate 		size = fread(buf, 1, n_bits, inp);
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 		if (size <= 0) {
1436*7c478bd9Sstevel@tonic-gate 			if (feof(inp)) {
1437*7c478bd9Sstevel@tonic-gate 				/* end of file */
1438*7c478bd9Sstevel@tonic-gate 				return (-1);
1439*7c478bd9Sstevel@tonic-gate 			} else if (ferror(inp)) {
1440*7c478bd9Sstevel@tonic-gate 				ioerror();
1441*7c478bd9Sstevel@tonic-gate 			}
1442*7c478bd9Sstevel@tonic-gate 		}
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 		offset = 0;
1445*7c478bd9Sstevel@tonic-gate 		/* Round size down to integral number of codes */
1446*7c478bd9Sstevel@tonic-gate 		size = (size << 3) - (n_bits - 1);
1447*7c478bd9Sstevel@tonic-gate 	}
1448*7c478bd9Sstevel@tonic-gate 	r_off = offset;
1449*7c478bd9Sstevel@tonic-gate 	bits = n_bits;
1450*7c478bd9Sstevel@tonic-gate 	/*
1451*7c478bd9Sstevel@tonic-gate 	 * Get to the first byte.
1452*7c478bd9Sstevel@tonic-gate 	 */
1453*7c478bd9Sstevel@tonic-gate 	bp += (r_off >> 3);
1454*7c478bd9Sstevel@tonic-gate 	r_off &= 7;
1455*7c478bd9Sstevel@tonic-gate 	/* Get first part (low order bits) */
1456*7c478bd9Sstevel@tonic-gate 	code = (*bp++ >> r_off);
1457*7c478bd9Sstevel@tonic-gate 	bits -= (8 - r_off);
1458*7c478bd9Sstevel@tonic-gate 	r_off = 8 - r_off;		/* now, offset into code word */
1459*7c478bd9Sstevel@tonic-gate 	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
1460*7c478bd9Sstevel@tonic-gate 	if (bits >= 8) {
1461*7c478bd9Sstevel@tonic-gate 		code |= *bp++ << r_off;
1462*7c478bd9Sstevel@tonic-gate 		r_off += 8;
1463*7c478bd9Sstevel@tonic-gate 		bits -= 8;
1464*7c478bd9Sstevel@tonic-gate 	}
1465*7c478bd9Sstevel@tonic-gate 	/* high order bits. */
1466*7c478bd9Sstevel@tonic-gate 	code |= (*bp & rmask[bits]) << r_off;
1467*7c478bd9Sstevel@tonic-gate 	offset += n_bits;
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	return (code);
1470*7c478bd9Sstevel@tonic-gate }
1471*7c478bd9Sstevel@tonic-gate 
1472*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1473*7c478bd9Sstevel@tonic-gate static void
1474*7c478bd9Sstevel@tonic-gate printcodes()
1475*7c478bd9Sstevel@tonic-gate {
1476*7c478bd9Sstevel@tonic-gate 	/*
1477*7c478bd9Sstevel@tonic-gate 	 * Just print out codes from input file.  For debugging.
1478*7c478bd9Sstevel@tonic-gate 	 */
1479*7c478bd9Sstevel@tonic-gate 	code_int code;
1480*7c478bd9Sstevel@tonic-gate 	int col = 0, bits;
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	bits = n_bits = INIT_BITS;
1483*7c478bd9Sstevel@tonic-gate 	maxcode = MAXCODE(n_bits);
1484*7c478bd9Sstevel@tonic-gate 	free_ent = ((block_compress) ? FIRST : 256);
1485*7c478bd9Sstevel@tonic-gate 	while ((code = getcode()) >= 0) {
1486*7c478bd9Sstevel@tonic-gate 		if ((code == CLEAR) && block_compress) {
1487*7c478bd9Sstevel@tonic-gate 			free_ent = FIRST - 1;
1488*7c478bd9Sstevel@tonic-gate 			clear_flg = 1;
1489*7c478bd9Sstevel@tonic-gate 		} else if (free_ent < maxmaxcode)
1490*7c478bd9Sstevel@tonic-gate 			free_ent++;
1491*7c478bd9Sstevel@tonic-gate 		if (bits != n_bits) {
1492*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\nChange to %d bits\n", n_bits);
1493*7c478bd9Sstevel@tonic-gate 			bits = n_bits;
1494*7c478bd9Sstevel@tonic-gate 			col = 0;
1495*7c478bd9Sstevel@tonic-gate 		}
1496*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%5d%c",
1497*7c478bd9Sstevel@tonic-gate 			code, (col += 6) >= 74 ? (col = 0, '\n') : ' ');
1498*7c478bd9Sstevel@tonic-gate 	}
1499*7c478bd9Sstevel@tonic-gate 	(void) putc('\n', stderr);
1500*7c478bd9Sstevel@tonic-gate }
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1505*7c478bd9Sstevel@tonic-gate static void
1506*7c478bd9Sstevel@tonic-gate dump_tab()	/* dump string table */
1507*7c478bd9Sstevel@tonic-gate {
1508*7c478bd9Sstevel@tonic-gate 	int i, first;
1509*7c478bd9Sstevel@tonic-gate 	int ent;
1510*7c478bd9Sstevel@tonic-gate 	int stack_top = STACK_SIZE;
1511*7c478bd9Sstevel@tonic-gate 	int c;
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	if (do_decomp == 0) {	/* compressing */
1514*7c478bd9Sstevel@tonic-gate 		int flag = 1;
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < hsize; i++) {	/* build sort pointers */
1517*7c478bd9Sstevel@tonic-gate 			if ((long)htabof(i) >= 0) {
1518*7c478bd9Sstevel@tonic-gate 				sorttab[codetabof(i)] = i;
1519*7c478bd9Sstevel@tonic-gate 			}
1520*7c478bd9Sstevel@tonic-gate 		}
1521*7c478bd9Sstevel@tonic-gate 		first = block_compress ? FIRST : 256;
1522*7c478bd9Sstevel@tonic-gate 		for (i = first; i < free_ent; i++) {
1523*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%5d: \"", i);
1524*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '\n';
1525*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '"';
1526*7c478bd9Sstevel@tonic-gate 			stack_top =
1527*7c478bd9Sstevel@tonic-gate 				in_stack((htabof(sorttab[i]) >> maxbits) & 0xff,
1528*7c478bd9Sstevel@tonic-gate 					stack_top);
1529*7c478bd9Sstevel@tonic-gate 			for (ent = htabof(sorttab[i]) & ((1 << maxbits) -1);
1530*7c478bd9Sstevel@tonic-gate 				ent > 256;
1531*7c478bd9Sstevel@tonic-gate 				ent = htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
1532*7c478bd9Sstevel@tonic-gate 				stack_top = in_stack(
1533*7c478bd9Sstevel@tonic-gate 					htabof(sorttab[ent]) >> maxbits,
1534*7c478bd9Sstevel@tonic-gate 					stack_top);
1535*7c478bd9Sstevel@tonic-gate 			}
1536*7c478bd9Sstevel@tonic-gate 			stack_top = in_stack(ent, stack_top);
1537*7c478bd9Sstevel@tonic-gate 			(void) fwrite(&de_stack[stack_top], 1,
1538*7c478bd9Sstevel@tonic-gate 				STACK_SIZE - stack_top, stderr);
1539*7c478bd9Sstevel@tonic-gate 			stack_top = STACK_SIZE;
1540*7c478bd9Sstevel@tonic-gate 		}
1541*7c478bd9Sstevel@tonic-gate 	} else if (!debug) {	/* decompressing */
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < free_ent; i++) {
1544*7c478bd9Sstevel@tonic-gate 			ent = i;
1545*7c478bd9Sstevel@tonic-gate 			c = tab_suffixof(ent);
1546*7c478bd9Sstevel@tonic-gate 			if (isascii(c) && isprint(c))
1547*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%5d: %5d/'%c'  \"",
1548*7c478bd9Sstevel@tonic-gate 					ent, tab_prefixof(ent), c);
1549*7c478bd9Sstevel@tonic-gate 			else
1550*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%5d: %5d/\\%03o \"",
1551*7c478bd9Sstevel@tonic-gate 					ent, tab_prefixof(ent), c);
1552*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '\n';
1553*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '"';
1554*7c478bd9Sstevel@tonic-gate 			for (; ent != NULL;
1555*7c478bd9Sstevel@tonic-gate 				ent = (ent >= FIRST ? tab_prefixof(ent) :
1556*7c478bd9Sstevel@tonic-gate 						NULL)) {
1557*7c478bd9Sstevel@tonic-gate 				stack_top = in_stack(tab_suffixof(ent),
1558*7c478bd9Sstevel@tonic-gate 								stack_top);
1559*7c478bd9Sstevel@tonic-gate 			}
1560*7c478bd9Sstevel@tonic-gate 			(void) fwrite(&de_stack[stack_top], 1,
1561*7c478bd9Sstevel@tonic-gate 				STACK_SIZE - stack_top, stderr);
1562*7c478bd9Sstevel@tonic-gate 			stack_top = STACK_SIZE;
1563*7c478bd9Sstevel@tonic-gate 		}
1564*7c478bd9Sstevel@tonic-gate 	}
1565*7c478bd9Sstevel@tonic-gate }
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1568*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1569*7c478bd9Sstevel@tonic-gate static int
1570*7c478bd9Sstevel@tonic-gate in_stack(int c, int stack_top)
1571*7c478bd9Sstevel@tonic-gate {
1572*7c478bd9Sstevel@tonic-gate 	if ((isascii(c) && isprint(c) && c != '\\') || c == ' ') {
1573*7c478bd9Sstevel@tonic-gate 		de_stack[--stack_top] = c;
1574*7c478bd9Sstevel@tonic-gate 	} else {
1575*7c478bd9Sstevel@tonic-gate 		switch (c) {
1576*7c478bd9Sstevel@tonic-gate 		case '\n': de_stack[--stack_top] = 'n'; break;
1577*7c478bd9Sstevel@tonic-gate 		case '\t': de_stack[--stack_top] = 't'; break;
1578*7c478bd9Sstevel@tonic-gate 		case '\b': de_stack[--stack_top] = 'b'; break;
1579*7c478bd9Sstevel@tonic-gate 		case '\f': de_stack[--stack_top] = 'f'; break;
1580*7c478bd9Sstevel@tonic-gate 		case '\r': de_stack[--stack_top] = 'r'; break;
1581*7c478bd9Sstevel@tonic-gate 		case '\\': de_stack[--stack_top] = '\\'; break;
1582*7c478bd9Sstevel@tonic-gate 		default:
1583*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '0' + c % 8;
1584*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '0' + (c / 8) % 8;
1585*7c478bd9Sstevel@tonic-gate 			de_stack[--stack_top] = '0' + c / 64;
1586*7c478bd9Sstevel@tonic-gate 			break;
1587*7c478bd9Sstevel@tonic-gate 		}
1588*7c478bd9Sstevel@tonic-gate 		de_stack[--stack_top] = '\\';
1589*7c478bd9Sstevel@tonic-gate 	}
1590*7c478bd9Sstevel@tonic-gate 	return (stack_top);
1591*7c478bd9Sstevel@tonic-gate }
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1594*7c478bd9Sstevel@tonic-gate static void
1595*7c478bd9Sstevel@tonic-gate ioerror()
1596*7c478bd9Sstevel@tonic-gate {
1597*7c478bd9Sstevel@tonic-gate 	longjmp(env, 1);
1598*7c478bd9Sstevel@tonic-gate }
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate static void
1601*7c478bd9Sstevel@tonic-gate copystat(char *ifname, struct stat *ifstat, char *ofname)
1602*7c478bd9Sstevel@tonic-gate {
1603*7c478bd9Sstevel@tonic-gate 	mode_t mode;
1604*7c478bd9Sstevel@tonic-gate 	struct utimbuf timep;
1605*7c478bd9Sstevel@tonic-gate 	int aclcnt;
1606*7c478bd9Sstevel@tonic-gate 	aclent_t *aclp;
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 	if (fclose(outp)) {
1609*7c478bd9Sstevel@tonic-gate 		perror(ofname);
1610*7c478bd9Sstevel@tonic-gate 		if (!quiet) {
1611*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(" -- file unchanged"));
1612*7c478bd9Sstevel@tonic-gate 			newline_needed = 1;
1613*7c478bd9Sstevel@tonic-gate 		}
1614*7c478bd9Sstevel@tonic-gate 		perm_stat = 1;
1615*7c478bd9Sstevel@tonic-gate 	} else if (ifstat == NULL) {	/* Get stat on input file */
1616*7c478bd9Sstevel@tonic-gate 		perror(ifname);
1617*7c478bd9Sstevel@tonic-gate 		return;
1618*7c478bd9Sstevel@tonic-gate 	} else if ((ifstat->st_mode &
1619*7c478bd9Sstevel@tonic-gate 			S_IFMT /* 0170000 */) != S_IFREG /* 0100000 */) {
1620*7c478bd9Sstevel@tonic-gate 		if (quiet) {
1621*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", ifname);
1622*7c478bd9Sstevel@tonic-gate 		}
1623*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1624*7c478bd9Sstevel@tonic-gate 			" -- not a regular file: unchanged"));
1625*7c478bd9Sstevel@tonic-gate 		newline_needed = 1;
1626*7c478bd9Sstevel@tonic-gate 		perm_stat = 1;
1627*7c478bd9Sstevel@tonic-gate 	} else if (ifstat->st_nlink > 1) {
1628*7c478bd9Sstevel@tonic-gate 		if (quiet) {
1629*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", ifname);
1630*7c478bd9Sstevel@tonic-gate 		}
1631*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1632*7c478bd9Sstevel@tonic-gate 			" -- has %d other links: unchanged"),
1633*7c478bd9Sstevel@tonic-gate 			(uint_t)ifstat->st_nlink - 1);
1634*7c478bd9Sstevel@tonic-gate 		newline_needed = 1;
1635*7c478bd9Sstevel@tonic-gate 		perm_stat = 1;
1636*7c478bd9Sstevel@tonic-gate 	} else if (didnt_shrink && !force) {
1637*7c478bd9Sstevel@tonic-gate 		/* No compression: remove file.Z */
1638*7c478bd9Sstevel@tonic-gate 		if (!quiet) {
1639*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1640*7c478bd9Sstevel@tonic-gate 				" -- file unchanged"));
1641*7c478bd9Sstevel@tonic-gate 			newline_needed = 1;
1642*7c478bd9Sstevel@tonic-gate 		}
1643*7c478bd9Sstevel@tonic-gate 	} else if ((pathconf(ifname, _PC_XATTR_EXISTS) == 1) &&
1644*7c478bd9Sstevel@tonic-gate 			(mv_xattrs(ifname, ofname, 0) < 0)) {
1645*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1646*7c478bd9Sstevel@tonic-gate 			"%s: -- cannot preserve extended attributes, "
1647*7c478bd9Sstevel@tonic-gate 			"file unchanged"), ifname);
1648*7c478bd9Sstevel@tonic-gate 		newline_needed = 1;
1649*7c478bd9Sstevel@tonic-gate 		/* Move attributes back ... */
1650*7c478bd9Sstevel@tonic-gate 		(void) mv_xattrs(ofname, ifname, 1);
1651*7c478bd9Sstevel@tonic-gate 		perm_stat = 1;
1652*7c478bd9Sstevel@tonic-gate 	} else {	/* ***** Successful Compression ***** */
1653*7c478bd9Sstevel@tonic-gate 		mode = ifstat->st_mode & 07777;
1654*7c478bd9Sstevel@tonic-gate 		if (chmod(ofname, mode))	 /* Copy modes */
1655*7c478bd9Sstevel@tonic-gate 			perror(ofname);
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate 		/* Copy ACL info */
1658*7c478bd9Sstevel@tonic-gate 		if ((aclcnt = acl(ifname, GETACLCNT, 0, NULL)) < 0) {
1659*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1660*7c478bd9Sstevel@tonic-gate 			    "%s: failed to get acl count\n"),
1661*7c478bd9Sstevel@tonic-gate 			    ifname);
1662*7c478bd9Sstevel@tonic-gate 			perm_stat = 1;
1663*7c478bd9Sstevel@tonic-gate 		}
1664*7c478bd9Sstevel@tonic-gate 		/*
1665*7c478bd9Sstevel@tonic-gate 		 * Get ACL info: don't bother allocating space if
1666*7c478bd9Sstevel@tonic-gate 		 * there are only standard permissions, i.e.,
1667*7c478bd9Sstevel@tonic-gate 		 * ACL count < 4.
1668*7c478bd9Sstevel@tonic-gate 		 */
1669*7c478bd9Sstevel@tonic-gate 		if (aclcnt > MIN_ACL_ENTRIES) {
1670*7c478bd9Sstevel@tonic-gate 			if ((aclp = (aclent_t *)malloc(
1671*7c478bd9Sstevel@tonic-gate 			    sizeof (aclent_t) * aclcnt)) == NULL) {
1672*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1673*7c478bd9Sstevel@tonic-gate 				    "Insufficient memory\n"));
1674*7c478bd9Sstevel@tonic-gate 				exit(1);
1675*7c478bd9Sstevel@tonic-gate 			}
1676*7c478bd9Sstevel@tonic-gate 			if (acl(ifname, GETACL, aclcnt, aclp) < 0) {
1677*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1678*7c478bd9Sstevel@tonic-gate 				    "%s: failed to get acl entries\n"),
1679*7c478bd9Sstevel@tonic-gate 				    ifname);
1680*7c478bd9Sstevel@tonic-gate 				perm_stat = 1;
1681*7c478bd9Sstevel@tonic-gate 			} else {
1682*7c478bd9Sstevel@tonic-gate 				if (acl(ofname, SETACL,
1683*7c478bd9Sstevel@tonic-gate 				    aclcnt, aclp) < 0) {
1684*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
1685*7c478bd9Sstevel@tonic-gate 					    "%s: failed to set acl "
1686*7c478bd9Sstevel@tonic-gate 					    "entries\n"), ofname);
1687*7c478bd9Sstevel@tonic-gate 					perm_stat = 1;
1688*7c478bd9Sstevel@tonic-gate 				}
1689*7c478bd9Sstevel@tonic-gate 			}
1690*7c478bd9Sstevel@tonic-gate 			free(aclp);
1691*7c478bd9Sstevel@tonic-gate 		}
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 		/* Copy ownership */
1694*7c478bd9Sstevel@tonic-gate 		(void) chown(ofname, ifstat->st_uid, ifstat->st_gid);
1695*7c478bd9Sstevel@tonic-gate 		timep.actime = ifstat->st_atime;
1696*7c478bd9Sstevel@tonic-gate 		timep.modtime = ifstat->st_mtime;
1697*7c478bd9Sstevel@tonic-gate 		/* Update last accessed and modified times */
1698*7c478bd9Sstevel@tonic-gate 		(void) utime(ofname, &timep);
1699*7c478bd9Sstevel@tonic-gate 		if (unlink(ifname))	/* Remove input file */
1700*7c478bd9Sstevel@tonic-gate 			perror(ifname);
1701*7c478bd9Sstevel@tonic-gate 		if (!quiet) {
1702*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1703*7c478bd9Sstevel@tonic-gate 				" -- replaced with %s"), ofname);
1704*7c478bd9Sstevel@tonic-gate 			newline_needed = 1;
1705*7c478bd9Sstevel@tonic-gate 		}
1706*7c478bd9Sstevel@tonic-gate 		return;		/* Successful return */
1707*7c478bd9Sstevel@tonic-gate 	}
1708*7c478bd9Sstevel@tonic-gate 
1709*7c478bd9Sstevel@tonic-gate 	/* Unsuccessful return -- one of the tests failed */
1710*7c478bd9Sstevel@tonic-gate 	if (ofname[0] != '\0') {
1711*7c478bd9Sstevel@tonic-gate 		if (unlink(ofname)) {
1712*7c478bd9Sstevel@tonic-gate 			perror(ofname);
1713*7c478bd9Sstevel@tonic-gate 		}
1714*7c478bd9Sstevel@tonic-gate 
1715*7c478bd9Sstevel@tonic-gate 		ofname[0] = '\0';
1716*7c478bd9Sstevel@tonic-gate 	}
1717*7c478bd9Sstevel@tonic-gate }
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate static void
1720*7c478bd9Sstevel@tonic-gate onintr()
1721*7c478bd9Sstevel@tonic-gate {
1722*7c478bd9Sstevel@tonic-gate 	if (!precious && !use_stdout && ofname[0] != '\0')
1723*7c478bd9Sstevel@tonic-gate 		(void) unlink(ofname);
1724*7c478bd9Sstevel@tonic-gate 	exit(1);
1725*7c478bd9Sstevel@tonic-gate }
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate static void
1728*7c478bd9Sstevel@tonic-gate oops()	/* wild pointer -- assume bad input */
1729*7c478bd9Sstevel@tonic-gate {
1730*7c478bd9Sstevel@tonic-gate 	if (do_decomp) {
1731*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("uncompress: corrupt input\n"));
1732*7c478bd9Sstevel@tonic-gate 	}
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate 	if (!use_stdout && ofname[0] != '\0') {
1735*7c478bd9Sstevel@tonic-gate 		(void) unlink(ofname);
1736*7c478bd9Sstevel@tonic-gate 	}
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate 	exit(1);
1739*7c478bd9Sstevel@tonic-gate }
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate static void
1742*7c478bd9Sstevel@tonic-gate cl_block(count_long in_count)	/* table clear for block compress */
1743*7c478bd9Sstevel@tonic-gate {
1744*7c478bd9Sstevel@tonic-gate 	count_long rat;
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 	checkpoint = (count_long)in_count + (count_long)CHECK_GAP;
1747*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1748*7c478bd9Sstevel@tonic-gate 	if (debug) {
1749*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "count: %lld, ratio: ",
1750*7c478bd9Sstevel@tonic-gate 			(count_long)in_count);
1751*7c478bd9Sstevel@tonic-gate 		prratio(stderr, (count_long)in_count, (count_long)bytes_out);
1752*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
1753*7c478bd9Sstevel@tonic-gate 	}
1754*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate 	/* shift will overflow */
1757*7c478bd9Sstevel@tonic-gate 	if ((count_long)in_count > (count_long)0x007fffffffffffff) {
1758*7c478bd9Sstevel@tonic-gate 		rat = (count_long)bytes_out >> 8;
1759*7c478bd9Sstevel@tonic-gate 		if (rat == 0) {		/* Don't divide by zero */
1760*7c478bd9Sstevel@tonic-gate 			rat = 0x7fffffffffffffff;
1761*7c478bd9Sstevel@tonic-gate 		} else {
1762*7c478bd9Sstevel@tonic-gate 			rat = (count_long)in_count / (count_long)rat;
1763*7c478bd9Sstevel@tonic-gate 		}
1764*7c478bd9Sstevel@tonic-gate 	} else {
1765*7c478bd9Sstevel@tonic-gate 		/* 8 fractional bits */
1766*7c478bd9Sstevel@tonic-gate 		rat = ((count_long)in_count << 8) /(count_long)bytes_out;
1767*7c478bd9Sstevel@tonic-gate 	}
1768*7c478bd9Sstevel@tonic-gate 	if (rat > ratio) {
1769*7c478bd9Sstevel@tonic-gate 		ratio = rat;
1770*7c478bd9Sstevel@tonic-gate 	} else {
1771*7c478bd9Sstevel@tonic-gate 		ratio = 0;
1772*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1773*7c478bd9Sstevel@tonic-gate 		if (verbose)
1774*7c478bd9Sstevel@tonic-gate 			dump_tab();	/* dump string table */
1775*7c478bd9Sstevel@tonic-gate #endif
1776*7c478bd9Sstevel@tonic-gate 		cl_hash((count_int) hsize);
1777*7c478bd9Sstevel@tonic-gate 		free_ent = FIRST;
1778*7c478bd9Sstevel@tonic-gate 		clear_flg = 1;
1779*7c478bd9Sstevel@tonic-gate 		output((code_int) CLEAR);
1780*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1781*7c478bd9Sstevel@tonic-gate 		if (debug)
1782*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "clear\n");
1783*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1784*7c478bd9Sstevel@tonic-gate 	}
1785*7c478bd9Sstevel@tonic-gate }
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate static void
1788*7c478bd9Sstevel@tonic-gate cl_hash(count_int hsize)		/* reset code table */
1789*7c478bd9Sstevel@tonic-gate {
1790*7c478bd9Sstevel@tonic-gate 	count_int *htab_p = htab+hsize;
1791*7c478bd9Sstevel@tonic-gate 	long i;
1792*7c478bd9Sstevel@tonic-gate 	long m1 = -1;
1793*7c478bd9Sstevel@tonic-gate 
1794*7c478bd9Sstevel@tonic-gate 	i = hsize - 16;
1795*7c478bd9Sstevel@tonic-gate 	do {				/* might use Sys V memset(3) here */
1796*7c478bd9Sstevel@tonic-gate 		*(htab_p-16) = m1;
1797*7c478bd9Sstevel@tonic-gate 		*(htab_p-15) = m1;
1798*7c478bd9Sstevel@tonic-gate 		*(htab_p-14) = m1;
1799*7c478bd9Sstevel@tonic-gate 		*(htab_p-13) = m1;
1800*7c478bd9Sstevel@tonic-gate 		*(htab_p-12) = m1;
1801*7c478bd9Sstevel@tonic-gate 		*(htab_p-11) = m1;
1802*7c478bd9Sstevel@tonic-gate 		*(htab_p-10) = m1;
1803*7c478bd9Sstevel@tonic-gate 		*(htab_p-9) = m1;
1804*7c478bd9Sstevel@tonic-gate 		*(htab_p-8) = m1;
1805*7c478bd9Sstevel@tonic-gate 		*(htab_p-7) = m1;
1806*7c478bd9Sstevel@tonic-gate 		*(htab_p-6) = m1;
1807*7c478bd9Sstevel@tonic-gate 		*(htab_p-5) = m1;
1808*7c478bd9Sstevel@tonic-gate 		*(htab_p-4) = m1;
1809*7c478bd9Sstevel@tonic-gate 		*(htab_p-3) = m1;
1810*7c478bd9Sstevel@tonic-gate 		*(htab_p-2) = m1;
1811*7c478bd9Sstevel@tonic-gate 		*(htab_p-1) = m1;
1812*7c478bd9Sstevel@tonic-gate 		htab_p -= 16;
1813*7c478bd9Sstevel@tonic-gate 	} while ((i -= 16) >= 0);
1814*7c478bd9Sstevel@tonic-gate 		for (i += 16; i > 0; i--)
1815*7c478bd9Sstevel@tonic-gate 			*--htab_p = m1;
1816*7c478bd9Sstevel@tonic-gate }
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate static void
1819*7c478bd9Sstevel@tonic-gate prratio(FILE *stream, count_long num, count_long den)
1820*7c478bd9Sstevel@tonic-gate {
1821*7c478bd9Sstevel@tonic-gate 	int q;  /* store percentage */
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 	q = (int)(10000LL * (count_long)num / (count_long)den);
1824*7c478bd9Sstevel@tonic-gate 	if (q < 0) {
1825*7c478bd9Sstevel@tonic-gate 		(void) putc('-', stream);
1826*7c478bd9Sstevel@tonic-gate 		q = -q;
1827*7c478bd9Sstevel@tonic-gate 	}
1828*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stream, "%d%s%02d%%", q / 100,
1829*7c478bd9Sstevel@tonic-gate 			localeconv()->decimal_point, q % 100);
1830*7c478bd9Sstevel@tonic-gate }
1831*7c478bd9Sstevel@tonic-gate 
1832*7c478bd9Sstevel@tonic-gate static void
1833*7c478bd9Sstevel@tonic-gate version()
1834*7c478bd9Sstevel@tonic-gate {
1835*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s, Berkeley 5.9 5/11/86\n", rcs_ident);
1836*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Options: ");
1837*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1838*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "DEBUG, ");
1839*7c478bd9Sstevel@tonic-gate #endif
1840*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "BITS = %d\n", BITS);
1841*7c478bd9Sstevel@tonic-gate }
1842*7c478bd9Sstevel@tonic-gate 
1843*7c478bd9Sstevel@tonic-gate static void
1844*7c478bd9Sstevel@tonic-gate Usage()
1845*7c478bd9Sstevel@tonic-gate {
1846*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1847*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1848*7c478bd9Sstevel@tonic-gate 	"Usage: compress [-dDVfc] [-b maxbits] [file ...]\n");
1849*7c478bd9Sstevel@tonic-gate #else
1850*7c478bd9Sstevel@tonic-gate 	if (strcmp(progname, "compress") == 0) {
1851*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1852*7c478bd9Sstevel@tonic-gate 		    gettext(
1853*7c478bd9Sstevel@tonic-gate 		    "Usage: compress [-fv] [-b maxbits] [file ...]\n"\
1854*7c478bd9Sstevel@tonic-gate 		    "       compress [-cfv] [-b maxbits] [file]\n"));
1855*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(progname, "uncompress") == 0)
1856*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1857*7c478bd9Sstevel@tonic-gate 		    "Usage: uncompress [-cfv] [file ...]\n"));
1858*7c478bd9Sstevel@tonic-gate 	else if (strcmp(progname, "zcat") == 0)
1859*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Usage: zcat [file ...]\n"));
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1862*7c478bd9Sstevel@tonic-gate }
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate static char *
1865*7c478bd9Sstevel@tonic-gate local_basename(char *path)
1866*7c478bd9Sstevel@tonic-gate {
1867*7c478bd9Sstevel@tonic-gate 	char *p;
1868*7c478bd9Sstevel@tonic-gate 	char *ret = (char *)path;
1869*7c478bd9Sstevel@tonic-gate 
1870*7c478bd9Sstevel@tonic-gate 	while ((p = (char *)strpbrk(ret, "/")) != NULL)
1871*7c478bd9Sstevel@tonic-gate 		ret = p + 1;
1872*7c478bd9Sstevel@tonic-gate 	return (ret);
1873*7c478bd9Sstevel@tonic-gate }
1874*7c478bd9Sstevel@tonic-gate 
1875*7c478bd9Sstevel@tonic-gate static int
1876*7c478bd9Sstevel@tonic-gate addDotZ(char *fn, size_t fnsize)
1877*7c478bd9Sstevel@tonic-gate {
1878*7c478bd9Sstevel@tonic-gate 	char *fn_dup;
1879*7c478bd9Sstevel@tonic-gate 	char *dir;
1880*7c478bd9Sstevel@tonic-gate 	long int max_name;
1881*7c478bd9Sstevel@tonic-gate 	long int max_path;
1882*7c478bd9Sstevel@tonic-gate 
1883*7c478bd9Sstevel@tonic-gate 	fn_dup = strdup(fn);
1884*7c478bd9Sstevel@tonic-gate 	dir = dirname(fn_dup);
1885*7c478bd9Sstevel@tonic-gate 	max_name = pathconf(dir, _PC_NAME_MAX);
1886*7c478bd9Sstevel@tonic-gate 	max_path = pathconf(dir, _PC_PATH_MAX);
1887*7c478bd9Sstevel@tonic-gate 	free(fn_dup);
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 	/* Check for component length too long */
1890*7c478bd9Sstevel@tonic-gate 
1891*7c478bd9Sstevel@tonic-gate 	if ((strlen(local_basename(fn)) + 2) > (size_t)max_name) {
1892*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1893*7c478bd9Sstevel@tonic-gate 			gettext("%s: filename too long to tack on .Z:"
1894*7c478bd9Sstevel@tonic-gate 				" %s\n"), progname, fn);
1895*7c478bd9Sstevel@tonic-gate 		return (-1);
1896*7c478bd9Sstevel@tonic-gate 	}
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 	/* Check for path length too long */
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate 	if ((strlen(fn) + 2) > (size_t)max_path - 1) {
1901*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1902*7c478bd9Sstevel@tonic-gate 			gettext("%s: Pathname too long to tack on .Z:"
1903*7c478bd9Sstevel@tonic-gate 				" %s\n"), progname, fn);
1904*7c478bd9Sstevel@tonic-gate 		return (-1);
1905*7c478bd9Sstevel@tonic-gate 	}
1906*7c478bd9Sstevel@tonic-gate 
1907*7c478bd9Sstevel@tonic-gate 	if (strlcat(fn, ".Z", fnsize) >= fnsize) {
1908*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1909*7c478bd9Sstevel@tonic-gate 			gettext("%s: Buffer overflow adding .Z to %s\n"),
1910*7c478bd9Sstevel@tonic-gate 				progname, fn);
1911*7c478bd9Sstevel@tonic-gate 		return (-1);
1912*7c478bd9Sstevel@tonic-gate 	}
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	return (0);
1915*7c478bd9Sstevel@tonic-gate }
1916*7c478bd9Sstevel@tonic-gate 
1917*7c478bd9Sstevel@tonic-gate /*
1918*7c478bd9Sstevel@tonic-gate  * mv_xattrs - move (via renameat) all of the extended attributes
1919*7c478bd9Sstevel@tonic-gate  *	associated with the file infile to the file outfile.
1920*7c478bd9Sstevel@tonic-gate  *	This function returns 0 on success and -1 on error.
1921*7c478bd9Sstevel@tonic-gate  */
1922*7c478bd9Sstevel@tonic-gate static int
1923*7c478bd9Sstevel@tonic-gate mv_xattrs(char *infile, char *outfile, int silent)
1924*7c478bd9Sstevel@tonic-gate {
1925*7c478bd9Sstevel@tonic-gate 	int indfd, outdfd, tmpfd;
1926*7c478bd9Sstevel@tonic-gate 	DIR *dirp = NULL;
1927*7c478bd9Sstevel@tonic-gate 	struct dirent *dp = NULL;
1928*7c478bd9Sstevel@tonic-gate 	int error = 0;
1929*7c478bd9Sstevel@tonic-gate 	char *etext;
1930*7c478bd9Sstevel@tonic-gate 
1931*7c478bd9Sstevel@tonic-gate 	indfd = outdfd = tmpfd = -1;
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 	if ((indfd = attropen(infile, ".", O_RDONLY)) == -1) {
1934*7c478bd9Sstevel@tonic-gate 		etext = gettext("cannot open source");
1935*7c478bd9Sstevel@tonic-gate 		error = -1;
1936*7c478bd9Sstevel@tonic-gate 		goto out;
1937*7c478bd9Sstevel@tonic-gate 	}
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	if ((outdfd = attropen(outfile, ".", O_RDONLY)) == -1) {
1940*7c478bd9Sstevel@tonic-gate 		etext = gettext("cannot open target");
1941*7c478bd9Sstevel@tonic-gate 		error = -1;
1942*7c478bd9Sstevel@tonic-gate 		goto out;
1943*7c478bd9Sstevel@tonic-gate 	}
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 	if ((tmpfd = dup(indfd)) == -1) {
1946*7c478bd9Sstevel@tonic-gate 		etext = gettext("cannot dup descriptor");
1947*7c478bd9Sstevel@tonic-gate 		error = -1;
1948*7c478bd9Sstevel@tonic-gate 		goto out;
1949*7c478bd9Sstevel@tonic-gate 
1950*7c478bd9Sstevel@tonic-gate 	}
1951*7c478bd9Sstevel@tonic-gate 	if ((dirp = fdopendir(tmpfd)) == NULL) {
1952*7c478bd9Sstevel@tonic-gate 		etext = gettext("cannot access source");
1953*7c478bd9Sstevel@tonic-gate 		error = -1;
1954*7c478bd9Sstevel@tonic-gate 		goto out;
1955*7c478bd9Sstevel@tonic-gate 	}
1956*7c478bd9Sstevel@tonic-gate 
1957*7c478bd9Sstevel@tonic-gate 	while (dp = readdir(dirp)) {
1958*7c478bd9Sstevel@tonic-gate 		if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
1959*7c478bd9Sstevel@tonic-gate 		    (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
1960*7c478bd9Sstevel@tonic-gate 		    dp->d_name[2] == '\0'))
1961*7c478bd9Sstevel@tonic-gate 			continue;
1962*7c478bd9Sstevel@tonic-gate 		if ((renameat(indfd, dp->d_name, outdfd, dp->d_name)) == -1) {
1963*7c478bd9Sstevel@tonic-gate 			etext = dp->d_name;
1964*7c478bd9Sstevel@tonic-gate 			error = -1;
1965*7c478bd9Sstevel@tonic-gate 			goto out;
1966*7c478bd9Sstevel@tonic-gate 		}
1967*7c478bd9Sstevel@tonic-gate 	}
1968*7c478bd9Sstevel@tonic-gate out:
1969*7c478bd9Sstevel@tonic-gate 	if (error == -1 && silent == 0) {
1970*7c478bd9Sstevel@tonic-gate 		if (quiet) {
1971*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", infile);
1972*7c478bd9Sstevel@tonic-gate 		} else {
1973*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, ", ");
1974*7c478bd9Sstevel@tonic-gate 		}
1975*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("extended attribute error: "));
1976*7c478bd9Sstevel@tonic-gate 		perror(etext);
1977*7c478bd9Sstevel@tonic-gate 	}
1978*7c478bd9Sstevel@tonic-gate 	if (dirp)
1979*7c478bd9Sstevel@tonic-gate 		(void) closedir(dirp);
1980*7c478bd9Sstevel@tonic-gate 	if (indfd != -1)
1981*7c478bd9Sstevel@tonic-gate 		(void) close(indfd);
1982*7c478bd9Sstevel@tonic-gate 	if (outdfd != -1)
1983*7c478bd9Sstevel@tonic-gate 		(void) close(outdfd);
1984*7c478bd9Sstevel@tonic-gate 	return (error);
1985*7c478bd9Sstevel@tonic-gate }
1986