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


=nupdel.c
-/*
- * nudel.c - operations which delete from a NuFX archive
- * nuupd.c - update/freshen 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>
-#ifdef BSD43
-# include <strings.h>
-#else  /* SYSV, APW, MSC */
-# include <string.h>
-#endif
-
-#ifdef UNIX
-# include <errno.h>
-#endif
-#ifdef APW
-# include <types.h>
-# include <prodos.h> /* ? */
-# include <shell.h>
-# include <strings.h>  /* APW string ops */
-#endif
-#ifdef MSDOS
-# include <io.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <errno.h>
-#endif
-
-#include "nuread.h"
-#include "nuadd.h"  /* AddFile(), etc. */
-#include "nupak.h"  /* uses PAKBUFSIZ */
-#include "nupdel.h"
-#include "nuetc.h"
-
-static BOOLEAN dofreshen;  /* do freshen instead of update? */
-
-/* delete routines */
-
-/*
- * Rebuild an archive, excluding files marked as deleted.
- * Does not use absolute position values; just seeks along.  The archive
- * should be seeked just beyond the master header block.
- */
-static void RebuildArchive(arcfd, archive, tmpname, remaining)
-int arcfd;
-ListHdr *archive;
-char *tmpname;
-long remaining;
-{
-    int dstfd;	/* destination filename */
-    onebyt *mptr;
-    RNode *RNodePtr;
-    TNode *TNodePtr;
-    int rec, thread;
-    long size;
-    long master_eof;
-#ifdef APW
-    FileRec create_p;
-#endif
-    static char *procName = "RebuildArchive";
-
-    if (verbose) { printf("Building new archive file...");  fflush(stdout); }
-
-    ArcfiCreate(tmpname);	/* create file */
-    master_eof = (long) MHsize;
-
-    if ((dstfd = open(tmpname, O_WRONLY | O_TRUNC | O_BINARY, WPERMS)) < 0)
-	Fatal("Unable to open dest file", procName);
-    if (lseek(dstfd, (long) MHsize, S_ABS) < 0)
-	Fatal("Unable to lseek past dest mhblock", procName);
-
-    RNodePtr = archive->RNodePtr;
-
-    /* copy the surviving records to the destination file */
-    for (rec = 0; rec < archive->MHptr->total_records; rec++) {
-#ifdef APW
-	if (STOP()) { printf("aborting.\n"); Quit(1); }
-#endif
-	size = (long) RNodePtr->RHptr->attrib_count;
-	size += (long) RNodePtr->filename_length;
-	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);
-	    }
-	    size += (long) THsize;
-	    size += TNodePtr->THptr->comp_thread_eof;
-	    TNodePtr = TNodePtr->TNext;
-	}
-
-	if (!RNodePtr->filename[0]) {
-	    if (lseek(arcfd, size, S_REL) < 0)
-		Fatal("Unable to seek past deleted record", procName);
-	} else {
-	    FCopy(arcfd, dstfd, size, pakbuf, FALSE);
-	    master_eof += size;
-	}
-
-	RNodePtr = RNodePtr->RNext;  /* move on to next record */
-    }
-
-    mptr = MakeMHblock(archive, remaining, master_eof);  /* build mheader */
-    if (lseek(dstfd, 0L, S_ABS) < 0)
-	Fatal("Unable to seek back in dest file", procName);
-    if (write(dstfd, mptr, MHsize) < MHsize)
-	Fatal("Unable to write master header", procName);
-
-    if (close(dstfd) < 0)
-	Fatal("Unable to close archive", procName);
-    if (verbose) printf("done.\n");
-}
-
-
-/*
- * Delete files from archive
- *
- * Scan archive, deleting files which match the strings in "names".
- */
-static void Delete(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 */
-    int len, *lentab;  /* hold strlen() of all names */
-    char *pn;  /* archived pathname */
-    long remaining;
-    char *tmpname = (char *) Malloc(MAXFILENAME);
-    static char *procName = "Delete";
-
-    archive = NuRead(filename);
-    if ((arcfd = open(archive->arc_name, O_RDONLY | O_BINARY)) < 0)
-	Fatal("Unable to open archive", procName);
-
-    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;
-    remaining = MHptr->total_records;
-
-    /* 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("WARNING: '%s' has unknown record version_number\n", pn);
-
-	for (idx = 0; idx < namecount; idx++) {  /* find file in archive */
-	    /* try to match argument with first few chars of stored filename */
-	    /* or the entire filename, depending on EXPAND flag */
-	    if ((len >= lentab[idx]) && doExpand ?
-			(!strncasecmp(pn, names[idx], lentab[idx])) :
-			(!strcasecmp(pn, names[idx])) ) {
-
-		if (verbose) printf("Marking '%s' as deleted.\n", pn);
-		RNodePtr->filename[0] = '\0';  /* mark as deleted */
-		remaining--;
-		break;	/* out of filename matching for-loop */
-	    }
-	}
-
-	RNodePtr = RNodePtr->RNext;  /* move on to next record */
-    }
-
-    if (remaining == MHptr->total_records) {
-	if (verbose) printf("No files selected; archive not modified\n");
-	if (close(arcfd) < 0)
-	    Fatal("Source (archive) close failed", procName);
-	Quit (0);
-    }
-    if (remaining == 0L) {
-	printf("All files in archive marked for deletion...");	fflush(stdout);
-	if (close(arcfd) < 0)
-	    Fatal("Source (archive) close failed", procName);
-#ifdef APW
-	if (STOP()) { printf("aborting.\n"); Quit (1); }
-#endif
-	printf(" deleteing archive file.\n");
-
-	if (unlink(archive->arc_name) < 0)
-	    Fatal("Unable to delete archive", procName);
-    } else {
-	tmpname = MakeTemp(tmpname);
-#ifdef APW
-	if (STOP()) { printf("aborting.\n"); Quit (1); }
-#endif
-	if (lseek(arcfd, (long) MHsize, S_ABS) < 0)
-	    Fatal("Unable to seek past master block", procName);
-	RebuildArchive(arcfd, archive, tmpname, remaining);
-
-	if (close(arcfd) < 0)
-	    Fatal("Source (archive) close failed", procName);
-	if (verbose) {
-	    printf("Deleteing old archive file...");
-	    fflush(stdout);
-	}
-	if (unlink(archive->arc_name) < 0)
-	    Fatal("Unable to delete original archive", procName);
-	Rename(tmpname, archive->arc_name);
-	if (verbose) printf("done.\n");
-
-    }
-    free (tmpname);
-    free (lentab);
-}
-
-
-/*
- * Entry point for deleteing files from archive.
- */
-void NuDelete(filename, namecount, names, options)
-char *filename;
-int namecount;
-char **names;
-char *options;
-{
-    static char *procName = "NuDelete";
-
-    /* presently does nothing */
-
-    Delete(filename, namecount, names);
-}
-
-
-/**********  update routines  **********/
-
-/*
- * Updates the archive.
- *
- * Evaluate the command line arguments and compare them with the files in
- * the archive.  Put the most recent copy of the file in a new archive file.
- * Essentially a combination of add and delete.
- *
- * This procedure is huge.  Someday I may clean this up a bit...
- */
-static void Update(archive, namecount, names)
-ListHdr *archive;
-int namecount;
-char **names;
-{
-    int arcfd, dstfd;  /* archive file descriptor */
-    static file_info *FIArray[MAXARGS];  /* entries malloc()ed by EvalArgs */
-    unsigned int rec;
-    int idx, thread;
-    MHblock *MHptr;   /* Master Header block */
-    RNode *RNodePtr;  /* Record Node */
-    TNode *TNodePtr;   /* Thread block */
-    char *pn;  /* archived pathname */
-    BOOLEAN keeparc, gotone;
-    char *tmpname = (char *) Malloc(MAXFILENAME);
-    Time *atptr, *ftptr;
-    long a_dt, f_dt;
-    long size;
-    fourbyt totalrecs, master_eof;
-    onebyt *mptr;
-    twobyt *twoptr;
-    static char *procName = "Update";
-
-    if ((arcfd = open(archive->arc_name, O_RDONLY | O_BINARY)) < 0)
-	Fatal("Unable to open archive", procName);
-
-    /* expand wildcards/subdirectories, and get info */
-    namecount = EvalArgs(namecount, names, FIArray, TRUE);
-    if (!namecount) {
-	if (verbose) printf("No files selected; archive not modified.\n");
-	Quit (0);
-    }
-
-    /*
-     * For each file in the archive, check for an *exact* match with the
-     * store_names in FIArray (case independent).  If a match is found,
-     * compare the dates, and copy/add the most recent file.  If no match
-     * is found, copy the file.  After all archived files have been processed,
-     * add all remaining files specified on the command line (unless the
-     * F)reshen option is used, in which case this exits).
-     */
-
-    MHptr = archive->MHptr;
-    RNodePtr = archive->RNodePtr;
-    gotone = FALSE;
-
-    /* mark files that will be replaced */
-    for (rec = 0; rec < MHptr->total_records; rec++) {
-#ifdef APW
-	if (STOP()) { printf("aborting.\n"); Quit (1); }
-#endif
-	pn = RNodePtr->filename;
-	if (RNodePtr->RHptr->version_number > MAXVERS)
-	    printf("WARNING: '%s' has unknown record version_number\n", pn);
-
-	for (idx = 0; idx < namecount; idx++) {  /* find file in archive */
-	    /* try to match argument with first few chars of stored filename */
-	    if (!strcasecmp(pn, FIArray[idx]->store_name)) {
-		atptr = &RNodePtr->RHptr->mod_when;
-		ftptr = &FIArray[idx]->mod_dt;
-
-		/* compare month/year [ I think it's best-case faster... ] */
-		a_dt = (atptr->year * 12) + atptr->month;
-		f_dt = (ftptr->year * 12) + ftptr->month;
-		if (a_dt > f_dt)	/* archive is more recent? */
-		    keeparc = TRUE;
-		else if (a_dt < f_dt)	/* file is more recent? */
-		    keeparc = FALSE;
-		else {	/* year & month match, check rest */
-		    a_dt = (atptr->day * 86400L) + (atptr->hour * 3600) +
-			   (atptr->minute * 60) + (atptr->second);
-		    f_dt = (ftptr->day * 86400L) + (ftptr->hour * 3600) +
-			   (ftptr->minute * 60) + (ftptr->second);
-		    if (a_dt < f_dt)
-			keeparc = FALSE;
-		    else  /* (a_dt >= f_dt) */
-			keeparc = TRUE;
-		}
-
-		if (!keeparc) {  /* not keeping; mark as being replaced */
-#ifndef APW  /* APW uses actual filetype; other systems keep old */
-		    FIArray[idx]->fileType = RNodePtr->RHptr->file_type;
-		    FIArray[idx]->auxType = RNodePtr->RHptr->extra_type;
-#endif
-		    RNodePtr->RHptr->version_number = 65535; /*can't do fname*/
-		    twoptr = (twobyt *) RNodePtr->filename;
-		    *twoptr = idx;  /* null filename -> problems */
-		    gotone = TRUE;
-		}
-		FIArray[idx]->marked = TRUE;  /* MARK as processed */
-	    }
-	}
-
-	RNodePtr = RNodePtr->RNext;  /* move on to next record */
-    }
-
-    totalrecs = MHptr->total_records;  /* none will be deleted */
-    if (!dofreshen) {  /* add new files? */
-	for (idx = 0; idx < namecount; idx++) {  /* handle unmatched args */
-	    if (!FIArray[idx]->marked) {
-		gotone = TRUE;
-		totalrecs++;  /* count new ones too */
-	    }
-	}
-    }
-    if (!gotone) {
-	if (verbose) printf("No files need updating; archive not modified\n");
-	if (close(arcfd) < 0)
-	    Fatal("Source (archive) close failed", procName);
-	Quit (0);
-    }
-
-    /*
-     * Rebuild archive file
-     */
-    if (verbose) printf("Building new archive file...\n");
-    tmpname = MakeTemp(tmpname);
-    ArcfiCreate(tmpname);
-
-    master_eof = (long) MHsize;
-
-    if (lseek(arcfd, (long) MHsize, S_ABS) < 0)
-	Fatal("Bad archive seek", procName);
-
-    if ((dstfd = open(tmpname, O_RDWR | O_TRUNC | O_BINARY)) < 0)
-	Fatal("Unable to open dest file", procName);
-    if (lseek(dstfd, (long) MHsize, S_ABS) < 0)
-	Fatal("Bad dest seek", procName);	/* leave space for later */
-
-    RNodePtr = archive->RNodePtr;
-    for (rec = 0; rec < MHptr->total_records; rec++) {
-	size = (long) RNodePtr->RHptr->attrib_count;
-	size += (long) RNodePtr->filename_length;
-	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);
-	    }
-	    size += (long) THsize;
-	    size += TNodePtr->THptr->comp_thread_eof;
-	    TNodePtr = TNodePtr->TNext;
-	}
-	/* we now know the size; either copy the old or replace with new */
-	if (RNodePtr->RHptr->version_number != 65535) { /* file not replaced */
-/*	    if (verbose) {
- *		printf("Copying '%s'...", RNodePtr->filename);
- *		fflush(stdout);
- *	    }
- */
-	    FCopy(arcfd, dstfd, size, pakbuf, FALSE);
-	    master_eof += (fourbyt) size;
-/*	    if (verbose) printf("done.\n");
- */
-	} else {  /* file replaced; skip orig and add new */
-	    if (lseek(arcfd, size, S_REL) < 0)
-		Fatal("Bad skip seek", procName);
-	    twoptr = (twobyt *) RNodePtr->filename;
-	    idx = *twoptr;
-	    if (verbose) printf("Replacing/");  /* +"Adding 'filename'..." */
-	    master_eof += AddFile(dstfd, FIArray[idx]);
-	}
-
-	RNodePtr = RNodePtr->RNext;  /* move on to next record */
-    }
-
-    if (!dofreshen) {
-	for (idx = 0 ; idx < namecount; idx++) {
-#ifdef APW
-	    if (STOP()) Quit(1);  /* check for OA-. */
-#endif
-	    if (!FIArray[idx]->marked) {
-		master_eof += AddFile(dstfd, FIArray[idx]);
-	    }
-	}
-    }
-
-    /* build master header */
-    mptr = MakeMHblock(archive, totalrecs, master_eof);
-    if (lseek(dstfd, 0L, S_ABS) < 0)
-	Fatal("Bad lseek for master header", procName);
-    if (write(dstfd, mptr, MHsize) < MHsize)
-	Fatal("Unable to write master header", procName);
-
-    if (close(arcfd) < 0)
-	Fatal("Source (old archive) close failed", procName);
-    if (close(dstfd) < 0)
-	Fatal("Destination (new archive) close failed", procName);
-
-    if (verbose) { printf("Deleteing old archive file...");  fflush(stdout); }
-    if (unlink(archive->arc_name) < 0)
-	Fatal("Unable to delete original archive", procName);
-    Rename(tmpname, archive->arc_name);
-    if (verbose) printf("done.\n");
-
-    free (tmpname);
-}
-
-
-/*
- * Update files in archive
- *
- * This part just evaluates the options, sets parms, and calls Update().
- */
-void NuUpdate(filename, namecount, names, options)
-char *filename;
-int namecount;
-char **names;
-char *options;
-{
-    ListHdr *archive;
-    static char *procName = "NuUpdate";
-
-    if (*options == 'f') dofreshen = TRUE;
-    else dofreshen = FALSE;
-
-    /* change T subopt to convert FROM current system TO <subopt> */
-    if (transfrom >= 0) {
-	transto = transfrom;
-	transfrom = -1;
-    }
-
-    archive = NuRead(filename);
-    Update(archive, namecount, names);
-}
-
=nublu.c
-/*
- * nublu.c - operations on Binary II archives
- *
- * NuLib v3.0  February 1991  Freeware (distribute, don't sell)
- * By Andy McFadden (fadden@cory.berkeley.edu)
- */
-#ifdef APW
-segment "Compress"
-#endif
-
-#ifndef NO_BLU                       /***********************************/
-
-#include "nudefs.h"
-#include <stdio.h>
-#include <fcntl.h>
-
-#ifdef UNIX
-# include <errno.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-#ifdef APW
-# include <prodos.h>
-#endif
-#ifdef MSDOS
-# include <stdlib.h>
-# include <io.h>
-# include <string.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#include "nuview.h"  /* file types for BLU */
-#include "nuadd.h"   /* need OptNum() */
-#include "nupak.h"   /* need unpak_SQU */
-#include "nuetc.h"
-
-/* Binary II extraction routines are adapted from:			*/
-/*************************************************************************
- **									**
- **  Name    :	unblu							**
- **  Author  :	Marcel J.E. Mol 					**
- **  Date    :	10/05/88	      (first release)			**
- **  Version :	2.20							**
- **  Files   :	unblu.c 	Main source file			**
- **									**
- **  ------------------------- Revision List -------------------------	**
- **  Ver   Date       Name		     Remarks			**
- **  1.00  10/05/88   Marcel Mol	     Raw copy of a basic program**
- **  2.00  03/06/88   Marcel Mol	     Rewrite after blu info	**
- **					     was send to the net	**
- **  2.10  18/06/88   Marcel Mol	     Added filetype texts	**
- **  2.20  23/09/88   Marcel Mol	     Show mod and creation time **
- **									**
- ************************************************************************/
-
-
-/*char * copyright = "@(#) unblu.c  2.1 18/06/88  (c) M.J.E. Mol";*/
-#define BUFSIZE 128		    /* Blu block length */
-
-/* global variables */
-static char *progname;
-static char *blufile;
-static BOOLEAN extract = FALSE;  /* extract (as opposed to just listing) */
-
-
-/*
- * extract_file -- extract file fname from the archive fd. Fname
- *		   contains filelen bytes.
- *
- * If the first block has the .QQ magic numbers, go ahead and try to
- * unsqueeze it.  Not the best way to go about it, but it works.
- */
-static void extract_file(fd, fname, filelen)
-int fd;
-char *fname;  /* 64 bytes */
-long filelen;
-{
-    int ofd;
-    int n, i;
-    int j, len;
-    onebyt buf[BUFSIZE];
-    long full_len;
-    int offset;
-    static char *procName = "extract_file";
-
-    /*n = */ read(fd, buf, 70);  /* read first few bytes */
-    lseek(fd, -70L, S_REL);  /* back up */
-    if ((buf[0] == 0x76) && (buf[1] == 0xff)) {  /* is it squeezed? */
-	i = 0;				/* get the original file name */
-	while ((fname[i] = buf[4+i]) != '\0')
-	    i++;
-	offset = 5+i;  /* how far into file is end of filename? */
-	if (verbose) { printf("(as %s)...", fname);  fflush(stdout); }
-    }
-
-    len = strlen(fname);
-    for (j = 0; j < len; j++)
-	fname[j] &= 0x7f;	/* clear hi bits */
-
-    if (Exists(fname)) {
-	if (interact) {
-	    if (verbose) printf("file exists, overwite");
-	    else         printf("%s exists, overwite", fname);
-	    if (!AskYesNo()) {  /* return w/o overwriting */
-		full_len = ( (filelen / 128L) +1 ) * 128L;
-		lseek(fd, full_len, S_REL);
-		return;
-	    }
-	}
-	if (verbose) { printf("overwriting..."); fflush(stdout); }
-	if (unlink(fname) < 0)
-	    Fatal("Unable to remove existing file", procName);
-    }
-
-    if ((ofd = open(fname, O_BINARY|O_CREAT|O_WRONLY|O_TRUNC, 0644)) < 0) {
-	Fatal("Can't open destination file", "extract_file");
-    }
-
-    if ((buf[0] == 0x76) && (buf[1] == 0xff)) {  /* is it squeezed? */
-	if (verbose) { printf("unsqueezing...");  fflush(stdout); }
-	full_len = ( (filelen / 128L) +1 ) * 128L;
-	lseek(fd, (long) offset, S_REL);
-	full_len -= offset;  /* send unpak_SQU everything past fname */
-
-	unpak_SQU(fd, ofd, full_len);  /* unsqueeze it */
-
-    } else {  /* extract uncompressed */
-
-	lastseen = '\0';  /* used by crlf() translator */
-	while (filelen > 0L) {
-	    n = read(fd, buf, BUFSIZE);		/* Read 128 bytes */
-	    if (n != BUFSIZE) {
-		fprintf(stderr, "Extract_BNY: %s file size broken\n", blufile);
-		Quit(-1);
-	    }
-	    if (crlf(ofd, buf, (filelen >= BUFSIZE ? BUFSIZE : filelen)) !=
-			(filelen >= BUFSIZE ? BUFSIZE : filelen))
-		Fatal("Bad write", procName);
-	
-	    filelen -= (long) BUFSIZE;
-	}
-    }
-    close(ofd); 			     /* Close destination file */
-}
-
-
-/*
- * print_header -- print global information of the binary II file
- */
-static void print_header(buf)
-onebyt *buf;
-{
-    long disk_blocks;
-
-    disk_blocks = buf[117] + (buf[118]<<8) + (buf[119]<<16) + (buf[120]<<24);
-    printf("Listing %-40.40s  ", blufile);
-    printf("Blocks used: %-5ld", disk_blocks);
-    printf("Files: %d\n", buf[127]+1);
-    printf("\nFilename       Type Blocks   Modified        ");
-    printf("Created           Length  Subtype\n\n");
-}
-
-
-/*
- * want -- return TRUE if name exists in array wantlist,
- *	   else return FALSE
- */
-static BOOLEAN want(name, wantlist)
-char *name;
-char **wantlist;
-{
-    while (*wantlist != NULL) {
-	if (strcasecmp(name, *wantlist++) == NULL)
-	    return (TRUE);
-    }
-    return (FALSE);
-
-}
-
-
-/*
- * process_file -- retrieve or print file information of file given
- *		   in buf
- */
-static void process_file(fd, buf, count, wanted)
-int  fd;
-onebyt *buf;
-int count;
-char **wanted;
-{
-    int ftype, auxtype;
-    int fnamelen;
-    long filelen;
-    char fname[64];
-    char outbuf[16];  /* temp for sprintf */
-    int nblocks, problocks;
-    Time create_dt;
-    Time mod_dt;
-#ifdef APW
-    FileRec frec;
-#endif
-#ifdef UNIX
-    struct stat st;
-#endif
-#ifdef MSDOS
-    struct stat st;
-#endif
-/* +PORT+ */
-/*    int tf;
- *    int dflags;
- */
-    static char *procName = "process_file";
-
-    /* Get file info */
-    ftype =  buf[4];				/* File type */
-    auxtype = (int) buf[5] + ((int)buf[6] << 8);
-    fnamelen =	buf[23];			/* filename */
-    strncpy(fname, &buf[24], fnamelen);
-    fname[fnamelen] = '\0';
-    /* dflags =  buf[125]; 			/* Data flags */
-    /* tf =  buf[127];				/* Number of files to follow */
-    filelen = (long) buf[20] + ((long) buf[21] << 8) +
-	    ((long) buf[22] << 16);	/* calculate file len */
-    nblocks = (filelen + BUFSIZE-1) / BUFSIZE;	/* #of BNY blocks */
-    problocks = buf[8] + ((int) buf[9] << 8);
-
-    mod_dt.second = 0;
-    mod_dt.minute = buf[12] & 0x3f;
-    mod_dt.hour   = buf[13] & 0x1f;
-    mod_dt.day	  = (buf[10] & 0x1f) -1;
-    mod_dt.month  = (((buf[11] & 0x01) << 3) + (buf[10] >> 5)) -1;
-    mod_dt.year   = buf[11] >> 1;
-    mod_dt.weekDay= 0;
-    create_dt.second = 0;
-    create_dt.minute = buf[16] & 0x3f;
-    create_dt.hour   = buf[17] & 0x1f;
-    create_dt.day    = (buf[14] & 0x1f) -1;
-    create_dt.month  = (((buf[15] & 0x01) << 3) + (buf[14] >> 5)) -1;
-    create_dt.year   = buf[15] >> 1;
-    create_dt.weekDay= 0;
-
-    if (!count || want(fname, wanted)) {
-	if (!extract) { /* print file information ONLY */
-	    printf("%-15.15s %-3.3s ", fname, FT[ftype]);
-	    printf("%6d  ", problocks);
-	    printf("%-16.16s ", PrintDate(&mod_dt, TRUE));
-	    printf("%-16.16s ", PrintDate(&create_dt, TRUE));
-	    if (filelen < 0x100L)
-		sprintf(outbuf, "$%.2lx", filelen);
-	    else if (filelen < 0x10000L)
-		sprintf(outbuf, "$%.4lx", filelen);
-	    else sprintf(outbuf, "$%.6lx", filelen);
-	    printf("%7s    ", outbuf);
-	    printf("$%.4x\n", auxtype);
-
-/*	    if (dflags == 0)
- *		printf("stored");
- *	    else {
- *		if (dflags & 128) {
- *		    printf("squeezed");
- *		}
- *		if (dflags & 64) {
- *		    printf("encrypted");
- *		}
- *		if (dflags & 1)
- *		    printf("packed");
- *	    }
- *	    putchar('\n');
- */
-	    if (ftype != 15) {			/* If not a directory */
-		lseek(fd, (long) BUFSIZE*nblocks, S_REL); /*Seek to next file*/
-	    }
-
-	} else {  /* extract is TRUE */
-
-	    if (verbose) { printf("Extracting %s...", fname); fflush(stdout); }
-#ifdef UNIX
-	    if (ftype != 15)
-		extract_file(fd, fname, filelen);  /* note dates etc not set */
-	    else {
-		/* if no directory exists, then make one */
-		if (stat(fname, &st) < 0)
-		    if (errno == ENOENT) {
-			sprintf(tmpNameBuf, "mkdir %s", fname);
-			if (system(tmpNameBuf) != 0)  /* call UNIX mkdir */
-			    Fatal("Unable to create subdir", procName);
-		    } else {
-			Fatal("Unable to create dir", procName);
-		    }
-	    }
-#else
-# ifdef APW
-	    /* create file/directory , with appropriate type/auxtype stuff */
-	    c2pstr(fname);
-	    frec.pathname = fname;
-	    frec.fAccess = 0x00e3;  /* unlocked */
-	    frec.fileType = ftype;
-	    frec.auxType = (unsigned long) auxtype;
-	    frec.storageType = (int) buf[7];
-	    frec.createDate = 0x0000;  /* set later */
-	    frec.createTime = 0x0000;
-
-	    CREATE( &frec );
-	    ToolErrChk();
-	    p2cstr(fname);
-
-	    extract_file(fd, fname, filelen);
-
-	    /* set file attributes */
-	    c2pstr(fname);
-	    frec.fAccess = (word) buf[3];
-	    frec.modDate = (word) buf[10] + ((word)buf[11] << 8);
-	    frec.modTime = (word) buf[12] + ((word)buf[13] << 8);
-	    frec.createDate = (word) buf[14] + ((word)buf[15] << 8);
-	    frec.createTime = (word) buf[16] + ((word)buf[17] << 8);
-	    SET_FILE_INFO( &frec );
-	    ToolErrChk();
-	    p2cstr(fname);
-# else
-	    if (ftype != 15)
-		extract_file(fd, fname, filelen);
-	    else  /* +PORT+ */
-		printf("[ need [other] subdir create for UnBNY ]\n");
-# endif /* APW */
-#endif /* UNIX */
-	    if (verbose) printf("done.\n");
-	}
-    } else if (ftype != 15) {	/* This file not wanted; if not a directory */
-	lseek(fd, (long) BUFSIZE*nblocks, S_REL);       /* Seek to next file */
-    }
-}
-
-
-/*
- * unblu -- process a binary II file fd, and process the filenames
- *	    listed in wanted. If wanted is \0, all files are processed.
- */
-static void unblu(fd, count, wanted)
-int fd;
-int count;
-char **wanted;
-{
-    onebyt buf[BUFSIZE];
-    int  firstblock = 1;	/* First block needs special processing */
-    int  tofollow = 1;		/* Files to follow in the archive */
-    int  n;
-
-    while (tofollow && ((n = read(fd, buf, BUFSIZE)) > 0)) {
-						/* If there is a header block */
-
-	if (n != BUFSIZE) {
-	    fprintf(stderr, "UnBNY: %s file size is broken\n", blufile);
-	    Quit(-1);
-	}
-	if ((buf[0] != 10) || (buf[1] != 71) ||
-	    (buf[2] != 76) || (buf[18] != 2)) {
-	    fprintf(stderr,
-		"UnBNY: %s not a Binary II file or bad record\n", blufile);
-	    Quit(-1);
-	}
-
-	tofollow = buf[127];		/* How many files to follow */
-	if (firstblock && !extract) {
-	    print_header(buf);
-	}
-	firstblock = 0;
-	process_file(fd, buf, count, wanted);	 /* process the file for it */
-
-    }
-    if (firstblock && (n < 0))  /* length < 128 */
-	fprintf(stderr, "UnBNY: Not a Binary II file");
-}
-
-
-/*
- * Main entry point from CShrink
- */
-void NuBNY(filename, argc, argv, options)
-char *filename;
-int argc;
-char **argv;
-char *options;
-{
-    int  bfd;				/* File descriptor for blu file */
-    char *optr;
-
-    /* process X subopt ourselves */
-    if (INDEX(options+1, 'x')) extract = TRUE;
-    else extract = FALSE;
-
-    blufile = filename; 	  /* Make it global */
-    if ((bfd = open(filename, O_RDONLY | O_BINARY)) < 0)
-	Fatal("Unable to open Binary II archive", "NuBNY");
-
-    unblu(bfd, argc, argv);	     /* Process wanted files */
-
-    close(bfd);
-    Quit(0);
-}
-
-#endif /*NO_BLU*/                    /***********************************/
-
=nusq.c
-/*
- * nusq.c - Huffman squeeze/unsqueeze routines
- *	    Based on sq3/usq2 by Don Elton
- *
- * 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 "nuetc.h"
-
-/*
- * usq.c - undo Huffman coding
- * Adapated from code By Marcel J.E. Mol
- *
- * Squeezed file format:
- *     2 bytes MAGIC
- *     2 bytes dummy ???  (maybe CRC or checksum; not checked)
- *     filename ended by \0
- *
- *     2 bytes node count
- *     node count node values, each 2 bytes
- *     squeezed data per byte
- *
- * NuFX SQueezed format includes only the node count, node values, and
- *   the data.  The BLU routines are expected to strip off the MAGIC,
- *   checksum, and filename before calling this.
- */
-
-/*char *copyright = "@(#) usq.c  2.1 18/06/88  (c) M.J.E. Mol";*/
-#define BUFSIZE 128
-#define MAGIC	0xff76		       /* Squeezed file magic */
-#define DLE 0x90		       /* repeat byte flag */
-#define NOHIST 0		       /* no relevant history */
-#define INREP 1 		       /* sending a repeated value */
-#define SPEOF 256		       /* special endfile token */
-#define NUMVALS 257		       /* 256 data values plus SPEOF */
-
-/* global variable declarations */
-char *sfn;			       /* squeezed file name */
-struct nd {			       /* decoding tree */
-    int child[2];		       /* left, right */
-} node[NUMVALS];		       /* use large buffer */
-int state;			       /* repeat unpacking state */
-int bpos;			       /* last bit position read */
-int curin;			       /* last byte value read */
-int numnodes;			       /* number of nodes in decode tree */
-
-static unsigned char fromc;	/* for use in text translation */
-static BOOLEAN trbool;		/* BOOLEAN version of transfrom */
-
-
-/* Get an integer from the input stream */
-static twobyt get_int(f)
-FILE *f;
-{
-    twobyt val;
-
-    val = (twobyt)getc(f);
-    val += (twobyt)getc(f) << 8;
-    return (val);
-}
-
-
-static int getc_usq(f) 		       /* get byte from squeezed file */
-FILE *f;			       /* file containing squeezed data */
-{
-    register short i;		       /* tree index */
-
-    /* follow bit stream in tree to a leaf */
-    for (i=0; (i <= 0x7fff) && (i>=0); )/* work down(up?) from root */
-    {
-	 if (++bpos > 7) {
-	      if ((curin=getc(f)) == EOF)
-		   return(EOF);
-	      bpos = 0;
-
-	      /* move a level deeper in tree */
-	      i = node[i].child[1 & curin];
-	 }
-	 else i = node[i].child[1 & (curin >>= 1)];
-    }
-
-    /* decode fake node index to original data value */
-    i = -(i + 1);
-
-    /* decode special endfile token to normal EOF */
-    return ((i==SPEOF) ? EOF : i);
-}
-
-
-/*  putc-ncr -- decode non-repeat compression.	Bytes are passed one
- *		at a time in coded format, and are written out uncoded.
- *		The data is stored normally, except that runs of more
- *		than two characters are represented as:
- *
- *			 <char> <DLE> <count>
- *
- *		With a special case that a count of zero indicates a DLE
- *		as data, not as a repeat marker.
- */
-static void putc_ncr(c, t)	       /* put NCR coded bytes */
-unsigned char c;		       /* next byte of stream */
-FILE *t;			       /* file to receive data */
-{
-    static int lastc;	      /* last character seen */
-
-    /* if converting line terminators, do so now */
-    if (trbool && (c == fromc))
-#ifdef UNIX
-	c = 0x0a;
-#else
-# ifdef APW
-	c = 0x0d;
-# else
-	c = 0x0d;  /* No CRLF stuff in unSQueeze... sorry */
-# endif
-#endif
-
-    switch (state) {		       /* action depends on our state */
-	case NOHIST:		       /* no previous history */
-	    if (c==DLE) 	       /* if starting a series */
-		 state = INREP;        /* then remember it next time */
-	    else putc(lastc=c, t);     /* else nothing unusual */
-	    return;
-
-	case INREP:		       /* in a repeat */
-	    if (c)		       /* if count is nonzero */
-		while (--c)	       /* then repeatedly ... */
-		    putc(lastc, t);    /* ... output the byte */
-	    else putc(DLE, t);	       /* else output DLE as data */
-	    state = NOHIST;	       /* back to no history */
-	    return;
-
-	default:
-	    fprintf(stderr, "%s: bad NCR unpacking state (%d)",
-				prgName, state);
-    }
-}
-
-
-static int init_usq(f) 		       /* initialize Huffman unsqueezing */
-FILE *f;			       /* file containing squeezed data */
-{
-    register int i;		       /* node index */
-
-    switch (transfrom) {
-    case -1:  /* no translation */
-	trbool = 0;
-	break;
-    case 0:  /* from ProDOS */
-	trbool = 1;
-	fromc = 0x0d;
-	break;
-    case 1:  /* from UNIX */
-	trbool = 1;
-	fromc = 0x0a;
-	break;
-    case 2:  /* from MS-DOS... this needs fixing */
-	trbool = 1;
-	fromc = 0x0a;  /* just turn LFs into whatever... */
-	break;
-    default:  /* unknown */
-	fprintf(stderr, "%s: unknown translation type %d\n", prgName, trbool);
-	fprintf(stderr, "%s: assuming conversion from CR\n", prgName);
-	trbool = 1;  /* should just ignore flag, but other procs do this */
-	fromc = 0x0d;
-	break;
-    }
-
-    bpos = 99;			       /* force initial read */
-    numnodes = get_int(f);	       /* get number of nodes */
-
-    if (numnodes<0 || numnodes>=NUMVALS) {
-	 fprintf(stderr, "%s: usq: archived file has invalid decode tree\n",
-							prgName);
-	 return (-1);
-    }
-
-    /* initialize for possible empty tree (SPEOF only) */
-    node[0].child[0] = -(SPEOF + 1);
-    node[0].child[1] = -(SPEOF + 1);
-
-    for (i=0; i<numnodes; ++i) {	/* get decoding tree from file */
-	 node[i].child[0] = get_int(f);
-	 node[i].child[1] = get_int(f);
-    }
-
-    return (0);
-}
-
-
-/*
- * Unsqueeze a file
- */
-static int unsqueeze(sfp, dfp)
-FILE *sfp, *dfp;
-{
-    register int i;
-    register int c;			/* one char of stream */
-
-    state = NOHIST;		       /* initial repeat unpacking state */
-
-    if (init_usq(sfp))		       /* init unsqueeze algorithm */
-	return 1;
-    while ((c=getc_usq(sfp)) != EOF)   /* and unsqueeze file */
-	 putc_ncr(c, dfp);
-
-    return (0);			       /* file is okay */
-}
-
-
-/*
- * main entrance to unsqueeze
- *
- * We reset the file posn to where it should be according to "length"; note
- * that "length" is not actually used by the unsqueeze routines.  We have
- * do to this because fdopen() sticks about 8K or so in a buffer...
- *
- * Note also that we dup() the file descriptors before starting.  This
- * is so that we can cleanly fclose() the file descriptors when we're done,
- * but still keep the file open.
- */
-void unpak_SQU(srcfd, dstfd, length)
-int srcfd, dstfd;
-long length;  /* #of bytes we're expected to read */
-{
-    FILE *srcfp, *dstfp;		/* File pointers for squ/dest file */
-    int srcfd2, dstfd2;
-    long finalposn;
-    static char *procName = "unpak_SQU";
-
-    finalposn = lseek(srcfd, 0L, S_REL) + length;  /* where we should end up */
-    srcfd2 = dup(srcfd);
-    dstfd2 = dup(dstfd);
-    if ((srcfp = fdopen(srcfd2, FREAD_STR)) == NULL)
-	Fatal("Can't fdopen() archive", procName);
-    if ((dstfp = fdopen(dstfd2, FWRITE_STR)) == NULL)
-	Fatal("Can't fdopen() dest file", procName);
-
-    unsqueeze(srcfp, dstfp);  /* unsqueeze the file */
-    fclose(srcfp);  /* (was fflush) (this isn't really necessary) */
-    fclose(dstfp);  /* (was fflush) This is *very* necessary */
-
-    if (lseek(srcfd, finalposn, S_ABS) < 0)  /* set file posn back */
-	Fatal("Can't reset final posn", procName);
-    /* note that this lets things continue even if unSQueezing failed */
-}
-
=apwerr.h
-/*
- * apwerr.h - text versions of APW and ProDOS 16 error codes
- *   ERROR() didn't cut it, and I'm trying to separate things from the shell.
- *
- * NuLib v3.0  February 1991  Freeware (distribute, don't sell)
- * By Andy McFadden (fadden@cory.berkeley.edu)
- */
-
-/* APW-specific UNIX-like errors */
-
-/*
- [ this is derived from: ]
- errno.h -- error return codes
-
- Copyright American Telephone & Telegraph
- Modified and used with permission, Apple Computer Inc.
- Copyright Apple Computer Inc. 1985, 1986, 1987
- All rights reserved.
-*/
-/* @(#)errno.h 2.1 */
-/* 3.0 SID # 1.3 */
-
-#define sys_nerr 35	   /* err must be < Max APW Err */
-static char *sys_errlist[sys_nerr] = {
-    /* 0  (no err)  */	"[ call successful ]",
-    /* 1  EPERM     */	"permission denied",
-    /* 2  ENOENT    */	"no such file or directory",
-    /* 3  ENORSRC   */	"no such resource",
-    /* 4  EINTR     */	"interrupted system call",
-    /* 5  EIO	    */	"I/O error",
-    /* 6  ENXIO     */	"no such device or address",
-    /* 7  E2BIG     */	"insufficient space for return argument",
-    /* 8  ENOEXEC   */	"exec format error",
-    /* 9  EBADF     */	"bad file number",
-    /* 10 ECHILD    */	"no children",
-    /* 11 EAGAIN    */	"no more processes",
-    /* 12 ENOMEM    */	"not enough memory",
-    /* 13 EACCES    */	"permission denied",
-    /* 14 EFAULT    */	"bad address",
-    /* 15 ENOTBLK   */	"block device required",
-    /* 16 EBUSY     */	"mount device busy",
-    /* 17 EEXIST    */	"file exists",
-    /* 18 EXDEV     */	"cross-device link",
-    /* 19 ENODEV    */	"no such device",
-    /* 20 ENOTDIR   */	"not a directory",
-    /* 21 EISDIR    */	"is a directory",
-    /* 22 EINVAL    */	"invalid argument",
-    /* 23 ENFILE    */	"file table overflow",
-    /* 24 EMFILE    */	"too many open files",
-    /* 25 ENOTTY    */	"not a typewriter (sorry)",
-    /* 26 ETXTBSY   */	"text file busy",
-    /* 27 EFBIG     */	"file too large",
-    /* 28 ENOSPC    */	"no space left on device",
-    /* 29 ESPIPE    */	"illegal seek",
-    /* 30 EROFS     */	"read only file system",
-    /* 31 EMLINK    */	"too many links",
-    /* 32 EPIPE     */	"broken pipe",
-    /* 33 EDOM	    */	"math arg out of domain of func",
-    /* 34 ERANGE    */	"math result not representable"
-};
-
-
-/* ProDOS errors */
-
-/* [ This is derived from: ]
-/********************************************
-; File: ProDos.h
-;
-;
-; Copyright Apple Computer, Inc. 1986, 1987
-; All Rights Reserved
-;
-********************************************/
-
-#define MPErr 0x61	/* err must be < Max ProDOS Err # */
-static char *ProDOSErr[MPErr] = {
-    /* 00 (no error)	    */ "[ ProDOS call successful ]",
-    /* 01 invalidCallNum    */ "invalid call number / (fatal) unclaimed intr",
-    /* 02		    */ "",
-    /* 03		    */ "",
-    /* 04		    */ "(ProDOS 8 invalid parameter count)",
-    /* 05 badPBlockPtr	    */ "call pointer out of bounds",
-    /* 06 pdosActiveErr     */ "ProDOS is active",
-    /* 07 pdosBusyErr	    */ "ProDOS is busy",
-    /* 08		    */ "",
-    /* 09		    */ "",
-    /* 0a vcbUnusable	    */ "(fatal) VCB is unusable",
-    /* 0b fcbUnusable	    */ "(fatal) FCB is unusable",
-    /* 0c badBlockZero	    */ "(fatal) block zero allocated illegally",
-    /* 0d shdwInterruptErr  */ "(fatal) interrupt occurred while I/O shadowing off",
-    /* 0e		    */ "",
-    /* 0f		    */ "",
-    /* 10 devNotFound	    */ "device not found",
-    /* 11 badDevRefNum	    */ "invalid device ref# / (fatal) wrong OS version",
-    /* 12		    */ "",
-    /* 13		    */ "",
-    /* 14		    */ "",
-    /* 15		    */ "",
-    /* 16		    */ "",
-    /* 17		    */ "",
-    /* 18		    */ "",
-    /* 19		    */ "",
-    /* 1a		    */ "",
-    /* 1b		    */ "",
-    /* 1c		    */ "",
-    /* 1d		    */ "",
-    /* 1e		    */ "",
-    /* 1f		    */ "",
-    /* 20 badReqCode	    */ "invalid request code",
-    /* 21		    */ "",
-    /* 22		    */ "",
-    /* 23		    */ "",
-    /* 24		    */ "",
-    /* 25 intTableFull	    */ "interrupt table full",
-    /* 26 invalidOperation  */ "invalid operation",
-    /* 27 ioError	    */ "I/O error",
-    /* 28 noDevConnect	    */ "no device connected",
-    /* 29		    */ "",
-    /* 2a		    */ "",
-    /* 2b writeProtectErr   */ "write protect error",
-    /* 2c		    */ "",
-    /* 2d		    */ "",
-    /* 2e diskSwitchErr     */ "disk switched error",
-    /* 2f		    */ "device not online",
-    /* 30		    */ "device-specific err $30",
-    /* 31		    */ "device-specific err $31",
-    /* 32		    */ "device-specific err $32",
-    /* 33		    */ "device-specific err $33",
-    /* 34		    */ "device-specific err $34",
-    /* 35		    */ "device-specific err $35",
-    /* 36		    */ "device-specific err $36",
-    /* 37		    */ "device-specific err $37",
-    /* 38		    */ "device-specific err $38",
-    /* 39		    */ "device-specific err $39",
-    /* 3a		    */ "device-specific err $3a",
-    /* 3b		    */ "device-specific err $3b",
-    /* 3c		    */ "device-specific err $3c",
-    /* 3d		    */ "device-specific err $3d",
-    /* 3e		    */ "device-specific err $3e",
-    /* 3f		    */ "device-specific err $3f",
-    /* 40 badPathName	    */ "invalid pathname syntax",
-    /* 41		    */ "",
-    /* 42 fcbFullErr	    */ "FCB full error (too many files open)",
-    /* 43 badFileRefNum     */ "invalid file reference number",
-    /* 44 pathNotFound	    */ "path not found",
-    /* 45 volumeNotFound    */ "volume not found",
-    /* 46 fileNotFound	    */ "file not found",
-    /* 47 dupFileName	    */ "duplicate file name",
-    /* 48 volumeFullErr     */ "volume full error",
-    /* 49 dirFullErr	    */ "directory full error",
-    /* 4a versionErr	    */ "version error (incompatible file format)",
-    /* 4b badStoreType	    */ "unsupported (or incorrect) storage type",
-    /* 4c eofEncountered    */ "end-of-file encountered",
-    /* 4d positionRangeErr  */ "position out of range",
-    /* 4e accessErr	    */ "access not allowed",
-    /* 4f		    */ "",
-    /* 50 fileOpenErr	    */ "file already open",
-    /* 51 dirDamaged	    */ "directory structure is damaged (file count?)",
-    /* 52 badVolType	    */ "unsupported volume type",
-    /* 53 paramRangeErr     */ "parameter out of range",
-    /* 54 memoryFullErr     */ "out of memory",
-    /* 55 vcbFullErr	    */ "VCB full error",
-    /* 56		    */ "(ProDOS 8 bad buffer address)",
-    /* 57 dupVolumeErr	    */ "duplicate volume error",
-    /* 58 notBlkDevErr	    */ "not a block device",
-    /* 59 invalidLevel	    */ "invalid level",
-
-    /* 5a		    */ "block number out of range (bad vol bitmap?)",
-    /* 5b		    */ "illegal pathname change",
-    /* 5c		    */ "not an executable file",
-    /* 5d		    */ "file system not available",
-    /* 5e		    */ "cannot deallocate /RAM",
-    /* 5f		    */ "return stack overflow",
-    /* 60		    */ "data unavailable"
-};
+ END OF ARCHIVE