[comp.sources.misc] v20i064: compress - Compress 4.1, Part01/02

csu@alembic.ACS.COM (Dave Mack) (06/26/91)

Submitted-by: Dave Mack <csu@alembic.ACS.COM>
Posting-number: Volume 20, Issue 64
Archive-name: compress/part01
Environment: UNIX

This is Compress, Version 4.1. This submission consists of two parts.

Modifications for version 4.1: 
  o Added -r command line flag to allow recursive compression/
    decompression of directory trees. As a side-effect, compress
    no longer tries to compress/decompress anything that isn't
    a regular file. In particular, it ignores symbolic links.
  o zcat no longer cares whether a filename ends in .Z or
    not - it relies on the magic number in the file. If zcat
    is given a filename that doesn't end with .Z and the file
    referenced doesn't exist, zcat will append a .Z and try
    to open that instead.
  o compress -f will now compress multiply hardlinked files.
    Uncompress does not recreate the hard link, it creates
    a new file.
  o Removed compressdir/uncompressdir - no longer needed.
  o Removed atob/btoa/tarmail/untarmail - my versions are
    based on btoa 5.2 which is not compatible with the atob
    included with compress4.0.
  
Acknowledgments:

Pat Myrto (rwing!pat@cs.washington.edu) deserves the credit
for undoing all the damage I did to this version with respect
to System V and for giving me the occasional kick when my
changes clobbered some necessary functionality.

Thanks to James A. Woods for permitting me to corrupt his baby
and for passing along some tips on ways to improve the performance
over 4.0.

Thanks to the previous authors whom I didn't contact, for making
the program available originally.

