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