|
|
1.1 root 1: /* Set USERMEM to the maximum amount of physical user memory available
2: * in bytes. USERMEM is used to determine the maximum BITS that can be used
3: * for compression. If USERMEM is big enough, use fast compression algorithm.
4: *
5: * SACREDMEM is the amount of physical memory saved for others; compress
6: * will hog the rest.
7: */
8: #ifndef SACREDMEM
9: #define SACREDMEM 0
10: #endif
11:
12: #ifdef pdp11
13: # define BITS 12 /* max bits/code for 16-bit machine */
14: # define NO_UCHAR /* also if "unsigned char" functions as signed char */
15: # define SHORT_INT /* ints are short */
16: # undef USERMEM
17: #else !pdp11
18: # ifndef USERMEM
19: # define USERMEM 750000 /* default user memory */
20: # endif
21: #endif !pdp11
22: /*
23: * Define FBITS for machines with several MB of physical memory, to use
24: * table lookup for (b <= FBITS). If FBITS is made too large, performance
25: * will decrease due to increased swapping/paging. Since the program minus
26: * the fast lookup table is about a half Meg, we can allocate the rest of
27: * available physical memory to the fast lookup table.
28: *
29: * If FBITS is set to 12, a 2 MB array is allocated, but only 1 MB is
30: * addressed for parity-free input (i.e. text).
31: *
32: * FBITS=10 yields 1/2 meg lookup table + 4K code memory
33: * FBITS=11 yields 1 meg lookup table + 8K code memory
34: * FBITS=12 yields 2 meg lookup table + 16K code memory
35: * FBITS=13 yields 4 meg lookup table + 32K code memory
36: *
37: */
38:
39: #ifdef USERMEM
40: # if USERMEM >= (2621440+SACREDMEM)
41: # if USERMEM >= (4718592+SACREDMEM)
42: # define FBITS 13
43: # define PBITS 16
44: # else 2.5M <= USERMEM < 4.5M
45: # define FBITS 12
46: # define PBITS 16
47: # endif USERMEM <=> 4.5M
48: # else USERMEM < 2.5M
49: # if USERMEM >= (1572864+SACREDMEM)
50: # define FBITS 11
51: # define PBITS 16
52: # else USERMEM < 1.5M
53: # if USERMEM >= (1048576+SACREDMEM)
54: # define FBITS 10
55: # define PBITS 16
56: # else USERMEM < 1M
57: # if USERMEM >= (631808+SACREDMEM)
58: # define PBITS 16
59: # else
60: # if USERMEM >= (329728+SACREDMEM)
61: # define PBITS 15
62: # else
63: # if USERMEM >= (178176+SACREDMEM)
64: # define PBITS 14
65: # else
66: # if USERMEM >= (99328+SACREDMEM)
67: # define PBITS 13
68: # else
69: # define PBITS 12
70: # endif
71: # endif
72: # endif
73: # endif
74: # undef USERMEM
75: # endif USERMEM <=> 1M
76: # endif USERMEM <=> 1.5M
77: # endif USERMEM <=> 2.5M
78: #endif USERMEM
79:
80: #ifdef PBITS /* Preferred BITS for this memory size */
81: # ifndef BITS
82: # define BITS PBITS
83: # endif BITS
84: #endif PBITS
85:
86: #if BITS == 16
87: # define HSIZE 69001 /* 95% occupancy */
88: #endif
89: #if BITS == 15
90: # define HSIZE 35023 /* 94% occupancy */
91: #endif
92: #if BITS == 14
93: # define HSIZE 18013 /* 91% occupancy */
94: #endif
95: #if BITS == 13
96: # define HSIZE 9001 /* 91% occupancy */
97: #endif
98: #if BITS == 12
99: # define HSIZE 5003 /* 80% occupancy */
100: #endif
101: #if BITS == 11
102: # define HSIZE 2591 /* 79% occupancy */
103: #endif
104: #if BITS == 10
105: # define HSIZE 1291 /* 79% occupancy */
106: #endif
107: #if BITS == 9
108: # define HSIZE 691 /* 74% occupancy */
109: #endif
110: /* BITS < 9 will cause an error */
111:
112: /*
113: * a code_int must be able to hold 2**BITS values of type int, and also -1
114: */
115: #if BITS > 15
116: typedef long int code_int;
117: #else
118: typedef int code_int;
119: #endif
120:
121: #ifdef interdata
122: typedef unsigned long int count_int;
123: typedef unsigned short int count_short;
124: #else
125: typedef long int count_int;
126: #endif
127:
128: #ifdef NO_UCHAR
129: typedef char char_type;
130: #else UCHAR
131: typedef unsigned char char_type;
132: #endif UCHAR
133: char_type magic_header[] = { "\037\235" }; /* 1F 9D */
134:
135: /* Defines for third byte of header */
136: #define BIT_MASK 0x1f
137: #define BLOCK_MASK 0x80
138: /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
139: a fourth header byte (for expansion).
140: */
141: #define INIT_BITS 9 /* initial number of bits/code */
142:
143: /*
144: * compress.c - File compression ala IEEE Computer June 1984.
145: *
146: * Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
147: * Jim McKie (decvax!mcvax!jim)
148: * Steve Davies (decvax!vax135!petsd!peora!srd)
149: * Ken Turkowski (decvax!decwrl!turtlevax!ken)
150: * James A. Woods (decvax!ihnp4!ames!jaw)
151: * Joe Orost (decvax!vax135!petsd!joe)
152: *
153: * $Header: compress.c,v 3.0 84/11/27 11:50:00 joe Exp $
154: * $Log: compress.c,v $
155: * Revision 3.0 84/11/27 11:50:00 petsd!joe
156: * Set HSIZE depending on BITS. Set BITS depending on USERMEM. Unrolled
157: * loops in clear routines. Added "-C" flag for 2.0 compatability. Used
158: * unsigned compares on Perkin-Elmer. Fixed foreground check.
159: *
160: * Revision 2.7 84/11/16 19:35:39 ames!jaw
161: * Cache common hash codes based on input statistics; this improves
162: * performance for low-density raster images. Pass on #ifdef bundle
163: * from Turkowski.
164: *
165: * Revision 2.6 84/11/05 19:18:21 ames!jaw
166: * Vary size of hash tables to reduce time for small files.
167: * Tune PDP-11 hash function.
168: *
169: * Revision 2.5 84/10/30 20:15:14 ames!jaw
170: * Junk chaining; replace with the simpler (and, on the VAX, faster)
171: * double hashing, discussed within. Make block compression standard.
172: *
173: * Revision 2.4 84/10/16 11:11:11 ames!jaw
174: * Introduce adaptive reset for block compression, to boost the rate
175: * another several percent. (See mailing list notes.)
176: *
177: * Revision 2.3 84/09/22 22:00:00 petsd!joe
178: * Implemented "-B" block compress. Implemented REVERSE sorting of tab_next.
179: * Bug fix for last bits. Changed fwrite to putchar loop everywhere.
180: *
181: * Revision 2.2 84/09/18 14:12:21 ames!jaw
182: * Fold in news changes, small machine typedef from thomas,
183: * #ifdef interdata from joe.
184: *
185: * Revision 2.1 84/09/10 12:34:56 ames!jaw
186: * Configured fast table lookup for 32-bit machines.
187: * This cuts user time in half for b <= FBITS, and is useful for news batching
188: * from VAX to PDP sites. Also sped up decompress() [fwrite->putc] and
189: * added signal catcher [plus beef in writeerr()] to delete effluvia.
190: *
191: * Revision 2.0 84/08/28 22:00:00 petsd!joe
192: * Add check for foreground before prompting user. Insert maxbits into
193: * compressed file. Force file being uncompressed to end with ".Z".
194: * Added "-c" flag and "zcat". Prepared for release.
195: *
196: * Revision 1.10 84/08/24 18:28:00 turtlevax!ken
197: * Will only compress regular files (no directories), added a magic number
198: * header (plus an undocumented -n flag to handle old files without headers),
199: * added -f flag to force overwriting of possibly existing destination file,
200: * otherwise the user is prompted for a response. Will tack on a .Z to a
201: * filename if it doesn't have one when decompressing. Will only replace
202: * file if it was compressed.
203: *
204: * Revision 1.9 84/08/16 17:28:00 turtlevax!ken
205: * Removed scanargs(), getopt(), added .Z extension and unlimited number of
206: * filenames to compress. Flags may be clustered (-Ddvb12) or separated
207: * (-D -d -v -b 12), or combination thereof. Modes and other status is
208: * copied with copystat(). -O bug for 4.2 seems to have disappeared with
209: * 1.8.
210: *
211: * Revision 1.8 84/08/09 23:15:00 joe
212: * Made it compatible with vax version, installed jim's fixes/enhancements
213: *
214: * Revision 1.6 84/08/01 22:08:00 joe
215: * Sped up algorithm significantly by sorting the compress chain.
216: *
217: * Revision 1.5 84/07/13 13:11:00 srd
218: * Added C version of vax asm routines. Changed structure to arrays to
219: * save much memory. Do unsigned compares where possible (faster on
220: * Perkin-Elmer)
221: *
222: * Revision 1.4 84/07/05 03:11:11 thomas
223: * Clean up the code a little and lint it. (Lint complains about all
224: * the regs used in the asm, but I'm not going to "fix" this.)
225: *
226: * Revision 1.3 84/07/05 02:06:54 thomas
227: * Minor fixes.
228: *
229: * Revision 1.2 84/07/05 00:27:27 thomas
230: * Add variable bit length output.
231: *
232: */
233: #ifndef lint
234: static char rcs_ident[] = "$Header: compress.c,v 3.0 84/11/27 11:50:00 joe Exp $";
235: #endif !lint
236:
237: #include <stdio.h>
238: #include <ctype.h>
239: #include <signal.h>
240: #include <sys/types.h>
241: #include <sys/stat.h>
242:
243: #define ARGVAL() (*++(*argv) || (--argc && *++argv))
244:
245: int n_bits; /* number of bits/code */
246: int maxbits = BITS; /* user settable max # bits/code */
247: code_int maxcode; /* maximum code, given n_bits */
248: code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */
249: #ifdef COMPATIBLE /* But wrong! */
250: # define MAXCODE(n_bits) (1 << (n_bits) - 1)
251: #else COMPATIBLE
252: # define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
253: #endif COMPATIBLE
254:
255: /*
256: * One code could conceivably represent (1<<BITS) characters, but
257: * to get a code of length N requires an input string of at least
258: * N*(N-1)/2 characters. With 5000 chars in the stack, an input
259: * file would have to contain a 25Mb string of a single character.
260: * This seems unlikely.
261: */
262: #ifdef SHORT_INT
263: # define MAXSTACK 5000 /* size of output stack */
264: #else !SHORT_INT
265: # define MAXSTACK 8000 /* size of output stack */
266: #endif !SHORT_INT
267:
268: count_int htab [HSIZE];
269: unsigned short codetab [HSIZE];
270: code_int hsize = HSIZE; /* for dynamic table sizing */
271: count_int fsize;
272:
273: #define tab_prefix codetab /* prefix code for this entry */
274: char_type tab_suffix[1<<BITS]; /* last char in this entry */
275:
276: #ifdef USERMEM
277: short ftable [(1 << FBITS) * 256];
278: count_int fcodemem [1 << FBITS];
279: #endif USERMEM
280:
281: code_int free_ent = 0; /* first unused entry */
282: int exit_stat = 0;
283:
284: code_int getcode();
285:
286: Usage() {
287: #ifdef DEBUG
288: fprintf(stderr,"Usage: compress [-dDvqfFc] [-b maxbits] [file ...]\n");
289: }
290: int debug = 0;
291: #else DEBUG
292: fprintf(stderr,"Usage: compress [-dfFqc] [-b maxbits] [file ...]\n");
293: }
294: #endif DEBUG
295: int nomagic = 0; /* Use a 2 byte magic number header, unless old file */
296: int zcat_flg = 0; /* Write output on stdout, suppress messages */
297: int quiet = 0; /* don't tell me about compression */
298:
299: /*
300: * block compression parameters -- after all codes are used up,
301: * and compression rate changes, start over.
302: */
303: int block_compress = BLOCK_MASK;
304: int clear_flg = 0;
305: double ratio = 0.0; /* compression ratio for last block */
306: #define CHECK_GAP 10000 /* ratio check interval */
307: count_int checkpoint = CHECK_GAP;
308: /*
309: * the next two codes should not be changed lightly, as they must not
310: * lie within the contiguous general code space.
311: */
312: #define FIRST 257 /* first free entry */
313: #define CLEAR 256 /* table clear output code */
314:
315: int force = 0;
316: char ofname [100];
317: #ifdef DEBUG
318: int verbose = 0;
319: #endif DEBUG
320: int (*bgnd_flag)();
321:
322: /*****************************************************************
323: * TAG( main )
324: *
325: * Algorithm from "A Technique for High Performance Data Compression",
326: * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
327: *
328: * Usage: compress [-dfFqc] [-b bits] [file ...]
329: * Inputs:
330: * -d: If given, decompression is done instead.
331: *
332: * -c: Write output on stdout, don't remove original.
333: *
334: * -b: Parameter limits the max number of bits/code.
335: *
336: * -f: Forces output file to be generated, even if one already
337: * exists; if -f is not used, the user will be prompted if
338: * the stdin is a tty, otherwise, the output file will not
339: * be overwritten.
340: *
341: * -F: Forces output file to be generated, even if no space is
342: * saved by compressing.
343: *
344: * -q: No output, unless error
345: *
346: * file ...: Files to be compressed. If none specified, stdin
347: * is used.
348: * Outputs:
349: * file.Z: Compressed form of file with same mode, owner, and utimes
350: * or stdout (if stdin used as input)
351: *
352: * Assumptions:
353: * When filenames are given, replaces with the compressed version
354: * (.Z suffix) only if the file decreased in size.
355: * Algorithm:
356: * Modified Lempel-Ziv method (LZW). Basically finds common
357: * substrings and replaces them with a variable size code. This is
358: * deterministic, and can be done on the fly. Thus, the decompression
359: * procedure needs no input table, but tracks the way the table was
360: * built.
361: */
362:
363: main( argc, argv )
364: register int argc; char **argv;
365: {
366: int do_decomp = 0;
367: int overwrite = 0; /* Do not overwrite unless given -f flag */
368: char tempname[100];
369: char **filelist, **fileptr;
370: char *cp, *rindex();
371: struct stat statbuf;
372: extern onintr();
373:
374:
375: if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN )
376: signal ( SIGINT, onintr );
377:
378: #ifdef COMPATIBLE
379: nomagic = 1; /* Original didn't have a magic number */
380: #endif COMPATIBLE
381:
382: filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
383: *filelist = NULL;
384:
385: if((cp = rindex(argv[0], '/')) != 0) {
386: cp++;
387: } else {
388: cp = argv[0];
389: }
390: if(strcmp(cp, "uncompress") == 0) {
391: do_decomp = 1;
392: } else if(strcmp(cp, "zcat") == 0) {
393: do_decomp = 1;
394: zcat_flg = 1;
395: }
396:
397: #ifdef BSD4_2
398: /* 4.2BSD dependent - take it out if not */
399: setlinebuf( stderr );
400: #endif BSD4_2
401:
402: /* Argument Processing
403: * All flags are optional.
404: * -D => debug
405: * -d => do_decomp
406: * -v => verbose
407: * -f => force overwrite of output file
408: * -n => no header: useful to uncompress old files
409: * -b maxbits => maxbits. If -b is specified, then maxbits MUST be
410: * given also.
411: * -c => cat all output to stdout
412: * -C => generate output compatable with compress 2.0.
413: * if a string is left, must be an input filename.
414: */
415: for (argc--, argv++; argc > 0; argc--, argv++) {
416: if (**argv == '-') { /* A flag argument */
417: while (*++(*argv)) { /* Process all flags in this arg */
418: switch (**argv) {
419: #ifdef DEBUG
420: case 'D':
421: debug = 1;
422: break;
423: case 'v':
424: verbose = 1;
425: break;
426: #endif DEBUG
427: case 'd':
428: do_decomp = 1;
429: break;
430: case 'f':
431: overwrite = 1;
432: break;
433: case 'n':
434: nomagic = 1;
435: break;
436: case 'C':
437: block_compress = 0;
438: break;
439: case 'b':
440: if (!ARGVAL()) {
441: fprintf(stderr, "Missing maxbits\n");
442: Usage();
443: exit(1);
444: }
445: maxbits = atoi(*argv);
446: goto nextarg;
447: case 'c':
448: zcat_flg = 1;
449: break;
450: case 'q':
451: quiet = 1;
452: break;
453: case 'F':
454: force = 1;
455: break;
456: default:
457: fprintf(stderr, "Unknown flag: '%c'; ", **argv);
458: Usage();
459: exit(1);
460: }
461: }
462: }
463: else { /* Input file name */
464: *fileptr++ = *argv; /* Build input file list */
465: *fileptr = NULL;
466: /* goto nextarg; */
467: }
468: nextarg: continue;
469: }
470:
471: if(maxbits < INIT_BITS) maxbits = INIT_BITS;
472: if (maxbits > BITS) maxbits = BITS;
473: maxmaxcode = 1 << maxbits;
474:
475: if (*filelist != NULL) {
476: for (fileptr = filelist; *fileptr; fileptr++) {
477: exit_stat = 0;
478: if (do_decomp != 0) { /* DECOMPRESSION */
479: /* Check for .Z suffix */
480: if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
481: /* No .Z: tack one on */
482: strcpy(tempname, *fileptr);
483: strcat(tempname, ".Z");
484: *fileptr = tempname;
485: }
486: /* Open input file */
487: if ((freopen(*fileptr, "r", stdin)) == NULL) {
488: perror(*fileptr); continue;
489: }
490: /* Check the magic number */
491: if (nomagic == 0) {
492: if ((getchar() != (magic_header[0] & 0xFF))
493: || (getchar() != (magic_header[1] & 0xFF))) {
494: fprintf(stderr, "%s: not in compressed format\n",
495: *fileptr);
496: continue;
497: }
498: maxbits = getchar(); /* set -b from file */
499: block_compress = maxbits & BLOCK_MASK;
500: maxbits &= BIT_MASK;
501: maxmaxcode = 1 << maxbits;
502: if(maxbits > BITS) {
503: fprintf(stderr,
504: "%s: compressed with %d bits, can only handle %d bits\n",
505: *fileptr, maxbits, BITS);
506: continue;
507: }
508: }
509: /* Generate output filename */
510: strcpy(ofname, *fileptr);
511: ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
512: } else { /* COMPRESSION */
513: if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
514: fprintf(stderr, "%s: already has .Z suffix -- no change\n",
515: *fileptr);
516: continue;
517: }
518: /* Open input file */
519: if ((freopen(*fileptr, "r", stdin)) == NULL) {
520: perror(*fileptr); continue;
521: }
522: stat ( *fileptr, &statbuf );
523: fsize = (long) statbuf.st_size;
524: /*
525: * tune hash table size for small files -- ad hoc
526: */
527: #if HSIZE > 5003
528: if ( fsize < (1 << 12) )
529: hsize = 5003;
530: #if HSIZE > 9001
531: else if ( fsize < (1 << 13) )
532: hsize = 9001;
533: #if HSIZE > 18013
534: else if ( fsize < (1 << 14) )
535: hsize = 18013;
536: #if HSIZE > 35023
537: else if ( fsize < (1 << 15) )
538: hsize = 35023;
539: else if ( fsize < 47000 )
540: hsize = 50021;
541: #endif HSIZE > 35023
542: #endif HSIZE > 18013
543: #endif HSIZE > 9001
544: else
545: #endif HSIZE > 5003
546: hsize = HSIZE;
547: /* Generate output filename */
548: strcpy(ofname, *fileptr);
549: #ifndef BSD4_2 /* Short filenames */
550: if ((cp=rindex(ofname,'/')) != NULL) cp++;
551: else cp = ofname;
552: if (strlen(cp) > 12) {
553: fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
554: continue;
555: }
556: #endif BSD4_2 /* Long filenames allowed */
557: strcat(ofname, ".Z");
558: }
559: /* Check for overwrite of existing file */
560: if (overwrite == 0 && zcat_flg == 0) {
561: if (stat(ofname, &statbuf) == 0) {
562: char response[2];
563: response[0] = 'n';
564: fprintf(stderr, "%s already exists;", ofname);
565: if (foreground()) {
566: fprintf(stderr, " do you wish to overwrite (y or n)? ",
567: ofname);
568: fflush(stderr);
569: read(2, response, 2);
570: while (response[1] != '\n') {
571: if (read(2, response+1, 1) < 0) { /* Ack! */
572: perror("stderr"); break;
573: }
574: }
575: }
576: if (response[0] != 'y') {
577: fprintf(stderr, "\tnot overwritten\n");
578: continue;
579: }
580: }
581: }
582: if(zcat_flg == 0) { /* Open output file */
583: if (freopen(ofname, "w", stdout) == NULL) {
584: perror(ofname);
585: continue;
586: }
587: if(!quiet)
588: fprintf(stderr, "%s: ", *fileptr);
589: }
590:
591: /* Actually do the compression/decompression */
592: if (do_decomp == 0) compress();
593: #ifndef DEBUG
594: else decompress();
595: #else DEBUG
596: else if (debug == 0) decompress();
597: else printcodes();
598: if (verbose) dump_tab();
599: #endif DEBUG
600: if(zcat_flg == 0) {
601: copystat(*fileptr, ofname); /* Copy stats */
602: if(exit_stat || (!quiet))
603: putc('\n', stderr);
604: }
605: }
606: } else { /* Standard input */
607: if (do_decomp == 0) {
608: compress();
609: if(!quiet)
610: putc('\n', stderr);
611: } else {
612: /* Check the magic number */
613: if (nomagic == 0) {
614: if ((getchar()!=(magic_header[0] & 0xFF))
615: || (getchar()!=(magic_header[1] & 0xFF))) {
616: fprintf(stderr, "stdin: not in compressed format\n");
617: exit(1);
618: }
619: maxbits = getchar(); /* set -b from file */
620: block_compress = maxbits & BLOCK_MASK;
621: maxbits &= BIT_MASK;
622: maxmaxcode = 1 << maxbits;
623: fsize = 100000; /* assume stdin large for USERMEM */
624: if(maxbits > BITS) {
625: fprintf(stderr,
626: "stdin: compressed with %d bits, can only handle %d bits\n",
627: maxbits, BITS);
628: exit(1);
629: }
630: }
631: #ifndef DEBUG
632: decompress();
633: #else DEBUG
634: if (debug == 0) decompress();
635: else printcodes();
636: if (verbose) dump_tab();
637: #endif DEBUG
638: }
639: }
640: exit(exit_stat);
641: }
642:
643: static int offset;
644: long int in_count = 1; /* length of input */
645: long int bytes_out; /* length of compressed output */
646: long int out_count = 0; /* # of codes output (for debugging) */
647:
648: #define HOG_CHECK ((count_int) 2000) /* Number of chars to read b4 check */
649: #define MAX_CACHE ((count_int) 1<<BITS) /* Next line is this constant too */
650: unsigned short hashcache [1<<BITS]; /* common hash short circuit cache */
651: count_int cfreq [256]; /* character counts */
652: #ifndef vax
653: char chog; /* most common character from input */
654: # define CHOG ' ' /* Assume space is most frequent */
655: #else
656: int chog; /* char arith slow on VAX */
657: # define CHOG (int) ' ' /* Assume space is most frequent */
658: #endif
659: int cstat_flg = 0; /* on after determining char hog */
660:
661: /*
662: * compress stdin to stdout
663: *
664: * Algorithm: on large machines, for maxbits <= FBITS, use fast direct table
665: * lookup on the prefix code / next character combination. For smaller code
666: * size, use open addressing modular division double hashing (no chaining), ala
667: * Knuth vol. 3, sec. 6.4 Algorithm D, along with G. Knott's relatively-prime
668: * secondary probe. Do block compression with an adaptive reset, whereby the
669: * code table is cleared when the compression ratio decreases, but after the
670: * table fills. The variable-length output codes are re-sized at this point,
671: * and a special CLEAR code is generated for the decompressor. For the
672: * megamemory version, the sparse array is cleared indirectly through a
673: * "shadow" output code history. Late additions: for the hashing code,
674: * construct the table according to file size for noticeable speed improvement
675: * on small files. Also detect and cache codes associated with the most
676: * common character to bypass hash calculation on these codes (a characteristic
677: * of highly-compressable raster images). Please direct questions about this
678: * implementation to ames!jaw.
679: */
680:
681:
682: compress() {
683: register long fcode;
684: register code_int i = 0;
685: register int c;
686: register code_int ent;
687: register int disp;
688: register code_int hsize_reg;
689:
690: #ifndef COMPATIBLE
691: if (nomagic == 0) {
692: putchar(magic_header[0]); putchar(magic_header[1]);
693: putchar((char)(maxbits | block_compress));
694: }
695: #endif COMPATIBLE
696:
697: offset = 0;
698: bytes_out = 0;
699: out_count = 0;
700: clear_flg = 0;
701: ratio = 0.0;
702: in_count = 1;
703: checkpoint = CHECK_GAP;
704: maxcode = MAXCODE(n_bits = INIT_BITS);
705: free_ent = ((block_compress) ? FIRST : 256 );
706: ent = getchar ();
707:
708: #ifdef USERMEM
709: if ( maxbits <= FBITS && (fsize >= 30000) ) { /* use hashing on small files */
710:
711: while ( (c = getchar()) != (unsigned) EOF ) {
712: in_count++;
713: fcode = (long) (((long) c << maxbits) + ent);
714: if ( ftable [fcode] != 0 ) /* test for code in "string" table */
715: ent = ftable [fcode];
716: else {
717: output ( (code_int) ent );
718: out_count++;
719: ent = c;
720: if ( free_ent >= maxmaxcode ) {
721: if ( (count_int)in_count < checkpoint || (!block_compress) )
722: continue;
723: else {
724: clear ();
725: i = 0;
726: }
727: } else { /* put code in table */
728: ftable [fcode] = (short) free_ent++;
729: fcodemem [i++] = fcode; /* memorize for block compression */
730: }
731: }
732: }
733: goto fin;
734: }
735: #endif USERMEM
736:
737: chog = CHOG; /* assumed character for the hog */
738: cstat_flg = 0;
739: hsize_reg = hsize;
740: cl_hash(hsize_reg); /* clear hash tables */
741:
742: while ( (c = getchar()) != (unsigned) EOF ) {
743: in_count++;
744: if ( cstat_flg == 0 ) {
745: cfreq [c]++; /* gather frequencies at start of input */
746: if ( (count_int)in_count > HOG_CHECK ) {
747: cstat_flg = 1;
748: chog = hogtally(); /* compute char hog */
749: if(chog != CHOG) /* fixup for wrong assumption */
750: creset( (count_int) free_ent );
751: }
752: }
753: if ( c == chog )
754: if ( (i = hashcache [ent]) ) { /* cache -> code */
755: ent = i;
756: continue;
757: }
758: fcode = (long) (((long) c << maxbits) + ent);
759: #ifdef SHORT_INT
760: i = (((c + 12347) * ent) & 077777) % HSIZE; /* avoid 'lrem' call */
761: #else !SHORT_INT
762: i = fcode % hsize_reg; /* division hashing */
763: #endif SHORT_INT
764:
765: if ( htab [i] == fcode ) {
766: ent = codetab [i];
767: continue;
768: } else if ( (long)htab [i] < 0 ) /* empty slot */
769: goto nomatch;
770: disp = hsize_reg - i; /* secondary hash (G. Knott) */
771: if ( i == 0 )
772: disp = 1;
773: probe:
774: if ( (i -= disp) < 0 )
775: i += hsize_reg;
776:
777: if ( htab [i] == fcode ) {
778: ent = codetab [i];
779: continue;
780: }
781: if ( (long)htab [i] > 0 )
782: goto probe;
783: nomatch:
784: output ( (code_int) ent );
785: out_count++;
786: #ifdef interdata
787: if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
788: #else
789: if ( free_ent < maxmaxcode ) {
790: #endif
791: if ( c == chog ) /* code -> cache */
792: hashcache [ent] = free_ent;
793: /* code -> hashtable */
794: codetab [i] = free_ent++;
795: htab [i] = fcode;
796: }
797: else if ( (count_int)in_count >= checkpoint && block_compress )
798: clear ();
799: ent = c;
800: }
801: fin:
802: /*
803: * Put out the final code.
804: */
805: output( (code_int)ent );
806: out_count++;
807: output( (code_int)-1 );
808:
809: /*
810: * Print out stats on stderr
811: */
812: if(zcat_flg == 0 && !quiet) {
813: #ifdef DEBUG
814: fprintf( stderr,
815: "%ld chars in, %ld codes (%ld bytes) out, compression factor %g\n",
816: in_count, out_count, bytes_out,
817: (double)in_count / (double)bytes_out );
818: fprintf( stderr, "\tCompression as in compact: %5.2f%%\n",
819: 100.0 * ( in_count - bytes_out ) / (double) in_count );
820: fprintf( stderr, "\tLargest code was %d (%d bits)\n", free_ent - 1, n_bits );
821: #else DEBUG
822: fprintf( stderr, "Compression: %5.2f%%",
823: 100.0 * ( in_count - bytes_out ) / (double) in_count );
824: #endif DEBUG
825: }
826: if(bytes_out > in_count) /* exit(2) if no savings */
827: exit_stat = 2;
828: return;
829: }
830:
831: /*****************************************************************
832: * TAG( output )
833: *
834: * Output the given code.
835: * Inputs:
836: * code: A n_bits-bit integer. If == -1, then EOF. This assumes
837: * that n_bits =< (long)wordsize - 1.
838: * Outputs:
839: * Outputs code to the file.
840: * Assumptions:
841: * Chars are 8 bits long.
842: * Algorithm:
843: * Maintain a BITS character long buffer (so that 8 codes will
844: * fit in it exactly). Use the VAX insv instruction to insert each
845: * code in turn. When the buffer fills up empty it and start over.
846: */
847:
848: static char buf[BITS];
849:
850: #ifndef vax
851: char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
852: char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
853: #endif !vax
854:
855: output( code )
856: code_int code;
857: {
858: #ifdef DEBUG
859: static int col = 0;
860: #endif DEBUG
861:
862: /*
863: * On the VAX, it is important to have the register declarations
864: * in exactly the order given, or the asm will break.
865: */
866: register int r_off = offset, bits= n_bits;
867: register char * bp = buf;
868:
869: if ( code >= 0 ) {
870: #ifdef DEBUG
871: if ( verbose )
872: fprintf( stderr, "%5d%c", code,
873: (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
874: #endif DEBUG
875: #ifdef vax
876: /* VAX DEPENDENT!! Implementation on other machines may be
877: * difficult.
878: *
879: * Translation: Insert BITS bits from the argument starting at
880: * offset bits from the beginning of buf.
881: */
882: 0; /* C compiler bug ?? */
883: asm( "insv 4(ap),r11,r10,(r9)" );
884: #else not a vax
885: /* WARNING: byte/bit numbering on the vax is simulated by the following code
886: */
887: /*
888: * Get to the first byte.
889: */
890: bp += (r_off >> 3);
891: r_off &= 7;
892: /*
893: * Since code is always >= 8 bits, only need to mask the first
894: * hunk on the left.
895: */
896: *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
897: bp++;
898: bits -= (8 - r_off);
899: code >>= 8 - r_off;
900: /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
901: if ( bits >= 8 ) {
902: *bp++ = code;
903: code >>= 8;
904: bits -= 8;
905: }
906: /* Last bits. */
907: if(bits)
908: *bp = code;
909: #endif vax
910: offset += n_bits;
911: if ( offset == (n_bits << 3) ) {
912: bp = buf;
913: bits = n_bits;
914: bytes_out += bits;
915: do
916: putchar(*bp++);
917: while(--bits);
918: if (ferror(stdout))
919: writeerr();
920: offset = 0;
921: }
922:
923: /*
924: * If the next entry is going to be too big for the code size,
925: * then increase it, if possible.
926: */
927: if ( free_ent > maxcode || (clear_flg > 0)) {
928: /*
929: * Write the whole buffer, because the input side won't
930: * discover the size increase until after it has read it.
931: */
932: if ( offset > 0 ) {
933: if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
934: writeerr();
935: bytes_out += n_bits;
936: }
937: offset = 0;
938:
939: if ( clear_flg ) {
940: maxcode = MAXCODE (n_bits = INIT_BITS);
941: clear_flg = 0;
942: } else {
943: n_bits++;
944: if ( n_bits == maxbits )
945: maxcode = maxmaxcode;
946: else
947: maxcode = MAXCODE(n_bits);
948: }
949: #ifdef DEBUG
950: if ( debug ) {
951: fprintf( stderr, "\nChange to %d bits\n", n_bits );
952: col = 0;
953: }
954: #endif DEBUG
955: }
956: } else {
957: /*
958: * At EOF, write the rest of the buffer.
959: */
960: if ( offset > 0 )
961: fwrite( buf, 1, (offset + 7) / 8, stdout );
962: bytes_out += (offset + 7) / 8;
963: offset = 0;
964: fflush( stdout );
965: #ifdef DEBUG
966: if ( verbose )
967: fprintf( stderr, "\n" );
968: #endif DEBUG
969: if( ferror( stdout ) )
970: writeerr();
971: }
972: }
973:
974: decompress() {
975: register int stack_top = MAXSTACK;
976: register code_int code, oldcode, incode;
977: register int finchar;
978: char stack[MAXSTACK];
979:
980: /*
981: * As above, initialize the first 256 entries in the table.
982: */
983: maxcode = MAXCODE(n_bits = INIT_BITS);
984: for ( code = 255; code >= 0; code-- ) {
985: tab_prefix[code] = 0;
986: tab_suffix[code] = (char_type)code;
987: }
988: free_ent = ((block_compress) ? FIRST : 256 );
989:
990: finchar = oldcode = getcode();
991: putchar( (char)finchar ); /* first code must be 8 bits = char */
992:
993: while ( (code = getcode()) != -1 ) {
994:
995: if ( (code == CLEAR) && block_compress ) {
996: for ( code = 255; code > 0; code -= 4 ) {
997: tab_prefix [code-3] = 0;
998: tab_prefix [code-2] = 0;
999: tab_prefix [code-1] = 0;
1000: tab_prefix [code] = 0;
1001: }
1002: clear_flg = 1;
1003: free_ent = FIRST - 1;
1004: if ( (code = getcode ()) == -1 ) /* O, untimely death! */
1005: break;
1006: }
1007: incode = code;
1008: /*
1009: * Special case for KwKwK string.
1010: */
1011: if ( code >= free_ent ) {
1012: stack[--stack_top] = finchar;
1013: code = oldcode;
1014: }
1015:
1016: /*
1017: * Generate output characters in reverse order
1018: */
1019: #ifdef interdata
1020: while ( ((unsigned long)code) >= ((unsigned long)256) ) {
1021: #else !interdata
1022: while ( code >= 256 ) {
1023: #endif interdata
1024: stack[--stack_top] = tab_suffix[code];
1025: code = tab_prefix[code];
1026: }
1027: stack[--stack_top] = finchar = tab_suffix[code];
1028:
1029: /*
1030: * And put them out in forward order
1031: */
1032: for ( ; stack_top < MAXSTACK; stack_top++ )
1033: putchar(stack[stack_top]);
1034: if (ferror(stdout))
1035: writeerr ( );
1036: stack_top = MAXSTACK;
1037:
1038: /*
1039: * Generate the new entry.
1040: */
1041: if ( (code=free_ent) < maxmaxcode ) {
1042: tab_prefix[code] = (unsigned short)oldcode;
1043: tab_suffix[code] = finchar;
1044: free_ent = code+1;
1045: }
1046: /*
1047: * Remember previous code.
1048: */
1049: oldcode = incode;
1050: }
1051: fflush( stdout );
1052: if(ferror(stdout))
1053: writeerr();
1054: }
1055:
1056:
1057: /*****************************************************************
1058: * TAG( getcode )
1059: *
1060: * Read one code from the standard input. If EOF, return -1.
1061: * Inputs:
1062: * stdin
1063: * Outputs:
1064: * code or -1 is returned.
1065: */
1066:
1067: code_int
1068: getcode() {
1069: /*
1070: * On the VAX, it is important to have the register declarations
1071: * in exactly the order given, or the asm will break.
1072: */
1073: register code_int code;
1074: static int offset = 0, size = 0;
1075: static char_type buf[BITS];
1076: register int r_off, bits;
1077: register char_type *bp = buf;
1078:
1079: if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
1080: /*
1081: * If the next entry will be too big for the current code
1082: * size, then we must increase the size. This implies reading
1083: * a new buffer full, too.
1084: */
1085: if ( free_ent > maxcode ) {
1086: n_bits++;
1087: if ( n_bits == maxbits )
1088: maxcode = maxmaxcode; /* won't get any bigger now */
1089: else
1090: maxcode = MAXCODE(n_bits);
1091: }
1092: if ( clear_flg > 0) {
1093: maxcode = MAXCODE (n_bits = INIT_BITS);
1094: clear_flg = 0;
1095: }
1096: size = fread( buf, 1, n_bits, stdin );
1097: if ( size <= 0 )
1098: return -1; /* end of file */
1099: offset = 0;
1100: /* Round size down to integral number of codes */
1101: size = (size << 3) - (n_bits - 1);
1102: }
1103: r_off = offset;
1104: bits = n_bits;
1105: #ifdef vax
1106: asm( "extzv r10,r9,(r8),r11" );
1107: #else not a vax
1108: /*
1109: * Get to the first byte.
1110: */
1111: bp += (r_off >> 3);
1112: r_off &= 7;
1113: /* Get first part (low order bits) */
1114: #ifdef NO_UCHAR
1115: code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
1116: #else NO_UCHAR
1117: code = (*bp++ >> r_off);
1118: #endif NO_UCHAR
1119: bits -= (8 - r_off);
1120: r_off = 8 - r_off; /* now, offset into code word */
1121: /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
1122: if ( bits >= 8 ) {
1123: #ifdef NO_UCHAR
1124: code |= (*bp++ & 0xff) << r_off;
1125: #else NO_UCHAR
1126: code |= *bp++ << r_off;
1127: #endif NO_UCHAR
1128: r_off += 8;
1129: bits -= 8;
1130: }
1131: /* high order bits. */
1132: code |= (*bp & rmask[bits]) << r_off;
1133: #endif vax
1134: offset += n_bits;
1135:
1136: return code;
1137: }
1138:
1139: char *
1140: rindex(s, c) /* For those who don't have it in libc.a */
1141: register char *s, c;
1142: {
1143: char *p;
1144: for (p = NULL; *s; s++)
1145: if (*s == c)
1146: p = s;
1147: return(p);
1148: }
1149:
1150: #ifdef DEBUG
1151: printcodes()
1152: {
1153: /*
1154: * Just print out codes from input file. Mostly for debugging.
1155: */
1156: code_int code;
1157: int col = 0, bits;
1158:
1159: bits = n_bits = INIT_BITS;
1160: maxcode = MAXCODE(n_bits);
1161: free_ent = ((block_compress) ? FIRST : 256 );
1162: while ( ( code = getcode() ) >= 0 ) {
1163: if ( (code == CLEAR) && block_compress ) {
1164: free_ent = FIRST - 1;
1165: clear_flg = 1;
1166: }
1167: else if ( free_ent < maxmaxcode )
1168: free_ent++;
1169: if ( bits != n_bits ) {
1170: fprintf(stderr, "\nChange to %d bits\n", n_bits );
1171: bits = n_bits;
1172: col = 0;
1173: }
1174: fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
1175: }
1176: putc( '\n', stderr );
1177: exit( 0 );
1178: }
1179:
1180: dump_tab() /* dump string table */
1181: {
1182: register int i;
1183: register ent;
1184: char stack[4 * MAXSTACK]; /* \nnn makes it 4 times bigger */
1185: int stack_top = 4 * MAXSTACK;
1186:
1187: for ( i = 0; i < free_ent; i++ ) {
1188: ent = i;
1189: if ( isascii(tab_suffix[ent]) && isprint(tab_suffix[ent]) )
1190: fprintf( stderr, "%5d: %5d/'%c' \"",
1191: ent, tab_prefix[ent], tab_suffix[ent] );
1192: else
1193: fprintf( stderr, "%5d: %5d/\\%03o \"",
1194: ent, tab_prefix[ent], tab_suffix[ent] );
1195: stack[--stack_top] = '\n';
1196: stack[--stack_top] = '"';
1197: for ( ; ent != NULL;
1198: ent = (ent >= FIRST ? tab_prefix[ent] : NULL) ) {
1199: if ( isascii(tab_suffix[ent]) && isprint(tab_suffix[ent]) )
1200: stack[--stack_top] = tab_suffix[ent];
1201: else {
1202: switch( tab_suffix[ent] ) {
1203: case '\n': stack[--stack_top] = 'n'; break;
1204: case '\t': stack[--stack_top] = 't'; break;
1205: case '\b': stack[--stack_top] = 'b'; break;
1206: case '\f': stack[--stack_top] = 'f'; break;
1207: case '\r': stack[--stack_top] = 'r'; break;
1208: default:
1209: stack[--stack_top] = '0' + tab_suffix[ent] % 8;
1210: stack[--stack_top] = '0' + (tab_suffix[ent] / 8) % 8;
1211: stack[--stack_top] = '0' + tab_suffix[ent] / 64;
1212: break;
1213: }
1214: stack[--stack_top] = '\\';
1215: }
1216: }
1217: fwrite( &stack[stack_top], 1, 4 * MAXSTACK - stack_top, stderr );
1218: stack_top = 4 * MAXSTACK;
1219: }
1220: }
1221: #endif DEBUG
1222:
1223: /*****************************************************************
1224: * TAG( writeerr )
1225: *
1226: * Exits with a message. We only check for write errors often enough
1227: * to avoid a lot of "file system full" messages, not on every write.
1228: * ferror() check after fflush will catch any others (I trust).
1229: *
1230: */
1231:
1232: writeerr()
1233: {
1234: perror ( ofname );
1235: unlink ( ofname );
1236: exit ( 1 );
1237: }
1238:
1239: copystat(ifname, ofname)
1240: char *ifname, *ofname;
1241: {
1242: struct stat statbuf;
1243: int mode;
1244: time_t timep[2];
1245:
1246: fclose(stdout);
1247: if (stat(ifname, &statbuf)) { /* Get stat on input file */
1248: perror(ifname);
1249: return;
1250: }
1251: if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) {
1252: if(quiet)
1253: fprintf(stderr, "%s: ", ifname);
1254: fprintf(stderr, " -- not a regular file: unchanged");
1255: exit_stat = 1;
1256: } else if (statbuf.st_nlink > 1) {
1257: if(quiet)
1258: fprintf(stderr, "%s: ", ifname);
1259: fprintf(stderr, " -- has %d other links: unchanged",
1260: statbuf.st_nlink - 1);
1261: exit_stat = 1;
1262: } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
1263: fprintf(stderr, " -- file unchanged");
1264: } else { /* ***** Successful Compression ***** */
1265: exit_stat = 0;
1266: mode = statbuf.st_mode & 07777;
1267: if (chmod(ofname, mode)) /* Copy modes */
1268: perror(ofname);
1269: chown(ofname, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */
1270: timep[0] = statbuf.st_atime;
1271: timep[1] = statbuf.st_mtime;
1272: utime(ofname, timep); /* Update last accessed and modified times */
1273: if (unlink(ifname)) /* Remove input file */
1274: perror(ifname);
1275: if(!quiet)
1276: fprintf(stderr, " -- replaced with %s", ofname);
1277: return; /* Successful return */
1278: }
1279:
1280: /* Unsuccessful return -- one of the tests failed */
1281: if (unlink(ofname))
1282: perror(ofname);
1283: }
1284: /*
1285: * This routine returns 1 if we are running in the foreground and stderr
1286: * is a tty.
1287: */
1288: foreground()
1289: {
1290: if(bgnd_flag) { /* background? */
1291: return(0);
1292: } else { /* foreground */
1293: if(isatty(2)) { /* and stderr is a tty */
1294: return(1);
1295: } else {
1296: return(0);
1297: }
1298: }
1299: }
1300:
1301: onintr ( )
1302: {
1303: unlink ( ofname );
1304: exit ( 1 );
1305: }
1306:
1307: clear () /* table clear for block compress */
1308: {
1309: register code_int i;
1310: register count_int *p, *endp;
1311: register unsigned short *q;
1312:
1313: #ifdef DEBUG
1314: if(debug)
1315: fprintf ( stderr, "count: %ld ratio: %f\n", in_count,
1316: (double) in_count / (double) bytes_out );
1317: #endif DEBUG
1318:
1319: checkpoint = in_count + CHECK_GAP;
1320: if ( (double) in_count / (double) bytes_out > ratio )
1321: ratio = (double) in_count / (double) bytes_out;
1322: else {
1323: ratio = 0.0;
1324: #ifdef USERMEM
1325: if ( maxbits <= FBITS ) /* sparse array clear */
1326: for ( i = (1 << maxbits) - 1; i >= 0; i-- )
1327: ftable [fcodemem [i]] = 0; /* indirect thru "shadow" */
1328: else
1329: #endif USERMEM /* hash table clear */
1330: {
1331: endp = &htab [hsize];
1332: for ( p = &htab [0], q = &codetab [0]; p < endp; ) {
1333: *p++ = -1;
1334: *q++ = 0;
1335: }
1336: creset ( MAX_CACHE );
1337: }
1338: free_ent = FIRST;
1339: clear_flg = 1;
1340: output ( (code_int) CLEAR );
1341: #ifdef DEBUG
1342: if(debug)
1343: fprintf ( stderr, "clear\n" );
1344: #endif DEBUG
1345: }
1346: }
1347:
1348: creset ( n ) /* clear hash cache */
1349: register count_int n; /* clear at least this many entries */
1350: {
1351: register count_int i;
1352: register unsigned short *hash_p;
1353: register unsigned short zero = 0;
1354: static int nfiles = 0;
1355:
1356: if ( nfiles++ == 0 ) /* No clear needed if first time */
1357: return;
1358: n = (n+15) & (-16);
1359: hash_p = hashcache + n;
1360: for ( i = n; i > 0; i -=16 ) {
1361: *(hash_p-16) = zero;
1362: *(hash_p-15) = zero;
1363: *(hash_p-14) = zero;
1364: *(hash_p-13) = zero;
1365: *(hash_p-12) = zero;
1366: *(hash_p-11) = zero;
1367: *(hash_p-10) = zero;
1368: *(hash_p-9) = zero;
1369: *(hash_p-8) = zero;
1370: *(hash_p-7) = zero;
1371: *(hash_p-6) = zero;
1372: *(hash_p-5) = zero;
1373: *(hash_p-4) = zero;
1374: *(hash_p-3) = zero;
1375: *(hash_p-2) = zero;
1376: *(hash_p-1) = zero;
1377: hash_p -= 16;
1378: }
1379: }
1380:
1381: hogtally () /* compute character code hog */
1382: {
1383: register int i, most;
1384:
1385: for ( i = most = 0; i < 256; i++ )
1386: if ( cfreq [i] >= cfreq [most] )
1387: most = i;
1388: return ( most );
1389: }
1390:
1391: cl_hash(hsize)
1392: register int hsize;
1393: {
1394: register count_int *htab_p = htab+hsize;
1395: register int i;
1396: register long m1 = -1;
1397:
1398: /* clear hashcache */
1399: #define min(a,b) ((a>b) ? b : a)
1400: creset( min((count_int)hsize, MAX_CACHE) );
1401:
1402: i = hsize - 16;
1403: do {
1404: *(htab_p-16) = m1;
1405: *(htab_p-15) = m1;
1406: *(htab_p-14) = m1;
1407: *(htab_p-13) = m1;
1408: *(htab_p-12) = m1;
1409: *(htab_p-11) = m1;
1410: *(htab_p-10) = m1;
1411: *(htab_p-9) = m1;
1412: *(htab_p-8) = m1;
1413: *(htab_p-7) = m1;
1414: *(htab_p-6) = m1;
1415: *(htab_p-5) = m1;
1416: *(htab_p-4) = m1;
1417: *(htab_p-3) = m1;
1418: *(htab_p-2) = m1;
1419: *(htab_p-1) = m1;
1420: htab_p -= 16;
1421: } while ((i -= 16) >= 0);
1422: for ( i += 16; i > 0; i-- )
1423: *--htab_p = m1;
1424: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.