fadden@cory.Berkeley.EDU (Andy McFadden) (11/09/89)
NuLib part 5/5
-----
#! /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:
# nusq.c
# nuview.c
# This archive created: Thu Nov 9 01:07:48 1989
# By: Andy McFadden ()
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'nusq.c'" '(7091 characters)'
if test -f 'nusq.c'
then
echo shar: "will not over-write existing file 'nusq.c'"
else
cat << \!Funky!Stuff! > 'nusq.c'
/*
* nusq.c - Huffman squeeze/unsqueeze routines
* Based on sq3/usq2 by Don Elton
*
* By Andy McFadden (fadden@cory.berkeley.edu)
* NuLib v2.1 November 1989 Freeware (distribute, don't sell)
*/
#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...
*/
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 */
long finalposn;
static char *procName = "unpak_SQU";
finalposn = lseek(srcfd, 0L, S_REL) + length; /* where we should end up */
if ((srcfp = fdopen(srcfd, "r")) == NULL)
Fatal("Can't fdopen() archive", procName);
if ((dstfp = fdopen(dstfd, "w")) == NULL)
Fatal("Can't fdopen() dest file", procName);
unsqueeze(srcfp, dstfp); /* unsqueeze the file */
fflush(srcfp); /* (this isn't really necessary) */
fflush(dstfp); /* 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 makes things work even if unSQueezing failed */
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'nuview.c'" '(13399 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
*
* By Andy McFadden (fadden@cory.berkeley.edu)
* NuLib v2.1 November 1989 Freeware (distribute, don't sell)
*/
#include "nudefs.h"
#include <stdio.h>
#ifdef BSD43
# include <strings.h>
#else /* SYSV, APW, MSC */
# include <string.h>
#endif
#ifdef APW
# include <shell.h>
#endif
#include "nuview.h"
#include "nuread.h"
#include "nuetc.h"
/*
* String definitions for NuView
*/
/* unknown value msg */
char *unknownStr = "[ unknown ]";
/* weekDay values */
char *WD[8] = { "[ null ]", "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday" };
/* month values */
char *MO[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec" };
/* thread_class */
/*#define TCn 4*/
char *TC[TCn] = { "Message_thread", "Control_thread", "Data_thread",
"Sparse_thread" };
/*#define TKn 3 /* max #of thread_kinds in a thread_class */
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*/
char *TF[TFn] = { "Uncompressed", "SQueezed (SQ/USQ)",
"Dynamic LZW (ShrinkIt)" };
/* quick thread_format */
/*#define QTFn 3*/
char *QTF[QTFn] = { "unc", "squ", "shk" };
/* file_sys_id */
/*#define FIDn 12*/
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*/
char *ST[STn] = { "Standard file ($00)", "Standard file ($01)",
"Standard file ($02)", "Standard file ($03)", "??? ($04)",
"Extended file ($05)", "??? ($06)", "??? ($07)", "??? ($08)",
"??? ($09)", "??? ($0a)", "??? ($0b)", "??? ($0c)",
"Subdirectory ($0d)" };
/* file type names */
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" };
/*
* NuView program
*/
/* print date from Time structure */
char *PrintDate(tptr, brief)
Time *tptr;
BOOLEAN brief;
{
static char buf[64]; /* holds final date string; must be static */
char buf2[64]; /* space to hold string while building it */
/* check for validity */
if ( (tptr->day > 30) || (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 FULL 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)+1, 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 (used by FULL view mode)
*/
static void DumpThreads(RNodePtr)
RNode *RNodePtr;
{
int i;
fourbyt 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; (fourbyt) 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: %lu ", ind, THptr->thread_eof);
printf("comp_thread_eof: %lu\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: %lu ", ind, RNodePtr->unc_len);
printf("total comp_thread_eof: %lu\n", RNodePtr->comp_len);
}
/*
* Scan contents of the threads for certain things (for PROSHK view mode)
* Returns 65535 as error code (-1 in an unsigned short)
*/
static twobyt ScanThreads(RNodePtr, format)
RNode *RNodePtr;
twobyt *format;
{
int i;
fourbyt count = RNodePtr->RHptr->total_threads;
THblock *THptr;
TNode *TNodePtr;
*format = 65535; /* default = error */
TNodePtr = RNodePtr->TNodePtr;
for (i = 0; (fourbyt) 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
*
* Format types:
* T: NAMEONLY - Brief output of filenames only (good for pipes)
* V: PROSHK - ProDOS ShrinkIt format
* Z: FULL - Fully detailed output
*/
void NuView(filename, options)
char *filename;
char *options;
{
ListHdr *archive;
MHblock *MHptr;
RHblock *RHptr;
RNode *RNodePtr;
outtype prtform;
int rec;
char tmpbuf[64]; /* temporary buffer for sprintf + printf */
twobyt format, datakind; /* PROSHK */
int percent; /* PROSHK */
#ifdef APW /* kill "not used" messages */
char *ptr;
#endif
static char *procName = "NuView";
/* process options ourselves */
switch (options[0]) {
case 't':
if (INDEX(options+1, 'v')) prtform = PROSHK; /* -tv is same as -v */
if (INDEX(options+1, 'z')) prtform = FULL;
else prtform = NAMEONLY;
break;
case 'v':
prtform = PROSHK;
break;
default:
fprintf(stderr, "NuView internal error: unknown output format\n");
Quit (-1);
}
archive = NuRead(filename);
MHptr = archive->MHptr;
/* Print master header info */
if (prtform == NAMEONLY) {
/* don't print any info from master hedaer for NAMEONLY */
} else if (prtform == PROSHK) {
#ifdef APW
/* strip partial paths from APW filename (if any) */
ptr = RINDEX(archive->arc_name, '/');
printf(" %-15.15s ", ptr ? ptr+1 : archive->arc_name);
#else
printf(" %-15.15s ", archive->arc_name);
#endif
printf("Created:%s ", PrintDate(&MHptr->arc_create_when, TRUE));
printf("Mod:%s ", PrintDate(&MHptr->arc_mod_when, TRUE));
printf("Recs:%5lu\n\n", MHptr->total_records);
printf(" Name Kind Typ Auxtyp Archived");
printf(" Fmat Size Un-Length\n");
printf("-------------------------------------------------") ;
printf("----------------------------\n");
} else if (prtform == FULL) {
printf("Now processing archive '%s'\n", archive->arc_name);
printf("---> Master header information:\n");
printf("master ID: '%.6s' ", MHptr->ID);
printf("master_crc: $%.4X\n", MHptr->master_crc);
printf("total_records: %lu\n", MHptr->total_records);
printf("created: %s ", PrintDate(&MHptr->arc_create_when, FALSE));
printf("mod: %s\n", PrintDate(&MHptr->arc_mod_when, FALSE));
} else {
printf("NuView internal error: undefined output format\n");
Quit (-1);
}
/* Print record info */
RNodePtr = archive->RNodePtr;
for (rec = 0; (fourbyt) rec < MHptr->total_records; rec++) {
if (RNodePtr == (RNode *) NULL) {
fprintf(stderr, "WARNING: fewer records than expected\n");
return;
}
RHptr = RNodePtr->RHptr;
if (prtform == NAMEONLY) {
printf("%.79s\n", RNodePtr->filename); /* max 79 chars */
} else if (prtform == PROSHK) {
printf("%c", (RHptr->access == 0xE3L || RHptr->access == 0xC3L) ?
' ' : '+');
printf("%-21.21s ", RNodePtr->filename);
datakind = ScanThreads(RNodePtr, &format); /* data_thread info */
if (datakind == 65535) { /* no data thread... */
printf("???? ");
printf("%s ", RHptr->file_type < 256L ? FT[RHptr->file_type] :
"???");
printf("$%.4X ", (twobyt) RHptr->extra_type);
} else if (datakind == 1) { /* disk */
printf("Disk ");
printf("--- ");
(void) sprintf(tmpbuf, "%dk", (twobyt) RHptr->extra_type / 2);
printf("%-5s ", tmpbuf);
} else { /* must be a file */
printf("File ");
printf("%s ", RHptr->file_type < 256L ? FT[RHptr->file_type] :
"???");
printf("$%.4X ", (twobyt) 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);
}
if (!RNodePtr->unc_len && RNodePtr->comp_len) /* weird */
printf(" ????\n");
else
printf("%8ld\n", RNodePtr->unc_len);
} else if (prtform == FULL) {
printf("\n---> Information for record %d:\n", rec);
printf("Filename: (%d) '%s'\n",
RNodePtr->namelen, 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: %lu\n", RHptr->total_threads);
printf("file_sys_id: %s ", RHptr->file_sys_id < FIDn ?
FID[RHptr->file_sys_id] : unknownStr);
printf("sep: '%c' ", (onebyt) RHptr->file_sys_info);
printf("sparse: %s (%u)\n", (onebyt) RHptr->file_sys_info >> 8 ?
"Yes" : "No", (onebyt) RHptr->file_sys_info >> 8);
if (RHptr->file_sys_id == 0x0001) { /* ProDOS-specific */
printf("access: %s ($%.8lX) ", (RHptr->access == 0xE3L ||
RHptr->access == 0xC3L) ? "Unlocked" : "Locked", RHptr->access);
printf("file_type: %s ($%.8lX)\n", RHptr->file_type < 256L ?
FT[RHptr->file_type] : "???", RHptr->file_type);
} else { /* all other filesystems */
printf("access: $%.8lX", RHptr->access);
printf("file_type: $%.8lX\n", RHptr->file_type);
}
printf("extra_type: $%.8lX ", 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... */
} else {
printf("NuView internal error: undefined output format\n");
Quit (-1);
}
/* Print thread info */
if (prtform == FULL) DumpThreads(RNodePtr);
RNodePtr = RNodePtr->RNext; /* advance to next record */
#ifdef APW
if (STOP()) Quit (1); /* check for OA-period */
#endif
}
if (prtform == FULL)
printf("\n*** end of file position: %ld\n", archive->nextposn);
}
!Funky!Stuff!
fi # end of overwriting check
exit 0
# End of shell archive