[comp.binaries.apple2] C NuFX viewer v1.1

fadden@cory.Berkeley.EDU (Andy McFadden) (05/20/89)

Well, I had a little run-in with a VAX.  After some major bug battles, I
finally got it to run correctly.

(incidentally, VAXen do NOT use the HILO byte ordering; if you are running
on a VAX, comment out or delete the define in "nuread.h")

Things have been drastically re-arranged or totally re-written for speed
and portability.  I now use fseek to seek though archives faster, but
left the old seek routine in since I'm not sure how portable fseek is
(it isn't in any of the include files...).

The file position of the threads is now stored in the records, so anybody
who wants to write an extractor can just use that value as an argument
to Seek().

At any rate, this has now been tested on three different machines (a Sun,
the aforementioned VAX, and something completely different...).  I would
appreciate hearing from anybody who got it to work under APW (or any
other system for that matter!)  This, combined with "sciibin", should
allow a reasonable degree of manipulation of comp.binaries.apple2 postings
before they are downloaded.

-- 
fadden@cory.berkeley.edu (Andy McFadden)
...!ucbvax!cory!fadden
labc-3dc@widow.berkeley.edu

------------------------- cut here --------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	nuview.doc
#	Makefile
#	nuread.c
#	nuview.c
#	nuread.h
#	nustr.h
#	nuview.h
# This archive created: Sat May 20 04:31:09 1989
# By:	Andy McFadden ()
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'nuview.doc'" '(3145 characters)'
if test -f 'nuview.doc'
then
	echo shar: "will not over-write existing file 'nuview.doc'"
else
cat << \!Funky!Stuff! > 'nuview.doc'
Remarks about NuFX archive viewer
Version 1.1  May 1989

First and foremost:
This program is totally in the public domain.  I reserve no rights to
the program; do with it what you will.  If you make lots of money by
modifying and selling my code, great.  Stick my name in a comment somewhere
and I'll be more than happy.

This being the case, I also give up any responsibility to update and maintain
this program.

***** Revision history:

vers 1.1 - Did major rewrite of the way data is read in.  Used to just read
	into a buffer and pick parts out of it by applying a struct directly;
	now read into a special buffer and copy individual entries into a
	struct.  Cleaned up code a bit.  Used fseek instead of xx getc() calls.
	Added code to hold the position in file of all threads.  Fixed bug
	with non-(void) sprintf.

vers 1.0 - Initial release.

***** Program description:

In its present state, it will either produce a ShrinkIt-like listing (the
default), or a detailed breakdown of every known facet of the archive (run
it with the -l option).

When ShrinkIt packs a file, it always uses records with one thread (of type
data_thread).  I have tried to make the code flexible, but since I can't
generate proper archives with multiple threads and resource forks, I can't
honestly say that it will work when presented with such an archive.

I have tried to make this easy to extend for new advances.  While the
option parsing remains somewhat primitive, the program should be fairly solid.
The program uses fseek to do file positioning; I'm not sure how portable this
is (it doesn't appear in stdio.h for some reason, although ftell does...),
so I left in the getc() seek code (just define LAMESEEK at compile time).

***** System dependencies:

When compiling this on a Sun 3/50, I noticed something unfortunate: the byte
ordering for the //gs and the Sun are backward.  The header file "nufx.h"
currently contains a definition of "HILO"; when this is defined, the code
generated while reverse the byte ordering automatically.  You should clear
this if you start getting really weird results from valid archives (or if
you are sure that your machine works in LO->HI byte order).

There are definitions for one byte, two byte, and four byte variable types;
my compiler uses char, short, and int.  If these are different for your
compiler, be sure to change the typedefs.  These also appear in "nufx.h".

As mentioned above, define LAMESEEK (on the command line or in "nuread.h")
if fseek is undefined on your system.

***** Bugs / glitches:

CRCs are difficult to compute with the byte ordering reversed.  Hmm...

UNIX seek uses longs, which are usually four bytes.  Signed.  If an archive
is larger than 2 gigabytes, there may be a problem.

***** Final notes:

Although I added in the thread file position holder, I don't plan to
write a file extractor (the extraction is easy; the decompression is the
part I don't want to deal with).

If nothing else, this will allow you to check the output of sciibin before
you actually download the files.

Good luck...

					- Andy

fadden@cory.berkeley.edu (Andy McFadden)
...!ucbvax!cory!fadden

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'Makefile'" '(234 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
# Makefile for NuView
# Public Domain - fadden@cory.berkeley.edu (Andy McFadden)
# Version 1.1  May 1989
#
CFLAGS=
LIBS=
CC=cc

nuview: nuread.o nuview.o nuview.h nuread.h nustr.h
	$(CC) $(CFLAGS) nuread.o nuview.o -o nuview $(LIBS)

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'nuread.c'" '(6663 characters)'
if test -f 'nuread.c'
then
	echo shar: "will not over-write existing file 'nuread.c'"
else
cat << \!Funky!Stuff! > 'nuread.c'
/*
 * nuread.c - read NuFX archives (header info only) into structures
 *
 * Public domain - fadden@cory.berkeley.edu (Andy McFadden)
 * version 1.1  May 1989
 */

#include <stdio.h>
#include "nuview.h"
#include "nuread.h"

#define TRUE 1
#define FALSE 0

typedef int BOOLEAN;


/* swap two bytes */
void Swap(ptr, a, b)
onebyt *ptr;
register onebyt a, b;
{
    register onebyt tmp;

    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) {
#ifdef HILO
	while (i--) {  /* copy & reverse */
	    *(destptr+i) = *(srcptr + num - i);  /* dest+3 = src + 3 - 3 .. */
	}
#else
	while (i--) {  /* copy only */
	    *(destptr+i) = *(srcptr + i);
	}
#endif HILO
    } else {
	while (i--) {  /* byte ordering not important; just copy */
	    *(destptr+i) = *(srcptr+i);
	}
    }
}

#ifdef LAMESEEK
/* seek forward in a FILE in a somewhat lame (but portable) manner */
void Seek(fi, dist)
FILE *fi;
long dist;
{
    long i;

    while ((dist-- > 0L) && (getc(fi) >= 0))
        ;
    if (dist == 0L) return;
    perror("Seek");
    exit (-1);
}

#else
/* seek forward quickly */
void Seek(fi, dist)
FILE *fi;
long dist;
{
    if (fseek(fi, dist, 1 /*incr*/) < 0) {
	perror("Seek");
	exit (-1);
    }
}
#endif LAMESEEK


/*
 * Read thread header data, and skip data fields
 */

TNode *ReadThreads(fi, RHptr, tu_ptr, tc_ptr)
FILE *fi;
RHblock *RHptr;
unsigned int *tu_ptr;  /* pointer to int holding len of uncomp. threads */
unsigned int *tc_ptr;  /* same for sum of comp_thread_eof */
{
    int i, size;
    BOOLEAN first;
    TNode *TNodePtr, *THeadPtr = (TNode *) NULL;
    THblock *THptr;
    char filebuf[THsize];

    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;
	size = fread(filebuf, 1, THsize, fi);  /* should be 16 */
	if (size < THsize) {
	    perror("ReadThread (THblock)");
	    exit (-1);
	}

	/* copy all fields... */
	BCopy(filebuf+0, &THptr->thread_class, 2, TRUE);
	BCopy(filebuf+2, &THptr->thread_format, 2, TRUE);
	BCopy(filebuf+4, &THptr->thread_kind, 2, TRUE);
	BCopy(filebuf+6, &THptr->reserved, 2, TRUE);
	BCopy(filebuf+8, &THptr->thread_eof, 4, TRUE);
	BCopy(filebuf+12, &THptr->comp_thread_eof, 4, TRUE);

	/* update pointers and skip the actual data */
	*tu_ptr += THptr->thread_eof;
	*tc_ptr += THptr->comp_thread_eof;
	TNodePtr->fileposn = ftell(fi);
	Seek(fi, (long) THptr->comp_thread_eof);
    }
    return (THeadPtr);
}


/*
 * Read header data from a NuFX archive into memory
 */

ListHdr *NuRead(filename)
char *filename;
{
    FILE *fi;
    char namebuf[MAXFILENAME];
    int size, i;
    BOOLEAN first;
    twobyt namelen;
    ListHdr *ListPtr;  /* List Header struct */
    MHblock *MHptr;  /* Master Header block */
    RNode *RNodePtr;  /* Record Node */
    RHblock *RHptr;  /* Record Header block */
    onebyt filebuf[RHsize+1];  /* RHsize > MHsize */

    ListPtr = (ListHdr *) malloc(sizeof(ListHdr));  /* create head of list */
    ListPtr->MHptr = (MHblock *) malloc(sizeof(MHblock));  /* master block */

    if ((fi = fopen(filename, "r")) == (FILE *) NULL) {
	fprintf(stderr, "Unable to open archive\n");
	perror("NuRead");
	exit (-1);
    }

    /* create and read the master header block */
    MHptr = ListPtr->MHptr;
    size = fread(filebuf, 1, MHsize, fi);
    if (size < MHsize) {
	perror("NuRead (MHblock)");
	exit (-1);
    }

    BCopy(filebuf+0, MHptr->ID, 6, FALSE);
    BCopy(filebuf+6, &MHptr->master_crc, 2, TRUE);
    BCopy(filebuf+8, &MHptr->total_records, 4, TRUE);
    BCopy(filebuf+12, &MHptr->arc_create_when, 8, FALSE);  /* buggy */
    BCopy(filebuf+20, &MHptr->arc_mod_when, 8, FALSE);
    BCopy(filebuf+28, MHptr->reserved, 20, FALSE);

    if (strncmp(MHptr->ID, MasterID, 6)) {
	fprintf(stderr, "File '%s' is not a NuFX archive\n", filename);
	exit (-1);
    }

    /* main record read loop */
    first = TRUE;
    for (i = 0; i < MHptr->total_records; i++) {
	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 */
	RHptr = RNodePtr->RHptr;
	size = fread(filebuf, 1, RHsize, fi);  /* get known stuff */
	if (size < RHsize) {
	    perror("NuRead (RHblock)");
	    exit (-1);
	}
	BCopy(filebuf+0, RHptr->ID, 4, FALSE);
	BCopy(filebuf+4, &RHptr->header_crc, 2, TRUE);
	BCopy(filebuf+6, &RHptr->attrib_count, 2, TRUE);
	BCopy(filebuf+8, &RHptr->version_number, 2, TRUE);
	BCopy(filebuf+10, &RHptr->total_threads, 4, TRUE);
	BCopy(filebuf+14, &RHptr->file_sys_id, 2, TRUE);
	BCopy(filebuf+16, &RHptr->file_sys_info, 2, TRUE);
	BCopy(filebuf+18, &RHptr->access, 4, TRUE);
	BCopy(filebuf+22, &RHptr->file_type, 4, TRUE);
	BCopy(filebuf+26, &RHptr->extra_type, 4, TRUE);
	BCopy(filebuf+30, &RHptr->storage_type, 2, TRUE);
	BCopy(filebuf+32, &RHptr->create_when, 8, FALSE);
	BCopy(filebuf+40, &RHptr->mod_when, 8, FALSE);
	BCopy(filebuf+48, &RHptr->archive_when, 8, FALSE);

	/* seek past remaining (unknown) attributes to filename length field */
	Seek(fi, (long) RHptr->attrib_count - RHsize - 2);


	size = fread(&namelen, 1, 2, fi);  /* read filename len */
	if (size < 2) {
	    perror("NuRead (namelen)");
	    exit (-1);
	}
#ifdef HILO
	Swap(&namelen, 0, 1);
#endif HILO
	/* read filename, and store in struct */
	size = fread(namebuf, 1, namelen, fi);
	if (size < namelen) {
	    perror("NuRead (namebuf)");
	    exit (-1);
	}
	RNodePtr->filename = (char *) malloc(namelen+1);
	BCopy(namebuf, RNodePtr->filename, namelen, FALSE);  /* store fname */
	RNodePtr->filename[namelen] = '\0';

	RNodePtr->TNodePtr = ReadThreads(fi, RHptr, &RNodePtr->unc_len,
		&RNodePtr->comp_len);
    }

    if (fclose(fi) != 0) {
	perror("NuRead (close)");
	exit (-1);
    }
    return (ListPtr);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'nuview.c'" '(8634 characters)'
if test -f 'nuview.c'
then
	echo shar: "will not over-write existing file 'nuview.c'"
else
cat << \!Funky!Stuff! > 'nuview.c'
/*
 * nuview.c - prints the contents of a NuFX archive
 *
 * Public domain - fadden@cory.berkeley.edu (Andy McFadden)
 * version 1.1  May 1989
 */

#include <stdio.h>
#include <strings.h>
#include "nuview.h"
#include "nuread.h"
#include "nustr.h"

typedef int BOOLEAN;
#define TRUE	1
#define FALSE	0


/*
 * Usage:  nuview -v			print version number
 *	   nuview archive-name		print archive like ShrinkIt would
 *	   nuview -l archive-name	print full archive info
 */
void Usage(argv0)
char *argv0;
{
    printf("Usage: %s [-v | -l] archive-name\n", argv0);
}


/* print date from Time structure */
char *PrintDate(tptr, brief)
Time *tptr;
BOOLEAN brief;
{
    static char buf[64], buf2[64];

    /* check for validity */
    if ( (tptr->day > 31) || (tptr->month > 11) || (tptr->hour > 24) ||
	(tptr->minute > 59) ) {
	strcpy(buf, "   <invalid>   ");
	return (buf);
    }

    /* only print weekDay if one was stored and if we're in longout mode */
    if (!brief && tptr->weekDay) {
	(void) sprintf(buf, "%s, ", WD[tptr->weekDay]);
    } else {
	buf[0] = '\0';
    }
    (void) sprintf(buf2, "%.2d-%s-%.2d %.2d:%.2d",
	tptr->day, MO[tptr->month], tptr->year,
	tptr->hour, tptr->minute);
    (void) strcat(buf, buf2);
    if (!brief) {  /* add seconds to long output */
	(void) sprintf(buf2, ":%.2d", tptr->second);
	(void) strcat(buf, buf2);
    }
    return (buf);
}


/* Dump contents of the threads */
DumpThreads(RNodePtr)
RNode *RNodePtr;
{
    int i;
    int count = RNodePtr->RHptr->total_threads;
    static char ind[4] = "   ";  /* indentation */
    THblock *THptr;
    TNode *TNodePtr;

    /* go through all threads, printing as we go */
    TNodePtr = RNodePtr->TNodePtr;
    for (i = 0; i < count; i++) {
	if (TNodePtr == (TNode *) NULL) {
	    fprintf(stderr, "WARNING: fewer threads than expected\n");
	    return;
	}
	THptr = TNodePtr->THptr;

	printf("%s --> Information for thread %d\n", ind, i);
	printf("%s thread_class: %s\n", ind, THptr->thread_class < TCn ?
		TC[THptr->thread_class] : UNKNOWNSTR);
	printf("%s thread_format: %s\n", ind, THptr->thread_format < TFn ?
		TF[THptr->thread_format] : UNKNOWNSTR);
	printf("%s thread_kind: %s ($%.2X)\n", ind,
		(THptr->thread_kind < TKn && THptr->thread_class < TCn) ?
		TK[THptr->thread_class][THptr->thread_kind] : UNKNOWNSTR,
		THptr->thread_kind);
	printf("%s thread_eof: %u   ", ind, THptr->thread_eof);
	printf("comp_thread_eof: %u\n", THptr->comp_thread_eof);
	printf("%s * position within file: %ld\n", ind, TNodePtr->fileposn);

	TNodePtr = TNodePtr->TNext;
    }
    /* after all info printed, show sum total of thread lengths */
    printf("%s * total thread_eof: %u   ", ind, RNodePtr->unc_len);
    printf("total comp_thread_eof: %u\n", RNodePtr->comp_len);
}


/* Scan contents of the threads for certain things (for ShrinkIt) */
/* returns 65535 as error code (-1 in an unsigned short) */
twobyt ScanThreads(RNodePtr, format)
RNode *RNodePtr;
twobyt *format;
{
    int i;
    int count = RNodePtr->RHptr->total_threads;
    THblock *THptr;
    TNode *TNodePtr;

    *format = 65535;  /* default = error */
    TNodePtr = RNodePtr->TNodePtr;
    for (i = 0; i < count; i++) {
	if (TNodePtr == (TNode *) NULL) {
	    fprintf(stderr, "WARNING: fewer threads than expected\n");
	    return (65535);
	}
	THptr = TNodePtr->THptr;

	if (THptr->thread_class == 2) {  /* data thread? */
	    *format = THptr->thread_format;
	    return (THptr->thread_kind);
	}
    }
    return (65535);  /* no data thread found */
}


/*
 * View archive contents
 *
 * When "longout" is false, the output resembles a ShrinkIt archive listing
 */

void NuView(archive, filename, longout)
ListHdr *archive;
char *filename;
BOOLEAN longout;
{
    MHblock *MHptr = archive->MHptr;
    RHblock *RHptr;
    RNode *RNodePtr;
    static char tmpbuf[64];
    twobyt format, datakind;
    int percent, i;

    if (!longout) {
	(void) sprintf(tmpbuf, "%.15s", filename);
	printf("%-16s ", tmpbuf);
	printf("Created:%s   ", PrintDate(&MHptr->arc_create_when, TRUE));
	printf("Mod:%s     ", PrintDate(&MHptr->arc_mod_when, TRUE));
	printf("Recs:%5u\n\n", MHptr->total_records);
	printf(" Name                  Kind  Typ  Auxtyp Archived");
	printf("        Fmat Size  Un-Length\n");
	printf("-------------------------------------------------");
	printf("----------------------------\n");
    } else {
	printf("Now processing archive '%s'\n", filename);
	printf("---> Master header information:\n");
	printf("master ID: '%.6s'     ", MHptr->ID);
	printf("master_crc: $%.4X\n", MHptr->master_crc);
	printf("total_records: %u\n", MHptr->total_records);
	printf("created: %s   ", PrintDate(&MHptr->arc_create_when, FALSE));
	printf("mod: %s\n", PrintDate(&MHptr->arc_mod_when, FALSE));
    }

    RNodePtr = archive->RNodePtr;
    for (i = 0; i < MHptr->total_records; i++) {
	if (RNodePtr == (RNode *) NULL) {
	    fprintf(stderr, "WARNING: fewer records than expected\n");
	    return;
	}
	RHptr = RNodePtr->RHptr;
	if (!longout) {
	    printf("%c", (RHptr->access == 0xE3 || RHptr->access == 0xC3) ?
		' ' : '+');
	    (void) sprintf(tmpbuf, "%.21s", RNodePtr->filename);
	    printf("%-21s ", tmpbuf);
	    datakind = ScanThreads(RNodePtr, &format);  /* data_thread info */
	    if (datakind == 65535) {  /* no data thread... */
		printf("????  ");
	        printf("%s  ", RHptr->file_type < 256 ? FT[RHptr->file_type] :
			"???");
	        printf("$%.4X  ", RHptr->extra_type);
	    } else if (datakind == 1) {  /* disk */
		printf("Disk  ");
		printf("---  ");
		(void) sprintf(tmpbuf, "%dk", RHptr->extra_type / 2);
		printf("%-5s  ", tmpbuf);
	    } else {  /* must be a file */
		printf("File  ");
	        printf("%s  ", RHptr->file_type < 256 ? FT[RHptr->file_type] :
			"???");
	        printf("$%.4X  ", RHptr->extra_type);
	    }
	    printf("%s  ", PrintDate(&RHptr->archive_when, TRUE));
	    printf("%s  ", format < QTFn ? QTF[format] : "???");
	    /* figure out the percent size, and format it appropriately */
	    if (!RNodePtr->unc_len && !RNodePtr->comp_len) {
		printf("100%%  ");  /* file is 0 bytes long */
	    } else if ((!RNodePtr->unc_len && RNodePtr->comp_len) ||
			(RNodePtr->unc_len && !RNodePtr->comp_len)) {
		printf("????  ");  /* something weird happened */
	    } else if (RNodePtr->unc_len < RNodePtr->comp_len) {
		printf(">100%% ");  /* compression failed?!? */
	    } else {  /* compute from sum of thread lengths (use only data?) */
	        percent = (((float) RNodePtr->comp_len /
			(float) RNodePtr->unc_len) * 100.0) + 0.5;
		(void) sprintf(tmpbuf, "%.2d%%", percent);
		printf("%-4s  ", tmpbuf);
	        /*printf("%.3d%%  ", percent);*/
	    }
	    printf("%8d\n", RNodePtr->unc_len);
	} else {
	    printf("\n---> Information for record %d:\n", i);
	    printf("Filename: %s\n", RNodePtr->filename);
	    printf("header ID: '%.4s'   ", RHptr->ID);
	    printf("header_crc: $%.4X\n", RHptr->header_crc);
	    printf("attrib_count: %u   ", RHptr->attrib_count);
	    printf("version_number: %u   ", RHptr->version_number);
	    printf("total_threads: %u\n", RHptr->total_threads);
	    printf("file_sys_id: %s   ", RHptr->file_sys_id < FIDn ?
		FID[RHptr->file_sys_id] : UNKNOWNSTR);
	    printf("sep: '%c'\n", (onebyt) RHptr->file_sys_info);
	    printf("sparse: %s (%u)   ", (onebyt) RHptr->file_sys_info >> 8 ?
		"Yes" : "No", (onebyt) RHptr->file_sys_info >> 8);
	    printf("access: %s ($%.8X)\n", (RHptr->access == 0xE3 ||
		RHptr->access == 0xC3) ? "Unlocked" : "Locked", RHptr->access);
	    printf("file_type: %s ($%.8X)   ", RHptr->file_type < 256 ?
	   	 FT[RHptr->file_type] : "???", RHptr->file_type);
	    printf("extra_type: $%.8X\n", RHptr->extra_type);
	    printf("storage_type: %s\n", RHptr->storage_type < STn ?
		ST[RHptr->storage_type] : UNKNOWNSTR);
	    printf("created: %s   ", PrintDate(&RHptr->create_when, FALSE));
	    printf("mod: %s\n", PrintDate(&RHptr->mod_when, FALSE));
	    printf("archived: %s\n", PrintDate(&RHptr->archive_when,
	    	FALSE));
	    /* future expansion... */
	}

	if (longout) DumpThreads(RNodePtr);
	RNodePtr = RNodePtr->RNext;
    }
}


/*
 * Parse args, call functions.  Not idiot-proof by any stretch.
 * In a more complete system, this would be in a different file...
 */

main(argc, argv)
int argc;
char **argv;
{
    ListHdr *archive;
    BOOLEAN longout = FALSE;

    if (argc < 2) {
	Usage(argv[0]);
	exit (0);
    }
    if (!strcmp(argv[1], "-v")) {
	printf("Version 1.1  20-May-89  Public Domain  by Andy McFadden\n");
	exit (0);
    }
    if (!strcmp(argv[1], "-l")) {
	longout = TRUE;
	argv++;
    }

    archive = NuRead(argv[1]);
    NuView(archive, argv[1], longout);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'nuread.h'" '(2807 characters)'
if test -f 'nuread.h'
then
	echo shar: "will not over-write existing file 'nuread.h'"
else
cat << \!Funky!Stuff! > 'nuread.h'
/*
 * nuread.h - linked list structures used for holding NuFX header data,
 *	and structure definitions for archive innards
 *
 * Public domain - fadden@cory.berkeley.edu (Andy McFadden)
 * version 1.1  May 1989
 */

/* SYSTEM DEPENDENCIES */
typedef unsigned char onebyt;
typedef unsigned short twobyt;
typedef unsigned int fourbyt;
#define HILO	/* defined for 68xxx machines, undefined for VAXen */
/*#define LAME*/

/* Maximum file length that we intend to handle */
#define MAXFILENAME	1024

/* "NuFile" in alternating ASCII */
static onebyt MasterID[7] = { 0x4e, 0xf5, 0x46, 0xe9, 0x6c, 0xe5, 0x0 };


/*
 * Structure definitions for NuFX innards
 */

/* Time structure */
typedef struct {
    onebyt second;
    onebyt minute;
    onebyt hour;
    onebyt year;
    onebyt day;
    onebyt month;
    onebyt filler;
    onebyt weekDay;
} Time;

/* master header block */
typedef struct {
    onebyt ID[6];
    twobyt master_crc;
    fourbyt total_records;
    Time arc_create_when;
    Time arc_mod_when;
    onebyt reserved[20];
} MHblock;
#define MHsize 48  /* this should not change */

/* record header block */
typedef struct {
    onebyt ID[4];
    twobyt header_crc;
    twobyt attrib_count;
    twobyt version_number;
    fourbyt total_threads;
    twobyt file_sys_id;
    twobyt file_sys_info;
    fourbyt access;
    fourbyt file_type;
    fourbyt extra_type;
    twobyt storage_type;
    Time create_when;
    Time mod_when;
    Time archive_when;
    /* future expansion here... */
} RHblock;
#define RHsize 56  /* sizeof(RHblock) on a decent compiler */

/* thread record */
typedef struct {
    twobyt thread_class;
    twobyt thread_format;
    twobyt thread_kind;
    twobyt reserved;
    fourbyt thread_eof;
    fourbyt comp_thread_eof;
} THblock;
#define THsize 16  /* this should not change */


/*
 * Definitions for the linked lists
 * A linked list of Record headers, with linked lists of Threads attached
 */

/* thread nodes */
typedef struct TNode_s {
    THblock *THptr;  /* points to thread info */
    long fileposn;  /* absolute position of this thread in the file */
    struct TNode_s *TNext;  /* points to next thread node */
} TNode;

/* record nodes */
typedef struct RNode_s {
    RHblock *RHptr;  /* points to the record header block */
    char *filename;
    TNode *TNodePtr;  /* points to first thread node */
    unsigned int unc_len;  /* total uncompressed length of all threads */
    unsigned int comp_len;  /* total compressed length of all threads */
    struct RNode_s *RNext;  /* points to next record node */
} RNode;

/* head of list */
typedef struct {
    MHblock *MHptr;  /* points to master header */
    RNode *RNodePtr;  /* points to first record node */
} ListHdr;


/*
 * function declarations
 */

extern ListHdr *NuRead();
extern void Seek();

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'nustr.h'" '(3447 characters)'
if test -f 'nustr.h'
then
	echo shar: "will not over-write existing file 'nustr.h'"
else
cat << \!Funky!Stuff! > 'nustr.h'
/*
 * nustr.h - string definitions for the various structure entries
 *
 * Public Domain - fadden@cory.berkeley.edu (Andy McFadden)
 * version 1.1  May 1989
 */

#define UNKNOWNSTR	"[ unknown ]"

/* weekDay values */
static char *WD[8] = { "[ null ]", "Sunday", "Monday", "Tuesday", "Wednesday",
		"Thursday", "Friday", "Saturday" };

/* month values */
static char *MO[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
		"Aug", "Sep", "Oct", "Nov", "Dec" };

/* thread_class */
#define TCn 4
static char *TC[TCn] = { "Message_thread", "Control_thread", "Data_thread",
		"Sparse_thread" };

#define TKn 3  /* max #of thread_kinds in a thread_class */
static char *TK[TCn][TKn] = {
		{ "ASCII text", "<undef>", "<undef>" },
		{ "Create directory", "<undef>", "<undef>" },
		{ "File data_fork", "Disk image", "File resource_fork" },
		{ "<undef>", "<undef>", "<undef>" } };

/* thread_format */
#define TFn 3
static char *TF[TFn] = { "Uncompressed", "SQueezed (SQ/USQ)",
		"Dynamic LZW (ShrinkIt)" };

/* quick thread_format */
#define QTFn 3
static char *QTF[QTFn] = { "unc", "squ", "shk" };

/* file_sys_id */
#define FIDn 12
static char *FID[FIDn] = { "Reserved ($00)", "ProDOS/SOS", "DOS 3.3", "DOS 3.2",
		"Apple II Pascal", "Macintosh (HFS)", "Macintosh (MFS)",
		"LISA file system", "Apple CP/M", "Reserved ($09)", "MS-DOS",
		"High-Sierra/ISO 9660" };

/* storage_type */
#define STn 14
static char *ST[STn] = { "Standard file", "Standard file", "Standard file",
		"Standard file", "-", "Extended file", "-", "-", "-", "-",
		"-", "-", "-", "Subdirectory" };

/* file type names */
static char *FT[256] = {
	"NON", "BAD", "PCD", "PTX", "TXT", "PDA", "BIN", "CHR",
	"PIC", "BA3", "DA3", "WPD", "SOS", "$0D", "$0E", "DIR",
	"RPD", "RPI", "$12", "OUT", "$14", "RPT", "$16", "$17",
	"$18", "ADB", "AWP", "ASP", "$1C", "$1D", "$1E", "$1F",
	"$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27",
	"$28", "$29", "$2A", "$2B", "$2C", "$2D", "$2E", "$2F",
	"$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
	"$38", "$39", "$3A", "$3B", "$3C", "$3D", "$3E", "$3F",
	"$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47",
	"$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F",
	"$50", "$51", "$52", "$53", "$54", "$55", "$56", "$57",
	"$58", "$59", "$5A", "$5B", "$5C", "$5D", "$5E", "$5F",
	"PRE", "$61", "$62", "$63", "$64", "$65", "$66", "$67",
	"$68", "$69", "$6A", "NIO", "$6C", "DVR", "$6E", "HDV",
	"$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77",
	"$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F",
	"$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87",
	"$88", "$89", "$8A", "$8B", "$8C", "$8D", "$8E", "$8F",
	"$90", "$91", "$92", "$93", "$94", "$95", "$96", "$97",
	"$98", "$99", "$9A", "$9B", "$9C", "$9D", "$9E", "$9F",
	"WPF", "MAC", "HLP", "DAT", "$A4", "LEX", "$A6", "$A7",
	"$A8", "$A9", "$AA", "GSB", "ARC", "$AD", "$AE", "$AF",
	"SRC", "OBJ", "LIB", "S16", "RTL", "EXE", "STR", "TSF",
	"NDA", "CDA", "TOL", "DRV", "$BC", "FST", "$BE", "DOC",
	"PNT", "SCR", "ANI", "$C3", "$C4", "$C5", "$C6", "$C7",
	"FON", "FND", "ICN", "$CB", "$CC", "$CD", "$CE", "$CF",
	"$D0", "$D1", "$D2", "$D3", "$D4", "$D5", "$D6", "$D7",
	"$D8", "$D9", "$DA", "$DB", "$DC", "DDD", "$DE", "$DF",
	"LBR", "$E1", "ATI", "$E3", "$E4", "$E5", "$E6", "$E7",
	"$E8", "$E9", "$EA", "$EB", "$EC", "$ED", "$EE", "PAS",
	"CMD", "$F1", "$F2", "$F3", "$F4", "$F5", "$F6", "$F7",
	"$F8", "IMG", "INT", "IVR", "BAS", "VAR", "REL", "SYS" };

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'nuview.h'" '(159 characters)'
if test -f 'nuview.h'
then
	echo shar: "will not over-write existing file 'nuview.h'"
else
cat << \!Funky!Stuff! > 'nuview.h'
/*
 * nuview.h - declarations for nuview.c
 *
 * Public domain - fadden@cory.berkeley.edu (Andy McFadden)
 * version 1.1  May 1989
 */

extern void NuView();

!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive