jac@yoko.rutgers.edu (Jonathan A. Chandross) (05/02/91)
Submitted-by: Andy McFadden (fadden@cory.berkeley.edu) Posting-number: Volume 1, Source:32 Archive-name: archive/unix/nulib/part01.10 Architecture: UNIX Version-number: 3.03 Nulib allows handles many of the archiving formats used on the Apple. Very handy indeed. Enjoy. =README -Nulib v3.03 (February 1991) -- Fixed XENIX problems with includes and libs (Ron Higgins). -- Fixed bug in directory expansion (Larry W. Virden). -NuLib v3.02 -- Silenced screaming about bad dates (Larry W. Virden). -- Fixed glitches in nulib.lnk and nulib.mak (Bruce Kahn). -NuLib v3.01 -- Fixed non-compression bug in ShrinkIt LZW (Scott Blackman). - -NuLib v3.0 README (September 1990) - -New items in 3.0: -- ShrinkIt LZW compression -- UNIX 12-bit and 16-bit compression -- New archive listing format (similar to ARC and ZOO) - -Things work much better if you read the documentation file (now available -on the archive site... sorry I didn't put it up sooner). If you want to -use UNIX compress to store files, READ THE DOCUMENTATION FIRST. Not only -does it tell you how to do it, but it has some warnings about compatibility. - -Note that v3.0 does *NOT* unpack archives compressed with GS/ShrinkIt. The -problem is that NuLib cannot at present decode LZW/II compression. You can -read comments and extract files that were added without compression, but -that's about it. - -To compile this on a UNIX-type system, edit the file "nudefs.h". Several -systems are predefined; the default is a BSD UNIX system. If you want -to run this on something other than BSD, comment out the #define statements -(using "/*" and "*/"), and uncomment the appropriate statements. Then, -type "make" to execute the Makefile. If all goes well, you will be -left with an executable file called "nulib". If all does not go well, -double check "nudefs.h". Send some mail to me if you can't get it to work -at all. - -Currently AT&T 3B2 machines seem to be very uncooperative. If somebody gets -NuLib to run on one, please let me know. The problem is in the directory -manipulation routines (struct dirent, opendir(), readdir(), etc). - -To make the MS-DOS version, use the nulib.mak and nulib.lnk files with MS C -(supplied by Bruce Kahn). To make the APW version, put all the files in -one directory, and make a subdirectory called "OBJ". Put the "linked.scr" -and "linker.scr" files in OBJ, and then "make.apw". This will compile all -the files. When it finishes, change to OBJ and "alink linked.scr" (standard -linker) or "alink linker.scr" (ZapLink). The makefile used to do this -automatically, but with only 1.25MB of RAM you have to exit APW to purge -all the memory used by the compiler, and and then restart APW and -run the linker. - -In both cases, BE SURE to modify "nudefs.h" first. If you don't, the -compilation will halt in "numain.c" on a line which reminds you to change -"nudefs.h" (I tended to forget about this). Also, make sure all the file -types are set to SRC, and the auxtype to CC. These are changed with the -commands "filetype" and "change", respectively. - -Please send bug reports, ideas, or gripes to fadden@cory.berkeley.edu, or to -one of the addresses mentioned in the documentation or under the "-hw" -option. - -Known bugs: - - Under some systems, using UNIX compress on a file which does not compress -will cause the archive's EOF to be larger than it should be. This slack -space will be used up if you add more files to the archive (with NuLib -anyway; no guarantees about ShrinkIt or GS/ShrinkIt, but there's no reason -why they shouldn't work). - -(just to make things clear: if the file being compressed doesn't get any -smaller, the compression halts and the file is simply stored uncompressed. -Because of the way compress works, on some systems the space that would -have been occupied by more compressed data is left attached to the file. -The ShrinkIt compression does not suffer from this problem. If you add -more stuff to the file, NuLib will fill the slack space first, NOT just -append to the end of the file). - -Things to come: - - LZW/II decompression (for GS/ShrinkIt archives) - - Support for UNIX tar archives - - CRLF translations while adding files - - Better handling of comments - -Don't hold your breath waiting for these... - -I can be reached at: - fadden@cory.berkeley.edu (primary e-mail account) - fadden@hermes.berkeley.edu (secondary e-mail, since primary is buggy) - -All this stuff, and documentation as well, is available via anonymous FTP at: - avalanche.berkeley.edu - tornado.berkeley.edu - headcrash.berkeley.edu - ... -in pub/Apple2 - =nucomp.c -/* - * nucomp.c - code to perform UNIX style LZW compression - * - * NuLib v3.0 February 1991 Freeware (distribute, don't sell) - * By Andy McFadden (fadden@cory.berkeley.edu) - * - * This is the main compression code from compress v4.3. Modifications - * have been made to integrate it with NuLib (primarily in that it no longer - * uses stdin/stdout), but it's functionally the same. - */ -#ifdef APW -segment "Compress" -#endif - -#include "nudefs.h" -#include "nupak.h" -#define MAIN /* cause nucomp.h to alloc global vars */ - -/*@H************************ < COMPRESS API > **************************** -* * -* compress : compapi.c <current version of compress algorithm> * -* * -* 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*/ - -#include <stdio.h> -#define assert(x) -#include "nucomp.h" /* contains the rest of the include file declarations */ - -FILE *nustdin, *nustdout; /* NuLib: use these instead of stdin/stdout */ -long nubytes_read, nucomp_thread_eof; /* NuLib: used in nextcode (decomp) */ - -/* 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; - -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 */ - -static CODE prefxcode, nextfree; -static CODE highcode; -static CODE maxcode; -static HASH hashsize; -static int bits; - - -/* - * The following two parameter tables are the hash table sizes and - * maximum code values for various code bit-lengths. The requirements - * are that Hashsize[n] must be a prime number and Maxcode[n] must be less - * than Maxhash[n]. Table occupancy factor is (Maxcode - 256)/Maxhash. - * Note: I am using a lower Maxcode for 16-bit codes in order to - * keep the hash table size less than 64k entries. - */ -CONST HASH hs[] = { - 0x13FF, /* 12-bit codes, 75% occupancy */ - 0x26C3, /* 13-bit codes, 80% occupancy */ - 0x4A1D, /* 14-bit codes, 85% occupancy */ - 0x8D0D, /* 15-bit codes, 90% occupancy */ - 0xFFD9 /* 16-bit codes, 94% occupancy, 6% of code values unused */ -}; -#define Hashsize(maxb) (hs[(maxb) -MINBITS]) - -CONST CODE mc[] = { - 0x0FFF, /* 12-bit codes */ - 0x1FFF, /* 13-bit codes */ - 0x3FFF, /* 14-bit codes */ - 0x7FFF, /* 15-bit codes */ - 0xEFFF /* 16-bit codes, 6% of code values unused */ -}; -#define Maxcode(maxb) (mc[(maxb) -MINBITS]) - -#define allocx(type,ptr,size) \ - (((ptr) = (type FAR *) emalloc((unsigned int)(size),sizeof(type))) == NULLPTR(type) \ - ? NOMEM : OK \ - ) - -#define free_array(type,ptr,offset) \ - if (ptr != NULLPTR(type)) { \ - efree((ALLOCTYPE FAR *)((ptr) + (offset))); \ - (ptr) = NULLPTR(type); \ - } - - /* - * Macro to allocate new memory to a pointer with an offset value. - */ -#define alloc_array(type, ptr, size, offset) \ - ( allocx(type, ptr, (size) - (offset)) != OK \ - ? NOMEM \ - : (((ptr) -= (offset)), OK) \ - ) - -static char FAR *sfx = NULLPTR(char) ; -#define suffix(code) sfx[code] - - -#ifdef SPLIT_PFX - static CODE FAR *pfx[2] = {NULLPTR(CODE), NULLPTR(CODE)}; -#else - static CODE FAR *pfx = NULLPTR(CODE); -#endif - - -#ifdef SPLIT_HT - static CODE FAR *ht[2] = {NULLPTR(CODE),NULLPTR(CODE)}; -#else - static CODE FAR *ht = NULLPTR(CODE); -#endif - - -int alloc_tables(maxcode, hashsize) - CODE maxcode; - HASH hashsize; -{ - static CODE oldmaxcode = 0; - static HASH oldhashsize = 0; - - if (hashsize > oldhashsize) { -#ifdef SPLIT_HT - free_array(CODE,ht[1], 0); - free_array(CODE,ht[0], 0); -#else - free_array(CODE,ht, 0); -#endif - oldhashsize = 0; - } - - if (maxcode > oldmaxcode) { -#ifdef SPLIT_PFX - free_array(CODE,pfx[1], 128); - free_array(CODE,pfx[0], 128); -#else - free_array(CODE,pfx, 256); -#endif - free_array(char,sfx, 256); - - if ( alloc_array(char, sfx, maxcode + 1, 256) -#ifdef SPLIT_PFX - || alloc_array(CODE, pfx[0], (maxcode + 1) / 2, 128) - || alloc_array(CODE, pfx[1], (maxcode + 1) / 2, 128) -#else - || alloc_array(CODE, pfx, (maxcode + 1), 256) -#endif - ) { - oldmaxcode = 0; - exit_stat = NOMEM; - return(NOMEM); - } - oldmaxcode = maxcode; - } - if (hashsize > oldhashsize) { - if ( -#ifdef SPLIT_HT - alloc_array(CODE, ht[0], (hashsize / 2) + 1, 0) - || alloc_array(CODE, ht[1], hashsize / 2, 0) -#else - alloc_array(CODE, ht, hashsize, 0) -#endif - ) { - oldhashsize = 0; - exit_stat = NOMEM; - return(NOMEM); - } - oldhashsize = hashsize; - } - return (OK); -} - -# ifdef SPLIT_PFX - /* - * We have to split pfx[] table in half, - * because it's potentially larger than 64k bytes. - */ -# define prefix(code) (pfx[(code) & 1][(code) >> 1]) -# else - /* - * Then pfx[] can't be larger than 64k bytes, - * or we don't care if it is, so we don't split. - */ -# define prefix(code) (pfx[code]) -# endif - - -/* 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(). */ - -# ifdef SPLIT_HT - /* - * We have to split ht[] hash table in half, - * because it's potentially larger than 64k bytes. - */ -# define probe(hash) (ht[(hash) & 1][(hash) >> 1]) -# define init_tables() \ - { \ - hash = hashsize >> 1; \ - ht[0][hash] = 0; \ - while (hash--) ht[0][hash] = ht[1][hash] = 0; \ - highcode = ~(~(CODE)0 << (bits = INITBITS)); \ - nextfree = (block_compress ? FIRSTFREE : 256); \ - } - -# else - - /* - * Then ht[] can't be larger than 64k bytes, - * or we don't care if it is, so we don't split. - */ -# define probe(hash) (ht[hash]) -# define init_tables() \ - { \ - hash = hashsize; \ - while (hash--) ht[hash] = 0; \ - highcode = ~(~(CODE)0 << (bits = INITBITS)); \ - nextfree = (block_compress ? FIRSTFREE : 256); \ - } - -# endif - -#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 () -{ - register long int rat; - - checkpoint = in_count + CHECK_GAP; -#ifndef NDEBUG - if ( debug ) { - fprintf ( stderr, "count: %ld, ratio: ", in_count ); - prratio ( stderr, in_count, bytes_out ); - fprintf ( stderr, "\n"); - } -#endif - - 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; - return FALSE; - } - else { - ratio = 0; -#ifndef NDEBUG - if(debug) - fprintf ( stderr, "clear\n" ); -#endif - return TRUE; /* clear the table */ - } - return FALSE; /* don't clear the table */ -} -#endif - -/* - * compress stdin to stdout <-- nope - * NuLib: compress thread_eof bytes from srcfd, writing to dstfd - * Sets up a few things and then calls u_compress. - */ -int u_compress(srcfd, dstfd, thread_eof) -int srcfd, dstfd; -long thread_eof; -{ - int src2, dst2; - long srcposn, dstposn; - static char *procName = "u_compress"; - - if ((srcposn = lseek(srcfd, 0L, S_REL)) < 0) - Fatal("Bad posn lseek(1)", procName); - if ((dstposn = lseek(dstfd, 0L, S_REL)) < 0) - Fatal("Bad posn lseek(2)", procName); - - src2 = dup(srcfd); - dst2 = dup(dstfd); - - /* NuLib: open new stdin/stdout, and seek */ - if ((nustdin = fdopen(src2, FREAD_STR)) == NULL) - Fatal("can't fdopen() nustdin", procName); - if ((nustdout = fdopen(dst2, FWRITE_STR)) == NULL) - Fatal("can't fdopen() nustdout", procName); - setvbuf(nustdin,xbuf,_IOFBF,XBUFSIZE); /* make the buffers larger */ - setvbuf(nustdout,zbuf,_IOFBF,ZBUFSIZE); /* (note setvbuf is a macro) */ - if (fseek(nustdin, srcposn, S_ABS) < 0) /* seek may not be needed */ - Fatal("Bad stream posn lseek(1)", procName); - if (fseek(nustdout, dstposn, S_ABS) < 0) - Fatal("Bad stream posn lseek(2)", procName); - - oldbits = 0; /* init for putcode() */ - compress(thread_eof); - check_error(); - - fclose(nustdin); /* note this closes the duped fd */ - fclose(nustdout); - return (exit_stat); -} - -void compress(thread_eof) -long thread_eof; -{ - int c,adjbits; - register HASH hash; - register CODE code; - HASH hashf[256]; - - max_bytes_out = thread_eof; /* NuLib: don't exceed original size */ - maxcode = Maxcode(maxbits); - hashsize = Hashsize(maxbits); - -#ifdef COMP40 -/* Only needed for adaptive reset */ - checkpoint = CHECK_GAP; - ratio = 0; -#endif - - adjbits = maxbits -10; - for (c = 256; --c >= 0; ){ - hashf[c] = ((( c &0x7) << 7) ^ c) << adjbits; - } - exit_stat = OK; - if (alloc_tables(maxcode, hashsize)) /* exit_stat already set */ - return; - init_tables(); - /* if not zcat or filter (NuLib: never happens) */ - if(is_list && !zcat_flg) { /* Open output file */ - if (freopen(ofname, WRITE_FILE_TYPE, nustdout) == NULL) { - exit_stat = NOTOPENED; - return; - } - if (!quiet) - fprintf(stderr, "%s: ",ifname); - setvbuf(nustdout,zbuf,_IOFBF,ZBUFSIZE); - } - /* - * Check the input stream for previously seen strings. We keep - * adding characters to the previously seen prefix string until we - * get a character which forms a new (unseen) string. We then send - * the code for the previously seen prefix string, and add the new - * string to our tables. The check for previous strings is done by - * hashing. If the code for the hash value is unused, then we have - * a new string. If the code is used, we check to see if the prefix - * and suffix values match the current input; if so, we have found - * a previously seen string. Otherwise, we have a hash collision, - * and we try secondary hash probes until we either find the current - * string, or we find an unused entry (which indicates a new string). - */ - if (!nomagic) { - putc(magic_header[0], nustdout); /* was putchar() */ - putc(magic_header[1], nustdout); /* was putchar() */ - putc((char)(maxbits | block_compress), nustdout); /*was putchar*/ - if(ferror(nustdout)){ /* check it on entry */ - exit_stat = WRITEERR; - return; - } - bytes_out = 3L; /* includes 3-byte header mojo */ - } - else - bytes_out = 0L; /* no 3-byte header mojo */ - in_count = 1L; - offset = 0; - - if ((c = getc(nustdin)) == EOF) { /* NuLib: was getchar() */ - exit_stat = ferror(nustdin) ? READERR : OK; - return; - } - prefxcode = (CODE)c; - - while ((c = getc(nustdin)) != EOF) { /* NuLib: was getchar() */ - in_count++; - -/* NuLib : May not be compressing entire file, so can't rely on EOF for end */ - if (in_count > thread_eof) break; - - hash = prefxcode ^ hashf[c]; - /* I need to check that my hash value is within range - * because my 16-bit hash table is smaller than 64k. - */ - if (hash >= hashsize) - hash -= hashsize; - if ((code = probe(hash)) != UNUSED) { - if (suffix(code) != (char)c || prefix(code) != prefxcode) { - /* hashdelta is subtracted from hash on each iteration of - * the following hash table search loop. I compute it once - * here to remove it from the loop. - */ - HASH hashdelta = (0x120 - c) << (adjbits); - do { - /* rehash and keep looking */ - assert(code >= FIRSTFREE && code <= maxcode); - if (hash >= hashdelta) hash -= hashdelta; - else hash += (hashsize - hashdelta); - assert(hash < hashsize); - if ((code = probe(hash)) == UNUSED) - goto newcode; - } while (suffix(code) != (char)c || prefix(code) != prefxcode); - } - prefxcode = code; - } - else { - newcode: { - putcode(prefxcode, bits); - code = nextfree; - assert(hash < hashsize); - assert(code >= FIRSTFREE); - assert(code <= maxcode + 1); - if (code <= maxcode) { - probe(hash) = code; - prefix(code) = prefxcode; - suffix(code) = (char)c; - if (code > highcode) { - highcode += code; - ++bits; - } - nextfree = code + 1; - } -#ifdef COMP40 - else if (in_count >= checkpoint && block_compress ) { - if (cl_block()){ -#else - else if (block_compress){ -#endif - putcode((CODE)c, bits); - putcode((CODE)CLEAR,bits); - init_tables(); - if ((c = getc(nustdin)) == EOF) /* NuLib: was getchar*/ - break; - in_count++; -#ifdef COMP40 - } -#endif - } - prefxcode = (CODE)c; - } - } - } - putcode(prefxcode, bits); - putcode((CODE)CLEAR, 0); - if (ferror(nustdout)){ /* check it on exit */ - exit_stat = WRITEERR; - return; - } - /* - * Print out stats on stderr - */ - if(zcat_flg == 0 && !quiet) { -#ifndef NDEBUG - fprintf( stderr, - "%ld chars in, (%ld bytes) out, compression factor: ", - in_count, bytes_out ); - prratio( stderr, in_count, bytes_out ); - fprintf( stderr, "\n"); - fprintf( stderr, "\tCompression as in compact: " ); - prratio( stderr, in_count-bytes_out, in_count ); - fprintf( stderr, "\n"); - fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n", - prefxcode - 1, bits ); -#else - fprintf( stderr, "Compression: " ); - prratio( stderr, in_count-bytes_out, in_count ); -#endif /* NDEBUG */ - } - if(bytes_out > in_count) /* if no savings */ - exit_stat = NOSAVING; - - packedSize = bytes_out; /* NuLib : return packed size in global */ - - return ; -} - -CONST UCHAR rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; - -void putcode(code,bits) -CODE code; -register int bits; -{ - static UCHAR outbuf[MAXBITS]; - register UCHAR *buf; - register int shift; - register int ok_to_write; /* NuLib (kludge... sorry) */ - - ok_to_write = (exit_stat != NOSAVING); - - if (bits != oldbits) { - if (bits == 0) { - /* bits == 0 means EOF, write the rest of the buffer. */ - if (offset > 0) { - int x = ((offset+7) >> 3); /* NuLib */ - - if ((bytes_out + x) > max_bytes_out) { /* NuLib */ - /* compression failed. There's no clean way of bailing out - /* (could use setjmp/longjmp, but that may not be supported - /* on all systems), so just don't write anything. - */ - exit_stat = NOSAVING; - ok_to_write = FALSE; - } else { -/* fwrite(outbuf,1,(offset +7) >> 3, nustdout);*/ - fwrite(outbuf,1, x, nustdout); - } -/* bytes_out += ((offset +7) >> 3);*/ - bytes_out += x; - } - offset = 0; - oldbits = 0; - fflush(nustdout); - return; - } - else { - /* Change the code size. We must write the whole buffer, - * because the expand side won't discover the size change - * until after it has read a buffer full. - */ - if (offset > 0) { - if (ok_to_write) fwrite(outbuf, 1, oldbits, nustdout); - bytes_out += oldbits; - offset = 0; - } - oldbits = bits; -#ifndef NDEBUG - if ( debug ) - fprintf( stderr, "\nChange to %d bits\n", bits ); -#endif /* !NDEBUG */ - } - } - /* Get to the first byte. */ - buf = outbuf + ((shift = offset) >> 3); - if ((shift &= 7) != 0) { - *(buf) |= (*buf & rmask[shift]) | (UCHAR)(code << shift); - *(++buf) = (UCHAR)(code >> (8 - shift)); - if (bits + shift > 16) - *(++buf) = (UCHAR)(code >> (16 - shift)); - } - else { - /* Special case for fast execution */ - *(buf) = (UCHAR)code; - *(++buf) = (UCHAR)(code >> 8); - } - if ((offset += bits) == (bits << 3)) { - bytes_out += bits; - if (ok_to_write) fwrite(outbuf,1,bits,nustdout); - offset = 0; - } - return; -} - -int nextcode(codeptr) -CODE *codeptr; -/* Get the next code from input and put it in *codeptr. - * Return (TRUE) on success, or return (FALSE) on end-of-file. - * Adapted from COMPRESS V4.0. - */ -{ - register CODE code; - static int size; - static UCHAR inbuf[MAXBITS]; - register int shift; - UCHAR *bp; - - /* If the next entry is a different bit-size than the preceeding one - * then we must adjust the size and scrap the old buffer. - */ - if (prevbits != bits) { - prevbits = bits; - size = 0; - } - /* If we can't read another code from the buffer, then refill it. - */ - if (size - (shift = offset) < bits) { - static int bytesize; /* NuLib: sigh */ - /* Read more input and convert size from # of bytes to # of bits */ - - /* NuLib: stop after comp_thread_eof bytes */ - if (nubytes_read >= nucomp_thread_eof) - return(NO); - - /* NuLib: replace old fread command with... */ - /* - if ((size = fread(inbuf, 1, bits, nustdin) << 3) <= 0 || ferror(nustdin)) - return(NO); - */ - - bytesize = fread(inbuf, 1, bits, nustdin); - if (nubytes_read + bits > nucomp_thread_eof) { - bytesize = nucomp_thread_eof - nubytes_read; - } - size = bytesize << 3; - if (size <= 0 || ferror(nustdin)) - return (NO); - - /* NuLib: increment nubytes_read */ - nubytes_read += (long) bytesize; - - offset = shift = 0; - } - /* Get to the first byte. */ - bp = inbuf + (shift >> 3); - /* Get first part (low order bits) */ - code = (*bp++ >> (shift &= 7)); - /* high order bits. */ - code |= *bp++ << (shift = 8 - shift); - if ((shift += 8) < bits) code |= *bp << shift; - *codeptr = code & highcode; - offset += bits; - return (TRUE); -} - -/* - * NuLib: uncompress comp_thread_eof bytes from srcfd, writing to dstfd - * Sets up a few things and then calls compress. - */ -int u_decompress(srcfd, dstfd, comp_thread_eof) -int srcfd, dstfd; -long comp_thread_eof; -{ - int src2, dst2; - long srcposn, dstposn; - static char *procName = "u_decompress"; - - if ((srcposn = lseek(srcfd, 0L, S_REL)) < 0) - Fatal("Bad posn lseek(1)", procName); - if ((dstposn = lseek(dstfd, 0L, S_REL)) < 0) - Fatal("Bad posn lseek(2)", procName); - - src2 = dup(srcfd); - dst2 = dup(dstfd); - - /* NuLib: open new stdin/stdout, and seek */ - if ((nustdin = fdopen(src2, FREAD_STR)) == NULL) - Fatal("can't fdopen() nustdin", procName); - if ((nustdout = fdopen(dst2, FWRITE_STR)) == NULL) - Fatal("can't fdopen() nustdout", procName); - setvbuf(nustdin,zbuf,_IOFBF,ZBUFSIZE); /* make the buffers larger */ - setvbuf(nustdout,xbuf,_IOFBF,XBUFSIZE); /* (note order diff from comp) */ - if (fseek(nustdin, srcposn, S_ABS) < 0) /* seek may not be needed */ - Fatal("Bad stream posn lseek(1)", procName); - if (fseek(nustdout, dstposn, S_ABS) < 0) - Fatal("Bad stream posn lseek(2)", procName); - - /* Check the magic number */ - if (!nomagic) { - if ((getc(nustdin)!=(magic_header[0] & 0xFF)) /* NuLib: was getchar*/ - || (getc(nustdin)!=(magic_header[1] & 0xFF))) {/* NuLib: was getchar*/ - fprintf(stderr, "decompress: not in compressed format\n"); - return(-1); /* NuLib: was exit(ERROR) */ - } - maxbits = getc(nustdin); /* set -b from file (NuLib: was getchar) */ - block_compress = maxbits & BLOCK_MASK; - maxbits &= BIT_MASK; - if(maxbits > MAXBITS) { - fprintf(stderr, - "decompress: compressed with %d bits, can only handle %d bits\n", - maxbits, MAXBITS); - return(-1); /* NuLib: was exit(ERROR) */ - } - nubytes_read = 3L; - } else { - nubytes_read = 0L; - } - - nucomp_thread_eof = comp_thread_eof; -/* printf("src file posn = %ld\n", ftell(nustdin));*/ - prevbits = 0; /* init for nextcode() */ - decompress(); - check_error(); - - fclose(nustdin); /* note this closes the duped fd */ - fclose(nustdout); - return (exit_stat); -} - -void decompress() -{ - register int i; - register CODE code; - char sufxchar; - CODE savecode; - FLAG fulltable, cleartable; - static char token[MAXTOKLEN]; /* String buffer to build token */ - - exit_stat = OK; - - if (alloc_tables(maxcode = ~(~(CODE)0 << maxbits),0)) /* exit_stat already set */ - return; - - /* if not zcat or filter (NuLib: never) */ - if(is_list && !zcat_flg) { /* Open output file */ - if (freopen(ofname, WRITE_FILE_TYPE, nustdout) == NULL) { - exit_stat = NOTOPENED; - return; - } - if (!quiet) - fprintf(stderr, "%s: ",ifname); - setvbuf(nustdout,xbuf,_IOFBF,XBUFSIZE); - } - cleartable = TRUE; - savecode = CLEAR; - offset = 0; - do { - if ((code = savecode) == CLEAR && cleartable) { - highcode = ~(~(CODE)0 << (bits = INITBITS)); - fulltable = FALSE; - nextfree = (cleartable = block_compress) == FALSE ? 256 : FIRSTFREE; - if (!nextcode(&prefxcode)) - break; - putc((sufxchar = (char)prefxcode), nustdout); - continue; - } - i = 0; - if (code >= nextfree && !fulltable) { - if (code != nextfree){ - exit_stat = CODEBAD; -/* fprintf(stderr, "Bad code; nubytes_read = %ld\n", nubytes_read); */ - /* CDEBUG */ - return ; /* Non-existant code */ - } - /* Special case for sequence KwKwK (see text of article) */ - code = prefxcode; - token[i++] = sufxchar; - } - /* Build the token string in reverse order by chasing down through - * successive prefix tokens of the current token. Then output it. - */ - while (code >= 256) { -#ifndef NDEBUG - /* These are checks to ease paranoia. Prefix codes must decrease - * monotonically, otherwise we must have corrupt tables. We can - * also check that we haven't overrun the token buffer. - */ - if (code <= prefix(code)){ - exit_stat= TABLEBAD; - return; - } - if (i >= MAXTOKLEN){ - exit_stat = TOKTOOBIG; - return; - } -#endif - token[i++] = suffix(code); - code = prefix(code); - } - putc(sufxchar = (char)code, nustdout); - while (--i >= 0) - putc(token[i], nustdout); - if (ferror(nustdout)) { - exit_stat = WRITEERR; - return; - } - /* If table isn't full, add new token code to the table with - * codeprefix and codesuffix, and remember current code. - */ - if (!fulltable) { - code = nextfree; - assert(256 <= code && code <= maxcode); - prefix(code) = prefxcode; - suffix(code) = sufxchar; - prefxcode = savecode; - if (code++ == highcode) { - if (highcode >= maxcode) { - fulltable = TRUE; - --code; - } - else { - ++bits; - highcode += code; /* nextfree == highcode + 1 */ - } - } - nextfree = code; - } - - } while (nextcode(&savecode)); - exit_stat = (ferror(nustdin))? READERR : OK; - - return ; -} - - -/* - * These are routines pulled out of "compress.c" from compress v4.3. - */ -void prratio(stream, num, den) -FILE *stream; -long int num, den; -{ - register int q; /* Doesn't need to be long */ - - if(num > 214748L) { /* 2147483647/10000 */ - q = (int) (num / (den / 10000L)); - } - else { - q = (int) (10000L * num / den); /* Long calculations, though */ - } - if (q < 0) { - putc('-', stream); - q = -q; - } - fprintf(stream, "%d.%02d%%", q / 100, q % 100); -} - -/* - * Check exit status from compress() and decompress() - * - * exit_stat is a global var. Either returns something interesting or - * bails out completely. - */ -int check_error() /* returning OK continues with processing next file */ -{ - prog_name = prgName; /* NuLib: set prog_name to "nulib" */ - - switch(exit_stat) { - case OK: - return (OK); - case NOMEM: - if (do_decomp) - fprintf(stderr,"%s: not enough memory to decompress '%s'.\n", prog_name, ifname); - else - fprintf(stderr,"%s: not enough memory to compress '%s'.\n", prog_name, ifname); - return(OK); - case SIGNAL_ERROR: - fprintf(stderr,"%s: error setting signal interupt.\n",prog_name); - exit(ERROR); - break; - case READERR: - fprintf(stderr,"%s: read error on input '%s'.\n", prog_name, ifname); - break; - case WRITEERR: - fprintf(stderr,"%s: write error on output '%s'.\n", prog_name, ofname); - break; - case TOKTOOBIG: - fprintf(stderr,"%s: token too long in '%s'.\n", prog_name, ifname); - break; - case INFILEBAD: - fprintf(stderr, "%s: '%s' in unknown compressed format.\n", prog_name, ifname); - break; - case CODEBAD: - fprintf(stderr,"%s: file token bad in '%s'.\n", prog_name,ifname); - break; - case TABLEBAD: - fprintf(stderr,"%s: internal error -- tables corrupted.\n", prog_name); - break; - case NOTOPENED: - fprintf(stderr,"%s: could not open output file %s\n",prog_name,ofname); - exit(ERROR); - break; - case NOSAVING: - if (force) - exit_stat = OK; - return (OK); - default: - fprintf(stderr,"%s: internal error -- illegal return value = %d.\n", prog_name,exit_stat); - } - if (!zcat_flg && !keep_error){ - fclose(nustdout); /* won't get here without an error */ - unlink ( ofname ); - } - exit(exit_stat); - return(ERROR); -} - -/* - * These are routines from "compusi.c" - */ -void version() -{ -#ifdef XENIX -#ifndef NDEBUG - fprintf(stderr, "%s\nOptions: Xenix %s MAXBITS = %d\n", rcs_ident, - "DEBUG",MAXBITS); -#else - fprintf(stderr, "%s\nOptions: Xenix MAXBITS = %d\n", rcs_ident,MAXBITS); -#endif -#else -#ifndef NDEBUG - fprintf(stderr, "%s\nOptions: Unix %s MAXBITS = %d\n", rcs_ident, - "DEBUG",MAXBITS); -#else - fprintf(stderr, "%s\nOptions: Unix MAXBITS = %d\n", rcs_ident,MAXBITS); -#endif -#endif -} - -ALLOCTYPE FAR *emalloc(x,y) -unsigned int x; -int y; -{ - ALLOCTYPE FAR *p; - p = (ALLOCTYPE FAR *)ALLOCATE(x,y); - return(p); -} - -void efree(ptr) -ALLOCTYPE FAR *ptr; -{ - FREEIT(ptr); -} - + END OF ARCHIVE