|
|
1.1 root 1: /* compress - Reduce file size using Modified Lempel-Ziv encoding */
2: /*
3: * compress.c - File compression ala IEEE Computer, June 1984.
4: *
5: * Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
6: * Jim McKie (decvax!mcvax!jim)
7: * Steve Davies (decvax!vax135!petsd!peora!srd)
8: * Ken Turkowski (decvax!decwrl!turtlevax!ken)
9: * James A. Woods (decvax!ihnp4!ames!jaw)
10: * Joe Orost (decvax!vax135!petsd!joe)
11: *
12: * Richard Todd Port to MINIX
13: * Andy Tanenbaum Cleanup
14: *
15: *
16: * Algorithm from "A Technique for High Performance Data Compression",
17: * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
18: *
19: * Usage: compress [-dfvc] [-b bits] [-w workfile] [file ...]
20: * Inputs:
21: * -d: If given, decompression is done instead.
22: *
23: * -c: Write output on stdout.
24: *
25: * -b: Parameter limits the max number of bits/code.
26: *
27: * -f: Forces output file to be generated, even if one already
28: * exists, and even if no space is saved by compressing.
29: * If -f is not used, the user will be prompted if stdin is
30: * a tty, otherwise, the output file will not be overwritten.
31: *
32: * -v: Write compression statistics
33: *
34: * -w: Use specified workfile
35: *
36: * file ...: Files to be compressed. If none specified, stdin
37: * is used.
38: * Outputs:
39: * file.Z: Compressed form of file with same mode, owner, and utimes
40: * or stdout (if stdin used as input)
41: *
42: * Assumptions:
43: * When filenames are given, replaces with the compressed version
44: * (.Z suffix) only if the file decreases in size.
45: * Algorithm:
46: * Modified Lempel-Ziv method (LZW). Basically finds common
47: * substrings and replaces them with a variable size code. This is
48: * deterministic, and can be done on the fly. Thus, the decompression
49: * procedure needs no input table, but tracks the way the table was built.
50: *
51: * Revision history
52: * 90/07/11 07:53:00 Charles Fiterman
53: * Make compress work for COHERENT
54: * This first involved making it work on a system where an int
55: * is 16 bits. Then installing a virtualizing system to permit
56: * a small model compress.
57: */
58:
59: #ifdef MSDOS
60: #define DOS 1
61: #endif
62: #ifdef GEMDOS
63: #define DOS 1
64: #endif
65:
66: #define AZTEC86 1
67: #define MINIX 1
68:
69: #define min(a,b) ((a>b) ? b : a)
70:
71: /*
72: * Set USERMEM to the maximum amount of physical user memory available
73: * in bytes. USERMEM is used to determine the maximum BITS that can be used
74: * for compression.
75: *
76: * SACREDMEM is the amount of physical memory saved for others; compress
77: * will hog the rest.
78: */
79: #ifndef SACREDMEM
80: #define SACREDMEM 0
81: #endif
82:
83: #ifndef USERMEM
84: # define USERMEM 450000 /* default user memory */
85: #endif
86:
87: #define REGISTER register
88:
89: #ifdef AZTEC86
90: void prratio(),cl_block(),cl_hash(),output(),decompress(),
91: copystat(),writeerr(),compress(),Usage(),version();
92: #endif /* AZTEC86 */
93:
94: #ifdef USERMEM
95: # if USERMEM >= (433484+SACREDMEM)
96: # define PBITS 16
97: # else
98: # if USERMEM >= (229600+SACREDMEM)
99: # define PBITS 15
100: # else
101: # if USERMEM >= (127536+SACREDMEM)
102: # define PBITS 14
103: # else
104: # if USERMEM >= (73464+SACREDMEM)
105: # define PBITS 13
106: # else
107: # define PBITS 12
108: # endif
109: # endif
110: # endif
111: # endif
112: # undef USERMEM
113: #endif /* USERMEM */
114:
115: #ifdef PBITS /* Preferred BITS for this memory size */
116: # ifndef BITS
117: # define BITS PBITS
118: # endif
119: #endif /* PBITS */
120:
121: #if BITS == 16
122: # define HSIZE 69001L /* 95% occupancy */
123: #endif
124: #if BITS == 15
125: # define HSIZE 35023L /* 94% occupancy */
126: #endif
127: #if BITS == 14
128: # define HSIZE 18013 /* 91% occupancy */
129: #endif
130: #if BITS == 13
131: # define HSIZE 9001 /* 91% occupancy */
132: #endif
133: #if BITS <= 12
134: # define HSIZE 5003 /* 80% occupancy */
135: #endif
136:
137:
138: /*
139: * a code_int must be able to hold 2**BITS values of type int, and also -1
140: */
141: #if BITS > 15
142: typedef long code_int;
143: #else
144: typedef int code_int;
145: #endif
146:
147: #ifdef SIGNED_COMPARE_SLOW
148: typedef unsigned long count_int;
149: typedef unsigned short count_short;
150: #else
151: typedef long count_int;
152: #endif
153:
154: #ifdef DOS
155: #define SLASH '\\'
156: #else
157: #define SLASH '/'
158: #endif
159:
160: #ifdef NO_UCHAR
161: typedef char char_type;
162: #else
163: typedef unsigned char char_type;
164: #endif /* UCHAR */
165: char_type magic_header[] = { "\037\235" }; /* 1F 9D */
166:
167: /* Defines for third byte of header */
168: #define BIT_MASK 0x1f
169: #define BLOCK_MASK 0x80
170: /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
171: a fourth header byte (for expansion).
172: */
173: #define INIT_BITS 9 /* initial number of bits/code */
174: static char rcs_ident[] = "$Header: /newbits/bin/compress/RCS/compress.c,v 1.3 91/09/17 06:34:57 bin Exp Locker: bin $";
175:
176: #include <stdio.h>
177: #include <ctype.h>
178: #include <signal.h>
179: #ifdef GEMDOS
180: #include <types.h>
181: #include <stat.h>
182: #else
183: #include <sys/types.h>
184: #include <sys/stat.h>
185: #endif
186:
187: #define ARGVAL() (*++(*argv) || (--argc && *++argv))
188:
189: int n_bits; /* number of bits/code */
190: code_int maxcode; /* maximum code, given n_bits */
191: code_int maxmaxcode = 1L << BITS; /* should NEVER generate this code */
192: char outbuf[512];
193: #ifdef COMPATIBLE /* But wrong! */
194: # define MAXCODE(n_bits) (1L << (n_bits) - 1)
195: #else
196: # define MAXCODE(n_bits) ((1L << (n_bits)) - 1)
197: #endif /* COMPATIBLE */
198:
199: #ifndef AZTEC86
200: count_int htab [HSIZE];
201: unsigned short codetab [HSIZE];
202: int maxbits = BITS; /* user settable max bits */
203: #else /* AZTEC86 */
204: #ifdef VIRTUAL
205: /*
206: * Virtual memory for compress. Uses hash algorithm
207: * rather than LRU to get it up fast.
208: */
209: #include <assert.h>
210:
211: #define VBLKB 6
212: #define VBLK (1 << VBLKB) /* bytes in a virtual block */
213: #define MBKS 512 /* number of virtual blocks */
214:
215: struct mapper {
216: unsigned dirty:1;
217: unsigned what_in:15; /* which block is in memory */
218: };
219: static unsigned long codedsp, codelim;
220: static int tmpf, ramsw = 0;
221: static int maxbits = 12; /* user settable max bits code */
222: static char *tmpn = NULL;
223:
224: static char ram1[] = "/dev/ram1";
225: static char data[MBKS][VBLK];
226: static struct mapper map[MBKS];
227: /*
228: * Init file system for virtual arrays.
229: * On compress data is ordered htab then codetab
230: * On decompress data is only suffix
231: */
232: initV(hsize, codesiz)
233: long hsize, codesiz;
234: {
235: extern char *tempnam();
236: static int fts = 0;
237:
238: if(fts || (12 >= maxbits))
239: return;
240:
241: codedsp = hsize;
242: codelim = codedsp + codesiz;
243:
244: fts = 1;
245:
246: if(NULL == tmpn)
247: #ifdef GEMDOS
248: tmpn = tempnam("d:", NULL); /* I had space here on my ST */
249: #else
250: switch(is_fs(tmpn = ram1)) {
251: case -1:
252: fprintf(stderr, "Error opening %s\n", ram1);
253: fprintf(stderr, "Use the -w workf option\n");
254: exit(1);
255: break;
256: case 1:
257: fprintf(stderr, "Possible file system on %s", ram1);
258: fprintf(stderr, "Remove file system or use -w workf option\n");
259: exit(1);
260: break;
261: case 0:
262: tmpf = open(tmpn, 2);
263: ramsw = 1;
264: }
265: #endif
266: if(!ramsw) {
267: if(-1 == (tmpf = creat(tmpn, 0600))) { /* rw for owner */
268: fprintf(stderr, "Cannot create %s\n", tmpn);
269: exit(1);
270: }
271: close(tmpf);
272:
273: tmpf = open(tmpn, 2); /* open to read and write */
274: unlink(tmpn); /* remove after close */
275: }
276: if(-1 == tmpf) {
277: fprintf(stderr, "Cannot open %s\n", tmpn);
278: exit(1);
279: }
280: }
281:
282: ioError(s)
283: char *s;
284: {
285: fprintf(stderr, "Error in %s on %s\n", s, tmpn);
286: if(!strcmp(ram1, tmpn))
287: fprintf(stderr, "Use the -w workfile option\n");
288: myExit(1);
289: }
290:
291: /*
292: * Find spot on virtual array
293: */
294: char *
295: virtual(bp, dirty)
296: long bp; /* data address */
297: int dirty;
298: {
299: unsigned which, what_in, byte_no;
300: unsigned long diskad;
301: extern long lseek();
302:
303: byte_no = bp & (VBLK - 1);
304: bp >>= VBLKB;
305: which = bp % MBKS;
306: what_in = bp / MBKS;
307:
308: if((diskad = map[which].what_in) != what_in) {
309: if(map[which].dirty) {
310: diskad *= MBKS;
311: diskad += which;
312: diskad <<= VBLKB;
313: if(-1 == lseek(tmpf, diskad, 0))
314: ioError("seek");
315: if(VBLK != write(tmpf, &data[which][0], VBLK))
316: ioError("write");
317: }
318: diskad = what_in;
319: diskad *= MBKS;
320: diskad += which;
321: diskad <<= VBLKB;
322: if(-1 == lseek(tmpf, diskad, 0))
323: ioError("seek");
324:
325: if(VBLK != read(tmpf, &data[which][0], VBLK))
326: memset(&data[which][0], 0, VBLK);
327:
328: map[which].what_in = what_in;
329: map[which].dirty = 0; /* clean */
330: }
331: map[which].dirty |= dirty;
332: return(data[which] + byte_no);
333: }
334: #define HSIZE12 5003
335:
336: #define htabof(bp) (*(count_int *)((12 >= maxbits) ? \
337: (data[0] + ((int)(bp) << 2)) : virtual(((long)(bp) << 2), 0)))
338: #define sethtab(bp, v) (*(count_int *)((12 >= maxbits) ? \
339: (data[0] + ((int)(bp) << 2)) : virtual(((long)(bp) << 2), 1)) = (v))
340:
341: #define codetabof(bp) (*(unsigned short *)((12 >= maxbits) ? \
342: (data[0] + ((int)(bp) << 1) + (HSIZE12 * sizeof(count_int))) : \
343: virtual(((long)(bp) << 1) + codedsp, 0)))
344: #define setcodtab(bp, v) (*(unsigned short *)((12 >= maxbits) ? \
345: (data[0] + ((int)(bp) << 1) + (HSIZE12 * sizeof(count_int))) : \
346: virtual(((long)(bp) << 1) + codedsp, 1)) = (v))
347:
348: #else /* Normal machine */
349: int maxbits = BITS; /* user settable max bits code */
350: count_int *htab;
351: unsigned short *codetab;
352:
353:
354: #define htabof(i) htab[(unsigned long)i]
355: #define sethtab(i, v) htabof(i) = v
356: #define codetabof(i) codetab[(unsigned long)i]
357: #define setcodtab(i, v) codetabof(i) = v
358: #endif /* VIRTUAL */
359: #endif /* AZTEC86 */
360:
361: # define HTABSIZE (HSIZE*sizeof(count_int))
362: # define CODETABSIZE (HSIZE*sizeof(unsigned short))
363:
364: code_int hsize = HSIZE; /* for dynamic table sizing */
365: count_int fsize;
366:
367: /*
368: * To save much memory, we overlay the table used by compress() with those
369: * used by decompress(). The tab_prefix table is the same size and type
370: * as the codetab. The tab_suffix table needs 2**BITS characters. We
371: * get this from the beginning of htab. The output stack uses the rest
372: * of htab, and contains characters. There is plenty of room for any
373: * possible stack (stack used to be 8000 characters).
374: */
375: #ifdef VIRTUAL
376: #define tab_prefixof(i) codetabof(i)
377:
378: #define tab_suffixof(bp) (*(char_type *)((12 >= maxbits) ? \
379: (data[0] + (bp)) : virtual((long)(bp), 0)))
380: #define setsuffix(bp, v) (*(char_type *)((12 >= maxbits) ? \
381: (data[0] + (bp)) : virtual((long)(bp), 1)) = (v))
382:
383: char_type de_stack[8192];
384:
385: #else /* normal machine */
386: #define tab_prefixof(i) codetabof(i)
387: # define tab_suffixof(i) ((char_type *)(htab))[(unsigned long)i]
388: # define setsuffix(i, v) tab_suffixof(i) = v
389: # define de_stack ((char_type *)&tab_suffixof(1<<BITS))
390: #endif /* VIRTUAL */
391:
392: code_int free_ent = 0; /* first unused entry */
393: int exit_stat = 0;
394: char dotz[] = ".Z";
395:
396: code_int getcode();
397:
398: void Usage() {
399: #ifdef DEBUG
400: #ifdef VIRTUAL
401: fprintf(stderr,
402: "Usage: compress [-dDVfc] [-b maxbits] [-w workfile] [file ...]\n");
403: #else
404: fprintf(stderr, "Usage: compress [-dDVfc] [-b maxbits] [file ...]\n");
405: #endif
406: }
407: int debug = 0;
408: #else
409: #ifdef VIRTUAL
410: fprintf(stderr,
411: "Usage: compress [-dfvcV] [-b maxbits] [-w workfile] [file ...]\n");
412: #else
413: fprintf(stderr,"Usage: compress [-dfvcV] [-b maxbits] [file ...]\n");
414: #endif
415: }
416: #endif /* DEBUG */
417: int nomagic = 0; /* Use a 3-byte magic number header, unless old file */
418: int zcat_flg = 0; /* Write output on stdout, suppress messages */
419: int quiet = 1; /* don't tell me about compression */
420:
421: /*
422: * block compression parameters -- after all codes are used up,
423: * and compression rate changes, start over.
424: */
425: int block_compress = BLOCK_MASK;
426: int clear_flg = 0;
427: long ratio = 0;
428: #define CHECK_GAP 10000L /* ratio check interval */
429: count_int checkpoint = CHECK_GAP;
430: /*
431: * the next two codes should not be changed lightly, as they must not
432: * lie within the contiguous general code space.
433: */
434: #define FIRST 257 /* first free entry */
435: #define CLEAR 256 /* table clear output code */
436:
437: int force = 0;
438: char ofname [100];
439: #ifdef DEBUG
440: int verbose = 0;
441: #endif /* DEBUG */
442:
443: #ifndef METAWARE
444: #ifdef AZTEC86
445: void
446: #else
447: int
448: #endif
449: (*bgnd_flag)();
450: #endif
451:
452: int do_decomp = 0;
453:
454: void main( argc, argv )
455: REGISTER int argc; char **argv;
456: {
457: int overwrite = 0; /* Do not overwrite unless given -f flag */
458: char tempname[100];
459: char filesw, **filelist, **fileptr;
460: char *cp;extern char *strrchr(), *malloc();
461: struct stat statbuf;
462: #ifndef METAWARE
463: extern void onintr(), oops();
464: if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
465: signal ( SIGINT, onintr );
466: signal ( SIGSEGV, oops );
467: }
468: #endif
469:
470: setbuf(stdout, outbuf);
471: #ifdef AZTEC86
472: #ifdef METAWARE
473: _setmode(NULL,_ALL_FILES_BINARY);
474: _setmode(stdin,_BINARY);
475: _setmode(stdout,_BINARY);
476: _setmode(stderr,_TEXT);
477: #endif
478: #endif /* AZTEC86 */
479:
480: #ifdef COMPATIBLE
481: nomagic = 1; /* Original didn't have a magic number */
482: #endif /* COMPATIBLE */
483:
484: fileptr = filelist = (char **)(malloc((unsigned)(argc * sizeof(*argv))));
485: *fileptr = NULL;
486: filesw = 0;
487:
488: if((cp = strrchr(argv[0], SLASH)) != 0) {
489: cp++;
490: } else {
491: cp = argv[0];
492: }
493: if(strcmp(cp, "uncompress") == 0) {
494: do_decomp = 1;
495: } else if(strcmp(cp, "zcat") == 0) {
496: do_decomp = 1;
497: zcat_flg = 1;
498: }
499:
500: #ifdef BSD4_2
501: /* 4.2BSD dependent - take it out if not */
502: setlinebuf( stderr );
503: #endif /* BSD4_2 */
504:
505: /* Argument Processing
506: * All flags are optional.
507: * -D => debug
508: * -V => print Version; debug verbose
509: * -d => do_decomp
510: * -v => unquiet
511: * -f => force overwrite of output file
512: * -n => no header: useful to uncompress old files
513: * -b maxbits => maxbits. If -b is specified, then maxbits MUST be
514: * given also.
515: * -c => cat all output to stdout
516: * -w workfile => use workfile for virtual work.
517: * -C => generate output compatible with compress 2.0.
518: * if a string is left, must be an input filename.
519: */
520: for (argc--, argv++; argc > 0; argc--, argv++)
521: {
522: if (**argv == '-')
523: { /* A flag argument */
524: while (*++(*argv))
525: { /* Process all flags in this arg */
526: switch (**argv)
527: {
528: #ifdef DEBUG
529: case 'D':
530: debug = 1;
531: break;
532: case 'V':
533: verbose = 1;
534: version();
535: break;
536: #else
537: case 'V':
538: version();
539: break;
540: #endif /* DEBUG */
541: case 'v':
542: quiet = 0;
543: break;
544: case 'd':
545: do_decomp = 1;
546: break;
547: case 'f':
548: case 'F':
549: overwrite = 1;
550: force = 1;
551: break;
552: case 'n':
553: nomagic = 1;
554: break;
555: case 'C':
556: block_compress = 0;
557: break;
558: case 'b':
559: if (!ARGVAL())
560: {
561: fprintf(stderr, "Missing maxbits\n");
562: Usage();
563: myExit(1);
564: }
565: maxbits = atoi(*argv);
566: goto nextarg;
567: #ifdef VIRTUAL
568: case 'w':
569: if(!ARGVAL()) {
570: fprintf(stderr, "Missing workfile\n");
571: Usage();
572: myExit(1);
573: }
574: tmpn = *argv;
575: goto nextarg;
576: #endif
577: case 'c':
578: zcat_flg = 1;
579: break;
580: case 'q':
581: quiet = 1;
582: break;
583: default:
584: fprintf(stderr, "Unknown flag: '%c'; ", **argv);
585: Usage();
586: myExit(1);
587: }
588: }
589: }
590: else
591: { /* Input file name */
592: *fileptr++ = *argv; /* Build input file list */
593: *fileptr = NULL;
594: filesw = 1;
595: /* process nextarg; */
596: }
597: nextarg: continue;
598: }
599:
600: if(maxbits < INIT_BITS) maxbits = INIT_BITS;
601: #if BITS == 16
602: if (maxbits > 15) maxbits = 15;
603: #else
604: if (maxbits > BITS) maxbits = BITS;
605: #endif
606: maxmaxcode = 1L << maxbits;
607:
608: #ifndef VIRTUAL
609: if (NULL == (htab = (count_int *)malloc((unsigned)HTABSIZE)))
610: {
611: fprintf(stderr,"Can't allocate htab\n");
612: exit(1);
613: }
614: if (NULL == (codetab = (unsigned short *)malloc((unsigned)CODETABSIZE)))
615: {
616: fprintf(stderr,"Can't allocate codetab\n");
617: exit(1);
618: }
619: #endif /* VIRTUAL */
620:
621: if (filesw)
622: {
623: for (fileptr = filelist; *fileptr; fileptr++)
624: {
625: exit_stat = 0;
626: if (do_decomp != 0)
627: { /* DECOMPRESSION */
628: /* Check for .Z suffix */
629: #ifndef DOS
630: if (strcmp(*fileptr + strlen(*fileptr) - 2,
631: dotz) != 0)
632: #else
633: if (strcmp(*fileptr + strlen(*fileptr) - 1,
634: dotz) != 0)
635: #endif
636: {
637: /* No .Z: tack one on */
638: strcpy(tempname, *fileptr);
639: #ifndef DOS
640: strcat(tempname, dotz);
641: #else
642: /* either tack one on or replace last character */
643: {
644: char *dot;extern char *strchr();
645: if (NULL == (dot = strchr(tempname,'.'))) {
646: strcat(tempname, dotz);
647: }
648: else
649: /* if there is a dot then either tack a z on
650: or replace last character */
651: {
652: if (strlen(dot) < 4)
653: strcat(dot, dotz + 1);
654: else
655: strcpy(dot, dotz);
656: }
657: }
658: #endif
659: *fileptr = tempname;
660: }
661: /* Open input file */
662: if ((freopen(*fileptr, "rb", stdin)) == NULL)
663: {
664: perror(*fileptr); continue;
665: }
666: /* Check the magic number */
667: if (nomagic == 0)
668: {
669: unsigned magic1, magic2;
670: if (((magic1 = getc(stdin)) != (magic_header[0] & 0xFF))
671: || ((magic2 = getc(stdin)) != (magic_header[1] & 0xFF)))
672: {
673: fprintf(stderr,
674: "%s: not in compressed format %x %x\n",
675: *fileptr,magic1,magic2);
676: continue;
677: }
678: maxbits = getc(stdin); /* set -b from file */
679: block_compress = maxbits & BLOCK_MASK;
680: maxbits &= BIT_MASK;
681: maxmaxcode = 1L << maxbits;
682: if(maxbits > BITS)
683: {
684: fprintf(stderr,
685: "%s: compressed with %d bits, can only handle %d bits\n",
686: *fileptr, maxbits, BITS);
687: continue;
688: }
689: }
690: /* Generate output filename */
691: strcpy(ofname, *fileptr);
692: #ifndef DOS
693: ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
694: #else
695: /* kludge to handle various common three character extension */
696: {
697: char *dot; extern char *strchr();
698: char fixup = '\0';
699: /* first off, map name to upper case */
700: for (dot = ofname; *dot; dot++)
701: *dot = toupper(*dot);
702: if (NULL == (dot = strchr(ofname,'.')))
703: {
704: fprintf(stderr,"Bad filename %s\n",ofname);
705: myExit(1);
706: }
707: if (strlen(dot) == 4)
708: /* we got three letter extensions */
709: {
710: if (strcmp(dot,".EXZ") == 0)
711: fixup = 'E';
712: else if (strcmp(dot,".COZ") == 0)
713: fixup = 'M';
714: else if (strcmp(dot,".BAZ") == 0)
715: fixup = 'S';
716: else if (strcmp(dot,".OBZ") == 0)
717: fixup = 'J';
718: else if (strcmp(dot,".SYZ") == 0)
719: fixup = 'S';
720: else if (strcmp(dot,".DOZ") == 0)
721: fixup = 'C';
722:
723: }
724: /* replace the Z */
725: ofname[strlen(*fileptr) - 1] = fixup;
726: }
727: #endif
728: } else
729: { /* COMPRESSION */
730: if (strcmp(*fileptr + strlen(*fileptr) - 2, dotz) == 0)
731: {
732: fprintf(stderr, "%s: already has .Z suffix -- no change\n",
733: *fileptr);
734: continue;
735: }
736: /* Open input file */
737: if ((freopen(*fileptr, "rb", stdin)) == NULL)
738: {
739: perror(*fileptr); continue;
740: }
741: (void)stat( *fileptr, &statbuf );
742: fsize = (long) statbuf.st_size;
743: /*
744: * tune hash table size for small files
745: * -- ad hoc,
746: * but the sizes match earlier #defines, which
747: * serve as upper bounds on the number of
748: * output codes.
749: */
750: hsize = HSIZE; /*lint -e506 -e712 */
751: if ( (12 >= maxbits) || fsize < (1 << 12) )
752: hsize = min ( 5003, HSIZE );
753: else if ( (13 == maxbits) || fsize < (1 << 13) )
754: hsize = min ( 9001, HSIZE );
755: else if ( (14 == maxbits) || fsize < (1 << 14) )
756: hsize = min ( 18013, HSIZE );
757: else if ( (15 == maxbits) || fsize < (1 << 15) )
758: hsize = min ( 35023L, HSIZE );
759: else if ( fsize < 47000L )
760: hsize = min ( 50021L, HSIZE ); /*lint +e506 +e712 */
761:
762: /* Generate output filename */
763: strcpy(ofname, *fileptr);
764: #ifndef BSD4_2 /* Short filenames */
765: if ((cp=strrchr(ofname,SLASH)) != NULL)
766: cp++;
767: else
768: cp = ofname;
769: if (strlen(cp) > 12)
770: {
771: fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
772: continue;
773: }
774: #ifdef DOS
775: else
776: {
777: /* either tack one on or replace last character */
778: char *dot;extern char *strchr();
779: if (NULL == (dot = strchr(cp,'.')))
780: {
781: strcat(cp, dotz);
782: }
783: else
784: /* if there is a dot then either tack a z on
785: or replace last character */
786: {
787: if (strlen(dot) < 4)
788: strcat(dot, dotz + 1);
789: else
790: strcpy(dot, dotz);
791: }
792: }
793: #endif
794: #endif /* BSD4_2 Long filenames allowed */
795: #ifndef DOS
796: /* DOS takes care of this above */
797: strcat(ofname, dotz);
798: #endif
799: }
800: /* Check for overwrite of existing file */
801: if (overwrite == 0 && zcat_flg == 0)
802: {
803: if (stat(ofname, &statbuf) == 0)
804: {
805: char response[2]; int fd;
806: response[0] = 'n';
807: fprintf(stderr, "%s already exists;", ofname);
808: if (foreground())
809: {
810: fd = open("/dev/tty", 0);
811: fprintf(stderr,
812: " do you wish to overwrite %s (y or n)? ", ofname);
813: fflush(stderr);
814: (void)read(fd, response, 2);
815: while (response[1] != '\n')
816: {
817: if (read(fd, response+1, 1) < 0)
818: { /* Ack! */
819: perror("stderr");
820: break;
821: }
822: }
823: close(fd);
824: }
825: if (response[0] != 'y')
826: {
827: fprintf(stderr, "\tnot overwritten\n");
828: continue;
829: }
830: }
831: }
832:
833: if(zcat_flg == 0)
834: { /* Open output file */
835: if (freopen(ofname, "wb", stdout) == NULL)
836: {
837: perror(ofname);
838: continue;
839: }
840: if(!quiet)
841: fprintf(stderr, "%s: ", *fileptr);
842: }
843:
844: /* Actually do the compression/decompression */
845: if (do_decomp == 0)
846: compress();
847: #ifndef DEBUG
848: else
849: decompress();
850: #else
851: else if (debug == 0)
852: decompress();
853: else
854: printcodes();
855:
856: if (verbose)
857: dump_tab();
858: #endif /* DEBUG */
859: if(zcat_flg == 0)
860: {
861: copystat(*fileptr, ofname); /* Copy stats */
862:
863: if((exit_stat == 1) || (!quiet))
864: putc('\n', stderr);
865:
866: if(!exit_stat) /* kill old version */
867: unlink(*fileptr);
868: }
869: }
870: } else
871: { /* Standard input */
872: if (do_decomp == 0)
873: {
874: #ifdef VIRTUAL
875: if(12 >= maxbits)
876: hsize = HSIZE12;
877: #endif
878: compress();
879: #ifdef DEBUG
880: if(verbose) dump_tab();
881: #endif /* DEBUG */
882: if(!quiet)
883: putc('\n', stderr);
884: } else
885: {
886: /* Check the magic number */
887: if (nomagic == 0)
888: {
889: if ((getc(stdin)!=(magic_header[0] & 0xFF))
890: || (getc(stdin)!=(magic_header[1] & 0xFF)))
891: {
892: fprintf(stderr, "stdin: not in compressed format\n");
893: myExit(1);
894: }
895: maxbits = getc(stdin); /* set -b from file */
896: block_compress = maxbits & BLOCK_MASK;
897: maxbits &= BIT_MASK;
898: maxmaxcode = 1L << maxbits;
899: fsize = 100000L; /* assume stdin large for USERMEM */
900: if(maxbits > BITS)
901: {
902: fprintf(stderr,
903: "stdin: compressed with %d bits, can only handle %d bits\n",
904: maxbits, BITS);
905: myExit(1);
906: }
907: }
908: #ifndef DEBUG
909: decompress();
910: #else
911: if (debug == 0) decompress();
912: else printcodes();
913: if (verbose) dump_tab();
914: #endif /* DEBUG */
915: }
916: }
917: myExit(exit_stat);
918: }
919:
920: static int offset;
921: long in_count = 1; /* length of input */
922: long bytes_out; /* length of compressed output */
923: long out_count = 0; /* # of codes output (for debugging) */
924:
925: /*
926: * compress stdin to stdout
927: *
928: * Algorithm: use open addressing double hashing (no chaining) on the
929: * prefix code / next character combination. We do a variant of Knuth's
930: * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
931: * secondary probe. Here, the modular division first probe is gives way
932: * to a faster exclusive-or manipulation. Also do block compression with
933: * an adaptive reset, whereby the code table is cleared when the compression
934: * ratio decreases, but after the table fills. The variable-length output
935: * codes are re-sized at this point, and a special CLEAR code is generated
936: * for the decompressor. Late addition: construct the table according to
937: * file size for noticeable speed improvement on small files. Please direct
938: * questions about this implementation to ames!jaw.
939: */
940:
941: void compress()
942: {
943: REGISTER long fcode;
944: REGISTER code_int i = 0;
945: REGISTER int c;
946: REGISTER code_int ent;
947: REGISTER long disp;
948: code_int hsize_reg;
949: int hshift;
950:
951: #ifdef VIRTUAL
952: initV((long)HTABSIZE, (long)CODETABSIZE);
953: #endif
954:
955: #ifndef COMPATIBLE
956: if (nomagic == 0)
957: {
958: putc(magic_header[0],stdout);
959: putc(magic_header[1],stdout);
960: putc((char)(maxbits | block_compress),stdout);
961: if(ferror(stdout))
962: writeerr();
963: }
964: #endif /* COMPATIBLE */
965:
966: offset = 0;
967: bytes_out = 3; /* includes 3-byte header mojo */
968: out_count = 0;
969: clear_flg = 0;
970: ratio = 0;
971: in_count = 1;
972: checkpoint = CHECK_GAP;
973: maxcode = MAXCODE(n_bits = INIT_BITS);
974: free_ent = ((block_compress) ? FIRST : 256 );
975:
976: ent = getc(stdin);
977:
978: hshift = 0;
979: for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
980: hshift++;
981: hshift = 8 - hshift; /* set hash code range bound */
982:
983: hsize_reg = hsize;
984: cl_hash( (count_int) hsize_reg); /* clear hash table */
985:
986: #ifdef SIGNED_COMPARE_SLOW
987: while ( (c = getc(stdin)) != (unsigned) EOF )
988: #else
989: while ( (c = getc(stdin)) != EOF )
990: #endif
991: {
992: in_count++;
993: fcode = (long) (((long) c << maxbits) + ent);
994: i = ((c << hshift) ^ ent); /* xor hashing */
995:
996: if ( htabof (i) == fcode )
997: {
998: ent = codetabof (i);
999: continue;
1000: } else if ( (long)htabof (i) < 0 ) /* empty slot */
1001: goto nomatch;
1002: disp = hsize_reg - i; /* secondary hash (after G. Knott) */
1003: if ( i == 0 )
1004: disp = 1;
1005: probe:
1006: if ( (i -= disp) < 0 )
1007: i += hsize_reg;
1008:
1009: if ( htabof (i) == fcode )
1010: {
1011: ent = codetabof (i);
1012: continue;
1013: }
1014: if ( (long)htabof (i) > 0 )
1015: goto probe;
1016: nomatch:
1017: output ( (code_int) ent );
1018: out_count++;
1019: ent = c;
1020: #ifdef SIGNED_COMPARE_SLOW
1021: if ( (unsigned) free_ent < (unsigned) maxmaxcode)
1022: #else
1023: if ( free_ent < maxmaxcode )
1024: #endif
1025: {
1026: setcodtab (i, free_ent++); /* code -> hashtable */
1027: sethtab (i, fcode);
1028: }
1029: else if ( (count_int)in_count >= checkpoint && block_compress )
1030: cl_block ();
1031: }
1032: /*
1033: * Put out the final code.
1034: */
1035: output( (code_int)ent );
1036: out_count++;
1037: output( (code_int)-1 );
1038:
1039: /*
1040: * Print out stats on stderr
1041: */
1042: if(zcat_flg == 0 && !quiet)
1043: {
1044: #ifdef DEBUG
1045: fprintf( stderr,
1046: "%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
1047: in_count, out_count, bytes_out );
1048: prratio( stderr, in_count, bytes_out );
1049: fprintf( stderr, "\n");
1050: fprintf( stderr, "\tCompression as in compact: " );
1051: prratio( stderr, in_count-bytes_out, in_count );
1052: fprintf( stderr, "\n");
1053: fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
1054: free_ent - 1, n_bits );
1055: #else /* !DEBUG */
1056: fprintf( stderr, "Compression: " );
1057: prratio( stderr, in_count-bytes_out, in_count );
1058: #endif /* DEBUG */
1059: }
1060: if(bytes_out > in_count) /* exit(2) if no savings */
1061: exit_stat = 2;
1062: return;
1063: }
1064:
1065: /*****************************************************************
1066: * TAG( output )
1067: *
1068: * Output the given code.
1069: * Inputs:
1070: * code: A n_bits-bit integer. If == -1, then EOF. This assumes
1071: * that n_bits =< (long)wordsize - 1.
1072: * Outputs:
1073: * Outputs code to the file.
1074: * Assumptions:
1075: * Chars are 8 bits long.
1076: * Algorithm:
1077: * Maintain a BITS character long buffer (so that 8 codes will
1078: * fit in it exactly). Use the VAX insv instruction to insert each
1079: * code in turn. When the buffer fills up empty it and start over.
1080: */
1081:
1082: static char buf[BITS];
1083:
1084: #ifndef vax
1085: char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
1086: char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
1087: #endif /* vax */
1088: void output( code )
1089: code_int code;
1090: {
1091: #ifdef DEBUG
1092: static int col = 0;
1093: #endif /* DEBUG */
1094:
1095: /*
1096: * On the VAX, it is important to have the REGISTER declarations
1097: * in exactly the order given, or the asm will break.
1098: */
1099: REGISTER int r_off = offset, bits= n_bits;
1100: REGISTER char * bp = buf;
1101: #ifndef BREAKHIGHC
1102: #ifdef METAWARE
1103: int temp;
1104: #endif
1105: #endif
1106: #ifdef DEBUG
1107: if ( verbose )
1108: fprintf( stderr, "%5d%c", code,
1109: (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
1110: #endif /* DEBUG */
1111: if ( code >= 0 )
1112: {
1113: #ifdef vax
1114: /* VAX DEPENDENT!! Implementation on other machines is below.
1115: *
1116: * Translation: Insert BITS bits from the argument starting at
1117: * offset bits from the beginning of buf.
1118: */
1119: 0; /* Work around for pcc -O bug with asm and if stmt */
1120: asm( "insv 4(ap),r11,r10,(r9)" );
1121: #else /* not a vax */
1122: /*
1123: * byte/bit numbering on the VAX is simulated by the following code
1124: */
1125: /*
1126: * Get to the first byte.
1127: */
1128: bp += (r_off >> 3);
1129: r_off &= 7;
1130: /*
1131: * Since code is always >= 8 bits, only need to mask the first
1132: * hunk on the left.
1133: */
1134: #ifndef BREAKHIGHC
1135: #ifdef METAWARE
1136: *bp &= rmask[r_off];
1137: temp = (code << r_off) & lmask[r_off];
1138: *bp |= temp;
1139: #else
1140: *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
1141: #endif
1142: #else
1143: *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
1144: #endif
1145: bp++;
1146: bits -= (8 - r_off);
1147: code >>= (8 - r_off);
1148: /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
1149: if ( bits >= 8 )
1150: {
1151: *bp++ = code;
1152: code >>= 8;
1153: bits -= 8;
1154: }
1155: /* Last bits. */
1156: if(bits)
1157: *bp = code;
1158: #endif /* vax */
1159: offset += n_bits;
1160: if ( offset == (n_bits << 3) )
1161: {
1162: bp = buf;
1163: bits = n_bits;
1164: bytes_out += bits;
1165: do
1166: putc(*bp++,stdout);
1167: while(--bits);
1168: offset = 0;
1169: }
1170:
1171: /*
1172: * If the next entry is going to be too big for the code size,
1173: * then increase it, if possible.
1174: */
1175: if ( free_ent > maxcode || (clear_flg > 0))
1176: {
1177: /*
1178: * Write the whole buffer, because the input side won't
1179: * discover the size increase until after it has read it.
1180: */
1181: if ( offset > 0 )
1182: {
1183: if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
1184: writeerr();
1185: bytes_out += n_bits;
1186: }
1187: offset = 0;
1188:
1189: if ( clear_flg )
1190: {
1191: maxcode = MAXCODE (n_bits = INIT_BITS);
1192: clear_flg = 0;
1193: }
1194: else
1195: {
1196: n_bits++;
1197: if ( n_bits == maxbits )
1198: maxcode = maxmaxcode;
1199: else
1200: maxcode = MAXCODE(n_bits);
1201: }
1202: #ifdef DEBUG
1203: if ( debug )
1204: {
1205: fprintf( stderr, "\nChange to %d bits\n", n_bits );
1206: col = 0;
1207: }
1208: #endif /* DEBUG */
1209: }
1210: } else
1211: {
1212: /*
1213: * At EOF, write the rest of the buffer.
1214: */
1215: if ( offset > 0 )
1216: fwrite( buf, 1, (offset + 7) / 8, stdout );
1217: bytes_out += (offset + 7) / 8;
1218: offset = 0;
1219: fflush( stdout );
1220: #ifdef DEBUG
1221: if ( verbose )
1222: fprintf( stderr, "\n" );
1223: #endif /* DEBUG */
1224: if( ferror( stdout ) )
1225: writeerr();
1226: }
1227: }
1228: /*
1229: * Decompress stdin to stdout. This routine adapts to the codes in the
1230: * file building the "string" table on-the-fly; requiring no table to
1231: * be stored in the compressed file. The tables used herein are shared
1232: * with those of the compress() routine. See the definitions above.
1233: */
1234:
1235: void decompress() {
1236: REGISTER char_type *stackp;
1237: REGISTER long finchar;
1238: REGISTER code_int code, oldcode, incode;
1239:
1240: #ifdef VIRTUAL
1241: initV((long)HTABSIZE, (long)CODETABSIZE);
1242: #endif
1243:
1244: /*
1245: * As above, initialize the first 256 entries in the table.
1246: */
1247: maxcode = MAXCODE(n_bits = INIT_BITS);
1248: for ( code = 255; code >= 0; code-- ) {
1249: setcodtab(code, 0);
1250: setsuffix(code, code);
1251: }
1252: free_ent = ((block_compress) ? FIRST : 256 );
1253:
1254: finchar = oldcode = getcode();
1255: if(oldcode == -1) /* EOF already? */
1256: return; /* Get out of here */
1257: putc( (char)finchar,stdout ); /* first code must be 8 bits = char */
1258: if(ferror(stdout)) /* Crash if can't write */
1259: writeerr();
1260: stackp = de_stack;
1261:
1262: while ( (code = getcode()) > -1 ) {
1263:
1264: if ( (code == CLEAR) && block_compress ) {
1265: for ( code = 255; code >= 0; code-- )
1266: setcodtab(code, 0);
1267: clear_flg = 1;
1268: free_ent = FIRST - 1;
1269: if ( (code = getcode ()) == -1 ) /* O, untimely death! */
1270: break;
1271: }
1272: incode = code;
1273: /*
1274: * Special case for KwKwK string.
1275: */
1276: if ( code >= free_ent ) {
1277: *stackp++ = finchar;
1278: code = oldcode;
1279: }
1280:
1281: /*
1282: * Generate output characters in reverse order
1283: */
1284: #ifdef SIGNED_COMPARE_SLOW
1285: while ( ((unsigned long)code) >= ((unsigned long)256) ) {
1286: #else
1287: while ( code >= 256 ) {
1288: #endif
1289: *stackp++ = tab_suffixof(code);
1290: code = tab_prefixof(code);
1291: }
1292: *stackp++ = finchar = tab_suffixof(code);
1293:
1294: /*
1295: * And put them out in forward order
1296: */
1297: do
1298: putc ( *--stackp ,stdout);
1299: while ( stackp > de_stack );
1300:
1301: /*
1302: * Generate the new entry.
1303: */
1304: if ( (code=free_ent) < maxmaxcode )
1305: {
1306: setcodtab(code, oldcode);
1307: setsuffix(code, finchar);
1308: free_ent = code+1;
1309: }
1310: /*
1311: * Remember previous code.
1312: */
1313: oldcode = incode;
1314: }
1315: if(ferror(stdout))
1316: writeerr();
1317: }
1318:
1319: /*****************************************************************
1320: * TAG( getcode )
1321: *
1322: * Read one code from the standard input. If EOF, return -1.
1323: * Inputs:
1324: * stdin
1325: * Outputs:
1326: * code or -1 is returned.
1327: */
1328:
1329: code_int
1330: getcode()
1331: {
1332: /*
1333: * On the VAX, it is important to have the REGISTER declarations
1334: * in exactly the order given, or the asm will break.
1335: */
1336: REGISTER code_int code;
1337: static int offset = 0, size = 0;
1338: static char_type buf[BITS];
1339: REGISTER int r_off, bits;
1340: REGISTER char_type *bp = buf;
1341:
1342: if ( clear_flg > 0 || offset >= size || free_ent > maxcode )
1343: {
1344: /*
1345: * If the next entry will be too big for the current code
1346: * size, then we must increase the size. This implies reading
1347: * a new buffer full, too.
1348: */
1349: if ( free_ent > maxcode )
1350: {
1351: n_bits++;
1352: if ( n_bits == maxbits )
1353: maxcode = maxmaxcode; /* won't get any bigger now */
1354: else
1355: maxcode = MAXCODE(n_bits);
1356: }
1357: if ( clear_flg > 0)
1358: {
1359: maxcode = MAXCODE (n_bits = INIT_BITS);
1360: clear_flg = 0;
1361: }
1362: size = fread( buf, 1, n_bits, stdin );
1363: if ( size <= 0 )
1364: return -1; /* end of file */
1365: offset = 0;
1366: /* Round size down to integral number of codes */
1367: size = (size << 3) - (n_bits - 1);
1368: }
1369: r_off = offset;
1370: bits = n_bits;
1371: #ifdef vax
1372: asm( "extzv r10,r9,(r8),r11" );
1373: #else /* not a vax */
1374: /*
1375: * Get to the first byte.
1376: */
1377: bp += (r_off >> 3);
1378: r_off &= 7;
1379: /* Get first part (low order bits) */
1380: #ifdef NO_UCHAR
1381: code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
1382: #else
1383: code = (*bp++ >> r_off);
1384: #endif /* NO_UCHAR */
1385: bits -= (8 - r_off);
1386: r_off = 8 - r_off; /* now, offset into code word */
1387: /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
1388: if ( bits >= 8 )
1389: {
1390: #ifdef NO_UCHAR
1391: code |= (*bp++ & 0xff) << r_off;
1392: #else
1393: code |= *bp++ << r_off;
1394: #endif /* NO_UCHAR */
1395: r_off += 8;
1396: bits -= 8;
1397: }
1398: /* high order bits. */
1399: code |= (*bp & rmask[bits]) << r_off;
1400: #endif /* vax */
1401: offset += n_bits;
1402:
1403: return code;
1404: }
1405:
1406: #ifndef METAWARE
1407: #ifdef DEBUG
1408: printcodes()
1409: {
1410: /*
1411: * Just print out codes from input file. For debugging.
1412: */
1413: code_int code;
1414: int col = 0, bits;
1415:
1416: bits = n_bits = INIT_BITS;
1417: maxcode = MAXCODE(n_bits);
1418: free_ent = ((block_compress) ? FIRST : 256 );
1419: while ( ( code = getcode() ) >= 0 ) {
1420: if ( (code == CLEAR) && block_compress ) {
1421: free_ent = FIRST - 1;
1422: clear_flg = 1;
1423: }
1424: else if ( free_ent < maxmaxcode )
1425: free_ent++;
1426: if ( bits != n_bits ) {
1427: fprintf(stderr, "\nChange to %d bits\n", n_bits );
1428: bits = n_bits;
1429: col = 0;
1430: }
1431: fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
1432: }
1433: putc( '\n', stderr );
1434: myExit( 0 );
1435: }
1436: #ifdef DEBUG2
1437: code_int sorttab[1<<BITS]; /* sorted pointers into htab */
1438: #define STACK_SIZE 500
1439: static char stack[STACK_SIZE];
1440: /* dumptab doesn't use main stack now -prevents distressing crashes */
1441: dump_tab() /* dump string table */
1442: {
1443: REGISTER int i, first;
1444: REGISTER long ent;
1445: int stack_top = STACK_SIZE;
1446: REGISTER c;
1447:
1448: if(do_decomp == 0) { /* compressing */
1449: REGISTER int flag = 1;
1450:
1451: for(i=0; i<hsize; i++) { /* build sort pointers */
1452: if((long)htabof(i) >= 0) {
1453: sorttab[codetabof(i)] = i;
1454: }
1455: }
1456: first = block_compress ? FIRST : 256;
1457: for(i = first; i < free_ent; i++) {
1458: fprintf(stderr, "%5d: \"", i);
1459: stack[--stack_top] = '\n';
1460: stack[--stack_top] = '"'; /* " */
1461: stack_top = in_stack((int)(htabof(sorttab[i])>>maxbits)&0xff,
1462: stack_top);
1463: for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
1464: ent > 256;
1465: ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
1466: stack_top = in_stack((int)(htabof(sorttab[ent]) >> maxbits),
1467: stack_top);
1468: }
1469: stack_top = in_stack(ent, stack_top);
1470: fwrite( &stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
1471: stack_top = STACK_SIZE;
1472: }
1473: } else if(!debug) { /* decompressing */
1474:
1475: for ( i = 0; i < free_ent; i++ ) {
1476: ent = i;
1477: c = tab_suffixof(ent);
1478: if ( isascii(c) && isprint(c) )
1479: fprintf( stderr, "%5d: %5d/'%c' \"",
1480: ent, tab_prefixof(ent), c );
1481: else
1482: fprintf( stderr, "%5d: %5d/\\%03o \"",
1483: ent, tab_prefixof(ent), c );
1484: stack[--stack_top] = '\n';
1485: stack[--stack_top] = '"'; /* " */
1486: for ( ; ent != NULL;
1487: ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
1488: stack_top = in_stack(tab_suffixof(ent), stack_top);
1489: }
1490: fwrite( &stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
1491: stack_top = STACK_SIZE;
1492: }
1493: }
1494: }
1495:
1496: int
1497: in_stack(c, stack_top)
1498: REGISTER int c, stack_top;
1499: {
1500: if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
1501: stack[--stack_top] = c;
1502: } else {
1503: switch( c ) {
1504: case '\n': stack[--stack_top] = 'n'; break;
1505: case '\t': stack[--stack_top] = 't'; break;
1506: case '\b': stack[--stack_top] = 'b'; break;
1507: case '\f': stack[--stack_top] = 'f'; break;
1508: case '\r': stack[--stack_top] = 'r'; break;
1509: case '\\': stack[--stack_top] = '\\'; break;
1510: default:
1511: stack[--stack_top] = '0' + c % 8;
1512: stack[--stack_top] = '0' + (c / 8) % 8;
1513: stack[--stack_top] = '0' + c / 64;
1514: break;
1515: }
1516: stack[--stack_top] = '\\';
1517: }
1518: if (stack_top<0) {
1519: fprintf(stderr,"dump_tab stack overflow!!!\n");
1520: myExit(1);
1521: }
1522: return stack_top;
1523: }
1524: #else
1525: dump_tab() {}
1526: #endif /* DEBUG2 */
1527: #endif /* DEBUG */
1528: #endif /* METAWARE */
1529:
1530: void writeerr()
1531: {
1532: perror ( ofname );
1533: unlink ( ofname );
1534: myExit ( 1 );
1535: }
1536:
1537: void copystat(ifname, ofname)
1538: char *ifname, *ofname;
1539: {
1540: struct stat statbuf;
1541: int mode;
1542: #ifndef AZTEC86
1543: time_t timep[2];
1544: #else
1545: unsigned long timep[2];
1546: #endif
1547: fflush(stdout);
1548: close(fileno(stdout));
1549: if (stat(ifname, &statbuf))
1550: { /* Get stat on input file */
1551: perror(ifname);
1552: return;
1553: }
1554: #ifndef DOS
1555: /* meddling with UNIX-style file modes */
1556: if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/)
1557: {
1558: if(quiet)
1559: fprintf(stderr, "%s: ", ifname);
1560: fprintf(stderr, " -- not a regular file: unchanged");
1561: exit_stat = 1;
1562: } else if (statbuf.st_nlink > 1)
1563: {
1564: if(quiet)
1565: fprintf(stderr, "%s: ", ifname);
1566: fprintf(stderr, " -- has %d other links: unchanged",
1567: statbuf.st_nlink - 1);
1568: exit_stat = 1;
1569: } else
1570: #endif
1571: if (exit_stat == 2 && (!force))
1572: { /* No compression: remove file.Z */
1573: if(!quiet)
1574: fprintf(stderr, " -- file unchanged");
1575: } else
1576: { /* ***** Successful Compression ***** */
1577: exit_stat = 0;
1578: mode = statbuf.st_mode & 07777;
1579:
1580: if (chmod(ofname, mode)) /* Copy modes */
1581: perror(ofname);
1582: #ifndef DOS
1583: chown(ofname, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */
1584: timep[0] = statbuf.st_atime;
1585: timep[1] = statbuf.st_mtime;
1586: #else
1587: timep[0] = statbuf.st_mtime;
1588: timep[1] = statbuf.st_mtime;
1589: #endif
1590: utime(ofname, timep); /* Update last accessed and modified times */
1591:
1592: if(!quiet)
1593: if(do_decomp == 0)
1594: fprintf(stderr, " -- compressed to %s", ofname);
1595: else
1596: fprintf(stderr, " -- decompressed to %s", ofname);
1597: return; /* Successful return */
1598: }
1599:
1600: /* Unsuccessful return -- one of the tests failed */
1601: if (unlink(ofname))
1602: perror(ofname);
1603: }
1604: /*
1605: * This routine returns 1 if we are running in the foreground and stderr
1606: * is a tty.
1607: */
1608: int foreground()
1609: {
1610: #ifndef METAWARE
1611: if(bgnd_flag) { /* background? */
1612: return(0);
1613: } else { /* foreground */
1614: #endif
1615: if(isatty(2)) { /* and stderr is a tty */
1616: return(1);
1617: } else {
1618: return(0);
1619: }
1620: #ifndef METAWARE
1621: }
1622: #endif
1623: }
1624:
1625: closeRam()
1626: {
1627: if(ramsw) {
1628: close(tmpf);
1629: tmpf = open("/dev/ram1close", 0);
1630: close(tmpf);
1631: }
1632: }
1633:
1634: myExit(n)
1635: {
1636: closeRam();
1637: exit(n);
1638: }
1639:
1640: #ifndef METAWARE
1641: void onintr ( )
1642: {
1643: (void)signal(SIGINT,SIG_IGN);
1644: unlink ( ofname );
1645: myExit ( 1 );
1646: }
1647:
1648: void oops ( ) /* wild pointer -- assume bad input */
1649: {
1650: (void)signal(SIGSEGV,SIG_IGN);
1651: if ( do_decomp == 1 )
1652: fprintf ( stderr, "uncompress: corrupt input\n" );
1653: unlink ( ofname );
1654: myExit ( 1 );
1655: }
1656: #endif
1657: void cl_block () /* table clear for block compress */
1658: {
1659: REGISTER long rat;
1660:
1661: checkpoint = in_count + CHECK_GAP;
1662: #ifdef DEBUG
1663: if ( debug ) {
1664: fprintf ( stderr, "count: %ld, ratio: ", in_count );
1665: prratio ( stderr, in_count, bytes_out );
1666: fprintf ( stderr, "\n");
1667: }
1668: #endif /* DEBUG */
1669:
1670: if(in_count > 0x007fffffL) { /* shift will overflow */
1671: rat = bytes_out >> 8;
1672: if(rat == 0) { /* Don't divide by zero */
1673: rat = 0x7fffffffL;
1674: } else {
1675: rat = in_count / rat;
1676: }
1677: } else {
1678: rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
1679: }
1680: if ( rat > ratio ) {
1681: ratio = rat;
1682: } else {
1683: ratio = 0;
1684: #ifdef DEBUG
1685: if(verbose)
1686: dump_tab(); /* dump string table */
1687: #endif
1688: cl_hash ( (count_int) hsize );
1689: free_ent = FIRST;
1690: clear_flg = 1;
1691: output ( (code_int) CLEAR );
1692: #ifdef DEBUG
1693: if(debug)
1694: fprintf ( stderr, "clear\n" );
1695: #endif /* DEBUG */
1696: }
1697: }
1698:
1699: void cl_hash(hsize) /* reset code table */
1700: REGISTER count_int hsize;
1701: {
1702: #ifdef AZTEC86
1703: #ifdef VIRTUAL
1704: REGISTER count_int i;
1705:
1706: for(i = 0; i < hsize; i++)
1707: sethtab(i, -1L);
1708: #else /* VIRTUAL */
1709: #ifdef DOS
1710: memset(htab,-1,(int)(hsize * sizeof(count_int)));
1711: #else
1712: /* MINIX and all non-PC machines do it this way */
1713: REGISTER count_int *htab_p = htab+hsize;
1714: REGISTER long i;
1715: REGISTER long m1 = -1;
1716:
1717: i = hsize - 16;
1718: do
1719: { /* might use Sys V memset(3) here */
1720: *(htab_p-16) = m1;
1721: *(htab_p-15) = m1;
1722: *(htab_p-14) = m1;
1723: *(htab_p-13) = m1;
1724: *(htab_p-12) = m1;
1725: *(htab_p-11) = m1;
1726: *(htab_p-10) = m1;
1727: *(htab_p-9) = m1;
1728: *(htab_p-8) = m1;
1729: *(htab_p-7) = m1;
1730: *(htab_p-6) = m1;
1731: *(htab_p-5) = m1;
1732: *(htab_p-4) = m1;
1733: *(htab_p-3) = m1;
1734: *(htab_p-2) = m1;
1735: *(htab_p-1) = m1;
1736: htab_p -= 16;
1737: } while ((i -= 16) >= 0);
1738: for ( i += 16; i > 0; i-- )
1739: *--htab_p = m1;
1740: #endif
1741: #endif
1742: #endif
1743: }
1744:
1745: void prratio(stream, num, den)
1746: FILE *stream;
1747: long num, den;
1748: {
1749: REGISTER int q; /* Doesn't need to be long */
1750: if(num > 214748L)
1751: { /* 2147483647/10000 */
1752: q = (int)(num / (den / 10000L));
1753: } else
1754: {
1755: q = (int)(10000L * num / den); /* Long calculations, though */
1756: }
1757: if (q < 0)
1758: {
1759: putc('-', stream);
1760: q = -q;
1761: }
1762: fprintf(stream, "%d.%02d%c", q / 100, q % 100, '%');
1763: }
1764:
1765: void version()
1766: {
1767: fprintf(stderr, "%s\n", rcs_ident);
1768: fprintf(stderr, "Options: ");
1769: #ifdef VIRTUAL
1770: fprintf(stderr, "VIRTUAL, ");
1771: #endif
1772: #ifdef vax
1773: fprintf(stderr, "vax, ");
1774: #endif
1775: #ifdef MINIX
1776: fprintf(stderr, "MINIX, ");
1777: #endif
1778: #ifdef NO_UCHAR
1779: fprintf(stderr, "NO_UCHAR, ");
1780: #endif
1781: #ifdef SIGNED_COMPARE_SLOW
1782: fprintf(stderr, "SIGNED_COMPARE_SLOW, ");
1783: #endif
1784: #ifdef COMPATIBLE
1785: fprintf(stderr, "COMPATIBLE, ");
1786: #endif
1787: #ifdef DEBUG
1788: fprintf(stderr, "DEBUG, ");
1789: #endif
1790: #ifdef BSD4_2
1791: fprintf(stderr, "BSD4_2, ");
1792: #endif
1793: fprintf(stderr, "BITS = %d\n", BITS);
1794: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.