home *** CD-ROM | disk | FTP | other *** search
- /*
- * Compress - data compression program
- *
- * Additional Features Copyright (C) 1990, 1991 Ingo Feulner:
- *
- * - xx.xx.90: Compress acts now like a real UN*X compress
- * Compress compiles now under Lattice/SAS C using small code/data model!
- * Added prototypes so that registerized parameters can be used.
- * - 17.02.91: Speeded up disk access by using a bigger io buf.
- * - 18.02.91: Added the flag '-m'. With this flag the maximum io buf can be set.
- * - 19.02.91: Added online help. Now compress used fewer mem when in decompression mode
- * - 21.02.91: Removed the flag '-m'. Added instead a test for enough free space with
- * AllocMem(MEMF_LARGEST).
- *
- */
-
-
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <fcntl.h>
- #ifdef AMIGA
- #define VERDATE " 1.37 (21 Feb 91) "
-
- #include <dos.h>
- #include <dos/dosextens.h>
- #include <dos/stdio.h>
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <libraries/dos.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include "compress.h" /* Prototypes */
- #endif /* AMIGA */
-
- extern struct DosLibrary *DOSBase;
-
- LONG __asm MFRead(register __d1 BPTR, register __d2 UBYTE *,
- register __d3 ULONG, register __d4 ULONG);
-
- /*
- * Set USERMEM to the maximum amount of physical user memory available
- * in bytes. USERMEM is used to determine the maximum BITS that can be used
- * for compression.
- *
- * SACREDMEM is the amount of physical memory saved for others; compress
- * will hog the rest.
- */
-
- /* Version String for 2.0 */
-
- static char *version20 = "$VER: compress" VERDATE "\n\r";
-
- #define perror(x) poserr(x) /* Amiga DOS Error messages */
-
- #define USERMEM 450000 /* default user memory */
- #define PBITS 16
- #define BITS PBITS
-
- #define HSIZE 69001 /* 95% occupancy */
-
- /*
- * a code_int must be able to hold 2**BITS values of type int, and also -1
- */
-
- #if BITS > 15
- typedef long int code_int;
- #else
- typedef int code_int;
- #endif
-
- typedef long int count_int;
- typedef unsigned char char_type;
-
- char_type magic_header[] = { "\037\235" }; /* 1F 9D */
-
- /* Defines for third byte of header */
- #define BIT_MASK 0x1f
- #define BLOCK_MASK 0x80
- /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
- a fourth header byte (for expansion).
- */
- #define INIT_BITS 9 /* initial number of bits/code */
-
- static char rcs_ident[] = "AmigaUUCP Plus: compress" VERDATE "\n" \
- "Fastest compress in the South...\n" \
- "Written by Ingo Feulner\n";
-
- #define ARGVAL() (*++(*argv) || (--argc && *++argv))
-
- int n_bits; /* number of bits/code */
- int maxbits = BITS; /* user settable max # bits/code */
- code_int maxcode; /* maximum code, given n_bits */
- code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */
-
- #define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
-
- count_int *htab;
- unsigned short *codetab;
-
- // Extension by IF
- #define STDIOBUFSIZE 16348
- long iobufsize;
-
- char *bufin;
- char *bufout;
-
- BPTR infile; // Filehandle to read from
- BPTR outfile; // FileHandle to write to
-
- #define htabof(i) htab[i]
- #define codetabof(i) codetab[i]
-
- code_int hsize = HSIZE; /* for dynamic table sizing */
- count_int fsize = 0;
-
- /*
- * To save much memory, we overlay the table used by compress() with those
- * used by decompress(). The tab_prefix table is the same size and type
- * as the codetab. The tab_suffix table needs 2**BITS characters. We
- * get this from the beginning of htab. The output stack uses the rest
- * of htab, and contains characters. There is plenty of room for any
- * possible stack (stack used to be 8000 characters).
- */
-
- #define tab_prefixof(i) codetabof(i)
- #define tab_suffixof(i) ((char_type *)(htab))[i]
- #define de_stack ((char_type *)&tab_suffixof(1<<BITS))
-
- code_int free_ent = 0; /* first unused entry */
- int exit_stat = 0;
-
-
- void Usage(void)
- {
- fprintf(stderr, "Usage: compress [-dfvcV] [-b maxbits] [file ...]\n");
- fprintf(stderr, "\n\t-d: If given, decompression is done instead.\n");
- fprintf(stderr, "\t-c: Write output on stdout, don't remove original.\n");
- fprintf(stderr, "\t-b: Parameter limits the max number of bits/code.\n");
- fprintf(stderr, "\t-f: Forces output file to be generated, even if one already\n");
- fprintf(stderr, "\t exists, and even if no space is saved by compressing.\n");
- fprintf(stderr, "\t-v: Write compression statistics.\n");
- fprintf(stderr, "\t-V: Print version.\n");
- }
-
- int nomagic = 0; /* Use a 3-byte magic number header, unless old file */
- int zcat_flg = 0; /* Write output on stdout, suppress messages */
- int quiet = 1; /* don't tell me about compression */
-
- /*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
-
- int block_compress = BLOCK_MASK;
- int clear_flg = 0;
- long int ratio = 0;
-
- #define CHECK_GAP 10000 /* ratio check interval */
-
- count_int checkpoint = CHECK_GAP;
- /*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-
- #define FIRST 257 /* first free entry */
- #define CLEAR 256 /* table clear output code */
-
- int force = 0;
- char ofname[100];
-
- int do_decomp = 0;
-
-
- /*****************************************************************
- * TAG( main )
- *
- * Algorithm from "A Technique for High Performance Data Compression",
- * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
- *
- * Usage: compress [-dfvc] [-b bits] [file ...]
- * Inputs:
- * -d: If given, decompression is done instead.
- *
- * -c: Write output on stdout, don't remove original.
- *
- * -b: Parameter limits the max number of bits/code.
- *
- * -f: Forces output file to be generated, even if one already
- * exists, and even if no space is saved by compressing.
- * If -f is not used, the user will be prompted if stdin is
- * a tty, otherwise, the output file will not be overwritten.
- *
- * -v: Write compression statistics
- *
- * file ...: Files to be compressed. If none specified, stdin
- * is used.
- * Outputs:
- * file.Z: Compressed form of file with same mode, owner, and utimes
- * or stdout (if stdin used as input)
- *
- * Assumptions:
- * When filenames are given, replaces with the compressed version
- * (.Z suffix) only if the file decreases in size.
- * Algorithm:
- * Modified Lempel-Ziv method (LZW). Basically finds common
- * substrings and replaces them with a variable size code. This is
- * deterministic, and can be done on the fly. Thus, the decompression
- * procedure needs no input table, but tracks the way the table was built.
- */
-
-
- void main(int argc, char **argv)
- {
- int overwrite = 0; /* Do not overwrite unless given -f flag */
- int newsskip = 0;
- int showversion = 0;
- char tempname[100];
- char **filelist, **fileptr;
- char *cp;
-
-
- filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
- *filelist = NULL;
-
- if((cp = rindex(argv[0], '/')) != 0)
- {
- cp++;
- }
- else
- {
- cp = argv[0];
- }
-
- if(strcmp(cp, "uncompress") == 0)
- {
- do_decomp = 1;
- }
- else if(strcmp(cp, "zcat") == 0)
- {
- do_decomp = 1;
- zcat_flg = 1;
- }
-
- /* Argument Processing
- * All flags are optional.
- * -D => debug
- * -V => print Version; debug verbose
- * -d => do_decomp
- * -v => unquiet
- * -f => force overwrite of output file
- * -n => no header: useful to uncompress old files
- * -b maxbits => maxbits. If -b is specified, then maxbits MUST be
- * given also.
- * -c => cat all output to stdout
- * -C => generate output compatible with compress 2.0.
- *
- * New flags added by Ingo Feulner:
- * -s => skip first 12 bytes from stdin; added for newssupport.
- */
-
- for (argc--, argv++; argc > 0; argc--, argv++)
- {
- if (**argv == '-') /* A flag argument */
- {
- while (*++(*argv)) /* Process all flags in this arg */
- {
- switch (**argv)
- {
- case 'V':
- showversion = 1;
- break;
- case 'v':
- quiet = 0;
- break;
- case 'd':
- do_decomp = 1;
- break;
- case 'f':
- case 'F':
- overwrite = 1;
- force = 1;
- break;
- case 'n':
- nomagic = 1;
- break;
- case 'C':
- block_compress = 0;
- break;
- case 'b':
- if (!ARGVAL())
- {
- fprintf(stderr, "Missing maxbits\n");
- Usage();
- exit(1);
- }
- maxbits = atoi(*argv);
- goto nextarg;
- case 'c':
- zcat_flg = 1;
- break;
- case 'q':
- quiet = 1;
- break;
- case 's':
- do_decomp = 1;
- newsskip = 1; /* Newssupport flag. See above */
- break;
- case '?':
- Usage();
- exit(0);
- break;
- default:
- fprintf(stderr, "Unknown flag: '%c'; ", **argv);
- Usage();
- exit(1);
- }
- }
- }
- else /* Input file name */
- {
- *fileptr++ = *argv; /* Build input file list */
- *fileptr = NULL;
- /* process nextarg; */
- }
-
- nextarg:
- continue;
- }
-
- if(showversion != 0)
- version();
-
- if(maxbits < INIT_BITS)
- maxbits = INIT_BITS;
-
- if(maxbits > BITS)
- maxbits = BITS;
-
- maxmaxcode = 1 << maxbits;
-
- /* Now: allocate mem! -IF- */
- if(do_decomp != 1)
- htab = (count_int *)malloc(HSIZE * sizeof(count_int));
- else // If Decompression, we need not so much memory...
- htab = (count_int *)malloc((1L << BITS) + 8000);
- codetab = (unsigned short *)malloc(HSIZE * sizeof(unsigned short));
-
- if(htab == NULL || codetab == NULL)
- {
- fprintf(stderr, "%s: can't allocate memory.\n", argv[0]);
- exit(20);
- }
-
- if(*filelist != NULL)
- {
- for (fileptr = filelist; *fileptr; fileptr++)
- {
- exit_stat = 0;
- if (do_decomp != 0) /* DECOMPRESSION */
- {
- /* Check for .Z suffix */
- if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0)
- {
- /* No .Z: tack one on */
- strcpy(tempname, *fileptr);
- strcat(tempname, ".Z");
- *fileptr = tempname;
- }
- /* Open input file */
- if((infile = Open(*fileptr, MODE_OLDFILE)) == 0)
- {
- perror(*fileptr);
- continue;
- }
-
- fsize = getfilesize(*fileptr);
-
- iobufsize = (fsize * 4) / 10;
- if((iobufsize < STDIOBUFSIZE) || (AvailMem(MEMF_LARGEST) < (iobufsize * 2)))
- {
- iobufsize = STDIOBUFSIZE;
- }
-
- if((bufin = malloc(iobufsize)) == NULL)
- {
- fprintf(stderr, "%s: can't allocate memory.\n", argv[0]);
- exit(10);
- }
- if((SetVBuf(infile, bufin, BUF_FULL, iobufsize)) != 0)
- {
- fprintf(stderr, "%s: SetVBuf() failed.\n", argv[0]);
- Close(infile);
- exit(10);
- }
-
-
- /* Check the magic number */
- if (nomagic == 0)
- {
- if ((FGetC(infile) != (magic_header[0] & 0xFF))
- || (FGetC(infile) != (magic_header[1] & 0xFF)))
- {
- fprintf(stderr, "%s: not in compressed format\n", *fileptr);
- continue;
- }
- maxbits = FGetC(infile); /* set -b from file */
- block_compress = maxbits & BLOCK_MASK;
- maxbits &= BIT_MASK;
- maxmaxcode = 1 << maxbits;
- if(maxbits > BITS)
- {
- fprintf(stderr, "%s: compressed with %d bits, can only handle %d bits\n",
- *fileptr, maxbits, BITS);
- continue;
- }
- }
- /* Generate output filename */
- strcpy(ofname, *fileptr);
- ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
- }
- else /* COMPRESSION */
- {
- if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0)
- {
- fprintf(stderr, "%s: already has .Z suffix -- no change\n", *fileptr);
- continue;
- }
-
- /* Open input file */
- if((infile = Open(*fileptr, MODE_OLDFILE)) == 0)
- {
- perror(*fileptr);
- continue;
- }
-
- fsize = getfilesize(*fileptr);
-
- iobufsize = (fsize * 2) / 10;
- if((iobufsize < STDIOBUFSIZE ) || (AvailMem(MEMF_LARGEST) < (iobufsize * 2)))
- {
- iobufsize = STDIOBUFSIZE;
- }
-
- if((bufin = malloc(iobufsize)) == NULL)
- {
- fprintf(stderr, "%s: can't allocate memory.\n", argv[0]);
- exit(10);
- }
-
- if((SetVBuf(infile, bufin, BUF_FULL, iobufsize)) != 0)
- {
- fprintf(stderr, "%s: SetVBuf() failed.\n", argv[0]);
- Close(infile);
- exit(10);
- }
-
- /*
- * tune hash table size for small files -- ad hoc,
- * but the sizes match earlier #defines, which
- * serve as upper bounds on the number of output codes.
- */
- hsize = HSIZE;
- if ( fsize < (1 << 12) )
- hsize = min ( 5003, HSIZE );
- else if ( fsize < (1 << 13) )
- hsize = min ( 9001, HSIZE );
- else if ( fsize < (1 << 14) )
- hsize = min ( 18013, HSIZE );
- else if ( fsize < (1 << 15) )
- hsize = min ( 35023, HSIZE );
- else if ( fsize < 47000 )
- hsize = min ( 50021, HSIZE );
-
- /* Generate output filename */
-
- strcpy(ofname, *fileptr);
- strcat(ofname, ".Z");
- }
-
- /* Check for overwrite of existing file */
- if(overwrite == 0 && zcat_flg == 0)
- {
- BPTR lock;
-
- if((lock = Lock(ofname, ACCESS_READ)) != NULL)
- {
- char response[2];
-
- UnLock(lock);
-
- fprintf(stderr, "%s already exists;", ofname);
- if(foreground())
- {
- fprintf(stderr, " do you want to overwrite %s (y or n)?", ofname);
- fflush(stderr);
- read(2, response, 2);
- while(response[1] != '\n')
- {
- if(read(2, response+1, 1) < 0)
- {
- perror("stderr");
- break;
- }
- }
- }
-
- if(response[0] != 'y')
- {
- fprintf(stderr, "\tnot overwritten\n");
- continue;
- }
- }
- }
-
- if(zcat_flg == 0) /* Open output file */
- {
- if((outfile = Open(ofname, MODE_NEWFILE)) == NULL)
- {
- perror(ofname);
- continue;
- }
-
- if((bufout = malloc(iobufsize)) == NULL)
- {
- fprintf(stderr, "%s: can't allocate memory.\n", argv[0]);
- exit(10);
- }
-
- if((SetVBuf(outfile, bufout, BUF_FULL, iobufsize)) != 0)
- {
- fprintf(stderr, "%s: SetVBuf() failed.\n", argv[0]);
- Close(infile);
- Close(outfile);
- exit(10);
- }
-
- if(!quiet)
- fprintf(stderr, "%s: ", *fileptr);
- }
-
- /* Actually do the compression/decompression */
- if (do_decomp == 0)
- compress();
- else
- decompress();
-
- if(zcat_flg == 0)
- {
- copystat(*fileptr, ofname); /* Copy stats */
- if((exit_stat == 1) || (!quiet))
- putc('\n', stderr);
- }
- }
- } /* Standard input */
- else
- {
- bufin = malloc(STDIOBUFSIZE);
- bufout = malloc(STDIOBUFSIZE);
-
- if(bufin == NULL || bufout == NULL)
- {
- fprintf(stderr, "%s: can't allocate memory.\n", argv[0]);
- exit(10);
- }
- /* Set new buffers */
- setvbuf(stdin, bufin, _IOFBF, STDIOBUFSIZE);
- setvbuf(stdout, bufout, _IOFBF, STDIOBUFSIZE);
-
- if (do_decomp == 0)
- {
- compress();
- if(!quiet)
- putc('\n', stderr);
- }
- else
- {
- if(newsskip == 1)
- {
- short zaehler = 0;
-
- /* Skip first 12 bytes, which contain "#! cunbatch\n" */
- while(zaehler++ < 12)
- FGetC(infile);
- }
-
- /* Check the magic number */
- if (nomagic == 0)
- {
- if ((FGetC(infile) != (magic_header[0] & 0xFF))
- || (FGetC(infile) != (magic_header[1] & 0xFF)))
- {
- fprintf(stderr, "stdin: not in compressed format\n");
- exit(1);
- }
- maxbits = FGetC(infile); /* set -b from file */
- block_compress = maxbits & BLOCK_MASK;
- maxbits &= BIT_MASK;
- maxmaxcode = 1 << maxbits;
- fsize = 100000; /* assume stdin large for USERMEM */
- if(maxbits > BITS)
- {
- fprintf(stderr,
- "stdin: compressed with %d bits, can only handle %d bits\n",
- maxbits, BITS);
- exit(1);
- }
- }
- decompress();
- }
- }
- exit(exit_stat);
- }
-
- static int offset;
- long int in_count = 1; /* length of input */
- long int bytes_out; /* length of compressed output */
-
- /*
- * compress stdin to stdout
- *
- * Algorithm: use open addressing double hashing (no chaining) on the
- * prefix code / next character combination. We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe. Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation. Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills. The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor. Late addition: construct the table according to
- * file size for noticeable speed improvement on small files. Please direct
- * questions about this implementation to ames!jaw.
- */
-
- static void compress(void)
- {
- long fcode;
- code_int i;
- int c;
- code_int ent;
- int disp;
- code_int hsize_reg;
- int hshift;
-
- if(nomagic == 0)
- {
- FPutC(outfile, (long)magic_header[0]);
- FPutC(outfile, (long)magic_header[1]);
-
- FPutC(outfile, (long)(maxbits | block_compress));
- /*
- if(ferror(stdout))
- writeerr();
- */
- }
-
- offset = 0;
- bytes_out = 3; /* includes 3-byte header mojo */
- clear_flg = 0;
- ratio = 0;
- in_count = 1;
- checkpoint = CHECK_GAP;
- maxcode = MAXCODE(n_bits = INIT_BITS);
- free_ent = ((block_compress) ? FIRST : 256 );
-
- ent = FGetC(infile);
-
- hshift = 0;
- for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
- hshift++;
-
- hshift = 8 - hshift; /* set hash code range bound */
-
- hsize_reg = hsize;
- cl_hash( (count_int) hsize_reg); /* clear hash table */
-
- while ( (c = FGetC(infile)) != EOF )
- {
- in_count++;
- fcode = (long) (((long) c << maxbits) + ent);
- i = ((c << hshift) ^ ent); /* xor hashing */
-
- if ( htabof (i) == fcode )
- {
- ent = codetabof (i);
- continue;
- }
- else if ( (long)htabof (i) < 0 ) /* empty slot */
- goto nomatch;
-
- disp = hsize_reg - i; /* secondary hash (after G. Knott) */
- if ( i == 0 )
- disp = 1;
-
- probe:
- if ( (i -= disp) < 0 )
- i += hsize_reg;
-
- if ( htabof (i) == fcode )
- {
- ent = codetabof (i);
- continue;
- }
- if ( (long)htabof (i) > 0 )
- goto probe;
- nomatch:
- output ( (code_int) ent );
- ent = c;
-
- if ( free_ent < maxmaxcode )
- {
- codetabof (i) = free_ent++; /* code -> hashtable */
- htabof (i) = fcode;
- }
- else if ( (count_int)in_count >= checkpoint && block_compress )
- cl_block();
- }
- /*
- * Put out the final code.
- */
- output( (code_int)ent );
- output( (code_int)-1 );
-
- /*
- * Print out stats on stderr
- */
- if(zcat_flg == 0 && (!quiet))
- {
- fprintf( stderr, "Compression: " );
- prratio( stderr, in_count-bytes_out, in_count );
- }
- if(bytes_out > in_count) /* exit(2) if no savings */
- exit_stat = 2;
- return;
- }
-
- /*****************************************************************
- * TAG( output )
- *
- * Output the given code.
- * Inputs:
- * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- * that n_bits =< (long)wordsize - 1.
- * Outputs:
- * Outputs code to the file.
- * Assumptions:
- * Chars are 8 bits long.
- * Algorithm:
- * Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly). Use the VAX insv instruction to insert each
- * code in turn. When the buffer fills up empty it and start over.
- */
-
- static char buf[BITS];
-
- char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
- char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-
- void output(code)
- code_int code;
- {
- int r_off = offset, bits = n_bits;
- char *bp = buf;
-
- if ( code >= 0 )
- {
- /*
- * Get to the first byte.
- */
-
- bp += (r_off >> 3);
- r_off &= 7;
-
- /*
- * Since code is always >= 8 bits, only need to mask the first
- * hunk on the left.
- */
-
- *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
- bp++;
- bits -= (8 - r_off);
- code >>=(8 - r_off);
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 )
- {
- *bp++ = code;
- code >>= 8;
- bits -= 8;
- }
- /* Last bits. */
- if(bits)
- *bp = code;
-
- offset += n_bits;
- if ( offset == (n_bits << 3) )
- {
- bp = buf;
- bits = n_bits;
- bytes_out += bits;
- do
- FPutC(outfile, (long)*bp++);
- while(--bits);
- offset = 0;
- }
-
- /*
- * If the next entry is going to be too big for the code size,
- * then increase it, if possible.
- */
- if ( free_ent > maxcode || (clear_flg > 0))
- {
- /*
- * Write the whole buffer, because the input side won't
- * discover the size increase until after it has read it.
- */
- if ( offset > 0 )
- {
- if(FWrite(outfile, buf, 1, n_bits) != n_bits)
- writeerr();
- bytes_out += n_bits;
- }
- offset = 0;
-
- if ( clear_flg )
- {
- maxcode = MAXCODE (n_bits = INIT_BITS);
- clear_flg = 0;
- }
- else
- {
- n_bits++;
- if ( n_bits == maxbits )
- maxcode = maxmaxcode;
- else
- maxcode = MAXCODE(n_bits);
- }
- }
- }
- else
- {
- /*
- * At EOF, write the rest of the buffer.
- */
- if ( offset > 0 )
- FWrite(outfile, buf, 1, (offset + 7) / 8);
- bytes_out += (offset + 7) / 8;
- offset = 0;
- Flush(outfile);
- }
- }
-
- /*
- * Decompress stdin to stdout. This routine adapts to the codes in the
- * file building the "string" table on-the-fly; requiring no table to
- * be stored in the compressed file. The tables used herein are shared
- * with those of the compress() routine. See the definitions above.
- */
-
- static void decompress(void)
- {
- char_type *stackp;
- int finchar;
- code_int code, oldcode, incode;
-
- /*
- * As above, initialize the first 256 entries in the table.
- */
- maxcode = MAXCODE(n_bits = INIT_BITS);
- for ( code = 255; code >= 0; code-- )
- {
- tab_prefixof(code) = 0;
- tab_suffixof(code) = (char_type)code;
- }
- free_ent = ((block_compress) ? FIRST : 256 );
-
- finchar = oldcode = getcode();
- if(oldcode == -1) /* EOF already? */
- return; /* Get out of here */
- FPutC(outfile, (long)finchar); /* first code must be 8 bits = char */
-
- // if(ferror(stdout)) /* Crash if can't write */
- // writeerr();
- stackp = de_stack;
-
- while ( (code = getcode()) > -1 )
- {
- if ( (code == CLEAR) && block_compress )
- {
- for ( code = 255; code >= 0; code-- )
- tab_prefixof(code) = 0;
- clear_flg = 1;
- free_ent = FIRST - 1;
- if ( (code = getcode ()) == -1 ) /* O, untimely death! */
- break;
- }
- incode = code;
-
- /*
- * Special case for KwKwK string.
- */
-
- if ( code >= free_ent )
- {
- *stackp++ = finchar;
- code = oldcode;
- }
-
- /*
- * Generate output characters in reverse order
- */
-
- while ( code >= 256 )
- {
- *stackp++ = tab_suffixof(code);
- code = tab_prefixof(code);
- }
- *stackp++ = finchar = tab_suffixof(code);
-
- /*
- * And put them out in forward order
- */
- do
- FPutC(outfile, (long)*--stackp);
- while ( stackp > de_stack );
-
- /*
- * Generate the new entry.
- */
- if((code = free_ent) < maxmaxcode)
- {
- tab_prefixof(code) = (unsigned short)oldcode;
- tab_suffixof(code) = finchar;
- free_ent = code+1;
- }
- /*
- * Remember previous code.
- */
- oldcode = incode;
- }
- Flush(outfile);
- /*
- if(ferror(stdout))
- writeerr();
- */
- }
-
- /*****************************************************************
- * TAG( getcode )
- *
- * Read one code from the standard input. If EOF, return -1.
- * Inputs:
- * stdin
- * Outputs:
- * code or -1 is returned.
- */
-
- code_int getcode(void)
- {
- code_int code;
- static int offset = 0, size = 0;
- static char_type buf[BITS];
- int r_off, bits;
- char_type *bp = buf;
-
- if ( clear_flg > 0 || offset >= size || free_ent > maxcode )
- {
- /*
- * If the next entry will be too big for the current code
- * size, then we must increase the size. This implies reading
- * a new buffer full, too.
- */
- if ( free_ent > maxcode )
- {
- n_bits++;
- if ( n_bits == maxbits )
- maxcode = maxmaxcode; /* won't get any bigger now */
- else
- maxcode = MAXCODE(n_bits);
- }
- if ( clear_flg > 0)
- {
- maxcode = MAXCODE (n_bits = INIT_BITS);
- clear_flg = 0;
- }
-
- size = MFRead(infile, buf, 1, n_bits);
- if ( size <= 0 )
- return -1; /* end of file */
- offset = 0;
- /* Round size down to integral number of codes */
- size = (size << 3) - (n_bits - 1);
- }
- r_off = offset;
- bits = n_bits;
-
- /*
- * Get to the first byte.
- */
- bp += (r_off >> 3);
- r_off &= 7;
-
- /* Get first part (low order bits) */
- code = (*bp++ >> r_off);
-
- bits -= (8 - r_off);
- r_off = 8 - r_off; /* now, offset into code word */
-
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 )
- {
- code |= *bp++ << r_off;
- r_off += 8;
- bits -= 8;
- }
-
- /* high order bits. */
- code |= (*bp & rmask[bits]) << r_off;
- offset += n_bits;
-
- return code;
- }
-
- char *rindex(char *s, char c) /* For those who don't have it in libc.a */
- {
- char *p;
-
- for (p = NULL; *s; s++)
- if(*s == c)
- p = s;
-
- return(p);
- }
-
- void writeerr(void)
- {
- perror(ofname);
- remove(ofname);
- exit(1);
- }
-
- void copystat(char *ifname, char *ofname)
- {
- Close(infile);
- Close(outfile);
-
- if(exit_stat == 2 && (!force))
- {
- if(!quiet)
- fprintf(stderr, " -- file unchanged");
- }
- else
- {
- exit_stat = 0;
-
- if(remove(ifname))
- perror(ifname);
-
- if(!quiet)
- fprintf(stderr, " -- replaced with %s", ofname);
-
- return;
- }
-
- if(remove(ofname))
- perror(ofname);
- }
-
- int foreground(void)
- {
- if(IsInteractive(Input()) != DOSFALSE)
- {
- return 1;
- }
- else
- return 0;
- }
-
- void onintr(void)
- {
- remove(ofname);
- exit(1);
- }
-
- void oops(void) /* wild pointer -- assume bad input */
- {
- if(do_decomp == 1)
- fprintf(stderr, "uncompress: corrupt input\n");
- remove(ofname);
- exit(1);
- }
-
- void cl_block(void) /* table clear for block compress */
- {
- long int rat;
-
- checkpoint = in_count + CHECK_GAP;
-
- if(in_count > 0x007fffff) /* shift will overflow */
- {
- rat = bytes_out >> 8;
- if(rat == 0) /* Don't divide by zero */
- {
- rat = 0x7fffffff;
- }
- else
- {
- rat = in_count / rat;
- }
- }
- else
- {
- rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
- }
-
- if ( rat > ratio )
- {
- ratio = rat;
- }
- else
- {
- ratio = 0;
-
- cl_hash ( (count_int) hsize );
- free_ent = FIRST;
- clear_flg = 1;
- output ( (code_int) CLEAR );
- }
- }
-
- void cl_hash(count_int hsize) /* reset code table */
- {
- count_int *htab_p = htab + hsize;
- const long m1 = -1;
- long i;
-
- i = hsize - 16;
- do
- {
- *(htab_p - 16) = m1;
- *(htab_p - 15) = m1;
- *(htab_p - 14) = m1;
- *(htab_p - 13) = m1;
- *(htab_p - 12) = m1;
- *(htab_p - 11) = m1;
- *(htab_p - 10) = m1;
- *(htab_p - 9) = m1;
- *(htab_p - 8) = m1;
- *(htab_p - 7) = m1;
- *(htab_p - 6) = m1;
- *(htab_p - 5) = m1;
- *(htab_p - 4) = m1;
- *(htab_p - 3) = m1;
- *(htab_p - 2) = m1;
- *(htab_p - 1) = m1;
- htab_p -= 16;
- } while ((i -= 16) >= 0);
-
- for ( i += 16; i > 0; i-- )
- *--htab_p = m1;
- }
-
- void prratio(FILE *stream, long int num, long int den)
- {
- int q; /* Doesn't need to be long */
-
- if(num > 214748L) /* 2147483647/10000 */
- {
- q = num / (den / 10000L);
- }
- else
- {
- q = 10000L * num / den; /* Long calculations, though */
- }
-
- if (q < 0)
- {
- putc('-', stream);
- q = -q;
- }
- fprintf(stream, "%d.%02d%%", q / 100, q % 100);
- }
-
- void version(void)
- {
- fprintf(stderr, "%s\n", rcs_ident);
- fprintf(stderr, "Options: ");
- fprintf(stderr, "BITS = %d\n", BITS);
- }
-
- /*
- * getfilesize() for the AMIGA.
- * 22.4.90 Ingo Feulner.
- */
-
- long getfilesize(char *name)
- {
- long size = 100000;
- struct FileInfoBlock *fib;
- BPTR lock;
-
- if((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_CLEAR)) != NULL)
- {
- if((lock = Lock(name, ACCESS_READ)) != NULL)
- {
- if((Examine(lock, fib)) != DOSFALSE)
- {
- size = fib->fib_Size;
- }
- UnLock(lock);
- }
- FreeMem(fib, sizeof(struct FileInfoBlock));
- }
- return(size);
- }
-
- LONG __asm MFRead(register __d1 BPTR fh, register __d2 UBYTE *buffer,
- register __d3 ULONG bsize, register __d4 ULONG nblocks)
- {
- UBYTE *ptr;
- ULONG nb, bs;
- ULONG c;
-
- ptr = buffer;
-
- for(nb = 0; nb < nblocks; nb++)
- {
- for(bs = 0; bs < bsize; bs++)
- {
- c = FGetC(fh);
- if(c == -1L)
- return (LONG)nb;
-
- *ptr++ = (UBYTE)c;
- }
- }
- return (LONG)nb;
- }
-