Path: ns-mx!hobbes.physics.uiowa.edu!zaphod.mps.ohio-state.edu!swrinde!cs.utexas.edu!sun-barr!newstop!sun!amdahl!fadden From: fadden@uts.amdahl.com (Andy McFadden) Newsgroups: comp.binaries.apple2 Subject: NuLib v3.10 (UNIX) nulib.04 Message-ID: <59By02KJ09rT00@amdahl.uts.amdahl.com> Date: 1 Nov 91 04:12:09 GMT Reply-To: fadden@amdahl.uts.amdahl.com (Andy McFadden) Organization: Amdahl Corporation, Sunnyvale CA Lines: 997 NuLib v3.10 - nulib.04 ---- Cut Here and feed the following to sh ---- #!/bin/sh # This is part 04 of a multipart archive # ============= nucomp.c ============== if test -f 'nucomp.c' -a X"$1" != X"-c"; then echo 'x - skipping nucomp.c (File already exists)' else echo 'x - extracting nucomp.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'nucomp.c' && /* X * nucomp.c - code to perform UNIX style LZW compression X * X * NuLib v3.1 October 1991 Freeware (distribute, don't sell) X * By Andy McFadden (fadden@cory.berkeley.edu) X */ /* X * This is the main compression code from compress v4.3. Modifications X * have been made to integrate it with NuLib (primarily in that it no longer X * uses stdin/stdout), but it's functionally the same. X */ #ifdef APW segment "Compress" #endif X #include "nudefs.h" #include "nupak.h" #define MAIN /* cause nucomp.h to alloc global vars */ X /*@H************************ < COMPRESS API > **************************** * * * compress : compapi.c * * * * port by : Donald J. Gloistein * * * * Source, Documentation, Object Code: * * released to Public Domain. This code is based on code as documented * * below in release notes. * * * *--------------------------- Module Description --------------------------* * Contains source code for modified Lempel-Ziv method (LZW) compression * * and decompression. * * * * This code module can be maintained to keep current on releases on the * * Unix system. The command shell and dos modules can remain the same. * * * *--------------------------- Implementation Notes --------------------------* * * * compiled with : compress.h compress.fns compress.c * * linked with : compress.obj compusi.obj * * * * problems: * * * * * * CAUTION: Uses a number of defines for access and speed. If you change * * anything, make sure about side effects. * * * * Compression: * * 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 block compression with an adaptive reset was used in original code, * * whereby the code table is cleared when the compression ration decreases * * but after the table fills. This was removed from this edition. The table * * is re-sized at this point when it is filled , and a special CLEAR code is * * generated for the decompressor. This results in some size difference from * * straight version 4.0 joe Release. But it is fully compatible in both v4.0 * * and v4.01 * * * * Decompression: * * 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. * * * * Initials ---- Name --------------------------------- * * DjG Donald J. Gloistein, current port to MsDos 16 bit * * Plus many others, see rev.hst file for full list * * LvR Lyle V. Rains, many thanks for improved implementation * * of the compression and decompression routines. * *************************************************************************@H*/ X #include #define assert(x) #include "nucomp.h" /* contains the rest of the include file declarations */ X FILE *nustdin, *nustdout; /* NuLib: use these instead of stdin/stdout */ long nubytes_read, nucomp_thread_eof; /* NuLib: used in nextcode (decomp) */ X /* NuLib: pulled this out of nextcode() so we can initialize it every time */ static int prevbits = 0; /* NuLib: pulled out of putcode() */ static int oldbits = 0; X static int offset; static long int in_count ; /* length of input */ static long int bytes_out; /* length of compressed output */ static long int max_bytes_out; /* NuLib: max #of bytes to output */ X static CODE prefxcode, nextfree; static CODE highcode; static CODE maxcode; static HASH hashsize; static int bits; X X /* X * The following two parameter tables are the hash table sizes and X * maximum code values for various code bit-lengths. The requirements X * are that Hashsize[n] must be a prime number and Maxcode[n] must be less X * than Maxhash[n]. Table occupancy factor is (Maxcode - 256)/Maxhash. X * Note: I am using a lower Maxcode for 16-bit codes in order to X * keep the hash table size less than 64k entries. X */ CONST HASH hs[] = { X 0x13FF, /* 12-bit codes, 75% occupancy */ X 0x26C3, /* 13-bit codes, 80% occupancy */ X 0x4A1D, /* 14-bit codes, 85% occupancy */ X 0x8D0D, /* 15-bit codes, 90% occupancy */ X 0xFFD9 /* 16-bit codes, 94% occupancy, 6% of code values unused */ }; #define Hashsize(maxb) (hs[(maxb) -MINBITS]) X CONST CODE mc[] = { X 0x0FFF, /* 12-bit codes */ X 0x1FFF, /* 13-bit codes */ X 0x3FFF, /* 14-bit codes */ X 0x7FFF, /* 15-bit codes */ X 0xEFFF /* 16-bit codes, 6% of code values unused */ }; #define Maxcode(maxb) (mc[(maxb) -MINBITS]) X #define allocx(type,ptr,size) \ X (((ptr) = (type FAR *) emalloc((unsigned int)(size),sizeof(type))) == NULLPTR(type) \ X ? NOMEM : OK \ X ) X #define free_array(type,ptr,offset) \ X if (ptr != NULLPTR(type)) { \ X efree((ALLOCTYPE FAR *)((ptr) + (offset))); \ X (ptr) = NULLPTR(type); \ X } X X /* X * Macro to allocate new memory to a pointer with an offset value. X */ #define alloc_array(type, ptr, size, offset) \ X ( allocx(type, ptr, (size) - (offset)) != OK \ X ? NOMEM \ X : (((ptr) -= (offset)), OK) \ X ) X static char FAR *sfx = NULLPTR(char) ; #define suffix(code) sfx[code] X X #ifdef SPLIT_PFX X static CODE FAR *pfx[2] = {NULLPTR(CODE), NULLPTR(CODE)}; #else X static CODE FAR *pfx = NULLPTR(CODE); #endif X X #ifdef SPLIT_HT X static CODE FAR *ht[2] = {NULLPTR(CODE),NULLPTR(CODE)}; #else X static CODE FAR *ht = NULLPTR(CODE); #endif X X int alloc_tables(maxcode, hashsize) X CODE maxcode; X HASH hashsize; { X static CODE oldmaxcode = 0; X static HASH oldhashsize = 0; X X if (hashsize > oldhashsize) { #ifdef SPLIT_HT X free_array(CODE,ht[1], 0); X free_array(CODE,ht[0], 0); #else X free_array(CODE,ht, 0); #endif X oldhashsize = 0; X } X X if (maxcode > oldmaxcode) { #ifdef SPLIT_PFX X free_array(CODE,pfx[1], 128); X free_array(CODE,pfx[0], 128); #else X free_array(CODE,pfx, 256); #endif X free_array(char,sfx, 256); X X if ( alloc_array(char, sfx, maxcode + 1, 256) #ifdef SPLIT_PFX X || alloc_array(CODE, pfx[0], (maxcode + 1) / 2, 128) X || alloc_array(CODE, pfx[1], (maxcode + 1) / 2, 128) #else X || alloc_array(CODE, pfx, (maxcode + 1), 256) #endif X ) { X oldmaxcode = 0; X exit_stat = NOMEM; X return(NOMEM); X } X oldmaxcode = maxcode; X } X if (hashsize > oldhashsize) { X if ( #ifdef SPLIT_HT X alloc_array(CODE, ht[0], (hashsize / 2) + 1, 0) X || alloc_array(CODE, ht[1], hashsize / 2, 0) #else X alloc_array(CODE, ht, hashsize, 0) #endif X ) { X oldhashsize = 0; X exit_stat = NOMEM; X return(NOMEM); X } X oldhashsize = hashsize; X } X return (OK); } X # ifdef SPLIT_PFX X /* X * We have to split pfx[] table in half, X * because it's potentially larger than 64k bytes. X */ # define prefix(code) (pfx[(code) & 1][(code) >> 1]) # else X /* X * Then pfx[] can't be larger than 64k bytes, X * or we don't care if it is, so we don't split. X */ # define prefix(code) (pfx[code]) # endif X X /* The initializing of the tables can be done quicker with memset() */ /* but this way is portable through out the memory models. */ /* If you use Microsoft halloc() to allocate the arrays, then */ /* include the pragma #pragma function(memset) and make sure that */ /* the length of the memory block is not greater than 64K. */ /* This also means that you MUST compile in a model that makes the */ /* default pointers to be far pointers (compact or large models). */ /* See the file COMPUSI.DOS to modify function emalloc(). */ X # ifdef SPLIT_HT X /* X * We have to split ht[] hash table in half, X * because it's potentially larger than 64k bytes. X */ # define probe(hash) (ht[(hash) & 1][(hash) >> 1]) # define init_tables() \ X { \ X hash = hashsize >> 1; \ X ht[0][hash] = 0; \ X while (hash--) ht[0][hash] = ht[1][hash] = 0; \ X highcode = ~(~(CODE)0 << (bits = INITBITS)); \ X nextfree = (block_compress ? FIRSTFREE : 256); \ X } X # else X X /* X * Then ht[] can't be larger than 64k bytes, X * or we don't care if it is, so we don't split. X */ # define probe(hash) (ht[hash]) # define init_tables() \ X { \ X hash = hashsize; \ X while (hash--) ht[hash] = 0; \ X highcode = ~(~(CODE)0 << (bits = INITBITS)); \ X nextfree = (block_compress ? FIRSTFREE : 256); \ X } X # endif X #ifdef COMP40 /* table clear for block compress */ /* this is for adaptive reset present in version 4.0 joe release */ /* DjG, sets it up and returns TRUE to compress and FALSE to not compress */ int cl_block () { X register long int rat; X X checkpoint = in_count + CHECK_GAP; #ifndef NDEBUG X if ( debug ) { X fprintf ( stderr, "count: %ld, ratio: ", in_count ); X prratio ( stderr, in_count, bytes_out ); X fprintf ( stderr, "\n"); X } #endif X X if(in_count > 0x007fffff) { /* shift will overflow */ X rat = bytes_out >> 8; X if(rat == 0) /* Don't divide by zero */ X rat = 0x7fffffff; X else X rat = in_count / rat; X } X else X rat = (in_count << 8) / bytes_out; /* 8 fractional bits */ X X if ( rat > ratio ){ X ratio = rat; X return FALSE; X } X else { X ratio = 0; #ifndef NDEBUG X if(debug) X fprintf ( stderr, "clear\n" ); #endif X return TRUE; /* clear the table */ X } X /*NOTREACHED*/ X return FALSE; /* don't clear the table */ } #endif /*COMP40*/ X /* X * compress stdin to stdout <-- nope X * NuLib: compress thread_eof bytes from srcfd, writing to dstfd X * Sets up a few things and then calls u_compress. X */ int u_compress(srcfd, dstfd, thread_eof) int srcfd, dstfd; long thread_eof; { X int src2, dst2; X long srcposn, dstposn; X static char *procName = "u_compress"; X X if ((srcposn = lseek(srcfd, 0L, S_REL)) < 0) X Fatal("Bad posn lseek(1)", procName); X if ((dstposn = lseek(dstfd, 0L, S_REL)) < 0) X Fatal("Bad posn lseek(2)", procName); X X src2 = dup(srcfd); X dst2 = dup(dstfd); X X /* NuLib: open new stdin/stdout, and seek */ X if ((nustdin = fdopen(src2, FREAD_STR)) == NULL) X Fatal("can't fdopen() nustdin", procName); X if ((nustdout = fdopen(dst2, FWRITE_STR)) == NULL) X Fatal("can't fdopen() nustdout", procName); X setvbuf(nustdin,xbuf,_IOFBF,XBUFSIZE); /* make the buffers larger */ X setvbuf(nustdout,zbuf,_IOFBF,ZBUFSIZE); /* (note setvbuf is a macro) */ X if (fseek(nustdin, srcposn, S_ABS) < 0) /* seek may not be needed */ X Fatal("Bad stream posn lseek(1)", procName); X if (fseek(nustdout, dstposn, S_ABS) < 0) X Fatal("Bad stream posn lseek(2)", procName); X X oldbits = 0; /* init for putcode() */ X compress(thread_eof); X check_error(); X X fclose(nustdin); /* note this closes the duped fd */ X fclose(nustdout); X return (exit_stat); } X void compress(thread_eof) long thread_eof; { X int c,adjbits; X register HASH hash; X register CODE code; X HASH hashf[256]; X X max_bytes_out = thread_eof; /* NuLib: don't exceed original size */ X maxcode = Maxcode(maxbits); X hashsize = Hashsize(maxbits); X #ifdef COMP40 /* Only needed for adaptive reset */ X checkpoint = CHECK_GAP; X ratio = 0; #endif X X adjbits = maxbits -10; X for (c = 256; --c >= 0; ){ X hashf[c] = ((( c &0x7) << 7) ^ c) << adjbits; X } X exit_stat = OK; X if (alloc_tables(maxcode, hashsize)) /* exit_stat already set */ X return; X init_tables(); X /* if not zcat or filter (NuLib: never happens) */ X if(is_list && !zcat_flg) { /* Open output file */ X if (freopen(ofname, WRITE_FILE_TYPE, nustdout) == NULL) { X exit_stat = NOTOPENED; X return; X } X if (!quiet) X fprintf(stderr, "%s: ",ifname); X setvbuf(nustdout,zbuf,_IOFBF,ZBUFSIZE); X } X /* X * Check the input stream for previously seen strings. We keep X * adding characters to the previously seen prefix string until we X * get a character which forms a new (unseen) string. We then send X * the code for the previously seen prefix string, and add the new X * string to our tables. The check for previous strings is done by X * hashing. If the code for the hash value is unused, then we have X * a new string. If the code is used, we check to see if the prefix X * and suffix values match the current input; if so, we have found X * a previously seen string. Otherwise, we have a hash collision, X * and we try secondary hash probes until we either find the current X * string, or we find an unused entry (which indicates a new string). X */ X if (!nomagic) { X putc(magic_header[0], nustdout); /* was putchar() */ X putc(magic_header[1], nustdout); /* was putchar() */ X putc((char)(maxbits | block_compress), nustdout); /*was putchar*/ X if(ferror(nustdout)){ /* check it on entry */ X exit_stat = WRITEERR; X return; X } X bytes_out = 3L; /* includes 3-byte header mojo */ X } X else X bytes_out = 0L; /* no 3-byte header mojo */ X in_count = 1L; X offset = 0; X X if ((c = getc(nustdin)) == EOF) { /* NuLib: was getchar() */ X exit_stat = ferror(nustdin) ? READERR : OK; X return; X } X prefxcode = (CODE)c; X X while ((c = getc(nustdin)) != EOF) { /* NuLib: was getchar() */ X in_count++; X /* NuLib : May not be compressing entire file, so can't rely on EOF for end */ X if (in_count > thread_eof) break; X X hash = prefxcode ^ hashf[c]; X /* I need to check that my hash value is within range X * because my 16-bit hash table is smaller than 64k. X */ X if (hash >= hashsize) X hash -= hashsize; X if ((code = probe(hash)) != UNUSED) { X if (suffix(code) != (char)c || prefix(code) != prefxcode) { X /* hashdelta is subtracted from hash on each iteration of X * the following hash table search loop. I compute it once X * here to remove it from the loop. X */ X HASH hashdelta = (0x120 - c) << (adjbits); X do { X /* rehash and keep looking */ X assert(code >= FIRSTFREE && code <= maxcode); X if (hash >= hashdelta) hash -= hashdelta; X else hash += (hashsize - hashdelta); X assert(hash < hashsize); X if ((code = probe(hash)) == UNUSED) X goto newcode; X } while (suffix(code) != (char)c || prefix(code) != prefxcode); X } X prefxcode = code; X } X else { X newcode: { X putcode(prefxcode, bits); X code = nextfree; X assert(hash < hashsize); X assert(code >= FIRSTFREE); X assert(code <= maxcode + 1); X if (code <= maxcode) { X probe(hash) = code; X prefix(code) = prefxcode; X suffix(code) = (char)c; X if (code > highcode) { X highcode += code; X ++bits; X } X nextfree = code + 1; X } #ifdef COMP40 X else if (in_count >= checkpoint && block_compress ) { X if (cl_block()){ #else X else if (block_compress){ #endif X putcode((CODE)c, bits); X putcode((CODE)CLEAR,bits); X init_tables(); X if ((c = getc(nustdin)) == EOF) /* NuLib: was getchar*/ X break; X in_count++; #ifdef COMP40 X } #endif X } X prefxcode = (CODE)c; X } X } X } X putcode(prefxcode, bits); X putcode((CODE)CLEAR, 0); X if (ferror(nustdout)){ /* check it on exit */ X exit_stat = WRITEERR; X return; X } X /* X * Print out stats on stderr X */ X if(zcat_flg == 0 && !quiet) { #ifndef NDEBUG X fprintf( stderr, X "%ld chars in, (%ld bytes) out, compression factor: ", X in_count, bytes_out ); X prratio( stderr, in_count, bytes_out ); X fprintf( stderr, "\n"); X fprintf( stderr, "\tCompression as in compact: " ); X prratio( stderr, in_count-bytes_out, in_count ); X fprintf( stderr, "\n"); X fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n", X prefxcode - 1, bits ); #else X fprintf( stderr, "Compression: " ); X prratio( stderr, in_count-bytes_out, in_count ); #endif /* NDEBUG */ X } X if(bytes_out > in_count) /* if no savings */ X exit_stat = NOSAVING; X X packedSize = bytes_out; /* NuLib : return packed size in global */ X X return ; } X CONST UCHAR rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; X void putcode(code,bits) CODE code; register int bits; { X static UCHAR outbuf[MAXBITS]; X register UCHAR *buf; X register int shift; X register int ok_to_write; /* NuLib (kludge... sorry) */ X X ok_to_write = (exit_stat != NOSAVING); X X if (bits != oldbits) { X if (bits == 0) { X /* bits == 0 means EOF, write the rest of the buffer. */ X if (offset > 0) { X int x = ((offset+7) >> 3); /* NuLib */ X X if ((bytes_out + x) > max_bytes_out) { /* NuLib */ X /* compression failed. There's no clean way of bailing out X /* (could use setjmp/longjmp, but that may not be supported X /* on all systems), so just don't write anything. X */ X exit_stat = NOSAVING; X ok_to_write = FALSE; X } else { /* fwrite(outbuf,1,(offset +7) >> 3, nustdout);*/ X fwrite(outbuf,1, x, nustdout); X } /* bytes_out += ((offset +7) >> 3);*/ X bytes_out += x; X } X offset = 0; X oldbits = 0; X fflush(nustdout); X return; X } X else { X /* Change the code size. We must write the whole buffer, X * because the expand side won't discover the size change X * until after it has read a buffer full. X */ X if (offset > 0) { X if (ok_to_write) fwrite(outbuf, 1, oldbits, nustdout); X bytes_out += oldbits; X offset = 0; X } X oldbits = bits; #ifndef NDEBUG X if ( debug ) X fprintf( stderr, "\nChange to %d bits\n", bits ); #endif /* !NDEBUG */ X } X } X /* Get to the first byte. */ X buf = outbuf + ((shift = offset) >> 3); X if ((shift &= 7) != 0) { X *(buf) |= (*buf & rmask[shift]) | (UCHAR)(code << shift); X *(++buf) = (UCHAR)(code >> (8 - shift)); X if (bits + shift > 16) X *(++buf) = (UCHAR)(code >> (16 - shift)); X } X else { X /* Special case for fast execution */ X *(buf) = (UCHAR)code; X *(++buf) = (UCHAR)(code >> 8); X } X if ((offset += bits) == (bits << 3)) { X bytes_out += bits; X if (ok_to_write) fwrite(outbuf,1,bits,nustdout); X offset = 0; X } X return; } X int nextcode(codeptr) CODE *codeptr; /* Get the next code from input and put it in *codeptr. X * Return (TRUE) on success, or return (FALSE) on end-of-file. X * Adapted from COMPRESS V4.0. X */ { X register CODE code; X static int size; X static UCHAR inbuf[MAXBITS]; X register int shift; X UCHAR *bp; X X /* If the next entry is a different bit-size than the preceeding one X * then we must adjust the size and scrap the old buffer. X */ X if (prevbits != bits) { X prevbits = bits; X size = 0; X } X /* If we can't read another code from the buffer, then refill it. X */ X if (size - (shift = offset) < bits) { X static int bytesize; /* NuLib: sigh */ X /* Read more input and convert size from # of bytes to # of bits */ X X /* NuLib: stop after comp_thread_eof bytes */ X if (nubytes_read >= nucomp_thread_eof) X return(NO); X X /* NuLib: replace old fread command with... */ X /* X if ((size = fread(inbuf, 1, bits, nustdin) << 3) <= 0 || ferror(nustdin)) X return(NO); X */ X X bytesize = fread(inbuf, 1, bits, nustdin); X if (nubytes_read + bits > nucomp_thread_eof) { X bytesize = nucomp_thread_eof - nubytes_read; X } X size = bytesize << 3; X if (size <= 0 || ferror(nustdin)) X return (NO); X X /* NuLib: increment nubytes_read */ X nubytes_read += (long) bytesize; X X offset = shift = 0; X } X /* Get to the first byte. */ X bp = inbuf + (shift >> 3); X /* Get first part (low order bits) */ X code = (*bp++ >> (shift &= 7)); X /* high order bits. */ X code |= *bp++ << (shift = 8 - shift); X if ((shift += 8) < bits) code |= *bp << shift; X *codeptr = code & highcode; X offset += bits; X return (TRUE); } X /* X * NuLib: uncompress comp_thread_eof bytes from srcfd, writing to dstfd X * Sets up a few things and then calls compress. X */ int u_decompress(srcfd, dstfd, comp_thread_eof) int srcfd, dstfd; long comp_thread_eof; { X int src2, dst2; X long srcposn, dstposn; X static char *procName = "u_decompress"; X X if ((srcposn = lseek(srcfd, 0L, S_REL)) < 0) X Fatal("Bad posn lseek(1)", procName); X if ((dstposn = lseek(dstfd, 0L, S_REL)) < 0) X Fatal("Bad posn lseek(2)", procName); X X src2 = dup(srcfd); X dst2 = dup(dstfd); X X /* NuLib: open new stdin/stdout, and seek */ X if ((nustdin = fdopen(src2, FREAD_STR)) == NULL) X Fatal("can't fdopen() nustdin", procName); X if ((nustdout = fdopen(dst2, FWRITE_STR)) == NULL) X Fatal("can't fdopen() nustdout", procName); X setvbuf(nustdin,zbuf,_IOFBF,ZBUFSIZE); /* make the buffers larger */ X setvbuf(nustdout,xbuf,_IOFBF,XBUFSIZE); /* (note order diff from comp) */ X if (fseek(nustdin, srcposn, S_ABS) < 0) /* seek may not be needed */ X Fatal("Bad stream posn lseek(1)", procName); X if (fseek(nustdout, dstposn, S_ABS) < 0) X Fatal("Bad stream posn lseek(2)", procName); X X /* Check the magic number */ X if (!nomagic) { X if ((getc(nustdin)!=(magic_header[0] & 0xFF)) /* NuLib: was getchar*/ X || (getc(nustdin)!=(magic_header[1] & 0xFF))) {/* NuLib: was getchar*/ X fprintf(stderr, "decompress: not in compressed format\n"); X return(-1); /* NuLib: was exit(ERROR) */ X } X maxbits = getc(nustdin); /* set -b from file (NuLib: was getchar) */ X block_compress = maxbits & BLOCK_MASK; X maxbits &= BIT_MASK; X if(maxbits > MAXBITS) { X fprintf(stderr, X "decompress: compressed with %d bits, can only handle %d bits\n", X maxbits, MAXBITS); X return(-1); /* NuLib: was exit(ERROR) */ X } X nubytes_read = 3L; X } else { X nubytes_read = 0L; X } X X nucomp_thread_eof = comp_thread_eof; /* printf("src file posn = %ld\n", ftell(nustdin));*/ X prevbits = 0; /* init for nextcode() */ X decompress(); X check_error(); X X fclose(nustdin); /* note this closes the duped fd */ X fclose(nustdout); X return (exit_stat); } X void decompress() { X register int i; X register CODE code; X char sufxchar; X CODE savecode; X FLAG fulltable, cleartable; X static char token[MAXTOKLEN]; /* String buffer to build token */ X X exit_stat = OK; X X if (alloc_tables(maxcode = ~(~(CODE)0 << maxbits),0)) /* exit_stat already set */ X return; X X /* if not zcat or filter (NuLib: never) */ X if(is_list && !zcat_flg) { /* Open output file */ X if (freopen(ofname, WRITE_FILE_TYPE, nustdout) == NULL) { X exit_stat = NOTOPENED; X return; X } X if (!quiet) X fprintf(stderr, "%s: ",ifname); X setvbuf(nustdout,xbuf,_IOFBF,XBUFSIZE); X } X cleartable = TRUE; X savecode = CLEAR; X offset = 0; X do { X if ((code = savecode) == CLEAR && cleartable) { X highcode = ~(~(CODE)0 << (bits = INITBITS)); X fulltable = FALSE; X nextfree = (cleartable = block_compress) == FALSE ? 256 : FIRSTFREE; X if (!nextcode(&prefxcode)) X break; X putc((sufxchar = (char)prefxcode), nustdout); X continue; X } X i = 0; X if (code >= nextfree && !fulltable) { X if (code != nextfree){ X exit_stat = CODEBAD; /* fprintf(stderr, "Bad code; nubytes_read = %ld\n", nubytes_read); */ X /* CDEBUG */ X return ; /* Non-existant code */ X } X /* Special case for sequence KwKwK (see text of article) */ X code = prefxcode; X token[i++] = sufxchar; X } X /* Build the token string in reverse order by chasing down through X * successive prefix tokens of the current token. Then output it. X */ X while (code >= 256) { #ifndef NDEBUG X /* These are checks to ease paranoia. Prefix codes must decrease X * monotonically, otherwise we must have corrupt tables. We can X * also check that we haven't overrun the token buffer. X */ X if (code <= prefix(code)){ X exit_stat= TABLEBAD; X return; X } X if (i >= MAXTOKLEN){ X exit_stat = TOKTOOBIG; X return; X } #endif X token[i++] = suffix(code); X code = prefix(code); X } X putc(sufxchar = (char)code, nustdout); X while (--i >= 0) X putc(token[i], nustdout); X if (ferror(nustdout)) { X exit_stat = WRITEERR; X return; X } X /* If table isn't full, add new token code to the table with X * codeprefix and codesuffix, and remember current code. X */ X if (!fulltable) { X code = nextfree; X assert(256 <= code && code <= maxcode); X prefix(code) = prefxcode; X suffix(code) = sufxchar; X prefxcode = savecode; X if (code++ == highcode) { X if (highcode >= maxcode) { X fulltable = TRUE; X --code; X } X else { X ++bits; X highcode += code; /* nextfree == highcode + 1 */ X } X } X nextfree = code; X } X X } while (nextcode(&savecode)); X exit_stat = (ferror(nustdin))? READERR : OK; X X return ; } X X /* X * These are routines pulled out of "compress.c" from compress v4.3. X */ void prratio(stream, num, den) FILE *stream; long int num, den; { X register int q; /* Doesn't need to be long */ X X if(num > 214748L) { /* 2147483647/10000 */ X q = (int) (num / (den / 10000L)); X } X else { X q = (int) (10000L * num / den); /* Long calculations, though */ X } X if (q < 0) { X putc('-', stream); X q = -q; X } X fprintf(stream, "%d.%02d%%", q / 100, q % 100); } X /* X * Check exit status from compress() and decompress() X * X * exit_stat is a global var. Either returns something interesting or X * bails out completely. X */ int check_error() /* returning OK continues with processing next file */ { X prog_name = prgName; /* NuLib: set prog_name to "nulib" */ X X switch(exit_stat) { X case OK: X return (OK); X case NOMEM: X if (do_decomp) X fprintf(stderr,"%s: not enough memory to decompress '%s'.\n", prog_name, ifname); X else X fprintf(stderr,"%s: not enough memory to compress '%s'.\n", prog_name, ifname); X return(OK); X case SIGNAL_ERROR: X fprintf(stderr,"%s: error setting signal interupt.\n",prog_name); X exit(ERROR); X break; X case READERR: X fprintf(stderr,"%s: read error on input '%s'.\n", prog_name, ifname); X break; X case WRITEERR: X fprintf(stderr,"%s: write error on output '%s'.\n", prog_name, ofname); X break; X case TOKTOOBIG: X fprintf(stderr,"%s: token too long in '%s'.\n", prog_name, ifname); X break; X case INFILEBAD: X fprintf(stderr, "%s: '%s' in unknown compressed format.\n", prog_name, ifname); X break; X case CODEBAD: X fprintf(stderr,"%s: file token bad in '%s'.\n", prog_name,ifname); X break; X case TABLEBAD: X fprintf(stderr,"%s: internal error -- tables corrupted.\n", prog_name); X break; X case NOTOPENED: X fprintf(stderr,"%s: could not open output file %s\n",prog_name,ofname); X exit(ERROR); X break; X case NOSAVING: X if (force) X exit_stat = OK; X return (OK); X default: X fprintf(stderr,"%s: internal error -- illegal return value = %d.\n", prog_name,exit_stat); X } X if (!zcat_flg && !keep_error){ X fclose(nustdout); /* won't get here without an error */ X unlink ( ofname ); X } X exit(exit_stat); X return(ERROR); } X /* X * These are routines from "compusi.c" X */ void version() { #ifdef XENIX #ifndef NDEBUG X fprintf(stderr, "%s\nOptions: Xenix %s MAXBITS = %d\n", rcs_ident, X "DEBUG",MAXBITS); #else X fprintf(stderr, "%s\nOptions: Xenix MAXBITS = %d\n", rcs_ident,MAXBITS); #endif #else #ifndef NDEBUG X fprintf(stderr, "%s\nOptions: Unix %s MAXBITS = %d\n", rcs_ident, X "DEBUG",MAXBITS); #else X fprintf(stderr, "%s\nOptions: Unix MAXBITS = %d\n", rcs_ident,MAXBITS); #endif #endif } X ALLOCTYPE FAR * emalloc(x,y) unsigned int x; int y; { X ALLOCTYPE FAR *p; X p = (ALLOCTYPE FAR *)ALLOCATE(x,y); X return(p); } X void efree(ptr) ALLOCTYPE FAR *ptr; { X FREEIT(ptr); } X SHAR_EOF chmod 0644 nucomp.c || echo 'restore of nucomp.c failed' Wc_c="`wc -c < 'nucomp.c'`" test 30783 -eq "$Wc_c" || echo 'nucomp.c: original size 30783, current size' "$Wc_c" fi true || echo 'restore of nuetc.c failed' echo End of part 4, continue with part 5 exit 0 -- fadden@uts.amdahl.com (Andy McFadden) fadden@cory.berkeley.edu (expires in December) [ Above opinions are mine, Amdahl has nothing to do with them, etc, etc. ]