home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************
- * ex:se ts=4 sw=4 ai:
- *
- * Data compression program.
- *
- * Author: Gene H. Olson
- * Smartware Consulting
- *
- * This is FREE software in the PUBLIC DOMAIN.
- *
- * This program may be used only for research into data
- * compression techniques. See WARNING in compact(1)
- * manual page for further discussion.
- *
- * "Everything FREE contains no guarantee."
- ********************************************************************/
-
- #define VERSION "compact version 1.0 PL0"
-
- #ifndef lint
- static char sccs[] = "@(#)compact.c 1.25 10/28/90" ;
- #endif
-
- #include <sys/lock.h>
-
- #include <fcntl.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <assert.h>
- #include <signal.h>
-
- #if MARK
- # include <prof.h>
- #else
- # define MARK(x)
- #endif
-
- extern void exit() ;
- extern char *memset() ;
- extern char *memcpy() ;
-
- extern char *share_create() ;
- extern char *share_open() ;
-
- #ifndef DEBUG
- # ifdef lint
- # define DEBUG 99
- # else
- # define DEBUG 0
- # endif
- #endif
-
- #ifndef CHECK
- # if DEBUG >= 2
- # define CHECK 100
- # else
- # define CHECK 0
- # endif
- #endif
-
- /*
- * Pet typedefs.
- */
-
- #define SWAP(x) (((ushort)(x) >> 8) | ((ushort)(x) << 8))
-
- #define uchar unsigned char
- #define ushort unsigned short
- #define ulong unsigned long
-
- #if lint
- #define malloc(x) 0
- #define realloc(x,y) 0
- #endif
-
- /*
- * Fundamental constants.
- */
-
- #define MAGIC 0xc5a3 /* Magic number */
- #define ODDMAGIC 0xc3a4 /* EOF magic for odd files */
- #define EVENMAGIC 0xc3a5 /* EOF magic for even files */
-
- #define MAXCHAR ((1 << 16) + 1) /* Size of character set */
-
- /*
- * Tuning parameter defaults.
- */
-
- #define MEMORY 0x40000000 /* Default bytes memory */
- #define INRUN 10000000 /* Default bytes input run */
-
- #ifndef HASHRATIO
- #define HASHRATIO 1.2 /* Ratio of hash entries to items */
- #endif
-
- /*
- * Compression item table definition.
- */
-
- #define HASHFUN(prefix, suffix) \
- ((((((prefix) << 3) + (suffix)) << 4) - (prefix) + (suffix)) & (hashmask))
-
- typedef struct h_struct ITEM ;
-
- struct h_struct
- {
- ITEM* h_next ; /* Next item on hash list */
- ITEM** h_last ; /* Link ptr to this item */
- ulong h_code ; /* Previous code */
- ushort h_char ; /* Current input character */
- ushort h_ref ; /* Reference flag */
- } ;
-
- int hashsize ; /* Hash table size (power 2) */
-
- int maxitem ; /* Maximum item number */
-
- /*
- * Decompression item table definition.
- */
-
- typedef struct d_struct DEC ;
-
- struct d_struct
- {
- ulong d_code ; /* Decompression code */
- ushort d_char ; /* Decompression character */
- ushort d_ref ; /* Reference flag */
- } ;
-
- /*
- * Caught signal list.
- */
-
- int sig[] = { SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, 0 } ;
-
- /*
- * Debugging stuff.
- */
-
- #if DEBUG >= 1
- int debug ; /* Debug level */
- #endif
-
- /*
- * Efficiency checks.
- */
-
- #if DEBUG >= 1
- long collision ;
- #endif
-
- /*
- * User parameters.
- */
-
- int action ; /* c==compact or e==expand */
-
- char *infname ; /* Input file name */
- char *outfname ; /* Output file name */
-
- int infd ; /* Input file descriptor */
- int outfd ; /* Output file descriptor */
-
- long inrun ; /* Maximum input run length */
-
- long memory ; /* Memory to use */
- long maxwidth ; /* Max width of output code */
-
- int quiet ; /* Quiet mode */
-
- int inbs ; /* Input block size */
- int outbs ; /* Output block size */
-
- int phys ; /* Output physical record size */
-
- int insize ; /* Input volume size (records) */
- int outsize ; /* Output volume size (records) */
-
- ulong inrec ; /* Input record number */
- ulong outrec ; /* Output record number */
-
- int incopy ; /* Read input to non-shared buffer */
- int outcopy ; /* Write output from non-shared buffer */
-
- int inswap ; /* Swap input bytes */
- int outswap ; /* Swap output bytes */
-
- int memlock ; /* Lock process into memory */
-
- int intank ; /* Number of input buffers */
- int outtank ; /* Number of output buffers */
-
- int inpid ; /* Input tank process PID */
- int outpid ; /* Output tank process PID */
-
- int (*getin)() ; /* Get input routine */
- int (*putout)() ; /* Put output routine */
-
- char *acommand ; /* Medium setup command */
- char *zcommand ; /* Medium teardown command */
-
- char *rsh ; /* Read share structure (opaque) */
- char *wsh ; /* Write share structure (opaque) */
-
- /*
- * Miscellaneous declarations.
- */
-
- int invol ; /* Input volume number */
- int outvol ; /* Output volume number */
-
- ushort *inbuf ; /* Input buffer */
- ushort *outbuf ; /* Output buffer */
-
- ushort *lastbuf ; /* Last buffer read by inprocess */
- int lastcount ; /* Corresponding buffer count */
-
- ulong intotal ; /* Input character count */
- ulong outtotal ; /* Output character count */
-
- ushort eofmagic ; /* EOF magic number */
-
-
-
- /**************************************************************
- * quit - Exit gracefully.
- **************************************************************/
-
- void
- quit(s)
- int s ;
- {
- register int i ;
- register int pid ;
- int rs ;
-
- for (i = 0 ; sig[i] ; i++) (void) signal(sig[i], SIG_IGN) ;
-
- /*
- * Close shared memory.
- */
-
- if (rsh) share_close(rsh) ;
- if (wsh) share_close(wsh) ;
-
- /*
- * Wait for inprocess and outprocess to complete.
- */
-
- while (inpid | outpid)
- {
- pid = wait(&rs) ;
- if (pid == -1) break ;
- if (inpid == pid)
- {
- inpid = 0 ;
- if (s == 0) s = rs ;
- }
- if (outpid == pid)
- {
- outpid = 0 ;
- if (s > 0) s = rs ;
- }
- }
-
- /*
- * Destroy allocated shared memory.
- */
-
- if (rsh) share_destroy(rsh) ;
- if (wsh) share_destroy(wsh) ;
-
- /*
- * Execute final teardown command.
- *
- * Note that if we were in compress mode with
- * multi-volume input, the zcommand has already
- * been done by the input() routine when prompting
- * for the last volume of the set.
- */
-
- if (s == 0 && zcommand && !(action == 'c' && insize))
- (void) system(zcommand) ;
-
- exit(s) ;
- }
-
-
-
- /***********************************************************
- * getval - Get value
- ***********************************************************/
-
- long
- getval(cp, units)
- register char *cp ;
- int units ;
- {
- register int val ;
-
- units = 0 ;
-
- if (!isdigit(*cp)) return(-1) ;
-
- val = 0 ;
- do
- {
- val *= 10 ;
- val += *cp++ - '0' ;
- } while (isdigit(*cp)) ;
-
- if (*cp) units = *cp++ ;
-
- switch (units)
- {
- case 'B':
- case 'b':
- val *= 512 ;
- break ;
-
- case 'K':
- case 'k':
- val *= 1024 ;
- break ;
-
- case 'M':
- case 'm':
- val *= 1000 * 1024 ;
- break ;
-
- case 0:
- break ;
-
- default:
- return(-1) ;
- }
-
- return (*cp==0 ? val : -1) ;
- }
-
-
-
- /************************************************************
- * confirm - Wait for volume load confirmation.
- ************************************************************/
-
- confirm()
- {
- register int n ;
- char ch ;
- int answer ;
- static int ttyfd = -1 ;
-
- /*
- * Get a file descriptor to reference the
- * users tty terminal.
- */
-
- if (ttyfd < 0)
- {
- if (isatty(0)) ttyfd = 0 ;
- else if ((ttyfd = open("/dev/tty", O_RDWR)) == -1)
- {
- (void) fprintf(stderr, "Cannot open ") ;
- perror("/dev/tty") ;
- quit(1) ;
- }
- }
-
- /*
- * Read the tty for the user's answer.
- */
-
- answer = 0 ;
-
- for (;;)
- {
- n = read(ttyfd, &ch, 1) ;
- if (n == 1)
- {
- if (ch == '\r' || ch == '\n') break ;
- if (answer == 0) answer = ch ;
- }
- if (n < 0)
- {
- perror("TTY") ;
- quit(1) ;
- }
- }
-
- return(answer) ;
- }
-
-
-
- /************************************************************
- * input - Get an input block.
- ************************************************************/
-
- input()
- {
- register int n ;
- register int i ;
- register ushort *wp ;
- int ch ;
- static int eoi ;
-
- if (eoi) return(0) ;
-
- /*
- * Loop to read in a full input record.
- */
-
- for (n = 0 ;;)
- {
- /*
- * Handle multi-volume input.
- */
-
- if (infname && inrec == 0)
- {
- /*
- * If not the first volume of an n-volume set,
- * ask for confirmation before opening the file.
- *
- * If he responds with (q), assume the last
- * volume has been read, and return end-of-file.
- */
-
- if (++invol > 1)
- {
- if (zcommand) (void) system(zcommand) ;
-
- for (;;)
- {
- (void) fprintf(stderr,
- "Mount input volume #%d, hit <RETURN> (or 'q' to quit)? ",
- invol) ;
-
- ch = confirm() ;
-
- if (ch == 0) break ;
-
- if (ch == 'q')
- {
- eoi = 1 ;
- goto done ;
- }
- }
-
-
- if (acommand) (void) system(acommand) ;
- }
-
- /*
- * Open the file.
- */
-
- if ((infd = open(infname, O_RDONLY)) == -1)
- {
- (void) fprintf(stderr, "Cannot open ") ;
- perror(infname) ;
- quit(1) ;
- }
- }
-
- /*
- * Read in records until we get a full record, an
- * end-of-file, or an error.
- */
-
- for (;;)
- {
- i = read(infd, (char*)inbuf + n, inbs - n) ;
-
- /*
- * Handle EOF. If we are not doing multi-volume input
- * consider this the EOI. If we are doing multi-volume
- * input, go back for the next volume.
- */
-
- if (i == 0)
- {
- (void) close(infd) ;
-
- if (insize)
- {
- inrec = 0 ;
- break ;
- }
-
- eoi = 1 ;
- goto done ;
- }
-
- /*
- * Handle a file I/O error.
- */
-
- if (i == -1)
- {
- n = -1 ;
- perror("Input read error") ;
- (void) close(infd) ;
- return(-1) ;
- }
-
- /*
- * A good read. Add the bytes read this time to
- * the running total. When we get a full record,
- * increment the volume record count. When the
- * full volume size is reached, reset the record
- * position so we go back for another volume next
- * time.
- */
-
- n += i ;
-
- if (n == inbs)
- {
- if (++inrec == insize)
- {
- (void) close(infd) ;
- inrec = 0 ;
- }
- goto done ;
- }
- }
- }
-
- /*
- * If byte swapping is in effect, swap all the
- * bytes in the current input buffer.
- */
-
- done:
- if (inswap)
- {
- wp = inbuf ;
- i = (n + 1) / 2 ;
- while (--i >= 0)
- {
- *wp = SWAP(*wp) ;
- wp++ ;
- }
- }
-
- return(n) ;
- }
-
-
-
- /******************************************************************
- * fileinput - File input.
- ******************************************************************/
-
- fileinput()
- {
- register int n ;
-
- n = input() ;
-
- if (n > 0)
- {
- intotal += n ;
- if (n & 1) eofmagic = ODDMAGIC ;
- }
-
- return((n + 1) / 2 - 1) ;
- }
-
-
-
- /******************************************************************
- * inprocess - Input process
- *
- * This procedure forks, then runs as a process reading from
- * the input device or pipe.
- ******************************************************************/
-
- inprocess()
- {
- register char *sh ;
- int rc ;
- ushort *buf ;
- ushort *ibuf ;
- ushort *wp ;
- int pfd[2] ;
- int cfd[2] ;
-
- rsh = share_create(pfd, cfd, inbs, intank) ;
- if (rsh == 0)
- {
- (void) fprintf(stderr, "Shared memory allocated failed\n") ;
- quit(1) ;
- }
-
- /*
- * Create the task. Setup file descriptors so the
- * inprocess will die on SIGPIPE if the primary process
- * exits, but no SIGPIPE occurs to the promary process
- * when inprocess exits.
- */
-
- while ((inpid = fork()) == -1) sleep(1) ;
-
- if (inpid == 0)
- {
- (void) close(1) ;
- (void) close(cfd[0]) ;
- (void) close(cfd[1]) ;
-
- /*
- * If input is done to a non-shared buffer,
- * allocate the buffer here.
- */
-
- if (incopy)
- {
- buf = (ushort *)malloc(inbs) ;
- if (buf == 0)
- {
- (void) fprintf(stderr, "Not enough memory\n") ;
- exit(1) ;
- }
- }
- else buf = 0 ;
-
- /*
- * Loop reading input blocks until done.
- */
-
- sh = share_open(pfd) ;
- assert(sh) ;
-
- for (;;)
- {
- /*
- * Get a block, read data into it, then pass it
- * to the data compression process.
- */
-
- if (share_get(sh, (char**)&inbuf, &rc) <= 0) break ;
-
- if (buf)
- {
- ibuf = inbuf ;
- inbuf = buf ;
- }
-
- if ((rc = input()) <= 0) break ;
-
- if (buf)
- {
- inbuf = ibuf ;
- (void) memcpy((char *)inbuf, (char *)buf, rc) ;
- }
-
- if (share_put(sh, (char*)inbuf, rc) <= 0) break ;
-
- /*
- * In data compression mode with multi-volume
- * input, detect EOI here so as to avoid prompting
- * the user unnecessarily for another volume.
- */
-
- if (action == 'e' && insize)
- {
- wp = inbuf + rc / sizeof(ushort) ;
-
- while (wp > inbuf && *--wp == 0) ;
-
- if ( wp >= inbuf
- && (*wp == ODDMAGIC || *wp == EVENMAGIC)
- && (wp == inbuf || *--wp == 0)
- && (wp == inbuf || *--wp == 0)
- && (wp == inbuf || *--wp == 0)
- )
- break ;
- }
- }
-
- #if DEBUG >= 2
- if (debug >= 2)
- {
- (void) fprintf(stderr, "Input child terminating normally\n") ;
- }
- #endif
-
- /*
- * Exit the child when complete.
- */
-
- share_close(sh) ;
-
- exit(0) ;
- }
-
- /*
- * Initialize the shared memory interface in the
- * parent process.
- */
-
- (void) close(pfd[1]) ;
-
- rsh = share_open(cfd) ;
- }
-
-
-
- /************************************************************
- * shareinput - Do input from shared memory.
- ************************************************************/
-
- shareinput()
- {
- int n ;
-
- if (inbuf) (void) share_put(rsh, (char*)inbuf, 0) ;
-
- if (share_get(rsh, (char**)&inbuf, &n) <= 0) return(-1) ;
-
- if (n > 0)
- {
- intotal += n ;
- if (n & 1) eofmagic = ODDMAGIC ;
- }
-
- return((n + 1) / 2 - 1) ;
- }
-
-
-
- /***********************************************************
- * output - Output a block of data.
- ***********************************************************/
-
- output(nbyte)
- int nbyte ; /* Number of bytes to write */
- {
- register ushort *wp ;
- register int n ;
- register int bsize ;
-
- /*
- * Open the output file if necessary.
- */
-
- if (outfname && outrec == 0)
- {
- if (++outvol > 1)
- {
- if (zcommand) (void) system(zcommand) ;
-
- (void) fprintf(stderr,
- "Please mount output volume #%d, hit <RETURN> ",
- outvol) ;
-
- (void) confirm() ;
-
- if (acommand) (void) system(acommand) ;
- }
-
- if ((outfd = open(outfname, O_WRONLY)) == -1)
- {
- (void) fprintf(stderr, "Cannot open ") ;
- perror(outfname) ;
- quit(1) ;
- }
- }
-
- /*
- * Swap output bytes if that option is selected.
- */
-
- if (outswap)
- {
- n = nbyte / 2 + 1 ;
- wp = outbuf ;
- while (--n >= 0)
- {
- *wp = SWAP(*wp) ;
- wp++ ;
- }
- }
-
- /*
- * Pad to a multiple of the given physical size if
- * that option is selected.
- */
-
- if (nbyte < outbs && phys)
- {
- wp = &outbuf[nbyte/2] ;
- bsize = (nbyte + phys - 1) / phys * phys ;
- while (nbyte < bsize)
- {
- *wp++ = 0 ;
- nbyte += 2 ;
- }
- }
-
- /*
- * Write the data and check for errors.
- */
-
- n = write(outfd, (char*) outbuf, (int) nbyte) ;
-
- if (n < 0)
- {
- perror("Write error") ;
- return(0) ;
- }
-
- if (n != nbyte)
- {
- (void) fprintf(stderr,
- "Write of %d bytes returned %d\n", nbyte, n) ;
- }
-
- if (++outrec == outsize)
- {
- outrec = 0 ;
- (void) close(outfd) ;
- }
-
- return(outbs) ;
- }
-
-
-
- /*****************************************************************
- * fileoutput - File oriented output routine.
- *****************************************************************/
-
- fileoutput(n)
- {
- if (n < outbs && phys) outtotal += (n + phys - 1) / phys * phys ;
- else outtotal += n ;
-
- return(output(n) / 2) ;
- }
-
-
-
- /******************************************************************
- * outprocess - Output process
- *
- * This procedure forks, then runs as a process writing to
- * the output device or pipe.
- ******************************************************************/
-
- outprocess()
- {
- int pfd[2] ;
- int cfd[2] ;
- int wcount ;
- int n ;
- char *sh ;
- ushort *obuf ;
- ushort *buf ;
-
- wsh = share_create(pfd, cfd, outbs, outtank) ;
- if (wsh == 0)
- {
- (void) fprintf(stderr, "Shared memory allocated failed\n") ;
- quit(1) ;
- }
-
- /*
- * Create the task. Setup file descriptors so the
- * primary process will die on SIGPIPE if outprocess
- * exits, but no SIGPIPE occurs to outprocess when
- * the primary process exits.
- */
-
- while ((outpid = fork()) == -1) sleep(1) ;
-
- if (outpid == 0)
- {
- (void) close(0) ;
- (void) close(pfd[1]) ;
-
- sh = share_open(cfd) ;
- assert(sh) ;
-
- if (outcopy)
- {
- buf = (ushort *)malloc(outbs) ;
- if (buf == 0)
- {
- (void) fprintf(stderr, "Not enough memory!\n") ;
- exit(1) ;
- }
- }
- else buf = 0 ;
-
- for (;;)
- {
- if (share_get(sh, (char**)&outbuf, &wcount) <= 0) break ;
-
- if (buf)
- {
- (void) memcpy((char *)buf, (char *)outbuf, wcount) ;
- obuf = outbuf ;
- outbuf = buf ;
- }
-
- if (output(wcount) <= 0) break ;
-
- if (buf) outbuf = obuf ;
-
- if (share_put(sh, (char*) outbuf, 0) <= 0) break ;
- }
-
- share_close(sh) ;
-
- exit(0) ;
- }
-
- (void) close(cfd[0]) ;
- (void) close(cfd[1]) ;
-
- wsh = share_open(pfd) ;
-
- (void) share_get(wsh, (char**)&outbuf, &n) ;
- }
-
-
-
- /********************************************************
- * shareoutput - Shared memory output routine.
- ********************************************************/
-
- shareoutput(n)
- int n ;
- {
- if (n < outbs && phys) outtotal += (n + phys - 1) / phys * phys ;
- else outtotal += n ;
-
- if (share_put(wsh, (char*) outbuf, n) <= 0) return(0) ;
-
- if (share_get(wsh, (char**)&outbuf, &n) <= 0) return(0) ;
-
- return(outbs/2) ;
- }
-
-
-
- /*************************************************************
- * check - keep track of the progress of the algorithm.
- *************************************************************/
-
- #if CHECK
- check(incount, outptr)
- int incount ;
- ushort *outptr ;
- {
- ulong in ;
- ulong out ;
- float avg ;
- float ratio ;
-
- static ulong lastin ;
- static ulong lastout ;
-
- in = intotal - incount * sizeof(ushort) ;
- out = outtotal + (long) outptr - (long) outbuf ;
-
- avg = 100.0 * (float) out / (float) in ;
- ratio = 100.0 * (float) (out - lastout) / (float) (in - lastin) ;
-
- lastin = in ;
- lastout = out ;
-
- #if DEBUG >= 1
- if (debug >= 1) (void) fprintf(stderr,
- "Read: %-8ld Wrote: %-8ld Col: %-8ld Ratio: %6.2f%% %6.2f%%\n",
- in, out, collision, ratio, avg
- ) ;
- #endif
- }
- #endif
-
-
-
- /**************************************************************
- * compact - Compression algorithm.
- **************************************************************/
-
- compact()
- {
- register ITEM *hp ;
- register ITEM *sp ;
- register ITEM **hpp ;
- register ushort *inptr ;
- register ushort *outptr ;
-
- register ulong ch ;
- register ulong code ;
- register ulong out ;
- register int obit ;
- register int osize ;
-
- register int incount ;
- register int outcount ;
- register ulong nitem ;
- register ulong mitem ;
- register ulong hashmask ;
-
- ITEM *itemtable ;
- ITEM **hashtable ;
-
- ITEM *ep ;
- long bitcount ;
- long blockcount ;
- long i ;
-
- ushort header[10] ;
-
- #if CHECK
- long chkcount = CHECK ;
- #endif
-
- /*
- * If max output width is given, set maxitem accordingly.
- */
-
- maxitem = (1 << maxwidth) - MAXCHAR ;
-
- /*
- * Reduce maxitem if necessary to fit into the requested
- * maximum memory.
- */
-
- i = memory / (sizeof(ITEM) + sizeof(ITEM *)) ;
- if (maxitem > i) maxitem = i ;
-
- /*
- * Set the hashtable to have the same approximate number
- * of entries as in maxitem, rounded to the closest
- * power of 2.
- */
-
- hashsize = HASHRATIO * maxitem ;
- while (i = hashsize & (hashsize - 1)) hashsize = i ;
- hashmask = hashsize - 1 ;
-
- #if DEBUG >= 2
- if (debug >= 2)
- {
- (void) fprintf(stderr,
- "hashsize = %ld (%ldK), maxitem = %ld (%ldK)\n",
- hashsize, sizeof(ITEM *) * hashsize / 1024,
- maxitem, sizeof(ITEM) * maxitem / 1024) ;
- }
- #endif
-
- /*
- * Allocate hash table and item table.
- */
-
- itemtable = (ITEM *)malloc(maxitem * sizeof(ITEM)) ;
- hashtable = (ITEM **)malloc(hashsize * sizeof(ITEM *)) ;
-
- if (itemtable == 0 || hashtable == 0)
- {
- (void) fprintf(stderr,
- "Cannot allocate enough memory!\n") ;
- exit(2) ;
- }
-
- /*
- * Initialize output.
- */
-
- outcount = outbs / 2 + 1 ;
- outptr = outbuf ;
- eofmagic = EVENMAGIC ;
-
- /*
- * Each pass through the loop, compress one block
- * of data.
- */
-
- for (;;)
- {
-
- #if DEBUG >= 1
- if (debug >= 1) (void) fprintf(stderr, "\n") ;
- #endif
-
- /*
- * Initialize for a new scan.
- */
-
- (void) memset((char*)hashtable, 0, (int)(hashsize * sizeof(ITEM *))) ;
-
- nitem = 0 ;
-
- sp = &itemtable[0] ;
- ep = &itemtable[maxitem] ;
-
- out = 0 ;
- obit = 0 ;
- code = 0 ;
- osize = 17 ;
- bitcount = (1 << 16) ;
-
- blockcount = inrun / inbs + .5 ;
-
- /*
- * Prepare the Magic number, and the maximum number
- * of output codes for transmission.
- */
-
- mitem = maxitem ;
-
- header[0] = MAGIC ;
- header[1] = 17 ;
- header[2] = maxitem & 0xffff ;
- header[3] = maxitem >> 16 ;
-
- for (i = 0 ; i < 4 ; i++)
- {
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
- *outptr++ = header[i] ;
- }
-
- /*
- * Read in the first input character of the run.
- */
-
- if ((incount = (*getin)()) < 0) goto endrun ;
-
- inptr = inbuf ;
- ch = *inptr++ ;
-
- /*
- * Each pass through the loop, compress 1 or
- * more input characters to output 1 compression
- * code.
- */
-
- for (;;)
- {
-
- MARK(cmatch) ;
-
- code = ch + 1 ;
-
- #if DEBUG >= 3
- if (debug >= 3) (void) fprintf(stderr,
- "\nMatching char: %04x\n", ch) ;
- #endif
-
- /*
- * Each time through the loop, match the next
- * input character if possible and continue.
- * Exit when the match fails.
- */
-
- for (;;)
- {
-
- /*
- * Read in the next input character.
- */
-
- if (--incount < 0)
- {
-
- if (--blockcount == 0)
- {
- incount = 0 ;
- goto endrun ;
- }
- #if CHECK
- if (--chkcount <= 0)
- {
- check(0, outptr) ;
- chkcount = CHECK ;
- }
- #endif
- if ((incount = (*getin)()) < 0) goto endrun ;
-
- inptr = inbuf ;
- }
-
- ch = *inptr++ ;
-
- #if DEBUG >= 3
- if (debug >= 3) (void) fprintf(stderr,
- "Read input char: %04x", ch) ;
- #endif
-
- /*
- * Search the hash table for the required
- * last code and current character.
- */
-
- hpp = &hashtable[HASHFUN(code, ch)] ;
-
- for (;;)
- {
- if ((hp = *hpp) == 0) goto miss ;
-
- if (hp->h_code == code && hp->h_char == ch) break ;
-
- hpp = &hp->h_next ;
- #if DEBUG >= 1
- collision++ ;
- #endif
- }
-
- code = hp - itemtable + MAXCHAR ;
-
- #if DEBUG >= 3
- if (debug >= 3) (void) fprintf(stderr,
- "\tMatched code: %lx\n", (ulong) code) ;
- #endif
- }
-
- /*
- * Output the next code.
- */
-
- miss:
- MARK(cout) ;
-
- out |= code << obit ;
- obit += osize ;
-
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- *outptr++ = out ;
-
- out >>= 16 ;
- obit -= 16 ;
-
- if (obit >= 16)
- {
-
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- *outptr++ = out ;
-
- if (obit > 16) out |= code >> (osize - obit) ;
-
- out >>= 16 ;
- obit -= 16 ;
- }
-
- #if DEBUG >= 3
- if (debug >= 3) (void) fprintf(stderr,
- "\nOutput code: %lx\n", (ulong) code) ;
- #endif
-
- MARK(cbuild) ;
-
- sp->h_next = 0 ;
- sp->h_last = hpp ;
- *hpp = sp ;
-
- sp->h_code = code ;
- sp->h_char = ch ;
- sp->h_ref = 0 ;
- sp++ ;
-
- if (code >= MAXCHAR) itemtable[code - MAXCHAR].h_ref = 1 ;
-
- #if DEBUG >= 3
- if (debug >= 3)
- {
- (void) fprintf(stderr,
- "Created compression code: %05lx ( %05lx %04x )\n",
- sp - itemtable + MAXCHAR - 1, code, ch) ;
- }
- #endif
- /*
- * If we added a new entry to the table, expand
- * the output bitsize if necessary.
- */
-
- if (nitem < mitem)
- {
- MARK(calloc) ;
-
- if (--bitcount == 0)
- {
- bitcount = 1 << osize ;
- osize++ ;
- #if DEBUG >= 2
- if (debug >= 2) (void) fprintf(stderr,
- "nitem = %d, osize = %d, bitcount = %d\n",
- nitem, osize, bitcount) ;
- #endif
- }
-
- if (++nitem != mitem) continue ;
- }
-
- /*
- * When the compress item table has become full,
- * find the least-recently-used leaf node and
- * reallocate it.
- */
-
- MARK(cscan) ;
-
- for (;;)
- {
- if (sp == ep) sp = itemtable ;
-
- if (sp->h_ref == 0) break ;
-
- if (sp->h_code >= MAXCHAR)
- {
- itemtable[sp->h_code - MAXCHAR].h_ref = 1 ;
- }
-
- sp->h_ref = 0 ;
- sp++ ;
- }
-
- *sp->h_last = sp->h_next ;
- if (sp->h_next) sp->h_next->h_last = sp->h_last ;
- }
-
- /*
- * Flush the output buffer, and add a few bytes
- * of zero to guarantee synchronization.
- */
-
- endrun:
- MARK(cend) ;
-
- #if DEBUG >= 3
- if (debug >= 3) (void) fprintf(stderr,
- "\nOutput final code: %lx\n", (ulong) code) ;
- #endif
-
- for (i = 0 ; i < 6 ; i++)
- {
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- out |= code << obit ;
-
- *outptr++ = out ;
-
- out >>= 16 ;
- code >>= 16 ;
- }
-
- if (incount < 0) break ;
-
- #if CHECK
- check(incount, outptr) ;
- chkcount = CHECK ;
- #endif
- }
-
- /*
- * Add the EOF code at the end.
- */
-
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- *outptr++ = eofmagic ;
-
- if ( outptr != outbuf
- && (*putout)((int) ((long)outptr-(long)outbuf)) == 0
- )
- return(1) ;
-
- #if DEBUG >= 1
- if (debug >= 1) check(0, outbuf) ;
- #endif
-
- if (!quiet && intotal != 0)
- {
- (void) fprintf(stderr,
- "Read %ld, Wrote %ld, Compression %6.2f%%\n",
- intotal, outtotal, 100.0 * (long)(intotal - outtotal) / intotal
- ) ;
- }
-
- #if DEBUG >= 1
- if (!quiet && intotal > 1)
- {
- (void) fprintf(stderr,
- "Collisions: %ld, %6.2f %%\n",
- collision,
- (100.0 * 17.0 / 16.0 * collision) / (intotal-1)
- ) ;
- }
- #endif
-
- return(0) ;
- }
-
-
-
- /***********************************************************
- * expand - Expand previously compressed data.
- ***********************************************************/
-
- expand()
- {
- register DEC *sp ;
- register DEC *dp ;
- register ushort *bp ;
- register ushort *outptr ;
- register ushort *inptr ;
-
- register int ibit ;
- register ulong in ;
- register ulong ch ;
- register ulong code ;
- register ulong lastcode ;
- register int incount ;
- register int outcount ;
-
- int bitcount ;
- ulong maxcode ;
- DEC *dectable ;
- DEC *ep ;
-
- int isize ;
- ulong imask ;
- ushort *ip ;
- ushort *buffer ;
- int ic ;
- int i ;
- ulong skip ;
- ulong zskip ;
- int state ;
- ulong ncode ;
- int err ;
- int magic ;
- int nbyte ;
-
- ushort header[4] ;
-
- /*
- * Initialize I/O buffers.
- */
-
- err = 0 ;
- incount = 0 ;
- magic = 0 ;
- outptr = outbuf ;
- outcount = outbs / 2 + 1 ;
- maxcode = 0 ;
- dectable = 0 ;
- buffer = 0 ;
-
- /*
- * Each time through the loop, process a complete
- * block of data.
- */
-
- state = 4 ;
-
- for (;;)
- {
-
- /*
- * Synchronize to the beginning of a new block of data.
- *
- * The file begins immediately with a magic number.
- *
- * Thereafter, blocks of decompression data are delimited
- * by at least two bytes of zero, followed by the two
- * byte magic number.
- */
-
- MARK(esync) ;
-
- skip = 0 ;
- zskip = 0 ;
-
- for (;;)
- {
- if (--incount < 0)
- {
- if ((incount = (*getin)()) < 0) break ;
- inptr = inbuf ;
- }
- in = *inptr++ ;
-
- if (in == 0)
- {
- if (state <= 4) state++ ;
- else zskip += sizeof(ushort) ;
- }
- else
- {
- if (state >= 2)
- {
- if (in == MAGIC)
- {
- magic = 1 ;
- break ;
- }
- if (in == (SWAP(MAGIC) & 0xffff))
- {
- if (!quiet) (void) fprintf(stderr,
- "Automatically reversing byte order!\n") ;
-
- inswap = !inswap ;
- outswap = !outswap ;
-
- ip = inptr ;
- ic = incount ;
- while (--ic >= 0)
- {
- *ip = SWAP(*ip) ;
- ip++ ;
- }
- magic = 1 ;
- break ;
- }
- if ((in == ODDMAGIC || in == EVENMAGIC) && magic)
- {
- eofmagic = in ;
- magic = 2 ;
- incount = -1 ;
- break ;
- }
- }
- skip += sizeof(ushort) ;
- state = 0 ;
- }
- }
-
- /*
- * Mention that data was skipped.
- */
-
- if (skip != 0 || zskip != 0 && incount >= 0)
- {
- (void) fprintf(stderr,
- "Warning: %d bytes of unintelligible data skipped!\n",
- skip + zskip) ;
- }
-
- if (incount < 0)
- {
- if (magic == 0) (void) fprintf(stderr,
- "Warning: Magic number not found!\n") ;
- if (magic == 1) (void) fprintf(stderr,
- "Warning: Old style EOF encountered!\n") ;
- goto eof ;
- }
-
- /*
- * Get the maximum code present in the data.
- */
-
- for (i = 1 ; i < 4 ; i++)
- {
- if (--incount < 0)
- {
- if ((incount = (*getin)()) < 0)
- {
- (void) fprintf(stderr, "EOF in header!\n") ;
- err = 1 ;
- goto eof ;
- }
- inptr = inbuf ;
- }
- header[i] = *inptr++ ;
- }
-
- code = header[3] ;
- code <<= 16 ;
- code |= header[2] ;
-
- #if DEBUG >= 2
- if (debug >= 2) (void) fprintf(stderr,
- "Read header, nbits=%d, maxitem=%d\n", header[1], code) ;
- #endif
-
- /*
- * Allocate the required memory.
- */
-
- if (maxcode != code)
- {
-
- dectable = dectable
- ? (DEC *) realloc((char*) dectable, code * sizeof(DEC))
- : (DEC *) malloc(code * sizeof(DEC))
- ;
-
- buffer = buffer
- ? (ushort *) realloc((char*)buffer, code * sizeof(ushort))
- : (ushort *) malloc(code * sizeof(ushort))
- ;
-
- if (dectable == 0 || buffer == 0)
- {
- (void) fprintf(stderr,
- "Cannot get enough memory to decode %d items\n", code) ;
- exit(1) ;
- }
-
- maxcode = code ;
- }
-
- sp = &dectable[0] ;
- ep = &dectable[maxcode] ;
-
- /*
- * Initialize to decompress this block of data.
- */
-
- in = 0 ;
- ibit = 0 ;
- ncode = 0 ;
- bp = buffer ;
-
- isize = 17 ;
- bitcount = (1 << 16) ;
- imask = 0x1ffff ;
-
- /*
- * Read in the first item, which must be a
- * single character.
- */
-
- do
- {
- if (--incount < 0)
- {
- if ((incount = (*getin)()) < 0)
- {
- (void) fprintf(stderr, "Premature eof!\n") ;
- err = 1 ;
- goto eof ;
- }
- inptr = inbuf ;
- }
- in |= *inptr++ << ibit ;
- ibit += 16 ;
- } while (ibit < 17) ;
-
- code = in & imask ;
-
- if (code == 0)
- {
- state = 0 ;
- continue ;
- }
-
- in >>= 17 ;
- ibit -= 17 ;
-
- if (code == 0)
- {
- (void) fprintf(stderr, "Null compression block!\n") ;
- break ;
- }
-
- ch = code - 1 ;
-
- #if DEBUG >= 3
- if (debug >= 3) (void) fprintf(stderr,
- "First input code: %05lx output as < %04x >\n", code, ch) ;
- #endif
-
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- *outptr++ = ch ;
-
- /*
- * Each time through the loop, read and process one
- * compressed item code.
- */
-
- MARK(eloop) ;
-
- for (;;)
- {
- lastcode = code ;
-
- /*
- * Expand the input bitsize if necessary.
- */
-
- if (ncode < maxcode)
- {
- MARK(ealloc) ;
-
- if (--bitcount == 0)
- {
- bitcount = 1 << isize ;
- isize++ ;
- imask += imask + 1 ;
- #if DEBUG >= 2
- if (debug >= 2) (void) fprintf(stderr,
- "ncode = %d, isize = %d, bitcount = %d\n",
- ncode, isize, bitcount) ;
- #endif
- }
- ncode++ ;
- }
-
- /*
- * If the table is full, find the oldest leaf node
- * and reallocate it.
- */
-
- else
- {
- MARK(escan) ;
-
- for (;;)
- {
- if (sp == ep) sp = dectable ;
- if (sp->d_ref == 0) break ;
- if (sp->d_code >= MAXCHAR)
- {
- dectable[sp->d_code - MAXCHAR].d_ref = 1 ;
- }
- sp->d_ref = 0 ;
- sp++ ;
- }
- }
-
- /*
- * Read in the next compression code.
- */
-
- MARK(eread) ;
-
- if (--incount < 0)
- {
- if ((incount = (*getin)()) < 0)
- {
- (void) fprintf(stderr, "Premature eof\n") ;
- err = 1 ;
- goto eof ;
- }
- inptr = inbuf ;
- }
-
- in |= *inptr++ << ibit ;
- ibit += 16 ;
-
- if (ibit >= isize)
- {
- code = in & imask ;
-
- in >>= isize ;
- ibit -= isize ;
- }
- else
- {
- if (--incount < 0)
- {
- if ((incount = (*getin)()) < 0)
- {
- (void) fprintf(stderr, "Premature eof\n") ;
- err = 1 ;
- goto eof ;
- }
- inptr = inbuf ;
- }
-
- if (ibit <= 16)
- {
- in |= (ulong) *inptr++ << ibit ;
-
- code = in & imask ;
-
- in >>= isize ;
- ibit -= isize - 16 ;
- }
- else
- {
- in |= (ulong) *inptr << ibit ;
-
- code = in & imask ;
-
- in >>= isize ;
- in |= (ulong) *inptr++ >> (isize - ibit) ;
-
- ibit -= isize - 16 ;
- }
- }
-
- #if DEBUG >= 4
- if (debug >= 4) (void) fprintf(stderr,
- "Read input code: %05lx\n", code) ;
- #endif
- /*
- * If a zero code is detected, start a new
- * decompression pass.
- *
- * If a character code is detected, output it.
- */
-
- MARK(eexpand) ;
-
- if (code < MAXCHAR)
- {
- if (code == 0) break ;
- ch = code ;
- }
-
- /*
- * Expand a compression code.
- *
- * If the code is the next one to be allocated,
- * then it was allocated by the compression program
- * already to be the lastcode + the first character
- * of the last code.
- *
- * Also check for an out-of-range decompression
- * code. Signal an error in this case.
- */
-
- else
- {
- if (code - MAXCHAR >= ncode)
- {
- (void) fprintf(stderr,
- "Decompress error - attempting resync\n") ;
- break ;
- }
-
- dp = &dectable[code - MAXCHAR] ;
-
- if (dp == sp)
- {
-
- if (sp - dectable == lastcode - MAXCHAR)
- {
- (void) fprintf(stderr,
- "Nasty decompress error - attempting resync\n") ;
- break ;
- }
-
- *bp++ = ch ;
-
- ch = lastcode ;
-
- if (ch >= MAXCHAR)
- {
-
- dp = &dectable[ch - MAXCHAR] ;
-
- for (;;)
- {
- *bp++ = dp->d_char ;
- ch = dp->d_code ;
- if (ch < MAXCHAR) break ;
- dp = &dectable[ch - MAXCHAR] ;
- }
- }
- }
-
- else
- {
- for (;;)
- {
- *bp++ = dp->d_char ;
- ch = dp->d_code ;
- if (ch < MAXCHAR) break ;
- dp = &dectable[ch - MAXCHAR] ;
- }
- }
- }
-
- ch -= 1 ;
-
- /*
- * Output the compression code data.
- */
-
- MARK(eout) ;
-
- #if DEBUG >= 3
- if (debug >= 3)
- {
- ushort *wp ;
- (void) fprintf(stderr, "Expanded code %05lx to <", code) ;
- wp = bp ;
- *wp++ = ch ;
- do
- {
- (void) fprintf(stderr, " %04x", *--wp) ;
- } while (wp != buffer) ;
- (void) fprintf(stderr, " >\n") ;
- }
- #endif
-
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- *outptr++ = ch ;
-
- while (bp != buffer)
- {
- if (--outcount <= 0)
- {
- if ((outcount = (*putout)(outbs)) == 0) return(1) ;
- outptr = outbuf ;
- }
-
- *outptr++ = *--bp ;
- }
-
- /*
- * Create a new code from the input data.
- */
-
- MARK(ebuild) ;
-
- sp->d_code = lastcode ;
- sp->d_char = ch ;
- sp->d_ref = 0 ;
- sp++ ;
-
- if (lastcode >= MAXCHAR) dectable[lastcode - MAXCHAR].d_ref = 1 ;
-
- #if DEBUG >= 3
- if (debug >= 3)
- {
- (void) fprintf(stderr,
- "Created compression code: %05lx ( %05lx %04x )\n",
- sp - dectable + MAXCHAR - 1, lastcode, ch) ;
- }
- #endif
- }
-
- state = 0 ;
- }
-
- eof:
- nbyte = (long)outptr - (long)outbuf ;
- if (eofmagic == ODDMAGIC) nbyte-- ;
-
- if (nbyte && (*putout)(nbyte) == 0) return(1) ;
-
- if (!quiet && intotal != 0)
- {
- (void) fprintf(stderr,
- "Read %ld, Wrote %ld, Expansion %6.2f%%\n",
- intotal, outtotal,
- 100.0 * (long)(outtotal - intotal) / intotal) ;
- }
-
- return(err) ;
- }
-
-
-
- /**************************************************************
- * main - main program.
- **************************************************************/
-
- main(argc, argv)
- int argc ;
- char **argv ;
- {
- register int i ;
- register int c ;
- register int err ;
- register int rs ;
- register char *p ;
- extern char *optarg ;
- extern int optind ;
-
- /*
- * Set default parameters.
- */
-
- infd = 0 ;
- outfd = 1 ;
-
- inbs = BUFSIZ ;
- outbs = BUFSIZ ;
-
- memory = MEMORY ;
- maxwidth = 17 ;
-
- inrun = INRUN ;
-
- /*
- * If command begins with 'e' or 'u', expand the
- * input file. Otherwise compress it.
- */
-
- p = argv[0] ;
- action = *p ;
- while (*p) if (*p++ == '/') action = *p ;
-
- if (action == 'u') action = 'e' ;
- else if (action != 'e') action = 'c' ;
-
- #if DEBUG >= 1
- debug = DEBUG ;
- #endif
-
- /*
- * Unpack parameters.
- */
-
- err = 0 ;
-
- for (;;)
- {
- c = getopt(argc, argv, "a:b:B:cd:ef:F:lm:n:N:p:qr:R:sSt:T:uvw:xXz:") ;
-
- if (c == EOF) break ;
-
- switch (c)
- {
-
- /*
- * Media setup command to be performed before
- * first open.
- */
-
- case 'a':
- acommand = optarg ;
- break ;
-
- /*
- * Input/output block size.
- */
-
- case 'b':
- inbs = getval(optarg, 'k') ;
- if (inbs <= 2 || (inbs & 1)) err++ ;
- break ;
-
- case 'B':
- outbs = getval(optarg, 'k') ;
- if (outbs <= 2 || (outbs & 1)) err++ ;
- break ;
-
- /*
- * Compress or expand action.
- */
-
- case 'c':
- case 'e':
- action = c ;
- break ;
-
- /*
- * Debug level.
- */
-
- #if DEBUG >= 1
- case 'd':
- debug = atoi(optarg) ;
- if (debug > DEBUG) err++ ;
- break ;
- #endif
-
- /*
- * Input/Output file name.
- */
-
- case 'f':
- infname = optarg ;
- break ;
-
- case 'F':
- outfname = optarg ;
- break ;
-
- /*
- * Lock process into memory.
- */
-
- case 'l':
- memlock = 1 ;
- break ;
-
- /*
- * Amount of memory to use.
- */
-
- case 'm':
- memory = getval(optarg, 'k') ;
- if (memory < 1) err++ ;
- break ;
-
- /*
- * Physical record size. Causes the last output
- * record to be padded with zeros to the next
- * multiple of this size if necessary.
- */
-
- case 'p':
- phys = getval(optarg, 'k') ;
- if (phys <= 2 || (phys & 1)) err++ ;
- break ;
-
- /*
- * Quiet mode.
- */
-
- case 'q':
- quiet = 1 ;
- break ;
-
- /*
- * Number of input/output records in volume.
- */
-
- case 'n':
- insize = getval(optarg, 'k') ;
- if (insize < 1) err++ ;
- break ;
-
- case 'N':
- outsize = getval(optarg, 'k') ;
- if (outsize < 1) err++ ;
- break ;
-
- /*
- * Maximum run length.
- */
-
- case 'r':
- inrun = getval(optarg, 0) ;
- if (inrun < 5) err++ ;
- break ;
-
- /*
- * Swap input or output bytes.
- */
-
- case 's':
- inswap++ ;
- break ;
-
- case 'S':
- outswap++ ;
- break ;
-
- /*
- * Tank size.
- */
-
- case 't':
- intank = getval(optarg, 0) ;
- if (intank < 2 || intank > 500) err++ ;
- break ;
-
- case 'T':
- outtank = getval(optarg, 0) ;
- if (outtank < 2 || outtank > 500) err++ ;
- break ;
-
- /*
- * Uncompress.
- */
-
- case 'u':
- action = 'e' ;
- break ;
-
- /*
- * Version.
- */
-
- case 'v':
- #if DEBUG >= 1
- (void) fprintf(stderr, "%s (debug %d)\n", VERSION, DEBUG) ;
- #else
- (void) fprintf(stderr, "%s\n", VERSION) ;
- #endif
- return(0) ;
-
- /*
- * Maximum output bit width.
- */
-
- case 'w':
- maxwidth = getval(optarg, 0) ;
- if (maxwidth < 17 || maxwidth > 24) err++ ;
- break ;
-
- /*
- * Read/Write data to/from non-shared memory buffers
- * to avoid driver problems.
- */
-
- case 'x':
- incopy = 1 ;
- break ;
-
- case 'X':
- outcopy = 1 ;
- break ;
-
- /*
- * Command to be performed after last close.
- */
-
- case 'z':
- zcommand = optarg ;
- break ;
-
- default:
- err++ ;
- }
- }
-
- /*
- * Check parameter consistency.
- */
-
- if (insize && !infname)
- {
- (void) fprintf(stderr, "-n requires -f\n") ;
- err++ ;
- }
-
- if (outsize && !outfname)
- {
- (void) fprintf(stderr, "-N requires -F\n") ;
- err++ ;
- }
-
- /*
- * Print the USAGE message.
- */
-
- if (optind != argc || err)
- {
- (void) fprintf(stderr, "Usage: %s %s%s%s", argv[0],
- "[-celqsSvxX] [-a cmd] [-b cbs] [-B ebs] [-f cfile] [-F efile]\n",
- "\t[-m memory] [-n cblks] [-N eblks] [-p outpad] [-r runsize]\n",
- "\t[-t cbuf] [-T ebuf] [-w width] [-z cmd]\n") ;
- exit(2) ;
- }
-
- /*
- * Adjust compression parameters.
- */
-
- if (action == 'c')
- {
- long i ;
- char *p ;
-
- /*
- * Switch parameters around if necessary so the lower
- * case options refer to the compressed file, and the
- * upper case letters refer to the expanded file.
- */
-
- if (phys == 0) phys = 512 ;
-
- i = insize ; insize = outsize ; outsize = i ;
- i = inbs ; inbs = outbs ; outbs = i ;
- i = intank ; intank = outtank ; outtank = i ;
- i = inswap ; inswap = outswap ; outswap = i ;
- i = incopy ; incopy = outcopy ; outcopy = i ;
- p = infname ; infname = outfname ; outfname = p ;
- }
-
- /*
- * Adjust output block size to correspond with
- * the requested output padding.
- */
-
- if (phys)
- {
- if (outbs < phys) outbs = phys ;
- else outbs = (outbs + phys - 1) / phys * phys ;
- }
-
- /*
- * Execute setup command.
- */
-
- if (acommand) (void) system(acommand) ;
-
- /*
- * Setup input operation through shared memory.
- */
-
- if (intank)
- {
- inprocess() ;
- getin = shareinput ;
- }
- else
- {
- inbuf = (ushort *) malloc((unsigned) inbs+1) ;
- getin = fileinput ;
- }
-
- /*
- * Setup output operation through shared memory.
- */
-
- if (outtank)
- {
- outprocess() ;
- putout = shareoutput ;
- }
- else
- {
- outbuf = (ushort *) malloc((unsigned) outbs) ;
- putout = fileoutput ;
- }
-
- /*
- * Lock process into memory.
- */
-
- if (memlock && plock(PROCLOCK) == -1)
- {
- (void) perror("Cannot lock process in memory") ;
- return(2) ;
- }
-
- /*
- * Setup to gracefully exit.
- */
-
- for (i = 0 ; sig[i] ; i++)
- {
- if (signal(sig[i], SIG_IGN) != SIG_IGN)
- (void) signal(sig[i], quit) ;
- }
-
- /*
- * Compress or expand input data.
- */
-
- rs = action == 'c' ? compact() : expand() ;
-
- quit(rs) ;
-
- return(0) ;
- }
-