[comp.sources.apple2] v001SRC033: Nulib - Archive Library Tools

jac@yoko.rutgers.edu (Jonathan A. Chandross) (05/02/91)

Submitted-by: Andy McFadden (fadden@cory.berkeley.edu)
Posting-number: Volume 1, Source:33
Archive-name: archive/unix/nulib/part02.10
Architecture: UNIX
Version-number: 3.03


=nushk.c
-/*
- * nushk.c - P8 ShrinkIt compress/uncompress routines
- *
- * NuLib v3.0  February 1991  Freeware (distribute, don't sell)
- * By Andy McFadden (fadden@cory.berkeley.edu)
- */
-#ifdef APW
-segment "Compress"
-#endif
-
-#include "nudefs.h"
-#include <stdio.h>
-#include <fcntl.h>
-
-#ifdef MSDOS     /* For file IO */
-# include <io.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <errno.h>
-#endif
-
-#include "nuread.h"  /* need CalcCRC() */
-#include "nupak.h"
-#include "nuetc.h"
-
-#define BLKSIZ	4096
-/*#define DEBUG 	/* do verbose debugging output */
-/*#define DEBUG1	/* debugging output in main routine */
-
-static onebyt *ibuf;	/* large buffer (usually set to packBuffer) */
-onebyt lbuf[BLKSIZ+7];	/* temporary buffer for storing data after LZW */
-onebyt rbuf[BLKSIZ+7];	/* temporary buffer for storing data after RLE */
-
-
-/*
- * P8 ShrinkIt compression routines
- * Copyright 1989 Kent Dickey
- *
- * C translation by Kent Dickey / Andy McFadden
- */
-
-#define ESCAPE_CHAR	0xdb
-#define HSIZE 4219		/* Must be prime */
-
-struct ht {
-	int entry;
-	int prefix;
-	unsigned char chr;
-} htab[HSIZE];
-
-int s_at_bit;
-int s_at_byte;
-
-int mask[] = {	0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f,
-		0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff };
-
-int bit_tab[] = { 0,9,10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12 };
-
-
-/*
- * Output code to buffer.
- */
-int put_code(code, ent, bfr)
-int code;
-register int ent;
-char *bfr;
-{
-	int lo_byte;
-	long mycode;
-	int bits;
-
-	bits = bit_tab[(ent >> 8)];
-/*	if (((s_at_bit + bits + 7) / 8) + s_at_byte > BLKSIZ) {*/
-	if (((s_at_bit + bits + 7) >> 3) + s_at_byte > BLKSIZ) {
-		return(-1);
-	}
-	mycode = (long)(code & mask[bits]);
-/*	fprintf(stderr,"Byte: %d, %lx\n", s_at_byte, mycode); */
-	lo_byte = bfr[s_at_byte] & mask[s_at_bit];
-	if (s_at_bit != 0) {
-		mycode <<= s_at_bit;
-	}
-	bfr[s_at_byte++] = (unsigned char)lo_byte | (char)(mycode & 0xff);
-	bfr[s_at_byte] = (unsigned char)((mycode >>= 8) & 0xff);
-	if ((s_at_bit += bits) >= 16) {
-		bfr[++s_at_byte] = (char)((mycode >>= 8) & 0xff);
-	}
-	s_at_bit &= 0x07;
-
-	return(0);
-}
-
-
-/*
- * Try LZW compression on the buffer.
- *
- * Compresses from "buffer" to "outbuf".  "inlen" is the #of bytes of data in
- * "buffer."  Returns the #of bytes of data placed into "outbuf", or -1 on
- * failure.
- */
-int do_LZW(bufr, inlen, outbuf)
-unsigned char *bufr;
-int inlen;
-unsigned char *outbuf;
-{
-	int ent, prefix;
-	register int index;
-	register unsigned char k;
-	register unsigned char *inbuf, *endbuf;
-
-	s_at_byte = 0;
-	s_at_bit =0;
-	ent = 0x101;
-	inbuf = bufr;
-	endbuf = bufr + inlen;
-
-
-	k = ((char)*inbuf++);
-Loop0:
-	prefix = (int)k;
-Loop1:
-	if (inbuf >= endbuf) {
-		if (put_code(prefix, ent, outbuf) < 0) {
-			return(BLKSIZ+2);
-		}
-		if (s_at_bit == 0) return(s_at_byte);
-		else		   return(s_at_byte+1);
-	}
-	k = (unsigned char)*inbuf++;
-	index = (prefix + (k<<4)) & 0xfff;
-
-Check_ent:
-	if (htab[index].entry == 0) {
-		/* Entry is 0... */
-		if (put_code(prefix, ent, outbuf) < 0) {
-			return(-1);	/* failed */
-		}
-		htab[index].entry = ent++;
-		htab[index].prefix = prefix;
-		htab[index].chr = k;
-		goto Loop0;
-	}
-	else if (htab[index].prefix == prefix) {
-		/* Same prefix... */
-		if (htab[index].chr == k) {
-			/* It's HERE!  Yeah! */
-			prefix = htab[index].entry;
-			goto Loop1;
-		}
-		goto Sec_hash;
-	}
-		/* Check for more...secondary hash on index */
-	  else {
-Sec_hash:
-		index = (index + (unsigned int)(k) + 1) % HSIZE;
-	/*	fprintf(stderr,"New ind: %d, k=%d\n", index, (unsigned int)k);  */
-		goto Check_ent;
-	}
-}
-
-
-/*
- * Clear out the hash table.
- */
-void ClearTab()
-{
-	register int i;
-
-	for(i=0; i < HSIZE; i++) {
-		htab[i].entry = 0;
-	}
-}
-
-
-/*
- * Do run-length encoding
- *
- * Takes input from srcptr, and writes to dstptr.  Maximum expansion is
- * (BLKSIZ / 2) + (BLKSIZ / 2) * 3 == 2 * BLKSIZ
- * Output of form  <DLE> char count
- *
- * This really isn't very pretty, but it works.
- */
-int do_RLE(srcptr, dstptr)
-register onebyt *srcptr, *dstptr;
-{
-    int found, scount, dcount;
-    register onebyt c, lastc, tlastc;
-
-    c = *(srcptr++);  scount = 1;
-    dcount = 0;
-    found = 1;  /* one char has been found */
-    lastc = '\0';
-    while (scount < BLKSIZ) {
-	tlastc = lastc;
-	lastc = c;
-	c = *(srcptr++);  scount++;
-
-	if (found == 1) {  /* no run found */
-	    if (c != lastc) {  /* no run starting */
-		if (lastc == ESCAPE_CHAR) {
-		    *(dstptr++) = ESCAPE_CHAR;  dcount++;
-		    *(dstptr++) = lastc;  dcount++;
-		    *(dstptr++) = 0;  dcount++;  /* found one */
-		} else {
-		    *(dstptr++) = lastc;  dcount++;
-		}
-		found = 1;
-	    } else {
-		found = 2;  /* they matched, so two in a row */
-	    }
-
-	} else if (found == 2) {  /* got two, try for three */
-	    if (c != lastc) {  /* only got two in a row */
-		if (lastc == ESCAPE_CHAR) {  /* and tlastc as well */
-		    *(dstptr++) = ESCAPE_CHAR;  dcount++;
-		    *(dstptr++) = lastc;  dcount++;
-		    *(dstptr++) = 1;  dcount++;  /* found two */
-		} else {
-		    *(dstptr++) = tlastc;  dcount++;
-		    *(dstptr++) = lastc;  dcount++;
-		}
-		found = 1;
-	    } else {  /* found 3, got a run going */
-		found = 3;
-	    }
-
-	} else {  /* (found >= 3), got a run going */
-	    if (c == lastc) {  /* found another */
-		found++;
-	    }
-	    if ((c != lastc) || (found > 256)) {  /* end, or too many */
-		*(dstptr++) = ESCAPE_CHAR;  dcount++;
-		*(dstptr++) = lastc;  dcount++;
-		*(dstptr++) = (found > 256) ? 255 : found-1;
-		dcount++;
-		found = 1;  /* c has something other than the run char	*/
-			    /* or found is 257-256 = 1		 	*/
-	    }
-	}
-    }  /* while */
-
-    /* reached end of buffer; flush what was left */
-    if (found == 1) {
-	if (c == ESCAPE_CHAR) {
-	    *(dstptr++) = ESCAPE_CHAR;  dcount++;
-	    *(dstptr++) = c;  dcount++;
-	    *(dstptr++) = 0;  dcount++;
-	} else {
-	    *(dstptr++) = c;  dcount++;
-	}
-
-    } else if (found == 2) {
-	/* maybe have if lastc == c == ESCAPE_CHAR? */
-	if (lastc == ESCAPE_CHAR) {
-	    *(dstptr++) = ESCAPE_CHAR;  dcount++;
-	    *(dstptr++) = lastc;  dcount++;
-	    *(dstptr++) = 0;  dcount++;
-	} else {
-	    *(dstptr++) = lastc;  dcount++;
-	}
-	if (c == ESCAPE_CHAR) {
-	    *(dstptr++) = ESCAPE_CHAR;  dcount++;
-	    *(dstptr++) = c;  dcount++;
-	    *(dstptr++) = 0;  dcount++;
-	} else {
-	    *(dstptr++) = c;  dcount++;
-	}
-
-    } else {  /* found >= 3, in the middle of processing a run */
-	*(dstptr++) = ESCAPE_CHAR;  dcount++;
-	*(dstptr++) = c;  dcount++;
-	*(dstptr++) = found-1;  dcount++;
-    }
-
-    return (dcount);
-}
-
-
-/*
- * Main compression entry point.
- *
- * Returns actual thread_format used.
- *
- * Note that "copybuf" should be at least twice as big as BLKSIZ.
- */
-long pak_SHK(srcfd, dstfd, length, copybuf)
-int srcfd, dstfd;
-long length;		/* uncompressed size */
-onebyt *copybuf;
-{
-    unsigned int partial;   /* size for partial read/write */
-    onebyt *rptr, *out_buf;
-    register int idx;
-    onebyt scratch[8];
-    long srcposn,	/* start in source file */
-	 startposn,	/* start in dest file */
-	 endposn;	/* end in dest file */
-    long unc_len = length,
-	 comp_len = 0L;
-    twobyt CRC;
-    int rlesize, lzwsize, out_size;	/* length after compression */
-    int sc;  /* spin counter */
-    static char *procName = "pak_SHK";
-
-    CRC = 0;
-    if ((srcposn = lseek(srcfd, 0L, S_REL)) < 0)	/* only used if */
-	Fatal("Bad seek (srcposn)", procName);		/* compress fails */
-    if ((startposn = lseek(dstfd, 0L, S_REL)) < 0)
-	Fatal("Bad seek (startposn)", procName);
-    lseek(dstfd, 4L, S_REL);  /* leave room for 4-byte header */
-    comp_len += 4L;
-
-    sc = 0;
-    do {  /* have to handle when length == 0L */
-	if (length > (long) BLKSIZ) {
-	    partial = (unsigned int) BLKSIZ;
-	    length -= (long) BLKSIZ;
-	} else {
-	    partial = (unsigned int) length;
-	    length = 0L;
-	    for (idx = partial; idx < BLKSIZ; idx++)  /* fill in zeroes */
-		*(copybuf + idx) = 0;
-	}
-
-	if (partial > 0) {  /* should work anyway, but let's be careful */
-	    if (read(srcfd, copybuf, partial) != partial)
-		Fatal("Source read failed", procName);
-	}
-	/* calc CRC on all 4096 bytes */
-	CRC = CalcCRC(CRC, (onebyt *) copybuf, BLKSIZ); 
-	rlesize = do_RLE(copybuf, copybuf + BLKSIZ+1);  /* pack 4096 bytes */
-	if (rlesize < 0x1000) {  /* did it pack or expand? */
-	    rptr = copybuf + BLKSIZ+1;  /* use packed version */
-	} else {
-	    rlesize = 0x1000;  /* just store original */
-	    rptr = copybuf;
-	}
-	ClearTab();
-	lzwsize = do_LZW(rptr, rlesize, lbuf);	/* compress from rle to lzw */
-	if ((lzwsize > rlesize) || (lzwsize < 0)) {
-	    /* lzw failed, use rle'd copy */
-	    scratch[2] = 0;
-	    out_size = rlesize;
-	    out_buf = rptr;
-	} else {
-	    /* lzw succeeded, use it */
-	    scratch[2] = 1;		/* LZW on */
-	    out_size = lzwsize;
-	    out_buf = lbuf;
-	}
-	scratch[0] = (onebyt) (rlesize & 0x00ff);	/* NOT out_size */
-	scratch[1] = (onebyt) ((rlesize >> 8) & 0x00ff);
-	if (write(dstfd, scratch, 3) != 3)
-	    Fatal("Dest hdr write failed", procName);
-	comp_len += 3;
-	comp_len += out_size;
-	if (comp_len > unc_len)
-	    goto bad_compress;		/* you didn't see this */
-	if (write(dstfd, out_buf, out_size) != out_size)  /* need to do CRLF */
-	    Fatal("Dest write failed", procName);
-
-	sc++;
-	if (sc == 15) {
-	    sc = 0;
-	    Spin();
-	}
-    } while (length != 0L);
-
-    if ((endposn = lseek(dstfd, 0L, S_REL)) < 0)
-	Fatal("Bad seek (now)", procName);
-    if (lseek(dstfd, startposn, S_ABS) < 0)
-	Fatal("Bad seek (to4)", procName);
-    scratch[0] = (char) CRC;
-    scratch[1] = (char) (CRC >> 8);
-    scratch[2] = 0;
-    scratch[3] = ESCAPE_CHAR;
-    if (write(dstfd, scratch, 4) != 4)
-	Fatal("Dest hdr write failed", procName);
-    if (lseek(dstfd, endposn, S_ABS) < 0)
-	Fatal("Bad seek (last)", procName);
-
-    if (comp_len != endposn - startposn) {
-	printf(
-	    "internal error: comp_len=%ld, endposn=%ld, startposn=%ld (%ld)\n",
-		comp_len, endposn, startposn, endposn - startposn);
-    }
-    packedSize = comp_len;
-    return (0x0002);	/* SHK packing */
-
-bad_compress:	/* I'm too lazy to do a procedure call... */
-
-    if (verbose) { printf("storing...");  fflush(stdout); }
-    if (lseek(srcfd, srcposn, S_ABS) < 0)
-	Fatal("Bad seek (srcposn in bad_compress)", procName);
-    if (lseek(dstfd, startposn, S_ABS) < 0)
-	Fatal("Bad seek (startposn in bad_compress)", procName);
-    FCopy(srcfd, dstfd, unc_len, copybuf, FALSE);
-    packedSize = unc_len;
-    return (0x0000);	/* no compression */
-}
-
-
-/*
- * P8 ShrinkIt uncompression routines
- *
- * Copyright 1989 Kent Dickey
- * C translation by Kent Dickey / Andy McFadden
- * Modifications for LZW-II by Andy Nicholas
- */
-
-static int inf;  /* to make Getc() calls happy */
-static BOOLEAN type2;	/* true if working with LZW-II format */
-
-static onebyt escape_char;
-
-typedef struct {
-    unsigned char chr;
-    int prefix;
-} Table_ent;
-
-static Table_ent Real_tab[BLKSIZ-256];  /* first 256 don't exist */
-static Table_ent *Table;
-
-static int Mask_tab[16] = {
-	0x0000, 0x01ff, 0x03ff, 0x03ff, 0x07ff,
-	0x07ff, 0x07ff, 0x07ff, 0x0fff, 0x0fff,
-	0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff,
-	0x0fff
-};
-static int Number[16] = {
-	0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
-
-static onebyt Stack[100];  /* simulated stack; should be <= 64 */
-static int out_bytes, stack_ptr, entry, at_bit, at_byte;
-static onebyt last_byte;  /* used in get_code */
-
-
-/* fake Getc(); easier to make this a macro than to change the code */
-#ifdef DEBUG
-onebyt Getc(foo)
-int foo;  /* this is ignored */
-{
-    return (*(ibuf++));
-}
-#else  /* if not debugging, use a macro */
-# define Getc(foo) *(ibuf++)
-#endif /* DEBUG */
-
-
-/*
- * Stack operations; used by undo_LZW
- */
-#ifdef DEBUG
-void push(a_byte)
-unsigned char a_byte;
-{
-    if (stack_ptr > 100) {
-	printf("\n*** stack_ptr exceeded 100 in push() [%d]\n", stack_ptr);
-	exit (-1);
-    }
-    Stack[stack_ptr++] = a_byte;
-}
-#else  /* if not debugging, use a macro */
-# define push(a_byte) Stack[stack_ptr++] = a_byte
-#endif /* DEBUG */
-
-
-#ifdef DEBUG
-void dump_stack(buffer)
-unsigned char *buffer;
-{
-    printf("--- Going to dump stack, stack_ptr = %d, out_bytes = %d\n",
-	stack_ptr, out_bytes);
-    while (stack_ptr > 0) {
-	*(buffer + out_bytes++) = Stack[--stack_ptr];
-    }
-}
-#else  /* if not debugging, use a macro */
-# define dump_stack(buffer) while (stack_ptr > 0) { \
-				*( buffer +out_bytes++) = Stack[--stack_ptr];\
-			    }
-#endif /* DEBUG */
-
-
-/*
- * Decipher LZW codes.
- */
-static int get_code(/*Buffer*/)
-/*unsigned char *Buffer;*/
-{
-    register int num_bits, old_bit, last_bit;
-    long value, mask;
-    unsigned char byte1, byte2, byte3;  /* get compressed chars... */
-
-#ifdef DEBUG
-    printf("ENT: bit=%d byte=%-4d last_byte=$%.2x ",
-	at_bit, at_byte, last_byte);
-    printf("Entry: %.4x \n", entry);
-#endif
-
-    num_bits = ((entry+1) >> 8);  /* get hi-byte of entry */
-    last_bit = at_bit + Number[num_bits] + 8;
-    old_bit = at_bit;
-#ifdef DEBUG
-    if (at_byte >= BLKSIZ) {
-	fprintf(stderr, "at_byte exceeded BLKSIZ (4096) in get_code()\n");
-	exit (-1);
-    }
-#endif
-    if (at_bit == 0)
-	last_byte = Getc(inf);
-    byte1 = last_byte;  /* first byte = last one used */
-    byte2 = Getc(inf);
-    if (last_bit > 16) {  /* get 3rd byte if nec. */
-	byte3 = Getc(inf);
-	last_byte = byte3;
-    } else {
-	byte3 = 0;
-	last_byte = byte2;
-    }
-    value = ((((long)byte3 << 8) + (long)byte2) << 8) + (long)byte1;
-/*    value = (((Buffer[at_byte+2] << 8) + Buffer[at_byte+1]) << 8) +	*/
-/*	Buffer[at_byte];						*/
-
-    mask = (long) Mask_tab[num_bits];
-    at_byte += (last_bit >> 3);  /* new byte */
-    at_bit = (last_bit & 0x07);
-
-#ifdef DEBUG
-    printf("| EX: value=$%.6x mask=$%.4x return=$%.3x\n",
-	value, mask, ((value >> old_bit) & mask));
-#endif
-    if (old_bit)
-	return ((value >> old_bit) & mask);
-    else
-	return (value & mask);  /* shifting by zero may be undefined */
-}
-
-
-/*
- * Un-LZW a range of bytes
- *
- * Reads data with get_code (eventually from packBuffer) and stores the
- * output in "buffer".
- */
-static void undo_LZW(buffer, length)
-unsigned char *buffer;  /* where to put output */
-int length;  /* uncompressed length of output */
-{
-    register int oldc, incode, finalc, ptr;
-
-    /* initialize variables */
-    Table = Real_tab-256;
-    entry = 0x101;  /* start at $101 */
-    at_bit = at_byte = 0;
-    out_bytes = 0;
-    stack_ptr = 0;
-
-    last_byte = 0;  /* init last_byte */
-    oldc = incode = get_code(/*buffer*/);
-    finalc = (oldc & 0xff);
-    *(buffer + out_bytes++) = (unsigned char) incode;
-
-    /* main loop */
-    while (out_bytes < length) {
-	incode = ptr = get_code(/*buffer*/);
-	if (ptr >= entry) {
-	    push(finalc);
-	    ptr = oldc;
-	}
-	while (ptr > 0xff) {
-	    push(Table[ptr].chr);
-	    ptr = Table[ptr].prefix;
-	}
-
-	/* ptr is now < 0x100 */
-	finalc = ptr;
-	push(finalc);
-	dump_stack(buffer);
-	Table[entry].chr = (finalc & 0xff);  /* mask to get unsigned?? byte */
-	Table[entry].prefix = oldc;
-	entry++;
-	oldc = incode;
-    }
-}
-
-
-/*
- * Un-LZW-II a range of bytes (someday!)
- *
- * Reads data with get_code (eventually from packBuffer) and stores the
- * output in "buffer".  Has additional code to support LZW-II's table
- * clears.
- */
-static void undo_LZW_2(buffer, length)
-unsigned char *buffer;  /* where to put output */
-int length;  /* uncompressed length of output */
-{
-    register int oldc, incode, finalc, ptr;
-
-    /* initialize variables */
-    Table = Real_tab-256;
-    entry = 0x101;  /* start at $101 */
-    at_bit = at_byte = 0;
-    out_bytes = 0;
-    stack_ptr = 0;
-
-    last_byte = 0;  /* init last_byte */
-    oldc = incode = get_code(/*buffer*/);
-    finalc = (oldc & 0xff);
-    *(buffer + out_bytes++) = (unsigned char) incode;
-
-    /* main loop */
-    while (out_bytes < length) {
-	incode = ptr = get_code(/*buffer*/);
-	if (ptr >= entry) {
-	    push(finalc);
-	    ptr = oldc;
-	}
-	while (ptr > 0xff) {
-	    push(Table[ptr].chr);
-	    ptr = Table[ptr].prefix;
-	}
-
-	/* ptr is now < 0x100 */
-	finalc = ptr;
-	push(finalc);
-	dump_stack(buffer);
-	Table[entry].chr = (finalc & 0xff);  /* mask to get unsigned?? byte */
-	Table[entry].prefix = oldc;
-	entry++;
-	oldc = incode;
-    }
-}
-
-
-/*
- * Second pass... undo the Run Length Encoding.
- *
- * Copy data from inbuffer to outbuffer.  Keep going until we've got
- * exactly BLKSIZ bytes.  Note that this uses codes of the form
- *   <DLE> char count
- * which is different from some other programs.
- */
-static void undo_RLE(inbuffer, outbuffer)
-unsigned char *inbuffer, *outbuffer;
-/*int length;  /* how many bytes from LZW; just to make sure... */
-{
-    register unsigned char c;
-    register int total, count;  /* count is RLE reps */
-
-#ifdef DEBUG
-    /*printf("Starting undo_RLE, length = %d\n", length);*/
-#endif
-    total = 0;
-    while (total < BLKSIZ) {
-	c = *(inbuffer++);  /*length--;*/
-	if (c == (onebyt) escape_char) {
-	    c = *(inbuffer++);  /*length--;*/
-	    count = *(inbuffer++);  /*length--;*/
-	    total += count +1;  /* count of zero -> 1 byte */
-	    while (count-- >= 0) {
-		*(outbuffer++) = c;  /*Putc(c, outf);*/
-	    }
-	} else {
-	    *(outbuffer++) = c;  /*Putc(c, outf);*/
-	    total++;
-	}
-    }
-
-    if (total != 4096)
-	fprintf(stderr, "internal error: bad undo_RLE\n");
-#ifdef DEBUG
-/*    printf("Exiting undo_RLE, length = %d (should be 0), total = %d (4096)\n",
-	length, total);*/
-#endif
-}
-
-
-/*
- * Main entry point.
- *
- * This is among the more hellish things I've written.  Uses
- *   a large buffer for efficiency reasons, and unpacks a stream of bytes
- *   (LZW-II improves things a little).
- * If you find this hard to understand, imagine what it was like to debug.
- *
- * Could use some cleaning up, esp argument list...
- */
-void
-unpak_SHK(srcfd,dstfd,comp_thread_eof,thread_eof,buffer, use_type2, thread_crc)
-int srcfd, dstfd;
-fourbyt comp_thread_eof, thread_eof;
-register onebyt *buffer;
-BOOLEAN use_type2;		/* true if we should expect LZW-II */
-twobyt thread_crc;
-{
-    twobyt CRC, blkCRC;
-    onebyt vol;
-    onebyt *wrbuf;  /* points to buffer we're about to write */
-    short unlen, lzwflag, rleflag, complen;	/* should be short */
-    unsigned int partial, toread, still_in_buf;
-    fourbyt tmp4;  /* temporary 4-byte variable */
-    int cc;
-    static char *procName = "unpak_SHK";
-
-    CRC = 0;
-    type2 = use_type2;
-
-    /* read min(PAKBUFSIZ, comp_thread_eof) bytes into buffer */
-    if (comp_thread_eof > (fourbyt) PAKBUFSIZ) {
-	toread = (unsigned int) PAKBUFSIZ;
-	comp_thread_eof -= (fourbyt) PAKBUFSIZ;
-    } else {
-	toread = (unsigned int) comp_thread_eof;  /* read it all... */
-	comp_thread_eof = (fourbyt) 0;
-    }
-
-    /* do initial read */
-#ifdef DEBUG1
-    printf("initial read = %u\n", toread);
-#endif
-    if ((cc = read(srcfd, buffer, toread)) < toread) {
-#ifdef DEBUG1
-	printf("Only read %d bytes\n", cc);
-#endif
-	Fatal("Bad read during uncompress", procName);
-    }
-    ibuf = buffer;  /* set input pointer to start of buffer */
-
-    /* get header data */
-    if (type2) {
-	blkCRC = thread_crc;
-    } else {
-	blkCRC = Getc(inf);
-	blkCRC += (Getc(inf) << 8);
-    }
-    vol = (char) Getc(inf);  /* disk volume #; not used here */
-    escape_char = (char) Getc(inf);  /* RLE delimiter */
-
-#ifdef DEBUG1
-    printf("vol = %d, escape_char = %x\n", vol, escape_char);
-#endif
-
-    /*
-     * main loop
-     */
-    while (thread_eof != (fourbyt) 0) {
-
-	/* note "unlen" is un-LZWed length (i.e., after RLE) */
-	if (type2) {
-	    unlen = Getc(inf);
-	    unlen += (Getc(inf) << 8);
-	    lzwflag = (unlen & 0x8000) ? 1 : 0;	/* flag is hi bit */
-	    unlen &= 0x1fff;			/* strip extra stuff */
-	    rleflag = (unlen != BLKSIZ);
-	    if (lzwflag) {	/* will the real length bytes please stand up*/
-		complen = Getc(inf);
-		complen += (Getc(inf) << 8);
-	    }
-	} else {
-	    unlen = Getc(inf);
-	    unlen += (Getc(inf) << 8);
-	    lzwflag = Getc(inf);
-	    rleflag = (unlen != BLKSIZ);
-	}
-#ifdef DEBUG1
-	printf("Length after RLE = %d ($%.4x)\n", unlen, unlen);
-	printf("LZW flag = %d, RLE flag = %d\n", lzwflag, rleflag);
-	if (lzwflag != 0 && lzwflag != 1) {  /* this is weird... */
-	    for (lzwflag = -6; lzwflag < 3; lzwflag++) {
-		printf("foo %d: %.2x\n", lzwflag, *(ibuf+lzwflag));
-	    }
-	}
-	if (type2 && lzwflag) {
-	    printf("Length after RLE+LZW = %d ($%.4x)\n", complen, complen);
-	}
-#endif
-
-	/* If it looks like we're going to run out of room, shift & read
-	/* Mostly a guess; LZW length is less than unlen...  This is
-	/* complicated and very prone to errors.
-	/* tmp4 is the number of bytes between the current ptr and the end;
-	/* some (16-bit) compilers yack if it's all one statement.*/
-	tmp4 = (fourbyt) buffer + (fourbyt) PAKBUFSIZ;
-	tmp4 -= (fourbyt) ibuf;
-	if (tmp4 < (unlen + 6)) {  /* 6 = 3/4 byte header + two just in case */
-	    still_in_buf = tmp4;
-
-#ifdef DEBUG1
-	    printf("--- unlen = %d, space left = %d bytes\n",
-		    unlen, still_in_buf);
-#endif
-	    BCopy((onebyt *) ibuf, (onebyt *) buffer, still_in_buf, FALSE);
-	    if (comp_thread_eof != (fourbyt) 0) {  /* no read, just shift */
-		if (comp_thread_eof > ((fourbyt) PAKBUFSIZ - still_in_buf)){
-		    toread = (unsigned int) PAKBUFSIZ - still_in_buf;
-		    comp_thread_eof -= (fourbyt) PAKBUFSIZ - still_in_buf;
-		} else {
-		    toread = (unsigned int) comp_thread_eof;
-		    comp_thread_eof = (fourbyt) 0;
-		}
-#ifdef DEBUG1
-		printf("--- reading another %u bytes\n", toread);
-#endif
-		if (read(srcfd, buffer+still_in_buf, toread) < toread)
-		    Fatal("Unable to read [middle]", procName);
-		if (verbose) Spin();
-	    }
-	    ibuf = buffer;
-	}
-    
-	/* how much of the buffered data do we really need? */
-	if (thread_eof > (fourbyt) BLKSIZ) {
-	    partial = (unsigned int) BLKSIZ;
-	    thread_eof -= (fourbyt) BLKSIZ;
-	} else {
-	    partial = (unsigned int) thread_eof;  /* last block of file */
-	    thread_eof = (fourbyt) 0;
-	}
-
-	/*
-	 * undo_LZW reads from ibuf (using Getc()) and writes to lbuf
-	 * undo_LZW_2 does what undo_LZW does, but for LZW-II.
-	 * undo_RLE reads from where you tell it and writes to rbuf
-	 *
-	 * This is really insane...
-	 */
-	if (lzwflag && rleflag) {
-	    if (type2)
-		undo_LZW_2(lbuf, unlen);  /* from ibuf -> lbuf */
-	    else
-		undo_LZW(lbuf, unlen);  /* from ibuf -> lbuf */
-	    undo_RLE(lbuf, rbuf);  /* from lbuf -> rbuf */
-	    wrbuf = rbuf;  /* write rbuf */
-	    CRC = CalcCRC(CRC, (onebyt *) rbuf, BLKSIZ);  /* always 4K bytes */
-	} else if (lzwflag && !rleflag) {
-	    if (type2)
-		undo_LZW_2(lbuf, unlen);  /* from ibuf -> lbuf */
-	    else
-		undo_LZW(lbuf, unlen);  /* from ibuf -> lbuf */
-	    wrbuf = lbuf;  /* write lbuf */
-	    CRC = CalcCRC(CRC, (onebyt *) lbuf, BLKSIZ);
-	} else if (!lzwflag && rleflag) {
-	    undo_RLE(ibuf, rbuf);  /* from ibuf -> rbuf */
-	    wrbuf = rbuf;  /* write rbuf */
-	    CRC = CalcCRC(CRC, (onebyt *) rbuf, BLKSIZ);
-	    ibuf += unlen;  /* have to skip over RLE-only data */
-			/* normally ibuf is advanced by Getc() calls */
-	} else {
-	    wrbuf = ibuf;  /* write ibuf */
-	    CRC = CalcCRC(CRC, (onebyt *) ibuf, BLKSIZ);
-	    ibuf += partial;  /* skip over uncompressed data */
-			/* normally ibuf is advanced by Getc() calls */
-	}
-#ifdef DEBUG1
-	printf("Writing %d bytes.\n", partial);
-#endif
-	if (crlf(dstfd, wrbuf, partial) < partial)  /* write wrbuf */
-	    Fatal("Bad write", procName);
-    }
-
-    if (CRC != blkCRC) {
-	fprintf(stderr, "WARNING: CRC does not match...");
-	if (verbose) fprintf(stderr, "\n");
-	else fprintf(stderr, "extract with V suboption to see filenames.\n");
-    }
-}
-
=nuadd.c
-/*
- * nuadd.c - operations which add to a NuFX archive
- *
- * NuLib v3.0  February 1991  Freeware (distribute, don't sell)
- * By Andy McFadden (fadden@cory.berkeley.edu)
- */
-#ifdef APW
-segment "NuMain"
-#endif
-
-#include "nudefs.h"
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#ifdef BSD43
-# include <strings.h>
-#else
-# include <string.h>
-#endif
-
-#ifdef UNIX
-# include <sys/types.h>
-# include <sys/stat.h>
-# ifdef XENIX386
-#  include <sys/ndir.h>		/* maybe <sys/ndir.h>, <dirent.h>, <dir.h>...*/
-# else
-#  include <sys/dir.h>
-# endif
-#endif
-#ifdef APW
-# include <types.h>
-# include <prodos.h>
-# include <shell.h>
-# include <strings.h>
-#endif
-#ifdef MSDOS
-# include <stdlib.h>
-# include <errno.h>
-# include <time.h>
-# include <io.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#include "nuread.h"
-#include "nuadd.h"
-#include "nupak.h"
-#include "nuetc.h"
-
-#ifdef DATAGENERAL					/* BAK */
-# ifdef AOSVS						/* BAK */
-#  define BROKEN_ON_MVs				/* MV/UX is NOT a full UNIX */
-# endif						/* implem. so we just skip */
-#endif						/* the 'UNIX' code on MVs */
-
-#define MAXGSPREFIX 64
-
-static BOOLEAN domove;    /* are we M)oving the files in? */
-static BOOLEAN docreate;  /* using the 'C' option? */
-
-
-/*
- * Expand command args into filenames
- * Stuff number of names into int; build File Information Array.
- * (this routine is heavily implementation-specific, since no two systems
- *  expand wildcards or deal with subdirectories in the same way).
- *
- * Recursively expands subdirectories, unless doSubdir is FALSE.
- */
-int EvalArgs(count, names, FIArray, first)
-int count;	/* #of filenames */
-char **names;	/* array of file names */
-file_info *FIArray[];  /* array to fill with file info */
-BOOLEAN first;	/* first time through? */
-{
-    static char *procName = "EvalArgs";
-#ifdef UNIX
-    /* UNIX shells (sh, csh) won't expand subdirectories, but they do
-     * expand wildcards in arguments before we get them
-     */
-    static int idx;
-    struct stat st;
-    char *cp;  /* temp char pointer */
-    /* dir stuff */
-    int newcount;
-    char **newnames;
-#ifndef BROKEN_ON_MVs
-    DIR *dirp;
-#endif
-    struct direct *dp;
-    int nmlen;
-
-    if (first) idx = 0;
-
-    while (count--) {
-	FIArray[idx] = (file_info *) Malloc(sizeof(file_info));
-
-	if (stat(*names, &st) < 0) {  /* get file info */
-	    if (errno == ENOENT) {
-		fprintf(stderr, "%s: '%s' not found\n", prgName, *names);
-		names++;
-		continue;  /* with while */
-	    }
-	    Fatal("Bad stat()", procName);
-	}
-
-	if ((st.st_mode & S_IFDIR) && doSubdir) {  /* is it a directory? */
-# ifndef BROKEN_ON_MVs
-	    newnames = (char **) Malloc(MAXARGS * sizeof(char *));
-	    strcpy(tmpNameBuf, *names);  /* earlier dir stuff */
-	    strcat(tmpNameBuf, "/");
-	    nmlen = strlen(tmpNameBuf);
-
-	    if ((dirp = opendir(*names)) == NULL)
-		Fatal("Unable to open subdirectory", procName);
-	    for (newcount=0, dp=readdir(dirp); dp != NULL; dp=readdir(dirp)) {
-		if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, "..")))
-		    continue;  /* with for */
-		newnames[newcount] = (char *) Malloc(nmlen + dp->d_namlen +1);
-		strcpy(newnames[newcount], tmpNameBuf);
-		strcat(newnames[newcount], dp->d_name);  /* append the name */
-		newcount++;
-	    }
-	    closedir(dirp);
-
-	    EvalArgs(newcount, newnames, FIArray, FALSE);  /* do subdir */
-
-	    while (newcount-- > 0)  /* free up the space we allocated */
-		free(newnames[newcount]);
-	    free(newnames);
-
-	    names++;
-# else								/* BAK */
-	    printf("Help, I ran into a directory and can't handle it!\n");
-# endif								/* BAK */
-	} else if ((st.st_mode & S_IFDIR) && !doSubdir) {
-	    /* maybe print message? */
-	    names++;
-	    continue;	/* with while */
-	} else if (st.st_mode & S_IFREG) {
-	    FIArray[idx]->eof = (long) st.st_size;
-
-	    if (st.st_mode & S_IWRITE)  /* write permission enabled? */
-		FIArray[idx]->fAccess = (fourbyt) 0x00e3;	/* locked */
-	    else
-		FIArray[idx]->fAccess = (fourbyt) 0x0021;	/* unlocked */
-
-	    FIArray[idx]->fileType = defFileType;
-	    FIArray[idx]->auxType = defAuxType;
-	    FIArray[idx]->fileSysID = 0x0001;  /* ProDOS */
-	    FIArray[idx]->fileSysInfo = 0x2f;  /* '/' */
-	    ExpandTime(&st.st_mtime, &FIArray[idx]->create_dt);  /*use mod.. */
-	    ExpandTime(&st.st_mtime, &FIArray[idx]->mod_dt); /*time for both */
-	    FIArray[idx]->marked = FALSE;
-
-	    FIArray[idx]->pathname = (char *) Malloc(strlen(*names)+1);
-	    strcpy(FIArray[idx]->pathname, *names);
-	    FIArray[idx]->store_name = (char *) Malloc(strlen(*names)+1);
-	    cp = *names;
-	    while (*cp == '/') cp++;  /* advance past leading '/' */
-	    strcpy(FIArray[idx]->store_name, cp);  /* can't otherwise fix */
-
-	    names++;
-	    idx++;
-	} else {
-	    printf("Unknown storage type for '%s'\n", *names);
-	    names++;
-	    continue;	/* with while */
-	}
-
-    }
-    return (idx);
-
-#else /* UNIX */
-# ifdef APW
-    static int idx;  /* will eventually hold the total #of filenames */
-    char *nextname = (char *) Malloc(MAXFILENAME);  /* for subdir expand */
-    char prefix[MAXGSPREFIX+1];  /* Max ProDOS prefix size; now 64 */
-    char *fnptr;
-    FileRec finfo_p;
-    PrefixRec prefix_p;
-    OpenRec open_p;
-    EOFRec eof_p;
-
-    if (first) idx = 0;
-
-    prefix_p.prefixNum = 0;  /* current dir */
-    prefix_p.prefix = prefix;  /* prefix buffer */
-    GET_PREFIX( &prefix_p );
-    ToolErrChk();
-    p2cstr(prefix);
-
-    while (count) {
-	strcpy(tmpNameBuf, *names);
-	c2pstr(tmpNameBuf);
-	INIT_WILDCARD(tmpNameBuf, 0);
-	ToolErrChk();
-
-	while (*NEXT_WILDCARD(tmpNameBuf)) {
-	    if (idx >= MAXARGS) {
-		fprintf(stderr, "Too many files (%d, %d max)\n", idx, MAXARGS);
-		Quit (-1);
-	    }
-
-	    finfo_p.pathname = tmpNameBuf;
-	    GET_FILE_INFO( &finfo_p );
-	    ToolErrChk();
-
-	    open_p.openPathname = tmpNameBuf;
-	    OPEN( &open_p );
-	    ToolErrChk();
-
-	    eof_p.eofRefNum = open_p.openRefNum;
-	    GET_EOF( &eof_p );
-	    ToolErrChk();
-
-	    CLOSE( &open_p );
-	    ToolErrChk();
-
-	    p2cstr(tmpNameBuf);  /* also does p2cstr(finfo_p.pathname) */
-	    switch (finfo_p.storageType) {
-	    case 0x00:	/* standard ProDOS storage types */
-	    case 0x01:
-	    case 0x02:
-	    case 0x03:
-		FIArray[idx] = (file_info *) Malloc(sizeof(file_info));
-
-		FIArray[idx]->eof = eof_p.eofPosition;
-		FIArray[idx]->fAccess = finfo_p.fAccess;
-		FIArray[idx]->fileType = (fourbyt) finfo_p.fileType;
-		FIArray[idx]->auxType = (fourbyt) finfo_p.auxType;
-		FIArray[idx]->storageType = finfo_p.storageType;
-		FIArray[idx]->fileSysID = 0x0001;  /* ProDOS */
-		FIArray[idx]->fileSysInfo = 0x2f;  /* '/' */
-		ExpandTime(&finfo_p.createDate, &FIArray[idx]->create_dt);
-		ExpandTime(&finfo_p.modDate, &FIArray[idx]->mod_dt);
-		FIArray[idx]->marked = FALSE;
-
-		FIArray[idx]->pathname = (char *) Malloc(strlen(tmpNameBuf)+1);
-		strcpy(FIArray[idx]->pathname, tmpNameBuf);
-
-		/* are we adding from current directory? */
-		if (!strncmp(tmpNameBuf, prefix, strlen(prefix))) {
-		    FIArray[idx]->store_name =			      /* yes */
-		       (char *) Malloc(strlen(tmpNameBuf) - strlen(prefix) +1);
-		  strcpy(FIArray[idx]->store_name, tmpNameBuf+ strlen(prefix));
-		} else {
-		    fnptr = RINDEX(tmpNameBuf, '/') + 1;	      /* no  */
-		    FIArray[idx]->store_name = (char *)Malloc(strlen(fnptr)+1);
-		    strcpy(FIArray[idx]->store_name, fnptr);
-		}
-		idx++;
-		break;
-
-	    case 0x05:
-		printf("Can't handle Extended file '%s'\n", tmpNameBuf);
-		break;
-	    case 0x0d:
-		if (doSubdir) {
-		    strcpy(nextname, tmpNameBuf);  /* make new copy */
-		    strcat(nextname, "/=");  /* APW-only wildcard */
-		    EvalArgs(1, &nextname, FIArray, FALSE);  /* read subdir */
-		}
-		break;
-	    default:
-		printf("Unknown storage type for '%s'\n", tmpNameBuf);
-		break;
-	    }
-
-	} /* inner while */
-
-	names++, count--;
-    }  /* outer while */
-    free (nextname);
-    return (idx);
-# endif /* APW */
-
-# ifdef MSDOS
-    /* MS-DOS or other shell wildcard expansion here */
-    int idx, error;
-    struct stat fStat;
-
-    idx = 0;
-
-    while (count--) {
-
-	error = stat (*names, &fStat);
-
-	/* If the filename is a directory, we need to expand that too! */
-
-	if (!error) {
-	    FIArray[idx]              = (file_info *) Malloc(sizeof(file_info));
-	    FIArray[idx]->pathname    = (char *) Malloc(strlen(*names)+1);
-	    strcpy(FIArray[idx]->pathname, *names);
-	    FIArray[idx]->store_name  = (char *) Malloc(strlen(*names)+1);
-	    strcpy(FIArray[idx]->store_name, *names);
-	    FIArray[idx]->fAccess     = 0x00e3L;  /* unlocked */
-	    FIArray[idx]->fileType    = defFileType;
-	    FIArray[idx]->auxType     = defAuxType;
-	    FIArray[idx]->storageType = 0x0000;
-	    FIArray[idx]->fileSysID   = 0x0001;  /* ProDOS */
-	    FIArray[idx]->fileSysInfo = 0x1c;  /* '\' */
-	    ExpandTime(&fStat.st_ctime, &FIArray[idx]->create_dt);
-	    ExpandTime(&fStat.st_mtime, &FIArray[idx]->mod_dt);
-	    FIArray[idx]->eof = fStat.st_size;
-
-	    FIArray[idx]->marked = FALSE;
-	    idx++;
-	}
-	names++;
-    }
-    return (idx);
-# endif /* MDOS */
-
-# ifndef APW
-# ifndef MSDOS
-    /* nothing else defined */
-
-    /* +PORT+ */
-    printf("\n[other] wildcard expansion/file info needs work\n");
-    while (count--) {
-	FIArray[count] = (file_info *) Malloc(sizeof(file_info));
-
-	FIArray[count]->pathname = (char *) Malloc(strlen(*names)+1);
-	strcpy(FIArray[count]->pathname, *names);
-	FIArray[count]->store_name = (char *) Malloc(strlen(*names)+1);
-	strcpy(FIArray[count]->store_name, *names);
-	FIArray[count]->fAccess = 0x00e3L;  /* unlocked */
-	FIArray[count]->fileType = 0x0006L;  /* BIN */
-	FIArray[count]->auxType = 0L;
-	FIArray[count]->storageType = 0x0000;
-	FIArray[count]->fileSysID = 0x0001;  /* ProDOS */
-	FIArray[count]->fileSysInfo = 0x1c;  /* '\' */
-	ExpandTime((char *) NULL, &FIArray[count]->create_dt);
-	ExpandTime((char *) NULL, &FIArray[count]->mod_dt);
-	FIArray[count]->marked = FALSE;
-
-	names++;
-    }
-    return (count);
-# endif /* none2 */
-# endif /* none1 */
-#endif /* UNIX */
-}
-
-
-/*
- * Add a file onto the end of an archive; does not check to see if an entry
- * already exists.
- *
- * This creates the record entry, and calls subroutines to add the various
- * threads.  The archive fd should be open, the file fd should not.  Returns
- * the size of the record added.
- */
-long AddFile(arcfd, infoptr)
-int arcfd;
-file_info *infoptr;
-{
-    int srcfd;	/* file to add */
-    onebyt *recBuf;  /* record header block */
-    twobyt *twoptr;
-    THblock thread[1];	/* thread block */
-    twobyt CRC;
-    int idx;
-    fourbyt total_threads;
-    long recposn;  /* file posn for record entry */
-    long thposn;   /* file posn for last thread */
-    long tmpposn;  /* temporary file posn */
-    static char *procName = "AddFile";
-
-    if (verbose) {
-	printf("Adding '%s' (data)...",
-					  infoptr->store_name, infoptr->eof);
-	fflush(stdout);
-    }
-
-    recBuf = (onebyt *) Malloc(ATTSIZE);
-    for (idx = 0; idx < ATTSIZE; idx++)  /* zero the buffer */
-	*(recBuf+idx) = 0;
-
-    total_threads = 0;
-
-    strncpy((char *) recBuf+0, (char *) RecordID, 4);
-    twoptr = (twobyt *) (recBuf+6);
-    *twoptr = ATTSIZE;	/* don't have an attrib_count... */
-    HiSwap((onebyt *) recBuf, 6, 7);
-    twoptr = (twobyt *) (recBuf+8);
-    *twoptr = OURVERS;	/* store new record with our rec vers */
-    HiSwap((onebyt *) recBuf, 8, 9);
-    /* total_threads */
-/*    BCopy((onebyt *) &total_threads, (onebyt *) recBuf+10, 2, TRUE); */
-    *(recBuf+12) = 0;  /* reserved1 */
-    *(recBuf+13) = 0;
-    BCopy((onebyt *) &infoptr->fileSysID, (onebyt *) recBuf+14, 2, TRUE);
-    BCopy((onebyt *) &infoptr->fileSysInfo, (onebyt *) recBuf+16, 1, TRUE);
-    *(recBuf+17) = 0;  /* reserved2 */
-    BCopy((onebyt *) &infoptr->fAccess, (onebyt *) recBuf+18, 4, TRUE);
-    BCopy((onebyt *) &infoptr->fileType, (onebyt *) recBuf+22, 4, TRUE);
-    BCopy((onebyt *) &infoptr->auxType, (onebyt *) recBuf+26, 4, TRUE);
-    BCopy((onebyt *) &infoptr->create_dt, (onebyt *) recBuf+32,
-	sizeof(Time), FALSE);
-    BCopy((onebyt *) &infoptr->mod_dt, (onebyt *) recBuf+40, sizeof(Time),
-	FALSE);
-    BCopy((onebyt *) GetTime(), (onebyt *) recBuf+48, sizeof(Time), FALSE);
-    twoptr = (twobyt *) (recBuf + (ATTSIZE - 2));
-    *twoptr = strlen(infoptr->store_name);
-
-    /* correct strlen ordering */
-    HiSwap((onebyt *) recBuf, ATTSIZE-2, ATTSIZE-1);
-
-    thread[0].thread_class = 0x0002;  /* data */
-    HiSwap((onebyt *) &thread[0].thread_class, 0, 1);
-    thread[0].thread_kind = 0x0000;  /* data fork */
-    HiSwap((onebyt *) &thread[0].thread_kind, 0, 1);
-    thread[0].thread_format = 0x0000;  /* filled in later */
-    thread[0].thread_crc = 0x0000;  /* not supported yet */
-    /* so I don't forget if I support these */
-    HiSwap((onebyt *) &thread[0].thread_crc, 0, 1); 
-    thread[0].thread_eof = infoptr->eof;
-    HiSwap((onebyt *) &thread[0].thread_eof, 0, 3);
-    HiSwap((onebyt *) &thread[0].thread_eof, 1, 2);
-    thread[0].comp_thread_eof = -1L;  /* filled in later */
-    total_threads++;
-
-    BCopy((onebyt *) &total_threads, (onebyt *) recBuf+10, 4, TRUE);
-
-    /*
-     * Because we don't know CRCs or compressed size yet, we must:
-     * skip record entry and filename.
-     * for each thread:
-     *	 skip thread entry, write data, move back, write thread entry.
-     * move back, write record entry and filename.
-     * move forward to next position.
-     */
-    if ((srcfd = open(infoptr->pathname, O_RDONLY | O_BINARY)) < 0)
-	Fatal("Unable to open file", procName);
-
-    recposn = lseek(arcfd, 0L, S_REL);	/* save record posn */
-    if (lseek(arcfd, (long) (ATTSIZE + strlen(infoptr->store_name)), S_REL)<0)
-	Fatal("Bad seek (R.rel)", procName);
-
-    /* loop... */
-    thposn = lseek(arcfd, 0L, S_REL);  /* save thread posn */
-    if (lseek(arcfd, (long) THsize, S_REL) < 0)
-	Fatal("Bad seek (Th)", procName);
-
-    /*
-     * since we can store files as being packed without actually packing them,
-     * we need to check "dopack" to see if we want packMethod or zero.  Note
-     * that packing can fail for various reasons; the value returned by
-     * PackFile() is the actual algorithm used to pack the file.
-     *
-     * NuLib uses version 0 records; thread_crcs are not stored.
-     */
-
-    thread[0].thread_format = 
-	    PackFile(srcfd,arcfd, infoptr->eof, dopack ? packMethod:0, pakbuf);
-    if (!dopack) thread[0].thread_format = packMethod;  /* for S subopt */
-    HiSwap((onebyt *) &thread[0].thread_format, 0, 1);
-    thread[0].comp_thread_eof = (fourbyt) packedSize;
-    HiSwap((onebyt *) &thread[0].comp_thread_eof, 0, 3);  /* correct ordering*/
-    HiSwap((onebyt *) &thread[0].comp_thread_eof, 1, 2);
-    tmpposn = lseek(arcfd, 0L, S_REL);
-
-    if (lseek(arcfd, thposn, S_ABS) < 0)  /* seek back to thread posn */
-	Fatal("Bad seek (Th2)", procName);
-    if (write(arcfd, &thread[0], THsize) < THsize)  /* write updated thread */
-	Fatal("Unable to write thread", procName);
-    if (lseek(arcfd, tmpposn, S_ABS) < 0)  /* seek back to where we were */
-	Fatal("Bad seek (TmpA)", procName);
-    /* ...loop end */
-
-    if (close(srcfd) < 0)
-	Fatal("Unable to close file", procName);
-
-    CRC = CalcCRC(0, (onebyt *) recBuf+6, ATTSIZE-6);
-    CRC = CalcCRC(CRC, (onebyt *) infoptr->store_name,
-	strlen(infoptr->store_name));
-    CRC = CalcCRC(CRC, (onebyt *) &thread[0], THsize);
-    twoptr = (twobyt *) (recBuf+4);
-    *twoptr = CRC;
-    HiSwap((onebyt *) recBuf, 4, 5);
-
-    tmpposn = lseek(arcfd, 0L, S_REL);	   /* record posn (next posn) */
-    if (lseek(arcfd, recposn, S_ABS) < 0)  /* seek back to record entry */
-	Fatal("Bad seek (R.abs)", procName);
-    if (write(arcfd, recBuf, ATTSIZE) < ATTSIZE)
-	Fatal("Unable to write record", procName);
-    if (write(arcfd, infoptr->store_name, strlen(infoptr->store_name))
-				     < strlen(infoptr->store_name))
-	Fatal("Unable to store filename", procName);
-    if (lseek(arcfd, tmpposn, S_ABS) < 0)  /* seek back to where we were */
-	Fatal("Bad seek (TmpB)", procName);
-
-    if (verbose) printf("done.\n");
-    free(recBuf);
-
-    /* switch ordering back */
-    HiSwap((onebyt *) &thread[0].comp_thread_eof, 0, 3);
-    HiSwap((onebyt *) &thread[0].comp_thread_eof, 1, 2);
-    return ( (long) (THsize * total_threads) + (long) ATTSIZE +
-	  (long) strlen(infoptr->store_name) + thread[0].comp_thread_eof);
-}
-
-
-/*
- * Certain options can cause an archive to be created (add, create, move).
- * If the archive does not already exist, then an empty file is created (of
- * type $e0/8002 under ProDOS) and an empty archive struct is built.
- *
- * Note that this requires certain options to deal with archive structures that
- * do not have any records, and archive files that are empty.
- *
- * If the file exists, this will call NuRead() to read it; otherwise, it will
- * create it.
- */
-static ListHdr *CreateMaybe(filename)
-char *filename;
-{
-    ListHdr *archive;
-    MHblock *MHptr;
-    onebyt *bufPtr;
-    twobyt *twoptr;
-    fourbyt *fourptr;
-    int idx;
-#ifdef APW
-    FileRec create_p;
-#endif
-    static char *procName = "CreateMaybe";
-
-    if (Exists(filename)) {
-	archive = NuRead(filename);
-	return (archive);
-    }
-
-    if (!docreate)
-	printf("Archive does not exist; creating archive file...\n");
-
-    archive = (ListHdr *) Malloc(sizeof(ListHdr));
-    archive->arc_name = (char *) Malloc(strlen(filename)+1);
-    strcpy(archive->arc_name, filename);
-    archive->MHptr = (MHblock *) Malloc(sizeof(MHblock));
-    archive->RNodePtr = (RNode *) NULL;
-    archive->nextposn = (long) MHsize;
-
-    bufPtr = (onebyt *) archive->MHptr;
-    for (idx = 0; idx < MHsize; idx++)
-	*(bufPtr+idx) = '\0';
-
-    /* total_records -> zero */
-    MHptr = archive->MHptr;
-    strncpy((char *) MHptr->ID, (char *) MasterID, 6);
-    BCopy((onebyt *) GetTime(), (onebyt *) &(MHptr->arc_create_when),8, FALSE);
-    BCopy((onebyt *) bufPtr+12, (onebyt *) &(MHptr->arc_mod_when), 8, FALSE);
-    fourptr = (fourbyt *) (&(MHptr->master_eof));
-    *fourptr = (fourbyt) MHsize;
-
-/*    twoptr = (twobyt *) (&(MHptr->master_crc));
-    *twoptr = CalcCRC(0, (onebyt *) bufPtr+8, MHsize-8); */
-
-    ArcfiCreate(filename);  /* create SHK file */
-    return (archive);
-}
-
-
-/*
- * Return a pointer to a valid Master Header block
- * Anything that isn't set to a default value needs to be passed as a
- * parameter [ right now I can't remember why ].
- */
-onebyt *MakeMHblock(archive, total_records, master_eof)
-ListHdr *archive;
-fourbyt total_records;
-fourbyt master_eof;
-{
-    static onebyt buf[MHsize];  /* must be static */
-    twobyt *twoptr;
-    fourbyt *fourptr;
-    int idx;
-    static char *procName = "MakeMHblock";
-
-    for (idx = 0; idx < MHsize ; idx++)
-	buf[idx] = '\0';
-
-    /* messy... should've used MHptr->thing here, but if it ain't broke... */
-    strncpy((char *) buf, (char *) MasterID, 6);
-    BCopy((onebyt *) &total_records, (onebyt *) &buf[8], 4, TRUE);
-    BCopy((onebyt *) &archive->MHptr->arc_create_when, (onebyt *) &buf[12],
-	sizeof(Time), FALSE);
-    BCopy((onebyt *) GetTime(), (onebyt *) &buf[20], sizeof(Time), FALSE);
-    twoptr = (twobyt *) &buf[28];  /* master version */
-    *twoptr = OURMVERS;
-    HiSwap((onebyt *) buf, 28, 29);  /* correct byte ordering */
-    BCopy((onebyt *) &master_eof, (onebyt *) &buf[38], 4, TRUE);
-    twoptr = (twobyt *) &buf[6];
-    *twoptr = CalcCRC(0, (onebyt *) &buf[8], MHsize-8);
-    HiSwap((onebyt *) buf, 6, 7);
-
-    return (buf);
-}
-
-
-/*
- * Add files to archive
- *
- * Read files from disk, adding them to the end of the archive as we go.
- * Update the master header block after all files have been added.
- */
-static void Add(filename, namecount, names)
-char *filename;
-int namecount;
-char **names;
-{
-    ListHdr *archive;
-    int arcfd;
-    file_info *FIArray[MAXARGS];  /* entries malloc()ed by EvalArgs */
-    int idx;
-    onebyt *mptr;  /* points to a MHblock suitable for writing */
-    long addSize;
-    static char *procName = "Add";
-
-    /* expand wildcards/subdirectories, and get file info */
-    namecount = EvalArgs(namecount, names, FIArray, TRUE);
-    if (!namecount) {
-	if (verbose) printf("No files selected.\n");
-	Quit (0);
-    }
-
-    archive = CreateMaybe(filename);
-    if ((arcfd = open(archive->arc_name, O_RDWR | O_BINARY)) < 0)
-	Fatal("Unable to open archive", procName);
-    if (lseek(arcfd, archive->nextposn, S_ABS) < 0)  /* seek to end */
-	Fatal("Unable to seek in archive", procName);
-
-    for (idx = 0 ; idx < namecount; idx++) {
-#ifdef APW
-	if (STOP()) Quit(1);  /* check for OA-. */
-#endif
-	addSize = AddFile(arcfd, FIArray[idx]);
-	archive->MHptr->master_eof += addSize;
-	archive->nextposn += addSize;
-	archive->MHptr->total_records++;
-    }
-
-    mptr = MakeMHblock(archive, archive->MHptr->total_records,
-		archive->MHptr->master_eof);
-    if (lseek(arcfd, 0L, S_ABS) < 0)
-	Fatal("Unable to rewind archive for master header", procName);
-
-    if (write(arcfd, mptr, MHsize) < MHsize)
-	Fatal("Unable to update master header", procName);
-    if (close(arcfd) < 0)
-	Fatal("Unable to close archive", procName);
-
-    if (domove) {
-	if (verbose) printf("Deleteing files...\n");
-	for (idx = 0; idx < namecount; idx++) {
-	    if (verbose) {
-		printf("%s...", FIArray[idx]->pathname);
-		fflush(stdout);
-	    }
-	    if (unlink(FIArray[idx]->pathname) < 0) {
-		if (verbose) printf("failed.\n");
-	    } else {
-		if (verbose) printf("done.\n");
-	    }
-	}
-    }
-}
-
-
-/*
- * Main entry point for adding files.
- */
-void NuAdd(filename, namecount, names, options)
-char *filename;
-int namecount;
-char **names;
-char *options;
-{
-    char *optr;
-    int idx;
-    char type[5];
-    static char *procName = "NuAdd";
-
-    if (*options == 'm')
-	domove = TRUE;
-
-    if (*options == 'c')
-	docreate = TRUE;
-
-    /* change T subopt to convert FROM current system TO <subopt> */
-    if (transfrom >= 0) {
-	transto = transfrom;
-	transfrom = -1;
-    }
-
-    Add(filename, namecount, names);  /* do main processing */
-}
-
+ END OF ARCHIVE