compress.c

Go to the documentation of this file.
00001 /* compress - Reduce file size using Modified Lempel-Ziv encoding */
00002 
00003 /*
00004  * compress.c - File compression ala IEEE Computer, June 1984.
00005  *
00006  * Authors:     Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
00007  *              Jim McKie               (decvax!mcvax!jim)
00008  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
00009  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
00010  *              James A. Woods          (decvax!ihnp4!ames!jaw)
00011  *              Joe Orost               (decvax!vax135!petsd!joe)
00012  *
00013  *              Richard Todd            Port to MINIX
00014  *              Andy Tanenbaum          Cleanup
00015  *
00016  *
00017  * Algorithm from "A Technique for High Performance Data Compression",
00018  * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
00019  *
00020  * Usage: compress [-dfvc] [-b bits] [file ...]
00021  * Inputs:
00022  *      -d:         If given, decompression is done instead.
00023  *
00024  *      -c:         Write output on stdout.
00025  *
00026  *      -b:         Parameter limits the max number of bits/code.
00027  *
00028  *      -f:         Forces output file to be generated, even if one already
00029  *                  exists, and even if no space is saved by compressing.
00030  *                  If -f is not used, the user will be prompted if stdin is
00031  *                  a tty, otherwise, the output file will not be overwritten.
00032  *
00033  *      -v:         Write compression statistics
00034  *
00035  *      file ...:   Files to be compressed.  If none specified, stdin
00036  *                  is used.
00037  * Outputs:
00038  *      file.Z:     Compressed form of file with same mode, owner, and utimes
00039  *      or stdout   (if stdin used as input)
00040  *
00041  * Assumptions:
00042  *      When filenames are given, replaces with the compressed version
00043  *      (.Z suffix) only if the file decreases in size.
00044  * Algorithm:
00045  *      Modified Lempel-Ziv method (LZW).  Basically finds common
00046  * substrings and replaces them with a variable size code.  This is
00047  * deterministic, and can be done on the fly.  Thus, the decompression
00048  * procedure needs no input table, but tracks the way the table was built.
00049  */
00050 
00051 
00052 #define AZTEC86 1
00053 
00054 #define min(a,b)        ((a>b) ? b : a)
00055 
00056 /*
00057  * Set USERMEM to the maximum amount of physical user memory available
00058  * in bytes.  USERMEM is used to determine the maximum BITS that can be used
00059  * for compression.
00060  *
00061  * SACREDMEM is the amount of physical memory saved for others; compress
00062  * will hog the rest.
00063  */
00064 #ifndef SACREDMEM
00065 #define SACREDMEM       0
00066 #endif
00067 
00068 #ifndef USERMEM
00069 # define USERMEM        450000  /* default user memory */
00070 #endif
00071 
00072 #define REGISTER register
00073 #define DOTZ ".Z"
00074 
00075 #include <limits.h>
00076 #include <dirent.h>
00077 
00078 /* The default for Minix is -b13, but we can do -b16 if the machine can. */
00079 #define DEFAULTBITS 13
00080 #if INT_MAX == 32767
00081 # define BITS 13
00082 #else
00083 # define BITS 16
00084 #endif
00085 
00086 #ifdef USERMEM
00087 # if USERMEM >= (433484+SACREDMEM)
00088 #  define PBITS 16
00089 # else
00090 #  if USERMEM >= (229600+SACREDMEM)
00091 #   define PBITS        15
00092 #  else
00093 #   if USERMEM >= (127536+SACREDMEM)
00094 #    define PBITS       14
00095 #   else
00096 #    if USERMEM >= (73464+SACREDMEM)
00097 #     define PBITS      13
00098 #    else
00099 #     define PBITS      12
00100 #    endif
00101 #   endif
00102 #  endif
00103 # endif
00104 # undef USERMEM
00105 #endif /* USERMEM */
00106 
00107 #ifdef PBITS            /* Preferred BITS for this memory size */
00108 # ifndef BITS
00109 #  define BITS PBITS
00110 # endif
00111 #endif /* PBITS */
00112 
00113 #if BITS == 16
00114 # define HSIZE  69001           /* 95% occupancy */
00115 #endif
00116 #if BITS == 15
00117 # define HSIZE  35023           /* 94% occupancy */
00118 #endif
00119 #if BITS == 14
00120 # define HSIZE  18013           /* 91% occupancy */
00121 #endif
00122 #if BITS == 13
00123 # define HSIZE  9001            /* 91% occupancy */
00124 #endif
00125 #if BITS <= 12
00126 # define HSIZE  5003            /* 80% occupancy */
00127 #endif
00128 
00129 
00130 /*
00131  * a code_int must be able to hold 2**BITS values of type int, and also -1
00132  */
00133 #if BITS > 15
00134 typedef long int        code_int;
00135 #else
00136 typedef int             code_int;
00137 #endif
00138 
00139 #ifdef SIGNED_COMPARE_SLOW
00140 typedef unsigned long int count_int;
00141 typedef unsigned short int count_short;
00142 #else
00143 typedef long int          count_int;
00144 #endif
00145 
00146 #ifdef NO_UCHAR
00147  typedef char   char_type;
00148 #else
00149  typedef        unsigned char   char_type;
00150 #endif /* UCHAR */
00151 char_type magic_header[] = "\037\235";  /* 1F 9D */
00152 
00153 /* Defines for third byte of header */
00154 #define BIT_MASK        0x1f
00155 #define BLOCK_MASK      0x80
00156 /* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
00157    a fourth header byte (for expansion).
00158 */
00159 #define INIT_BITS 9                     /* initial number of bits/code */
00160 
00161 #include <sys/types.h>
00162 #include <sys/stat.h>
00163 #include <fcntl.h>
00164 #include <ctype.h>
00165 #include <signal.h>
00166 #include <stdlib.h>
00167 #include <string.h>
00168 #include <unistd.h>
00169 #include <utime.h>
00170 #include <stdio.h>
00171 
00172 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
00173 
00174 int n_bits;                             /* number of bits/code */
00175 int maxbits = DEFAULTBITS;              /* user settable max # bits/code */
00176 code_int maxcode;                       /* maximum code, given n_bits */
00177 code_int maxmaxcode = 1 << BITS;        /* should NEVER generate this code */
00178 #ifdef COMPATIBLE               /* But wrong! */
00179 # define MAXCODE(n_bits)        (1 << (n_bits) - 1)
00180 #else
00181 # define MAXCODE(n_bits)        ((1 << (n_bits)) - 1)
00182 #endif /* COMPATIBLE */
00183 
00184 #ifndef AZTEC86
00185         count_int htab [HSIZE];
00186         unsigned short codetab [HSIZE];
00187 #else
00188         count_int *htab;
00189         unsigned short *codetab;
00190 #       define HTABSIZE ((size_t)(HSIZE*sizeof(count_int)))
00191 #       define CODETABSIZE ((size_t)(HSIZE*sizeof(unsigned short)))
00192 
00193 
00194 #define htabof(i)       htab[i]
00195 #define codetabof(i)    codetab[i]
00196 #endif  /* XENIX_16 */
00197 code_int hsize = HSIZE;                 /* for dynamic table sizing */
00198 count_int fsize;
00199 
00200 /*
00201  * To save much memory, we overlay the table used by compress() with those
00202  * used by decompress().  The tab_prefix table is the same size and type
00203  * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
00204  * get this from the beginning of htab.  The output stack uses the rest
00205  * of htab, and contains characters.  There is plenty of room for any
00206  * possible stack (stack used to be 8000 characters).
00207  */
00208 
00209 #define tab_prefixof(i) codetabof(i)
00210 #ifdef XENIX_16
00211 # define tab_suffixof(i)        ((char_type *)htab[(i)>>15])[(i) & 0x7fff]
00212 # define de_stack               ((char_type *)(htab2))
00213 #else   /* Normal machine */
00214 # define tab_suffixof(i)        ((char_type *)(htab))[i]
00215 # define de_stack               ((char_type *)&tab_suffixof(1<<BITS))
00216 #endif  /* XENIX_16 */
00217 
00218 code_int free_ent = 0;                  /* first unused entry */
00219 int exit_stat = 0;
00220 
00221 _PROTOTYPE(int main, (int argc, char **argv));
00222 _PROTOTYPE(void Usage, (void));
00223 _PROTOTYPE(void compress, (void));
00224 _PROTOTYPE(void onintr, (int dummy));
00225 _PROTOTYPE(void oops, (int dummy));
00226 _PROTOTYPE(void output, (code_int code));
00227 _PROTOTYPE(int foreground, (void));
00228 _PROTOTYPE(void decompress, (void));
00229 _PROTOTYPE(code_int getcode, (void)); 
00230 _PROTOTYPE(void writeerr, (void));
00231 _PROTOTYPE(void copystat, (char *ifname, char *ofname));
00232 _PROTOTYPE(int foreground, (void));
00233 _PROTOTYPE(void cl_block , (void));
00234 _PROTOTYPE(void cl_hash, (count_int hsize));
00235 _PROTOTYPE(void prratio, (FILE *stream, long int num, long int den));
00236 _PROTOTYPE(void version, (void));
00237 
00238 void Usage() {
00239 #ifdef DEBUG
00240 fprintf(stderr,"Usage: compress [-dDVfc] [-b maxbits] [file ...]\n");
00241 }
00242 int debug = 0;
00243 #else
00244 fprintf(stderr,"Usage: compress [-dfvcV] [-b maxbits] [file ...]\n");
00245 }
00246 #endif /* DEBUG */
00247 int nomagic = 0;        /* Use a 3-byte magic number header, unless old file */
00248 int zcat_flg = 0;       /* Write output on stdout, suppress messages */
00249 int quiet = 0;          /* don't tell me about compression */
00250 
00251 /*
00252  * block compression parameters -- after all codes are used up,
00253  * and compression rate changes, start over.
00254  */
00255 int block_compress = BLOCK_MASK;
00256 int clear_flg = 0;
00257 long int ratio = 0;
00258 #define CHECK_GAP 10000 /* ratio check interval */
00259 count_int checkpoint = CHECK_GAP;
00260 /*
00261  * the next two codes should not be changed lightly, as they must not
00262  * lie within the contiguous general code space.
00263  */ 
00264 #define FIRST   257     /* first free entry */
00265 #define CLEAR   256     /* table clear output code */
00266 
00267 int force = 0;
00268 char ofname [100];
00269 #ifdef DEBUG
00270 int verbose = 0;
00271 #endif /* DEBUG */
00272 
00273 #ifndef METAWARE
00274 #ifdef AZTEC86
00275 void
00276 #else
00277 int
00278 #endif
00279 #ifndef __STDC__
00280 (*bgnd_flag)();
00281 #else
00282 (*bgnd_flag)(int);
00283 #endif
00284 #endif
00285 
00286 int do_decomp = 0;
00287 
00288 
00289 int main(argc, argv)
00290 int argc;
00291 char **argv;
00292 {
00293     int overwrite = 0;  /* Do not overwrite unless given -f flag */
00294     char tempname[100];
00295     char **filelist, **fileptr;
00296     char *cp;
00297     struct stat statbuf;
00298 #ifndef METAWARE
00299     if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
00300         signal ( SIGINT, onintr );
00301         signal ( SIGSEGV, oops );
00302     }
00303 #endif
00304 #ifdef AZTEC86
00305 #ifdef METAWARE
00306         _setmode(NULL,_ALL_FILES_BINARY);
00307         _setmode(stdin,_BINARY);
00308         _setmode(stdout,_BINARY);
00309         _setmode(stderr,_TEXT);
00310 #endif
00311         if (NULL == (htab = (count_int *)malloc(HTABSIZE)))
00312         {
00313                 fprintf(stderr,"Can't allocate htab\n");
00314                 exit(1);
00315         }
00316         if (NULL == (codetab = (unsigned short *)malloc(CODETABSIZE)))
00317         {
00318                 fprintf(stderr,"Can't allocate codetab\n");
00319                 exit(1);
00320         }
00321 #endif
00322 #ifdef COMPATIBLE
00323     nomagic = 1;        /* Original didn't have a magic number */
00324 #endif /* COMPATIBLE */
00325 
00326     filelist = fileptr = (char **)(malloc((size_t)(argc * sizeof(*argv))));
00327     *filelist = NULL;
00328 
00329     if((cp = strrchr(argv[0], '/')) != 0) {
00330         cp++;
00331     } else {
00332         cp = argv[0];
00333     }
00334     if(strcmp(cp, "uncompress") == 0) {
00335         do_decomp = 1;
00336     } else if(strcmp(cp, "zcat") == 0) {
00337         do_decomp = 1;
00338         zcat_flg = 1;
00339     }
00340 
00341 #ifdef BSD4_2
00342     /* 4.2BSD dependent - take it out if not */
00343     setlinebuf( stderr );
00344 #endif /* BSD4_2 */
00345 
00346     /* Argument Processing
00347      * All flags are optional.
00348      * -D => debug
00349      * -V => print Version; debug verbose
00350      * -d => do_decomp
00351      * -v => unquiet
00352      * -f => force overwrite of output file
00353      * -n => no header: useful to uncompress old files
00354      * -b maxbits => maxbits.  If -b is specified, then maxbits MUST be
00355      *      given also.
00356      * -c => cat all output to stdout
00357      * -C => generate output compatible with compress 2.0.
00358      * if a string is left, must be an input filename.
00359      */
00360     for (argc--, argv++; argc > 0; argc--, argv++) 
00361         {
00362                 if (**argv == '-') 
00363                 {       /* A flag argument */
00364                     while (*++(*argv)) 
00365                         {       /* Process all flags in this arg */
00366                                 switch (**argv) 
00367                                 {
00368 #ifdef DEBUG
00369                             case 'D':
00370                                         debug = 1;
00371                                         break;
00372                             case 'V':
00373                                         verbose = 1;
00374                                         version();
00375                                         break;
00376 #else
00377                             case 'V':
00378                                         version();
00379                                         break;
00380 #endif /* DEBUG */
00381                             case 'v':
00382                                         quiet = 0;
00383                                         break;
00384                             case 'd':
00385                                         do_decomp = 1;
00386                                         break;
00387                             case 'f':
00388                             case 'F':
00389                                         overwrite = 1;
00390                                         force = 1;
00391                                         break;
00392                             case 'n':
00393                                         nomagic = 1;
00394                                         break;
00395                             case 'C':
00396                                         block_compress = 0;
00397                                         break;
00398                             case 'b':
00399                                         if (!ARGVAL()) 
00400                                         {
00401                                             fprintf(stderr, "Missing maxbits\n");
00402                                             Usage();
00403                                             exit(1);
00404                                         }
00405                                         maxbits = atoi(*argv);
00406                                         goto nextarg;
00407                             case 'c':
00408                                         zcat_flg = 1;
00409                                         break;
00410                             case 'q':
00411                                         quiet = 1;
00412                                         break;
00413                             default:
00414                                         fprintf(stderr, "Unknown flag: '%c'; ", **argv);
00415                                         Usage();
00416                                         exit(1);
00417                                 }
00418                     }
00419                 }
00420                 else 
00421                 {               /* Input file name */
00422                     *fileptr++ = *argv; /* Build input file list */
00423                     *fileptr = NULL;
00424                     /* process nextarg; */
00425                 }
00426                 nextarg: continue;
00427     }
00428 
00429     if(maxbits < INIT_BITS) maxbits = INIT_BITS;
00430     if (maxbits > BITS) maxbits = BITS;
00431     maxmaxcode = 1 << maxbits;
00432 
00433     if (*filelist != NULL) 
00434         {
00435                 for (fileptr = filelist; *fileptr; fileptr++) 
00436                 {
00437                     exit_stat = 0;
00438                     if (do_decomp != 0) 
00439                         {                       /* DECOMPRESSION */
00440                                 /* Check for .Z suffix */
00441 #ifndef PCDOS
00442                                 if (strcmp(*fileptr + strlen(*fileptr) - 2, DOTZ) != 0) 
00443 #else
00444                                 if (strcmp(*fileptr + strlen(*fileptr) - 1, DOTZ) != 0) 
00445 #endif
00446                                 {
00447                                     /* No .Z: tack one on */
00448                                     strcpy(tempname, *fileptr);
00449 #ifndef PCDOS
00450                                     strcat(tempname, DOTZ);
00451 #else
00452                                         /* either tack one on or replace last character */
00453                                         {
00454                                                 char *dot;
00455                                                 if (NULL == (dot = strchr(tempname,'.')))
00456                                                 {
00457                                                         strcat(tempname,".Z");
00458                                                 }
00459                                                 else
00460                                                 /* if there is a dot then either tack a z on
00461                                                    or replace last character */
00462                                                 {
00463                                                         if (strlen(dot) < 4)
00464                                                                 strcat(tempname,DOTZ);
00465                                                         else
00466                                                                 dot[3] = 'Z';
00467                                                 }
00468                                         }
00469 #endif
00470                                     *fileptr = tempname;
00471                                 }
00472                                 /* Open input file */
00473                                 if ((freopen(*fileptr, "r", stdin)) == NULL) 
00474                                 {
00475                                         perror(*fileptr); continue;
00476                                 }
00477                                 /* Check the magic number */
00478                                 if (nomagic == 0) 
00479                                 {
00480                                         unsigned magic1, magic2;
00481                                     if (((magic1 = getc(stdin)) != (magic_header[0] & 0xFF))
00482                                      || ((magic2 = getc(stdin)) != (magic_header[1] & 0xFF))) 
00483                                         {
00484                                                 fprintf(stderr, 
00485                                                 "%s: not in compressed format %x %x\n",
00486                                             *fileptr,magic1,magic2);
00487                                             continue;
00488                                     }
00489                                     maxbits = getc(stdin);      /* set -b from file */
00490                                     block_compress = maxbits & BLOCK_MASK;
00491                                     maxbits &= BIT_MASK;
00492                                     maxmaxcode = 1 << maxbits;
00493                                     if(maxbits > BITS) 
00494                                         {
00495                                                 fprintf(stderr,
00496                                         "%s: compressed with %d bits, can only handle %d bits\n",
00497                                                 *fileptr, maxbits, BITS);
00498                                                 continue;
00499                                     }
00500                                 }
00501                                 /* Generate output filename */
00502                                 strcpy(ofname, *fileptr);
00503 #ifndef PCDOS
00504                                 ofname[strlen(*fileptr) - 2] = '\0';  /* Strip off .Z */
00505 #else
00506                                 /* kludge to handle various common three character extension */
00507                                 {
00508                                         char *dot; 
00509                                         char fixup = '\0';
00510                                         /* first off, map name to upper case */
00511                                         for (dot = ofname; *dot; dot++)
00512                                                 *dot = toupper(*dot);
00513                                         if (NULL == (dot = strchr(ofname,'.')))
00514                                         {
00515                                                 fprintf(stderr,"Bad filename %s\n",ofname);
00516                                                 exit(1);
00517                                         }
00518                                         if (strlen(dot) == 4)
00519                                         /* we got three letter extensions */
00520                                         {
00521                                                 if (strcmp(dot,".EXZ") == 0)
00522                                                         fixup = 'E';
00523                                                 else if (strcmp(dot,".COZ") == 0)
00524                                                         fixup = 'M';
00525                                                 else if (strcmp(dot,".BAZ") == 0)
00526                                                         fixup = 'S';
00527                                                 else if (strcmp(dot,".OBZ") == 0)
00528                                                         fixup = 'J';
00529                                                 else if (strcmp(dot,".SYZ") == 0)
00530                                                         fixup = 'S';
00531                                                 else if (strcmp(dot,".DOZ") == 0)
00532                                                         fixup = 'C';
00533 
00534                                         } 
00535                                         /* replace the Z */
00536                                         ofname[strlen(*fileptr) - 1] = fixup;
00537                                 }
00538 #endif
00539                     } else 
00540                         {                                       /* COMPRESSION */
00541                                 if (strcmp(*fileptr + strlen(*fileptr) - 2, DOTZ) == 0) 
00542                                 {
00543                                 fprintf(stderr, "%s: already has .Z suffix -- no change\n",
00544                                     *fileptr);
00545                                     continue;
00546                                 }
00547                                 /* Open input file */
00548                                 if ((freopen(*fileptr, "r", stdin)) == NULL) 
00549                                 {
00550                                     perror(*fileptr); continue;
00551                                 }
00552                                 (void)stat( *fileptr, &statbuf );
00553                                 fsize = (long) statbuf.st_size;
00554                                 /*
00555                                  * tune hash table size for small files -- ad hoc,
00556                                  * but the sizes match earlier #defines, which
00557                                  * serve as upper bounds on the number of output codes. 
00558                                  */
00559                                 hsize = HSIZE; /*lint -e506 -e712 */
00560                                 if ( fsize < (1 << 12) )
00561                                     hsize = min ( 5003, HSIZE );
00562                                 else if ( fsize < (1 << 13) )
00563                                     hsize = min ( 9001, HSIZE );
00564                                 else if ( fsize < (1 << 14) )
00565                                     hsize = min ( 18013, HSIZE );
00566                                 else if ( fsize < (1 << 15) )
00567                                     hsize = min ( 35023, HSIZE );
00568                                 else if ( fsize < 47000 )
00569                                     hsize = min ( 50021, HSIZE ); /*lint +e506 +e712 */
00570 
00571                                 /* Generate output filename */
00572                                 strcpy(ofname, *fileptr);
00573 #ifndef BSD4_2          /* Short filenames */
00574                                 if ((cp=strrchr(ofname,'/')) != NULL)
00575                                         cp++;
00576                                 else
00577                                         cp = ofname;
00578                                 if (strlen(cp) >= _DIRENT_NAME_LEN-3) 
00579                                 {
00580                                     fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
00581                                     continue;
00582                                 }
00583 #ifdef PCDOS
00584                                 else
00585                                 {
00586                                         /* either tack one on or replace last character */
00587                                         char *dot;
00588                                         if (NULL == (dot = strchr(cp,'.')))
00589                                         {
00590                                                 strcat(cp,".Z");
00591                                         }
00592                                         else
00593                                         /* if there is a dot then either tack a z on
00594                                            or replace last character */
00595                                         {
00596                                                 if (strlen(dot) < 4)
00597                                                         strcat(cp,DOTZ);
00598                                                 else
00599                                                         dot[3] = 'Z';
00600                                         }
00601                                 }
00602 #endif
00603 #endif  /* BSD4_2               Long filenames allowed */
00604 #ifndef PCDOS
00605                         /* PCDOS takes care of this above */
00606                                 strcat(ofname, DOTZ);
00607 #endif
00608                     }
00609                     /* Check for overwrite of existing file */
00610                     if (overwrite == 0 && zcat_flg == 0) 
00611                         {
00612                                 if (stat(ofname, &statbuf) == 0) 
00613                                 {
00614                                     char response[2]; int fd;
00615                                     response[0] = 'n';
00616                                     fprintf(stderr, "%s already exists;", ofname);
00617                                     if (foreground()) 
00618                                         {
00619                                                 fd = open("/dev/tty", O_RDONLY);
00620                                                 fprintf(stderr, 
00621                                                 " do you wish to overwrite %s (y or n)? ", ofname);
00622                                                 fflush(stderr);
00623                                                 (void)read(fd, response, 2);
00624                                                 while (response[1] != '\n') 
00625                                                 {
00626                                                     if (read(fd, response+1, 1) < 0) 
00627                                                         {       /* Ack! */
00628                                                                 perror("stderr"); 
00629                                                                 break;
00630                                                     }
00631                                                 }
00632                                                 close(fd);
00633                                     }
00634                                     if (response[0] != 'y') 
00635                                         {
00636                                                 fprintf(stderr, "\tnot overwritten\n");
00637                                                 continue;
00638                                     }
00639                                 }
00640                     }
00641                     if(zcat_flg == 0) 
00642                         {               /* Open output file */
00643                                 if (freopen(ofname, "w", stdout) == NULL) 
00644                                 {
00645                                     perror(ofname);
00646                                     continue;
00647                                 }
00648                                 if(!quiet)
00649                                         fprintf(stderr, "%s: ", *fileptr);
00650                     }
00651 
00652                     /* Actually do the compression/decompression */
00653                     if (do_decomp == 0) 
00654                                 compress();
00655 #ifndef DEBUG
00656                     else                        
00657                                 decompress();
00658 #else
00659                     else if (debug == 0)        
00660                                 decompress();
00661                     else                        
00662                                 printcodes();
00663                     if (verbose)                
00664                                 dump_tab();
00665 #endif /* DEBUG */
00666                     if(zcat_flg == 0) 
00667                         {
00668                                 copystat(*fileptr, ofname);     /* Copy stats */
00669                                 if((exit_stat == 1) || (!quiet))
00670                                         putc('\n', stderr);
00671                     }
00672                 }
00673     } else 
00674         {               /* Standard input */
00675                 if (do_decomp == 0) 
00676                 {
00677                         compress();
00678 #ifdef DEBUG
00679                         if(verbose)             dump_tab();
00680 #endif /* DEBUG */
00681                         if(!quiet)
00682                                 putc('\n', stderr);
00683                 } else 
00684                 {
00685                     /* Check the magic number */
00686                     if (nomagic == 0) 
00687                         {
00688                                 if ((getc(stdin)!=(magic_header[0] & 0xFF))
00689                                  || (getc(stdin)!=(magic_header[1] & 0xFF))) 
00690                                 {
00691                                     fprintf(stderr, "stdin: not in compressed format\n");
00692                                     exit(1);
00693                                 }
00694                                 maxbits = getc(stdin);  /* set -b from file */
00695                                 block_compress = maxbits & BLOCK_MASK;
00696                                 maxbits &= BIT_MASK;
00697                                 maxmaxcode = 1 << maxbits;
00698                                 fsize = 100000;         /* assume stdin large for USERMEM */
00699                                 if(maxbits > BITS) 
00700                                 {
00701                                         fprintf(stderr,
00702                                         "stdin: compressed with %d bits, can only handle %d bits\n",
00703                                         maxbits, BITS);
00704                                         exit(1);
00705                                 }
00706                     }
00707 #ifndef DEBUG
00708                     decompress();
00709 #else
00710                     if (debug == 0)     decompress();
00711                     else                printcodes();
00712                     if (verbose)        dump_tab();
00713 #endif /* DEBUG */
00714                 }
00715     }
00716     return(exit_stat);
00717 }
00718 
00719 static int offset;
00720 long int in_count = 1;                  /* length of input */
00721 long int bytes_out;                     /* length of compressed output */
00722 long int out_count = 0;                 /* # of codes output (for debugging) */
00723 
00724 /*
00725  * compress stdin to stdout
00726  *
00727  * Algorithm:  use open addressing double hashing (no chaining) on the 
00728  * prefix code / next character combination.  We do a variant of Knuth's
00729  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
00730  * secondary probe.  Here, the modular division first probe is gives way
00731  * to a faster exclusive-or manipulation.  Also do block compression with
00732  * an adaptive reset, whereby the code table is cleared when the compression
00733  * ratio decreases, but after the table fills.  The variable-length output
00734  * codes are re-sized at this point, and a special CLEAR code is generated
00735  * for the decompressor.  Late addition:  construct the table according to
00736  * file size for noticeable speed improvement on small files.  Please direct
00737  * questions about this implementation to ames!jaw.
00738  */
00739 
00740 void compress() 
00741 {
00742     REGISTER long fcode;
00743     REGISTER code_int i = 0;
00744     REGISTER int c;
00745     REGISTER code_int ent;
00746 #ifdef XENIX_16
00747     REGISTER code_int disp;
00748 #else   /* Normal machine */
00749     REGISTER int disp;
00750 #endif
00751     REGISTER code_int hsize_reg;
00752     REGISTER int hshift;
00753 
00754 #ifndef COMPATIBLE
00755     if (nomagic == 0) 
00756         {
00757                 putc(magic_header[0],stdout); 
00758                 putc(magic_header[1],stdout);
00759                 putc((char)(maxbits | block_compress),stdout);
00760                 if(ferror(stdout))
00761                         writeerr();
00762     }
00763 #endif /* COMPATIBLE */
00764 
00765     offset = 0;
00766     bytes_out = 3;              /* includes 3-byte header mojo */
00767     out_count = 0;
00768     clear_flg = 0;
00769     ratio = 0;
00770     in_count = 1;
00771     checkpoint = CHECK_GAP;
00772     maxcode = MAXCODE(n_bits = INIT_BITS);
00773     free_ent = ((block_compress) ? FIRST : 256 );
00774 
00775     ent = getc(stdin);
00776 
00777     hshift = 0;
00778     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
00779         hshift++;
00780     hshift = 8 - hshift;                /* set hash code range bound */
00781 
00782     hsize_reg = hsize;
00783     cl_hash( (count_int) hsize_reg);            /* clear hash table */
00784 
00785 #ifdef SIGNED_COMPARE_SLOW
00786     while ( (c = getc(stdin)) != (unsigned) EOF )
00787 #else
00788     while ( (c = getc(stdin)) != EOF )
00789 #endif
00790         {
00791                 in_count++;
00792                 fcode = (long) (((long) c << maxbits) + ent);
00793                 i = ((c << hshift) ^ ent);      /* xor hashing */
00794 
00795                 if ( htabof (i) == fcode ) 
00796                 {
00797                     ent = codetabof (i);
00798                     continue;
00799                 } else if ( (long)htabof (i) < 0 )      /* empty slot */
00800                     goto nomatch;
00801                 disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
00802                 if ( i == 0 )
00803                     disp = 1;
00804 probe:
00805                 if ( (i -= disp) < 0 )
00806                     i += hsize_reg;
00807 
00808                 if ( htabof (i) == fcode ) 
00809                 {
00810                     ent = codetabof (i);
00811                     continue;
00812                 }
00813                 if ( (long)htabof (i) > 0 ) 
00814                     goto probe;
00815 nomatch:
00816                 output ( (code_int) ent );
00817                 out_count++;
00818                 ent = c;
00819 #ifdef SIGNED_COMPARE_SLOW
00820                 if ( (unsigned) free_ent < (unsigned) maxmaxcode)
00821 #else
00822                 if ( free_ent < maxmaxcode )
00823 #endif
00824                 {
00825                     codetabof (i) = free_ent++; /* code -> hashtable */
00826                     htabof (i) = fcode;
00827                 }
00828                 else if ( (count_int)in_count >= checkpoint && block_compress )
00829                     cl_block ();
00830     }
00831     /*
00832      * Put out the final code.
00833      */
00834     output( (code_int)ent );
00835     out_count++;
00836     output( (code_int)-1 );
00837 
00838     /*
00839      * Print out stats on stderr
00840      */
00841     if(zcat_flg == 0 && !quiet) 
00842         {
00843 #ifdef DEBUG
00844                 fprintf( stderr,
00845                 "%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
00846                 in_count, out_count, bytes_out );
00847                 prratio( stderr, in_count, bytes_out );
00848                 fprintf( stderr, "\n");
00849                 fprintf( stderr, "\tCompression as in compact: " );
00850                 prratio( stderr, in_count-bytes_out, in_count );
00851                 fprintf( stderr, "\n");
00852                 fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
00853                 free_ent - 1, n_bits );
00854 #else /* !DEBUG */
00855                 fprintf( stderr, "Compression: " );
00856                 prratio( stderr, in_count-bytes_out, in_count );
00857 #endif /* DEBUG */
00858     }
00859     if(bytes_out > in_count)    /* exit(2) if no savings */
00860                 exit_stat = 2;
00861     return;
00862 }
00863 
00864 /*****************************************************************
00865  * TAG( output )
00866  *
00867  * Output the given code.
00868  * Inputs:
00869  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
00870  *              that n_bits =< (long)wordsize - 1.
00871  * Outputs:
00872  *      Outputs code to the file.
00873  * Assumptions:
00874  *      Chars are 8 bits long.
00875  * Algorithm:
00876  *      Maintain a BITS character long buffer (so that 8 codes will
00877  * fit in it exactly).  Use the VAX insv instruction to insert each
00878  * code in turn.  When the buffer fills up empty it and start over.
00879  */
00880 
00881 static char buf[BITS];
00882 
00883 #ifndef vax
00884 char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
00885 char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
00886 #endif /* vax */
00887 void output( code )
00888 code_int  code;
00889 {
00890 #ifdef DEBUG
00891     static int col = 0;
00892 #endif /* DEBUG */
00893 
00894     /*
00895      * On the VAX, it is important to have the REGISTER declarations
00896      * in exactly the order given, or the asm will break.
00897      */
00898     REGISTER int r_off = offset, bits= n_bits;
00899     REGISTER char * bp = buf;
00900 #ifndef BREAKHIGHC
00901 #ifdef METAWARE
00902         int temp;
00903 #endif
00904 #endif
00905 #ifdef DEBUG
00906         if ( verbose )
00907             fprintf( stderr, "%5d%c", code,
00908                     (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
00909 #endif /* DEBUG */
00910     if ( code >= 0 ) 
00911         {
00912 #ifdef vax
00913         /* VAX DEPENDENT!! Implementation on other machines is below.
00914          *
00915          * Translation: Insert BITS bits from the argument starting at
00916          * offset bits from the beginning of buf.
00917          */
00918         0;      /* Work around for pcc -O bug with asm and if stmt */
00919         asm( "insv      4(ap),r11,r10,(r9)" );
00920 #else /* not a vax */
00921 /* 
00922  * byte/bit numbering on the VAX is simulated by the following code
00923  */
00924         /*
00925          * Get to the first byte.
00926          */
00927         bp += (r_off >> 3);
00928         r_off &= 7;
00929         /*
00930          * Since code is always >= 8 bits, only need to mask the first
00931          * hunk on the left.
00932          */
00933 #ifndef BREAKHIGHC
00934 #ifdef METAWARE
00935         *bp &= rmask[r_off];
00936         temp = (code << r_off) & lmask[r_off];
00937         *bp |= temp;
00938 #else
00939         *bp = (*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]);
00940 #endif
00941 #else
00942         *bp = (*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]);
00943 #endif
00944         bp++;
00945         bits -= (8 - r_off);
00946         code >>= (8 - r_off);
00947         /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
00948         if ( bits >= 8 ) 
00949         {
00950             *bp++ = code;
00951             code >>= 8;
00952             bits -= 8;
00953         }
00954         /* Last bits. */
00955         if(bits)
00956             *bp = code;
00957 #endif /* vax */
00958         offset += n_bits;
00959         if ( offset == (n_bits << 3) ) 
00960         {
00961             bp = buf;
00962             bits = n_bits;
00963             bytes_out += bits;
00964             do
00965                 putc(*bp++,stdout);
00966             while(--bits);
00967             offset = 0;
00968         }
00969 
00970         /*
00971          * If the next entry is going to be too big for the code size,
00972          * then increase it, if possible.
00973          */
00974         if ( free_ent > maxcode || (clear_flg > 0))
00975         {
00976             /*
00977              * Write the whole buffer, because the input side won't
00978              * discover the size increase until after it has read it.
00979              */
00980             if ( offset > 0 ) 
00981                 {
00982                         if( fwrite( buf, (size_t)1, (size_t)n_bits, stdout ) != n_bits)
00983                                 writeerr();
00984                         bytes_out += n_bits;
00985             }
00986             offset = 0;
00987 
00988             if ( clear_flg ) 
00989                 {
00990                 maxcode = MAXCODE (n_bits = INIT_BITS);
00991                         clear_flg = 0;
00992             }
00993             else 
00994                 {
00995                 n_bits++;
00996                 if ( n_bits == maxbits )
00997                             maxcode = maxmaxcode;
00998                 else
00999                             maxcode = MAXCODE(n_bits);
01000             }
01001 #ifdef DEBUG
01002             if ( debug ) 
01003                 {
01004                         fprintf( stderr, "\nChange to %d bits\n", n_bits );
01005                         col = 0;
01006             }
01007 #endif /* DEBUG */
01008         }
01009     } else 
01010         {
01011         /*
01012          * At EOF, write the rest of the buffer.
01013          */
01014         if ( offset > 0 )
01015             fwrite( buf, (size_t)1, (size_t)(offset + 7) / 8, stdout );
01016         bytes_out += (offset + 7) / 8;
01017         offset = 0;
01018         fflush( stdout );
01019 #ifdef DEBUG
01020         if ( verbose )
01021             fprintf( stderr, "\n" );
01022 #endif /* DEBUG */
01023         if( ferror( stdout ) )
01024                 writeerr();
01025     }
01026 }
01027 /*
01028  * Decompress stdin to stdout.  This routine adapts to the codes in the
01029  * file building the "string" table on-the-fly; requiring no table to
01030  * be stored in the compressed file.  The tables used herein are shared
01031  * with those of the compress() routine.  See the definitions above.
01032  */
01033 
01034 void decompress() {
01035     REGISTER char_type *stackp;
01036     REGISTER int finchar;
01037     REGISTER code_int code, oldcode, incode;
01038 
01039     /*
01040      * As above, initialize the first 256 entries in the table.
01041      */
01042     maxcode = MAXCODE(n_bits = INIT_BITS);
01043     for ( code = 255; code >= 0; code-- ) {
01044         tab_prefixof(code) = 0;
01045         tab_suffixof(code) = (char_type)code;
01046     }
01047     free_ent = ((block_compress) ? FIRST : 256 );
01048 
01049     finchar = oldcode = getcode();
01050     if(oldcode == -1)   /* EOF already? */
01051         return;                 /* Get out of here */
01052     putc( (char)finchar,stdout );               /* first code must be 8 bits = char */
01053     if(ferror(stdout))          /* Crash if can't write */
01054         writeerr();
01055     stackp = de_stack;
01056 
01057     while ( (code = getcode()) > -1 ) {
01058 
01059         if ( (code == CLEAR) && block_compress ) {
01060             for ( code = 255; code >= 0; code-- )
01061                 tab_prefixof(code) = 0;
01062             clear_flg = 1;
01063             free_ent = FIRST - 1;
01064             if ( (code = getcode ()) == -1 )    /* O, untimely death! */
01065                 break;
01066         }
01067         incode = code;
01068         /*
01069          * Special case for KwKwK string.
01070          */
01071         if ( code >= free_ent ) {
01072             *stackp++ = finchar;
01073             code = oldcode;
01074         }
01075 
01076         /*
01077          * Generate output characters in reverse order
01078          */
01079 #ifdef SIGNED_COMPARE_SLOW
01080         while ( ((unsigned long)code) >= ((unsigned long)256) ) {
01081 #else
01082         while ( code >= 256 ) {
01083 #endif
01084             *stackp++ = tab_suffixof(code);
01085             code = tab_prefixof(code);
01086         }
01087         *stackp++ = finchar = tab_suffixof(code);
01088 
01089         /*
01090          * And put them out in forward order
01091          */
01092         do
01093             putc ( *--stackp ,stdout);
01094         while ( stackp > de_stack );
01095 
01096         /*
01097          * Generate the new entry.
01098          */
01099         if ( (code=free_ent) < maxmaxcode ) 
01100         {
01101             tab_prefixof(code) = (unsigned short)oldcode;
01102             tab_suffixof(code) = finchar;
01103             free_ent = code+1;
01104         } 
01105         /*
01106          * Remember previous code.
01107          */
01108         oldcode = incode;
01109     }
01110     fflush( stdout );
01111     if(ferror(stdout))
01112         writeerr();
01113 }
01114 
01115 /*****************************************************************
01116  * TAG( getcode )
01117  *
01118  * Read one code from the standard input.  If EOF, return -1.
01119  * Inputs:
01120  *      stdin
01121  * Outputs:
01122  *      code or -1 is returned.
01123  */
01124 
01125 code_int
01126 getcode() 
01127 {
01128     /*
01129      * On the VAX, it is important to have the REGISTER declarations
01130      * in exactly the order given, or the asm will break.
01131      */
01132     REGISTER code_int code;
01133     static int offset = 0, size = 0;
01134     static char_type buf[BITS];
01135     REGISTER int r_off, bits;
01136     REGISTER char_type *bp = buf;
01137 
01138     if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) 
01139         {
01140                 /*
01141                  * If the next entry will be too big for the current code
01142                  * size, then we must increase the size.  This implies reading
01143                  * a new buffer full, too.
01144                  */
01145                 if ( free_ent > maxcode ) 
01146                 {
01147                     n_bits++;
01148                     if ( n_bits == maxbits )
01149                                 maxcode = maxmaxcode;   /* won't get any bigger now */
01150                     else
01151                                 maxcode = MAXCODE(n_bits);
01152                 }
01153                 if ( clear_flg > 0) 
01154                 {
01155             maxcode = MAXCODE (n_bits = INIT_BITS);
01156                     clear_flg = 0;
01157                 }
01158                 size = fread( buf, (size_t)1, (size_t)n_bits, stdin );
01159                 if ( size <= 0 )
01160                     return -1;                  /* end of file */
01161                 offset = 0;
01162                 /* Round size down to integral number of codes */
01163                 size = (size << 3) - (n_bits - 1);
01164     }
01165     r_off = offset;
01166     bits = n_bits;
01167 #ifdef vax
01168     asm( "extzv   r10,r9,(r8),r11" );
01169 #else /* not a vax */
01170         /*
01171          * Get to the first byte.
01172          */
01173         bp += (r_off >> 3);
01174         r_off &= 7;
01175         /* Get first part (low order bits) */
01176 #ifdef NO_UCHAR
01177         code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
01178 #else
01179         code = (*bp++ >> r_off);
01180 #endif /* NO_UCHAR */
01181         bits -= (8 - r_off);
01182         r_off = 8 - r_off;              /* now, offset into code word */
01183         /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
01184         if ( bits >= 8 ) 
01185         {
01186 #ifdef NO_UCHAR
01187             code |= (*bp++ & 0xff) << r_off;
01188 #else
01189             code |= *bp++ << r_off;
01190 #endif /* NO_UCHAR */
01191             r_off += 8;
01192             bits -= 8;
01193         }
01194         /* high order bits. */
01195         code |= (*bp & rmask[bits]) << r_off;
01196 #endif /* vax */
01197     offset += n_bits;
01198 
01199     return code;
01200 }
01201 
01202 #ifndef AZTEC86
01203 char *
01204 strrchr(s, c)           /* For those who don't have it in libc.a */
01205 REGISTER char *s, c;
01206 {
01207         char *p;
01208         for (p = NULL; *s; s++)
01209             if (*s == c)
01210                 p = s;
01211         return(p);
01212 }
01213 #endif
01214 
01215 
01216 #ifndef METAWARE
01217 #ifdef DEBUG
01218 printcodes()
01219 {
01220     /*
01221      * Just print out codes from input file.  For debugging.
01222      */
01223     code_int code;
01224     int col = 0, bits;
01225 
01226     bits = n_bits = INIT_BITS;
01227     maxcode = MAXCODE(n_bits);
01228     free_ent = ((block_compress) ? FIRST : 256 );
01229     while ( ( code = getcode() ) >= 0 ) {
01230         if ( (code == CLEAR) && block_compress ) {
01231             free_ent = FIRST - 1;
01232             clear_flg = 1;
01233         }
01234         else if ( free_ent < maxmaxcode )
01235             free_ent++;
01236         if ( bits != n_bits ) {
01237             fprintf(stderr, "\nChange to %d bits\n", n_bits );
01238             bits = n_bits;
01239             col = 0;
01240         }
01241         fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
01242     }
01243     putc( '\n', stderr );
01244     exit( 0 );
01245 }
01246 #ifdef DEBUG2
01247 code_int sorttab[1<<BITS];      /* sorted pointers into htab */
01248 #define STACK_SIZE      500
01249 static char stack[STACK_SIZE];
01250 /* dumptab doesn't use main stack now -prevents distressing crashes */
01251 dump_tab()      /* dump string table */
01252 {
01253     REGISTER int i, first;
01254     REGISTER ent;
01255     int stack_top = STACK_SIZE;
01256     REGISTER c;
01257 
01258     if(do_decomp == 0) {        /* compressing */
01259         REGISTER int flag = 1;
01260 
01261         for(i=0; i<hsize; i++) {        /* build sort pointers */
01262                 if((long)htabof(i) >= 0) {
01263                         sorttab[codetabof(i)] = i;
01264                 }
01265         }
01266         first = block_compress ? FIRST : 256;
01267         for(i = first; i < free_ent; i++) {
01268                 fprintf(stderr, "%5d: \"", i);
01269                 stack[--stack_top] = '\n';
01270                 stack[--stack_top] = '"'; /* " */
01271                 stack_top = in_stack((int)(htabof(sorttab[i])>>maxbits)&0xff, 
01272                                      stack_top);
01273                 for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
01274                     ent > 256;
01275                     ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
01276                         stack_top = in_stack((int)(htabof(sorttab[ent]) >> maxbits),
01277                                                 stack_top);
01278                 }
01279                 stack_top = in_stack(ent, stack_top);
01280                 fwrite( &stack[stack_top], (size_t)1, (size_t)(STACK_SIZE-stack_top), stderr);
01281                 stack_top = STACK_SIZE;
01282         }
01283    } else if(!debug) {  /* decompressing */
01284 
01285        for ( i = 0; i < free_ent; i++ ) {
01286            ent = i;
01287            c = tab_suffixof(ent);
01288            if ( isascii(c) && isprint(c) )
01289                fprintf( stderr, "%5d: %5d/'%c'  \"",
01290                            ent, tab_prefixof(ent), c );
01291            else
01292                fprintf( stderr, "%5d: %5d/\\%03o \"",
01293                            ent, tab_prefixof(ent), c );
01294            stack[--stack_top] = '\n';
01295            stack[--stack_top] = '"'; /* " */
01296            for ( ; ent != NULL;
01297                    ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
01298                stack_top = in_stack(tab_suffixof(ent), stack_top);
01299            }
01300            fwrite( &stack[stack_top], (size_t)1, (size_t)(STACK_SIZE - stack_top), stderr );
01301            stack_top = STACK_SIZE;
01302        }
01303     }
01304 }
01305 
01306 int
01307 in_stack(c, stack_top)
01308         REGISTER int c, stack_top;
01309 {
01310         if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
01311             stack[--stack_top] = c;
01312         } else {
01313             switch( c ) {
01314             case '\n': stack[--stack_top] = 'n'; break;
01315             case '\t': stack[--stack_top] = 't'; break;
01316             case '\b': stack[--stack_top] = 'b'; break;
01317             case '\f': stack[--stack_top] = 'f'; break;
01318             case '\r': stack[--stack_top] = 'r'; break;
01319             case '\\': stack[--stack_top] = '\\'; break;
01320             default:
01321                 stack[--stack_top] = '0' + c % 8;
01322                 stack[--stack_top] = '0' + (c / 8) % 8;
01323                 stack[--stack_top] = '0' + c / 64;
01324                 break;
01325             }
01326             stack[--stack_top] = '\\';
01327         }
01328         if (stack_top<0) {
01329             fprintf(stderr,"dump_tab stack overflow!!!\n");
01330             exit(1);
01331         }
01332         return stack_top;
01333 }
01334 #else
01335 dump_tab() {}
01336 #endif /* DEBUG2 */
01337 #endif /* DEBUG */
01338 #endif /* METAWARE */
01339 
01340 void writeerr()
01341 {
01342     perror ( ofname );
01343     unlink ( ofname );
01344     exit ( 1 );
01345 }
01346 
01347 void copystat(ifname, ofname)
01348 char *ifname, *ofname;
01349 {
01350     struct stat statbuf;
01351     int mode;
01352 #ifndef AZTEC86
01353     time_t timep[2];
01354 #else
01355         unsigned long timep[2];
01356 #endif
01357     fflush(stdout);
01358     close(fileno(stdout));
01359     if (stat(ifname, &statbuf)) 
01360         {               /* Get stat on input file */
01361                 perror(ifname);
01362                 return;
01363     }
01364 #ifndef PCDOS
01365     /* meddling with UNIX-style file modes */
01366     if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) 
01367         {
01368                 if(quiet)
01369                 fprintf(stderr, "%s: ", ifname);
01370                 fprintf(stderr, " -- not a regular file: unchanged");
01371                 exit_stat = 1;
01372     } else if (statbuf.st_nlink > 1) 
01373         {
01374                 if(quiet)
01375                 fprintf(stderr, "%s: ", ifname);
01376                 fprintf(stderr, " -- has %d other links: unchanged",
01377                 statbuf.st_nlink - 1);
01378                 exit_stat = 1;
01379     } else 
01380 #endif
01381         if (exit_stat == 2 && (!force)) 
01382         { /* No compression: remove file.Z */
01383                 if(!quiet)
01384                         fprintf(stderr, " -- file unchanged");
01385     } else 
01386         {                       /* ***** Successful Compression ***** */
01387                 exit_stat = 0;
01388 #ifndef PCDOS
01389                 mode = statbuf.st_mode & 07777;
01390 #else
01391                 mode = statbuf.st_attr & 07777;
01392 #endif
01393                 if (chmod(ofname, mode))                /* Copy modes */
01394                     perror(ofname);
01395 #ifndef PCDOS
01396                 chown(ofname, statbuf.st_uid, statbuf.st_gid);  /* Copy ownership */
01397                 timep[0] = statbuf.st_atime;
01398                 timep[1] = statbuf.st_mtime;
01399 #else
01400                 timep[0] = statbuf.st_mtime;
01401                 timep[1] = statbuf.st_mtime;
01402 #endif
01403                 utime(ofname, (struct utimbuf *)timep); /* Update last accessed and modified times */
01404 /*
01405                 if (unlink(ifname))
01406                     perror(ifname);
01407 */
01408                 if(!quiet)
01409                     if(do_decomp == 0)
01410                         fprintf(stderr, " -- compressed to %s", ofname);
01411                     else
01412                         fprintf(stderr, " -- decompressed to %s", ofname);
01413                 return;         /* Successful return */
01414     }
01415 
01416     /* Unsuccessful return -- one of the tests failed */
01417     if (unlink(ofname))
01418                 perror(ofname);
01419 }
01420 /*
01421  * This routine returns 1 if we are running in the foreground and stderr
01422  * is a tty.
01423  */
01424 int foreground()
01425 {
01426 #ifndef METAWARE
01427         if(bgnd_flag) { /* background? */
01428                 return(0);
01429         } else {                        /* foreground */
01430 #endif
01431                 if(isatty(2)) {         /* and stderr is a tty */
01432                         return(1);
01433                 } else {
01434                         return(0);
01435                 }
01436 #ifndef METAWARE
01437         }
01438 #endif
01439 }
01440 #ifndef METAWARE
01441 void onintr (dummy)
01442 int dummy; /* to keep the compiler happy */
01443 {
01444         (void)signal(SIGINT,SIG_IGN);
01445     unlink ( ofname );
01446     exit ( 1 );
01447 }
01448 
01449 void oops (dummy)       /* wild pointer -- assume bad input */
01450 int dummy; /* to keep the compiler happy */
01451 {
01452         (void)signal(SIGSEGV,SIG_IGN);
01453     if ( do_decomp == 1 ) 
01454         fprintf ( stderr, "uncompress: corrupt input\n" );
01455     unlink ( ofname );
01456     exit ( 1 );
01457 }
01458 #endif
01459 void cl_block ()                /* table clear for block compress */
01460 {
01461     REGISTER long int rat;
01462 
01463     checkpoint = in_count + CHECK_GAP;
01464 #ifdef DEBUG
01465         if ( debug ) {
01466                 fprintf ( stderr, "count: %ld, ratio: ", in_count );
01467                 prratio ( stderr, in_count, bytes_out );
01468                 fprintf ( stderr, "\n");
01469         }
01470 #endif /* DEBUG */
01471 
01472     if(in_count > 0x007fffff) { /* shift will overflow */
01473         rat = bytes_out >> 8;
01474         if(rat == 0) {          /* Don't divide by zero */
01475             rat = 0x7fffffff;
01476         } else {
01477             rat = in_count / rat;
01478         }
01479     } else {
01480         rat = (in_count << 8) / bytes_out;      /* 8 fractional bits */
01481     }
01482     if ( rat > ratio ) {
01483         ratio = rat;
01484     } else {
01485         ratio = 0;
01486 #ifdef DEBUG
01487         if(verbose)
01488                 dump_tab();     /* dump string table */
01489 #endif
01490         cl_hash ( (count_int) hsize );
01491         free_ent = FIRST;
01492         clear_flg = 1;
01493         output ( (code_int) CLEAR );
01494 #ifdef DEBUG
01495         if(debug)
01496                 fprintf ( stderr, "clear\n" );
01497 #endif /* DEBUG */
01498     }
01499 }
01500 
01501 void cl_hash(hsize)             /* reset code table */
01502         REGISTER count_int hsize;
01503 {
01504 #ifdef AZTEC86
01505 #ifdef PCDOS
01506         /* This function only in PC-DOS lib, not in MINIX lib */
01507         memset(htab,-1, hsize * sizeof(count_int));
01508 #else
01509 /* MINIX and all non-PC machines do it this way */      
01510 #ifndef XENIX_16        /* Normal machine */
01511         REGISTER count_int *htab_p = htab+hsize;
01512 #else
01513         REGISTER j;
01514         REGISTER long k = hsize;
01515         REGISTER count_int *htab_p;
01516 #endif
01517         REGISTER long i;
01518         REGISTER long m1 = -1;
01519 
01520 #ifdef XENIX_16
01521     for(j=0; j<=8 && k>=0; j++,k-=8192) 
01522         {
01523                 i = 8192;
01524                 if(k < 8192) 
01525                 {
01526                         i = k;
01527                 }
01528                 htab_p = &(htab[j][i]);
01529                 i -= 16;
01530                 if(i > 0) 
01531                 {
01532 #else
01533         i = hsize - 16;
01534 #endif
01535                 do 
01536                 {                               /* might use Sys V memset(3) here */
01537                         *(htab_p-16) = m1;
01538                         *(htab_p-15) = m1;
01539                         *(htab_p-14) = m1;
01540                         *(htab_p-13) = m1;
01541                         *(htab_p-12) = m1;
01542                         *(htab_p-11) = m1;
01543                         *(htab_p-10) = m1;
01544                         *(htab_p-9) = m1;
01545                         *(htab_p-8) = m1;
01546                         *(htab_p-7) = m1;
01547                         *(htab_p-6) = m1;
01548                         *(htab_p-5) = m1;
01549                         *(htab_p-4) = m1;
01550                         *(htab_p-3) = m1;
01551                         *(htab_p-2) = m1;
01552                         *(htab_p-1) = m1;
01553                         htab_p -= 16;
01554                 } while ((i -= 16) >= 0);
01555 #ifdef XENIX_16
01556                 }
01557     }
01558 #endif
01559         for ( i += 16; i > 0; i-- )
01560                 *--htab_p = m1;
01561 #endif
01562 #endif
01563 }
01564 
01565 void prratio(stream, num, den)
01566 FILE *stream;
01567 long int num;
01568 long int den;
01569 {
01570         REGISTER int q;                 /* Doesn't need to be long */
01571         if(num > 214748L) 
01572         {               /* 2147483647/10000 */
01573                 q = (int)(num / (den / 10000L));
01574         } else 
01575         {
01576                 q = (int)(10000L * num / den);          /* Long calculations, though */
01577         }
01578         if (q < 0) 
01579         {
01580                 putc('-', stream);
01581                 q = -q;
01582         }
01583         fprintf(stream, "%d.%02d%c", q / 100, q % 100, '%');
01584 }
01585 
01586 void version()
01587 {
01588         fprintf(stderr, "compress 4.1\n");
01589         fprintf(stderr, "Options: ");
01590 #ifdef vax
01591         fprintf(stderr, "vax, ");
01592 #endif
01593 #ifdef _MINIX
01594         fprintf(stderr, "MINIX, ");
01595 #endif
01596 #ifdef NO_UCHAR
01597         fprintf(stderr, "NO_UCHAR, ");
01598 #endif
01599 #ifdef SIGNED_COMPARE_SLOW
01600         fprintf(stderr, "SIGNED_COMPARE_SLOW, ");
01601 #endif
01602 #ifdef XENIX_16
01603         fprintf(stderr, "XENIX_16, ");
01604 #endif
01605 #ifdef COMPATIBLE
01606         fprintf(stderr, "COMPATIBLE, ");
01607 #endif
01608 #ifdef DEBUG
01609         fprintf(stderr, "DEBUG, ");
01610 #endif
01611 #ifdef BSD4_2
01612         fprintf(stderr, "BSD4_2, ");
01613 #endif
01614         fprintf(stderr, "BITS = %d\n", BITS);
01615 }
01616 /* End of text from uok.UUCP:net.sources */
01617 

Generated on Fri Apr 14 22:56:46 2006 for minix by  doxygen 1.4.6