+/* compact.c 4.1 83/02/11 */
+/*
+ * Adaptive Huffman code input to output
+ *
+ * On - line algorithm
+ *
+ * Does not prepend decoding tree
+ *
+ * Written by Colin L. Mc Master (UCB) February 28, 1979
+ */
+
+
+#include "compact.h"
+
+union cio d;
+int bits;
+
+
+main (argc, argv)
+short argc;
+char *argv [ ];
+{
+ register short i, j;
+ register int m;
+ union cio c;
+ short l;
+ longint ic, n;
+ char *cp, fname [LNAME];
+
+ dir [513] . next = NULL;
+ for (head = dir + (j = 513); j--; ) {
+ dirp = head--;
+ head -> next = dirp;
+ }
+ bottom = dirp -> pt = dict;
+ dict [0] . top [0] = dict [0] . top [1] = dirp;
+ dirq = dirp -> next;
+ in [EF] . flags = FBIT | SEEN;
+
+ for (i = 1; ; i++) {
+ ic = oc = 0;
+ (bottom -> top [1]) -> next = flist;
+ bottom -> top [1] = dirp;
+ flist = dirq;
+ if (i >= argc) {
+ uncfp = stdin;
+ cfp = stdout;
+ }
+ else {
+ m = -1;
+ cp = fname;
+ for (l = 0; l < (LNAME - 3) && (*cp = argv [i][l]); l++)
+ if (*cp++ == '/') m = l;
+ if (l >= (LNAME - 3) || (l - m) > 13) {
+ fprintf (stderr, "%s: File name too long\n", argv [i]);
+ if (i == argc - 1) break;
+ continue;
+ }
+ if ((uncfp = fopen (argv [i], "r")) == NULL) {
+ perror (argv [i]);
+ if (i == argc - 1) break;
+ continue;
+ }
+ }
+
+ fstat (fileno (uncfp), &status);
+ if ((status.st_mode & 040000) == 040000) {
+ fprintf (stderr, "%s: Can't compact a directory\n", argv [i]);
+ if (i < argc) goto closein;
+ break;
+ }
+
+ if ((d . integ = getc (uncfp)) != EOF) {
+ ic++;
+ if ((c . integ = getc (uncfp)) != EOF) {
+ d . chars . hib = c . integ & 0377;
+ if ((d . integ &= 0177777) == COMPACTED) {
+ fprintf (stderr, "%s: Already compacted.\n", argv [i]);
+ if (i < argc) goto closein;
+ break;
+ }
+ if (d . integ == PACKED) {
+ fprintf (stderr, "%s: Already packed using program pack. Use unpack.\n", argv [i]);
+ if (i < argc) goto closein;
+ break;
+ }
+ if (i < argc) {
+ *cp++ = '.'; *cp++ = 'C'; *cp = '\0';
+ if ((cfp = fopen (fname, "w")) == NULL) {
+ perror (fname);
+ goto closein;
+ }
+ chmod (fname, status.st_mode);
+ }
+ c . integ = COMPACTED;
+ putc (c . chars . lob, cfp);
+ putc (c . chars . hib, cfp);
+ if (ferror (cfp))
+ if (i < argc) {
+ perror (fname);
+ unlink (fname);
+ goto closeboth;
+ }
+ else goto fail;
+ bits = 8;
+ oc = 2;
+ c . integ = d . integ & 0377;
+
+ in [NC] . fp = in [EF] . fp = dict [0] . sp [0] . p = bottom = dict + 1;
+ bottom -> count [0] = bottom -> count [1] = dict [0] . count [1] = 1;
+ dirp -> next = dict [0] . top [1] = bottom -> top [0] = bottom -> top [1] = dirq = NEW;
+ dirq -> next = NULL;
+ dict [0] . fath . fp = NULL;
+ dirq -> pt = bottom -> fath . fp = in [c . integ] . fp = dict;
+ in [c . integ] . flags = (FBIT | SEEN);
+ in [NC] . flags = SEEN;
+ dict [0] . fath . flags = RLEAF;
+ bottom -> fath . flags = (LLEAF | RLEAF);
+ dict [0] . count [0] = 2;
+
+ dict [0] . sp [1] . ch = c . integ;
+ bottom -> sp [0] . ch = NC;
+ bottom -> sp [1] . ch = EF;
+
+ for (c . integ = ((d . integ >> 8) & 0377); c . integ != EOF; c . integ = getc (uncfp)) {
+ ic++;
+ if (in [c . integ] . flags & SEEN) encode (c . integ);
+ else {
+ encode (NC);
+ uptree (NC);
+ insert (c . integ);
+
+ m = 0200;
+ for (j = 8; j--; m >>= 1) {
+ d . integ <<= 1;
+ if (m & c . integ) d . integ++;
+ ++bits;
+ if ((bits &= 017) == 0) {
+ putc (d . chars . hib, cfp);
+ putc (d . chars . lob, cfp);
+ oc += 2;
+ }
+ }
+ }
+ if (ferror (cfp))
+ if (i < argc) {
+ perror (fname);
+ unlink (fname);
+ goto closeboth;
+ }
+ else goto fail;
+ uptree (c . integ);
+
+ }
+
+ if (ferror (uncfp))
+ if (i < argc) {
+ perror (argv [i]);
+ unlink (fname);
+ goto closeboth;
+ }
+ else goto fail;
+
+ encode (EF);
+
+ if (bits) {
+ d . integ <<= (16 - bits);
+ oc++;
+ putc (d . chars . hib, cfp);
+ if (bits > 8) {
+ oc++;
+ putc (d . chars . lob, cfp);
+ }
+ bits = 0;
+ }
+ }
+ else oc = ic;
+ }
+
+ if (ferror (uncfp) || ferror (cfp))
+ if (i < argc) {
+ if (ferror (cfp))
+ perror (fname);
+ else
+ perror (argv [i]);
+ if (oc > 1) {
+ unlink (fname);
+ goto closeboth;
+ }
+ goto closein;
+ }
+ else goto fail;
+ else {
+ if (oc >= ic) {
+ if (i < argc) fprintf (stderr, "%s: ", argv [i]);
+ if (i < argc) fprintf (stderr, "Not compacted. ");
+ fprintf (stderr, "Does not save bytes.\n");
+ if (i < argc) {
+ if (oc > 1) {
+ unlink (fname);
+ goto closeboth;
+ }
+ goto closein;
+ }
+ else break;
+ }
+ while ((ic - oc) > 21474) {
+ ic /= 10;
+ oc /= 10;
+ }
+ n = 100000 * (ic - oc) / ic + 5;
+ m = (n % 1000) / 10;
+ bits = m % 10 + '0';
+ c . integ = m / 10 + '0';
+ if (i < argc) fprintf (stderr, "%s: ", argv [i]);
+ fprintf (stderr, "Compression : %4ld.%c%c%%\n", n / 1000, c . chars . lob, bits);
+ }
+
+ if (i >= argc) break;
+ unlink (argv [i]);
+ closeboth : fclose (cfp);
+ closein : fclose (uncfp);
+ if (i == argc - 1) break;
+ for (j = 256; j--; ) in [j] . flags = 0;
+ continue;
+ fail : fprintf (stderr, "Unsuccessful compact of standard input to standard output.\n");
+ break;
+ }
+}
+
+encode (ch)
+int ch;
+{
+
+ register struct node *pp;
+ register char j;
+ union cio c;
+ int stack [17], stp, stbits;
+
+ c . integ = ch;
+ stack [stp = 0] = in [c . integ] . flags & FBIT;
+ stbits = 1;
+ pp = in [c . integ] . fp;
+
+ while (pp -> fath . fp) {
+ stack [stp] <<= 1;
+ if (pp -> fath . flags & FBIT) stack [stp]++;
+ stbits++;
+ if ((stbits &= 017) == 0) stp++;
+ pp = pp -> fath . fp;
+ }
+
+ /* pop the output stack */
+
+ for (stp++; stp--; ) {
+ for (j = 0; j < stbits; j++) {
+ d . integ <<= 1;
+ if (stack [stp] & 01) d . integ++;
+ ++bits;
+ if ((bits &= 017) == 0) {
+ putc (d . chars . hib, cfp);
+ putc (d . chars . lob, cfp);
+ if (ferror (cfp)) return;
+ oc += 2;
+ }
+ stack [stp] >>= 1;
+ }
+ stbits = 16;
+ }
+}