[comp.sources.apple2] v001SRC034: 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:34
Archive-name: archive/unix/nulib/part03.10
Architecture: UNIX
Version-number: 3.03


=nuread.c
-/*
- * nuread.c - read NuFX archives (header info only) into structures
- *
- * 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>
-
-#ifdef MSDOS     /* For file IO */
-# include <stdlib.h>		/* errno, among others */
-# include <string.h>
-# include <io.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#ifdef CRC_TAB
-# include "crc.h"     /* fast CRC lookup */
-#endif
-#include "nuread.h"
-#include "nupak.h"  /* uses PAKBUFSIZ */
-#include "nuetc.h"
-
-#define UNKNOWN_FN	"<No Filename>"
-
-/* quick proc to save x00 bytes of static storage */
-void OtherArc(str1, str2)
-{
-    fprintf(stderr, "File may be %s; try \"%s\".\n", str1, str2);
-}
-
-/* swap two bytes if HiLo is TRUE */
-void HiSwap(ptr, a, b)
-onebyt *ptr;
-register onebyt a, b;
-{
-    register onebyt tmp;
-
-    if (HiLo) {
-	tmp = ptr[a], ptr[a] = ptr[b], ptr[b] = tmp;
-    }
-}
-
-
-/* copy bytes from buffer to buffer, reversing byte order if necessary */
-void BCopy(srcptr, destptr, num, order)
-onebyt *srcptr, *destptr;
-register int num;
-BOOLEAN order;	/* true if byte ordering is important */
-{
-    register int i = num--;
-
-    if (order && HiLo) {
-	while (i--) {  /* copy & reverse */
-	    *(destptr+i) = *(srcptr + num - i);  /* dest+3 = src + 3 - 3 .. */
-	}
-    } else if (order) {
-	while (i--) {  /* copy only */
-	    *(destptr+i) = *(srcptr + i);
-	}
-    } else {
-	while (i--) {  /* byte ordering not important; just copy */
-	    *(destptr+i) = *(srcptr+i);
-	}
-    }
-}
-
-
-/*
- * Calculate CRC on a region
- *
- * A CRC is the result of a mathematical operation based on the
- * coefficients of a polynomial when multiplied by X^16 then divided by
- * the generator polynomial (X^16 + X^12 + X^5 + 1) using modulo two
- * arithmetic.
- *
- * This routine is a slightly modified verison of one found in:
- * _Advanced Programming Techniques for the Apple //gs Toolbox_
- * By Morgan Davis and Dan Gookin (Compute! Publications, Inc.)
- * It can either calculate the CRC bit-by-bit or use a table.
- * [ one of the few //gs books worth the money	+atm ]
- */
-twobyt CalcCRC(seed, ptr, count)
-twobyt seed;  /* initial value for CRC */
-onebyt *ptr;  /* pointer to start of data buffer */
-int count;    /* number of bytes to scan through - note 64K max */
-{
-    register int x;
-    register twobyt CRC = seed;
-
-    do {
-#ifndef CRC_TAB
-	CRC ^= *ptr++ << 8;		  /* XOR hi-byte of CRC w/data	 */
-	for (x = 8; x; --x)		  /* Then, for 8 bit shifts...	 */
-	    if (CRC & 0x8000)		  /* Test hi order bit of CRC	 */
-		CRC = CRC << 1 ^ 0x1021;  /* if set, shift & XOR w/$1021 */
-	    else
-		CRC <<= 1;		  /* Else, just shift left once. */
-#else
-	CRC = updcrc(*ptr++, CRC);	  /* look up new value in table  */
-#endif
-    } while (--count);
-    return (CRC);
-}
-
-
-/*
- * Test an archive's integrity.
- *
- * Reads the entire file, and checks CRCs for certain things.
- */
-void NuTest(filename, options)
-char *filename;
-char *options;
-{
-    ListHdr *archive;
-    onebyt *copybuf;  /* buffer for reading record */
-    int partial;   /* size for partial read */
-    unsigned int rec;
-    RNode *RNodePtr;
-    MHblock *MHptr;
-    TNode *TNodePtr;
-    long hdr_size, total_size, thread_size;
-    int srcfd;	/* file descriptor */
-    int thread;
-    twobyt CRC, RecordCRC;
-    long CRCsum = 0L;	/* sum of CRCs for all records */
-    BOOLEAN check_thread_crc;	/* TRUE if we want to check a give thread */
-    static char *procName = "NuTest";
-
-    printf("Testing %s", filename);
-    if (verbose) printf("\n");
-    else       { printf("...");  fflush(stdout); }
-
-    archive = NuRead(filename);  /* this catches most errors... */
-
-    MHptr = archive->MHptr;
-    RNodePtr = archive->RNodePtr;
-    copybuf = (onebyt *) Malloc(PAKBUFSIZ);
-    if ((srcfd = open(filename, O_RDONLY | O_BINARY)) < 0)
-	Fatal("Unable to close archive", procName);
-    if (lseek(srcfd, (long) MHsize, S_ABS) < 0)  /* seek past master block */
-	Fatal("Bad seek (MH)", procName);
-
-    for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) {
-	if (verbose) printf("Record %d (%s): ", rec, RNodePtr->filename);
-	hdr_size = (long) RNodePtr->RHptr->attrib_count;
-	hdr_size += (long) RNodePtr->filename_length;
-	total_size = hdr_size;
-	TNodePtr = RNodePtr->TNodePtr;
-	for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){
-	    if (TNodePtr == (TNode *) NULL) {
-		fprintf(stderr, "Internal error: Bad thread structure\n");
-		Quit(-1);
-	    }
-	    hdr_size += (long) THsize;
-	    total_size += (long) THsize;
-	    total_size += TNodePtr->THptr->comp_thread_eof;
-	    TNodePtr = TNodePtr->TNext;
-	}
-	if (verbose) {
-	    printf("total record size = %ld (%d threads)\n", total_size,
-		(int) RNodePtr->RHptr->total_threads);
-	    fflush(stdout);
-	}
-
-	/* read record header */
-	RecordCRC = 0;
-	while (hdr_size != 0L) {
-	    if (hdr_size > (long) PAKBUFSIZ) {
-		partial = (unsigned int) PAKBUFSIZ;
-		hdr_size -= (long) PAKBUFSIZ;
-	    } else {
-		partial = (unsigned int) hdr_size;
-		hdr_size = 0L;
-	    }
-
-	    if (read(srcfd, copybuf, partial) != partial) {
-		fprintf(stderr, ">>> Read error");
-		if (verbose) fprintf(stderr, "\n");
-		else fprintf(stderr,
-			" - record %d (%s)\n",  rec, RNodePtr->filename);
-		fprintf(stderr, "Operation aborted.\n");
-		Quit(-1);
-	    }
-	    if (verbose) RecordCRC = CalcCRC(CRC, (onebyt *) copybuf, partial);
-	}
-
-	TNodePtr = RNodePtr->TNodePtr;
-	for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){
-	    if (lseek(srcfd, (long) TNodePtr->fileposn, S_ABS) < 0)
-		Fatal("whoops!", procName);
-	    thread_size = TNodePtr->THptr->comp_thread_eof;
-
-	    /* decide whether or not to check thread CRCs */
-	    check_thread_crc = FALSE;
-	    if (RNodePtr->RHptr->version_number >= 2)	/* valid CRCs */
-		if (TNodePtr->THptr->thread_class == 2)	/* data_thread */
-		    check_thread_crc = TRUE;
-	    if (RNodePtr->RHptr->version_number == 3)	/* CRC of uncom data */
-		if (TNodePtr->THptr->thread_format != 0x0000)
-		    check_thread_crc = FALSE;		/* can't check comp */
-
-	    if (check_thread_crc) CRC = 0xffff;
-	    while (thread_size != 0L) {
-		if (thread_size > (long) PAKBUFSIZ) {
-		    partial = (unsigned int) PAKBUFSIZ;
-		    thread_size -= (long) PAKBUFSIZ;
-		} else {
-		    partial = (unsigned int) thread_size;
-		    thread_size = 0L;
-		}
-
-		if (read(srcfd, copybuf, partial) != partial) {
-		    fprintf(stderr, ">>> Read error in thread");
-		    if (verbose) fprintf(stderr, " %d\n", thread);
-		    else fprintf(stderr, " - record %d (%s), thread %d\n",
-			    rec, RNodePtr->filename, thread);
-		    fprintf(stderr, "Operation aborted.\n");
-		    Quit(-1);
-		}
-
-		if (verbose)
-		    RecordCRC = CalcCRC(RecordCRC, (onebyt *)copybuf, partial);
-
-		/* calculate CRC for thread, and compare with thread_crc */
-		if (check_thread_crc)
-		    CRC = CalcCRC(CRC, (onebyt *) copybuf, partial);
-#ifdef DEBUG
-		printf(
-"At posn %ld: rec %d/thread %d (%ld bytes)  CalcCRC = 0x%.4x (0x%.4x)\n",
-TNodePtr->fileposn, rec, thread, thread_size, CRC, TNodePtr->THptr->thread_crc
-		);
-#endif
-	    }
-
-	    /* check and see if CRC matches */
-	    if (check_thread_crc) {
-		if (CRC != TNodePtr->THptr->thread_crc) {
-		    fprintf(stderr, ">>> Bad CRC for thread %d",
-			thread);
-		    if (verbose) fprintf(stderr, "\n");
-		    else fprintf(stderr, " in record %d\n", rec);
-		} else {
-		    if (verbose) printf("--- CRC matched for thread %d\n",
-			thread);
-		}
-	    }
-	    TNodePtr = TNodePtr->TNext;
-	}
-
-	if (verbose) {
-	    printf("--- CRC for entire record was $%.4x\n", RecordCRC);
-	    CRCsum += RecordCRC;
-	}
-	RNodePtr = RNodePtr->RNext;
-    }
-    if (close(srcfd) < 0)
-	Fatal("Unable to close archive", procName);
-
-    free(copybuf);
-    if (verbose) printf("Sum of CRCs = $%.8lx\n", CRCsum);
-    printf("done.\n");
-}
-
-
-/*
- * Read thread header data, and skip data fields
- */
-
-static TNode *ReadThreads(fd, RHptr, RNodePtr, CRC_ptr)
-int fd;
-RHblock *RHptr;
-RNode *RNodePtr;
-twobyt *CRC_ptr;  /* CRC seed; result is returned thru this */
-{
-    int i;
-    unsigned int size;
-    BOOLEAN first;
-    TNode *TNodePtr, *THeadPtr = (TNode *) NULL;
-    THblock *THptr;
-    char filebuf[THsize];
-    twobyt CRC = *CRC_ptr;
-    static char *procName = "ReadThreads";
-
-    RNodePtr->unc_len = 0L;
-    RNodePtr->comp_len = 0L;
-    first = TRUE;
-    for (i = 0; i < RHptr->total_threads; i++) {
-	if (first) {  /* create first block, or... */
-	    TNodePtr = (TNode *) Malloc(sizeof(TNode));
-	    THeadPtr = TNodePtr;
-	    first = FALSE;
-	} else {  /* create next block and go on */
-	    TNodePtr->TNext = (TNode *) Malloc(sizeof(TNode));
-	    TNodePtr = TNodePtr->TNext;
-	}
-	TNodePtr->TNext = (TNode *) NULL;
-
-	/* Create the thread header block, and read it in */
-	TNodePtr->THptr = (THblock *) Malloc(sizeof(THblock));
-	THptr = TNodePtr->THptr;
-
-	if (size = read(fd, filebuf, THsize) < THsize) {  /* should be 16 */
-	    printf("read size = %d, THsize = %d\n", size, THsize);
-	    Fatal("ReadThread (THblock)", procName);
-	}
-	CRC = CalcCRC(CRC, (onebyt *) filebuf, 16);  /* hdr CRC part(s) 5/5 */
-
-	/* copy all fields... */
-	BCopy(filebuf+0, (onebyt *) &THptr->thread_class, 2, TRUE);
-	BCopy(filebuf+2, (onebyt *) &THptr->thread_format, 2, TRUE);
-	BCopy(filebuf+4, (onebyt *) &THptr->thread_kind, 2, TRUE);
-	BCopy(filebuf+6, (onebyt *) &THptr->thread_crc, 2, TRUE);
-	BCopy(filebuf+8, (onebyt *) &THptr->thread_eof, 4, TRUE);
-	BCopy(filebuf+12, (onebyt *) &THptr->comp_thread_eof, 4, TRUE);
-
-	RNodePtr->unc_len += THptr->thread_eof;
-	RNodePtr->comp_len += THptr->comp_thread_eof;
-	if (THptr->comp_thread_eof > 2097152L)	/* SANITY CHECK */
-	    fprintf(stderr, "Sanity check: found comp_thread_eof > 2MB\n");
-    }
-
-    /* skip the actual data */
-    TNodePtr = THeadPtr;
-    for (i = 0; i < RHptr->total_threads; i++) {
-	THptr = TNodePtr->THptr;
-	if ((TNodePtr->fileposn = lseek(fd, 0L, S_REL)) < 0)
-	    Fatal("Bad thread posn lseek()", procName);
-
-	/* pull filenames out of threads, if present */
-	if (THptr->thread_class == 0x0003) {	/* filename thread */
-	    RNodePtr->filename = (char *) Malloc(THptr->thread_eof +1);
-	    if (read(fd, RNodePtr->filename, THptr->thread_eof) < 0) {
-		fprintf(stderr, "Error on thread %d\n", i);
-		Fatal("Unable to read filename", procName);
-	    }
-	    RNodePtr->filename[THptr->thread_eof] = '\0';
-	    RNodePtr->real_fn_length = THptr->thread_eof;
-
-	    {		/* patch to fix bug in ShrinkIt v3.0.0 */
-		int j, name_len = strlen(RNodePtr->filename);
-
-		for (j = 0; j < name_len; j++) {
-		    RNodePtr->filename[j] &= 0x7f;	/* clear hi bit */
-		}
-	    }
-
-	    if (lseek(fd, TNodePtr->fileposn, S_ABS) < 0)
-		Fatal("Unable to seek back after fn", procName);
-	}
-	if (lseek(fd, THptr->comp_thread_eof, S_REL) < 0)
-	    Fatal("Bad skip-thread seek", procName);
-	TNodePtr = TNodePtr->TNext;
-    }
-    *CRC_ptr = CRC;
-    return (THeadPtr);
-}
-
-
-/*
- * Read header data from a NuFX archive into memory
- */
-ListHdr *NuRead(filename)
-char *filename;
-{
-    int fd;  /* archive file descriptor */
-    char namebuf[MAXFILENAME];
-    int rec, num;
-    BOOLEAN first;
-    twobyt namelen;
-    twobyt CRC;
-    ListHdr *ListPtr;  /* List Header struct */
-    MHblock *MHptr;  /* Master Header block */
-    RNode *RNodePtr;  /* Record Node */
-    RHblock *RHptr;  /* Record Header block */
-    onebyt filebuf[RECBUFSIZ];	/* must be > RH, MH, or atts-RH size */
-    static char *procName = "NuRead";
-
-    ListPtr = (ListHdr *) Malloc(sizeof(ListHdr));  /* create head of list */
-    ListPtr->arc_name = (char *) Malloc(strlen(filename)+1); /* archive fnam */
-    strcpy(ListPtr->arc_name, filename);
-    ListPtr->MHptr = (MHblock *) Malloc(sizeof(MHblock));  /* master block */
-
-    if ((fd = open(filename, O_RDONLY | O_BINARY)) < 0) {
-	if (errno == ENOENT) {
-	    fprintf(stderr, "%s: can't find file '%s'\n", prgName, filename);
-	    Quit (-1);
-	} else
-	    Fatal("Unable to open archive", procName);
-    }
-
-    /* create and read the master header block */
-    MHptr = ListPtr->MHptr;
-    if (read(fd, filebuf, MHsize) < MHsize) {
-	fprintf(stderr, "File '%s' may not be a NuFX archive\n", filename);
-	Fatal("Unable to read Master Header Block", procName);
-    }
-
-    CRC = CalcCRC(0, (onebyt *) filebuf+8, MHsize-8);  /* master header CRC */
-
-    /* Copy data to structs, correcting byte ordering if necessary */
-    BCopy(filebuf+0, (onebyt *) MHptr->ID, 6, FALSE);
-    BCopy(filebuf+6, (onebyt *) &MHptr->master_crc, 2, TRUE);
-    BCopy(filebuf+8, (onebyt *) &MHptr->total_records, 4, TRUE);
-    BCopy(filebuf+12, (onebyt *) &MHptr->arc_create_when, sizeof(Time), FALSE);
-    BCopy(filebuf+20, (onebyt *) &MHptr->arc_mod_when, sizeof(Time), FALSE);
-    BCopy(filebuf+28, (onebyt *) &MHptr->master_version, 2, TRUE);
-    BCopy(filebuf+30, (onebyt *) MHptr->reserved1, 8, FALSE);
-    BCopy(filebuf+38, (onebyt *) &MHptr->master_eof, 4, TRUE);  /* m_v $0001 */
-    BCopy(filebuf+42, (onebyt *) MHptr->reserved2, 6, FALSE);
-
-    if (strncmp(MHptr->ID, MasterID, 6)) {
-	fprintf(stderr, "\nFile '%s' is not a NuFX archive\n", filename);
-	if ((filebuf[0] == 10) && (filebuf[1] == 71) &&
-	    (filebuf[2] == 76) && (filebuf[18] == 2))
-#ifdef NO_BLU
-	    OtherArc("Binary II", "unblu");
-#else
-	    fprintf(stderr, "File may be Binary II; try 'B' option\n");
-#endif
-	if ((filebuf[0] == '\037') && (filebuf[1] == '\036'))
-	    OtherArc("packed", "unpack");
-	if ((filebuf[0] == (onebyt)'\377') && (filebuf[1] == '\037'))
-	    OtherArc("compacted", "uncompact");
-	if ((filebuf[0] == '\037') && (filebuf[1] == (onebyt)'\235'))
-	    OtherArc("compressed", "uncompress");
-	if ((filebuf[0] == 0x76) && (filebuf[1] == 0xff))
-	    OtherArc("SQueezed", "usq");
-	if ((filebuf[0] == 0x04) && (filebuf[1] == 0x03) &&
-	    (filebuf[2] == 0x4b) && (filebuf[3] == 0x50))
-	    OtherArc("a ZIP archive", "UnZip");
-	if (!strncmp((char *) filebuf, "ZOO", 3))	/* zoo */
-	    OtherArc("a ZOO archive", "zoo");
-	if ((filebuf[0] == 0x1a) && (filebuf[1] == 0x08))	/* arc */
-	    OtherArc("an ARC archive", "arc");
-	if (!strncmp((char *) filebuf, "SIT!", 4))	/* StuffIt */
-	    OtherArc("a StuffIt archive", "StuffIt (Macintosh)");
-	if (!strncmp((char *) filebuf, "<ar>", 4))	/* system V arch */
-	    OtherArc("a library archive (Sys V)", "ar");
-	if (!strncmp((char *) filebuf, "!<arch>", 7))
-	    OtherArc("a library archive", "ar");
-	if (!strncmp((char *) filebuf, "#! /bin/sh", 10) ||
-	    !strncmp((char *) filebuf, "#!/bin/sh", 9))
-	    OtherArc("a shar archive", "/bin/sh");
-	if (!strncmp((char *) filebuf, "GIF87a", 6))
-	    OtherArc("a GIF picture", "?!?");
-	/* still need ZIP */
-
-	Quit (-1);
-    }
-
-    if (CRC != MHptr->master_crc)
-	printf("WARNING: Master Header block may be corrupted (bad CRC)\n");
-
-    if (MHptr->master_version > MAXMVERS)
-	printf("WARNING: unknown Master Header version, trying to continue\n");
-
-    /* main record read loop */
-    first = TRUE;
-    for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) {
-	if (first) {  /* allocate first, or... */
-	    ListPtr->RNodePtr = (RNode *) Malloc(sizeof(RNode));
-	    RNodePtr = ListPtr->RNodePtr;
-	    first = FALSE;
-	} else {  /* allocate next, and go on */
-	    RNodePtr->RNext = (RNode *) Malloc(sizeof(RNode)); /* next Rnode */
-	    RNodePtr = RNodePtr->RNext;  /* move on to next record */
-	}
-	RNodePtr->RNext = (RNode *) NULL;
-
-	RNodePtr->RHptr = (RHblock *) Malloc(sizeof(RHblock)); /* alloc blk */
-	/* expansion here */
-	RHptr = RNodePtr->RHptr;
-	if (read(fd, filebuf, RHsize) < RHsize) {  /* get known stuff */
-	    fprintf(stderr,"%s: error in record %d (at EOF?)\n", prgName, rec);
-	    Fatal("Bad RHblock read", procName);
-	}
-
-	/* rec hdr CRC part 1/5 */
-	CRC = CalcCRC(0, (onebyt *) filebuf+6, RHsize-6);
-
-	BCopy(filebuf+0, (onebyt *) RHptr->ID, 4, FALSE);
-	BCopy(filebuf+4, (onebyt *) &RHptr->header_crc, 2, TRUE);
-	BCopy(filebuf+6, (onebyt *) &RHptr->attrib_count, 2, TRUE);
-	BCopy(filebuf+8, (onebyt *) &RHptr->version_number, 2, TRUE);
-	BCopy(filebuf+10, (onebyt *) &RHptr->total_threads, 2, TRUE);
-	BCopy(filebuf+12, (onebyt *) &RHptr->reserved1, 2, TRUE);
-	BCopy(filebuf+14, (onebyt *) &RHptr->file_sys_id, 2, TRUE);
-	BCopy(filebuf+16, (onebyt *) &RHptr->file_sys_info, 1, TRUE);
-	BCopy(filebuf+17, (onebyt *) &RHptr->reserved2, 1, TRUE);
-	BCopy(filebuf+18, (onebyt *) &RHptr->access, 4, TRUE);
-	BCopy(filebuf+22, (onebyt *) &RHptr->file_type, 4, TRUE);
-	BCopy(filebuf+26, (onebyt *) &RHptr->extra_type, 4, TRUE);
-	BCopy(filebuf+30, (onebyt *) &RHptr->storage_type, 2, TRUE);
-	BCopy(filebuf+32, (onebyt *) &RHptr->create_when, sizeof(Time), FALSE);
-	BCopy(filebuf+40, (onebyt *) &RHptr->mod_when, sizeof(Time), FALSE);
-	BCopy(filebuf+48, (onebyt *) &RHptr->archive_when, sizeof(Time), FALSE);
-	BCopy(filebuf+56, (onebyt *) &RHptr->option_size, 2, TRUE);
-	/* expansion here */
-
-	if (strncmp(RHptr->ID, RecordID, 4)) {
-	    fprintf(stderr, "%s: Found bad record ID (#%d) -- exiting\n",
-								prgName, rec);
-	    Quit (-1);
-	}
-
-	/* read remaining (unknown) attributes into buffer, if any */
-	num = RHptr->attrib_count - RHsize - 2;
-	if (num > RECBUFSIZ) {
-	    fprintf(stderr, "ERROR: attrib_count > RECBUFSIZ\n");
-	    Quit (-1);
-	}
-	if (num > 0) {
-	    if (read(fd, filebuf, num) < num)
-		Fatal("Bad xtra attr read", procName);
-	    CRC = CalcCRC(CRC, (onebyt *) filebuf, num);  /* hdr CRC part 2/5 */
-	}
-
-	if (read(fd, (char *) &namelen, 2) < 2)  /* read filename len */
-	    Fatal("Bad namelen read", procName);
-	CRC = CalcCRC(CRC, (onebyt *) &namelen, 2);  /* rec hdr CRC part 3/5 */
-
-	HiSwap((onebyt *) &namelen, 0, 1);
-	/* read filename, and store in struct */
-	if (namelen > MAXFILENAME) {
-	    fprintf(stderr, "ERROR: namelen > MAXFILENAME\n");
-	    Quit (-1);
-	}
-	RNodePtr->filename_length = namelen;
-
-	if (namelen > 0) {
-	    RNodePtr->real_fn_length = namelen;
-	    if (read(fd, namebuf, namelen) < namelen)
-		Fatal("Bad namebuf read", procName);
-	    /* rec hdr CRC part 4/5 */
-	    CRC = CalcCRC(CRC, (onebyt *) namebuf, namelen); 
-
-	    RNodePtr->filename = (char *) Malloc(namelen+1);  /* store fname */
-	    BCopy(namebuf, (onebyt *) RNodePtr->filename, namelen, FALSE);
-	    RNodePtr->filename[namelen] = '\0';
-	} else {
-	    RNodePtr->filename = UNKNOWN_FN;
-	    RNodePtr->real_fn_length = strlen(UNKNOWN_FN);
-	}
-
-	RNodePtr->TNodePtr = ReadThreads(fd, RHptr, RNodePtr, &CRC);
-	/* rec hdr CRC part 5/5 calculated by ReadThreads */
-
-	if (CRC != RHptr->header_crc) {
-	    printf("WARNING: Detected a bad record header CRC\n");
-	    printf("         Rec %d in file '%.60s'\n",rec,RNodePtr->filename);
-	}
-    }
-
-    /* begin adding new files at  this point */
-    if ((ListPtr->nextposn = lseek(fd, 0L, S_REL)) < 0)
-	Fatal("Bad final lseek()", procName);
-
-    if (close(fd) < 0) {
-	Fatal("Bad close", procName);
-    }
-
-    if (MHptr->master_version > 0x0000) {
-	if (MHptr->master_eof != ListPtr->nextposn) {
-	    printf("WARNING: master_eof (stored)=%ld, nextposn (actual)=%ld\n",
-		MHptr->master_eof, ListPtr->nextposn);
-	    printf(
-		"         (master_eof will be fixed if archive is changed)\n");
-	}
-    }
-	
-    return (ListPtr);
-}
-
=nuext.c
-/*
- * nuext.c - operations which extract from 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>
-#ifdef BSD43
-# include <strings.h>
-#else  /* SYSV, APW, MSC */
-# include <string.h>
-#endif
-#include <fcntl.h>
-
-#ifdef UNIX
-# include <errno.h>
-# include <time.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-#ifdef APW
-# include <types.h>
-# include <prodos.h>
-# include <shell.h>
-# include <strings.h>
-#endif
-#ifdef MSDOS
-# include <io.h>
-# include <time.h>
-# include <stdlib.h>
-# include <errno.h>
-# include <direct.h>
-# include <utime.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#include "nuread.h"
-#include "nuext.h"
-#include "nupak.h"
-#include "nuetc.h"
-
-static BOOLEAN extall;	/* extract all files? */
-static BOOLEAN print;   /* extract to screen rather than file? */
-
-
-/*
- * Get the answer to a yes/no question.
- *
- * Returns TRUE for yes, FALSE for no.  May return additional things in the
- * future... (y/n/q)?
- */
-int AskYesNo()
-{
-    char buf[16];  /* if user answers with >16 chars, bad things happen */
-    char c;
-
-    printf(" (y/n)? ");
-    fflush(stdout);
-    gets(buf);
-    c = *buf;
-    if ((c == 'y') || (c == 'Y'))
-	return (TRUE);
-    else
-	return (FALSE);
-}
-
-
-/*
- * Convert a filename to one legal in the present file system.
- *
- * Does not allocate new space; alters string in place (so original string
- * will be "corrupted").  Assumes that it has been passed a filename without
- * the filename separators.
- */
-void ConvFileName(str)
-char *str;
-{
-    int idx = 0;
-#ifdef UNIX
-
-    while (*str != '\0') {
-	if ((*str > 127) || (*str < 0)) *str &= 0x7f;  /* clear hi bit */
-	if (*str == '/') *str = '.';
-	if (++idx > 255) { *str = '\0'; break; }
-	str++;
-    }
-#else
-# ifdef APW
-    static char *legal =
-	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.";
-
-    /* assumes ProDOS limits, not GS/OS */
-    if ( ((*str < 'A') && (*str > 'Z'))  ||  ((*str < 'a') && (*str > 'z')) )
-	*str = 'X';  /* must start with alpha char */
-    while (*str != '\0') {
-	if (!INDEX(legal, *str)) *str = '.';
-	if (++idx > 15) { *str = '\0'; break; }
-	str++;
-    }
-# endif /* APW */
-# ifdef MSDOS
-    while (*str != '\0') {
-       if ((*str > 127) || (*str < 0)) *str &= 0x7f;  /* clear hi bit */
-       if (*str == '/') *str = '_';
-       if (*str == '\\') *str = '_';
-       if (*str == '!') *str = '_';
-       if (*str == ':') *str = '_';
-       if (++idx > 255) { *str = '\0'; break; }
-       str++;
-    }
-# endif /* MSDOS */
-
-# ifndef APW
-# ifndef MSDOS
-    printf("Need [other] filename converter\n");  /* +PORT+ */
-# endif /* none2 */
-# endif /* none1 */
-#endif /*UNIX*/
-}
-
-/*
- * Set a file's attributes according to info in a record structure.
- */
-void SetFInfo(filename, RHptr)
-char *filename;
-RHblock *RHptr;
-{
-    static char *procName = "SetFInfo";
-#ifdef UNIX
-    long ltime;
-    time_t timep[2];
-
-    ltime = ReduceTime(&RHptr->mod_when);  /* set both to mod time */
-    timep[0] = ltime;  /* accessed */
-    timep[1] = ltime;  /* modified */
-    utime(filename, timep);
-
-    if ((RHptr->access == 0xe3L) || (RHptr->access == 0xc3L))  /* unlocked */
-	chmod(filename, S_IREAD | S_IWRITE | 044);
-    if ((RHptr->access == 0x21L) || (RHptr->access == 0x01L))  /* locked */
-	chmod(filename, S_IREAD | 044);
-
-#else  /* UNIX */
-# ifdef APW
-    /*
-     * Call ProDOS SET_FILE_INFO to set attributes for a file.
-     * Uses the information in the record header block.
-     */
-    FileRec finfo;
-    OpenRec oinfo;
-    twobyt date, time;
-    long ltime;
-
-    finfo.pathname = c2pstr(filename);	/* temp storage...? */
-    finfo.fAccess = (twobyt) RHptr->access;
-    finfo.fileType = (twobyt) RHptr->file_type;
-    finfo.auxType = RHptr->extra_type;
-    finfo.storageType = 0;  /* RHptr->storage_type otherwise */
-    ltime = ReduceTime(&RHptr->create_when);
-    date = (twobyt) ltime;  /* date is lower 16 */
-    time = (twobyt) (ltime >> 16);  /* time is upper */
-    finfo.createDate = date;
-    finfo.createTime = time;
-    ltime = ReduceTime(&RHptr->mod_when);
-    date = (twobyt) ltime;  /* date is lower 16 */
-    time = (twobyt) (ltime >> 16);  /* time is upper */
-    finfo.modDate = date;
-    finfo.modTime = time;
-
-    SET_FILE_INFO( &finfo );
-    ToolErrChk();
-# endif /* APW */
-# ifdef MSDOS
-    long ltime;
-    time_t timep[2];
-
-    ltime = ReduceTime(&RHptr->mod_when);
-    timep[0] = ltime;  /* accessed */
-    timep[1] = ltime;  /* modified */
-    utime(filename, timep);
-
-    if ((RHptr->access == 0xe3L) || (RHptr->access == 0xc3L))  /* unlocked */
-       chmod(filename, S_IREAD | S_IWRITE | 044);
-    if ((RHptr->access == 0x21L) || (RHptr->access == 0x01L))  /* locked */
-       chmod(filename, S_IREAD | 044);
-# endif /* MSDOS */
-
-# ifndef APW
-# ifndef MSDOS
-    printf("need [other] SetFInfo stuff\n");  /* +PORT+ */
-# endif /* none2 */
-# endif /* none1 */
-#endif /* APW */
-}
-
-
-/*
- * Create a subdirectory
- *
- * This routine will exit on most errors, since generally more than one file
- * will be unpacked to a given subdirectory, and we don't want it charging
- * bravely onward if it's going to run into the same problem every time.
- */
-void CreateSubdir(pathname)
-char *pathname;
-{
-    char *buffer = (char *) Malloc(MAXFILENAME+6);
-    static char *procName = "CreateSubdir";
-#ifdef UNIX
-    struct stat st;
-
-    /* if no directory exists, then make one */
-    if (stat(pathname, &st) < 0)
-	if (errno == ENOENT) {
-	    sprintf(buffer, "mkdir %s", pathname);
-	    if (system(buffer) != 0)  /* call UNIX mkdir to create subdir */
-		Fatal("Unable to create subdir", procName);
-	} else {
-	    Fatal("Unable to create dir", procName);
-	}
-#else
-# ifdef APW
-    static FileRec create_p = { "", 0x00e3, 0x000f, 0L, 0x000d, 0, 0 }; /*dir*/
-    FileRec info_p;  /* check if file exists, is dir */
-    int err;  /* holds _toolErr */
-
-    strcpy(buffer, pathname);
-    c2pstr(buffer);
-    info_p.pathname = buffer;
-    GET_FILE_INFO( &info_p );
-
-    switch (_toolErr) {
-    case 0x0000:  /* no error */
-	if (info_p.storageType != 0x000d)  /* not a DIR? */
-	    Fatal("File in path exists, is not a directory.", procName);
-	return;  /* file exists, is directory, no need to create */
-
-    case fileNotFound:
-	create_p.pathname = buffer;
-	CREATE( &create_p );
-	if   (!_toolErr) return;   /* created okay? */
-	else ToolErrChk();
-
-    default:  /* unknown error */
-	ToolErrChk();
-	Fatal("whoops!", procName); /* shouldn't get here */
-    }
-# endif /* APW */
-# ifdef MSDOS
-    struct stat st;
-
-    /* if no directory exists, then make one */
-    if (stat(pathname, &st) < 0)
-	if (errno == ENOENT) {
-	    if (mkdir(pathname) != 0)
-		Fatal("Unable to create subdir", procName);
-        } else {
-	    Fatal("Unable to create dir", procName);
-        }
-# endif /* MSDOS */
-
-# ifndef APW
-# ifndef MSDOS
-
-    /* don't forget to check if it exists first... */  /* +PORT+ */
-    printf("don't know how to create [other] subdirectories\n"); /* mkdir() */
-# endif /* none2 */
-# endif /* none1 */
-#endif /* UNIX */
-    free(buffer);
-}
-
-
-/*
- * Given a pathname, create subdirectories as needed.  All file names are run
- * through a system-dependent filename filter, which means that the pathname
- * has to be broken down, the subdirectory created, and then the pathname
- * reconstructed with the "legal" pathname.  The converted filename is held
- * in a static buffer; subsequent calls will overwrite the previous string.
- *
- * This is useful when unpacking "dir1/dir2/fubar" and dir1 and dir2 don't
- * necessarily exist.
- *
- * It is assumed that all filenames are relative to the current directory.
- * According to the NuFX docs (revision 3 2/3/89), initial separators (like
- * "/", "\", or ":") should NOT be included.  If they are, this routine may
- * break.
- */
-static char *CreatePath(pathname, fssep)
-char *pathname;  /* full pathname; should not include ProDOS volume name */
-onebyt fssep;  /* file system pathname separator, usually "/" or "\" */
-{
-    int idx;
-    char *ptr;
-    static char workbuf[MAXFILENAME];  /* work buffer; must be static */
-    static char *procName = "CreatePath";
-
-    idx = 0;
-    while (TRUE) {  /* move through string */
-	ptr = INDEX(pathname, fssep);	/* find break */
-	if (ptr)  /* down to actual filename? */
-	    *ptr = '\0';  /* no, isolate this part of the string */
-
-	strcpy(&workbuf[idx], pathname);  /* copy component to buf */
-	ConvFileName(&workbuf[idx]); /* convert to legal str; may be shorter */
-	idx += strlen(&workbuf[idx]);  /* advance index to end of string */
-	if (!ptr) {  /* down to actual filename? */
-	    workbuf[idx] = '\0';  /* yes, clean up */
-	    break;  /* out of while */
-	}
-	workbuf[idx] = '\0';
-
-	CreateSubdir(workbuf);	/* system-dependent dir create */
-
-#ifdef UNIX
-	workbuf[idx++] = '/';	/* tack a filename separator on, and advance */
-	*ptr = '/';	/* be nice */
-#else
-# ifdef APW
-	workbuf[idx++] = '/';
-	*ptr = '/';
-# endif
-# ifdef MSDOS
-	workbuf[idx++] = '\';
-	*ptr = '\';
-# endif
-# ifndef APW		/* +PORT+ */
-# ifndef MSDOS
-	workbuf[idx++] = '/';
-	*ptr = '/';
-# endif
-# endif
-#endif /*UNIX*/
-
-/* was:	workbuf[idx++] = fssep;  /* tack an fssep on the end, and advance */
-/* was:	*ptr = fssep;	/* be nice */
-
-	pathname = ptr+1;  /* go again with next component */
-    }
-
-    return (workbuf);
-}
-
-
-/*
- * Extract a thread, and place in a file.
- *
- * Returns TRUE if the extract was successful, FALSE otherwise.  The most
- * common reason for a FALSE return value is a "no" answer when asked about
- * overwriting an existing file.
- */
-static BOOLEAN ExtractThread(arcfd, fileposn, destpn, THptr)
-int arcfd;	/* source file descriptor (must be open) */
-long fileposn;	/* position of data in source file */
-char *destpn;	/* destination filename */
-THblock *THptr;  /* pointer to thread info */
-{
-    int dstfd;	/* destination file descriptor */
-    static char *procName = "ExtractThread";
-
-    if (!print) {
-	if (Exists(destpn)) {
-	    if (interact) {
-		if (verbose) printf("file exists, overwite");
-		else         printf("%s exists, overwite", destpn);
-		if (!AskYesNo()) {  /* return w/o overwriting */
-		    return (FALSE);
-		}
-	    }
-	    if (verbose) { printf("overwriting..."); fflush(stdout); }
-	    if (unlink(destpn) < 0)
-		Fatal("Unable to remove existing file", procName);
-	}
-
-	if ((dstfd =
-		open(destpn, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, WPERMS)) < 0)
-	    Fatal("Unable to open target path", procName);
-
-	if (lseek(arcfd, fileposn, S_ABS) < 0)
-	    Fatal("Seek failed", procName);
-
-	if (!UnpackFile(arcfd, dstfd, THptr,
-			dopack ? THptr->thread_format : 0, pakbuf)) {
-	    if (close(dstfd) < 0)
-		Fatal("Dest close failed", procName);
-	    unlink(destpn);  /* some sys can't delete while file open */
-	} else {
-	    if (close(dstfd) < 0)
-		Fatal("Dest close failed", procName);
-	}
-
-    } else {  /* print */
-	if ((dstfd = fileno(stdout)) < 0)
-	    Fatal("Unable to get file for stdout", procName);
-	if (lseek(arcfd, fileposn, S_ABS) < 0)
-	    Fatal("Seek failed", procName);
-
-	if (!UnpackFile(arcfd, dstfd, THptr,
-	    		dopack ? THptr->thread_format : 0, pakbuf)) {
-	    printf("Unpack failed.\n");
-	    return (FALSE);
-	}
-	fflush(stdout);
-    }
-
-    return (TRUE);
-}
-
-
-/*
- * Handle message_threads
- */
-static void message_thread(arcfd, RNodePtr, TNodePtr)
-int arcfd;
-RNode *RNodePtr;
-TNode *TNodePtr;
-{
-    int i;
-    int oldTo, oldFrom;
-    static char *procName = "message_thread";
-
-    switch (TNodePtr->THptr->thread_kind) {
-    case 0x0000:  /* ASCII text */
-	printf("Found ASCII text thread\n");
-	break;
-    case 0x0001:  /* ASCII text, predefined size */
-	if (verbose && !print && TNodePtr->THptr->thread_eof) {
-	    printf("\n--- Comment for file '%s':\n", RNodePtr->filename);
-	    fflush(stdout);
-	    if (lseek(arcfd, TNodePtr->fileposn, S_ABS) < 0)
-		Fatal("unable to seek to comment", procName);
-	    oldTo = transto;
-	    oldFrom = transfrom;
-	    transto = -1;	/* switch to CR -> current mode */
-	    transfrom = 0;	/* (assumes created under ProDOS) */
-				/* may need to fix this later (but how?) */
-	    FCopy(arcfd, fileno(stdout), TNodePtr->THptr->thread_eof,
-		pakbuf, TRUE);
-#ifdef FUBAR
-	    print = TRUE;
-	    verbose = FALSE;  /* turn off "unshrinking..." messages */
-	    ExtractThread(arcfd,TNodePtr->fileposn, "stdout", TNodePtr->THptr);
-	    print = FALSE;
-	    verbose = TRUE;
-#endif
-	    transto = oldTo;
-	    transfrom = oldFrom;
-	    putchar('\n');
-	}
-	break;
-    default:
-	printf("Found unknown message_thread %.4x in '%s'\n",
-	    TNodePtr->THptr->thread_kind, RNodePtr->filename);
-	break;
-    }
-}
-
-/*
- * Handle control_threads
- */
-static void control_thread(arcfd, RNodePtr, TNodePtr)
-int arcfd;
-RNode *RNodePtr;
-TNode *TNodePtr;
-{
-    switch (TNodePtr->THptr->thread_kind) {
-    case 0x000:  /* create dir */
-	printf("Found create directory control thread\n");
-	break;
-    default:
-	printf("Found unknown control_thread %.4x in '%s'\n",
-	    TNodePtr->THptr->thread_kind, RNodePtr->filename);
-	break;
-    }
-}
-
-
-/*
- * Handle data_threads
- *
- * Does not guarantee that the archive file position is anything rational;
- * the TNode's fileposn should be (and is) used here.
- */
-static void data_thread(arcfd, RNodePtr, TNodePtr)
-int arcfd;
-RNode *RNodePtr;
-TNode *TNodePtr;
-{
-    long fileposn;     /* absolute position of thread in file */
-    long old_eof;
-    char *fn;
-    int ov;
-
-    if (print)  /* this is something of a hack... */
-	if (TNodePtr->THptr->thread_kind != 0x0000) {  /* not a data fork? */
-	    fprintf(stderr, "Can't print non-data fork for '%s'.\n",
-				RNodePtr->filename);
-	    return;  /* this hoses the file posn... */
-	} else {
-	    if (verbose) printf("\n*****  %s  *****\n", RNodePtr->filename);
-	    fflush(stdout);
-	    ov = verbose;
-	    verbose = FALSE;  /* turn off "unshrinking..." messages */
-	    fileposn = TNodePtr->fileposn;
-	    ExtractThread(arcfd,fileposn, "stdout", TNodePtr->THptr);
-	    verbose = ov;
-	    return;
-	}
-
-    switch (TNodePtr->THptr->thread_kind) {
-    case 0x0000:  /* data fork */
-	if (verbose) {
-	    printf("Extracting '%s' (data)...", RNodePtr->filename);
-	    fflush(stdout);
-	}
-
-	/* create any needed subdirs */
-	fn = CreatePath(RNodePtr->filename, RNodePtr->RHptr->file_sys_info);
-
-	/* extract the file */
-	if (ExtractThread(arcfd, TNodePtr->fileposn, fn, TNodePtr->THptr)) {
-	    SetFInfo(fn, RNodePtr->RHptr);  /* set file attributes, dates... */
-	    if (verbose) printf("done.\n");
-	}
-	break;
-
-    case 0x0001:  /* disk image */
-/*	printf("Found disk image (not extracted)\n");*/
-
-	if (verbose) {
-	    printf("Extracting '%s' (disk image)...", RNodePtr->filename);
-	    fflush(stdout);
-	}
-
-	/* setup path (normalize file name) */
-	fn = CreatePath(RNodePtr->filename, RNodePtr->RHptr->file_sys_info);
-
-	/* thread_eof is invalid for disks, so figure it out */
-	old_eof = TNodePtr->THptr->thread_eof;
-	if (RNodePtr->RHptr->storage_type <= 3) {	/* should be block */
-	    TNodePtr->THptr->thread_eof =		/* size, but shk301 */
-		RNodePtr->RHptr->extra_type * 512;	/* stored it wrong */
-	} else {
-	    TNodePtr->THptr->thread_eof =
-		RNodePtr->RHptr->extra_type * RNodePtr->RHptr->storage_type;
-	}
-
-	/* extract the disk into a file */
-	if (ExtractThread(arcfd, TNodePtr->fileposn, fn, TNodePtr->THptr)) {
-	    /*SetFInfo(fn, RNodePtr->RHptr);/* set file attributes, dates... */
-	    if (verbose) printf("done.\n");
-	}
-
-	TNodePtr->THptr->thread_eof = old_eof;
-	break;
-
-    case 0x0002:  /* resource_fork */
-	printf("Found resource_fork (not extracted)\n");
-	break;
-    default:
-	printf("Found unknown data_thread %.4x in '%s'\n",
-	    TNodePtr->THptr->thread_kind, RNodePtr->filename);
-	break;
-    }
-}
-
-
-/*
- * Extract files from archive
- *
- * Scan archive, extracting files which start with the strings in "names".
- * Calls subroutines to handle the various thread_class types.
- */
-static void Extract(filename, namecount, names)
-char *filename;
-int namecount;
-char **names;
-{
-    ListHdr *archive;
-    int arcfd;	/* archive file descriptor */
-    int rec, idx;
-    MHblock *MHptr;   /* Master Header block */
-    RNode *RNodePtr;  /* Record Node */
-    TNode *TNodePtr;   /* Thread block */
-    int len, *lentab;  /* hold strlen() of all names */
-    char *pn;  /* archived pathname */
-    int thread;  /* current thread #; max 65535 threads */
-    BOOLEAN gotone = FALSE;
-    static char *procName = "Extract";
-
-    archive = NuRead(filename);
-    if ((arcfd = open(archive->arc_name, O_RDONLY | O_BINARY)) < 0)
-	Fatal("Unable to open archive", procName);
-
-    pakbuf = (onebyt *) Malloc(PAKBUFSIZ);  /* allocate unpack buffer */
-
-    lentab = (int *) Malloc( sizeof(int) * namecount ); /* calloc() is nicer */
-    for (idx = 0; idx < namecount; idx++)  /* calc. once (for efficiency) */
-	lentab[idx] = strlen(names[idx]);
-
-    MHptr = archive->MHptr;
-    RNodePtr = archive->RNodePtr;
-
-    if (!namecount)
-	extall = TRUE;
-
-    /* main record read loop */
-    for (rec = 0; rec < MHptr->total_records; rec++) {
-	pn = RNodePtr->filename;
-	len = strlen(pn);
-	if (RNodePtr->RHptr->version_number > MAXVERS) {
-	    printf("Unable to extract '%s': unknown record version_number\n",
-		    pn);
-	    continue;  /* with for */
-	}
-
-	for (idx = 0; extall || idx < namecount; idx++) { /* find arced file */
-	    /* try to match argument with first few chars of stored filename */
-	    /* or the entire filename, depending on EXPAND flag */
-	    if (extall || ((len >= lentab[idx]) && doExpand ?
-			(!strncasecmp(pn, names[idx], lentab[idx])) :
-			(!strcasecmp(pn, names[idx])) )) {
-
-		gotone = TRUE;
-		/* go through all threads */
-		TNodePtr = RNodePtr->TNodePtr;
-		for (thread = 0; thread < (int) RNodePtr->RHptr->total_threads;
-								   thread++) {
-		    switch(TNodePtr->THptr->thread_class) {
-		    case 0x0000:
-			message_thread(arcfd, RNodePtr, TNodePtr);
-			break;
-		    case 0x0001:
-			control_thread(arcfd, RNodePtr, TNodePtr);
-			break;
-		    case 0x0002:
-			/* don't extract if doMessages is set */
-			if (!doMessages)
-			    data_thread(arcfd, RNodePtr, TNodePtr);
-			break;
-		    case 0x0003:
-			/* filename_thread; ignore */
-			break;
-		    default:
-			printf("Unknown thread_class %.4x for '%s'\n",
-			    TNodePtr->THptr->thread_class, RNodePtr->filename);
-			break;
-		    }
-		    TNodePtr = TNodePtr->TNext;
-		}
-		break;	/* out of filename matching (inner) FOR loop */
-	    }
-	}
-
-	RNodePtr = RNodePtr->RNext;  /* move on to next record */
-    }
-    if (!gotone && verbose)
-	printf("None selected\n");
-    if (close(arcfd) < 0)
-	Fatal("Source (archive) close failed", procName);
-
-}
-
-/*
- * Entry point to extract routines.
- */
-void NuExtract(filename, namecount, names, options)
-char *filename;
-int namecount;
-char **names;
-char *options;
-{
-    static char *procName = "NuExtract";
-
-    if (*options == 'p') {  /* printing rather then extracting to file */
-	print = TRUE;
-	dopack = TRUE;  /* no extract uncompressed! */
-    } else print = FALSE;
-
-    Extract(filename, namecount, names);  /* do stuff */
-}
-
+ END OF ARCHIVE