Dave Mack
---
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  README compress.c
# Wrapped by csu@alembic on Thu May 30 16:24:07 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(7854 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XCompress compresses files using a heavily modified version of the
XLZW algorithm as described in IEEE Computer, June 1984.
XSee the comments in compress.c and the Usenet article at
Xthe end of this file for more details.
X
XThe "usermem" script attempts to determine the maximum process size.  Some
Xediting of the script may be necessary (see the comments).  If you can't get
Xit to work at all, just create file "USERMEM" containing the maximum process
Xsize in decimal.
X
XThe following preprocessor symbols control the compilation of "compress.c":
X
X	o USERMEM		Maximum process memory on the system
X	o SACREDMEM		Amount to reserve for other proceses
X	o SIGNED_COMPARE_SLOW	Unsigned compare instructions are faster
X	o NO_UCHAR		Don't use "unsigned char" types
X	o BITS			Overrules default set by USERMEM-SACREDMEM
X	o vax			Generate inline assembler
X	o interdata		Defines SIGNED_COMPARE_SLOW
X	o M_XENIX		Makes arrays < 65536 bytes each
X	o pdp11			BITS=12, NO_UCHAR
X	o z8000			BITS=12
X	o pcxt			BITS=12
X	o SHORTNAMES		Disallow long filenames ( > 14 characters)
X	o BSD4			Call setlinebuf(stderr), lstat vs stat, etc.
X	o VOIDSIG		signal returns a void pointer
X	o DIRENT		use <dirent.h> instead of <sys/dir.h>
X
XSee the comments at the beginning of the Makefile.
X
XThe difference "usermem-sacredmem" determines the maximum BITS that can be
Xspecified with the "-b" flag.
X
Xmemory: at least		BITS
X------  -- -----                ----
X     433,484			 16
X     229,600			 15
X     127,536			 14
X      73,464			 13
X           0			 12
X
XThe default is BITS=16.
X
XThe maximum bits can be overrulled by specifying "-DBITS=bits" at
Xcompilation time.
X
XWARNING: files compressed on a large machine with more bits than allowed by 
Xa version of compress on a smaller machine cannot be decompressed!  Use the
X"-b12" flag to generate a file on a large machine that can be uncompressed 
Xon a 16-bit machine.
X
XWARNING: compatibility with compress 3.0 has not been tested in
Xthe 4.1 release of compress.
X
XThe output of compress 4.0 is fully compatible with that of compress 3.0.
XIn other words, the output of compress 4.0 may be fed into uncompress 3.0 or
Xthe output of compress 3.0 may be fed into uncompress 4.0.
X
XThe output of compress 4.0 is not compatible with that of
Xcompress 2.0.  However, compress 4.0 still accepts the output of
Xcompress 2.0.  To generate output that is compatible with compress
X2.0, use the undocumented "-C" flag.
X
XCheck the Makefile, then "make".
X
XSend comments, complaints and especially patches relating to
Xcompress4.1 to csu@alembic.acs.com.
X
XRandom comments: 
X
Xcompress' handling of hard links has been criticized (it refuses to
Xcompress a multiply linked file.) In general, this is the correct
Xthing to do. Hard links cannot cross file system boundaries, and if
Xthe objective of compressing files is to free disk space in a file
Xsystem, compressing one link to a file won't help. Compress has no
Xway of knowing where the other links are. If you REALLY want to
Xcompress a hard link, use the -f flag. Be aware that when it is
Xuncompressed, the hardlink will not be recreated.
X
Xcompress4.0's handling of symbolic links was (IMHO) incorrect.
XUncompressing a collection of files should yield exactly what
Xyou had before you compressed them. This didn't happen with
Xsymlinks. Version 4.1 simply ignores attempts to compress
Xsymbolic links, along with anything else that isn't a regular
Xfile. If you're accustomed to using compress followed by tar
Xto get everything that a directory references, both directly and
Xindirectly, this may come as something of a disappointment.
X
XThe following article from James A. Woods, one of the earlier
Xauthors of compress, explains its relationship to the Unisys
Xpatent on the LZW compression method:
X
XFrom uunet!zephyr.ens.tek.com!uw-beaver!mit-eddie!wuarchive!usc!ucsd!ucbvax!agate!riacs!jaw Wed Aug  1 15:06:59 EDT 1990
XArticle: 1282 of gnu.misc.discuss
XPath: alembic!uunet!zephyr.ens.tek.com!uw-beaver!mit-eddie!wuarchive!usc!ucsd!ucbvax!agate!riacs!jaw
XFrom: jaw@riacs.edu (James A. Woods)
XNewsgroups: gnu.misc.discuss
XSubject: Sperry patent #4,558,302 does *not* affect 'compress'
XKeywords: data compression, algorithm, patent
XMessage-ID: <1990Jul31.220935.1424@riacs.edu>
XDate: 31 Jul 90 22:09:35 GMT
XOrganization: RIACS, NASA Ames Research Center
XLines: 69
X
X#  "The chief defect of Henry King
X    Was chewing little bits of string."
X
X        -- Hilaire Belloc, Cautionary Tales [1907]
X
X     As a co-author of 'compress' who has had contact with an attorney for
XUnisys (nee Sperry), I would like to relay a very basic admission from Unisys
Xthat noncommercial use of 'compress' is perfectly legal.  'Compress' is also
Xcommercially distributed by AT&T as part of Unix System 5 release 4,
Xwith no further restrictions placed upon the use of the binary, as far
Xas I am aware.
X
X     From conversations with Professor Abraham Lempel and others, it 
Xappears that neither AT&T, Sun Microsystems, Hewlett Packard, nor IBM
Xare paying any sort of license fees to Unisys in conjunction with patent
X#4,558,302.  It may be true that some organizations are paying fees for
Xdata compression technology licensed from one or more of the many holders
Xof compression patents, but this is all independent from 'compress'.
X
X     In particular, I received a letter at NASA dated October 1, 1987 from
XJohn B. Sowell of the Unisys law department, informing me for the first
Xtime that some form of LZW was patented.  I naturally expressed
Xskepticism that an algorithm could be patented (a murky legal area
Xwhich remains so), stated that 'compress' is not identical to LZW,
Xand in fact was designed, developed, and distributed before the ink
Xon the patent was dry.  Several telephone conversations later, Mr. Sowell
Xintimated that they would *not* seek any fees from users of 'compress'
Xbut instead were signing licensees for hardware implementations of LZW.
X
X     So, regardless of what you believe about a shady legal area, if anyone
Xfrom Unisys contacts you to extract tribute for the use of 'compress', please
Xtell them that, first, it is not theirs to begin with, and, second, there is
Xsomeone who will testify in court about the conversation above.
XIt is not even clear if anyone can "own" 'compress', since original developer
XSpencer Thomas, myself, and others placed the code in the public domain
Xlong before the adoption of the Berne copyright convention.
X
X     In light of the events above, it seems that the Free Software
XFoundation is being unduly paranoid about the use of 'compress'.
XNow I can well believe that FSF is more likely to be a legal target
Xthan a behemoth like AT&T, but if they are simply redistributing
Xuntouched free software developed years ago in the public sector,
XI see no problem.
X
X     Aside:  I am investigating, possibly for a case history to be
Xrecycled to USENET, the particulars of data compression patents.
XI am aware of the following patents: IBM's Miller-Wegman LZ variant,
Xthose of Telcor and ACT [losing candidates for the British Telecom modem
Xstandard], James A. Storer's work on limited lookahead as explicated in his
Xtext "Data Compression (methods and theory)", Computer Science Press, 1988,
Xand the various patents pending associated with the Fiala and Greene
XCACM article of April, 1989 on textual substitution methods.
XIf you have any lore, send it this way.
X
X
X
X					Sincerely,
X
X					James A. Woods
X					NASA Ames Research Center (RIACS)
X					jaw@riacs.edu (or ames!jaw)
X
X
XP.S.  The algorithm patent issue certainly is a "topic A" at the moment.
XOne useful reference is the review article by Anthony and Colwell --
X"Litigating the Validity and Infringement of Software Patents" in
XWashington and Lee Law Review, volume 41, fall 1984.  I know Robert Colwell
Xpersonally.  As a practicing patent attorney, he tells me that, at a minimum,
Xuse of an invention "for research purposes" is legitimate.
X
X
X
X
END_OF_FILE
if test 7854 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'compress.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'compress.c'\"
else
echo shar: Extracting \"'compress.c'\" \(42620 characters\)
sed "s/^X//" >'compress.c' <<'END_OF_FILE'
X/* 
X * Compress - data compression program 
X */
X#define	min(a,b)	((a>b) ? b : a)
X
X/*
X * machine variants which require cc -Dmachine:  pdp11, z8000, pcxt
X */
X
X/*
X * Set USERMEM to the maximum amount of physical user memory available
X * in bytes.  USERMEM is used to determine the maximum BITS that can be used
X * for compression.
X *
X * SACREDMEM is the amount of physical memory saved for others; compress
X * will hog the rest.
X */
X#ifndef SACREDMEM
X#define SACREDMEM	0
X#endif
X
X#ifndef USERMEM
X# define USERMEM 	450000	/* default user memory */
X#endif
X
X#ifdef interdata		/* (Perkin-Elmer) */
X#define SIGNED_COMPARE_SLOW	/* signed compare is slower than unsigned */
X#endif
X
X#ifdef pdp11
X# define BITS 	12	/* max bits/code for 16-bit machine */
X# define NO_UCHAR	/* also if "unsigned char" functions as signed char */
X# undef USERMEM 
X#endif /* pdp11 */	/* don't forget to compile with -i */
X
X#ifdef z8000
X# define BITS 	12
X# undef vax		/* weird preprocessor */
X# undef USERMEM 
X#endif /* z8000 */
X
X#ifdef pcxt
X# define BITS   12
X# undef USERMEM
X#endif /* pcxt */
X
X#ifdef USERMEM
X# if USERMEM >= (433484+SACREDMEM)
X#  define PBITS	16
X# else
X#  if USERMEM >= (229600+SACREDMEM)
X#   define PBITS	15
X#  else
X#   if USERMEM >= (127536+SACREDMEM)
X#    define PBITS	14
X#   else
X#    if USERMEM >= (73464+SACREDMEM)
X#     define PBITS	13
X#    else
X#     define PBITS	12
X#    endif
X#   endif
X#  endif
X# endif
X# undef USERMEM
X#endif /* USERMEM */
X
X#ifdef PBITS		/* Preferred BITS for this memory size */
X# ifndef BITS
X#  define BITS PBITS
X# endif /* BITS */
X#endif /* PBITS */
X
X#if BITS == 16
X# define HSIZE	69001		/* 95% occupancy */
X#endif
X#if BITS == 15
X# define HSIZE	35023		/* 94% occupancy */
X#endif
X#if BITS == 14
X# define HSIZE	18013		/* 91% occupancy */
X#endif
X#if BITS == 13
X# define HSIZE	9001		/* 91% occupancy */
X#endif
X#if BITS <= 12
X# define HSIZE	5003		/* 80% occupancy */
X#endif
X
X#ifdef M_XENIX			/* Stupid compiler can't handle arrays with */
X# if BITS == 16			/* more than 65535 bytes - so we fake it */
X#  define XENIX_16
X# else
X#  if BITS > 13			/* Code only handles BITS = 12, 13, or 16 */
X#   define BITS	13
X#  endif
X# endif
X#endif
X
X/*
X * a code_int must be able to hold 2**BITS values of type int, and also -1
X */
X#if BITS > 15
Xtypedef long int	code_int;
X#else
Xtypedef int		code_int;
X#endif
X
X#ifdef SIGNED_COMPARE_SLOW
Xtypedef unsigned long int count_int;
Xtypedef unsigned short int count_short;
X#else
Xtypedef long int	  count_int;
X#endif
X
X#ifdef NO_UCHAR
X typedef char	char_type;
X#else
X typedef	unsigned char	char_type;
X#endif /* UCHAR */
Xchar_type magic_header[] = { "\037\235" };	/* 1F 9D */
X
X/* Defines for third byte of header */
X#define BIT_MASK	0x1f
X#define BLOCK_MASK	0x80
X/* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
X   a fourth header byte (for expansion).
X*/
X#define INIT_BITS 9			/* initial number of bits/code */
X
X/*
X * compress.c - File compression ala IEEE Computer, June 1984.
X *
X * Authors:	Spencer W. Thomas	(decvax!harpo!utah-cs!utah-gr!thomas)
X *		Jim McKie		(decvax!mcvax!jim)
X *		Steve Davies		(decvax!vax135!petsd!peora!srd)
X *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
X *		James A. Woods		(decvax!ihnp4!ames!jaw)
X *		Joe Orost		(decvax!vax135!petsd!joe)
X *		Dave Mack		(csu@alembic.acs.com)
X *
X * Revision 4.1   91/05/26  	  csu@alembic.acs.com
X * Modified to recursively compress directories ('r' flag). As a side
X * effect, compress will no longer attempt to compress things that
X * aren't "regular" files. See Changes.
X *
X * Revision 4.0  85/07/30  12:50:00  joe
X * Removed ferror() calls in output routine on every output except first.
X * Prepared for release to the world.
X * 
X * Revision 3.6  85/07/04  01:22:21  joe
X * Remove much wasted storage by overlaying hash table with the tables
X * used by decompress: tab_suffix[1<<BITS], stack[8000].  Updated USERMEM
X * computations.  Fixed dump_tab() DEBUG routine.
X *
X * Revision 3.5  85/06/30  20:47:21  jaw
X * Change hash function to use exclusive-or.  Rip out hash cache.  These
X * speedups render the megamemory version defunct, for now.  Make decoder
X * stack global.  Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
X *
X * Revision 3.4  85/06/27  12:00:00  ken
X * Get rid of all floating-point calculations by doing all compression ratio
X * calculations in fixed point.
X *
X * Revision 3.3  85/06/24  21:53:24  joe
X * Incorporate portability suggestion for M_XENIX.  Got rid of text on #else
X * and #endif lines.  Cleaned up #ifdefs for vax and interdata.
X *
X * Revision 3.2  85/06/06  21:53:24  jaw
X * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
X * Default to "quiet" output (no compression statistics).
X *
X * Revision 3.1  85/05/12  18:56:13  jaw
X * Integrate decompress() stack speedups (from early pointer mods by McKie).
X * Repair multi-file USERMEM gaffe.  Unify 'force' flags to mimic semantics
X * of SVR2 'pack'.  Streamline block-compress table clear logic.  Increase 
X * output byte count by magic number size.
X * 
X * Revision 3.0   84/11/27  11:50:00  petsd!joe
X * Set HSIZE depending on BITS.  Set BITS depending on USERMEM.  Unrolled
X * loops in clear routines.  Added "-C" flag for 2.0 compatibility.  Used
X * unsigned compares on Perkin-Elmer.  Fixed foreground check.
X *
X * Revision 2.7   84/11/16  19:35:39  ames!jaw
X * Cache common hash codes based on input statistics; this improves
X * performance for low-density raster images.  Pass on #ifdef bundle
X * from Turkowski.
X *
X * Revision 2.6   84/11/05  19:18:21  ames!jaw
X * Vary size of hash tables to reduce time for small files.
X * Tune PDP-11 hash function.
X *
X * Revision 2.5   84/10/30  20:15:14  ames!jaw
X * Junk chaining; replace with the simpler (and, on the VAX, faster)
X * double hashing, discussed within.  Make block compression standard.
X *
X * Revision 2.4   84/10/16  11:11:11  ames!jaw
X * Introduce adaptive reset for block compression, to boost the rate
X * another several percent.  (See mailing list notes.)
X *
X * Revision 2.3   84/09/22  22:00:00  petsd!joe
X * Implemented "-B" block compress.  Implemented REVERSE sorting of tab_next.
X * Bug fix for last bits.  Changed fwrite to putchar loop everywhere.
X *
X * Revision 2.2   84/09/18  14:12:21  ames!jaw
X * Fold in news changes, small machine typedef from thomas,
X * #ifdef interdata from joe.
X *
X * Revision 2.1   84/09/10  12:34:56  ames!jaw
X * Configured fast table lookup for 32-bit machines.
X * This cuts user time in half for b <= FBITS, and is useful for news batching
X * from VAX to PDP sites.  Also sped up decompress() [fwrite->putc] and
X * added signal catcher [plus beef in writeerr()] to delete effluvia.
X *
X * Revision 2.0   84/08/28  22:00:00  petsd!joe
X * Add check for foreground before prompting user.  Insert maxbits into
X * compressed file.  Force file being uncompressed to end with ".Z".
X * Added "-c" flag and "zcat".  Prepared for release.
X *
X * Revision 1.10  84/08/24  18:28:00  turtlevax!ken
X * Will only compress regular files (no directories), added a magic number
X * header (plus an undocumented -n flag to handle old files without headers),
X * added -f flag to force overwriting of possibly existing destination file,
X * otherwise the user is prompted for a response.  Will tack on a .Z to a
X * filename if it doesn't have one when decompressing.  Will only replace
X * file if it was compressed.
X *
X * Revision 1.9  84/08/16  17:28:00  turtlevax!ken
X * Removed scanargs(), getopt(), added .Z extension and unlimited number of
X * filenames to compress.  Flags may be clustered (-Ddvb12) or separated
X * (-D -d -v -b 12), or combination thereof.  Modes and other status is
X * copied with copystat().  -O bug for 4.2 seems to have disappeared with
X * 1.8.
X *
X * Revision 1.8  84/08/09  23:15:00  joe
X * Made it compatible with vax version, installed jim's fixes/enhancements
X *
X * Revision 1.6  84/08/01  22:08:00  joe
X * Sped up algorithm significantly by sorting the compress chain.
X *
X * Revision 1.5  84/07/13  13:11:00  srd
X * Added C version of vax asm routines.  Changed structure to arrays to
X * save much memory.  Do unsigned compares where possible (faster on
X * Perkin-Elmer)
X *
X * Revision 1.4  84/07/05  03:11:11  thomas
X * Clean up the code a little and lint it.  (Lint complains about all
X * the regs used in the asm, but I'm not going to "fix" this.)
X *
X * Revision 1.3  84/07/05  02:06:54  thomas
X * Minor fixes.
X *
X * Revision 1.2  84/07/05  00:27:27  thomas
X * Add variable bit length output.
X *
X */
Xstatic char version_id[] = "compress.c 4.1";
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifndef DIRENT
X#include <sys/dir.h>
X#else
X#include <dirent.h>
X#endif
X#include <errno.h>
Xextern int errno;
X
X#include "patchlevel.h"
X
X#define ARGVAL() (*++(*argv) || (--argc && *++argv))
X
Xint n_bits;				/* number of bits/code */
Xint maxbits = BITS;			/* user settable max # bits/code */
Xcode_int maxcode;			/* maximum code, given n_bits */
Xcode_int maxmaxcode = 1 << BITS;	/* should NEVER generate this code */
X#ifdef COMPATIBLE		/* But wrong! */
X# define MAXCODE(n_bits)	(1 << (n_bits) - 1)
X#else
X# define MAXCODE(n_bits)	((1 << (n_bits)) - 1)
X#endif /* COMPATIBLE */
X
X#ifdef XENIX_16
Xcount_int htab0[8192];
Xcount_int htab1[8192];
Xcount_int htab2[8192];
Xcount_int htab3[8192];
Xcount_int htab4[8192];
Xcount_int htab5[8192];
Xcount_int htab6[8192];
Xcount_int htab7[8192];
Xcount_int htab8[HSIZE-65536];
Xcount_int * htab[9] = {
X	htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8 };
X
X#define htabof(i)	(htab[(i) >> 13][(i) & 0x1fff])
Xunsigned short code0tab[16384];
Xunsigned short code1tab[16384];
Xunsigned short code2tab[16384];
Xunsigned short code3tab[16384];
Xunsigned short code4tab[16384];
Xunsigned short * codetab[5] = {
X	code0tab, code1tab, code2tab, code3tab, code4tab };
X
X#define codetabof(i)	(codetab[(i) >> 14][(i) & 0x3fff])
X
X#else	/* Normal machine */
Xcount_int htab [HSIZE];
Xunsigned short codetab [HSIZE];
X#define htabof(i)	htab[i]
X#define codetabof(i)	codetab[i]
X#endif	/* XENIX_16 */
Xcode_int hsize = HSIZE;			/* for dynamic table sizing */
Xcount_int fsize;
X
X/*
X * To save much memory, we overlay the table used by compress() with those
X * used by decompress().  The tab_prefix table is the same size and type
X * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
X * get this from the beginning of htab.  The output stack uses the rest
X * of htab, and contains characters.  There is plenty of room for any
X * possible stack (stack used to be 8000 characters).
X */
X
X#define tab_prefixof(i)	codetabof(i)
X#ifdef XENIX_16
X# define tab_suffixof(i)	((char_type *)htab[(i)>>15])[(i) & 0x7fff]
X# define de_stack		((char_type *)(htab2))
X#else	/* Normal machine */
X# define tab_suffixof(i)	((char_type *)(htab))[i]
X# define de_stack		((char_type *)&tab_suffixof(1<<BITS))
X#endif	/* XENIX_16 */
X
Xcode_int free_ent = 0;			/* first unused entry */
Xint exit_stat = 0;
X
Xcode_int getcode();
X
XUsage() {
X#ifdef DEBUG
Xfprintf(stderr,"Usage: compress [-dDVfcr] [-b maxbits] [file ...]\n");
X}
Xint debug = 0;
X#else
Xfprintf(stderr,"Usage: compress [-dfvcVr] [-b maxbits] [file ...]\n");
X}
X#endif /* DEBUG */
Xint nomagic = 0;	/* Use a 3-byte magic number header, unless old file */
Xint zcat_flg = 0;	/* Write output on stdout, suppress messages */
Xint quiet = 1;		/* don't tell me about compression */
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
Xint block_compress = BLOCK_MASK;
Xint clear_flg = 0;
Xlong int ratio = 0;
X#if BITS == 16
X#define CHECK_GAP 50000	/* ratio check interval recommended by jaw */
X#else
X#define CHECK_GAP 10000	/* ratio check interval */
X#endif
Xcount_int checkpoint = CHECK_GAP;
X/*
X * the next two codes should not be changed lightly, as they must not
X * lie within the contiguous general code space.
X */ 
X#define FIRST	257	/* first free entry */
X#define	CLEAR	256	/* table clear output code */
X
Xint force = 0;
Xchar ofname [100];
X#ifdef DEBUG
Xint verbose = 0;
X#endif /* DEBUG */
X
X#ifndef	VOIDSIG
Xint (*bgnd_flag)();
X#else
Xvoid (*bgnd_flag)();
X#endif	/* VOIDSIG */
X
X
Xint do_decomp = 0;
X
X/*****************************************************************
X * TAG( main )
X *
X * Algorithm from "A Technique for High Performance Data Compression",
X * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
X *
X * Usage: compress [-dfvc] [-b bits] [file ...]
X * Inputs:
X *	-d:	    If given, decompression is done instead.
X *
X *      -c:         Write output on stdout, don't remove original.
X *
X *      -b:         Parameter limits the max number of bits/code.
X *
X *	-f:	    Forces output file to be generated, even if one already
X *		    exists, and even if no space is saved by compressing.
X *		    If -f is not used, the user will be prompted if stdin is
X *		    a tty, otherwise, the output file will not be overwritten.
X *
X *      -v:	    Write compression statistics
X *
X *	-r:		Recursive. If a filename is a directory, descend
X *			into it and compress everything in it.
X *
X * 	file ...:   Files to be compressed.  If none specified, stdin
X *		    is used.
X * Outputs:
X *	file.Z:	    Compressed form of file with same mode, owner, and utimes
X * 	or stdout   (if stdin used as input)
X *
X * Assumptions:
X *	When filenames are given, replaces with the compressed version
X *	(.Z suffix) only if the file decreases in size.
X * Algorithm:
X * 	Modified Lempel-Ziv method (LZW).  Basically finds common
X * substrings and replaces them with a variable size code.  This is
X * deterministic, and can be done on the fly.  Thus, the decompression
X * procedure needs no input table, but tracks the way the table was built.
X */
X
Xint overwrite = 0;	/* Do not overwrite unless given -f flag */
Xint recursive = 0;  /* compress directories */
Xmain( argc, argv )
Xregister int argc; char **argv;
X{
X    char **filelist, **fileptr;
X    char *cp, *rindex(), *malloc();
X    extern onintr(), oops();
X
X
X    if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
X	signal ( SIGINT, onintr );
X	signal ( SIGSEGV, oops );
X    }
X
X#ifdef COMPATIBLE
X    nomagic = 1;	/* Original didn't have a magic number */
X#endif /* COMPATIBLE */
X
X    filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
X    *filelist = NULL;
X
X    if((cp = rindex(argv[0], '/')) != 0) {
X	cp++;
X    } else {
X	cp = argv[0];
X    }
X    if(strcmp(cp, "uncompress") == 0) {
X	do_decomp = 1;
X    } else if(strcmp(cp, "zcat") == 0) {
X	do_decomp = 1;
X	zcat_flg = 1;
X    }
X
X#ifdef BSD4
X    /* 4.2BSD dependent - take it out if not */
X    setlinebuf( stderr );
X#endif /* BSD4 */
X
X    /* Argument Processing
X     * All flags are optional.
X     * -D => debug
X     * -V => print Version; debug verbose
X     * -d => do_decomp
X     * -v => unquiet
X     * -f => force overwrite of output file
X     * -n => no header: useful to uncompress old files
X     * -b maxbits => maxbits.  If -b is specified, then maxbits MUST be
X     *	    given also.
X     * -c => cat all output to stdout
X     * -C => generate output compatible with compress 2.0.
X     * -r => recursively compress directories
X     * if a string is left, must be an input filename.
X     */
X    for (argc--, argv++; argc > 0; argc--, argv++) {
X	if (**argv == '-') {	/* A flag argument */
X	    while (*++(*argv)) {	/* Process all flags in this arg */
X		switch (**argv) {
X#ifdef DEBUG
X		    case 'D':
X			debug = 1;
X			break;
X		    case 'V':
X			verbose = 1;
X			version();
X			break;
X#else
X		    case 'V':
X			version();
X			break;
X#endif /* DEBUG */
X		    case 'v':
X			quiet = 0;
X			break;
X		    case 'd':
X			do_decomp = 1;
X			break;
X		    case 'f':
X		    case 'F':
X			overwrite = 1;
X			force = 1;
X			break;
X		    case 'n':
X			nomagic = 1;
X			break;
X		    case 'C':
X			block_compress = 0;
X			break;
X		    case 'b':
X			if (!ARGVAL()) {
X			    fprintf(stderr, "Missing maxbits\n");
X			    Usage();
X			    exit(1);
X			}
X			maxbits = atoi(*argv);
X			goto nextarg;
X		    case 'c':
X			zcat_flg = 1;
X			break;
X		    case 'q':
X			quiet = 1;
X			break;
X		    case 'r':
X		    case 'R':
X			recursive = 1;
X			break;
X		    default:
X			fprintf(stderr, "Unknown flag: '%c'; ", **argv);
X			Usage();
X			exit(1);
X		}
X	    }
X	}
X	else {		/* Input file name */
X	    *fileptr++ = *argv;	/* Build input file list */
X	    *fileptr = NULL;
X	    /* process nextarg; */
X	}
X	nextarg: continue;
X    }
X
X    if(maxbits < INIT_BITS) maxbits = INIT_BITS;
X    if (maxbits > BITS) maxbits = BITS;
X    maxmaxcode = 1 << maxbits;
X
X    if (*filelist != NULL) {
X      for (fileptr = filelist; *fileptr; fileptr++) {
X	comprexx(fileptr);
X      }
X    } else {		/* Standard input */
X	if (do_decomp == 0) {
X		compress();
X		if(!quiet)
X			putc('\n', stderr);
X	} else {
X		/* Check the magic number */
X		if (nomagic == 0) {
X		if ((getchar()!=(magic_header[0] & 0xFF))
X		 || (getchar()!=(magic_header[1] & 0xFF))) {
X			fprintf(stderr, "stdin: not in compressed format\n");
X			exit(1);
X		}
X		maxbits = getchar();	/* set -b from file */
X		block_compress = maxbits & BLOCK_MASK;
X		maxbits &= BIT_MASK;
X		maxmaxcode = 1 << maxbits;
X		fsize = 100000;		/* assume stdin large for USERMEM */
X		if(maxbits > BITS) {
X			fprintf(stderr,
X			"stdin: compressed with %d bits, can only handle %d bits\n",
X			maxbits, BITS);
X			exit(1);
X		}
X		}
X#ifndef DEBUG
X		decompress();
X#else   /* DEBUG */
X		if (debug == 0)	decompress();
X		else		printcodes();
X		if (verbose)	dump_tab();
X#endif /* DEBUG */
X	}
X	}
X	exit(exit_stat);
X}
X
Xcomprexx(fileptr)
Xchar **fileptr;
X{
X	struct stat statbuf,insbuf;
X	char tempname[1024], *cp;
X
X	strcpy(tempname,*fileptr);
X	errno = 0;
X#ifdef	BSD4
X	if (lstat(tempname,&insbuf) == -1) {
X#else
X	if (stat(tempname,&insbuf) == -1) {
X#endif
X	  if ( do_decomp ) {
X	    switch (errno) {
X	    case ENOENT:	/* file doesn't exist */
X	      /*
X	      ** if the given name doesn't end with .Z, try appending one
X	      ** This is obviously the wrong thing to do if it's a 
X	      ** directory, but it shouldn't do any harm.
X	      */
X	      if (strcmp(tempname + strlen(tempname) - 2, ".Z") != 0) {
X		strcat(tempname,".Z");
X		errno = 0;
X#ifdef	BSD4
X		if (lstat(tempname,&insbuf) == -1) {
X#else
X		if (stat(tempname,&insbuf) == -1) {
X#endif
X		  perror(tempname);
X		  return;
X		}
X	      }
X	      else {
X		perror(tempname);
X		return;
X	      }
X	      break;
X	    default:
X	      perror(tempname);
X	      return;
X	    } /* end switch */
X	  } /* endif */
X	  else {
X	    /* we can't stat the file, ignore it */
X	      perror(tempname);
X	      return;
X	  }
X	} /* endif */
X
X	switch (insbuf.st_mode & S_IFMT) {
X	case S_IFDIR:	/* directory */
X	  if (recursive)
X	    compdir(tempname);
X	  break;
X
X	case S_IFREG:	/* regular file */
X	  exit_stat = 0;
X	  if (do_decomp != 0) {
X	/* DECOMPRESSION */
X	    if ( ! zcat_flg ) {
X	      if (strcmp(tempname + strlen(tempname) - 2, ".Z") != 0) {
X		if ( ! quiet ) {
X		  fprintf(stderr,"%s - no .Z suffix\n",tempname);
X		}
X		return;
X	      }
X	    }
X	    /* Open input file */
X	    if ((freopen(tempname, "r", stdin)) == NULL) {
X	      perror(tempname); return;
X	    }
X		/* Check the magic number */
X		if (nomagic == 0) {
X		    if ((getchar() != (magic_header[0] & 0xFF))
X		     || (getchar() != (magic_header[1] & 0xFF))) {
X			fprintf(stderr, "%s: not in compressed format\n",
X			    tempname);
X					return;
X		    }
X		    maxbits = getchar();	/* set -b from file */
X		    block_compress = maxbits & BLOCK_MASK;
X		    maxbits &= BIT_MASK;
X		    maxmaxcode = 1 << maxbits;
X		    if(maxbits > BITS) {
X			fprintf(stderr,
X			"%s: compressed with %d bits, can only handle %d bits\n",
X			tempname, maxbits, BITS);
X					return;
X		    }
X		}
X	        /* we have to ignore SIGINT for a while, otherwise
X		   a ^C can nuke an existing file with ofname */
X	        signal(SIGINT,SIG_IGN);
X		/* Generate output filename */
X		strcpy(ofname, tempname);
X		/* Check for .Z suffix */
X		if (strcmp(tempname + strlen(tempname) - 2, ".Z") == 0) {
X		  ofname[strlen(tempname) - 2] = '\0';  /* Strip off .Z */
X		}
X	    }
X	    else {
X	/* COMPRESSION */
X		if (strcmp(tempname + strlen(tempname) - 2, ".Z") == 0) {
X		    	fprintf(stderr, "%s: already has .Z suffix -- no change\n",
X			    tempname);
X		    return;
X		}
X		/* Open input file */
X		if ((freopen(tempname, "r", stdin)) == NULL) {
X		    perror(tempname); return;
X		}
X		fsize = (long) insbuf.st_size;
X		/*
X		 * tune hash table size for small files -- ad hoc,
X		 * but the sizes match earlier #defines, which
X		 * serve as upper bounds on the number of output codes. 
X		 */
X		hsize = HSIZE;
X		if ( fsize < (1 << 12) )
X		    hsize = min ( 5003, HSIZE );
X		else if ( fsize < (1 << 13) )
X		    hsize = min ( 9001, HSIZE );
X		else if ( fsize < (1 << 14) )
X		    hsize = min ( 18013, HSIZE );
X		else if ( fsize < (1 << 15) )
X		    hsize = min ( 35023, HSIZE );
X		else if ( fsize < 47000 )
X		    hsize = min ( 50021, HSIZE );
X
X	        /* we have to ignore SIGINT for a while, otherwise
X		   a ^C can nuke an existing file with ofname */
X	        signal(SIGINT,SIG_IGN);
X		/* Generate output filename */
X		strcpy(ofname, tempname);
X#ifdef SHORTNAMES	/* Short filenames */
X		if ((cp=rindex(ofname,'/')) != NULL)	cp++;
X		else					cp = ofname;
X		if (strlen(cp) > 12) {
X		    fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
X		    signal(SIGINT,onintr);
X		    return;
X		}
X#endif  /* SHORTNAMES */
X		strcat(ofname, ".Z");
X	    }
X	    /* Check for overwrite of existing file */
X	    if (overwrite == 0 && zcat_flg == 0) {
X		if (stat(ofname, &statbuf) == 0) {
X		    char response[2];
X		    response[0] = 'n';
X		    fprintf(stderr, "%s already exists;", ofname);
X		    if (foreground()) {
X			fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
X			ofname);
X			fflush(stderr);
X			read(2, response, 2);
X			while (response[1] != '\n') {
X			    if (read(2, response+1, 1) < 0) {	/* Ack! */
X				perror("stderr"); break;
X			    }
X			}
X		    }
X		    if (response[0] != 'y') {
X			fprintf(stderr, "\tnot overwritten\n");
X			signal(SIGINT,onintr);
X			return;
X		    }
X		}
X	    }
X	    signal(SIGINT,onintr);
X	    if(zcat_flg == 0) {		/* Open output file */
X		if (freopen(ofname, "w", stdout) == NULL) {
X		    perror(ofname);
X			return;
X		}
X		if(!quiet)
X			fprintf(stderr, "%s: ", tempname);
X	    }
X
X	    /* Actually do the compression/decompression */
X	    if (do_decomp == 0)	compress();
X#ifndef DEBUG
X	    else			decompress();
X#else
X	    else if (debug == 0)	decompress();
X	    else			printcodes();
X	    if (verbose)		dump_tab();
X#endif /* DEBUG */
X	    if(zcat_flg == 0) {
X		copystat(tempname, ofname);	/* Copy stats */
X		if((exit_stat == 1) || (!quiet))
X			putc('\n', stderr);
X	    }
X	default:
X		break;
X	} /* end switch */
X	return;
X} /* end comprexx */
X
Xcompdir(dir)
Xchar *dir;
X{
X	DIR *dirp;
X#ifndef	DIRENT
X	register struct direct *dp;
X#else
X	register struct dirent *dp;
X#endif
X	char nbuf[1024];
X	char *nptr = nbuf;
X	dirp = opendir(dir);
X	if (dirp == NULL) {
X		printf("%s unreadable\n", dir);		/* not stderr! */
X		return ;
X	}
X	while (dp = readdir(dirp)) {
X		if (dp->d_ino == 0)
X			continue;
X		if (strcmp(dp->d_name,".") == 0 || strcmp(dp->d_name,"..") == 0)
X			continue;
X		strcpy(nbuf,dir);
X		strcat(nbuf,"/");
X		strcat(nbuf,dp->d_name);
X		comprexx(&nptr);
X  	}
X	closedir(dirp);
X	return;
X} /* end compdir */
X
Xstatic int offset;
Xlong int in_count = 1;			/* length of input */
Xlong int bytes_out;			/* length of compressed output */
Xlong int out_count = 0;			/* # of codes output (for debugging) */
X
X/*
X * compress stdin to stdout
X *
X * Algorithm:  use open addressing double hashing (no chaining) on the 
X * prefix code / next character combination.  We do a variant of Knuth's
X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
X * secondary probe.  Here, the modular division first probe is gives way
X * to a faster exclusive-or manipulation.  Also do block compression with
X * an adaptive reset, whereby the code table is cleared when the compression
X * ratio decreases, but after the table fills.  The variable-length output
X * codes are re-sized at this point, and a special CLEAR code is generated
X * for the decompressor.  Late addition:  construct the table according to
X * file size for noticeable speed improvement on small files.  Please direct
X * questions about this implementation to ames!jaw.
X */
X
Xcompress() {
X    register long fcode;
X    register code_int i = 0;
X    register int c;
X    register code_int ent;
X#ifdef XENIX_16
X    register code_int disp;
X#else	/* Normal machine */
X    register int disp;
X#endif
X    register code_int hsize_reg;
X    register int hshift;
X
X#ifndef COMPATIBLE
X    if (nomagic == 0) {
X	putchar(magic_header[0]); putchar(magic_header[1]);
X	putchar((char)(maxbits | block_compress));
X	if(ferror(stdout))
X		writeerr();
X    }
X#endif /* COMPATIBLE */
X
X    offset = 0;
X    bytes_out = 3;		/* includes 3-byte header mojo */
X    out_count = 0;
X    clear_flg = 0;
X    ratio = 0;
X    in_count = 1;
X    checkpoint = CHECK_GAP;
X    maxcode = MAXCODE(n_bits = INIT_BITS);
X    free_ent = ((block_compress) ? FIRST : 256 );
X
X    ent = getchar ();
X
X    hshift = 0;
X    for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
X    	hshift++;
X    hshift = 8 - hshift;		/* set hash code range bound */
X
X    hsize_reg = hsize;
X    cl_hash( (count_int) hsize_reg);		/* clear hash table */
X
X#ifdef SIGNED_COMPARE_SLOW
X    while ( (c = getchar()) != (unsigned) EOF ) {
X#else
X    while ( (c = getchar()) != EOF ) {
X#endif
X	in_count++;
X	fcode = (long) (((long) c << maxbits) + ent);
X 	i = ((c << hshift) ^ ent);	/* xor hashing */
X
X	if ( htabof (i) == fcode ) {
X	    ent = codetabof (i);
X	    continue;
X	} else if ( (long)htabof (i) < 0 )	/* empty slot */
X	    goto nomatch;
X 	disp = hsize_reg - i;		/* secondary hash (after G. Knott) */
X	if ( i == 0 )
X	    disp = 1;
Xprobe:
X	if ( (i -= disp) < 0 )
X	    i += hsize_reg;
X
X	if ( htabof (i) == fcode ) {
X	    ent = codetabof (i);
X	    continue;
X	}
X	if ( (long)htabof (i) > 0 ) 
X	    goto probe;
Xnomatch:
X	output ( (code_int) ent );
X	out_count++;
X 	ent = c;
X#ifdef SIGNED_COMPARE_SLOW
X	if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
X#else
X	if ( free_ent < maxmaxcode ) {
X#endif
X 	    codetabof (i) = free_ent++;	/* code -> hashtable */
X	    htabof (i) = fcode;
X	}
X	else if ( (count_int)in_count >= checkpoint && block_compress )
X	    cl_block ();
X    }
X    /*
X     * Put out the final code.
X     */
X    output( (code_int)ent );
X    out_count++;
X    output( (code_int)-1 );
X
X    /*
X     * Print out stats on stderr
X     */
X    if(zcat_flg == 0 && !quiet) {
X#ifdef DEBUG
X	fprintf( stderr,
X		"%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
X		in_count, out_count, bytes_out );
X	prratio( stderr, in_count, bytes_out );
X	fprintf( stderr, "\n");
X	fprintf( stderr, "\tCompression as in compact: " );
X	prratio( stderr, in_count-bytes_out, in_count );
X	fprintf( stderr, "\n");
X	fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
X		free_ent - 1, n_bits );
X#else /* !DEBUG */
X	fprintf( stderr, "Compression: " );
X	prratio( stderr, in_count-bytes_out, in_count );
X#endif /* DEBUG */
X    }
X    if(bytes_out > in_count)	/* exit(2) if no savings */
X	exit_stat = 2;
X    return;
X}
X
X/*****************************************************************
X * TAG( output )
X *
X * Output the given code.
X * Inputs:
X * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
X *		that n_bits =< (long)wordsize - 1.
X * Outputs:
X * 	Outputs code to the file.
X * Assumptions:
X *	Chars are 8 bits long.
X * Algorithm:
X * 	Maintain a BITS character long buffer (so that 8 codes will
X * fit in it exactly).  Use the VAX insv instruction to insert each
X * code in turn.  When the buffer fills up empty it and start over.
X */
X
Xstatic char buf[BITS];
X
X#ifndef vax
Xchar_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
Xchar_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
X#endif /* vax */
X
Xoutput( code )
Xcode_int  code;
X{
X#ifdef DEBUG
X    static int col = 0;
X#endif /* DEBUG */
X
X    /*
X     * On the VAX, it is important to have the register declarations
X     * in exactly the order given, or the asm will break.
X     */
X    register int r_off = offset, bits= n_bits;
X    register char * bp = buf;
X
X#ifdef DEBUG
X	if ( verbose )
X	    fprintf( stderr, "%5d%c", code,
X		    (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
X#endif /* DEBUG */
X    if ( code >= 0 ) {
X#ifdef vax
X	/* VAX DEPENDENT!! Implementation on other machines is below.
X	 *
X	 * Translation: Insert BITS bits from the argument starting at
X	 * offset bits from the beginning of buf.
X	 */
X	0;	/* Work around for pcc -O bug with asm and if stmt */
X	asm( "insv	4(ap),r11,r10,(r9)" );
X#else /* not a vax */
X/* 
X * byte/bit numbering on the VAX is simulated by the following code
X */
X	/*
X	 * Get to the first byte.
X	 */
X	bp += (r_off >> 3);
X	r_off &= 7;
X	/*
X	 * Since code is always >= 8 bits, only need to mask the first
X	 * hunk on the left.
X	 */
X	*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
X	bp++;
X	bits -= (8 - r_off);
X	code >>= 8 - r_off;
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if ( bits >= 8 ) {
X	    *bp++ = code;
X	    code >>= 8;
X	    bits -= 8;
X	}
X	/* Last bits. */
X	if(bits)
X	    *bp = code;
X#endif /* vax */
X	offset += n_bits;
X	if ( offset == (n_bits << 3) ) {
X	    bp = buf;
X	    bits = n_bits;
X	    bytes_out += bits;
X	    do
X		putchar(*bp++);
X	    while(--bits);
X	    offset = 0;
X	}
X
X	/*
X	 * If the next entry is going to be too big for the code size,
X	 * then increase it, if possible.
X	 */
X	if ( free_ent > maxcode || (clear_flg > 0))
X	{
X	    /*
X	     * Write the whole buffer, because the input side won't
X	     * discover the size increase until after it has read it.
X	     */
X	    if ( offset > 0 ) {
X		if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
X			writeerr();
X		bytes_out += n_bits;
X	    }
X	    offset = 0;
X
X	    if ( clear_flg ) {
X    	        maxcode = MAXCODE (n_bits = INIT_BITS);
X	        clear_flg = 0;
X	    }
X	    else {
X	    	n_bits++;
X	    	if ( n_bits == maxbits )
X		    maxcode = maxmaxcode;
X	    	else
X		    maxcode = MAXCODE(n_bits);
X	    }
X#ifdef DEBUG
X	    if ( debug ) {
X		fprintf( stderr, "\nChange to %d bits\n", n_bits );
X		col = 0;
X	    }
X#endif /* DEBUG */
X	}
X    } else {
X	/*
X	 * At EOF, write the rest of the buffer.
X	 */
X	if ( offset > 0 )
X	    fwrite( buf, 1, (offset + 7) / 8, stdout );
X	bytes_out += (offset + 7) / 8;
X	offset = 0;
X	fflush( stdout );
X#ifdef DEBUG
X	if ( verbose )
X	    fprintf( stderr, "\n" );
X#endif /* DEBUG */
X	if( ferror( stdout ) )
X		writeerr();
X    }
X}
X
X/*
X * Decompress stdin to stdout.  This routine adapts to the codes in the
X * file building the "string" table on-the-fly; requiring no table to
X * be stored in the compressed file.  The tables used herein are shared
X * with those of the compress() routine.  See the definitions above.
X */
X
Xdecompress() {
X    register char_type *stackp;
X    register int finchar;
X    register code_int code, oldcode, incode;
X
X    /*
X     * As above, initialize the first 256 entries in the table.
X     */
X    maxcode = MAXCODE(n_bits = INIT_BITS);
X    for ( code = 255; code >= 0; code-- ) {
X	tab_prefixof(code) = 0;
X	tab_suffixof(code) = (char_type)code;
X    }
X    free_ent = ((block_compress) ? FIRST : 256 );
X
X    finchar = oldcode = getcode();
X    if(oldcode == -1)	/* EOF already? */
X	return;			/* Get out of here */
X    putchar( (char)finchar );		/* first code must be 8 bits = char */
X    if(ferror(stdout))		/* Crash if can't write */
X	writeerr();
X    stackp = de_stack;
X
X    while ( (code = getcode()) > -1 ) {
X
X	if ( (code == CLEAR) && block_compress ) {
X	    for ( code = 255; code >= 0; code-- )
X		tab_prefixof(code) = 0;
X	    clear_flg = 1;
X	    free_ent = FIRST - 1;
X	    if ( (code = getcode ()) == -1 )	/* O, untimely death! */
X		break;
X	}
X	incode = code;
X	/*
X	 * Special case for KwKwK string.
X	 */
X	if ( code >= free_ent ) {
X            *stackp++ = finchar;
X	    code = oldcode;
X	}
X
X	/*
X	 * Generate output characters in reverse order
X	 */
X#ifdef SIGNED_COMPARE_SLOW
X	while ( ((unsigned long)code) >= ((unsigned long)256) ) {
X#else
X	while ( code >= 256 ) {
X#endif
X	    *stackp++ = tab_suffixof(code);
X	    code = tab_prefixof(code);
X	}
X	*stackp++ = finchar = tab_suffixof(code);
X
X	/*
X	 * And put them out in forward order
X	 */
X	do
X	    putchar ( *--stackp );
X	while ( stackp > de_stack );
X
X	/*
X	 * Generate the new entry.
X	 */
X	if ( (code=free_ent) < maxmaxcode ) {
X	    tab_prefixof(code) = (unsigned short)oldcode;
X	    tab_suffixof(code) = finchar;
X	    free_ent = code+1;
X	} 
X	/*
X	 * Remember previous code.
X	 */
X	oldcode = incode;
X    }
X    fflush( stdout );
X    if(ferror(stdout))
X	writeerr();
X}
X
X/*****************************************************************
X * TAG( getcode )
X *
X * Read one code from the standard input.  If EOF, return -1.
X * Inputs:
X * 	stdin
X * Outputs:
X * 	code or -1 is returned.
X */
X
Xcode_int
Xgetcode() {
X    /*
X     * On the VAX, it is important to have the register declarations
X     * in exactly the order given, or the asm will break.
X     */
X    register code_int code;
X    static int offset = 0, size = 0;
X    static char_type buf[BITS];
X    register int r_off, bits;
X    register char_type *bp = buf;
X
X    if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
X	/*
X	 * If the next entry will be too big for the current code
X	 * size, then we must increase the size.  This implies reading
X	 * a new buffer full, too.
X	 */
X	if ( free_ent > maxcode ) {
X	    n_bits++;
X	    if ( n_bits == maxbits )
X		maxcode = maxmaxcode;	/* won't get any bigger now */
X	    else
X		maxcode = MAXCODE(n_bits);
X	}
X	if ( clear_flg > 0) {
X    	    maxcode = MAXCODE (n_bits = INIT_BITS);
X	    clear_flg = 0;
X	}
X	size = fread( buf, 1, n_bits, stdin );
X	if ( size <= 0 )
X	    return -1;			/* end of file */
X	offset = 0;
X	/* Round size down to integral number of codes */
X	size = (size << 3) - (n_bits - 1);
X    }
X    r_off = offset;
X    bits = n_bits;
X#ifdef vax
X    asm( "extzv   r10,r9,(r8),r11" );
X#else /* not a vax */
X	/*
X	 * Get to the first byte.
X	 */
X	bp += (r_off >> 3);
X	r_off &= 7;
X	/* Get first part (low order bits) */
X#ifdef NO_UCHAR
X	code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
X#else
X	code = (*bp++ >> r_off);
X#endif /* NO_UCHAR */
X	bits -= (8 - r_off);
X	r_off = 8 - r_off;		/* now, offset into code word */
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if ( bits >= 8 ) {
X#ifdef NO_UCHAR
X	    code |= (*bp++ & 0xff) << r_off;
X#else
X	    code |= *bp++ << r_off;
X#endif /* NO_UCHAR */
X	    r_off += 8;
X	    bits -= 8;
X	}
X	/* high order bits. */
X	code |= (*bp & rmask[bits]) << r_off;
X#endif /* vax */
X    offset += n_bits;
X
X    return code;
X}
X
Xchar *
Xrindex(s, c)		/* For those who don't have it in libc.a */
Xregister char *s, c;
X{
X	char *p;
X	for (p = NULL; *s; s++)
X	    if (*s == c)
X		p = s;
X	return(p);
X}
X
X#ifdef DEBUG
Xprintcodes()
X{
X    /*
X     * Just print out codes from input file.  For debugging.
X     */
X    code_int code;
X    int col = 0, bits;
X
X    bits = n_bits = INIT_BITS;
X    maxcode = MAXCODE(n_bits);
X    free_ent = ((block_compress) ? FIRST : 256 );
X    while ( ( code = getcode() ) >= 0 ) {
X	if ( (code == CLEAR) && block_compress ) {
X   	    free_ent = FIRST - 1;
X   	    clear_flg = 1;
X	}
X	else if ( free_ent < maxmaxcode )
X	    free_ent++;
X	if ( bits != n_bits ) {
X	    fprintf(stderr, "\nChange to %d bits\n", n_bits );
X	    bits = n_bits;
X	    col = 0;
X	}
X	fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
X    }
X    putc( '\n', stderr );
X    exit( 0 );
X}
X
Xcode_int sorttab[1<<BITS];	/* sorted pointers into htab */
X
Xdump_tab()	/* dump string table */
X{
X    register int i, first;
X    register ent;
X#define STACK_SIZE	15000
X    int stack_top = STACK_SIZE;
X    register c;
X
X    if(do_decomp == 0) {	/* compressing */
X	register int flag = 1;
X
X	for(i=0; i<hsize; i++) {	/* build sort pointers */
X		if((long)htabof(i) >= 0) {
X			sorttab[codetabof(i)] = i;
X		}
X	}
X	first = block_compress ? FIRST : 256;
X	for(i = first; i < free_ent; i++) {
X		fprintf(stderr, "%5d: \"", i);
X		de_stack[--stack_top] = '\n';
X		de_stack[--stack_top] = '"';
X		stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff, 
X                                     stack_top);
X		for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
X		    ent > 256;
X		    ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
X			stack_top = in_stack(htabof(sorttab[ent]) >> maxbits,
X						stack_top);
X		}
X		stack_top = in_stack(ent, stack_top);
X		fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
X	   	stack_top = STACK_SIZE;
X	}
X   } else if(!debug) {	/* decompressing */
X
X       for ( i = 0; i < free_ent; i++ ) {
X	   ent = i;
X	   c = tab_suffixof(ent);
X	   if ( isascii(c) && isprint(c) )
X	       fprintf( stderr, "%5d: %5d/'%c'  \"",
X			   ent, tab_prefixof(ent), c );
X	   else
X	       fprintf( stderr, "%5d: %5d/\\%03o \"",
X			   ent, tab_prefixof(ent), c );
X	   de_stack[--stack_top] = '\n';
X	   de_stack[--stack_top] = '"';
X	   for ( ; ent != NULL;
X		   ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
X	       stack_top = in_stack(tab_suffixof(ent), stack_top);
X	   }
X	   fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
X	   stack_top = STACK_SIZE;
X       }
X    }
X}
X
Xint
Xin_stack(c, stack_top)
X	register c, stack_top;
X{
X	if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
X	    de_stack[--stack_top] = c;
X	} else {
X	    switch( c ) {
X	    case '\n': de_stack[--stack_top] = 'n'; break;
X	    case '\t': de_stack[--stack_top] = 't'; break;
X	    case '\b': de_stack[--stack_top] = 'b'; break;
X	    case '\f': de_stack[--stack_top] = 'f'; break;
X	    case '\r': de_stack[--stack_top] = 'r'; break;
X	    case '\\': de_stack[--stack_top] = '\\'; break;
X	    default:
X	 	de_stack[--stack_top] = '0' + c % 8;
X	 	de_stack[--stack_top] = '0' + (c / 8) % 8;
X	 	de_stack[--stack_top] = '0' + c / 64;
X	 	break;
X	    }
X	    de_stack[--stack_top] = '\\';
X	}
X	return stack_top;
X}
X#endif /* DEBUG */
X
Xwriteerr()
X{
X    perror ( ofname );
X    unlink ( ofname );
X    exit ( 1 );
X}
X
Xcopystat(ifname, ofname)
Xchar *ifname, *ofname;
X{
X    struct stat statbuf;
X    int mode;
X    time_t timep[2];
X
X    fclose(stdout);
X    if (stat(ifname, &statbuf)) {		/* Get stat on input file */
X	perror(ifname);
X	return;
X    }
X    if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) {
X	if(quiet)
X	    	fprintf(stderr, "%s: ", ifname);
X	fprintf(stderr, " -- not a regular file: unchanged");
X	exit_stat = 1;
X    } else if (statbuf.st_nlink > 1 && (! force) ) {
X	if(quiet)
X	    	fprintf(stderr, "%s: ", ifname);
X	fprintf(stderr, " -- has %d other links: unchanged",
X		statbuf.st_nlink - 1);
X	exit_stat = 1;
X    } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
X	if(!quiet)
X		fprintf(stderr, " -- file unchanged");
X    } else {			/* ***** Successful Compression ***** */
X	exit_stat = 0;
X	mode = statbuf.st_mode & 07777;
X	if (chmod(ofname, mode))		/* Copy modes */
X	    perror(ofname);
X	chown(ofname, statbuf.st_uid, statbuf.st_gid);	/* Copy ownership */
X	timep[0] = statbuf.st_atime;
X	timep[1] = statbuf.st_mtime;
X	utime(ofname, timep);	/* Update last accessed and modified times */
X	if (unlink(ifname))	/* Remove input file */
X	    perror(ifname);
X	if(!quiet)
X		fprintf(stderr, " -- replaced with %s", ofname);
X	return;		/* Successful return */
X    }
X
X    /* Unsuccessful return -- one of the tests failed */
X    if (unlink(ofname))
X	perror(ofname);
X}
X/*
X * This routine returns 1 if we are running in the foreground and stderr
X * is a tty.
X */
Xforeground()
X{
X	if(bgnd_flag) {	/* background? */
X		return(0);
X	} else {			/* foreground */
X		if(isatty(2)) {		/* and stderr is a tty */
X			return(1);
X		} else {
X			return(0);
X		}
X	}
X}
X
Xonintr ( )
X{
X    unlink ( ofname );
X    exit ( 1 );
X}
X
Xoops ( )	/* wild pointer -- assume bad input */
X{
X    if ( do_decomp == 1 ) 
X    	fprintf ( stderr, "uncompress: corrupt input\n" );
X    unlink ( ofname );
X    exit ( 1 );
X}
X
Xcl_block ()		/* table clear for block compress */
X{
X    register long int rat;
X
X    checkpoint = in_count + CHECK_GAP;
X#ifdef DEBUG
X	if ( debug ) {
X    		fprintf ( stderr, "count: %ld, ratio: ", in_count );
X     		prratio ( stderr, in_count, bytes_out );
X		fprintf ( stderr, "\n");
X	}
X#endif /* DEBUG */
X
X    if(in_count > 0x007fffff) {	/* shift will overflow */
X	rat = bytes_out >> 8;
X	if(rat == 0) {		/* Don't divide by zero */
X	    rat = 0x7fffffff;
X	} else {
X	    rat = in_count / rat;
X	}
X    } else {
X	rat = (in_count << 8) / bytes_out;	/* 8 fractional bits */
X    }
X    if ( rat > ratio ) {
X	ratio = rat;
X    } else {
X	ratio = 0;
X#ifdef DEBUG
X	if(verbose)
X		dump_tab();	/* dump string table */
X#endif
X 	cl_hash ( (count_int) hsize );
X	free_ent = FIRST;
X	clear_flg = 1;
X	output ( (code_int) CLEAR );
X#ifdef DEBUG
X	if(debug)
X    		fprintf ( stderr, "clear\n" );
X#endif /* DEBUG */
X    }
X}
X
Xcl_hash(hsize)		/* reset code table */
X	register count_int hsize;
X{
X#ifndef XENIX_16	/* Normal machine */
X	register count_int *htab_p = htab+hsize;
X#else
X	register j;
X	register long k = hsize;
X	register count_int *htab_p;
X#endif
X	register long i;
X	register long m1 = -1;
X
X#ifdef XENIX_16
X    for(j=0; j<=8 && k>=0; j++,k-=8192) {
X	i = 8192;
X	if(k < 8192) {
X		i = k;
X	}
X	htab_p = &(htab[j][i]);
X	i -= 16;
X	if(i > 0) {
X#else
X	i = hsize - 16;
X#endif
X 	do {				/* might use Sys V memset(3) here */
X		*(htab_p-16) = m1;
X		*(htab_p-15) = m1;
X		*(htab_p-14) = m1;
X		*(htab_p-13) = m1;
X		*(htab_p-12) = m1;
X		*(htab_p-11) = m1;
X		*(htab_p-10) = m1;
X		*(htab_p-9) = m1;
X		*(htab_p-8) = m1;
X		*(htab_p-7) = m1;
X		*(htab_p-6) = m1;
X		*(htab_p-5) = m1;
X		*(htab_p-4) = m1;
X		*(htab_p-3) = m1;
X		*(htab_p-2) = m1;
X		*(htab_p-1) = m1;
X		htab_p -= 16;
X	} while ((i -= 16) >= 0);
X#ifdef XENIX_16
X	}
X    }
X#endif
X    	for ( i += 16; i > 0; i-- )
X		*--htab_p = m1;
X}
X
Xprratio(stream, num, den)
XFILE *stream;
Xlong int num, den;
X{
X	register int q;			/* Doesn't need to be long */
X
X	if(num > 214748L) {		/* 2147483647/10000 */
X		q = num / (den / 10000L);
X	} else {
X		q = 10000L * num / den;		/* Long calculations, though */
X	}
X	if (q < 0) {
X		putc('-', stream);
X		q = -q;
X	}
X	fprintf(stream, "%d.%02d%%", q / 100, q % 100);
X}
X
Xversion()
X{
X	fprintf(stderr, "%s, patchlevel %d\n", version_id, PATCHLEVEL);
X	fprintf(stderr, "Options: ");
X#ifdef vax
X	fprintf(stderr, "vax, ");
X#endif
X#ifdef SHORTNAMES
X	fprintf(stderr,"SHORTNAMES, ");
X#endif
X#ifdef VOIDSIG
X	fprintf(stderr,"VOIDSIG, ");
X#endif
X#ifdef DIRENT
X	fprintf(stderr,"DIRENT, ");
X#endif
X#ifdef NO_UCHAR
X	fprintf(stderr, "NO_UCHAR, ");
X#endif
X#ifdef SIGNED_COMPARE_SLOW
X	fprintf(stderr, "SIGNED_COMPARE_SLOW, ");
X#endif
X#ifdef XENIX_16
X	fprintf(stderr, "XENIX_16, ");
X#endif
X#ifdef COMPATIBLE
X	fprintf(stderr, "COMPATIBLE, ");
X#endif
X#ifdef DEBUG
X	fprintf(stderr, "DEBUG, ");
X#endif
X#ifdef BSD4
X	fprintf(stderr, "BSD4, ");
X#endif
X	fprintf(stderr, "BITS = %d\n", BITS);
X}
END_OF_FILE
if test 42620 -ne `wc -c <'compress.c'`; then
    echo shar: \"'compress.c'\" unpacked with wrong size!
fi
# end of 'compress.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0


-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.