home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff281.lzh / MRMan / zcat.c < prev   
C/C++ Source or Header  |  1989-11-20  |  36KB  |  1,203 lines

  1. static char     sccsid[] = "@(#)compress.c  @(#)compress.c  5.9 (Berkeley) 5/11/86";
  2.  
  3. /*
  4.  * Compress - data compression program Modified by Mark Rinfret for
  5.  * conditional compilation as "zcat".
  6.  */
  7. #define min(a,b)        ((a>b) ? b : a)
  8.  
  9. #ifndef BITS
  10. # define BITS 16                /* default is 16 bits */
  11. #endif
  12.  
  13. #if BITS == 16
  14. # define HSIZE    69001               /* 95% occupancy */
  15. #endif
  16. #if BITS == 15
  17. # define HSIZE    35023               /* 94% occupancy */
  18. #endif
  19. #if BITS == 14
  20. # define HSIZE    18013               /* 91% occupancy */
  21. #endif
  22. #if BITS == 13
  23. # define HSIZE    9001                /* 91% occupancy */
  24. #endif
  25. #if BITS <= 12
  26. # define HSIZE    5003                /* 80% occupancy */
  27. #endif
  28.  
  29. /*
  30.  * a code_int must be able to hold 2**BITS values of type int, and also -1
  31.  */
  32. typedef long int code_int;
  33. typedef long int count_int;
  34.  
  35. typedef unsigned char char_type;
  36. char_type       magic_header[] = {"\037\235"};  /* 1F 9D */
  37.  
  38. /* Defines for third byte of header */
  39. #define BIT_MASK    0x1f
  40. #define BLOCK_MASK    0x80
  41. /*
  42.  * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is a
  43.  * fourth header byte (for expansion).
  44.  */
  45. #define INIT_BITS 9             /* initial number of bits/code */
  46.  
  47. static char     rcs_ident[] = "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
  48.  
  49. #include <stdio.h>
  50. #include <ctype.h>
  51. #include <stat.h>
  52. #include <time.h>
  53.  
  54. #include <exec/types.h>
  55. #include <exec/memory.h>
  56. #include <exec/ports.h>
  57. #include <exec/io.h>
  58. #include <libraries/dos.h>
  59. #include <libraries/dosextens.h>
  60. #include <functions.h>
  61.  
  62.  
  63. #define ARGVAL() (*++(*argv) || (--argc && *++argv))
  64.  
  65. int             n_bits;         /* number of bits/code */
  66. int             maxbits = BITS; /* user settable max # bits/code */
  67. code_int        maxcode;        /* maximum code, given n_bits */
  68. code_int        maxmaxcode = 1 << BITS; /* should NEVER generate this code */
  69. #define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
  70.  
  71. /* extern int errno; */
  72.  
  73. count_int      *htab;
  74. unsigned short *codetab;
  75.  
  76. #define htabof(i)       htab[i]
  77. #define codetabof(i)    codetab[i]
  78.  
  79. code_int        hsize = HSIZE;  /* for dynamic table sizing */
  80. count_int       fsize;
  81.  
  82. /*
  83.  * To save much memory, we overlay the table used by compress() with those
  84.  * used by decompress().  The tab_prefix table is the same size and type as
  85.  * the codetab.  The tab_suffix table needs 2**BITS characters.  We get this
  86.  * from the beginning of htab.  The output stack uses the rest of htab, and
  87.  * contains characters.  There is plenty of room for any possible stack
  88.  * (stack used to be 8000 characters).
  89.  */
  90.  
  91. #define tab_prefixof(i) codetabof(i)
  92. #define tab_suffixof(i)        ((char_type *)(htab))[i]
  93. #define de_stack           ((char_type *)&tab_suffixof(1<<BITS))
  94.  
  95. code_int        free_ent = 0;   /* first unused entry */
  96. int             exit_stat = 0;  /* per-file status */
  97. int             perm_stat = 0;  /* permanent status */
  98.  
  99. code_int        getcode();
  100.  
  101. Usage()
  102. {
  103.     fprintf(stderr, "Usage: compress [-fvcd] [-b maxbits] [file ...]\n");
  104. }
  105. int             nomagic = 0;    /* Use a 3-byte magic number header, unless
  106.                                  * old file */
  107. #ifdef ZCAT
  108. int             zcat_flg = 1;   /* Write output on stdout, supress messages */
  109. #else
  110. int             zcat_flg = 0;   /* Write output on stdout, suppress messages */
  111. #endif
  112. int             precious = 1;   /* Don't unlink output file on interrupt */
  113. int             quiet = 1;      /* don't tell me about compression */
  114.  
  115. /*
  116.  * block compression parameters -- after all codes are used up, and
  117.  * compression rate changes, start over.
  118.  */
  119. int             block_compress = BLOCK_MASK;
  120. int             clear_flg = 0;
  121. long int        ratio = 0;
  122. #define CHECK_GAP 10000         /* ratio check interval */
  123. count_int       checkpoint = CHECK_GAP;
  124. /*
  125.  * the next two codes should not be changed lightly, as they must not lie
  126.  * within the contiguous general code space.
  127.  */
  128. #define FIRST    257                 /* first free entry */
  129. #define CLEAR    256                 /* table clear output code */
  130.  
  131. int             force = 0;
  132. char            ofname[100];
  133. int             (*oldint) ();
  134.  
  135. #ifdef ZCAT
  136. int             do_decomp = 1;
  137. #else
  138. int             do_decomp = 0;
  139. #endif
  140.  
  141. /*****************************************************************
  142.  * TAG( main )
  143.  *
  144.  * Algorithm from "A Technique for High Performance Data Compression",
  145.  * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
  146.  *
  147.  * Usage: compress [-dfvc] [-b bits] [file ...]
  148.  * Inputs:
  149.  *    -d:        If given, decompression is done instead.
  150.  *
  151.  *    -c:        Write output on stdout, don't remove original.
  152.  *
  153.  *    -b:        Parameter limits the max number of bits/code.
  154.  *
  155.  *    -f:        Forces output file to be generated, even if one already
  156.  *            exists, and even if no space is saved by compressing.
  157.  *            If -f is not used, the user will be prompted if stdin is
  158.  *            a tty, otherwise, the output file will not be overwritten.
  159.  *
  160.  *    -v:        Write compression statistics
  161.  *
  162.  *    file ...:   Files to be compressed.  If none specified, stdin
  163.  *            is used.
  164.  * Outputs:
  165.  *    file.Z:     Compressed form of file with same mode, owner, and utimes
  166.  *    or stdout   (if stdin used as input)
  167.  *
  168.  * Assumptions:
  169.  *    When filenames are given, replaces with the compressed version
  170.  *    (.Z suffix) only if the file decreases in size.
  171.  * Algorithm:
  172.  *    Modified Lempel-Ziv method (LZW).  Basically finds common
  173.  * substrings and replaces them with a variable size code.  This is
  174.  * deterministic, and can be done on the fly.  Thus, the decompression
  175.  * procedure needs no input table, but tracks the way the table was built.
  176.  */
  177.  
  178. main(argc, argv)
  179.     register int    argc;
  180.     char          **argv;
  181. {
  182.     int             overwrite = 0;      /* Do not overwrite unless given -f
  183.                                          * flag */
  184.     char            tempname[100];
  185.     char          **filelist, **fileptr;
  186.     char           *cp, *rindex(), *strcpy(), *malloc();
  187.     struct stat     statbuf;
  188.     extern          onintr(), oops();
  189.  
  190.     freopen("*", "r+", stderr);
  191.  
  192.     htab = (count_int *) malloc(HSIZE * sizeof(count_int));
  193.     codetab = (unsigned short *) malloc(HSIZE * sizeof(unsigned short));
  194.     if (htab == NULL || codetab == NULL) {
  195.         perror("compress");
  196.         exit(1);
  197.     }
  198.     filelist = fileptr = (char **) (malloc(argc * sizeof(*argv)));
  199.     *filelist = NULL;
  200.  
  201.     if ((cp = rindex(argv[0], '/')) != 0) {
  202.         cp++;
  203.     } else {
  204.         cp = argv[0];
  205.     }
  206.  
  207. #ifndef ZCAT
  208.     if (strcmp(cp, "uncompress") == 0) {
  209.         do_decomp = 1;
  210.     } else if (strcmp(cp, "zcat") == 0) {
  211.         do_decomp = 1;
  212.         zcat_flg = 1;
  213.     }
  214. #endif
  215.  
  216.     /*
  217.      * Argument Processing All flags are optional. -D => debug -V => print
  218.      * Version; debug verbose -d => do_decomp -v => unquiet -f => force
  219.      * overwrite of output file -n => no header: useful to uncompress old
  220.      * files -b maxbits => maxbits.  If -b is specified, then maxbits MUST be
  221.      * given also. -c => cat all output to stdout -C => generate output
  222.      * compatible with compress 2.0. if a string is left, must be an input
  223.      * filename.
  224.      */
  225.     for (argc--, argv++; argc > 0; argc--, argv++) {
  226.         if (**argv == '-') {    /* A flag argument */
  227.             while (*++(*argv)) {/* Process all flags in this arg */
  228.                 switch (**argv) {
  229. #ifndef ZCAT
  230.                 case 'V':
  231.                     version();
  232.                     break;
  233.                 case 'v':
  234.                     quiet = 0;
  235.                     break;
  236.                 case 'd':
  237.                     do_decomp = 1;
  238.                     break;
  239.                 case 'f':
  240.                 case 'F':
  241.                     overwrite = 1;
  242.                     force = 1;
  243.                     break;
  244.                 case 'n':
  245.                     nomagic = 1;
  246.                     break;
  247.                 case 'C':
  248.                     block_compress = 0;
  249.                     break;
  250.                 case 'b':
  251.                     if (!ARGVAL()) {
  252.                         fprintf(stderr, "Missing maxbits\n");
  253.                         Usage();
  254.                         exit(1);
  255.                     }
  256.                     maxbits = atoi(*argv);
  257.                     goto nextarg;
  258.                 case 'c':
  259.                     zcat_flg = 1;
  260.                     break;
  261.                 case 'q':
  262.                     quiet = 1;
  263.                     break;
  264. #endif
  265.                 default:
  266.                     fprintf(stderr, "Unknown flag: '%c'; ", **argv);
  267.                     Usage();
  268.                     exit(1);
  269.                 }
  270.             }
  271.         } else {                /* Input file name */
  272.             *fileptr++ = *argv; /* Build input file list */
  273.             *fileptr = NULL;
  274.             /* process nextarg; */
  275.         }
  276. nextarg:continue;
  277.     }
  278.  
  279.     if (maxbits < INIT_BITS)
  280.         maxbits = INIT_BITS;
  281.     if (maxbits > BITS)
  282.         maxbits = BITS;
  283.     maxmaxcode = 1 << maxbits;
  284.  
  285.     if (*filelist != NULL) {
  286.         for (fileptr = filelist; *fileptr; fileptr++) {
  287.             exit_stat = 0;
  288.             if (do_decomp) {    /* DECOMPRESSION */
  289. #ifndef ZCAT
  290.                 /* Check for .Z suffix */
  291.                 if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
  292.                     /* No .Z: tack one on */
  293.                     strcpy(tempname, *fileptr);
  294.                     strcat(tempname, ".Z");
  295.                     *fileptr = tempname;
  296.                 }
  297. #endif
  298.                 /* Open input file */
  299.                 if ((freopen(*fileptr, "r", stdin)) == NULL) {
  300.                     perror(*fileptr);
  301.                     perm_stat = 1;
  302.                     continue;
  303.                 }
  304.                 /* Check the magic number */
  305.                 if (nomagic == 0) {
  306.                     if ((getc(stdin) != (magic_header[0] & 0xFF))
  307.                         || (getc(stdin) != (magic_header[1] & 0xFF))) {
  308.                         fprintf(stderr, "%s: not in compressed format\n",
  309.                                 *fileptr);
  310.                         continue;
  311.                     }
  312.                     maxbits = getc(stdin);      /* set -b from file */
  313.                     block_compress = maxbits & BLOCK_MASK;
  314.                     maxbits &= BIT_MASK;
  315.                     maxmaxcode = 1 << maxbits;
  316.                     if (maxbits > BITS) {
  317.                         fprintf(stderr,
  318.                                 "%s: compressed with %d bits, can only handle %d bits\n",
  319.                                 *fileptr, maxbits, BITS);
  320.                         continue;
  321.                     }
  322.                 }
  323. #ifndef ZCAT
  324.                 /* Generate output filename */
  325.                 strcpy(ofname, *fileptr);
  326.                 ofname[strlen(*fileptr) - 2] = '\0';    /* Strip off .Z */
  327. #endif
  328.             }
  329. #ifndef ZCAT
  330.             else {              /* COMPRESSION */
  331.                 if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
  332.                     fprintf(stderr, "%s: already has .Z suffix -- no change\n",
  333.                             *fileptr);
  334.                     continue;
  335.                 }
  336.                 /* Open input file */
  337.                 if ((freopen(*fileptr, "r", stdin)) == NULL) {
  338.                     perror(*fileptr);
  339.                     perm_stat = 1;
  340.                     continue;
  341.                 }
  342.                 stat(*fileptr, &statbuf);
  343.                 fsize = (long) statbuf.st_size;
  344.                 /*
  345.                  * tune hash table size for small files -- ad hoc, but the
  346.                  * sizes match earlier #defines, which serve as upper bounds
  347.                  * on the number of output codes.
  348.                  */
  349.                 hsize = HSIZE;
  350.                 if (fsize < (1 << 12))
  351.                     hsize = min(5003, HSIZE);
  352.                 else if (fsize < (1 << 13))
  353.                     hsize = min(9001, HSIZE);
  354.                 else if (fsize < (1 << 14))
  355.                     hsize = min(18013, HSIZE);
  356.                 else if (fsize < (1 << 15))
  357.                     hsize = min(35023, HSIZE);
  358.                 else if (fsize < 47000)
  359.                     hsize = min(50021, HSIZE);
  360.  
  361.                 /* Generate output filename */
  362.                 strcpy(ofname, *fileptr);
  363.                 strcat(ofname, ".Z");
  364.             }
  365. #endif
  366.  
  367. #ifndef ZCAT
  368.             /* Check for overwrite of existing file */
  369.             if (overwrite == 0 && zcat_flg == 0) {
  370.                 if (stat(ofname, &statbuf) == 0) {
  371.                     char            response[2];
  372.                     response[0] = 'n';
  373.                     fprintf(stderr, "%s already exists;", ofname);
  374.                     if (isatty(2)) {
  375.                         fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
  376.                                 ofname);
  377.                         fflush(stderr);
  378.                         read(2, response, 2);
  379.                         while (response[1] != '\n') {
  380.                             if (read(2, response + 1, 1) < 0) { /* Ack! */
  381.                                 perror("stderr");
  382.                                 break;
  383.                             }
  384.                         }
  385.                     }
  386.                     if (response[0] != 'y') {
  387.                         fprintf(stderr, "\tnot overwritten\n");
  388.                         continue;
  389.                     }
  390.                 }
  391.             }
  392.             if (zcat_flg == 0) {/* Open output file */
  393.                 if (freopen(ofname, "w", stdout) == NULL) {
  394.                     perror(ofname);
  395.                     perm_stat = 1;
  396.                     continue;
  397.                 }
  398.                 precious = 0;
  399.                 if (!quiet)
  400.                     fprintf(stderr, "%s: ", *fileptr);
  401.             }
  402. #endif
  403.             /* Actually do the compression/decompression */
  404. #ifndef ZCAT
  405.             if (do_decomp == 0)
  406.                 compress();
  407.             else
  408. #endif
  409.                 decompress();
  410. #ifndef ZCAT
  411.             if (zcat_flg == 0) {
  412.                 copystat(*fileptr, ofname);     /* Copy stats */
  413.                 precious = 1;
  414.                 if ((exit_stat == 1) || (!quiet))
  415.                     putc('\n', stderr);
  416.             }
  417. #endif
  418.         }
  419.     }
  420. #ifndef ZCAT 
  421.     else {                    /* Standard input */
  422.         if (do_decomp == 0) {
  423.             compress();
  424.             if (!quiet)
  425.                 putc('\n', stderr);
  426.         } else {
  427.             /* Check the magic number */
  428.             if (nomagic == 0) {
  429.                 if ((getc(stdin) != (magic_header[0] & 0xFF))
  430.                     || (getc(stdin) != (magic_header[1] & 0xFF))) {
  431.                     fprintf(stderr, "stdin: not in compressed format\n");
  432.                     exit(1);
  433.                 }
  434.                 maxbits = getc(stdin);  /* set -b from file */
  435.                 block_compress = maxbits & BLOCK_MASK;
  436.                 maxbits &= BIT_MASK;
  437.                 maxmaxcode = 1 << maxbits;
  438.                 fsize = 100000; /* assume stdin large for USERMEM */
  439.                 if (maxbits > BITS) {
  440.                     fprintf(stderr,
  441.                             "stdin: compressed with %d bits, can only handle %d bits\n",
  442.                             maxbits, BITS);
  443.                     exit(1);
  444.                 }
  445.             }
  446.             decompress();
  447.         }
  448.     }
  449. #endif
  450.     exit(perm_stat ? perm_stat : exit_stat);
  451. }
  452.  
  453. static int      offset;
  454. long int        in_count = 1;   /* length of input */
  455. long int        bytes_out;      /* length of compressed output */
  456. long int        out_count = 0;  /* # of codes output (for debugging) */
  457.  
  458. #ifndef ZCAT
  459. /*
  460.  * compress stdin to stdout
  461.  * 
  462.  * Algorithm:  use open addressing double hashing (no chaining) on the prefix
  463.  * code / next character combination.  We do a variant of Knuth's algorithm D
  464.  * (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
  465.  * Here, the modular division first probe is gives way to a faster
  466.  * exclusive-or manipulation.  Also do block compression with an adaptive
  467.  * reset, whereby the code table is cleared when the compression ratio
  468.  * decreases, but after the table fills.    The variable-length output codes
  469.  * are re-sized at this point, and a special CLEAR code is generated for the
  470.  * decompressor.  Late addition:  construct the table according to file size
  471.  * for noticeable speed improvement on small files.  Please direct questions
  472.  * about this implementation to ames!jaw.
  473.  */
  474.  
  475. compress()
  476. {
  477.     register long   fcode;
  478.     register code_int i = 0;
  479.     register int    c;
  480.     register code_int ent;
  481.     register int    disp;
  482.     register code_int hsize_reg;
  483.     register int    hshift;
  484.  
  485.     if (nomagic == 0) {
  486.         putc(magic_header[0], stdout);
  487.         putc(magic_header[1], stdout);
  488.         putc((char) (maxbits | block_compress), stdout);
  489.         if (ferror(stdout))
  490.             writeerr();
  491.     }
  492.     offset = 0;
  493.     bytes_out = 3;              /* includes 3-byte header mojo */
  494.     out_count = 0;
  495.     clear_flg = 0;
  496.     ratio = 0;
  497.     in_count = 1;
  498.     checkpoint = CHECK_GAP;
  499.     maxcode = MAXCODE(n_bits = INIT_BITS);
  500.     free_ent = ((block_compress) ? FIRST : 256);
  501.  
  502.     ent = getc(stdin);
  503.  
  504.     hshift = 0;
  505.     for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
  506.         hshift++;
  507.     hshift = 8 - hshift;        /* set hash code range bound */
  508.  
  509.     hsize_reg = hsize;
  510.     cl_hash((count_int) hsize_reg);     /* clear hash table */
  511.  
  512.     while ((c = getc(stdin)) != EOF) {
  513.         in_count++;
  514.         fcode = (long) (((long) c << maxbits) + ent);
  515.         i = ((c << hshift) ^ ent);      /* xor hashing */
  516.  
  517.         if (htabof(i) == fcode) {
  518.             ent = codetabof(i);
  519.             continue;
  520.         } else if ((long) htabof(i) < 0)        /* empty slot */
  521.             goto nomatch;
  522.         disp = hsize_reg - i;   /* secondary hash (after G. Knott) */
  523.         if (i == 0)
  524.             disp = 1;
  525. probe:
  526.         if ((i -= disp) < 0)
  527.             i += hsize_reg;
  528.  
  529.         if (htabof(i) == fcode) {
  530.             ent = codetabof(i);
  531.             continue;
  532.         }
  533.         if ((long) htabof(i) > 0)
  534.             goto probe;
  535. nomatch:
  536.         output((code_int) ent);
  537.         out_count++;
  538.         ent = c;
  539.         if (free_ent < maxmaxcode) {
  540.             codetabof(i) = free_ent++;  /* code -> hashtable */
  541.             htabof(i) = fcode;
  542.         } else if ((count_int) in_count >= checkpoint && block_compress)
  543.             cl_block();
  544.     }
  545.     /*
  546.      * Put out the final code.
  547.      */
  548.     output((code_int) ent);
  549.     out_count++;
  550.     output((code_int) - 1);
  551.  
  552.     /*
  553.      * Print out stats on stderr
  554.      */
  555.     if (zcat_flg == 0 && !quiet) {
  556.         fprintf(stderr, "Compression: ");
  557.         prratio(stderr, in_count - bytes_out, in_count);
  558.     }
  559.     if (bytes_out > in_count)   /* exit(2) if no savings */
  560.         exit_stat = 2;
  561.     return;
  562. }
  563. #endif
  564.  
  565. /*****************************************************************
  566.  * TAG(output)
  567.  *
  568.  * Output the given code.
  569.  * Inputs:
  570.  *    code:    A n_bits-bit integer.  If == -1, then EOF.  This assumes
  571.  *        that n_bits =< (long)wordsize - 1.
  572.  * Outputs:
  573.  *    Outputs code to the file.
  574.  * Assumptions:
  575.  *    Chars are 8 bits long.
  576.  * Algorithm:
  577.  *    Maintain a BITS character long buffer (so that 8 codes will
  578.  * fit in it exactly).    Use the VAX insv instruction to insert each
  579.  * code in turn.  When the buffer fills up empty it and start over.
  580.  */
  581.  
  582. static char     buf[BITS];
  583.  
  584. char_type       lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
  585. char_type       rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  586.  
  587. #ifndef ZCAT
  588. output(code)
  589.     code_int        code;
  590. {
  591.  
  592.     /*
  593.      * On the VAX, it is important to have the register declarations in
  594.      * exactly the order given, or the asm will break.
  595.      */
  596.     register int    r_off = offset, bits = n_bits;
  597.     register char  *bp = buf;
  598.  
  599.     if (code >= 0) {
  600.         /*
  601.          * byte/bit numbering on the VAX is simulated by the following code
  602.          */
  603.         /*
  604.          * Get to the first byte.
  605.          */
  606.         bp += (r_off >> 3);
  607.         r_off &= 7;
  608.         /*
  609.          * Since code is always >= 8 bits, only need to mask the first hunk
  610.          * on the left.
  611.          */
  612.         *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
  613.         bp++;
  614.         bits -= (8 - r_off);
  615.         code >>= 8 - r_off;
  616.         /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  617.         if (bits >= 8) {
  618.             *bp++ = code;
  619.             code >>= 8;
  620.             bits -= 8;
  621.         }
  622.         /* Last bits. */
  623.         if (bits)
  624.             *bp = code;
  625.         offset += n_bits;
  626.         if (offset == (n_bits << 3)) {
  627.             bp = buf;
  628.             bits = n_bits;
  629.             bytes_out += bits;
  630.             do
  631.                 putc(*bp++, stdout);
  632.             while (--bits);
  633.             offset = 0;
  634.         }
  635.         /*
  636.          * If the next entry is going to be too big for the code size, then
  637.          * increase it, if possible.
  638.          */
  639.         if (free_ent > maxcode || (clear_flg > 0)) {
  640.             /*
  641.              * Write the whole buffer, because the input side won't discover
  642.              * the size increase until after it has read it.
  643.              */
  644.             if (offset > 0) {
  645.                 if (fwrite(buf, 1, n_bits, stdout) != n_bits)
  646.                     writeerr();
  647.                 bytes_out += n_bits;
  648.             }
  649.             offset = 0;
  650.  
  651.             if (clear_flg) {
  652.                 maxcode = MAXCODE(n_bits = INIT_BITS);
  653.                 clear_flg = 0;
  654.             } else {
  655.                 n_bits++;
  656.                 if (n_bits == maxbits)
  657.                     maxcode = maxmaxcode;
  658.                 else
  659.                     maxcode = MAXCODE(n_bits);
  660.             }
  661.         }
  662.     } else {
  663.         /*
  664.          * At EOF, write the rest of the buffer.
  665.          */
  666.         if (offset > 0)
  667.             fwrite(buf, 1, (offset + 7) / 8, stdout);
  668.         bytes_out += (offset + 7) / 8;
  669.         offset = 0;
  670.         fflush(stdout);
  671.         if (ferror(stdout))
  672.             writeerr();
  673.     }
  674. }
  675. #endif
  676.  
  677. /*
  678.  * Decompress stdin to stdout.    This routine adapts to the codes in the file
  679.  * building the "string" table on-the-fly; requiring no table to be stored in
  680.  * the compressed file.  The tables used herein are shared with those of the
  681.  * compress() routine.  See the definitions above.
  682.  */
  683.  
  684. decompress()
  685. {
  686.     register char_type *stackp;
  687.     register int    finchar;
  688.     register code_int code, oldcode, incode;
  689.  
  690.     /*
  691.      * As above, initialize the first 256 entries in the table.
  692.      */
  693.     maxcode = MAXCODE(n_bits = INIT_BITS);
  694.     for (code = 255; code >= 0; code--) {
  695.         tab_prefixof(code) = 0;
  696.         tab_suffixof(code) = (char_type) code;
  697.     }
  698.     free_ent = ((block_compress) ? FIRST : 256);
  699.  
  700.     finchar = oldcode = getcode();
  701.     if (oldcode == -1)          /* EOF already? */
  702.         return;                 /* Get out of here */
  703.     putc((char) finchar, stdout);       /* first code must be 8 bits = char */
  704.     if (ferror(stdout))         /* Crash if can't write */
  705.         writeerr();
  706.     stackp = de_stack;
  707.  
  708.     while ((code = getcode()) > -1) {
  709.  
  710.         if ((code == CLEAR) && block_compress) {
  711.             for (code = 255; code >= 0; code--)
  712.                 tab_prefixof(code) = 0;
  713.             clear_flg = 1;
  714.             free_ent = FIRST - 1;
  715.             if ((code = getcode()) == -1)       /* O, untimely death! */
  716.                 break;
  717.         }
  718.         incode = code;
  719.         /*
  720.          * Special case for KwKwK string.
  721.          */
  722.         if (code >= free_ent) {
  723.             *stackp++ = finchar;
  724.             code = oldcode;
  725.         }
  726.         /*
  727.          * Generate output characters in reverse order
  728.          */
  729.         while (code >= 256) {
  730.             *stackp++ = tab_suffixof(code);
  731.             code = tab_prefixof(code);
  732.         }
  733.         *stackp++ = finchar = tab_suffixof(code);
  734.  
  735.         /*
  736.          * And put them out in forward order
  737.          */
  738.         do
  739.             putc(*--stackp, stdout);
  740.         while (stackp > de_stack);
  741.  
  742.         /*
  743.          * Generate the new entry.
  744.          */
  745.         if ((code = free_ent) < maxmaxcode) {
  746.             tab_prefixof(code) = (unsigned short) oldcode;
  747.             tab_suffixof(code) = finchar;
  748.             free_ent = code + 1;
  749.         }
  750.         /*
  751.          * Remember previous code.
  752.          */
  753.         oldcode = incode;
  754.     }
  755.     fflush(stdout);
  756.     if (ferror(stdout))
  757.         writeerr();
  758. }
  759.  
  760. /*****************************************************************
  761.  * TAG( getcode )
  762.  *
  763.  * Read one code from the standard input.  If EOF, return -1.
  764.  * Inputs:
  765.  *    stdin
  766.  * Outputs:
  767.  *    code or -1 is returned.
  768.  */
  769.  
  770. code_int
  771. getcode()
  772. {
  773.     /*
  774.      * On the VAX, it is important to have the register declarations in
  775.      * exactly the order given, or the asm will break.
  776.      */
  777.     register code_int code;
  778.     static int      offset = 0, size = 0;
  779.     static char_type buf[BITS];
  780.     register int    r_off, bits;
  781.     register char_type *bp = buf;
  782.  
  783.     if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
  784.         /*
  785.          * If the next entry will be too big for the current code size, then
  786.          * we must increase the size.  This implies reading a new buffer
  787.          * full, too.
  788.          */
  789.         if (free_ent > maxcode) {
  790.             n_bits++;
  791.             if (n_bits == maxbits)
  792.                 maxcode = maxmaxcode;   /* won't get any bigger now */
  793.             else
  794.                 maxcode = MAXCODE(n_bits);
  795.         }
  796.         if (clear_flg > 0) {
  797.             maxcode = MAXCODE(n_bits = INIT_BITS);
  798.             clear_flg = 0;
  799.         }
  800.         size = fread(buf, 1, n_bits, stdin);
  801.         if (size <= 0)
  802.             return -1;          /* end of file */
  803.         offset = 0;
  804.         /* Round size down to integral number of codes */
  805.         size = (size << 3) - (n_bits - 1);
  806.     }
  807.     r_off = offset;
  808.     bits = n_bits;
  809.     /*
  810.      * Get to the first byte.
  811.      */
  812.     bp += (r_off >> 3);
  813.     r_off &= 7;
  814.     /* Get first part (low order bits) */
  815.     code = (*bp++ >> r_off);
  816.     bits -= (8 - r_off);
  817.     r_off = 8 - r_off;          /* now, offset into code word */
  818.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  819.     if (bits >= 8) {
  820.         code |= *bp++ << r_off;
  821.         r_off += 8;
  822.         bits -= 8;
  823.     }
  824.     /* high order bits. */
  825.     code |= (*bp & rmask[bits]) << r_off;
  826.     offset += n_bits;
  827.  
  828.     return code;
  829. }
  830.  
  831.  
  832. writeerr()
  833. {
  834.     perror(ofname);
  835.     unlink(ofname);
  836.     exit(1);
  837. }
  838.  
  839. #ifndef ZCAT
  840. copystat(ifname, ofname)
  841.     char           *ifname, *ofname;
  842. {
  843.     BOOL            CopyFileDate();
  844.  
  845.     fclose(stdout);
  846.     fclose(stdin);
  847.     if (exit_stat == 2 && (!force)) {   /* No compression: remove file.Z */
  848.         if (!quiet)
  849.             fprintf(stderr, " -- file unchanged"), fflush(stderr);
  850.     } else {                    /* ***** Successful Compression ***** */
  851.         exit_stat = 0;
  852.         if (CopyFileAttr(ifname, ofname) || CopyFileDate(ifname, ofname))
  853.             fprintf(stderr, " -- couldn't copy file attributes"), fflush(stderr);
  854.         if (unlink(ifname))     /* Remove input file */
  855.             perror(ifname), fflush(stderr);
  856.         else if (!quiet)
  857.             fprintf(stderr, " -- replaced with %s", ofname), fflush(stderr);
  858.         return;                 /* Successful return */
  859.     }
  860.  
  861.     /* Unsuccessful return -- one of the tests failed */
  862.     if (unlink(ofname))
  863.         perror(ofname), fflush(stderr);
  864. }
  865. #endif
  866.  
  867. onintr()
  868. {
  869. #ifndef ZCAT
  870.     if (!precious)
  871.         unlink(ofname);
  872. #endif
  873.     exit(1);
  874. }
  875.  
  876. oops()
  877. {                               /* wild pointer -- assume bad input */
  878.     if (do_decomp)
  879.         fprintf(stderr, "uncompress: corrupt input\n");
  880. #ifndef ZCAT
  881.     unlink(ofname);
  882. #endif
  883.     exit(1);
  884. }
  885.  
  886. #ifndef ZCAT
  887. cl_block()
  888. {                               /* table clear for block compress */
  889.     register long int rat;
  890.  
  891.     checkpoint = in_count + CHECK_GAP;
  892.  
  893.     if (in_count > 0x007fffff) {/* shift will overflow */
  894.         rat = bytes_out >> 8;
  895.         if (rat == 0) {         /* Don't divide by zero */
  896.             rat = 0x7fffffff;
  897.         } else {
  898.             rat = in_count / rat;
  899.         }
  900.     } else {
  901.         rat = (in_count << 8) / bytes_out;      /* 8 fractional bits */
  902.     }
  903.     if (rat > ratio) {
  904.         ratio = rat;
  905.     } else {
  906.         ratio = 0;
  907.         cl_hash((count_int) hsize);
  908.         free_ent = FIRST;
  909.         clear_flg = 1;
  910.         output((code_int) CLEAR);
  911.     }
  912. }
  913. #endif
  914.  
  915. #ifndef ZCAT
  916. cl_hash(hsize)                  /* reset code table */
  917.     register count_int hsize;
  918. {
  919.     register count_int *htab_p = &htab[hsize];
  920.     register long   i;
  921.     register long   m1 = -1;
  922.  
  923.     i = hsize - 16;
  924.     do {                        /* might use Sys V memset(3) here */
  925.         *(htab_p - 16) = m1;
  926.         *(htab_p - 15) = m1;
  927.         *(htab_p - 14) = m1;
  928.         *(htab_p - 13) = m1;
  929.         *(htab_p - 12) = m1;
  930.         *(htab_p - 11) = m1;
  931.         *(htab_p - 10) = m1;
  932.         *(htab_p - 9) = m1;
  933.         *(htab_p - 8) = m1;
  934.         *(htab_p - 7) = m1;
  935.         *(htab_p - 6) = m1;
  936.         *(htab_p - 5) = m1;
  937.         *(htab_p - 4) = m1;
  938.         *(htab_p - 3) = m1;
  939.         *(htab_p - 2) = m1;
  940.         *(htab_p - 1) = m1;
  941.         htab_p -= 16;
  942.     } while ((i -= 16) >= 0);
  943.     for (i += 16; i > 0; i--)
  944.         *--htab_p = m1;
  945. }
  946. #endif
  947. #ifndef ZCAT
  948. prratio(stream, num, den)
  949.     FILE           *stream;
  950.     long int        num, den;
  951. {
  952.     register int    q;          /* Doesn't need to be long */
  953.  
  954.     if (num > 214748L) {        /* 2147483647/10000 */
  955.         q = num / (den / 10000L);
  956.     } else {
  957.         q = 10000L * num / den; /* Long calculations, though */
  958.     }
  959.     if (q < 0) {
  960.         putc('-', stream);
  961.         q = -q;
  962.     }
  963.     fprintf(stream, "%d.%02d%%", q / 100, q % 100);
  964. }
  965. #endif
  966.  
  967. version()
  968. {
  969.     fprintf(stderr, "%s, Berkeley 5.9 5/11/86\n", rcs_ident);
  970.     fprintf(stderr, "Options: ");
  971.     fprintf(stderr, "AMIGA, ");
  972.     fprintf(stderr, "BITS = %d\n", BITS);
  973. }
  974.  
  975. #ifndef ZCAT
  976. /*
  977.  * Function: GetFileDate
  978.  * 
  979.  * Called with: name:    file name date:    pointer to DateStamp structure
  980.  * 
  981.  * Returns: result: 1 => got a date, 0 => didn't
  982.  * 
  983.  * Description: GetFileDate attempts to get the creation/modification date of a
  984.  * file (unfortunately, they're one and the same) and stores it into the
  985.  * location pointed to by <date>.  If the file doesn't exist or for some
  986.  * reason the date can't be obtained, <date> is set to zeros and a zero is
  987.  * returned.  Otherwise, <date> is set to the file date and a 1 is returned.
  988.  */
  989.  
  990. BOOL
  991. GetFileDate(name, date)
  992.     char           *name;
  993.     struct DateStamp *date;
  994. {
  995.     struct FileInfoBlock *Fib;
  996.     ULONG           FLock;
  997.     int             result = FALSE;
  998.     register struct DateStamp *d;
  999.  
  1000.     if ((FLock = (ULONG) Lock(name, (long) (ACCESS_READ))) == NULL)
  1001.         goto exit1;
  1002.  
  1003.     Fib = (struct FileInfoBlock *)
  1004.         AllocMem((long) sizeof(struct FileInfoBlock),
  1005.                  (long) (MEMF_CHIP | MEMF_PUBLIC));
  1006.  
  1007.     if (Fib == NULL)
  1008.         result = FALSE;
  1009.     else {
  1010.         if (!Examine(FLock, Fib)) {
  1011.             result = FALSE;
  1012.         } else if (Fib->fib_DirEntryType > 0)
  1013.             result = FALSE;     /* It's a directory */
  1014.         else {
  1015.             d = &Fib->fib_Date;
  1016.             date->ds_Days = d->ds_Days;
  1017.             date->ds_Minute = d->ds_Minute;
  1018.             date->ds_Tick = d->ds_Tick;
  1019.             result = TRUE;
  1020.         }
  1021.         FreeMem((void *) Fib, (long) sizeof(struct FileInfoBlock));
  1022.     }
  1023.  
  1024.     UnLock(FLock);
  1025. exit1:
  1026.     if (!result) {
  1027.         date->ds_Days = 0;
  1028.         date->ds_Minute = 0;
  1029.         date->ds_Tick = 0;
  1030.     }
  1031.     return result;
  1032. }
  1033. #endif
  1034.  
  1035. #ifndef ZCAT
  1036. /*---------------------------------------------------------------------*/
  1037. /* SetFileDate: datestamp the given file with the given date.           */
  1038. /*---------------------------------------------------------------------*/
  1039.  
  1040. #define ACTION_SETDATE_MODE 34L /* Set creation date on file */
  1041.  
  1042. BOOL
  1043. SetFileDate(name, date)
  1044.     char           *name;
  1045.     struct DateStamp *date;
  1046. {
  1047.     struct MsgPort *task;       /* for process id handler */
  1048.     ULONG           arg[4];     /* array of arguments      */
  1049.     int             nameleng;
  1050.     char           *bstr, *strcpy();    /* of file to be set      */
  1051.     long            rc;
  1052.     char           *strchr();
  1053.     int             strlen();
  1054.  
  1055.     rc = 0;
  1056.  
  1057.     nameleng = strlen(name);
  1058.     if (!(bstr = (char *) AllocMem((long) (nameleng + 2), MEMF_PUBLIC)))
  1059.         goto exit2;
  1060.  
  1061.     if (!(task = (struct MsgPort *) DeviceProc(name)))
  1062.         goto exit1;
  1063.  
  1064.     /* Dos Packet needs the filename in Bstring format */
  1065.  
  1066.     (void) strcpy(bstr + 1, name);
  1067.     *bstr = nameleng;
  1068.  
  1069.     arg[0] = (ULONG) NULL;
  1070.     arg[1] = (ULONG) IoErr();   /* lock on parent director set by
  1071.                                  * DeviceProc() */
  1072.     arg[2] = (ULONG) bstr >> 2;
  1073.     arg[3] = (ULONG) date;
  1074.     rc = sendpkt(task, ACTION_SETDATE_MODE, arg, 4L);
  1075.  
  1076. exit1:if (bstr)
  1077.         FreeMem((void *) bstr, (long) (nameleng + 2));
  1078. exit2:if (rc == DOSTRUE)
  1079.         return TRUE;
  1080.     else
  1081.         return FALSE;
  1082. }
  1083. #endif
  1084.  
  1085.  
  1086. #ifndef ZCAT
  1087. /*
  1088.  * Copy the last modified date from one file to another. Called with: from:
  1089.  * me of source file to:            name of destination file Returns: 0 => success, 1
  1090.  * => failure Note: Dynamic memory allocation of the DateStamp struction is
  1091.  * necessary to insure longword alignment.
  1092.  */
  1093.  
  1094. BOOL
  1095. CopyFileDate(from, to)
  1096.     char           *from, *to;
  1097. {
  1098.     struct DateStamp *date;
  1099.     int             status = 1; /* default is fail code */
  1100.  
  1101.     if (date = (struct DateStamp *)
  1102.         AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC)) {
  1103.         if (GetFileDate(from, date))
  1104.             if (SetFileDate(to, date))
  1105.                 status = 0;
  1106.         FreeMem(date, (long) sizeof(struct DateStamp));
  1107.     }
  1108.     return status;
  1109. }
  1110. #endif
  1111.  
  1112. #ifndef ZCAT
  1113. /****************************************************************************/
  1114. /*
  1115.  * Function: CopyFileAttr - Copy File Attributes
  1116.  * 
  1117.  * Called with: srcName:        source file name dstName:        destination file name
  1118.  * 
  1119.  * Returns: status where 0 => success
  1120.  * 
  1121.  * Description: CopyFileAttr is used by file copying functions to assign the
  1122.  * attributes of the source file to the destination file.
  1123.  */
  1124. int
  1125. CopyFileAttr(srcName, dstName)
  1126.     char           *srcName, *dstName;
  1127. {
  1128.     struct Lock    *srcLock = NULL;
  1129.     struct FileInfoBlock *srcFIB = NULL;
  1130.     int             status = 0;
  1131.  
  1132.     if (!(srcFIB = AllocMem((long) sizeof(*srcFIB), MEMF_FAST))) {
  1133. nomem:
  1134.         status = ERROR_NO_FREE_STORE;
  1135.         goto done;
  1136.     }
  1137.     if (!(srcLock = (struct Lock *) Lock(srcName, ACCESS_READ))) {
  1138. err:
  1139.         status = IoErr();
  1140.         goto done;
  1141.     }
  1142.     if (!Examine(srcLock, srcFIB))
  1143.         goto err;
  1144.     SetFileDate(dstName, &srcFIB->fib_Date);
  1145.     if (srcFIB->fib_Comment[0])
  1146.         SetComment(dstName, srcFIB->fib_Comment);
  1147.     SetProtection(dstName, srcFIB->fib_Protection);
  1148.  
  1149. done:
  1150.     if (srcLock)
  1151.         UnLock(srcLock);
  1152.     if (srcFIB)
  1153.         FreeMem(srcFIB, (long) sizeof(*srcFIB));
  1154.     return status;
  1155. }
  1156. #endif
  1157.  
  1158. #ifndef ZCAT
  1159. LONG
  1160. sendpkt(id, type, args, nargs)
  1161.     struct MsgPort *id;         /* process indentifier ... (handler's message
  1162.                                  * port ) */
  1163.     LONG            type,       /* packet type ... (what you want handler to
  1164.                                  * do )   */
  1165.                     args[],     /* a pointer to argument list */
  1166.                     nargs;      /* number of arguments in list     */
  1167. {
  1168.  
  1169.     struct MsgPort *replyport;
  1170.     struct StandardPacket *packet;
  1171.  
  1172.     LONG            count, *pargs, res1 = NULL;
  1173.  
  1174.     if (!(replyport = (struct MsgPort *) CreatePort(NULL, NULL)))
  1175.         return (NULL);
  1176.  
  1177.     packet = (struct StandardPacket *)
  1178.         AllocMem((LONG) sizeof(*packet), MEMF_PUBLIC | MEMF_CLEAR);
  1179.  
  1180.     if (packet) {
  1181.         packet->sp_Msg.mn_Node.ln_Name = &(packet->sp_Pkt);     /* link packet */
  1182.         packet->sp_Pkt.dp_Link = &(packet->sp_Msg);     /* to message    */
  1183.         packet->sp_Pkt.dp_Port = replyport;     /* set-up reply port   */
  1184.         packet->sp_Pkt.dp_Type = type;  /* what to do... */
  1185.  
  1186.         /* move all the arguments to the packet */
  1187.         pargs = &(packet->sp_Pkt.dp_Arg1);      /* address of first argument */
  1188.         for (count = 0; (count < nargs) && (count < 7); count++)
  1189.             pargs[count] = args[count];
  1190.  
  1191.         PutMsg(id, packet);     /* send packet */
  1192.         WaitPort(replyport);    /* wait for packet to come back */
  1193.         GetMsg(replyport);      /* pull message */
  1194.  
  1195.         res1 = packet->sp_Pkt.dp_Res1;  /* get result */
  1196.         FreeMem(packet, (LONG) sizeof(*packet));
  1197.  
  1198.     }
  1199.     DeletePort(replyport);
  1200.     return (res1);
  1201. }
  1202. #endif
  1203.