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