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