nulib/ 40755 765 144 0 6264126250 10256 5ustar gdrusersnulib/nudefs.h100644 765 144 20614 6247241714 12037 0ustar gdrusers/* * nudefs.h - system-dependent typdefs, and global #defines and variables. * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * IMPORTANT: This file must be first on the list of #includes, since some * include files will be processed based on these #defines * * $Id: nudefs.h,v 1.6 1996/11/28 07:48:28 gdr Exp $ */ #if defined(__GNUC__) || defined(__LCC__) #define __lint 1 #endif #ifndef __P #ifdef __STDC__ #define __P(proto) proto #else #define __P(proto) () #endif #endif /* SYSTEM DEPENDENCIES */ typedef unsigned char onebyt; typedef unsigned short twobyt; typedef unsigned long fourbyt; /* * Setup for Apple //gs compiling with APW or Orca/C * See also __GNO__, below. */ #if defined(APW) || defined(__ORCAC__) #define __appleiigs__ #pragma lint -1 #pragma memorymodel 1 #pragma optimize 7 /* pragma debug 25 */ /* Setup for Apple //gs compiling with lcc. See also __GNO__, below. */ #elif defined(__appleiigs__) && defined(__LCC__) /* Setup for HAL Sparc-64 (Solaris compatible) */ #elif defined(sparc) && defined(hal) #define UNIX #define SYSV #define __lint #define _POSIX_SOURCE #define HAS_DIRENT /* Setup for SunPro C and Solaris 2.5.1 */ #elif defined(__SUNPRO_C) && defined(__SunOS_5_5_1) #define UNIX #define SYSV #define _POSIX_SOURCE #define HAS_DIRENT #define __EXTENSIONS__ /* Setup for SunPro C and Solaris 2.4 */ #elif defined(__SUNPRO_C) && defined(__SunOS_5_4) #define UNIX #define SYSV #define _POSIX_SOURCE #define HAS_DIRENT #elif defined(__sun__) && defined(__GNUC__) #define UNIX #define HAS_DIRENT #ifdef __SVR4 #define SYSV /* Solaris with gcc */ #define _POSIX_SOURCE #else #define SUNOS4 /* SunOS 4.x with gcc */ #endif /* Setup for SunOS 4.1.3 with /usr/5bin/cc */ #elif defined(sun) && defined(sparc) && !defined(__GNUC__) #define UNIX #define BSD43 #define const /* "const" not understood */ #define SUNOS4 #undef HAS_DIRENT /* Setup for HPUX with cc and gcc */ #elif defined(__hpux) #define UNIX #define SYSV #define HAS_DIRENT #ifndef __STDC__ #define const /* HPUX cc not ANSI by default */ #endif #ifdef __GNUC__ #define _POSIX_SOURCE #endif /* Setup for Linux */ #elif defined(__linux__) #define UNIX #define SYSV #define HAS_DIRENT /* Setup for AIX */ #elif defined(_AIX) #define UNIX #define SYSV #define BSD_INCLUDES #define _ALL_SOURCE #define HAS_DIRENT /* Setup for BSD 4.4 systems (BSDI, NetBSD, FreeBSD, and OpenBSD) */ #elif defined(__bsdi__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) #define UNIX #define BSD43 #define HAS_UTIMBUF #undef HAS_DIRENT #undef __P #include /* to get __P definition */ #else %%%% unknown architecture %%%% #endif #ifdef __GNO__ #define UNIX #define BSD43 #define HAS_DIRENT #endif /* Setup for MS-DOS machines (80xxx based: IBM PC) */ /* #ifndef MSDOS */ /* #define MSDOS */ /* #endif */ /* Setup for BSD UNIX systems */ /*#define UNIX*/ /*#define BSD43*/ /* Setup for the NeXT */ /* #define UNIX */ /* #define BSD43 */ /* #define NeXT */ /* (is this defined automatically?) */ /* Setup for XENIX/386 */ /* NOTE: if you get error messages about readdir() and opendir() during */ /* linking, remove the leading '#' from the line "#CLIBS= -lx" in */ /* "Makefile" */ /* #define XENIX386 */ /* #define UNIX */ /* #define SYSV */ /* #define NO_RENAME */ /* no rename() call in C library */ /* Setup for Amdahl UTS 2.1; also works on the AT&T 3B2 */ /* #define UNIX */ /* #define SYSV */ /* #define NO_RENAME */ /* (UTS only:) */ /* #define HAS_EFT */ /*(don't forget to add "-eft" flag in Makefile for UTS 2.1)*/ /* Setup for AOS/VS @ DG */ /* #define UNIX */ /* #define DATAGENERAL */ /* #define AOSVS */ /* Setup for AViiONs */ /* #define UNIX */ /* #define SYSV */ /* #define HAS_EFT */ /* Setup for other UNIX systems */ /* #define UNIX */ /* #define SYSV (or whatever) */ /* use table lookups to get CRCs */ #define CRC_TAB /* don't include Binary II */ /* #define NO_BLU */ /* don't include UNIX compress */ /* #define NO_UCOMP */ #ifndef SEGMENT_NAME %%% unspecified segment %%% #endif #ifdef __ORCAC__ segment SEGMENT_NAME; #elif defined(APW) segment SEGMENT_NAME #elif defined(__appleiigs__) && defined(__LCC__) #pragma segment SEGMENT_NAME #endif #ifdef __ORCAC__ extern int _mapErr(int); #define TOOL_CHECK(action, file, isFatal) \ { \ if (_toolErr) { \ fprintf(stderr, "couldn't %s %s: %s\n", action, file, \ strerror(_mapErr(_toolErr))); \ if (isFatal) { \ QuitNulib(1); \ } \ } \ } #endif #ifdef UNIX /* (the #include setup for NuLib is pretty screwed up at this point...) */ # include /* need off_t, if it exists */ /* * With EFT, off_t is a longlong (8 bytes) and mode_t is four bytes (ulong). * They affect lseek() and open() calls. Without EFT, off_t is usually * four bytes, and mode_t is a short or an int. * * I'm not sure which systems don't have off_t or mode_t. BSD seems to have * off_t, but not mode_t; this'll have to be handled on a case-by-case basis. * Unfortunately #ifdefs don't pick up typedefs on all compilers... */ # ifndef HAS_EFT /*typedef long off_t;*/ /*typedef unsigned short mode_t;*/ # endif #else # ifndef HAS_EFT /* APW and MS-DOS should be the same */ typedef long off_t; typedef unsigned int mode_t; # endif #endif #if !defined(UNIX) && !defined(__ORCAC__) /* VERY important if lseek() doesn't return int */ extern off_t lseek __P((int, off_t, int)); #endif /* * Define this if you want the file sizes to be printed. */ #define SHOW_DATA_SIZE /* * The rest of this stuff shouldn't need to be changed */ /* * Some global defs */ /* errno wasn't defined in on some systems... */ #ifndef MSDOS extern int errno; #endif /* Maximum file name length that we intend to handle (watch stack size!) */ #define MAXFILENAME 1024 /* file operations */ #define S_ABS 0 /* seek absolute */ #define S_REL 1 /* seek relative */ #define S_END 2 /* seek from end */ #ifdef UNIX /* stuff for open() */ # ifdef __GNO__ # define WPERMS 0644 /* read/write for owner, read only for others */ # else # define WPERMS 0644 /* read/write for owner, read only for others */ # define O_BINARY 0 /* for non-UNIX open(); easier than #ifdefs */ # endif # define FREAD_STR "r" # define FWRITE_STR "w" #else # ifdef APW # define WPERMS 0666 /* read/write for all; this may not work for some */ # define FREAD_STR "rb" # define FWRITE_STR "wb" # endif # ifdef MSDOS # define S_IREAD 0000400 /* read permission, owner */ # define S_IWRITE 0000200 /* write permission, owner */ # define WPERMS S_IREAD | S_IWRITE # define FREAD_STR "rb" # define FWRITE_STR "wb" # endif # ifndef WPERMS /* other system */ # define WPERMS 0666 /* +PORT+ */ # define FREAD_STR "rb" # define FWRITE_STR "wb" # endif #endif /*UNIX*/ /* Time structure; same as TimeRec from misctool.h */ /* one-byte entries should not have alignment problems... */ typedef struct { onebyt second; onebyt minute; onebyt hour; onebyt year; onebyt day; onebyt month; onebyt extra; onebyt weekDay; } Time; /* * global to entire program */ /* byte ordering; TRUE if high byte is first (68xxx), else FALSE (65xxx) */ extern int HiLo; /* actually part of numain.c */ extern int verbose; /* BOOLEAN: print verbose? */ extern int interact; /* BOOLEAN: interactive when overwriting? */ extern int dopack; /* BOOLEAN: do we want to pack/unpack? */ extern int doSubdir; /* BOOLEAN: expand subdirectories? */ extern int doExpand; /* BOOLEAN: expand archived filenames? */ extern int doMessages; /* BOOLEAN: do comments instead of data? */ extern int transfrom; /* how to do CR<->LF translation? (-1 = none) */ extern int transto; extern int packMethod; /* how to pack a file (thread_format) */ extern int diskData; /* BOOLEAN: store files as disk images */ extern fourbyt defFileType; /* default file type */ extern fourbyt defAuxType; /* default aux type */ extern onebyt *pakbuf; /* used by compression routines; created once to */ /* eliminate overhead involved in malloc()ing a 64K buffer */ extern char *prgName; /* for errors; don't like argv[0] */ /* define these if they haven't been already */ /* (typedef int BOOLEAN caused too many problems... #define is easier) */ #ifdef __ORCAC__ # ifndef __TYPES__ # include # endif #elif !defined(BOOLEAN) # define BOOLEAN int #endif #ifndef TRUE # define TRUE 1 # define FALSE 0 #endif nulib/nublu.c100644 765 144 31543 6247227101 11670 0ustar gdrusers/* * nublu.c - operations on Binary II archives * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nublu.c,v 1.4 1996/11/28 06:16:33 gdr Exp $ */ #ifndef NO_BLU /***********************************/ #define SEGMENT_NAME "Compress2_" #include "nudefs.h" #include #include #include #include #include #ifdef UNIX # include # include # include # include #endif #ifdef __ORCAC__ # include #endif #ifdef APW # include #endif #ifdef MSDOS # include # include # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuview.h" /* file types for BLU */ #include "nuread.h" /* for typedef ListHdr */ #include "nuadd.h" /* need OptNum() */ #include "nupak.h" /* need unpak_SQU */ #include "nuetc.h" #include "nuext.h" #include "nublu.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 *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 #ifdef __STDC__ extract_file (int fd, char *fname, long filelen) #else extract_file(fd, fname, filelen) int fd; char *fname; /* 64 bytes */ long filelen; #endif { int ofd; int n, i; int len; onebyt buf[BUFSIZE]; long full_len; int offset = 0; static char *procName = "extract_file"; /*n = */ read(fd, buf, 70); /* read first few bytes */ lseek(fd, (off_t) -70, 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? */ ConvFileName(fname); if (verbose) { printf("(as %s)...", fname); fflush(stdout); } } ConvFileName(fname); /* strip hi bits, adjust special chars, etc */ len = strlen(fname); /* (no longer used?) */ #ifdef FUBAR for (j = 0; j < len; j++) fname[j] &= 0x7f; /* clear hi bits */ #endif 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, (off_t) 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, (mode_t)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, (off_t) 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); QuitNulib(-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 #ifdef __STDC__ print_header(onebyt *buf) #else print_header(buf) onebyt *buf; #endif { 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 #ifdef __STDC__ want(char *name, char **wantlist) #else want(name, wantlist) char *name; char **wantlist; #endif { while (*wantlist != NULL) { if (strcasecmp(name, *wantlist++) == 0) return (TRUE); } return (FALSE); } /* * process_file -- retrieve or print file information of file given * in buf */ static void #ifdef __STDC__ process_file (int fd, onebyt *buf, int count, char **wanted) #else process_file (fd, buf, count, wanted) int fd; onebyt *buf; int count; char **wanted; #endif { 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 __ORCAC__ static GSString255 gstr; static FileInfoRecPtrGS frec = NULL; #elif defined(APW) FileRec frec; #elif defined(UNIX) struct stat st; #elif defined(MSDOS) struct stat st; #else /* +PORT+ */ int tf; int dflags; #endif 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, (const char *) &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, (off_t) BUFSIZE*nblocks, S_REL); /*Seek to next file*/ } } else { /* extract is TRUE */ if (verbose) { printf("Extracting %s...", fname); fflush(stdout); } #ifdef __ORCAC__ /* create file/directory , with appropriate type/auxtype stuff */ if (frec == NULL) { frec = malloc (sizeof (FileInfoRecGS)); frec->pathname = &gstr; } frec->pCount = 5; frec->pathname->length = strlen(fname); assert(frec->pathname->length < 255); strcpy(frec->pathname->text, fname); frec->access = 0x00e3; /* unlocked, visible */ frec->fileType = ftype; frec->auxType = (LongWord) auxtype; frec->storageType = (Word) buf[7]; CreateGS(frec); TOOL_CHECK("create file", fname, 1); extract_file(fd, fname, filelen); /* set file attributes */ frec->access = (Word) buf[3]; frec->createDateTime = *((TimeRec *) &create_dt); frec->modDateTime = *((TimeRec *) &mod_dt); frec->storageType = 0; /* must be zero for SetFileInfoGS */ SetFileInfoGS(frec); TOOL_CHECK("set file info for", fname, 0); #elif defined(UNIX) /* && !defined(__GNO__) */ 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); } } #elif defined(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 /* !__ORCAC__, !UNIX, !APW */ if (ftype != 15) extract_file(fd, fname, filelen); else /* +PORT+ */ printf("[ need [other] subdir create for UnBNY ]\n"); #endif if (verbose) printf("done.\n"); } } else if (ftype != 15) { /* This file not wanted; if not a directory */ lseek(fd, (off_t) 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 #ifdef __STDC__ unblu(int fd, int count, char **wanted) #else unblu(fd, count, wanted) int fd; int count; char **wanted; #endif { 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); QuitNulib(-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); QuitNulib(-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 #ifdef __STDC__ NuBNY (char *filename, int argc, char **argv, char *options) #else NuBNY(filename, argc, argv, options) char *filename; int argc; char **argv; char *options; #endif { int bfd; /* File descriptor for blu file */ /* 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); QuitNulib(0); } #endif /*NO_BLU*/ /***********************************/ nulib/numain.c100644 765 144 47742 6264126250 12044 0ustar gdrusers/* * numain.c - shell-based front end for NuLib * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: numain.c,v 1.6 1997/01/06 07:41:28 gdr Exp $ */ #define SEGMENT_NAME "main______" #include "nudefs.h" /* system-dependent defines */ static char *header = "NuLib v3.25 January 1997 Freeware Copyright 1989-97 By Andy McFadden"; #include /* standard I/O library */ #include #include #include /* C type stuff, like tolower() */ #include #include #ifdef __STDC__ #include #endif #ifdef __ORCAC__ #include #endif #ifdef APW # include # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuread.h" /* structs for archive info, archive read routines */ #include "nuview.h" /* archive listing functions */ #include "nuadd.h" /* archive operations (add, create, move) */ #include "nuext.h" /* archive operations (extract) */ #include "nupdel.h" /* archive operations (delete, update, freshen) */ #include "nublu.h" /* Binary II archive operations */ #include "nupak.h" /* need PAKBUFSIZ */ #include "nuetc.h" /* Malloc(), Fatal(), etc. */ extern char *getenv __P((const char *)); /* +PORT+ */ static void GetDefaults __P((char *options)); #define Whoops(str) printf("WARNING: typedef %s may be set incorrectly\n",str); #define ENVAR "NULIBOPT" /* environment variable with options in it */ /* * global to entire program */ int HiLo; /* byte ordering; FALSE on low-first (65816) */ int verbose; /* print verbose? */ int interact; /* interactive overwrite mode? */ int dopack; /* do we want to pack/unpack? */ int doExpand; /* do we want to expand archive filenames? */ int doSubdir; /* process subdirectories at all? */ int doMessages; /* do comments instead of data */ int transfrom; /* how to do CR<->LF translation (from what?) (-1 = off) */ int transto; /* translate to ? */ int packMethod; /* how to pack a file */ int diskData; /* store files as if they are disk images */ fourbyt defFileType; /* default file type */ fourbyt defAuxType; /* default aux type */ onebyt *pakbuf; /* used by compression routines; created once to reduce */ /* overhead involved in malloc()ing a 64K buffer */ char *prgName = "NuLib"; /* for error messages; don't like argv[0] */ /* besides, the name changes every 3 weeks */ #ifdef __appleiigs__ extern int needsgno __P((void)); int GnoActive; #endif /* * Show only the file component of a path name. */ static char * #ifdef __STDC__ Basename __P((char *str)) #else Basename (str) char *str; #endif { char *p; #ifdef __appleiigs__ if ((p = strrchr(str, ':')) == NULL) { if ((p = strrchr(str, '/')) == NULL) { return str + strlen(str); } else { return p+1; } } else { return p+1; } #else if ((p = strrchr(str, '/')) == NULL) { return str + strlen(str); } else { return p+1; } #endif } /* * Print simple usage info */ static void #ifdef __STDC__ Usage(char *argv0) #else Usage(argv0) char *argv0; #endif { printf("\nUsage: %s option[suboptions] archive-name [filespec]\n", argv0); printf("\nType \"%s h\" for help.\n", argv0); } /* * Print usage info */ static void #ifdef __STDC__ Help(char *argv0, char *options) #else Help(argv0, options) char *argv0, *options; #endif { if (INDEX(options+1, 'n')) { /* using 'n' suboption? */ printf("%s\n", header); printf("\nCompression methods:\n"); printf(" # Name Abbr Pack? Unpack?\n"); printf(" 0: Uncompressed unc Y Y\n"); printf(" 1: SQueezed (sq/usq) squ N Y\n"); printf(" 2: Dynamic LZW-I (ShrinkIt) shk Y Y\n"); printf(" 3: Dynamic LZW-II (ShrinkIt) sh2 N Y\n"); printf(" 4: UNIX 12-bit compress u12 Y Y\n"); printf(" 5: UNIX 16-bit compress u16 Y Y\n"); printf("The default is #2\n"); printf("\nText conversion methods (during extraction):\n"); printf(" 0: Convert from CR to this system (ProDOS files)\n"); printf(" 1: Convert from LF to this system (UNIX files)\n"); printf(" 2: Convert from CRLF to this system (MS-DOS files)\n"); } else if (INDEX(options+1, 'w')) { /* print author info */ printf("%s\n", header); printf("Internet: fadden@netcom.com\n"); printf("\nShrinkIt and NuFX standard by Andy Nicholas.\n"); printf( "ShrinkIt LZW compression by Kent Dickey. LZW-II (a modified version of\n"); printf( " Kent's algorithm) designed by Andy Nicholas. C LZW-II decoder by Kent\n"); printf( " Dickey and Frank Petroski (independently and simultaneously).\n"); printf("\nUNIX compress code adapted from COMPRESS v4.3.\n"); printf( "\nBinary II unpack and unsqueeze C code adapted from unblu.c and usq.c by\n"); printf(" Marcel J.E. Mol (usq.c based on usq2/sq3 by Don Elton).\n"); printf("\nMS-DOS port by Robert B. Hess and Bruce Kahn.\n"); printf( "\nThis program is Freeware. Please distribute as widely as possible, but\n"); printf( " don't sell it. Source code is available via e-mail upon request.\n"); printf( "\nUsers without Usenet/Internet access may send mail to me at:\n"); printf(" Andy McFadden\n"); printf(" 1474 Saskatchewan Drive\n"); printf(" Sunnyvale, CA 94087\n"); } else if (INDEX(options+1, 's')) { /* suboption info */ printf("%s\n", header); printf("\nUsual meaning of suboptions:\n"); printf(" c - compression type, followed by a number\n"); printf( " f - file/aux type to add, followed by file/aux type spec\n"); printf(" d - store the files, but mark them as disk images\n"); printf(" i - interactive; prompt before overwriting file\n"); printf(" m - messages (add/extract comments instead of data)\n"); printf(" r - don't recursively descend subdirectories\n"); printf(" s - storage type (store as compressed w/o compressing), "); printf("followed by number\n"); printf( " t - text translation (CR<->LF), followed by conversion mode\n"); printf(" u - store as uncompressed (same as c0)\n"); printf(" v - verbose mode\n"); #ifndef NO_BLU printf(" x - extract during Binary II operations\n"); #endif printf(" + - match partial pathnames for extract and delete\n"); printf("\nTable of contents suboptions:\n"); printf(" v - verbose output (same as V option)\n"); printf(" a - ARC/ZOO style format\n"); printf(" z - full output, prints all aspects of archive\n"); printf("\nSample shell variable command (csh):\n"); printf( " setenv NULIBOPT=verbose,interactive,type=SRC,aux=000a,compress=5\n"); printf(" (default is non-verbose, non-interactive, type=NON, "); printf( "aux=0000, compress=2)\n"); } else { /* default help screen */ printf("%s\n", header); printf( "\nUsage: %s option[suboptions] archive-name [filespec]\n", argv0); printf("Option must be one of:\n"); printf(" a[vucsrfd] add to archive\n"); #ifndef NO_BLU printf(" b[xvti] Binary II archive operations\n"); #endif printf( " c[vucsrfd] create archive (add, but suppress 'create' message)\n"); printf(" d[v+] delete file from archive\n"); printf(" f[vucsrfd] freshen files in archive\n"); printf(" h[snw] show help screen (subopt/numbers/who's who)\n"); printf(" i[v] verify archive integrity\n"); printf(" m[vucsrfd] move files to archive (add, delete original)\n"); printf(" p[vmt+] print archived file to stdout\n"); printf(" t[vaz] display table of contents\n"); printf(" u[vucsrfd] update files in archive\n"); printf(" v verbose listing (ProDOS 8 ShrinkIt format)\n"); printf(" x,e[vumti+] extract from archive\n"); } } /* * If you get an error on either of these lines, then you need to * specify definitions for them in nudefs.h (see the comments in the * file for more info). */ typedef off_t dummy_off; typedef mode_t dummy_mode; /* * Check machine dependencies */ static void #ifdef __STDC__ CheckMach(void) #else CheckMach() #endif { onebyt one; onebyt *oneptr; twobyt two; fourbyt four; #ifdef UNIX # ifdef APW ^^ "ERROR: You have both APW and UNIX defined" ^^ # endif # ifdef MSDOS ^^ "ERROR: You have both MSDOS and UNIX defined" ^^ # endif #endif /*UNIX*/ #ifdef APW # ifdef MSDOS ^^ "ERROR: You have both APW and MSDOS defined" ^^ # endif #endif /* some compilers complain about (unsigned) -1 , so I'm doing it this */ /* way to keep everybody quiet. */ one = (onebyt) 0x100; if (one) Whoops("onebyt"); /* one > 1 */ two = (twobyt) 0x10000; if (two) Whoops("twobyt"); /* two > 2 */ two = 0x1000; if (!two) Whoops("twobyt"); /* two < 2 */ #ifdef __GNUC__ four = -1; #else four = 0xffffffff; #endif four++; if (four) Whoops("fourbyt"); /* four > 4 */ four = 0x10000; if (!four) Whoops("fourbyt"); /* four < 4 */ /* check byte ordering */ two = 0x1122; oneptr = (onebyt *) &two; if (*oneptr == 0x11) HiLo = TRUE; else if (*oneptr == 0x22) HiLo = FALSE; else { printf("WARNING: Unable to determine a value for HiLo\n"); HiLo = FALSE; } /* check some other stuff... compilers may (should?) give warnings here */ if (ATTSIZE < MHsize) printf("WARNING: ATTSIZE must be >= than MHsize\n"); if (RECBUFSIZ < ATTSIZE) printf("WARNING: RECBUFSIZ should be larger than ATTSIZE\n"); if (MHsize != 48 || THsize != 16) printf("WARNING: Bad MHsize or THsize\n"); if (sizeof(Time) != 8) printf("WARNING: struct Time not 8 bytes\n"); } /* * Check to see if string 2 is in string 1. * * Returns the position of string 2 within string 1; -1 if not found. */ static int #ifdef __STDC__ strc(char *host, char *sub) #else strc(host, sub) char *host, *sub; #endif { int hlen = strlen(host); int slen = strlen(sub); int i; if (slen > hlen) /* substring longer than host string */ return (-1); /* generic linear search... */ for (i = 0; i <= (hlen - slen); i++) if ((*(host+i) == *sub) && (!strncmp(host+i, sub, slen))) return (i); return (-1); } /* * Yank a number from a character string. */ int #ifdef __STDC__ OptNum(char *ptr) #else OptNum(ptr) char *ptr; #endif { int val = 0; while (*ptr && isdigit(*ptr)) { val *= 10; val += (*ptr - '0'); ptr++; } return (val); } /* * Set default values for globals. * * Should be of form "NULIBOPT=..." * verbose : default to verbose output * interactive : default to interactive mode when overwriting * type=xxx : set storage type to ProDOS type "xxx" * aux=xxxx : set aux storage type to 4-byte hex number "xxxx" */ static void #ifdef __STDC__ GetDefaults(char *options) #else GetDefaults(options) char *options; #endif { char *envptr; int off, idx, pt; int len = strlen(options); char type[5]; /* set program default values */ verbose = FALSE; /* silent mode */ interact = FALSE; /* don't ask questions */ doSubdir = TRUE; /* process subdirectories unless told not to */ dopack = TRUE; /* don't pack unless told to */ doExpand = FALSE; /* don't expand archived filenames */ doMessages = FALSE; /* do comments instead of data */ packMethod = 0x0002;/* ShrinkIt LZW */ diskData = FALSE; /* store as ordinary files */ transfrom = -1; /* no text translation */ transto = -1; defFileType = (fourbyt) 0; /* NON */ defAuxType = (fourbyt) 0; /* $0000 */ /* read from global envir var */ if ((envptr = getenv(ENVAR)) != NULL) { if (strc(envptr, "verbose") >= 0) { verbose = TRUE; } if (strc(envptr, "interactive") >= 0) { interact = TRUE; } if ((off = strc(envptr, "compress=")) >= 0) { off += 9; if (off+1 > strlen(envptr)) { fprintf(stderr, "Error with 'compress=n' in NULIBOPT var\n"); QuitNulib (-1); } packMethod = atoi(envptr+off); } if ((off = strc(envptr, "type=")) >= 0) { off += 5; if (off+3 > strlen(envptr)) { fprintf(stderr, "Error with 'type=xxx' in NULIBOPT var\n"); QuitNulib (-1); } strncpy(type, envptr+off, 3); type[3] = '\0'; for (idx = 0; idx < 256; idx++) /* scan for file type */ if (!strcasecmp(FT[idx], type)) { defFileType = (fourbyt) idx; break; /* out of for */ } } if ((off = strc(envptr, "aux=")) >= 0) { off += 4; if (off+4 > strlen(envptr)) { fprintf(stderr, "Error with 'aux=$xxxx' in NULIBOPT var\n"); QuitNulib (-1); } strncpy(type, envptr+off, 4); type[4] = '\0'; assert(sizeof(long) == 4); sscanf(type, "%lx", &defAuxType); } } /* handle command line suboption string */ for (pt = 1; pt < len; pt++) { /* skip option char */ switch(options[pt]) { case '+': /* expand */ doExpand = TRUE; break; case 'a': /* ARC/ZOO output format */ /* do nothing */ break; case 'c': /* compress method */ packMethod = OptNum(&options[pt+1]); while (pt < len && isdigit(options[pt+1])) /* advance to next */ pt++; dopack = TRUE; break; case 'd': /* treat as disk images instead of ordinary files */ diskData = TRUE; break; case 'f': /* filetype specified */ strncpy(type, &options[pt+1], 3); type[3] = '\0'; for (idx = 0; idx < 256; idx++) /* scan for file type */ if (!strcasecmp(FT[idx], type)) { defFileType = (fourbyt) idx; break; /* out of for */ } pt += strlen(type); if (options[pt+1] == '/') { /* auxtype specification */ pt++; strncpy(type, &options[pt+1], 4); type[4] = '\0'; sscanf(type, "%lx", &defAuxType); pt += strlen(type); } break; case 'i': /* interactive overwrites */ interact = TRUE; break; case 'm': /* do messages instead of data */ doMessages = TRUE; break; case 'n': /* help with numbers */ /* do nothing */ break; case 'r': /* don't recursively descend subdir */ doSubdir = FALSE; break; case 's': /* store method */ packMethod = OptNum(&options[pt+1]); while (pt < len && isdigit(options[pt+1])) /* advance to next */ pt++; dopack = FALSE; break; case 't': /* how to translate text? */ transfrom = OptNum(&options[pt+1]); while (pt < len && isdigit(options[pt+1])) pt++; break; case 'u': /* don't use compression */ dopack = FALSE; /* this doesn't matter, but FALSE may be faster */ packMethod = 0x0000; /* archive w/o compression */ break; case 'v': /* verbose mode */ verbose = TRUE; break; case 'w': /* help on people */ /* do nothing */ break; case 'x': /* extract BLU files */ /* do nothing */ break; case 'z': /* in view files */ /* do nothing */ break; default: /* unknown */ fprintf(stderr, "%s: unknown subopt '%c'\n", prgName, options[pt]); break; /* do nothing */ } } /* for */ } #ifdef __ORCAC__ /* * Expand a ProDOS filename using Orca wildcard characters. * * Returns a pointer to a buffer holding the filename. */ static char * #ifdef __STDC__ ExpandFilename(char *filename) #else ExpandFilename(filename) char *filename; #endif { extern GSString255Ptr __C2GSMALLOC(char *); static Init_WildcardGSPB initpb = { 2, NULL, 0x0000 }; static NextWildcardGSPB nextpb; static ResultBuf255 rbuf; assert(filename != NULL); if (*filename == '\0') { printf("Internal error: can't expand null filename\n"); QuitNulib (-1); } if ((initpb.wFile = __C2GSMALLOC(filename)) == NULL) { perror("couldn't initialize filename expansion"); QuitNulib(-1); } /* initialize the wild card routine */ InitWildcardGS(&initpb); TOOL_CHECK("initialize filename expansion for", filename, 1); /* expand the name */ nextpb.pCount = 1; rbuf.bufSize = 255; nextpb.pathName = &rbuf; NextWildcardGS(&nextpb); TOOL_CHECK("expand file name", filename, 1); if (rbuf.bufString.length == 0) { printf("couldn't expand file name %s: %s\n", filename, strerror(ENOENT)); QuitNulib(-1); } /* NULL-terminate it */ if (rbuf.bufString.length == 255) { printf("couldn't expand file name %s: expanded file name too long\n", filename); QuitNulib(-1); } rbuf.bufString.text[rbuf.bufString.length] = '\0'; free(initpb.wFile); return rbuf.bufString.text; } #elif defined(APW) /* * Expand a ProDOS filename using APW wildcard calls (even if the file doesn't * exist). * * Returns a pointer to a buffer holding the filename. */ static char * #ifdef __STDC__ ExpandFilename(char *filename) #else ExpandFilename(filename) char *filename; #endif { char *ptr; c2pstr(filename); if (!(*filename)) { printf("Internal error: can't expand null filename\n"); QuitNulib (-1); } INIT_WILDCARD(filename, 0); ToolErrChk(); p2cstr(filename); NEXT_WILDCARD(tmpNameBuf); p2cstr(tmpNameBuf); if (strlen(tmpNameBuf)) /* found it */ return(tmpNameBuf); else { /* file does not exist; expand path */ strcpy(tmpNameBuf, filename); ptr = RINDEX(tmpNameBuf, '/'); /* remove filename */ if (!ptr) /* filename only */ return (filename); *ptr = '\0'; if (!strlen(tmpNameBuf)) { /* something weird... */ printf("Unable to expand '%s'\n", filename); QuitNulib (-1); } c2pstr(tmpNameBuf); INIT_WILDCARD(tmpNameBuf, 0); ToolErrChk(); NEXT_WILDCARD(tmpNameBuf); p2cstr(tmpNameBuf); if (!strlen(tmpNameBuf)) { printf("Unable to fully expand '%s'\n", filename); QuitNulib (-1); } strcat(tmpNameBuf, RINDEX(filename, '/')); return (tmpNameBuf); } } #endif /* APW */ #if defined(__appleiigs__) && defined(STACK_CHECK) extern void begin_stack_check __P((void)); extern int end_stack_check __P((void)); void printstack __P((void)) { fprintf(stderr, "stack usage = %d bytes", end_stack_check()); } #endif /* * Parse args, call functions. */ int #ifdef __STDC__ main(int argc, char **argv) #else main(argc, argv) int argc; char **argv; #endif { char *filename; /* hold expanded archive file name */ int idx; #ifdef __appleiigs__ # ifdef STACK_CHECK begin_stack_check(); atexit(printstack); # endif # ifdef __GNO__ GnoActive = needsgno(); # else GnoActive = 0; # endif #endif /* __appleiigs__ */ filename = (char *) Malloc(MAXFILENAME); CheckMach(); /* check compiler options, and set HiLo */ if (argc < 2) { /* no arguments supplied */ Usage(Basename(argv[0])); QuitNulib (0); } if (argv[1][0] == '-') { /* skip initial dashes */ argv[1]++; } for (idx = 0; argv[1][idx]; idx++) /* conv opts to lower case */ if (isupper(argv[1][idx])) argv[1][idx] = tolower(argv[1][idx]); if (argc < 3) { /* no archive file specified; show help screen */ if (argv[1][0] == 'h') /* could be HS, HN, or HW */ Help(Basename(argv[0]), argv[1]); else /* not 'H' option; show generic help scrn */ Help(Basename(argv[0]), "h"); QuitNulib (0); } #if defined(APW) || defined(__ORCAC__) strcpy(filename, ExpandFilename(argv[2])); #else strcpy(filename, argv[2]); #endif GetDefaults(argv[1]); /* get defaults, process suboption string */ pakbuf = (onebyt *) Malloc(PAKBUFSIZ); /* allocate global pack buf */ switch (argv[1][0]) { case 'a': /* add */ case 'c': /* create */ case 'm': /* move */ NuAdd(filename, argc-3, argv+3, argv[1]); /* NuAdd will read */ break; #ifndef NO_BLU case 'b': /* Binary II operations */ NuBNY(filename, argc-3, argv+3, argv[1]); break; #endif case 'd': /* delete */ NuDelete(filename, argc-3, argv+3, argv[1]); break; case 'f': /* freshen */ case 'u': /* update */ NuUpdate(filename, argc-3, argv+3, argv[1]); break; case 'i': /* verify integrity */ NuTest(filename, argv[1]); break; case 't': /* table of contents */ case 'v': /* verbose output */ NuView(filename, argv[1]); break; case 'e': /* extract */ case 'x': case 'p': NuExtract(filename, argc-3, argv+3, argv[1]); break; default: /* need help */ fprintf(stderr, "%s: unknown option '%c'\n", argv[0], argv[1][0]); break; } free (filename); free (pakbuf); QuitNulib (0); /*NOTREACHED*/ #ifdef __lint return 0; #endif } nulib/crc.h100644 765 144 6445 6246126406 11307 0ustar gdrusers/* * crc.h - tables for fast computation of 16-bit CRCS * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: crc.h,v 1.3 1996/11/03 23:01:02 gdr Exp $ */ /* * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. * NOTE: First srgument must be in range 0 to 255. * Second argument is referenced twice. * * Programmers may incorporate any or all code into their programs, * giving proper credit within the source. Publication of the * source routines is permitted so long as proper credit is given * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, * Omen Technology. */ /*#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)*/ #define updcrc(cp, crc) ( (crctab[((crc >> 8) & 0xFF) ^ cp] ^ (crc << 8)) & 0xFFFF) /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ static unsigned short crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; nulib/linked.scr100644 765 144 4260 6246126406 12337 0ustar gdrusers; APW LinkEd script file for NuLib ; ; Does not search for segments with blank load segment names. ; Does not search files for DIRECT segments (only the CLIB). ; Does not search any libraries other than 2/clib. keep ../nulib * This is the main code segment (type = code) segment/$00 main loadselect 2/start.root main loadselect numain.root main loadselect nuread.root main loadselect nuetc.root main loadselect nuview.root main loadselect nuadd.root main loadselect nuext.root main loadselect nupdel.root main library/loadselect 2/clib main * This contains compression/Binary II code (type = dynamic) segment/dynamic Compress loadselect nupak.root main loadselect nublu.root main loadselect nucomp.root main loadselect nushk.root main loadselect nusq.root main library/loadselect 2/clib main * This contains all global definitions (type = private data) segment/$41 Globals loadselect 2/start.root ~globals loadselect numain.root ~globals loadselect nuread.root ~globals loadselect nuetc.root ~globals loadselect nuview.root ~globals loadselect nuadd.root ~globals loadselect nuext.root ~globals loadselect nupdel.root ~globals loadselect nupak.root ~globals loadselect nublu.root ~globals loadselect nucomp.root ~globals loadselect nushk.root ~globals loadselect nusq.root ~globals library/loadselect 2/clib ~globals * This holds all arrays (type = private data) segment/$41 Arrays loadselect 2/start.root ~arrays loadselect numain.root ~arrays loadselect nuread.root ~arrays loadselect nuetc.root ~arrays loadselect nuview.root ~arrays loadselect nuadd.root ~arrays loadselect nuext.root ~arrays loadselect nupdel.root ~arrays loadselect nupak.root ~arrays loadselect nublu.root ~arrays loadselect nucomp.root ~arrays loadselect nushk.root ~arrays loadselect nusq.root ~arrays library/loadselect 2/clib ~arrays * This has direct page stuff, like the stack segment/$12 Direct (type = direct-page/stack) library/loadselect 2/clib DIRECT list on * One other segment, SEGJPTBL, appears here... nulib/linker.scr100644 765 144 152 6246126406 12331 0ustar gdrusers13/start numain nuread nuview nuadd nuext nupdel nuetc nublu nucomp nupak nushk nusq 13/clib keep=nulib nulib/make.apw100644 765 144 1203 6246126406 12000 0ustar gdrusers* * NuLib AGE script (A pseudo-makefile for APW and ORCA) * for file in numain nuread nuview nuadd nuext nupdel nupak nuetc nublu nushk nusq nucomp age obj/{file}.root {file}.c if {age} != 0 echo compiling {file}.c delete obj/{file}.root compile {file}.c keep=obj/{file} end end * Once everything is compiled, I test the final * program file against the object modules that build it. * If linking is required, it is performed next followed * by a series of other statements to complete it: age cshk obj/=.root purge if {age} != 0 delete nulib prefix obj assemble linker.scr prefix .. end nulib/nuetc.h100644 765 144 4205 6247227102 11642 0ustar gdrusers/* * nuetc.h - declarations for nuetc.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * (this will be included by almost all source files; it should come last) * * $Id: nuetc.h,v 1.4 1996/11/28 06:16:34 gdr Exp $ */ /* define these if they haven't been already */ /* (typedef int BOOLEAN caused too many problems... #define is easier) */ #if 0 /* should only be nudefs.h */ #ifndef BOOLEAN # define BOOLEAN int #endif #endif #ifndef TRUE # define TRUE 1 # define FALSE 0 #endif #ifdef UNIX # ifdef BSD43 # ifndef NeXT extern char *index __P((const char *, int)); /* BSD version */ extern char *rindex __P((const char *, int)); # endif # define INDEX(s, c) index(s, c) # define RINDEX(s, c) rindex(s, c) # else extern char *strchr __P((const char *, int)); /* AT&T version */ extern char *strrchr __P((const char *, int)); # define INDEX(s, c) strchr(s, c) # define RINDEX(s, c) strrchr(s, c) # endif #else extern char *strchr __P((const char *, int)); /* APW, MSC */ extern char *strrchr __P((const char *, int)); # define INDEX(s, c) strchr(s, c) # define RINDEX(s, c) strrchr(s, c) #endif extern char tmpNameBuf[]; /* external function declarations */ extern void Fatal __P((char *, char *)); extern void QuitNulib __P((int)); extern char *Malloc __P((size_t)); extern long timecvt __P((Time *)); #ifdef APW extern void ToolErrChk __((void)); extern void perror __P((const char *)); #endif extern int strcasecmp __P((const char *, const char *)); extern int strncasecmp __P((const char *, const char *, size_t)); extern void ArcfiCreate __P((char *)); extern void Rename __P((char *, char *)); extern BOOLEAN Exists __P((char *)); extern char *MakeTemp __P((char *)); extern void ExpandTime __P((void *, Time *)); extern long ReduceTime __P((Time *)); extern Time *GetTime __P((void)); #ifdef __ORCAC__ # ifndef __TYPES__ # include # endif # ifdef __GNO__ # define STOP_KEY() 0 # else # define STOP_KEY() keyboardStop() # define unlink(name) remove(name) extern int keyboardStop(void); # endif extern GSString255Ptr __C2GSMALLOC(char *); #endif nulib/nuadd.c100644 765 144 73477 6247227101 11652 0ustar gdrusers/* * nuadd.c - operations which add to a NuFX archive * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuadd.c,v 1.4 1996/11/28 06:16:33 gdr Exp $ */ #define SEGMENT_NAME "NuMain2___" #define NEED_MASTER_ID /* in nuread.h */ #include "nudefs.h" #include #include #include #include #include #include #ifdef _AIX32 # include #endif #ifdef BSD43 # include #else # include #endif #ifdef UNIX # include # include # include # ifdef SYSV # ifdef XENIX386 # include /* maybe , , ...*/ # else /*other SYSV*/ # include # endif # endif # ifdef __GNO__ # include # elif defined(BSD43) # include # elif defined(SUNOS4) # include # endif #endif #ifdef __ORCAC__ # include # include # include extern char *getcwd(char *, size_t); #endif #ifdef APW # include # include # include # include #endif #ifdef MSDOS # include # include # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuread.h" #include "nuadd.h" #include "nupak.h" #include "nuetc.h" #ifdef DATAGENERAL /* BAK */ # ifdef AOSVS /* BAK */ # define BROKEN_ON_MVs /* MV/UX is NOT a full UNIX */ # endif /* implem. so we just skip */ #endif /* the 'UNIX' code on MVs */ #define MAXGSPREFIX 64 #ifdef __appleiigs__ extern int GnoActive; #endif static BOOLEAN domove; /* are we M)oving the files in? */ static BOOLEAN docreate; /* using the 'C' option? */ /* * Expand command args into filenames * Stuff number of names into int; build File Information Array. * (this routine is heavily implementation-specific, since no two systems * expand wildcards or deal with subdirectories in the same way). * * *FIArray should be NULL the first time this routine is entered. * We have to grow the actual array as necessary. * * Recursively expands subdirectories, unless doSubdir is FALSE. */ int EvalArgs #ifdef __STDC__ __P((int count, char **names, fileInfoArray FIArray, BOOLEAN first)) #else (count, names, FIArray, first) int count; /* #of filenames */ char **names; /* array of file names */ fileInfoArray FIArray; /* pointer to array to fill with file info */ BOOLEAN first; /* first time through? */ #endif { static char *procName = "EvalArgs"; #ifdef UNIX /* UNIX shells (sh, csh) won't expand subdirectories, but they do * expand wildcards in arguments before we get them */ file_info_ptr fip = NULL; struct stat st; char *cp; /* temp char pointer */ /* dir stuff */ #ifndef BROKEN_ON_MVs DIR *dirp; #endif #ifdef HAS_DIRENT struct dirent *dp; #else struct direct *dp; #endif int nmlen; if (names == NULL) { /* we're recursing */ assert(count == 0); } while (count--) { if (fip != NULL) { /* we were here before, but didn't add the name to the list */ free(fip); } fip = (file_info *) Malloc(sizeof(file_info)); if (stat(*names, &st) < 0) { /* get file info */ if (errno == ENOENT) { fprintf(stderr, "%s: '%s' not found\n", prgName, *names); names++; continue; /* with while */ } Fatal("Bad stat()", procName); } if ((st.st_mode & S_IFDIR) && doSubdir) { /* is it a directory? */ #ifndef BROKEN_ON_MVs stringArray namelist; namelist = newStringArray(); strcpy(tmpNameBuf, *names); /* earlier dir stuff */ strcat(tmpNameBuf, "/"); nmlen = strlen(tmpNameBuf); if ((dirp = opendir(*names)) == NULL) Fatal("Unable to open subdirectory", procName); while ((dp = readdir(dirp)) != NULL) { /* skip current and parent directories */ if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, ".."))) { continue; } #ifdef SYSV assert(nmlen + strlen(dp->d_name) < MAXFILENAME); #else assert((nmlen + dp->d_namlen) < MAXFILENAME); #endif strcat(tmpNameBuf, dp->d_name); addToStringArray(namelist, tmpNameBuf); tmpNameBuf[nmlen] = '\0'; } closedir(dirp); EvalArgs(namelist->used, namelist->vec, FIArray, FALSE); /* free up the space we allocated */ clearStringArray(namelist); free(namelist); names++; #else /* BROKEN_ON_MVs */ printf("Help, I ran into a directory and can't handle it!\n"); #endif continue; /* don't add the directory name to the list */ } else if ((st.st_mode & S_IFDIR) && !doSubdir) { /* maybe print message? */ names++; continue; /* with while */ } else if (st.st_mode & S_IFREG) { fip->eof = (long) st.st_size; if (st.st_mode & S_IWRITE) /* write permission enabled? */ fip->fAccess = (fourbyt) 0x00e3; /* locked */ else fip->fAccess = (fourbyt) 0x0021; /* unlocked */ fip->fileType = defFileType; fip->auxType = diskData ? st.st_size/512 : defAuxType; fip->fileSysID = 0x0001; /* ProDOS */ fip->fileSysInfo = 0x2f; /* '/' */ ExpandTime(&st.st_mtime, &fip->create_dt); /*use mod.. */ ExpandTime(&st.st_mtime, &fip->mod_dt); /*time for both */ fip->marked = FALSE; fip->pathname = (char *) Malloc(strlen(*names)+1); strcpy(fip->pathname, *names); fip->store_name = (char *) Malloc(strlen(*names)+1); cp = *names; while (*cp == '/') cp++; /* advance past leading '/' */ strcpy(fip->store_name, cp); /* can't otherwise fix */ names++; } else { printf("Unknown storage type for '%s'\n", *names); names++; continue; /* with while */ } addToFileArray (FIArray, fip); fip = NULL; } return (FIArray->used); #elif defined(__ORCAC__) /* && !defined(__GNO__) */ /* * GNO should be using this method as well, except that wildcard * expansion is broken under GNO v2.0.4 wrt expanding subdirectories; * the subdirectories are never traversed. Blech. */ static FileInfoRecGS frec; static NextWildcardGSPB nwcb; static ResultBuf255 outname; static char prefix[FILENAME_MAX]; /* cwd */ size_t prefixLen; Init_WildcardGSPB iwcb = { 2, NULL, 0x2000 }; char buffer[256]; char *fname; file_info_ptr fip = NULL; stringArray scratch = NULL; int i; /* initialize */ assert(FIArray != NULL); assert(names != NULL); assert(first); outname.bufSize = 255; nwcb.pCount = 1; nwcb.pathName = &outname; if (getcwd(prefix, FILENAME_MAX) == NULL) { perror("couldn't determine current directory"); QuitNulib(-1); } prefixLen = strlen(prefix); /* first expand all the files/directories in names FIArray */ scratch = newStringArray(); for (i=0; names[i] != NULL; i++) { iwcb.wFile = __C2GSMALLOC(names[i]); InitWildcardGS(&iwcb); TOOL_CHECK("init wildcard for", names[i], 1); for(;;) { int len; NextWildcardGS(&nwcb); TOOL_CHECK("get next wildcard", "", 1); if ((len = outname.bufString.length) == 0) { break; } strncpy(buffer, outname.bufString.text, len); buffer[len] = '\0'; addToStringArray(scratch, buffer); } free(iwcb.wFile); } /* now loop over the expanded file names */ for (i=0; i < scratch->used; i++) { if (fip != NULL) { /* we were here before, but didn't add the name to the list */ if (fip->pathname) free(fip->pathname); if (fip->store_name) free(fip->store_name); free(fip); } fip = (file_info *) Malloc(sizeof(file_info)); fname = scratch->vec[i]; /* get file info */ frec.pCount = 12; frec.pathname = __C2GSMALLOC(fname); GetFileInfoGS(&frec); TOOL_CHECK("get file info for", fname, 1); switch (frec.storageType) { case 0x01: /* standard file */ fip->eof = frec.eof; fip->fAccess = frec.access; fip->fileType = frec.fileType; fip->auxType = frec.auxType; fip->storageType = frec.storageType; fip->fileSysID = 0x0001; /* ProDOS */ fip->fileSysInfo = 0x2f; /* '/' */ fip->create_dt = *((Time *) &frec.createDateTime); fip->mod_dt = *((Time *) &frec.modDateTime); fip->marked = FALSE; fip->pathname = xstrdup(fname); /* * Orca wildcard expansion resolves to full pathnames. Remove * any leading prefix that matches the current working directory. * * This leaves the full pathname in for files residing in dirs * other than cwd. This may not be desirable. */ if (!strncmp(prefix, fname, prefixLen)) { fip->store_name = xstrdup(&fname[prefixLen]); } else { fip->store_name = xstrdup(fname); } addToFileArray (FIArray, fip); fip = NULL; case 0x05: /* extended (forked) file */ printf("Can't handle Extended file '%s'\n", fname); break; case 0x0d: /* subdirectory */ case 0x0f: /* volume directory */ /* -- do nothing (subdirs not explicitly stored?) */ break; default: printf("Unknown storage type for '%s'\n", fname); break; } } return (FIArray->used); #elif defined(APW) /* * This section is probably severly broken. I have changed the * UNIX and __ORCAC__ methods of doing this, but since I don't have * an APW compiler, I'm leaving it in its original version. -- gdr */ static int idx; /* will eventually hold the total #of filenames */ char *nextname = (char *) Malloc(MAXFILENAME); /* for subdir expand */ char prefix[MAXGSPREFIX+1]; /* Max ProDOS prefix size; now 64 */ char *fnptr; FileRec finfo_p; PrefixRec prefix_p; OpenRec open_p; EOFRec eof_p; if (first) idx = 0; prefix_p.prefixNum = 0; /* current dir */ prefix_p.prefix = prefix; /* prefix buffer */ GET_PREFIX( &prefix_p ); ToolErrChk(); p2cstr(prefix); while (count) { strcpy(tmpNameBuf, *names); c2pstr(tmpNameBuf); INIT_WILDCARD(tmpNameBuf, 0); ToolErrChk(); while (*NEXT_WILDCARD(tmpNameBuf)) { if (idx >= MAXARGS) { fprintf(stderr, "Too many files (%d, %d max)\n", idx, MAXARGS); QuitNulib (-1); } finfo_p.pathname = tmpNameBuf; GET_FILE_INFO( &finfo_p ); ToolErrChk(); open_p.openPathname = tmpNameBuf; OPEN( &open_p ); ToolErrChk(); eof_p.eofRefNum = open_p.openRefNum; GET_EOF( &eof_p ); ToolErrChk(); CLOSE( &open_p ); ToolErrChk(); p2cstr(tmpNameBuf); /* also does p2cstr(finfo_p.pathname) */ switch (finfo_p.storageType) { case 0x00: /* standard ProDOS storage types */ case 0x01: case 0x02: case 0x03: FIArray[idx] = (file_info *) Malloc(sizeof(file_info)); FIArray[idx]->eof = eof_p.eofPosition; FIArray[idx]->fAccess = finfo_p.fAccess; FIArray[idx]->fileType = (fourbyt) finfo_p.fileType; FIArray[idx]->auxType = (fourbyt) finfo_p.auxType; FIArray[idx]->storageType = finfo_p.storageType; FIArray[idx]->fileSysID = 0x0001; /* ProDOS */ FIArray[idx]->fileSysInfo = 0x2f; /* '/' */ ExpandTime(&finfo_p.createDate, &FIArray[idx]->create_dt); ExpandTime(&finfo_p.modDate, &FIArray[idx]->mod_dt); FIArray[idx]->marked = FALSE; FIArray[idx]->pathname = (char *) Malloc(strlen(tmpNameBuf)+1); strcpy(FIArray[idx]->pathname, tmpNameBuf); /* are we adding from current directory? */ if (!strncmp(tmpNameBuf, prefix, strlen(prefix))) { FIArray[idx]->store_name = /* yes */ (char *) Malloc(strlen(tmpNameBuf) - strlen(prefix) +1); strcpy(FIArray[idx]->store_name, tmpNameBuf+ strlen(prefix)); } else { fnptr = RINDEX(tmpNameBuf, '/') + 1; /* no */ FIArray[idx]->store_name = (char *)Malloc(strlen(fnptr)+1); strcpy(FIArray[idx]->store_name, fnptr); } idx++; break; case 0x05: printf("Can't handle Extended file '%s'\n", tmpNameBuf); break; case 0x0d: if (doSubdir) { strcpy(nextname, tmpNameBuf); /* make new copy */ strcat(nextname, "/="); /* APW-only wildcard */ EvalArgs(1, &nextname, FIArray, FALSE); /* read subdir */ } break; default: printf("Unknown storage type for '%s'\n", tmpNameBuf); break; } } /* inner while */ names++, count--; } /* outer while */ free (nextname); return (idx); #elif defined(MSDOS) /* * This section is probably severly broken. I have changed the * UNIX and __ORCAC__ methods of doing this, but since I don't have * an MS-DOS compiler, I'm leaving it in its original version. -- gdr */ /* MS-DOS or other shell wildcard expansion here */ int idx, error; struct stat fStat; idx = 0; while (count--) { error = stat (*names, &fStat); /* If the filename is a directory, we need to expand that too! */ if (!error) { FIArray[idx] = (file_info *) Malloc(sizeof(file_info)); FIArray[idx]->pathname = (char *) Malloc(strlen(*names)+1); strcpy(FIArray[idx]->pathname, *names); FIArray[idx]->store_name = (char *) Malloc(strlen(*names)+1); strcpy(FIArray[idx]->store_name, *names); FIArray[idx]->fAccess = 0x00e3L; /* unlocked */ FIArray[idx]->fileType = defFileType; FIArray[idx]->auxType = diskData ? fStat.st_size/512:defAuxType; FIArray[idx]->storageType = 0x0000; FIArray[idx]->fileSysID = 0x0001; /* ProDOS */ FIArray[idx]->fileSysInfo = 0x1c; /* '\' */ ExpandTime(&fStat.st_ctime, &FIArray[idx]->create_dt); ExpandTime(&fStat.st_mtime, &FIArray[idx]->mod_dt); FIArray[idx]->eof = fStat.st_size; FIArray[idx]->marked = FALSE; idx++; } names++; } return (idx); #else /* !UNIX && !__ORCAC__ !APW && !MSDOS */ /* nothing else defined */ /* +PORT+ */ printf("\n[other] wildcard expansion/file info needs work\n"); while (count--) { FIArray[count] = (file_info *) Malloc(sizeof(file_info)); FIArray[count]->pathname = (char *) Malloc(strlen(*names)+1); strcpy(FIArray[count]->pathname, *names); FIArray[count]->store_name = (char *) Malloc(strlen(*names)+1); strcpy(FIArray[count]->store_name, *names); FIArray[count]->fAccess = 0x00e3L; /* unlocked */ FIArray[count]->fileType = 0x0006L; /* BIN */ FIArray[count]->auxType = 0L; FIArray[count]->storageType = 0x0000; FIArray[count]->fileSysID = 0x0001; /* ProDOS */ FIArray[count]->fileSysInfo = 0x1c; /* '\' */ ExpandTime((char *) NULL, &FIArray[count]->create_dt); ExpandTime((char *) NULL, &FIArray[count]->mod_dt); FIArray[count]->marked = FALSE; names++; } return (count); #endif } /* * Add a file onto the end of an archive; does not check to see if an entry * already exists. * * This creates the record entry, and calls subroutines to add the various * threads. The archive fd should be open, the file fd should not. Returns * the size of the record added. */ long #ifdef __STDC__ AddFile(int arcfd, file_info *infoptr) #else AddFile(arcfd, infoptr) int arcfd; file_info *infoptr; #endif { int srcfd; /* file to add */ onebyt *recBuf; /* record header block */ twobyt *twoptr; THblock thread[1]; /* thread block */ twobyt CRC; int idx; fourbyt total_threads; long recposn; /* file posn for record entry */ long thposn; /* file posn for last thread */ long tmpposn; /* temporary file posn */ static char *procName = "AddFile"; if (verbose) { #ifdef SHOW_DATA_SIZE printf("Adding '%s' (data, %ld bytes)...", infoptr->store_name, infoptr->eof); #else printf("Adding '%s' (data)...", infoptr->store_name); #endif fflush(stdout); } recBuf = (onebyt *) Malloc(ATTSIZE); for (idx = 0; idx < ATTSIZE; idx++) /* zero the buffer */ *(recBuf+idx) = 0; total_threads = 0; strncpy((char *) recBuf+0, (char *) RecordID, 4); twoptr = (twobyt *) (recBuf+6); *twoptr = ATTSIZE; /* don't have an attrib_count... */ HiSwap((onebyt *) recBuf, 6, 7); twoptr = (twobyt *) (recBuf+8); *twoptr = OURVERS; /* store new record with our rec vers */ HiSwap((onebyt *) recBuf, 8, 9); /* total_threads */ /* BCopy((onebyt *) &total_threads, (onebyt *) recBuf+10, 2, TRUE); */ *(recBuf+12) = 0; /* reserved1 */ *(recBuf+13) = 0; BCopy((onebyt *) &infoptr->fileSysID, (onebyt *) recBuf+14, 2, TRUE); BCopy((onebyt *) &infoptr->fileSysInfo, (onebyt *) recBuf+16, 1, TRUE); *(recBuf+17) = 0; /* reserved2 */ BCopy((onebyt *) &infoptr->fAccess, (onebyt *) recBuf+18, 4, TRUE); BCopy((onebyt *) &infoptr->fileType, (onebyt *) recBuf+22, 4, TRUE); BCopy((onebyt *) &infoptr->auxType, (onebyt *) recBuf+26, 4, TRUE); BCopy((onebyt *) &infoptr->create_dt, (onebyt *) recBuf+32, sizeof(Time), FALSE); BCopy((onebyt *) &infoptr->mod_dt, (onebyt *) recBuf+40, sizeof(Time), FALSE); BCopy((onebyt *) GetTime(), (onebyt *) recBuf+48, sizeof(Time), FALSE); twoptr = (twobyt *) (recBuf + (ATTSIZE - 2)); *twoptr = strlen(infoptr->store_name); /* correct strlen ordering */ HiSwap((onebyt *) recBuf, ATTSIZE-2, ATTSIZE-1); thread[0].thread_class = 0x0002; /* data */ HiSwap((onebyt *) &thread[0].thread_class, 0, 1); thread[0].thread_kind = diskData ? 0x0001 : 0x0000; /* disk or data fork */ HiSwap((onebyt *) &thread[0].thread_kind, 0, 1); thread[0].thread_format = 0x0000; /* filled in later */ thread[0].thread_crc = 0x0000; /* not supported yet */ /* so I don't forget if I support these */ HiSwap((onebyt *) &thread[0].thread_crc, 0, 1); thread[0].thread_eof = infoptr->eof; HiSwap((onebyt *) &thread[0].thread_eof, 0, 3); HiSwap((onebyt *) &thread[0].thread_eof, 1, 2); thread[0].comp_thread_eof = -1L; /* filled in later */ total_threads++; BCopy((onebyt *) &total_threads, (onebyt *) recBuf+10, 4, TRUE); /* * Because we don't know CRCs or compressed size yet, we must: * skip record entry and filename. * for each thread: * skip thread entry, write data, move back, write thread entry. * move back, write record entry and filename. * move forward to next position. */ if ((srcfd = open(infoptr->pathname, O_RDONLY | O_BINARY)) < 0) Fatal("Unable to open file", procName); recposn = lseek(arcfd, (off_t) 0, S_REL); /* save record posn */ if (lseek(arcfd, (off_t) (ATTSIZE + strlen(infoptr->store_name)), S_REL)<0) Fatal("Bad seek (R.rel)", procName); /* loop... */ thposn = lseek(arcfd, (off_t) 0, S_REL); /* save thread posn */ if (lseek(arcfd, (off_t) THsize, S_REL) < 0) Fatal("Bad seek (Th)", procName); /* * since we can store files as being packed without actually packing them, * we need to check "dopack" to see if we want packMethod or zero. Note * that packing can fail for various reasons; the value returned by * PackFile() is the actual algorithm used to pack the file. * * NuLib uses version 0 records; thread_crcs are not stored. */ thread[0].thread_format = PackFile(srcfd,arcfd, infoptr->eof, dopack ? packMethod:0, pakbuf); if (!dopack) thread[0].thread_format = packMethod; /* for S subopt */ HiSwap((onebyt *) &thread[0].thread_format, 0, 1); thread[0].comp_thread_eof = (fourbyt) packedSize; HiSwap((onebyt *) &thread[0].comp_thread_eof, 0, 3); /* correct ordering*/ HiSwap((onebyt *) &thread[0].comp_thread_eof, 1, 2); tmpposn = lseek(arcfd, (off_t) 0, S_REL); if (lseek(arcfd, (off_t) thposn, S_ABS) < 0) /* seek back to thread posn */ Fatal("Bad seek (Th2)", procName); if (write(arcfd, &thread[0], THsize) < THsize) /* write updated thread */ Fatal("Unable to write thread", procName); if (lseek(arcfd, (off_t)tmpposn, S_ABS) < 0) /*seek back to where we were*/ Fatal("Bad seek (TmpA)", procName); /* ...loop end */ if (close(srcfd) < 0) Fatal("Unable to close file", procName); CRC = CalcCRC(0, (onebyt *) recBuf+6, ATTSIZE-6); CRC = CalcCRC(CRC, (onebyt *) infoptr->store_name, strlen(infoptr->store_name)); CRC = CalcCRC(CRC, (onebyt *) &thread[0], THsize); twoptr = (twobyt *) (recBuf+4); *twoptr = CRC; HiSwap((onebyt *) recBuf, 4, 5); tmpposn = lseek(arcfd, (off_t) 0, S_REL); /* record posn (next posn) */ if (lseek(arcfd, (off_t)recposn, S_ABS) < 0) /* seek back to record entry */ Fatal("Bad seek (R.abs)", procName); if (write(arcfd, recBuf, ATTSIZE) < ATTSIZE) Fatal("Unable to write record", procName); if (write(arcfd, infoptr->store_name, strlen(infoptr->store_name)) < strlen(infoptr->store_name)) Fatal("Unable to store filename", procName); if (lseek(arcfd, (off_t)tmpposn, S_ABS) < 0) /*seek back to where we were */ Fatal("Bad seek (TmpB)", procName); if (verbose) printf("done.\n"); free(recBuf); /* switch ordering back */ HiSwap((onebyt *) &thread[0].comp_thread_eof, 0, 3); HiSwap((onebyt *) &thread[0].comp_thread_eof, 1, 2); return ( (long) (THsize * total_threads) + (long) ATTSIZE + (long) strlen(infoptr->store_name) + thread[0].comp_thread_eof); } /* * Certain options can cause an archive to be created (add, create, move). * If the archive does not already exist, then an empty file is created (of * type $e0/8002 under ProDOS) and an empty archive struct is built. * * Note that this requires certain options to deal with archive structures that * do not have any records, and archive files that are empty. * * If the file exists, this will call NuRead() to read it; otherwise, it will * create it. */ static ListHdr * #ifdef __STDC__ CreateMaybe(char *filename) #else CreateMaybe(filename) char *filename; #endif { ListHdr *archive; MHblock *MHptr; onebyt *bufPtr; #if 0 twobyt *twoptr; #endif fourbyt *fourptr; int idx; #ifdef APW FileRec create_p; #endif #if 0 static char *procName = "CreateMaybe"; #endif if (Exists(filename)) { archive = NuRead(filename); return (archive); } if (!docreate) printf("Archive does not exist; creating archive file...\n"); archive = (ListHdr *) Malloc(sizeof(ListHdr)); archive->arc_name = (char *) Malloc(strlen(filename)+1); strcpy(archive->arc_name, filename); archive->MHptr = (MHblock *) Malloc(sizeof(MHblock)); archive->RNodePtr = (RNode *) NULL; archive->nextposn = (long) MHsize; bufPtr = (onebyt *) archive->MHptr; for (idx = 0; idx < MHsize; idx++) *(bufPtr+idx) = '\0'; /* total_records -> zero */ MHptr = archive->MHptr; strncpy((char *) MHptr->ID, (char *) MasterID, 6); BCopy((onebyt *) GetTime(), (onebyt *) &(MHptr->arc_create_when),8, FALSE); BCopy((onebyt *) bufPtr+12, (onebyt *) &(MHptr->arc_mod_when), 8, FALSE); fourptr = (fourbyt *) (&(MHptr->master_eof)); *fourptr = (fourbyt) MHsize; /* twoptr = (twobyt *) (&(MHptr->master_crc)); *twoptr = CalcCRC(0, (onebyt *) bufPtr+8, MHsize-8); */ ArcfiCreate(filename); /* create SHK file */ return (archive); } /* * Return a pointer to a valid Master Header block * Anything that isn't set to a default value needs to be passed as a * parameter [ right now I can't remember why ]. */ onebyt * #ifdef __STDC__ MakeMHblock (ListHdr *archive, fourbyt total_records, fourbyt master_eof) #else MakeMHblock(archive, total_records, master_eof) ListHdr *archive; fourbyt total_records; fourbyt master_eof; #endif { static onebyt buf[MHsize]; /* must be static */ twobyt *twoptr; #if 0 static char *procName = "MakeMHblock"; #endif int idx; for (idx = 0; idx < MHsize ; idx++) buf[idx] = '\0'; /* messy... should've used MHptr->thing here, but if it ain't broke... */ strncpy((char *) buf, (char *) MasterID, 6); BCopy((onebyt *) &total_records, (onebyt *) &buf[8], 4, TRUE); BCopy((onebyt *) &archive->MHptr->arc_create_when, (onebyt *) &buf[12], sizeof(Time), FALSE); BCopy((onebyt *) GetTime(), (onebyt *) &buf[20], sizeof(Time), FALSE); twoptr = (twobyt *) &buf[28]; /* master version */ *twoptr = OURMVERS; HiSwap((onebyt *) buf, 28, 29); /* correct byte ordering */ BCopy((onebyt *) &master_eof, (onebyt *) &buf[38], 4, TRUE); twoptr = (twobyt *) &buf[6]; *twoptr = CalcCRC(0, (onebyt *) &buf[8], MHsize-8); HiSwap((onebyt *) buf, 6, 7); return (buf); } /* * Add files to archive * * Read files from disk, adding them to the end of the archive as we go. * Update the master header block after all files have been added. * * Upon entry, is the name of the shrinkit archive. * is the number of files (to add) given on the command line, * and is an array of those file names. */ static void #ifdef __STDC__ Add (char *filename, int namecount, char **names) #else Add(filename, namecount, names) char *filename; int namecount; char **names; #endif { ListHdr *archive; int arcfd; #if 0 file_info *FIArray[MAXARGS]; /* entries malloc()ed by EvalArgs */ #else fileInfoArray FIArray = NULL; #endif int idx; onebyt *mptr; /* points to a MHblock suitable for writing */ long addSize; static char *procName = "Add"; FIArray = newFileArray(); /* expand wildcards/subdirectories, and get file info */ namecount = EvalArgs(namecount, names, FIArray, TRUE); if (!namecount) { if (verbose) printf("No files selected.\n"); QuitNulib (0); } assert(namecount == FIArray->used); archive = CreateMaybe(filename); if ((arcfd = open(archive->arc_name, O_RDWR | O_BINARY)) < 0) Fatal("Unable to open archive", procName); if (lseek(arcfd, (off_t)archive->nextposn, S_ABS) < 0) /* seek to end */ Fatal("Unable to seek in archive", procName); for (idx = 0 ; idx < namecount; idx++) { #ifdef __appleiigs__ if (!GnoActive && STOP_KEY()) QuitNulib(1); /* check for OA-. */ #endif addSize = AddFile(arcfd, FIArray->vec[idx]); archive->MHptr->master_eof += addSize; archive->nextposn += addSize; archive->MHptr->total_records++; } mptr = MakeMHblock(archive, archive->MHptr->total_records, archive->MHptr->master_eof); if (lseek(arcfd, (off_t) 0, S_ABS) < 0) Fatal("Unable to rewind archive for master header", procName); if (write(arcfd, mptr, MHsize) < MHsize) Fatal("Unable to update master header", procName); if (close(arcfd) < 0) Fatal("Unable to close archive", procName); if (domove) { if (verbose) printf("Deleteing files...\n"); for (idx = 0; idx < namecount; idx++) { if (verbose) { printf("%s...", FIArray->vec[idx]->pathname); fflush(stdout); } if (unlink(FIArray->vec[idx]->pathname) < 0) { if (verbose) printf("failed.\n"); } else { if (verbose) printf("done.\n"); } } } } /* * Main entry point for adding files. */ void #ifdef __STDC__ NuAdd (char *filename, int namecount, char **names, char *options) #else NuAdd(filename, namecount, names, options) char *filename; int namecount; char **names; char *options; #endif { #if 0 char *optr; int idx; char type[5]; static char *procName = "NuAdd"; #endif if (*options == 'm') domove = TRUE; if (*options == 'c') docreate = TRUE; /* change T subopt to convert FROM current system TO */ if (transfrom >= 0) { transto = transfrom; transfrom = -1; } Add(filename, namecount, names); /* do main processing */ } /* * newFileArray * * create and initialize an array of file_info pointers. */ fileInfoArray newFileArray __P((void)) { fileInfoArray result; result = xmalloc(sizeof(fileInfoArrayElem)); result->vec = NULL; result->alloced = 0; result->used = 0; return result; } /* * addToFileArray * * maintain an array of file_info pointers */ #define SLOTS_QUANTUM 64 void addToFileArray #ifdef __STDC__ __P((fileInfoArray array, file_info_ptr entry)) #else (array, entry) fileInfoArray array; file_info_ptr entry; #endif { assert(array); assert(array->used <= array->alloced); if (entry == NULL) return; /* grow the size of the array, if necessary */ if (array->alloced - array->used < 2) { array->alloced+=SLOTS_QUANTUM; array->vec = xrealloc(array->vec, array->alloced * sizeof(file_info_ptr)); } /* add in the entry */ array->vec[array->used] = entry; array->used++; array->vec[array->used] = NULL; return; } stringArray newStringArray __P((void)) { stringArray result; result = xmalloc(sizeof(stringArrayElem)); result->vec = NULL; result->alloced = 0; result->used = 0; return result; } void #ifdef __STDC__ clearStringArray __P((stringArray array)) #else clearStringArray (array) stringArray array; #endif { int i; for (i=0; iused; i++) { free(array->vec[i]); } free(array->vec); array->vec = NULL; array->alloced = 0; array->used = 0; } void addToStringArray #ifdef __STDC__ __P((stringArray array, char *entry)) #else (array, entry) stringArray array; char *entry; #endif { assert(array); assert(array->used <= array->alloced); if (entry == NULL) return; /* grow the size of the array, if necessary */ if (array->alloced - array->used < 2) { array->alloced+=SLOTS_QUANTUM; array->vec = xrealloc(array->vec, array->alloced * sizeof(char *)); } /* add in the entry */ array->vec[array->used] = xstrdup(entry); array->used++; array->vec[array->used] = NULL; return; } void * #ifdef __STDC__ xmalloc __P((size_t size)) #else xmalloc (size) size_t size; #endif { char *p; if ((p = malloc(size)) == NULL) { perror("xmalloc failed"); exit(-1); } return (void *) p; } void * #ifdef __STDC__ xrealloc __P((void *ptr, size_t size)) #else xrealloc (ptr, size) void *ptr; size_t size; #endif { char *p; /* some reallocs are broken when passed a NULL pointer; ensure it works */ if (ptr == NULL) { p = malloc(size); } else { p = realloc(ptr, size); } if (p == NULL) { perror("xrealloc failed"); exit(-1); } return p; } char * #ifdef __STDC__ xstrdup __P((const char *str)) #else xstrdup (str) const char *str; #endif { char *result; if ((result = malloc(strlen(str) + 1)) == NULL) { perror("xstrdup failed"); exit(-1); } strcpy (result, str); return result; } nulib/nuadd.h100644 765 144 3657 6246126406 11635 0ustar gdrusers/* * nuadd.h - declarations for nuadd.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuadd.h,v 1.3 1996/11/03 23:01:02 gdr Exp $ */ /* information is copied from file-dependent structures (FileRec) to here */ typedef struct file_info { char *pathname; /* as much of the path as we need to know */ char *store_name; /* what name the file will be stored under */ fourbyt eof; /* length of file */ fourbyt fAccess; /* was Word */ fourbyt fileType; /* was Word */ fourbyt auxType; twobyt storageType; Time create_dt; /* Time = TimeRec = 8 bytes in misctool.h/nuread.h */ Time mod_dt; twobyt fileSysID; /* these two are non-standard */ onebyt fileSysInfo; int marked; /* application specific */ } file_info, *file_info_ptr; typedef struct fileInfoArrayElem { file_info_ptr *vec; int alloced; int used; } fileInfoArrayElem, *fileInfoArray; typedef struct stringArrayElem { char **vec; int alloced; int used; } stringArrayElem, *stringArray; /* #define MAXARGS 255 *//* max #of files specified on command line; signed int */ extern void NuAdd __P((char *filename, int namecount, char **names, char *options)); extern long AddFile __P((int arcfd, file_info *infoptr)); extern onebyt *MakeMHblock __P((ListHdr *archive, fourbyt total_records, fourbyt master_eof)); extern int EvalArgs __P((int count, char **names, fileInfoArray FIArray, BOOLEAN first)); extern int OptNum __P((char *ptr)); extern void addToFileArray __P((fileInfoArray array, file_info_ptr entry)); extern void addToStringArray __P((stringArray array, char *entry)); extern fileInfoArray newFileArray __P((void)); extern stringArray newStringArray __P((void)); extern void clearStringArray __P((stringArray array)); extern void *xmalloc __P((size_t)); extern void *xrealloc __P((void *, size_t)); extern char *xstrdup __P((const char *str)); nulib/nucomp.c100644 765 144 76567 6247227101 12063 0ustar gdrusers/* * nucomp.c - code to perform UNIX style LZW compression * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * This is the main compression code from compress v4.3. Modifications * have been made to integrate it with NuLib (primarily in that it no longer * uses stdin/stdout), but it's functionally the same. * * $Id: nucomp.c,v 1.4 1996/11/28 06:16:33 gdr Exp $ */ #define SEGMENT_NAME "Compress2_" #include "nudefs.h" #include #include #ifdef UNIX #include #endif #if defined(__ORCAC__) && !defined(__GNO__) extern FILE *fdopen (int, char *); #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuread.h" #include "nupak.h" #include "nuetc.h" #define MAIN /* cause nucomp.h to alloc global vars */ /*@H************************ < COMPRESS API > **************************** * * * compress : compapi.c * * * * port by : Donald J. Gloistein * * * * Source, Documentation, Object Code: * * released to Public Domain. This code is based on code as documented * * below in release notes. * * * *--------------------------- Module Description --------------------------* * Contains source code for modified Lempel-Ziv method (LZW) compression * * and decompression. * * * * This code module can be maintained to keep current on releases on the * * Unix system. The command shell and dos modules can remain the same. * * * *--------------------------- Implementation Notes --------------------------* * * * compiled with : compress.h compress.fns compress.c * * linked with : compress.obj compusi.obj * * * * problems: * * * * * * CAUTION: Uses a number of defines for access and speed. If you change * * anything, make sure about side effects. * * * * Compression: * * Algorithm: use open addressing double hashing (no chaining) on the * * prefix code / next character combination. We do a variant of Knuth's * * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime * * secondary probe. Here, the modular division first probe is gives way * * to a faster exclusive-or manipulation. * * Also block compression with an adaptive reset was used in original code, * * whereby the code table is cleared when the compression ration decreases * * but after the table fills. This was removed from this edition. The table * * is re-sized at this point when it is filled , and a special CLEAR code is * * generated for the decompressor. This results in some size difference from * * straight version 4.0 joe Release. But it is fully compatible in both v4.0 * * and v4.01 * * * * Decompression: * * This routine adapts to the codes in the file building the "string" table * * on-the-fly; requiring no table to be stored in the compressed file. The * * tables used herein are shared with those of the compress() routine. * * * * Initials ---- Name --------------------------------- * * DjG Donald J. Gloistein, current port to MsDos 16 bit * * Plus many others, see rev.hst file for full list * * LvR Lyle V. Rains, many thanks for improved implementation * * of the compression and decompression routines. * *************************************************************************@H*/ #include #define assert(x) #include "nucomp.h" /* contains the rest of the include file declarations */ FILE *nustdin, *nustdout; /* NuLib: use these instead of stdin/stdout */ long nubytes_read, nucomp_thread_eof; /* NuLib: used in nextcode (decomp) */ /* NuLib: pulled this out of nextcode() so we can initialize it every time */ static int prevbits = 0; /* NuLib: pulled out of putcode() */ static int oldbits = 0; static int offset; static long int in_count ; /* length of input */ static long int bytes_out; /* length of compressed output */ static long int max_bytes_out; /* NuLib: max #of bytes to output */ static CODE prefxcode, nextfree; static CODE highcode; static CODE maxcode; static HASH hashsize; static int bits; /* * The following two parameter tables are the hash table sizes and * maximum code values for various code bit-lengths. The requirements * are that Hashsize[n] must be a prime number and Maxcode[n] must be less * than Maxhash[n]. Table occupancy factor is (Maxcode - 256)/Maxhash. * Note: I am using a lower Maxcode for 16-bit codes in order to * keep the hash table size less than 64k entries. */ CONST HASH hs[] = { 0x13FF, /* 12-bit codes, 75% occupancy */ 0x26C3, /* 13-bit codes, 80% occupancy */ 0x4A1D, /* 14-bit codes, 85% occupancy */ 0x8D0D, /* 15-bit codes, 90% occupancy */ 0xFFD9 /* 16-bit codes, 94% occupancy, 6% of code values unused */ }; #define Hashsize(maxb) (hs[(maxb) -MINBITS]) CONST CODE mc[] = { 0x0FFF, /* 12-bit codes */ 0x1FFF, /* 13-bit codes */ 0x3FFF, /* 14-bit codes */ 0x7FFF, /* 15-bit codes */ 0xEFFF /* 16-bit codes, 6% of code values unused */ }; #define Maxcode(maxb) (mc[(maxb) -MINBITS]) #define allocx(type,myPtr,size) \ (((myPtr) = (type FAR *) emalloc((unsigned int)(size),sizeof(type))) == NULLPTR(type) \ ? NOMEM : OK \ ) #define free_array(type,myPtr,offset) \ if (myPtr != NULLPTR(type)) { \ efree((ALLOCTYPE FAR *)((myPtr) + (offset))); \ (myPtr) = NULLPTR(type); \ } /* * Macro to allocate new memory to a pointer with an offset value. */ #define alloc_array(type, myPtr, size, offset) \ ( allocx(type, myPtr, (size) - (offset)) != OK \ ? NOMEM \ : (((myPtr) -= (offset)), OK) \ ) static char FAR *sfx = NULLPTR(char) ; #define suffix(code) sfx[code] #ifdef SPLIT_PFX static CODE FAR *pfx[2] = {NULLPTR(CODE), NULLPTR(CODE)}; #else static CODE FAR *pfx = NULLPTR(CODE); #endif #ifdef SPLIT_HT static CODE FAR *ht[2] = {NULLPTR(CODE),NULLPTR(CODE)}; #else static CODE FAR *ht = NULLPTR(CODE); #endif int #ifdef __STDC__ alloc_tables (CODE maxcode, HASH hashsize) #else alloc_tables(maxcode, hashsize) CODE maxcode; HASH hashsize; #endif { static CODE oldmaxcode = 0; static HASH oldhashsize = 0; if (hashsize > oldhashsize) { #ifdef SPLIT_HT free_array(CODE,ht[1], 0); free_array(CODE,ht[0], 0); #else free_array(CODE,ht, 0); #endif oldhashsize = 0; } if (maxcode > oldmaxcode) { #ifdef SPLIT_PFX free_array(CODE,pfx[1], 128); free_array(CODE,pfx[0], 128); #else free_array(CODE,pfx, 256); #endif free_array(char,sfx, 256); if ( alloc_array(char, sfx, maxcode + 1, 256) #ifdef SPLIT_PFX || alloc_array(CODE, pfx[0], (maxcode + 1) / 2, 128) || alloc_array(CODE, pfx[1], (maxcode + 1) / 2, 128) #else || alloc_array(CODE, pfx, (maxcode + 1), 256) #endif ) { oldmaxcode = 0; exit_stat = NOMEM; return(NOMEM); } oldmaxcode = maxcode; } if (hashsize > oldhashsize) { if ( #ifdef SPLIT_HT alloc_array(CODE, ht[0], (hashsize / 2) + 1, 0) || alloc_array(CODE, ht[1], hashsize / 2, 0) #else alloc_array(CODE, ht, hashsize, 0) #endif ) { oldhashsize = 0; exit_stat = NOMEM; return(NOMEM); } oldhashsize = hashsize; } return (OK); } # ifdef SPLIT_PFX /* * We have to split pfx[] table in half, * because it's potentially larger than 64k bytes. */ # define prefix(code) (pfx[(code) & 1][(code) >> 1]) # else /* * Then pfx[] can't be larger than 64k bytes, * or we don't care if it is, so we don't split. */ # define prefix(code) (pfx[code]) # endif /* The initializing of the tables can be done quicker with memset() */ /* but this way is portable through out the memory models. */ /* If you use Microsoft halloc() to allocate the arrays, then */ /* include the pragma #pragma function(memset) and make sure that */ /* the length of the memory block is not greater than 64K. */ /* This also means that you MUST compile in a model that makes the */ /* default pointers to be far pointers (compact or large models). */ /* See the file COMPUSI.DOS to modify function emalloc(). */ # ifdef SPLIT_HT /* * We have to split ht[] hash table in half, * because it's potentially larger than 64k bytes. */ # define probe(hash) (ht[(hash) & 1][(hash) >> 1]) # define init_tables() \ { \ hash = hashsize >> 1; \ ht[0][hash] = 0; \ while (hash--) ht[0][hash] = ht[1][hash] = 0; \ highcode = ~(~(CODE)0 << (bits = INITBITS)); \ nextfree = (block_compress ? FIRSTFREE : 256); \ } # else /* * Then ht[] can't be larger than 64k bytes, * or we don't care if it is, so we don't split. */ # define probe(hash) (ht[hash]) # define init_tables() \ { \ hash = hashsize; \ while (hash--) ht[hash] = 0; \ highcode = ~(~(CODE)0 << (bits = INITBITS)); \ nextfree = (block_compress ? FIRSTFREE : 256); \ } # endif #ifdef COMP40 /* table clear for block compress */ /* this is for adaptive reset present in version 4.0 joe release */ /* DjG, sets it up and returns TRUE to compress and FALSE to not compress */ int #ifdef __STDC__ cl_block (void) #else cl_block () #endif { register long int rat; checkpoint = in_count + CHECK_GAP; #ifndef NDEBUG if ( debug ) { fprintf ( stderr, "count: %ld, ratio: ", in_count ); prratio ( stderr, in_count, bytes_out ); fprintf ( stderr, "\n"); } #endif if(in_count > 0x007fffff) { /* shift will overflow */ rat = bytes_out >> 8; if(rat == 0) /* Don't divide by zero */ rat = 0x7fffffff; else rat = in_count / rat; } else rat = (in_count << 8) / bytes_out; /* 8 fractional bits */ if ( rat > ratio ){ ratio = rat; return FALSE; } else { ratio = 0; #ifndef NDEBUG if(debug) fprintf ( stderr, "clear\n" ); #endif return TRUE; /* clear the table */ } #if defined(__GNUC__) /* lcc and HAL hcc are smart enough to not need it */ return FALSE; /* don't clear the table */ #endif /*NOTREACHED*/ } #endif /*COMP40*/ /* * compress stdin to stdout <-- nope * NuLib: compress thread_eof bytes from srcfd, writing to dstfd * Sets up a few things and then calls u_compress. */ int #ifdef __STDC__ u_compress (int srcfd, int dstfd, long thread_eof) #else u_compress(srcfd, dstfd, thread_eof) int srcfd, dstfd; long thread_eof; #endif { int src2, dst2; long srcposn, dstposn; static char *procName = "u_compress"; if ((srcposn = (long) lseek(srcfd, (off_t) 0, S_REL)) < 0) Fatal("Bad posn lseek(1)", procName); if ((dstposn = (long) lseek(dstfd, (off_t) 0, S_REL)) < 0) Fatal("Bad posn lseek(2)", procName); src2 = dup(srcfd); dst2 = dup(dstfd); /* NuLib: open new stdin/stdout, and seek */ if ((nustdin = fdopen(src2, FREAD_STR)) == NULL) Fatal("can't fdopen() nustdin", procName); if ((nustdout = fdopen(dst2, FWRITE_STR)) == NULL) Fatal("can't fdopen() nustdout", procName); setvbuf(nustdin,xbuf,_IOFBF,XBUFSIZE); /* make the buffers larger */ setvbuf(nustdout,zbuf,_IOFBF,ZBUFSIZE); /* (note setvbuf is a macro) */ if (fseek(nustdin, (off_t)srcposn, S_ABS) < 0) /* seek may not be needed */ Fatal("Bad stream posn lseek(1)", procName); if (fseek(nustdout, (off_t)dstposn, S_ABS) < 0) Fatal("Bad stream posn lseek(2)", procName); oldbits = 0; /* init for putcode() */ compress(thread_eof); check_error(); fclose(nustdin); /* note this closes the duped fd */ fclose(nustdout); return (exit_stat); } void #ifdef __STDC__ compress(long thread_eof) #else compress(thread_eof) long thread_eof; #endif { int c,adjbits; register HASH hash; register CODE code; HASH hashf[256]; max_bytes_out = thread_eof; /* NuLib: don't exceed original size */ maxcode = Maxcode(maxbits); hashsize = Hashsize(maxbits); #ifdef COMP40 /* Only needed for adaptive reset */ checkpoint = CHECK_GAP; ratio = 0; #endif adjbits = maxbits -10; for (c = 256; --c >= 0; ){ hashf[c] = ((( c &0x7) << 7) ^ c) << adjbits; } exit_stat = OK; if (alloc_tables(maxcode, hashsize)) /* exit_stat already set */ return; init_tables(); /* if not zcat or filter (NuLib: never happens) */ if(is_list && !zcat_flg) { /* Open output file */ if (freopen(ofname, WRITE_FILE_TYPE, nustdout) == NULL) { exit_stat = NOTOPENED; return; } if (!quiet) fprintf(stderr, "%s: ",ifname); setvbuf(nustdout,zbuf,_IOFBF,ZBUFSIZE); } /* * Check the input stream for previously seen strings. We keep * adding characters to the previously seen prefix string until we * get a character which forms a new (unseen) string. We then send * the code for the previously seen prefix string, and add the new * string to our tables. The check for previous strings is done by * hashing. If the code for the hash value is unused, then we have * a new string. If the code is used, we check to see if the prefix * and suffix values match the current input; if so, we have found * a previously seen string. Otherwise, we have a hash collision, * and we try secondary hash probes until we either find the current * string, or we find an unused entry (which indicates a new string). */ if (!nomagic) { putc(magic_header[0], nustdout); /* was putchar() */ putc(magic_header[1], nustdout); /* was putchar() */ putc((char)(maxbits | block_compress), nustdout); /*was putchar*/ if(ferror(nustdout)){ /* check it on entry */ exit_stat = WRITEERR; return; } bytes_out = 3L; /* includes 3-byte header mojo */ } else bytes_out = 0L; /* no 3-byte header mojo */ in_count = 1L; offset = 0; if ((c = getc(nustdin)) == EOF) { /* NuLib: was getchar() */ exit_stat = ferror(nustdin) ? READERR : OK; return; } prefxcode = (CODE)c; while ((c = getc(nustdin)) != EOF) { /* NuLib: was getchar() */ in_count++; /* NuLib : May not be compressing entire file, so can't rely on EOF for end */ if (in_count > thread_eof) break; hash = prefxcode ^ hashf[c]; /* I need to check that my hash value is within range * because my 16-bit hash table is smaller than 64k. */ if (hash >= hashsize) hash -= hashsize; if ((code = probe(hash)) != UNUSED) { if (suffix(code) != (char)c || prefix(code) != prefxcode) { /* hashdelta is subtracted from hash on each iteration of * the following hash table search loop. I compute it once * here to remove it from the loop. */ HASH hashdelta = (0x120 - c) << (adjbits); do { /* rehash and keep looking */ assert(code >= FIRSTFREE && code <= maxcode); if (hash >= hashdelta) hash -= hashdelta; else hash += (hashsize - hashdelta); assert(hash < hashsize); if ((code = probe(hash)) == UNUSED) goto newcode; } while (suffix(code) != (char)c || prefix(code) != prefxcode); } prefxcode = code; } else { newcode: { putcode(prefxcode, bits); code = nextfree; assert(hash < hashsize); assert(code >= FIRSTFREE); assert(code <= maxcode + 1); if (code <= maxcode) { probe(hash) = code; prefix(code) = prefxcode; suffix(code) = (char)c; if (code > highcode) { highcode += code; ++bits; } nextfree = code + 1; } #ifdef COMP40 else if (in_count >= checkpoint && block_compress ) { if (cl_block()){ #else else if (block_compress){ #endif putcode((CODE)c, bits); putcode((CODE)CLEAR,bits); init_tables(); if ((c = getc(nustdin)) == EOF) /* NuLib: was getchar*/ break; in_count++; #ifdef COMP40 } #endif } prefxcode = (CODE)c; } } } putcode(prefxcode, bits); putcode((CODE)CLEAR, 0); if (ferror(nustdout)){ /* check it on exit */ exit_stat = WRITEERR; return; } /* * Print out stats on stderr */ if(zcat_flg == 0 && !quiet) { #ifndef NDEBUG fprintf( stderr, "%ld chars in, (%ld bytes) out, compression factor: ", in_count, bytes_out ); prratio( stderr, in_count, bytes_out ); fprintf( stderr, "\n"); fprintf( stderr, "\tCompression as in compact: " ); prratio( stderr, in_count-bytes_out, in_count ); fprintf( stderr, "\n"); fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n", prefxcode - 1, bits ); #else fprintf( stderr, "Compression: " ); prratio( stderr, in_count-bytes_out, in_count ); #endif /* NDEBUG */ } if(bytes_out > in_count) /* if no savings */ exit_stat = NOSAVING; packedSize = bytes_out; /* NuLib : return packed size in global */ return ; } CONST UCHAR rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; void #ifdef __STDC__ putcode (CODE code, register int bits) #else putcode(code,bits) CODE code; register int bits; #endif { static UCHAR outbuf[MAXBITS]; register UCHAR *buf; register int shift; register int ok_to_write; /* NuLib (kludge... sorry) */ ok_to_write = (exit_stat != NOSAVING); if (bits != oldbits) { if (bits == 0) { /* bits == 0 means EOF, write the rest of the buffer. */ if (offset > 0) { int x = ((offset+7) >> 3); /* NuLib */ if ((bytes_out + x) > max_bytes_out) { /* NuLib */ /* compression failed. There's no clean way of bailing out * (could use setjmp/longjmp, but that may not be supported * on all systems), so just don't write anything. */ exit_stat = NOSAVING; ok_to_write = FALSE; } else { /* fwrite(outbuf,1,(offset +7) >> 3, nustdout);*/ fwrite(outbuf,1, x, nustdout); } /* bytes_out += ((offset +7) >> 3);*/ bytes_out += x; } offset = 0; oldbits = 0; fflush(nustdout); return; } else { /* Change the code size. We must write the whole buffer, * because the expand side won't discover the size change * until after it has read a buffer full. */ if (offset > 0) { if (ok_to_write) fwrite(outbuf, 1, oldbits, nustdout); bytes_out += oldbits; offset = 0; } oldbits = bits; #ifndef NDEBUG if ( debug ) fprintf( stderr, "\nChange to %d bits\n", bits ); #endif /* !NDEBUG */ } } /* Get to the first byte. */ buf = outbuf + ((shift = offset) >> 3); if ((shift &= 7) != 0) { *(buf) |= (*buf & rmask[shift]) | (UCHAR)(code << shift); *(++buf) = (UCHAR)(code >> (8 - shift)); if (bits + shift > 16) *(++buf) = (UCHAR)(code >> (16 - shift)); } else { /* Special case for fast execution */ *(buf) = (UCHAR)code; *(++buf) = (UCHAR)(code >> 8); } if ((offset += bits) == (bits << 3)) { bytes_out += bits; if (ok_to_write) fwrite(outbuf,1,bits,nustdout); offset = 0; } return; } int #ifdef __STDC__ nextcode(CODE *codeptr) #else nextcode(codeptr) CODE *codeptr; #endif /* Get the next code from input and put it in *codeptr. * Return (TRUE) on success, or return (FALSE) on end-of-file. * Adapted from COMPRESS V4.0. */ { register CODE code; static int size; static UCHAR inbuf[MAXBITS]; register int shift; UCHAR *bp; /* If the next entry is a different bit-size than the preceeding one * then we must adjust the size and scrap the old buffer. */ if (prevbits != bits) { prevbits = bits; size = 0; } /* If we can't read another code from the buffer, then refill it. */ if (size - (shift = offset) < bits) { static int bytesize; /* NuLib: sigh */ /* Read more input and convert size from # of bytes to # of bits */ /* NuLib: stop after comp_thread_eof bytes */ if (nubytes_read >= nucomp_thread_eof) return(NO); /* NuLib: replace old fread command with... */ /* if ((size = fread(inbuf, 1, bits, nustdin) << 3) <= 0 || ferror(nustdin)) return(NO); */ bytesize = fread(inbuf, 1, bits, nustdin); if (nubytes_read + bits > nucomp_thread_eof) { bytesize = nucomp_thread_eof - nubytes_read; } size = bytesize << 3; if (size <= 0 || ferror(nustdin)) return (NO); /* NuLib: increment nubytes_read */ nubytes_read += (long) bytesize; offset = shift = 0; } /* Get to the first byte. */ bp = inbuf + (shift >> 3); /* Get first part (low order bits) */ code = (*bp++ >> (shift &= 7)); /* high order bits. */ code |= *bp++ << (shift = 8 - shift); if ((shift += 8) < bits) code |= *bp << shift; *codeptr = code & highcode; offset += bits; return (TRUE); } /* * NuLib: uncompress comp_thread_eof bytes from srcfd, writing to dstfd * Sets up a few things and then calls compress. */ int #ifdef __STDC__ u_decompress (int srcfd, int dstfd, long comp_thread_eof) #else u_decompress(srcfd, dstfd, comp_thread_eof) int srcfd, dstfd; long comp_thread_eof; #endif { int src2, dst2; long srcposn, dstposn; static char *procName = "u_decompress"; if ((srcposn = (long)lseek(srcfd, (off_t) 0, S_REL)) < 0) Fatal("Bad posn lseek(1)", procName); if ((dstposn = (long)lseek(dstfd, (off_t) 0, S_REL)) < 0) Fatal("Bad posn lseek(2)", procName); src2 = dup(srcfd); dst2 = dup(dstfd); /* NuLib: open new stdin/stdout, and seek */ if ((nustdin = fdopen(src2, FREAD_STR)) == NULL) Fatal("can't fdopen() nustdin", procName); if ((nustdout = fdopen(dst2, FWRITE_STR)) == NULL) Fatal("can't fdopen() nustdout", procName); setvbuf(nustdin,zbuf,_IOFBF,ZBUFSIZE); /* make the buffers larger */ setvbuf(nustdout,xbuf,_IOFBF,XBUFSIZE); /* (note order diff from comp) */ if (fseek(nustdin, (off_t)srcposn, S_ABS) < 0) /* seek may not be needed */ Fatal("Bad stream posn lseek(1)", procName); if (fseek(nustdout, (off_t)dstposn, S_ABS) < 0) Fatal("Bad stream posn lseek(2)", procName); /* Check the magic number */ if (!nomagic) { if ((getc(nustdin)!=(magic_header[0] & 0xFF)) /* NuLib: was getchar*/ || (getc(nustdin)!=(magic_header[1] & 0xFF))) {/* NuLib: was getchar*/ fprintf(stderr, "decompress: not in compressed format\n"); return(-1); /* NuLib: was exit(ERROR) */ } maxbits = getc(nustdin); /* set -b from file (NuLib: was getchar) */ block_compress = maxbits & BLOCK_MASK; maxbits &= BIT_MASK; if(maxbits > MAXBITS) { fprintf(stderr, "decompress: compressed with %d bits, can only handle %d bits\n", maxbits, MAXBITS); return(-1); /* NuLib: was exit(ERROR) */ } nubytes_read = 3L; } else { nubytes_read = 0L; } nucomp_thread_eof = comp_thread_eof; /* printf("src file posn = %ld\n", ftell(nustdin));*/ prevbits = 0; /* init for nextcode() */ decompress(); check_error(); fclose(nustdin); /* note this closes the duped fd */ fclose(nustdout); return (exit_stat); } void #ifdef __STDC__ decompress(void) #else decompress() #endif { register int i; register CODE code; char sufxchar; CODE savecode; FLAG fulltable, cleartable; static char token[MAXTOKLEN]; /* String buffer to build token */ exit_stat = OK; if (alloc_tables(maxcode = ~(~(CODE)0 << maxbits),0)) /* exit_stat already set */ return; /* if not zcat or filter (NuLib: never) */ if(is_list && !zcat_flg) { /* Open output file */ if (freopen(ofname, WRITE_FILE_TYPE, nustdout) == NULL) { exit_stat = NOTOPENED; return; } if (!quiet) fprintf(stderr, "%s: ",ifname); setvbuf(nustdout,xbuf,_IOFBF,XBUFSIZE); } cleartable = TRUE; fulltable = FALSE; savecode = CLEAR; sufxchar = '\0'; offset = 0; do { if ((code = savecode) == CLEAR && cleartable) { highcode = ~(~(CODE)0 << (bits = INITBITS)); fulltable = FALSE; nextfree = (cleartable = block_compress) == FALSE ? 256 : FIRSTFREE; if (!nextcode(&prefxcode)) break; putc((sufxchar = (char)prefxcode), nustdout); continue; } i = 0; if (code >= nextfree && !fulltable) { if (code != nextfree){ exit_stat = CODEBAD; /* fprintf(stderr, "Bad code; nubytes_read = %ld\n", nubytes_read); */ /* CDEBUG */ return ; /* Non-existant code */ } /* Special case for sequence KwKwK (see text of article) */ code = prefxcode; token[i++] = sufxchar; } /* Build the token string in reverse order by chasing down through * successive prefix tokens of the current token. Then output it. */ while (code >= 256) { #ifndef NDEBUG /* These are checks to ease paranoia. Prefix codes must decrease * monotonically, otherwise we must have corrupt tables. We can * also check that we haven't overrun the token buffer. */ if (code <= prefix(code)){ exit_stat= TABLEBAD; return; } if (i >= MAXTOKLEN){ exit_stat = TOKTOOBIG; return; } #endif token[i++] = suffix(code); code = prefix(code); } putc(sufxchar = (char)code, nustdout); while (--i >= 0) putc(token[i], nustdout); if (ferror(nustdout)) { exit_stat = WRITEERR; return; } /* If table isn't full, add new token code to the table with * codeprefix and codesuffix, and remember current code. */ if (!fulltable) { code = nextfree; assert(256 <= code && code <= maxcode); prefix(code) = prefxcode; suffix(code) = sufxchar; prefxcode = savecode; if (code++ == highcode) { if (highcode >= maxcode) { fulltable = TRUE; --code; } else { ++bits; highcode += code; /* nextfree == highcode + 1 */ } } nextfree = code; } } while (nextcode(&savecode)); exit_stat = (ferror(nustdin))? READERR : OK; return ; } /* * These are routines pulled out of "compress.c" from compress v4.3. */ void #ifdef __STDC__ prratio (FILE *stream, long int num, long int den) #else prratio(stream, num, den) FILE *stream; long int num, den; #endif { register int q; /* Doesn't need to be long */ if(num > 214748L) { /* 2147483647/10000 */ q = (int) (num / (den / 10000L)); } else { q = (int) (10000L * num / den); /* Long calculations, though */ } if (q < 0) { putc('-', stream); q = -q; } fprintf(stream, "%d.%02d%%", q / 100, q % 100); } /* * Check exit status from compress() and decompress() * * exit_stat is a global var. Either returns something interesting or * bails out completely. */ int #ifdef __STDC__ check_error (void) #else check_error() /* returning OK continues with processing next file */ #endif { prog_name = prgName; /* NuLib: set prog_name to "nulib" */ switch(exit_stat) { case OK: return (OK); case NOMEM: if (do_decomp) fprintf(stderr,"%s: not enough memory to decompress '%s'.\n", prog_name, ifname); else fprintf(stderr,"%s: not enough memory to compress '%s'.\n", prog_name, ifname); return(OK); case SIGNAL_ERROR: fprintf(stderr,"%s: error setting signal interupt.\n",prog_name); exit(ERROR); break; case READERR: fprintf(stderr,"%s: read error on input '%s'.\n", prog_name, ifname); break; case WRITEERR: fprintf(stderr,"%s: write error on output '%s'.\n", prog_name, ofname); break; case TOKTOOBIG: fprintf(stderr,"%s: token too long in '%s'.\n", prog_name, ifname); break; case INFILEBAD: fprintf(stderr, "%s: '%s' in unknown compressed format.\n", prog_name, ifname); break; case CODEBAD: fprintf(stderr,"%s: file token bad in '%s'.\n", prog_name,ifname); break; case TABLEBAD: fprintf(stderr,"%s: internal error -- tables corrupted.\n", prog_name); break; case NOTOPENED: fprintf(stderr,"%s: could not open output file %s\n",prog_name,ofname); exit(ERROR); break; case NOSAVING: if (force) exit_stat = OK; return (OK); default: fprintf(stderr,"%s: internal error -- illegal return value = %d.\n", prog_name,exit_stat); } if (!zcat_flg && !keep_error){ fclose(nustdout); /* won't get here without an error */ unlink ( ofname ); } exit(exit_stat); return(ERROR); } /* * These are routines from "compusi.c" */ void #ifdef __STDC__ version (void) #else version() #endif { #ifdef XENIX #ifndef NDEBUG fprintf(stderr, "%s\nOptions: Xenix %s MAXBITS = %d\n", rcs_ident, "DEBUG",MAXBITS); #else fprintf(stderr, "%s\nOptions: Xenix MAXBITS = %d\n", rcs_ident,MAXBITS); #endif #else #ifndef NDEBUG fprintf(stderr, "%s\nOptions: Unix %s MAXBITS = %d\n", rcs_ident, "DEBUG",MAXBITS); #else fprintf(stderr, "%s\nOptions: Unix MAXBITS = %d\n", rcs_ident,MAXBITS); #endif #endif } ALLOCTYPE FAR * #ifdef __STDC__ emalloc(unsigned int x, int y) #else emalloc(x,y) unsigned int x; int y; #endif { ALLOCTYPE FAR *p; p = (ALLOCTYPE FAR *)ALLOCATE(x,y); return(p); } void #ifdef __STDC__ efree (ALLOCTYPE FAR *myPtr) #else efree(myPtr) ALLOCTYPE FAR *myPtr; #endif { free(myPtr); } nulib/nublu.h100644 765 144 434 6246126406 11635 0ustar gdrusers/* * nublu.h - declarations for nublu.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nublu.h,v 1.3 1996/11/03 23:01:03 gdr Exp $ */ extern void NuBNY __P((char *filename, int argc, char **argv, char *options)); nulib/nuetc.c100644 765 144 56305 6247241715 11673 0ustar gdrusers/* * nuetc.c - extra stuff; mostly system-dependent subroutines. * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuetc.c,v 1.5 1996/11/28 07:48:29 gdr Exp $ */ #define SEGMENT_NAME "NuMain____" #include "nudefs.h" #include #include /* exit(), etc. */ #include #include #include /* errno declarations */ #include /* for tolower(), isupper() */ #ifdef UNIX # include /* need localtime() */ # include /* defn of time_t */ # include # include # include #endif #ifdef __ORCAC__ # include # include # include #endif #ifdef APW # include /* has _toolErr in it */ # include # include "apwerr.h" /* APW/ProDOS error codes */ #endif #ifdef MSDOS # include # include # include # include # include #endif #ifdef __ORCAC__ #include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuetc.h" /* note "nuread.h" is not included... none of the routines here assume */ /* any knowledge of NuFX archives. */ #ifdef APW extern Time ReadTimeHex(); /* should be TimeRec, from misctool.h */ #endif #if defined(__GNUC__) || defined(SUNOS4) || defined(hal) || defined(__SUNPRO_C) extern char *mktemp __P((char *)); #endif /* This is a generally available TEMPORARY filename buffer */ char tmpNameBuf[MAXFILENAME]; /******************** general misc routines ********************/ /* * Fatal error handler */ void #ifdef __STDC__ Fatal (char *deathstr, char *procName) #else Fatal(deathstr, procName) char *deathstr, *procName; #endif { fflush(stdout); fprintf(stderr, "\n%s: fatal error: %s\n--- ", prgName, deathstr); perror(procName); QuitNulib (-1); } /* * QuitNulib can be used to perform cleanup operations before exiting. */ void #ifdef __STDC__ QuitNulib (int val) #else QuitNulib (val) int val; #endif { exit(val); } /* * Safe malloc()... checks return value */ char * #ifdef __STDC__ Malloc __P((size_t size)) #else Malloc (size) size_t size; #endif { char *ptr = (char *) malloc(size); if (ptr != (char *) NULL) { return(ptr); } else { /* 8910.31 - RBH: report byte size that failed */ printf("Malloc: memory alloc error [%lu : bytes]\n", (unsigned long) size); #ifdef MSDOS /* (this doesn't work under Turbo C - MSC only) */ printf("(Largest Available Block: %u)\n", _memmax()); #endif QuitNulib (-1); /*NOTREACHED*/ } #ifdef __lint return NULL; #endif /*NOTREACHED*/ } /******************** UNIX compatibility routines ********************/ #ifdef UNIX /* * Convert expanded date to a number of seconds for UNIX systems. * * Remember that *atime follows the NuFX docs for time values, which * don't necessarily match those in UNIX manual pages. * Adapted from _Advanced UNIX Programming_ by Marc J. Rochkind. * * Returns 0 if date/time is invalid. */ long #ifdef __STDC__ timecvt (Time *atime) #else timecvt (atime) Time *atime; #endif { #ifdef __STDC__ time_t tm; #else long tm; #endif int days; BOOLEAN isleapyear; int tzone; char *tz; if ((tz = getenv("TZ")) == NULL) tzone = 8; /* pacific std time */ else tzone = atoi(&tz[3]); isleapyear = (atime->year != 0) && (atime->year%4 == 0); /* 2000 isn't */ if (atime->year < 70) atime->year += 100; /* years after 2000 */ days = (atime->year - 70) * 365L; days += ((atime->year - 69L) / 4); /* previous years' leap days */ switch (atime->month +1) { /* month is 0-11 */ case 12: days += 30; /* Nov */ case 11: days += 31; /* Oct */ case 10: days += 30; /* Sep */ case 9: days += 31; /* Aug */ case 8: days += 31; /* Jul */ case 7: days += 30; /* Jun */ case 6: days += 31; /* May */ case 5: days += 30; /* Apr */ case 4: days += 31; /* Mar */ case 3: days += (isleapyear ? 29 : 28); /* Feb */ case 2: days += 31; /* Jan */ case 1: break; default: /*printf("Invalid month\n");*/ return (0L); } if (atime->day > 31) { /*printf("Invalid day\n");*/ return (0L); } tm = (days + atime->day) * 24L * 60L * 60L; if (atime->hour > 23) { /*printf("Invalid hour\n");*/ return (0L); } atime->hour += tzone; /* correct for time zone */ tm += atime->hour * 60L * 60L; if (atime->minute > 59) { /*printf("Invalid minute\n");*/ return (0L); } tm += atime->minute * 60L; if (atime->second > 59) { /*printf("Invalid second\n");*/ return (0L); } tm += atime->second; if (localtime(&tm)->tm_isdst) /* was that day in dst? */ tm -= 60L * 60L; /* adjust for daylight savings */ return (tm); } #endif /* UNIX */ /******************** APW compatibility routines ********************/ #ifdef APW /* * Normally a C library function to print out a description of the most * recent system (non-toolbox, non-ProDOS) error. Exists under UNIX and * MS C 5.1, so I'm assuming it exists most everywhere else... */ void #ifdef __STDC__ perror(const char *errstr) #else perror(errstr) const char *errstr; #endif { fflush(stdout); if ( (errno > 0) && (errno < sys_nerr) ) { /* known APW error? */ fprintf(stderr, "%s: %s\n", errstr, sys_errlist[errno]); } else { fprintf(stderr, "%s: ", errstr); fflush(stderr); ERROR( errno ); } QuitNulib (-1); } #endif /* APW */ #if defined(APW) /* Check for //gs toolbox errors; all are fatal */ void #ifdef __STDC__ ToolErrChk (void) #else ToolErrChk() #endif { int err = _toolErr; if (err) { if (err < MPErr) { /* was a ProDOS error? */ fprintf(stderr, "Error: $%.2x %s\n", (char) err, ProDOSErr[err]); } else { fprintf(stderr, "Tool err ($%.4x): ", err); fflush(stderr); ERROR( err ); } QuitNulib (-1); } } #endif /* APW */ /******************** miscellaneous string routines ********************/ /* * Compare strings, ignoring case (may be in standard C lib; stricmp()?) */ int #ifdef __STDC__ strcasecmp (register const char *str1, register const char *str2) #else strcasecmp(str1, str2) register const char *str1, *str2; #endif { register char one, two; register int val; for ( ; *str1 && *str2; str1++, str2++) { one = (isupper(*str1) ? tolower(*str1) : *str1); two = (isupper(*str2) ? tolower(*str2) : *str2); if ((val = two - one)) return (val); } if (!(*str1) && !(*str2)) /* both zero -> equivalent */ return (0); else { /* one is shorter; return result */ one = (isupper(*str1) ? tolower(*str1) : *str1); two = (isupper(*str2) ? tolower(*str2) : *str2); return (two - one); } } int #ifdef __STDC__ strncasecmp (register const char *str1, register const char *str2, size_t num) #else strncasecmp (str1, str2, num) register const char *str1, *str2; int num; #endif { register int i; register char one, two; register int val; /* keep going 'til no more registers... */ for (i = 0; (i < num) && (*str1) && (*str2); i++, str1++, str2++) { one = (isupper(*str1) ? tolower(*str1) : *str1); two = (isupper(*str2) ? tolower(*str2) : *str2); if ((val = two - one)) return (val); } if (i == num) /* first num characters are equal, so return zero */ return (0); else { /* one ended early; return result */ one = (isupper(*str1) ? tolower(*str1) : *str1); two = (isupper(*str2) ? tolower(*str2) : *str2); return (two - one); } } /******************* file-related routines ********************/ /* * Do operating system-dependent CREATE stuff * * Creates a NuFX archive file, with type info where necessary. * Does not leave file open. */ void #ifdef __STDC__ ArcfiCreate(char *filename) #else ArcfiCreate(filename) char *filename; #endif { static char *procName = "ArcfiCreate"; #ifdef __ORCAC__ static CreateRecPtrGS crec; if ((crec = malloc(sizeof(CreateRecGS))) == NULL) { perror("ArcfiCreate failed"); QuitNulib(-1); } if ((crec->pathname = __C2GSMALLOC(filename)) == NULL) { perror("ArcfiCreate failed"); QuitNulib(-1); } crec->pCount = 4; crec->access = 0x00e3; /* unlocked, visible */ crec->fileType = 0x00e0; /* LBR */ crec->auxType = 0x8002; /* SHK */ CreateGS(crec); if (_toolErr) { errno = _mapErr(_toolErr); Fatal("Unable to create file", procName); } #elif defined(UNIX) /* && !defined(__GNO__) */ int fd; if ((fd = open(filename, O_CREAT|O_RDWR, (mode_t) WPERMS)) < 0) Fatal("Unable to create file", procName); close(fd); #elif defined(APW) FileRec create_p; c2pstr(filename); create_p.pathname = filename; create_p.fAccess = 0x00e3; create_p.fileType = 0x00e0; /* LBR */ create_p.auxType = 0x8002; /* SHK */ create_p.storageType = 0x0001; create_p.createDate = 0x0000; /* let ProDOS fill in the blanks */ create_p.createTime = 0x0000; CREATE( &create_p ); ToolErrChk(); p2cstr(filename); #elif defined(MSDOS) int fd; if ((fd = open(filename, O_CREAT|O_RDWR, (mode_t) WPERMS)) < 0) Fatal("Unable to create file", procName); close(fd); #else int fd; if ((fd = open(filename, O_CREAT|O_RDWR, (mode_t) WPERMS)) < 0) Fatal("Unable to create file", procName); close(fd); #endif } /* * Determine if a file already exists. */ BOOLEAN #ifdef __STDC__ Exists(char *filename) #else Exists(filename) char *filename; #endif { #if defined(MSDOS) || (defined(__ORCAC__) && !defined(__GNO__)) static char *procName = "Exists"; #endif #if defined(UNIX) && !defined(__GNO__) return (access(filename, F_OK) == 0) ? TRUE : FALSE; #elif defined(__ORCAC__) /* && !defined(__GNO__) */ static FileInfoRecGS frec; static GSString255 rbuf; int result; frec.pCount = 2; frec.pathname = __C2GSMALLOC(filename); GetFileInfoGS(&frec); switch (_toolErr) { case 0: result = TRUE; break; case devNotFound: case pathNotFound: case volNotFound: result = FALSE; break; default: printf("%s: GetFileInfoGS failed for %s: %s\n", procName, filename, strerror(_mapErr(_toolErr))); QuitNulib(-1); } free(frec.pathname); return result; #elif defined(APW) FileRec info_p; /* check if file exists, is dir */ int err; c2pstr(filename); info_p.pathname = filename; GET_FILE_INFO( &info_p ); err = _toolErr; p2cstr(filename); if (err == pathNotFound || err == fileNotFound) return (FALSE); else if (!err) return (TRUE); else { _toolErr = err; ToolErrChk(); return (TRUE); } #elif defined(MSDOS) struct stat sm; if (stat(filename, &sm) < 0) { if (errno == ENOENT) /* if doesn't exist, then okay */ return (FALSE); else /* some other problem killed stat(), probably serious */ fprintf(stderr, "Unable to stat() '%s'\n", filename); Fatal("Bad stat()", procName); /*serious prob*/ } else /* successful call - file exists */ return (TRUE); #else printf("Need [other] Exists()\n"); /* +PORT+ */ return (FALSE); #endif } /* * Generate a temporary file name (system dependent). * Assumes space is allocated for buffer. */ char * #ifdef __STDC__ MakeTemp(char *buffer) #else MakeTemp(buffer) char *buffer; #endif { #if 0 static char *procName = "MakeTemp"; #endif #ifdef UNIX strcpy(buffer, "nulb.tmpXXXXXX"); return mktemp(buffer); #elif defined(__ORCAC__) return tmpnam(NULL); #elif defined(APW) int idx = 0; do { sprintf(buffer, "nulb.tmp%d", idx++); } while (Exists(buffer)); return (buffer); #elif defined(MSDOS) extern char *mktemp(); strcpy(buffer, "nulbXXXX.tmp"); return (mktemp(buffer)); #else strcpy(buffer, "nulb.tmp"); /* +PORT+ */ return (buffer); #endif } #ifdef NO_RENAME /* * This is a replacement for the library call, in case somebody's C library * doesn't have it. */ int #ifdef __STDC__ rename(char *fromname, char *toname) #else rename(fromname, toname) char *fromname; char *toname; #endif { if (link(fromname, toname) < 0) return (-1); if (unlink(fromname) < 0) return (-1); } #endif /* * Rename a file. */ void #ifdef __STDC__ Rename(char *fromname, char *toname) #else Rename(fromname, toname) char *fromname, *toname; #endif { static char *procName = "Rename"; #ifdef __ORCAC__ if (rename(fromname, toname) != 0) { fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n", prgName, fromname, toname); Fatal("Bad rename()", procName); } #elif defined(UNIX) if (Exists(toname)) { fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n", prgName, fromname, toname); fflush(stderr); } # ifdef AOSVS /* BAK 04/30/90 */ printf("Work on AOS/VS rename command\n"); /* BAK 04/30/90 */ # else /* BAK 04/30/90 */ else { if (rename(fromname, toname) < 0) { /* this should "never" fail */ fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n", prgName, fromname, toname); Fatal("Bad rename()", procName); /*serious prob*/ } } # endif #elif defined(APW) PathNameRec cpath_p; if (Exists(toname)) { fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n", prgName, fromname, toname); fflush(stderr); return; } cpath_p.pathname = fromname; cpath_p.newPathname = toname; c2pstr(fromname); c2pstr(toname); CHANGE_PATH( &cpath_p ); ToolErrChk(); p2cstr(fromname); p2cstr(toname); #elif defined(MSDOS) if (Exists(toname)) { fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n", prgName, fromname, toname); fflush(stderr); return; } printf("Work on MSDOS rename command\n"); #else if (Exists(toname)) { fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n", prgName, fromname, toname); fflush(stderr); return; } printf("Need [other] rename command\n"); /* +PORT+ */ #endif } /******************** date/time routines ********************/ /* * Expand date/time from file-sys dependent format to eight byte NuFX format. * tptr is filesys format, TimePtr is NuFX format */ void #ifdef __STDC__ ExpandTime(void *tptr, Time *TimePtr) #else ExpandTime(tptr, TimePtr) /* (BSD) UNIX version */ onebyt *tptr; /* usually points to a time_t (long) */ Time *TimePtr; #endif { #if defined(UNIX) || defined(__ORCAC__) time_t *tp = (time_t *) tptr; struct tm *unixt; unixt = localtime(tp); /* expand time_t into components */ TimePtr->second = unixt->tm_sec; TimePtr->minute = unixt->tm_min; TimePtr->hour = unixt->tm_hour; TimePtr->year = unixt->tm_year; TimePtr->day = unixt->tm_mday -1; /* want 0-xx, not 1-xx */ TimePtr->month = unixt->tm_mon; TimePtr->extra = 0; TimePtr->weekDay = unixt->tm_wday +1; /* Sunday = 1, not 0 like UNIX */ #else # ifdef APW /* APW version */ twobyt date, time; date = (twobyt)tptr[0] + ((twobyt)tptr[1] << 8); time = (twobyt)tptr[2] + ((twobyt)tptr[3] << 8); TimePtr->second = 0; /* not stored in ProDOS file info */ TimePtr->minute = (char) time; /* truncated to char */ TimePtr->hour = time >> 8; TimePtr->year = date >> 9; TimePtr->day = (date & 0x1f) - 1; TimePtr->month = ((date & 0x01e0) >> 5) - 1; TimePtr->extra = 0; TimePtr->weekDay = 0; # endif /* APW */ # ifdef MSDOS struct tm *newtime; time_t *tp = (time_t *) tptr; newtime = localtime (tp); TimePtr->second = (onebyt)newtime->tm_sec; TimePtr->minute = (onebyt)newtime->tm_min; TimePtr->hour = (onebyt)newtime->tm_hour; TimePtr->year = (onebyt)newtime->tm_year; TimePtr->day = (onebyt)newtime->tm_mday - 1; TimePtr->month = (onebyt)newtime->tm_mon; TimePtr->extra = 0; TimePtr->weekDay= (onebyt)newtime->tm_wday + 1; # endif /* MSDOS */ # ifndef APW # ifndef MSDOS printf("Need [other] time-expander\n"); /* +PORT+ */ TimePtr->second = 0; TimePtr->minute = 0; TimePtr->hour = 0; TimePtr->year = 0; TimePtr->day = 0; TimePtr->month = 0; TimePtr->extra = 0; TimePtr->weekDay = 0; # endif /* none1 */ # endif /* none2 */ #endif /* UNIX */ } #ifdef SUNOS4 time_t time __P((time_t *)); #endif /* * Get current time, put in struct */ Time * #ifdef __STDC__ GetTime(void) #else GetTime() #endif { static Time t; #if defined(UNIX) || defined(__ORCAC__) struct tm *unixt; time_t now = time(NULL); unixt = localtime(&now); t.second = unixt->tm_sec; t.minute = unixt->tm_min; t.hour = unixt->tm_hour; t.year = unixt->tm_year; t.day = unixt->tm_mday -1; /* want 0-xx, not 1-xx */ t.month = unixt->tm_mon; t.extra = 0; t.weekDay = unixt->tm_wday +1; /* Sunday = 1, not 0 like UNIX */ /* return (&t) */ #else # ifdef APW t = ReadTimeHex(t); /* return (&t) */ # endif /* APW */ # ifdef MSDOS struct tm *pctime; time_t now = time(NULL); pctime = localtime(&now); t.second = (onebyt)pctime->tm_sec; t.minute = (onebyt)pctime->tm_min; t.hour = (onebyt)pctime->tm_hour; t.year = (onebyt)pctime->tm_year; t.day = (onebyt)pctime->tm_mday -1; /* want 0-xx, not 1-xx */ t.month = (onebyt)pctime->tm_mon; t.extra = 0; t.weekDay= (onebyt)pctime->tm_wday +1; /* Sunday = 1, not 0 */ /* return (&t) */ # endif /* MSDOS */ # ifndef APW # ifndef MSDOS printf("\nNeed [other] GetTime\n"); /* +PORT+ */ t->second = 0; t->minute = 0; t->hour = 0; t->year = 0; t->day = 0; t->month = 0; t->filler = 0; t->weekDay = 0; /* return (&t) */ # endif /* none1 */ # endif /* none2 */ #endif /* UNIX */ return (&t); } /* * Convert a NuFX Time struct to a compact system-dependent format * * This is used to set a file's date when extracting. Most systems don't * dedicate 8 bytes to storing the date; this reduces it to the format * used by a "set_file_date" command. */ long #ifdef __STDC__ ReduceTime(Time *tptr) #else ReduceTime(tptr) Time *tptr; #endif { #ifdef UNIX long t = timecvt(tptr); return (t ? t : time(NULL)); /* if stored time is invalid, */ /* return current time */ #else # ifdef APW twobyt date, time; long val; date = ((twobyt)tptr->year << 9) | ((((twobyt)tptr->month)+1) << 5) | (((twobyt)tptr->day)+1); time = ((twobyt)tptr->hour << 8) | ((twobyt)tptr->minute); val = (long) date + ((long) time << 16); return (val); # endif /* APW */ # ifdef MSDOS return (time(NULL)); /* not sure what to do, return current : RBH */ # endif /* MSDOS */ #ifndef APW #ifndef MSDOS printf("Need [other] ReduceTime\n"); /* +PORT+ */ # endif /* none2 */ # endif /* none1 */ #endif /* UNIX */ } #ifdef __ORCAC__ int keyboardStop(void) { StopGSPB sblock = { 1, 0 }; StopGS(&sblock); TOOL_CHECK("get stop info", "", 1); return sblock.flag; } #ifndef __GNO__ GSString255Ptr __C2GSMALLOC(char *s) { GSString255Ptr result; size_t len; if (s == NULL || (len = strlen(s)) > 255) { errno = EINVAL; return NULL; } result = malloc(sizeof(GSString255)); if (result != NULL) { result->length = len; strncpy(result->text, s, len); /* don't null-terminate iff len == 255 */ } return result; } #ifndef __GNO__ #define EPERM EIO #define ENOTBLK EIO #define ENOEXEC EIO #define EAGAIN EIO #endif int _mapErr (int gserrnum) { switch (gserrnum) { case invalidRefNum: /* invalid reference number */ return EBADF; /* bad file descriptor */ case outOfMem: /* out of memory */ return ENOMEM; /* Not enough memory */ case drvrPriorOpen: /* character device already open */ case drvrBusy: /* call aborted; driver is busy */ case drvrWrtProt: /* device is write protected */ return EACCESS; /* access bits prevent the operation */ case devNotFound: /* device not found */ case pathNotFound: /* subdirectory does not exist */ case volNotFound: /* volume not found */ case fileNotFound: /* file not found */ return ENOENT; /* No such file or directory */ case tooManyFilesOpen:/* too many files open on server volume */ case defListFull: /* device list is full */ case fileBusy: /* file is already open */ return EMFILE; /* too many files are open */ case gsosActive: /* GS/OS already active */ return EDOM; /* domain error */ case invalidAccess: /* access not allowed */ case dataUnavail: /* Data unavailable */ return EPERM; /* Not owner */ case notBlockDev: /* not a block device */ return ENOTBLK; /* not a block device */ case notSystemFile: /* not an executable file */ return ENOEXEC; /* Exec format error */ case volumeFull: /* volume full error */ case volDirFull: /* volume directory full */ return ENOSPC; /* the file is too large */ case dupPathname: /* create or rename with existing name */ case devNameErr: /* device exists with same name as replacement name */ return EEXIST; /* the file exists */ case outOfRange: /* position out of range */ return ERANGE; /* # too large, too small, or illegal */ case irqTableFull: /* interrupt table full */ case drvrNoResrc: /* resources not available */ case stackOverflow: /* too many applications on stack */ return EAGAIN; /* No more processes */ case endOfDir: /* end of directory has been reached */ case eofEncountered: /* end-of-file encountered */ return 0; /* no error ... */ case badSystemCall: /* bad system call number */ case invalidPcount: /* invalid parameter count */ case invalidDevNum: /* invalid device number */ case drvrBadReq: /* bad request or command */ case drvrBadCode: /* bad control or status code */ case drvrBadParm: /* bad call parameter */ case drvrBadCount: /* invalid byte count */ case drvrBadBlock: /* invalid block address */ case badPathSyntax: /* invalid pathname syntax */ case badFileFormat: /* version error (incompatible file format) */ case badStoreType: /* unsupported (or incorrect) storage type */ case buffTooSmall: /* buffer too small */ case paramRangeErr: /* parameter out of range */ case invalidClass: /* invalid FST call class */ case invalidFSTID: /* error - FST ID is invalid */ case invalidFSTop: /* invalid FST operation */ case unknownVol: /* unknown volume type */ case dupVolume: /* duplicate volume name */ case badPathNames: /* invalid pathnames for ChangePath */ case osUnsupported: /* Operating System not supported */ case invalidLevel: /* specifield level outside legal range */ return EINVAL; /* Invalid argument */ case drvrIOError: /* I/O error */ case resForkNotFound: /* file does not contain required resource */ case supListFull: /* supervisor list is full */ case fstError: /* generic FST error */ case resExistsErr: /* cannot expand file, resource already exists */ case resAddErr: /* cannot add resource fork to this type file */ case networkError: /* generic network error */ case drvrNotOpen: /* character device not open */ case drvrNoDevice: /* device not connected */ case drvrDiskSwitch: /* disk has been switched */ case drvrOffLine: /* device off line/ no media present */ case dirError: /* directory error */ case damagedBitMap: /* block number too large */ case fstCaution: /* FST handled call, but result is weird */ default: return EIO; /* I/O error */ } } #endif /* !__GNO__ */ #endif /* __ORCAC__ */ nulib/nucomp.h100644 765 144 44541 6247227101 12053 0ustar gdrusers/* * nucomp.h - declarations for nucomp.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nucomp.h,v 1.4 1996/11/28 06:16:33 gdr Exp $ */ #ifdef BSD43 # define NO_SETVBUF #endif #include #include #ifdef UNIX /* this is asking for trouble */ # include #else # ifdef IAPX286 # include # else # ifdef IAPX386 # include # else # include # endif # endif #endif #include #include #ifdef MSDOS # include #endif /*@H************************ < COMPRESS HEADER > **************************** * $@(#) compress.c,v 4.3 88/12/26 08:00:00 don Release ^ * * * * compress : compress.h * * * * port by : Donald J. Gloistein * * * * Source, Documentation, Object Code: * * released to Public Domain. This code is based on code as documented * * below in release notes. * * * *--------------------------- Module Description --------------------------* * THIS HEADER CONTAINS MUCH IMPLEMENTATION INFORMATION AND ASSUMPTIONS * * PLEASE PRINT IT OUT AND READ IT BEFORE COMPILING CODE FOR YOURSELF * * * * This header supports a number of compiler defines and predefines. * * Rather than explain all of them, please print the header and read the * * notes. Also the unix and xenix makefiles are commented for the * * various options. There continues to have a lot of Dos specific info in * * the header. This is to help on 16 bit Msdos machines to get their * * compiler to work properly. I make no appology for that, as this port * * began as a way to implement 16 bit compress on a segmented MsDos machine* * * * However, for Unix and Xenix, all you should have to define is -DXENIX * * or -DUNIX and compile. There may be a problem with whether your library * * supports alloc() or malloc(), but there is a define for that, also. * * * * This header can be maintained to keep up with the different compilers * * and systems. As distributed in don Release, the files will compile with * * no changes under Microsoft version 5.1 C compiler, and Xenix C compiler * * which is the Microsoft version 4 ported. If you are going to bind the * * code for use in MsDos and OS/2 machines, then you must uncomment the * * #define BIND in this header. Otherwise, this distribution of source * * detect Msdos and Xenix predefines from the compiler and adjust. * * * *--------------------------- Implementation Notes --------------------------* * * * compiled with : compress.fns * * * NOTE!!! Defaults of this code now are completely Unix, even for the * * msdos ports. That means that the program works as a filter, * * and will just sit there waiting for input from stdin if you * * issue just the command name. You must use -h or -? to get the * * full help screen now. Also, it will unlink (kill) as a default * * on successful compression and decompression. That means the * * source file will be erased. * * These defaults are changed with the FILTER and KEEPFLAG * * defines. * * * * NOTE!!! Compiler predefines were taken out of the compress.h header. * * You must either specify them on compile or uncomment the * * compiler define in this header. Compiling without doing these * * will result in a program that does unspecified actions. * * problems: * * The inpath and outpath is a bit kludged. It should work okay. * * Let me know if you have problems, especially under Unix. * * * * CAUTION: The bound version will run on Dos 2.x, but you must use the * * name compress.exe. If you rename the file, it will not run * * The unbound version will run on Dos 2.x with the name changed * * but due to the dos version, will not detect its own name. * * * * CAUTION: Non MsDos users. You must modify the _MAX_PATH defines for * * your operating system if it is different from the assumed * * standard. * * * * CAUTION: I have used a number of defines to make it possible to compile * * properly under a number of bit sizes and adjust for the memory * * allocation scheme needed. If you do not use a dos system, * * PLEASE pay attention to the defines for MAXSEG_64 and the one * * called SMALLMODEL. The SMALLMODEL define is set in the header * * but if you don't have a compiler that triggers the MAXSEG_64 * * define, you may end up with bad pointers. Becareful. * * * * Header for files using version 4 compress routines define MAIN * * in the file with defining instance of the global variables. * * There are a number of compilers for MsDos and Unix/Xenix. * * So the user must define the actions required. * * * * * * Defines: This header file contains most of the system wide defines. * * the purpose for this was to consolodate compiler differences * * into one area that is easily changed. * * * * define MAXBITS= if you want a different maximum bits. 16 bits will now * * run in about 400K of memory. * * define BIND if you are going to use Microsoft bind.exe program on the * * executable. * * * * define MSDOS if you are compiling under MsDos or PcDos and your compiler* * does not predefine it. * * * * Initials ---- Name --------------------------------- * * DjG Donald J. Gloistein, current port to MsDos 16 bit * * Plus many others, see rev.hst file for full list * * LvR Lyle V. Rains, many thanks for improved implementation * * of the compression and decompression routines. * *************************************************************************@H*/ #ifndef FALSE /* let's get some sense to this */ #define FALSE 0 #define TRUE !FALSE #endif #define NDEBUG #define NPROTO #define COMP40 /* take this out for a little more speed */ #define ALLOCATE(x,y) malloc((unsigned int) (x) * (y)) #define NOSIGNAL /* what the hell is "SIGTYPE"? */ #define setbinary(fp) #define FAR #define CONST #define _MAX_DIR 64 /* FILTER if you want the program to operate as a unix type filter */ /* if not defined TRUE, then issuing command without parameters will */ /* print a usage and help information */ /* Use -DFILTER=0 to deactivate filter operation */ #ifndef FILTER #define FILTER FALSE #endif /* KEEPFLAG determines the default action on successful completion */ /* Unix convention is FALSE (erase input file) */ /* Use -DKEEPFLAG=1 to keep files as default or change here */ /* if you don't set it before here and you are compiling the debug */ /* version, then files will be kept. */ #ifndef KEEPFLAG #define KEEPFLAG TRUE #endif /* the following tells the system that the maximum segment is 64k */ /* if your compiler is not one of these and has this limitation */ /* Because of this, this code should compile with minimum porting */ /* in the COMPUSI.XEN module to most unix systems. */ /* This is also used to keep array indexing to 16 bit integer */ /* if not predefined in compiler implementation, you must define */ /* it separately if applicable to your compiler/system */ #define MAXSEG_64K /* put this in if you are compiling in small code */ /* model and your compiler does not predefine it */ /* this is for CPU' with 64k segment limitation. */ /* Use this define for small code, it is used by */ /* the header to decide on value for NEARHEAP */ /* #define SMALLMODEL */ /* does your system use far pointers ? if you want it enabled keep this */ /* if you have segment limit and compile in larger than 13 bits */ /* then you will have to use compact or large model if your compiler */ /* does not support far pointer keyword. */ #ifndef FAR #define FAR #endif /* What type does the alloc() function return, char or void? */ #ifndef ALLOCTYPE #define ALLOCTYPE char #endif /* Does your run time library support the ANSI functions for:*/ /* reverse string set search? strrpbrk() if not: */ #define NO_REVSEARCH /* Does your library include strrchr()? If not define this: */ /*#define NO_STRRCHR*//* unix/xenix module uses this function*/ /* Does your library include strchr()? If not define this: */ /*#define NO_STRCHR*//* dos module uses this function. */ /* definition for const key word if supported */ #ifndef CONST #define CONST #endif /* And now for some typedefs */ typedef unsigned short CODE; typedef unsigned char UCHAR; typedef unsigned int HASH; typedef int FLAG; /* * You can define the value of MAXBITS to be anything betweeen MINBITS * and MAXMAXBITS. This is will determine the maximum memory you will * use and how the tables will be handled. I recommend you just leave * it at MAXMAXBITS, because you can define DFLTBITS in compiling the * module COMPRESS.C to set the default, and you can vary the number * of bits at runtime by using the -b switch. */ /* * The only reason to change MAXBITS is if you absolutely must have * faster performance. If you specify 14 bits, the tables will not * be split; at 13 bits, you can fit in the MSDOS small memory model * and allocate tables in near heap. * This value is available to other modules through the variable maxbits. */ #define INITBITS 9 #define MINBITS 12 #define MAXMAXBITS 16 #ifndef MAXBITS #define MAXBITS MAXMAXBITS #endif #if (MAXBITS > MAXMAXBITS) #undef MAXBITS #define MAXBITS MAXMAXBITS #endif #if (MAXBITS < MINBITS) #undef MAXBITS #define MAXBITS MINBITS #endif /* You should define DFLTBITS to be the default compression code * bit length you desire on your system. * (I define mine in the compiler command line in my Makefile.LvR) * (I leave mine alone and keep to the maximum. DjG) */ #ifndef DFLTBITS #define DFLTBITS MAXBITS #endif #if (DFLTBITS < MINBITS) #undef DFLTBITS #define DFLTBITS MINBITS #endif #if (DFLTBITS > MAXBITS) #undef DFLTBITS #define DFLTBITS MAXBITS #endif /* correcting for different types of pointer arithmatic */ /* probably won't have to change it */ #define NULLPTR(type) ((type FAR *) NULL) /* in making this program portable the following allocation and */ /* free functions are called, with the following parameters: */ /* ALLOCTYPE FAR *emalloc(unsigned int x, int y) */ /* void efree(ALLOCTYPE FAR *ptr) */ /* you must define the allocation function and the free function */ /* keep in mind that the casts must be correct for your compiler */ /* NOTE these are the two functions to change for allocating pointers to */ /* far data space if you are not using Microsoft C v.5.1 */ /* Consult your compiler manual and find the low level function that */ /* returns a far pointer when compiled in the small model. */ /* if your compiler does not support that, you will have to compile with */ /* a model that defaults to far pointers to data (compact or large model)*/ /* HERE ARE SOME SAMPLE PREDEFINED ONES */ /* default allocation function, in segmented addressing, must return */ /* a far pointer or compile with far pointer data as default */ #ifndef ALLOCATE #include #define ALLOCATE(x,y) malloc((unsigned int)x*y) #endif # ifdef MAXSEG_64K # if MAXBITS > 14 # define SPLIT_HT TRUE # else # define SPLIT_HT 0 # endif # else # define SPLIT_HT 0 # endif # ifdef MAXSEG_64K # if MAXBITS > 15 # define SPLIT_PFX TRUE # else # define SPLIT_PFX 0 # endif # else # define SPLIT_PFX 0 # endif #ifndef BUFSIZ #define BUFSIZ 512 #endif #ifdef NO_SETBUF #define NO_SETVBUF #endif /* NuLib: comment: this ought to use setbuffer() if available */ #ifdef NO_SETVBUF # ifndef NO_SETBUF # define setvbuf(fp,buf,mode,size) setbuf((fp),(buf)) # define ZBUFSIZE BUFSIZ # define XBUFSIZE BUFSIZ # else # define setvbuf(fp,buf,mode,size) # define ZBUFSIZE (1) # define XBUFSIZE (1) # endif #else # ifdef NEARHEAP # define XBUFSIZE (0xC00) # define ZBUFSIZE (0x1800) # else # define XBUFSIZE (0x3000) /* 12k bytes */ # define ZBUFSIZE (0x6000) /* 24k bytes */ # endif #endif #define UNUSED ((CODE)0) /* Indicates hash table value unused */ #define CLEAR ((CODE)256) /* Code requesting table to be cleared */ #define FIRSTFREE ((CODE)(CLEAR+1))/* First free code for token encoding */ #define MAXTOKLEN 512 /* Max chars in token; size of buffer */ #define OK 0 /* Result codes from functions: */ #define ERROR 1 #define NORMAL 0 #define SIGNAL_ERROR -1 /* signal function error */ #define NOMEM 2 /* Ran out of memory */ #define TOKTOOBIG 3 /* Token longer than MAXTOKLEN chars */ #define READERR 4 /* I/O error on input */ #define WRITEERR 5 /* I/O error on output */ #define INFILEBAD 6 /* Infile not in compressed format */ #define CODEBAD 7 /* Infile contained a bad token code */ #define TABLEBAD 8 /* The tables got corrupted (!) */ #define NOSAVING 9 /* no saving in file size */ #define NOTOPENED 10 /* output file couldn't be opened */ #define YES 1 #define NO 0 #include "nucompfn.h" /* This has to come late... needs typedefs above */ /* defines opening mode for files */ /* and suffixes for compressed file */ #define WRITE_FILE_TYPE FWRITE_STR /* NuLib: was "wb" */ #define READ_FILE_TYPE FREAD_STR /* NuLib: was "rb" */ #define SUFFIX ".Z" /* Defines for third byte of header */ #define BIT_MASK 0x1f #define BLOCK_MASK 0x80 /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is a fourth header byte (for expansion). */ #define CHECK_GAP 10000L /* ratio check interval */ #ifdef MAIN UCHAR magic_header[] = { 0x1F,0x9D }; /* 1F 9D */ char rcs_ident[] = "@(#) compress,v 4.3 88/12/26 08:00:00 don Release"; int overwrite = 0; /* Do not overwrite unless given -f flag */ int maxbits = DFLTBITS; /* user settable max # bits/code */ int exit_stat = 0; int keep = KEEPFLAG; /* True = don't kill file */ int keep_error = FALSE; /* True = keep output file even if error exist */ char *prog_name; char ifname[_MAX_DIR]; char inpath[_MAX_DIR]; char ofname [_MAX_DIR]; char outpath[_MAX_DIR]; int is_list = FALSE; /* flag for file parameters */ char endchar[1]; char xbuf[XBUFSIZE]; char zbuf[ZBUFSIZE]; char separator[] = "/"; int nomagic = FALSE; /* Use a 3-byte magic number header, unless old file */ int zcat_flg = TRUE; /* Write output on stdout, suppress messages */ int quiet = TRUE; /* don't tell me about compression */ /* * block compression parameters -- after all codes are used up, * and compression rate changes, start over. */ int block_compress = BLOCK_MASK; #ifdef COMP40 long int ratio = 0L; long checkpoint = CHECK_GAP; #endif /* force the overwrite */ int force = 0; #ifndef NDEBUG int verbose = FALSE; int debug = FALSE; #endif /* !NDEBUG */ int do_decomp = FALSE; #else /* not defining instance */ extern UCHAR magic_header[]; extern char rcs_ident[]; extern int overwrite; extern int maxbits; extern int exit_stat; extern int keep; extern int keep_error; extern char *prog_name; extern char inpath[]; extern char outpath[]; extern int is_list; extern char endchar[]; extern char xbuf[]; extern char zbuf[]; extern char ifname[]; extern char ofname[]; extern char separator[]; extern int nomagic; extern int zcat_flg; extern int quiet; extern int block_compress; #ifdef COMP40 extern long int ratio; extern long checkpoint; #endif extern int force; #ifndef NDEBUG extern int verbose; extern int debug; #endif /* !NDEBUG */ extern int do_decomp; #endif nulib/nucompfn.h100644 765 144 3575 6246126406 12366 0ustar gdrusers/* * nucompfn.h - function declarations for nucomp.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nucompfn.h,v 1.3 1996/11/03 23:01:03 gdr Exp $ */ /* * COMPRESS.FNS global function declarations * this should be compatible with any type of declaration for external * functions. See compress.h for explaination */ extern CODE getcode __P((void)); extern char *get_program_name __P((char *)); extern char *name_index __P((char *)); extern int alloc_tables __P((CODE maxcode, HASH hashsize)); extern int check_error __P((void)); extern int cl_block __P((void)); extern int is_z_name __P((char *)); extern int make_z_name __P((char *)); extern int nextcode __P((CODE *codeptr)); extern int u_compress __P((int srcfd, int dstfd, long thread_eof)); extern int u_decompress __P((int srcfd, int dstfd, long comp_thread_eof)); extern void Usage __P((char *)); extern void compress __P((long thread_eof)); extern void copystat __P((char *, char *)); extern void decompress __P((void)); extern void init_tables __P((void)); extern void prratio __P((FILE *stream, long int num, long int den)); extern void putcode __P((CODE code, int bits)); extern void unmake_z_name __P((char *)); extern void version __P((void)); extern void writeerr __P((void)); #ifdef NO_STRCHR extern char *strchr __P((const char *, int)); #endif #ifdef NO_STRRCHR extern char *strrchr __P((const char *, int)); #endif #ifdef NO_REVSEARCH extern char *strrpbrk __P((const char *, const char *)); #endif #ifndef NOSIGNAL extern int foreground __P((void)); extern SIGTYPE onintr __P((void)); extern SIGTYPE oops __P((void)); #endif #ifdef NEARHEAP extern ALLOCTYPE *emalloc __P((unsigned int x, int y)); extern void efree __P((ALLOCTYPE *ptr)); #else extern ALLOCTYPE FAR *emalloc __P((unsigned int x, int y)); extern void efree __P((ALLOCTYPE FAR *ptr)); #endif nulib/nulib.1100644 765 144 60237 6264126246 11603 0ustar gdrusers.\" man page for nulib written by Devin Reade .\" .\" $Id: nulib.1,v 1.5 1997/01/06 07:41:26 gdr Exp $ .\" .\" .TH NULIB 1 "Commands and Applications" "Version 3.25" "5 January 1997" .TH NULIB 1 "Version 3.25" "5 January 1997" "Commands and Applications" .SH NAME nulib \- NuFX file archiver .SH SYNOPSIS .BR nulib [-]\fIoption\fR[\fIsubopts\fR] .I archive_name [ .I filespec ] .SH DESCRIPTION .BR nulib is a shell-based NuFX archive utility, based loosely on .BR ARC for the IBM PC and .BR ar (1) under UNIX. It allows you to perform certain operations on the same archives used by .BR ShrinkIt , including view archive contents, add to archive, extract from archive, and delete from archive. In addition, it will list and unpack files from .BR "Binary II" archives. .LP This program is primarily targeted at users of non-Apple II computer systems, from IBM PC compatibles to workstations to mainframes. It will also be of use to people who use a GS/OS shell on the Apple IIgs, such as APW, ORCA, or ECP-16 (although it is considerably slower than .BR ShrinkIt ). .Br nulib may require more than 256k of free RAM to function properly. Apple //gs users can use .BR yankit (1) instead, which is much smaller and many times faster (though considerably less powerful). .LP .IR archive_name is the name of the NuFX archive. It doesn't need to exist prior to the add, create, or move options. .LP .IR filespec is the name of a file, either on disk or in the archive. More than one file may be named on the command line. While wildcard expansion is done by the shell on UNIX systems (including GNO), .BR nulib is required to do wildcard expansions when running under APW or the ORCA/Shell. The names of files in the actual .I archive do not undergo wildcard expansion on any system. .LP .BR Nulib will only work with Binary II and NuFX archives. If you try to view some other kind of file, you will get an error message and possibly an indication of what kind of file it is. .BR Nulib can recognize files processed with .BR compress (1), .BR Zip , .BR Zoo , .BR StuffIt , .BR ar (1), .BR shar (1), .BR GIF , and many others. .SH OPTIONS The following .IR option s are recognised, each of which is a single character, and may be followed by the specified .IR suboption s. The .IR option / suboption string may be entered in upper or lower case, and may be preceeded by a hyphen. Suboptions may be entered in any order. There must be no whitespace in the option-suboption string. .IP "\fBa\fR[\fBvurd\fR][\fBc\fI\fR][\fBs\fI\fR][\fBf\fI\fR[/\fI\fR]]" .sp 1 .BR "Quick Append" .sp 1 Quickly appends the specified files to the end of the archive. This option does not scan the archive to see if the files already exist, and will create a new archive file if one is not found. This option corresponds roughly to N)ew archive or A)dd files on the .BR ShrinkIt menu. .sp 1 If you add files from the current directory or a subdirectory of the current directory, then the entire partial pathname is stored. For example, .nf nulib av fubar.shk foo/bar/filename .fi will store .I foo/bar/filename in the archive .IR fubar.shk . If you add files from directory that is not a subdirectory of the current directory, only the filename will be stored. The example .nf nulib av fubar.shk ../zip/bang/filename .fi will store .I filename in the archive. This does not work under UNIX, since filenames are expanded by the shell instead of by .BR nulib . .sp 1 Wildcards are allowed, and subdirectories are recursively descended (the depth is limited only by the maximum length of a pathname and the available memory on the system), unless the .BR r suboption is used. The .BR r suboption will prevent subdirectories from being processed, so that for example .nf nulib avr fubar.shk * .fi (under UNIX) will add all files in the current directory, but will not descend into any subdirectories. The .BR v suboption displays the filenames as they are added. .sp 1 The .BR u suboption adds a file without compressing it. The .BR c suboption allows you to insert a file in the archive with a specific compression algorithm (specified by the argument .IR cval , which must immediately follow the suboption with no intervening spaces. The example .nf nulib ac5v fubar.shk file1 .fi would store .I file1 in .I fubar.shk using 16-bit UNIX-style LZW compression. .IR Value corresponds to the appopriate .B thread_format as specified in the section on compression methods. .sp 1 The .BR s suboption does not compress the file, but will store it as if it were by setting the .BR thread_format field to .IR sval . One use for this is adding compressed files without having to uncompress them first. For example, .nf nulib as1 foo.shk file1.qq .fi adds a squeezed file. This suboption could conceivably cause a NuFX extractor to crash; please don't use it unless you are sure of what you are doing. Note also that some compression methods (like ShrinkIt LZW) require both the "compressed length" and "uncompressed length" values to be correct; use of this suboption will (incorrectly) set them both to the current file length. .sp 1 Only one of the supoptions .BR u , .BR c , or .BR s may be specified. .sp 1 The .BR f suboption allows specification of the filetype attribute. It should be three characters long, and will be matched against a list of standard ProDOS file types. Those abbreviations currently recognised are .nf NON no type (default) BIN binary TXT text SRC source code OBJ object code EXE executable shell program .fi Both upper and lower case letters will match. .sp 1 If the filetype is followed by a "/", then the auxtype field will also be set. .BR Nulib expects the auxtype to be a four-byte hexadecimal number; entering less than four digits could cause the auxtype to be misinterpreted. The following example stores APW C source files: .nf nulib cvfSRC/000a nulib.shk file1.c file2.c ... .fi .sp 1 If the .BR d suboption is given, the entry will be tweaked to make it appear that the file is actually a disk image. This may be useful somewhere. Don't use it if you don't know what you're doing. .sp 1 Adding comments is not currently supported. .IP "\fBb\fR[\fBxvi\fR][\fBt\fIvalue\fR]" .sp 1 .B "Binary II Archive Operations" .sp 1 This option is included for compatibility with the older Binary II standard, since it is still in use by many communications programs. .sp 1 With no suboptions, this will list the information on the archived files specified by .IR filespec . The .BR x suboption extracts the named files from the archive, unsqueezing them if necessary. If the .I filespec parameter is omitted, then all files will be listed or extracted. Note that matches are case-independent. .sp 1 When the .BR v suboption is used in conjunction with the .BR x suboption, the names of the archived files are printed as they are extracted. The .BR v suboption has no effect otherwise. .sp 1 The .BR t suboption will perform a text substitution as it works; see the .B "NEWLINE CONVERSION" section for more information. .sp 1 If the filename of an extracted file would conflict with an existing file, the file will be overwritten and a message will be printed. If the .BR i suboption is used, then .BR nulib will give an "overwrite (y/n)?" prompt. An affirmative answer overwrites the file; a negative answer will skip the file and continue processing. .sp 1 Attempting to perform NuFX operations on a Binary II archive will fail. If the file appears to be Binary II format, then a message indicating this will be printed. Providing transparent support for Binary II archives is not impossible, but isn't needed often enough to be worth doing. .IP "\fBc\fR[\fBvurd\fR][\fBc\fI\fR][\fBs\fI\fR][\fBf\fI\fR[/\fI\fR]]" .sp 1 .BR "Create Archive" .sp 1 This is identical to the .BR a option, but the "creating archive" message is suppressed. .IP "\fBd\fR[\fBv+\fR]" .sp 1 .B "Delete Files" .sp 1 Deletes the named files from the archive. .BR Nulib scans the archive, marking all records that match the names in the file specification (case-independent). If all files are marked for deletion, then the archive file itself is deleted. Otherwise, a new archive is created, the unmarked records are transferred, and the old archive is deleted. An error during this process will leave the original archive unmodified. .sp 1 Note that this does not require an exact match if the .BR "+" suboption is used; the command .nf nulib d+ fubar.shk foo .fi will delete "foo", "Foozle", "food/recipies" and "food/stock." The .BR v suboption prints the list of marked records as it works. .IP "\fBu\fR[\fBvurd\fR][\fBc\fI\fR][\fBs\fI\fR][\fBf\fI\fR[/\fI\fR]]" .sp 1 .B "Freshen Files" .sp 1 Updates files in the archive, but doesn't add any new files. Creates a new archive file, and either transfers the old record or adds the file depending on which is more recent. Only exact filename matches are allowed (case-independent), including partial paths. The archive being updated must already exist. .sp 1 Wildcards are allowed, and subdirectories are automatically expanded unless the .BR r suboption is used. The .BR v suboption displays the filenames as they are added. The .BR u , .BR c , .BR s , and .BR f suboptions, explained under the description for the .BR a option, only apply to files being added to the archive or being updated (files that aren't updated are left unaltered). .sp 1 Files that are updated will retain their previous filetype. New files will get either the default filetype, the filetype specified by the .BR f suboption, or the actual filetype (on the IIgs only), in that order. .sp 1 .IP "\fBh\fR[\fBsnw\fR]" .sp 1 .B "Command Help" .sp 1 Displays a help screen. Three screens are available. .sp 1 The command .nf nulib h .fi alone displays help on the options. The .BR n suboption gives help with numbers; it lists the known compression methods and text translation types. The .BR w suboption gives a brief listing of contributors, and how to contact me. The .BR s suboption gives help on the suboptions. .IP "\fBi\fR[\fBv\fR]" .sp 1 .B "Verify Integrity" .sp 1 Verifies that the archive is intact. Does not modify the archive in any way. The .BR v suboption prints a list of CRCs for each entire record. This is different from those listed by the TZ option, which are only for the record headers and (sometimes) threads; this includes not only the headers but .I all data as well. .sp 1 Please note that this doesn't do much more than read the file, unless the .B record_version is $0002 or greater (which means that the data has a checksum stored; currently these records are only generated by .BR GS/ShrinkIt ), .I and no compression was used. This merely scans the records and verifies the header CRCs, .I not the data CRCs. The main purpose of the .B v suboption is to make a list of CRCs that can be sent along with the archive. .IP "\fBm\fR[\fBvurd\fR][\fBc\fI\fR][\fBs\fI\fR][\fBf\fI\fR[/\fI\fR]]" .sp 1 .B "Move Files to Archive" .sp 1 This is identical to the .BR a option, but the files are deleted after they are added to the archive. Note that the actual directory files are .I not deleted, unless they were given distinct record entries. .sp 1 Care should be taken to avoid trying to move an archive into itself. The act of adding may (depending on the OS and the archive) go into an infinite loop creating a huge file, and the coup de grace is when .BR NuLib then deletes the archive to which you were adding. .IP "\fBp\fR[\fBv+\fR][\fBt\fI\fR]" .sp 1 .B "Print Contents" .sp 1 Print the contents of an archived file without extracting it. Useful for viewing archived text files without having to actually unpack them. Note this only allows viewing of .BR data_threads ; resource forks and disk images will not be displayed, and comments are not shown. I take no responsibility for pagination or filtering of funky control characters ... .sp 1 The .BR v suboption will print the file's name right before it's contents are printed. The .BR + suboption allows you to specify the first part of a pathname; see the .B d or .B x options for details. .sp 1 The .B t suboption will perform a text substitution as it works; see the .B "NEWLINE CONVERSION" section for more information. .IP "\fBt\fR[\fBvaz\fR]" .sp 1 .B "Table of Contents" .sp 1 With no suboptions, this lists only the filenames of the archived files. Not only does this make it easier to view the archive contents (the .BR ShrinkIt format filename field is about 20 characters wide; this is as wide as it has to be), but the output is suitable for transmission via a pipe to other utilities. .sp 1 Using the .B v suboption will make it use .B ShrinkIt v2.0 output format (same as using the .B v option); it is included as a suboption mainly for people used to .BR ar (1). Using the .B a suboption will produce a list similar to the output of ARC or ZOO. .sp 1 Using the .B z suboption will dump everything known about the archive, including all information in headers, CRCs, relative file position, sizes of individual threads, etc. .IP "\fBu\fR[\fBvurd\fR][\fBc\fI\fR][\fBs\fI\fR][\fBf\fI\fR[/\fI\fR]]" .sp 1 .B "Update Files" .sp 1 Updates files in the archive, keeping the archived file or the file listed on the command line, whichever is most recent (or exists). Unlike freshen, this will add new files as necessary. Creates a new archive file, and either transfers the old record or adds the file. Only exact filename matches are allowed (case-independent), including partial pathnames. The archive being updated must already exist. .sp 1 Wildcards are allowed, and subdirectories are automatically expanded unless the .B r suboption is used. The .B v suboption displays the filenames as they are added. The .BR u , .BR c , .BR s , and .BR f suboptions, explained under the description for the .BR a option, only apply to files being added to the archive (files that aren't updated are left unaltered). Note that the order of files in the archive will be preserved. .sp 1 Files that are updated will retain their previous filetype. New files will get either the default filetype, the filetype specified by the .B f suboption, or the actual filetype (on the IIgs only), in that order. .IP "\fBv\fR" .sp 1 .B "Verbose Listing" .sp 1 Lists the archive contents in a format indentical to that used by the ProDOS 8 ShrinkIt v2.0 L)ist archive contents option. This is equivalent to invoking .BR nulib with the options .BR -tv . .IP "\fBx|e\fR[\fBvumi+\fR][\fBt\fI\fR]" .sp 1 .B "Extract From Archive" .sp 1 The .B x and .B e options are synonymous; they extract the specified files from the archive. If the file already exists, you are asked if you want to overwrite it. If part of a partial pathname does not exist, the subdirectory will be created. Omitting .I filespec will cause the entire archive to be unpacked. .sp 1 When files are archived, a pathname separator is stored ("/" for ProDOS and UNIX, "\" for MS-DOS, ":" for Mac HFS). During extraction, the pathnames are broken down into component file names, converted to names legal under the current operating system, and then recombined using the pathname separator for the current OS. This facilitates extraction of files archived under any OS, but can lead to filename conflicts that didn't exist when the files were added (such as a UNIX file that contained a backslash is unpacked under MS-DOS). .sp 1 If the filename of an extracted file would conflict with an existing file, the file will be overwritten and a message will be printed. If the .B i suboption is used, then .BR nulib will give an "overwrite (y/n)?" prompt. An affirmative answer overwrites the file; a negative answer will skip the file and continue processing. .sp 1 Note that extraction does not require an exact match if the .B "+" suboption is specified; the command .nf nulib x+ fubar.shk foo .fi will extract "FOO", "Foozle", "food/recipies" and "food/stock." This makes it possible to extract entire subdirectories at a time. The .B v suboption prints the list of marked records. .sp 1 If comments are present, then the .B v suboption also prints those as it extracts. Using the .B m suboption will cause the comments to be printed, but the files will not be extracted. .IR NOTE : The exact use of the .B m suboption has not been entirely settled. Since it may be desirable to extract comments into a file, future versions of .BR nulib may use .BR x (extract) to put them in a file and .BR p (print) to view them. Comments welcome, caveat emptor, have a nice day. .sp 1 The .B t suboption will perform a text substitution as it extracts; see the .B "NEWLINE CONVERSION" section for more information. .sp 1 The .B u suboption will extract the files without uncompressing them. This is rarely useful, but is easy to implement and is present for the curious. .SH "SUBOPTION SUMMARY" The full meaning of the suboptions are explained in the .B OPTIONS section, above. The following list is intended as a quick reference. The usual meaning of the suboptions are: .IP \fBa\fR ARC/ZOO style format (table of contents listing only) .IP \fBc\fR compression type, followed by a number. The table below shows compression numbers: .RS .nf # Name Abbr Pack? Unpack? 0: Uncompressed unc Y Y 1: SQueezed (sq/usq) squ N Y 2: Dynamic LZW-I (ShrinkIt) shk Y Y 3: Dynamic LZW-II (ShrinkIt) sh2 N Y 4: UNIX 12-bit compress u12 Y Y 5: UNIX 16-bit compress u16 Y Y .fi .RE .IP \fBf\fR file/aux type to add, followed by file/aux type spec .IP \fBd\fR store the files, but mark them as disk images .IP \fBi\fR interactive; prompt before overwriting file .IP \fBm\fR messages (add/extract comments instead of data) .IP \fBr\fR don't recursively descend subdirectories .IP \fBs\fR storage type (store as compressed w/o compressing), followed by number .IP \fBt\fR text translation (CR<->LF), followed by conversion mode. The legal conversion modes (during extraction) are: .nf 0: Convert from CR to this system (Apple files) 1: Convert from LF to this system (UNIX files) 2: Convert from CRLF to this system (MS-DOS files) .fi .IP \fBu\fR store as uncompressed (same as c0) .IP \fBv\fR verbose mode .IP \fBx\fR extract during Binary II operations .IP \fB+\fR match partial pathnames for extract and delete .IP \fBz\fR full output, prints all aspects of archive .SH "NEWLINE CONVERSION" Different operating systems use different line terminators in text files. The table below shows them for some popular systems: .nf Operating System Line Terminator Apple ProDOS CR ($0d) UNIX LF ($0a) MS-DOS CRLF ($0d0a) .fi While .BR nulib will know what kind of terminators the operating system it is running under uses, it cannot reliably determine what kind an archived file uses. Thus, the terminator used on the system where the file was created must be specified. .LP Note that text translation should .I not be performed on non-ASCII files (non-ASCII means anything other than pure text; word processing files and executables are two examples of files that should .I never have text translation performed on them). Doing so will probably ruin the file, causing strange errors. Because of the wide range of files that .BR nulib must handle, it is impractical to automatically determine which files are binaries and which are text. .LP In order to tell .BR nulib what format to expect, you have to specify one of the following .IR value s as an argument to the .B t suboption: .RS .BR 0 -- Convert from CR (Apple to current system). .br .BR 1 -- Convert from LF (UNIX to current system). .br .BR 2 -- Convert from CRLF (MS-DOS to current system). .RE .LP You may wish to use a more suitable and robust program for converting text files after extraction; .BR udl (1) is recommended. .SH ENVIRONMENT .IP \fBNULIBOPT\fR If set, this environment variable will set certain default behavior options. Any number of the following options may be specified, provided that they are separated by commas (no whitespace). .sp 1 An example, suitable for the .BR csh (1) shell, would be: .nf setenv NULIBOPT=verbose,type=SRC,aux=000a .fi .RS .IP \fBverbose\fR This sets verbose operation. The default is non-verbose. .IP \fBinteractive\fR This sets interactive operation. The defalut is non-interactive. .IP \fBtype=\fItypeid\fR This sets the ProDOS file type associated with each file. .IR typeid may be a hexadecimal number or one of .BR NON , or .BR SRC . The default type is .BR NON . .IP \fBaux=\fIauxid\fR This sets the ProDOS auxillary file type associated with each file in the archive. .IR auxid must be a hexadecimal number. .IP \fBcompress=\fIcompressid\fR This is the compression method to be used on the files in the archive. .IR compressid must be a numerical id from the table for the .B c suboption shown in the .IR "SUBOPTION SUMMARY" section above. A value of 2 (shk) is the default. .sp 1 .RE Note that the .B type and .B aux settings of this environment variable do .I not apply when running on the Apple IIgs. Files will be stored with their actual filetypes, regardless of the variable setting. Also, the .B f suboption will override these settings. .SH DIAGNOSTICS Many errors simply cause .BR nulib to exit, leaving the archive in an uncertain state (which sounds fairly evil). If you were extracting, deleting, viewing, or updating when the error occurred, the worst that can happen is you will be left with a bogus temporary file in the current directory (something like .IR nulib.tmp5610 ). .LP If you were adding to an existing archive, the files that were there will be unharmed, but additional files will not appear, and the archive will be oversized. This is because the master header block (which keeps a count of the number of records in the archive) is written last. .LP If you were creating a new archive, the file will be guano. This is because, as mentioned before, the master header block is not written until the very end. Since .BR nulib identifies NuFX archives by looking at certain bytes in the MHB, the file will not be identifiable as NuFX. Note that the .BR m ove option is safer than it looks, because files on disk are not deleted until the archive is safely closed. .SH "KNOWN BUGS" .BR nulib will not archive extended files. This is currently only of concern for versions compiled for the Apple IIgs. .LP Under some systems, using UNIX compress on a file which does not compress will cause the archive's EOF to be larger than it should be. This slack space will be used up if you add more files to the archive (with .BR nulib anyway; no guarantees about .BR ShrinkIt or .BR gshk [GS/ShrinkIt], but there's no reason why they shouldn't work). .LP To be more precise: If the file being compressed doesn't get any smaller, the compression halts and the file is simply stored uncompressed. Because of the way compress works, on some systems the space that would have been occupied by more compressed data is left attached to the file. The ShrinkIt compression does not suffer from this problem. If you add more stuff to the file, .BR nulib will fill the slack space first, .IR not just append to the end of the file. .LP See also the .I "Nulib Auxiliary Documentation" for more information on known bugs. .SH LEGAL This program is Freeware. Please distribute as widely as possible, but don't sell it. Source code is available via e-mail upon request. .LP Users without Usenet/Internet access may send mail to me at the address below. .SH AUTHOR .nf Andy McFadden 1474 Saskatchewan Drive Sunnyvale, CA 94087 .fi .IP \fINOTE\fR: .BR Nulib is currently maintained by Devin Reade, . .SH HISTORY The ShrinkIt and NuFX standards were written by Andy Nicholas. .LP ShrinkIt LZW compression was written by Kent Dickey. LZW-II (a modified version of Kent's algorithm) was designed by Andy Nicholas. The C LZW-II decoder was by Kent Dickey and Frank Petroski (independently and simultaneously). .LP The UNIX compress code adapted from COMPRESS v4.3. .LP The Binary II unpack and unsqueeze C code adapted from unblu.c and usq.c by Marcel J.E. Mol (usq.c based on usq2/sq3 by Don Elton). .LP MS-DOS port was by Robert B. Hess and Bruce Kahn. .SH "SEE ALSO" .BR gshk (1), .BR yankit (1), .BR shrinkit (1), .BR udl (1), and the .IR "NuLib Auxiliary Documentation" . nulib/README100644 765 144 751 6247222561 11221 0ustar gdrusersNuLib v3.25 README ============================================================================== Things work much better if you read both the manual page and the Auxiliary Documentation file; the two documents are complementary. The manual page is provided as nroff(1) source in the file "nulib.1". If you don't have nroff available, a preformatted version is available in the file "nulib.man". The Auxiliary Documentation is in the file "nulib.doc", and is preformatted ASCII text. nulib/Makefile100644 765 144 10322 6247241714 12035 0ustar gdrusers# # UNIX Makefile for NuLib v3.25 # # $Id: Makefile,v 1.6 1996/11/28 07:48:28 gdr Exp $ # # Where should nulib be installed? The man page will go into # $(MANDIR)/man1 BINDIR = /usr/local/bin MANDIR = /usr/local/man # This is Soenke Behrens' udl utility for converting between Apple, # Unix, and MS-DOS newline formats. You only need it if you are # creating a *.taz or *.shk archive of these sources. UDL = /usr/local/bin/udl # To make a smaller executable, you can exclude the Binary II routines # by setting DEFINES= -DNO_BLU # To exclude the UNIX compression routines, add -DNO_UCOMP # Under UTS 2.1, use -eft to make the linker use the EFT library. #EFT=-eft # # Besides the various vendors' compilers, nulib has also successfully # compiled with gcc and lcc. # # 'gcc' should work for all platforms. In addition, the following # compilers have been tested: # AIX 3.2.5, 4.1: cc, xlc (v2) # SunOS 4.x: /bin/cc, /usr/5bin/cc (v2 ?) # Solaris 2.5.1 SunPro cc (v4.0) # HAL Sparc-64 hcc (v1.0) # HPUX cc (v10.10) # CC = cc # Select appropriate flag... -g for debugging, -O for optimized. #OPTIMIZE = -g #OPTIMIZE = -p OPTIMIZE = -O GCC_PARANOIA = -Wall -Wtraditional \ -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith DEFINES = CFLAGS = $(DEFINES) $(OPTIMIZE) $(EFT) # $(GCC_PARANOIA) LDFLAGS = LIBS = #LIBS = -lx # For XENIX/386 users HDRS = nudefs.h nuread.h nuview.h nuadd.h nuext.h nupdel.h nupak.h nuetc.h \ nublu.h nucomp.h nucompfn.h SRCS = numain.c nuread.c nuview.c nuadd.c nuext.c nupdel.c nupak.c nuetc.c \ nublu.c nucomp.c nushk.c nusq.c OBJS = numain.o nuread.o nuview.o nuadd.o nuext.o nupdel.o nupak.o nuetc.o \ nublu.o nucomp.o nushk.o nusq.o ARCFILES= README NOTES Makefile make.apw linker.scr linked.scr \ mkshk nulib.mak nulib.lnk *.h *.c build all: nulib nulib: ${OBJS} ${CC} ${CFLAGS} ${OBJS} -o nulib ${LIBS} nulib.man: nulib.1 nroff -man $< > $@ install: nulib nulib.1 [ -d $(BINDIR) ] || mkdir -p $(BINDIR) [ -d $(MANDIR)/man1 ] || mkdir -p $(MANDIR)/man1 cp -p nulib $(BINDIR) cp -p nulib.1 $(MANDIR)/man1 # # .o targets # nuadd.o: nuadd.c nudefs.h nuread.h nuadd.h nupak.h nuetc.h nublu.o: nublu.c nudefs.h nuview.h nuread.h nuadd.h nupak.h nuetc.h \ nuext.h nublu.h nucomp.o: nucomp.c nudefs.h nuread.h nupak.h nuetc.h nucomp.h nucompfn.h nuetc.o: nuetc.c nudefs.h nuetc.h nuext.o: nuext.c nudefs.h nuread.h nuext.h nupak.h nuetc.h numain.o: numain.c nudefs.h nuread.h nuview.h nuadd.h nuext.h nupdel.h \ nublu.h nupak.h nuetc.h nupak.o: nupak.c nudefs.h nuread.h nucomp.h nucompfn.h nupak.h nuetc.h nupdel.o: nupdel.c nudefs.h nuread.h nuadd.h nupak.h nupdel.h nuetc.h nuread.o: nuread.c nudefs.h crc.h nuread.h nupak.h nuetc.h nushk.o: nushk.c nudefs.h nuread.h nupak.h nuetc.h nusq.o: nusq.c nudefs.h nuetc.h nuread.h nupak.h nuview.o: nuview.c nudefs.h nuview.h nuread.h nuetc.h # # other targets # saber: #load $(CFLAGS) $(SRCS) $(LIBS) # shar version 3.49 # -c : add "cut here" line at top # -o : base name for output files # -l48 : max size is 48KB, but don't split files # -v : (not used) turn off verbose msgs shar: shar349 -c -osh.files/nulib -l48 $(ARCFILES) tar: clobber @fulldir=`pwd`; \ dir=`basename $$fulldir`; \ tarfile="$$dir"325.tar.Z; \ echo "creating ../$$tarfile"; \ cd ..; \ xfile=exclude.$$$$; \ find $$dir -print | grep /CVS > $$xfile; \ tar -X $$xfile -cf - $$dir | compress > $$tarfile; \ rm $$xfile; zip: clobber @fulldir=`pwd`; \ dir=`basename $$fulldir`; \ zipfile="$$fulldir"325.zip; \ /bin/rm -f $$zipfile; \ echo "creating $$zipfile"; \ cd ..; \ tdir=/tmp/nulib.$$$$; \ mkdir -p $$tdir; \ tar -cf - $$dir | (cd $$tdir; tar -xf -); \ cd $$tdir; \ (cd $$dir; make clobber; /bin/rm -rf CVS); \ zip -lr $$zipfile $$dir; \ cd $$fulldir; \ /bin/rm -rf $$tdir; shk: nulib @fulldir=`pwd`; \ dir=`basename $$fulldir`; \ shkfile="$$fulldir"325.shk; \ /bin/rm -f $$shkfile; \ tdir=/tmp/nulib.$$$$; \ echo creating $$shkfile; \ cd ..; \ mkdir -p $$tdir; \ tar -cf - $$dir | (cd $$tdir; tar -xf -); \ cd $$tdir; \ (cd $$dir; make clobber; /bin/rm -rf CVS nulib); \ $(UDL) -gR $$dir; \ $$fulldir/nulib cf $$shkfile $$dir; \ cd $$fulldir; \ /bin/rm -rf $$tdir; clean: @rm -f $(OBJS) *~ clobber: clean @rm -f nulib nulib/nuext.c100644 765 144 54016 6247227102 11707 0ustar gdrusers/* * nuext.c - operations which extract from a NuFX archive * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuext.c,v 1.5 1996/11/28 06:16:34 gdr Exp $ */ #define SEGMENT_NAME "NuMain2___" #include "nudefs.h" #include #include #ifdef BSD43 # include #else /* SYSV, APW, MSC */ # include #endif #include #ifdef __ORCAC__ # include # include # ifndef __GNO__ # define fileno(stream) (stream->_file) # endif #endif #ifdef UNIX # include # include # include # include # ifdef __GNO__ # include # else # include # endif # include #endif #ifdef APW # include # include # include # include #endif #ifdef MSDOS # include # include # include # include # include # include /* need under MSC6? */ # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuread.h" #include "nuext.h" #include "nupak.h" #include "nuetc.h" static BOOLEAN extall; /* extract all files? */ static BOOLEAN print; /* extract to screen rather than file? */ /* * Get the answer to a yes/no question. * * Returns TRUE for yes, FALSE for no. May return additional things in the * future... (y/n/q)? */ int #ifdef __STDC__ AskYesNo(void) #else AskYesNo() #endif { #define BUFFERSIZE 16 char buf[BUFFERSIZE]; printf(" (y/n)? "); fflush(stdout); if (fgets (buf, BUFFERSIZE, stdin) == NULL) { return (FALSE); } if ((*buf == 'y') || (*buf == 'Y')) { return (TRUE); } else { return (FALSE); } } /* * Convert a filename to one legal in the present file system. * * Does not allocate new space; alters string in place (so original string * will be "corrupted"). Assumes that it has been passed a filename without * the filename separators. */ void #ifdef __STDC__ ConvFileName(char *str) #else ConvFileName(str) char *str; #endif { int idx = 0; #ifdef __appleiigs__ /* this should really use the GS/OS 6.0 JudgeName call */ static char *legal = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789."; /* assumes ProDOS limits, not GS/OS */ *str &= 0x7f; if ( ((*str < 'A') && (*str > 'Z')) || ((*str < 'a') && (*str > 'z')) ) *str = 'X'; /* must start with alpha char */ while (*str != '\0') { if (!INDEX(legal, *str)) *str = '.'; if (++idx > 15) { *str = '\0'; break; } str++; } #elif defined(UNIX) while (*str != '\0') { *str &= 0x7f; /* clear hi bit */ if (*str == '/') *str = '.'; if (++idx > 255) { *str = '\0'; break; } /* MAXNAMELEN? */ str++; } #elif defined(MSDOS) char *ostr = str, *prev_dot = NULL; while (*str != '\0') { *str &= 0x7f; /* clear hi bit */ if (*str == '/') *str = '_'; if (*str == '\\') *str = '_'; if (*str == '!') *str = '_'; if (*str == ':') *str = '_'; if (*str == '.') { if (prev_dot != NULL) *prev_dot = '_'; prev_dot = str; } if (++idx > 255) { *str = '\0'; break; } str++; } /* now limit the chars before the '.' to 8, and after to 3 */ /* (if no dot, cut it at 8) */ if (prev_dot == NULL) { if (strlen(str) > 8) str[8] = '\0'; } else { *prev_dot = '\0'; if (strlen(prev_dot+1) > 3) *(prev_dot+4) = '\0'; if (strlen(ostr) > 8) { *prev_dot = '.'; while (*prev_dot) *((ostr++) + 8) = *(prev_dot++); *((ostr++) + 8) = *(prev_dot++); } else *prev_dot = '.'; } #else printf("Need [other] filename converter\n"); /* +PORT+ */ #endif } /* * Set a file's attributes according to info in a record structure. */ #if defined(UNIX) && defined(_POSIX_SOURCE) && !defined(HAS_UTIMBUF) #define HAS_UTIMBUF #endif #ifdef __ORCAC__ static FileInfoRecGS finfo; #endif void #ifdef __STDC__ SetFInfo (char *filename, RHblock *RHptr) #else SetFInfo(filename, RHptr) char *filename; RHblock *RHptr; #endif { #if 0 static char *procName = "SetFInfo"; #endif #if defined(__ORCAC__) TimeRec *trp; finfo.pCount = 7; if ((finfo.pathname = __C2GSMALLOC(filename)) == NULL) { perror("SetFInfo failed"); QuitNulib(-1); } finfo.access = (twobyt) RHptr->access; finfo.fileType = (twobyt) RHptr->file_type; finfo.auxType = RHptr->extra_type; finfo.storageType = 0; /* RHptr->storage_type otherwise */ trp = (TimeRec *) &(RHptr->create_when); finfo.createDateTime = *trp; trp = (TimeRec *) &(RHptr->mod_when); finfo.modDateTime = *trp; SetFileInfoGS(&finfo); TOOL_CHECK("set file info for", filename, 0); free(finfo.pathname); #elif defined(UNIX) long ltime; # ifdef HAS_UTIMBUF struct utimbuf timep; # else time_t timep[2]; # endif ltime = ReduceTime(&RHptr->mod_when); /* set both to mod time */ # ifdef HAS_UTIMBUF timep.actime = ltime; /* accessed */ timep.modtime = ltime; /* modified */ utime(filename, &timep); # else timep[0] = ltime; /* accessed */ timep[1] = ltime; /* modified */ utime(filename, timep); # endif if ((RHptr->access == 0xe3L) || (RHptr->access == 0xc3L)) /* unlocked */ chmod(filename, S_IREAD | S_IWRITE | 044); if ((RHptr->access == 0x21L) || (RHptr->access == 0x01L)) /* locked */ chmod(filename, S_IREAD | 044); #elif defined(APW) /* * Call ProDOS SET_FILE_INFO to set attributes for a file. * Uses the information in the record header block. */ FileRec finfo; OpenRec oinfo; twobyt date, time; long ltime; finfo.pathname = c2pstr(filename); /* temp storage...? */ finfo.fAccess = (twobyt) RHptr->access; finfo.fileType = (twobyt) RHptr->file_type; finfo.auxType = RHptr->extra_type; finfo.storageType = 0; /* RHptr->storage_type otherwise */ ltime = ReduceTime(&RHptr->create_when); date = (twobyt) ltime; /* date is lower 16 */ time = (twobyt) (ltime >> 16); /* time is upper */ finfo.createDate = date; finfo.createTime = time; ltime = ReduceTime(&RHptr->mod_when); date = (twobyt) ltime; /* date is lower 16 */ time = (twobyt) (ltime >> 16); /* time is upper */ finfo.modDate = date; finfo.modTime = time; SET_FILE_INFO( &finfo ); ToolErrChk(); #elif defined(MSDOS) long ltime; time_t timep[2]; ltime = ReduceTime(&RHptr->mod_when); timep[0] = ltime; /* accessed */ timep[1] = ltime; /* modified */ utime(filename, timep); if ((RHptr->access == 0xe3L) || (RHptr->access == 0xc3L)) /* unlocked */ chmod(filename, S_IREAD | S_IWRITE | 044); if ((RHptr->access == 0x21L) || (RHptr->access == 0x01L)) /* locked */ chmod(filename, S_IREAD | 044); #else printf("need [other] SetFInfo stuff\n"); /* +PORT+ */ #endif } /* * Create a subdirectory * * This routine will exit on most errors, since generally more than one file * will be unpacked to a given subdirectory, and we don't want it charging * bravely onward if it's going to run into the same problem every time. */ void #ifdef __STDC__ CreateSubdir(char *pathname) #else CreateSubdir(pathname) char *pathname; #endif { char *buffer = (char *) Malloc(MAXFILENAME+6); static char *procName = "CreateSubdir"; #ifdef __ORCAC__ static CreateRecGS crec; finfo.pCount = 7; if ((finfo.pathname = __C2GSMALLOC(pathname)) == NULL) { perror("SetFInfo failed"); QuitNulib(-1); } GetFileInfoGS(&finfo); if (! _toolErr && finfo.storageType == 0x000d) { /* the directory is already there */ free(finfo.pathname); return; } else if (_toolErr == fileNotFound) { /* we can create the directory */ crec.pCount = 5; crec.pathname = finfo.pathname; crec.access = 0x00c3; crec.fileType = 0; crec.auxType = 0; crec.storageType = 0x000d; /* create a directory */ CreateGS(&crec); TOOL_CHECK("create", pathname, 1); free(finfo.pathname); return; } else { TOOL_CHECK("get file info for", pathname, 1); /* can't create the directory */ } #elif defined(UNIX) struct stat st; /* if no directory exists, then make one */ if (stat(pathname, &st) < 0) if (errno == ENOENT) { sprintf(buffer, "mkdir %s", pathname); if (system(buffer) != 0) /* call UNIX mkdir to create subdir */ Fatal("Unable to create subdir", procName); } else { Fatal("Unable to create dir", procName); } #elif defined(APW) static FileRec create_p = { "", 0x00e3, 0x000f, 0L, 0x000d, 0, 0 }; /*dir*/ FileRec info_p; /* check if file exists, is dir */ int err; /* holds _toolErr */ strcpy(buffer, pathname); c2pstr(buffer); info_p.pathname = buffer; GET_FILE_INFO( &info_p ); switch (_toolErr) { case 0x0000: /* no error */ if (info_p.storageType != 0x000d) /* not a DIR? */ Fatal("File in path exists, is not a directory.", procName); return; /* file exists, is directory, no need to create */ case fileNotFound: create_p.pathname = buffer; CREATE( &create_p ); if (!_toolErr) return; /* created okay? */ else ToolErrChk(); default: /* unknown error */ ToolErrChk(); Fatal("whoops!", procName); /* shouldn't get here */ } #elif defined(MSDOS) struct stat st; /* if no directory exists, then make one */ if (stat(pathname, &st) < 0) if (errno == ENOENT) { if (mkdir(pathname) != 0) Fatal("Unable to create subdir", procName); } else { Fatal("Unable to create dir", procName); } #else /* don't forget to check if it exists first... */ /* +PORT+ */ printf("don't know how to create [other] subdirectories\n"); /* mkdir() */ #endif free(buffer); } /* * Given a pathname, create subdirectories as needed. All file names are run * through a system-dependent filename filter, which means that the pathname * has to be broken down, the subdirectory created, and then the pathname * reconstructed with the "legal" pathname. The converted filename is held * in a static buffer; subsequent calls will overwrite the previous string. * * This is useful when unpacking "dir1/dir2/fubar" and dir1 and dir2 don't * necessarily exist. * * It is assumed that all filenames are relative to the current directory. * According to the NuFX docs (revision 3 2/3/89), initial separators (like * "/", "\", or ":") should NOT be included. If they are, this routine may * break. */ static char * #ifdef __STDC__ CreatePath (char *pathname, onebyt fssep) #else CreatePath(pathname, fssep) char *pathname; /* full pathname; should not include ProDOS volume name */ onebyt fssep; /* file system pathname separator, usually "/" or "\" */ #endif { int idx; char *ptr; static char workbuf[MAXFILENAME]; /* work buffer; must be static */ #if 0 static char *procName = "CreatePath"; #endif idx = 0; while (TRUE) { /* move through string */ ptr = INDEX(pathname, fssep); /* find break */ if (ptr) /* down to actual filename? */ *ptr = '\0'; /* no, isolate this part of the string */ strcpy(&workbuf[idx], pathname); /* copy component to buf */ ConvFileName(&workbuf[idx]); /* convert to legal str; may be shorter */ idx += strlen(&workbuf[idx]); /* advance index to end of string */ if (!ptr) { /* down to actual filename? */ workbuf[idx] = '\0'; /* yes, clean up */ break; /* out of while */ } workbuf[idx] = '\0'; CreateSubdir(workbuf); /* system-dependent dir create */ #if defined(UNIX) || defined(__appleiigs__) workbuf[idx++] = '/'; /* tack a filename separator on, and advance */ *ptr = '/'; /* be nice */ #elif defined(MSDOS) workbuf[idx++] = '\\'; *ptr = '\\'; #else workbuf[idx++] = '/'; *ptr = '/'; #endif /* was: workbuf[idx++] = fssep; *//* tack an fssep on the end, and advance */ /* was: *ptr = fssep; *//* be nice */ pathname = ptr+1; /* go again with next component */ } return (workbuf); } /* * Extract a thread, and place in a file. * * Returns TRUE if the extract was successful, FALSE otherwise. The most * common reason for a FALSE return value is a "no" answer when asked about * overwriting an existing file. */ static BOOLEAN #ifdef __STDC__ ExtractThread (int arcfd, long fileposn, char *destpn, THblock *THptr) #else ExtractThread(arcfd, fileposn, destpn, THptr) int arcfd; /* source file descriptor (must be open) */ long fileposn; /* position of data in source file */ char *destpn; /* destination filename */ THblock *THptr; /* pointer to thread info */ #endif { int dstfd; /* destination file descriptor */ static char *procName = "ExtractThread"; if (!print) { if (Exists(destpn)) { if (interact) { if (verbose) printf("file exists, overwite"); else printf("%s exists, overwite", destpn); if (!AskYesNo()) { /* return w/o overwriting */ return (FALSE); } } if (verbose) { printf("overwriting..."); fflush(stdout); } if (unlink(destpn) < 0) Fatal("Unable to remove existing file", procName); } if ((dstfd = open(destpn, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, (mode_t)WPERMS)) < 0) Fatal("Unable to open target path", procName); if (lseek(arcfd, (off_t) fileposn, S_ABS) < 0) Fatal("Seek failed", procName); if (!UnpackFile(arcfd, dstfd, THptr, dopack ? THptr->thread_format : 0, pakbuf)) { if (close(dstfd) < 0) Fatal("Dest close failed", procName); unlink(destpn); /* some sys can't delete while file open */ } else { if (close(dstfd) < 0) Fatal("Dest close failed", procName); } } else { /* print */ if ((dstfd = fileno(stdout)) < 0) Fatal("Unable to get file for stdout", procName); if (lseek(arcfd, (off_t) fileposn, S_ABS) < 0) Fatal("Seek failed", procName); if (!UnpackFile(arcfd, dstfd, THptr, dopack ? THptr->thread_format : 0, pakbuf)) { printf("Unpack failed.\n"); return (FALSE); } fflush(stdout); } return (TRUE); } /* * Handle message_threads */ static void #ifdef __STDC__ message_thread (int arcfd, RNode *RNodePtr, TNode *TNodePtr) #else message_thread(arcfd, RNodePtr, TNodePtr) int arcfd; RNode *RNodePtr; TNode *TNodePtr; #endif { int oldTo, oldFrom; static char *procName = "message_thread"; switch (TNodePtr->THptr->thread_kind) { case 0x0000: /* ASCII text */ printf("Found obsolete ASCII text thread (ignored)\n"); break; case 0x0001: /* ASCII text, predefined size */ if (verbose && !print && TNodePtr->THptr->thread_eof) { printf("\n--- Comment for file '%s':\n", RNodePtr->filename); fflush(stdout); if (lseek(arcfd, (off_t) TNodePtr->fileposn, S_ABS) < 0) Fatal("unable to seek to comment", procName); oldTo = transto; oldFrom = transfrom; transto = -1; /* switch to CR -> current mode */ transfrom = 0; /* (assumes created under ProDOS) */ /* may need to fix this later (but how?) */ FCopy(arcfd, fileno(stdout), TNodePtr->THptr->thread_eof, pakbuf, TRUE); #ifdef FUBAR print = TRUE; verbose = FALSE; /* turn off "unshrinking..." messages */ ExtractThread(arcfd,TNodePtr->fileposn, "stdout", TNodePtr->THptr); print = FALSE; verbose = TRUE; #endif transto = oldTo; transfrom = oldFrom; putchar('\n'); } break; case 0x0002: /* standard Apple IIgs icon */ printf("Found Apple IIgs Icon thread (ignored)\n"); break; default: printf("Found unknown message_thread %.4x in '%s'\n", TNodePtr->THptr->thread_kind, RNodePtr->filename); break; } } /* * Handle control_threads */ static void #ifdef __STDC__ control_thread (int arcfd, RNode *RNodePtr, TNode *TNodePtr) #else control_thread(arcfd, RNodePtr, TNodePtr) int arcfd; RNode *RNodePtr; TNode *TNodePtr; #endif { switch (TNodePtr->THptr->thread_kind) { case 0x000: /* create dir */ printf("Found create directory control thread (ignored)\n"); break; default: printf("Found unknown control_thread %.4x in '%s'\n", TNodePtr->THptr->thread_kind, RNodePtr->filename); break; } } /* * Handle data_threads * * Does not guarantee that the archive file position is anything rational; * the TNode's fileposn should be (and is) used here. */ static void #ifdef __STDC__ data_thread (int arcfd, RNode *RNodePtr, TNode *TNodePtr) #else data_thread(arcfd, RNodePtr, TNodePtr) int arcfd; RNode *RNodePtr; TNode *TNodePtr; #endif { long fileposn; /* absolute position of thread in file */ long old_eof; char *fn; int ov; if (print) /* this is something of a hack... */ if (TNodePtr->THptr->thread_kind != 0x0000) { /* not a data fork? */ fprintf(stderr, "Can't print non-data fork for '%s'.\n", RNodePtr->filename); return; /* this hoses the file posn... */ } else { if (verbose) printf("\n***** %s *****\n", RNodePtr->filename); fflush(stdout); ov = verbose; verbose = FALSE; /* turn off "unshrinking..." messages */ fileposn = TNodePtr->fileposn; ExtractThread(arcfd,fileposn, "stdout", TNodePtr->THptr); verbose = ov; return; } switch (TNodePtr->THptr->thread_kind) { case 0x0000: /* data fork */ if (verbose) { printf("Extracting '%s' (data)...", RNodePtr->filename); fflush(stdout); } /* create any needed subdirs */ fn = CreatePath(RNodePtr->filename, RNodePtr->RHptr->file_sys_info); /* extract the file */ if (ExtractThread(arcfd, TNodePtr->fileposn, fn, TNodePtr->THptr)) { SetFInfo(fn, RNodePtr->RHptr); /* set file attributes, dates... */ if (verbose) printf("done.\n"); } break; case 0x0001: /* disk image */ /* printf("Found disk image (not extracted)\n");*/ if (verbose) { printf("Extracting '%s' (disk image)...", RNodePtr->filename); fflush(stdout); } /* setup path (normalize file name) */ fn = CreatePath(RNodePtr->filename, RNodePtr->RHptr->file_sys_info); /* thread_eof is invalid for disks, so figure it out */ old_eof = TNodePtr->THptr->thread_eof; if (RNodePtr->RHptr->storage_type <= 3) { /* should be block */ TNodePtr->THptr->thread_eof = /* size, but shk301 */ RNodePtr->RHptr->extra_type * 512; /* stored it wrong */ } else { TNodePtr->THptr->thread_eof = RNodePtr->RHptr->extra_type * RNodePtr->RHptr->storage_type; } /* extract the disk into a file */ if (ExtractThread(arcfd, TNodePtr->fileposn, fn, TNodePtr->THptr)) { /*SetFInfo(fn, RNodePtr->RHptr);*//* set file attributes, dates... */ if (verbose) printf("done.\n"); } TNodePtr->THptr->thread_eof = old_eof; break; case 0x0002: /* resource_fork */ printf("Found resource_fork (not extracted)\n"); break; default: printf("Found unknown data_thread %.4x in '%s'\n", TNodePtr->THptr->thread_kind, RNodePtr->filename); break; } } /* * Extract files from archive * * Scan archive, extracting files which start with the strings in "names". * Calls subroutines to handle the various thread_class types. */ static void #ifdef __STDC__ Extract (char *filename, int namecount, char **names) #else Extract(filename, namecount, names) char *filename; int namecount; char **names; #endif { ListHdr *archive; int arcfd; /* archive file descriptor */ int rec, idx; MHblock *MHptr; /* Master Header block */ RNode *RNodePtr; /* Record Node */ TNode *TNodePtr; /* Thread block */ int len, *lentab; /* hold strlen() of all names */ char *pn; /* archived pathname */ int thread; /* current thread #; max 65535 threads */ BOOLEAN gotone = FALSE; static char *procName = "Extract"; archive = NuRead(filename); if ((arcfd = open(archive->arc_name, O_RDONLY | O_BINARY)) < 0) Fatal("Unable to open archive", procName); pakbuf = (onebyt *) Malloc(PAKBUFSIZ); /* allocate unpack buffer */ if (!namecount) { extall = TRUE; lentab = (int *) NULL; } else { lentab = (int *) Malloc(sizeof(int) * namecount); for (idx = 0; idx < namecount; idx++) /* calc. once (for efficiency) */ lentab[idx] = strlen(names[idx]); } MHptr = archive->MHptr; RNodePtr = archive->RNodePtr; /* main record read loop */ for (rec = 0; rec < MHptr->total_records; rec++) { pn = RNodePtr->filename; len = strlen(pn); if (RNodePtr->RHptr->version_number > MAXVERS) { printf("Unable to extract '%s': unknown record version_number\n", pn); continue; /* with for */ } for (idx = 0; extall || idx < namecount; idx++) { /* find arced file */ /* try to match argument with first few chars of stored filename */ /* or the entire filename, depending on EXPAND flag */ if (extall || ((len >= lentab[idx]) && doExpand ? (!strncasecmp(pn, names[idx], lentab[idx])) : (!strcasecmp(pn, names[idx])) )) { gotone = TRUE; /* go through all threads */ TNodePtr = RNodePtr->TNodePtr; for (thread = 0; thread < (int) RNodePtr->RHptr->total_threads; thread++) { switch(TNodePtr->THptr->thread_class) { case 0x0000: message_thread(arcfd, RNodePtr, TNodePtr); break; case 0x0001: control_thread(arcfd, RNodePtr, TNodePtr); break; case 0x0002: /* don't extract if doMessages is set */ if (!doMessages) data_thread(arcfd, RNodePtr, TNodePtr); break; case 0x0003: /* filename_thread; ignore */ break; default: printf("Unknown thread_class %.4x for '%s'\n", TNodePtr->THptr->thread_class, RNodePtr->filename); break; } TNodePtr = TNodePtr->TNext; } break; /* out of filename matching (inner) FOR loop */ } } RNodePtr = RNodePtr->RNext; /* move on to next record */ } if (!gotone && verbose) printf("None selected\n"); if (close(arcfd) < 0) Fatal("Source (archive) close failed", procName); } /* * Entry point to extract routines. */ void #ifdef __STDC__ NuExtract (char *filename, int namecount, char **names, char *options) #else NuExtract(filename, namecount, names, options) char *filename; int namecount; char **names; char *options; #endif { #if 0 static char *procName = "NuExtract"; #endif if (*options == 'p') { /* printing rather then extracting to file */ print = TRUE; dopack = TRUE; /* no extract uncompressed! */ } else print = FALSE; Extract(filename, namecount, names); /* do stuff */ } nulib/nuext.h100644 765 144 1050 6246126406 11666 0ustar gdrusers/* * nuext.h - declarations for nuext.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuext.h,v 1.3 1996/11/03 23:01:04 gdr Exp $ */ #define MAXDEPTH 64 /* max subdir depth we will unpack */ extern int AskYesNo __P((void)); extern void ConvFileName __P((char *str)); extern void NuExtract __P((char *filename, int namecount, char **names, char *options)); extern void SetFInfo __P((char *filename, RHblock *RHptr)); extern void CreateSubdir __P((char *pathname)); nulib/nulib.doc100644 765 144 51365 6264125776 12221 0ustar gdrusers NuFile eXchange (NuFX) Archive Utility NuLib v3.2.5 Auxiliary Documentation By Andy McFadden September 23, 1992 Modifications by Devin Reade January 5, 1997 Overview -------- This document is intended to enlarge on the information provided in the manual page. As duplication of information has been minimized, you need to read both this and the man page for complete information on NuLib. Where this document is written in the first person, the words are those of Andy McFadden's. Background ---------- For our purposes, an archive is simply a collection of one or more files stored as a single file. This allows groups of related files to be stored under a single filename, reducing directory clutter, and makes it possible to transfer groups of files without the use of a batch transfer utility. To reduce the space required to store the archives and the time it takes to transfer archives, most popular archiving programs automatically compress files as they are stored. Two popular compression methods are Huffman (variable-size codes are used, with smaller codes assigned to bytes that appear frequently) and Lempel-Ziv-Welch (LZW; finds common substrings in the file). Popular archiving programs include "BLU" (Apple II), "ShrinkIt" (Apple II), "GS/ShrinkIt" (Apple IIgs), "ARC"/"PKARC" (MS-DOS), "PKZIP" (MS-DOS), "lharc" (MS-DOS/Amiga), "zoo" (MS-DOS/Amiga), "PackIt" (Macintosh), "StuffIt" (Macintosh), "tar" (UNIX), and "ar" (UNIX). UNIX archivers don't generally compress files; a separate program (called "compress" of all things) is usually used. NuLib works with archives that ShrinkIt produces (NuFX). Regarding the program name, what started out as a NuFX viewer turned into a full-blown archiver. It went from NuView to NuARC, which was reasonable... until I spoke to Andy Nicholas. Apparently he'd been warned against using the name NuARC, so I had to pick a new one. "CShrink" seemed the most rational, since it is coded entirely in C and is meant to complement ShrinkIt. However, L&L now owns the name "ShrinkIt", so I switched over to NuLib. My other choice was "NuPak", but that's now a completely different (but compatible) program. Sigh. A rose by any other name would be as full of thorns. Excuses ------- The code is written to be portable first, efficient second. If you see a way to retain portability across a *wide* range of machines (from a //gs to a Cray) but increase efficiency, please let me know. Because of the way this was developed (archive viewer -> simple extractor -> extractor with extra goodies, plus the NuFX standard kept changing while I was working), I haven't exactly followed top-down programming practices. It shows (wince). Some of the procedures are rather long. Good progamming practice dictates that no procedure should be longer than your screen; my screen (a Sun 3/50 running X10) has 62 lines at the moment. This is certainly no excuse for procedures in excess of 150 lines, but I have tried to break things down into pieces within the procedures themselves. Some program-wide globals are used; most are boolean values or some special control variables that have to be visible across several files. Probably the worst is "onebyt *pakbuf", which was used so that I didn't have to keep malloc()ing a 64K buffer every few calls. It should be malloc()ed ONLY by routines called directly from main(), and should be free()d at the end of those procedures (which should cause execution to go back to main()). Another bad one is tmpNameBuf. I was worried about having multiple 1K buffers filling static storage (or the stack), so I made this... it is intended to be *very* temporary; don't make any calls to other NuLib procedures and expect it to survive. Compression Methods ------------------- The following methods are defined in the NuFX documentation: (# = method number, Name = method name [abbreviation], Pack? and Unpack? refer to the ability of NuLib to perform that operation using the given compression method. # Name Pack? Unpack? 00 Uncompressed [unc] Y Y 01 SQueezed [squ] N Y 02 Dynamic LZW I (ShrinkIt) [shk] Y Y 03 Dynamic LZW II (ShrinkIt) [sh2] N Y 04 12-bit UNIX Compress [u12] Y Y 05 16-bit UNIX Compress [u16] Y Y Attempting to use a compression method that does not exist will result in an error message like "[can't squeeze; storing]...". This means that the compression method you requested is unavailable, and it simply stored the file without compression. If you try to extract a file that has been compressed with an algorithm that NuLib is not familiar with, an error message will be printed and the file will not be extracted. WARNING: As of this writing, ShrinkIt v3.4 is not able to extract archived files compressed with UNIX compress. However, GSHK (GS/ShrinkIt) can uncompress these files. Limitations ----------- NuLib works just fine with records containing more than one thread (i.e., comments and resource forks). However, while comments can be printed, they can't be added. The big problem this program has is speed. Since it is meant to be portable first and efficient second, it won't run as fast as something like ShrinkIt (written entirely in assembly). What I envision is people using ShrinkIt at home on their Apple //s, but NuLib on UNIX systems or other microcomputers. This will facilitate transfers of large compressed files, which can then be quickly unpacked on the destination system (which will likely have greater computing power, or a C compiler more efficient than APW). Compilation ----------- In both cases, BE SURE to modify "nudefs.h" first. If you don't, the compilation will halt in "numain.c" on a line which reminds you to change "nudefs.h" (I tended to forget about this). Also, under APW make sure all the file types are set to SRC, and the auxtype to CC. These are changed with the commands "filetype" and "change", respectively. Configuration: You might not have to explicitly configure nulib for your system; see the section on Compilation, below. All system specific configuration is set up in the file "nudefs.h". The format of the configuration section is along the lines of #if defined(identifier1) #define configA #define configB #elif defined(identifier2) #define configC #define configD ... #else %%% Error: Unsupported architecture. %%% #endif where "identifier1" and "identifier2" are unique macros implicitly defined by the compiler for the current arch/os combination. Don't comment out the "%%% Error ..." section; it's there for a reason. If you are porting to an as-yet unsupported arch/os/compiler combination, please add in another "#elif defined()" block immediately prior to the #else described above. Once you have your implementation running, please send either a patch or a copy of your sources to Devin Reade. Please don't break other implementations by commenting out code or doing other incompatible changes. Also, please don't make changes just for the sake of coding style, indentation, etc; the smaller diffs the better (yes, I know the code is not pretty). There are definitions for one byte, two byte, and four byte variable types; my compiler uses char, short, and long. If these are different for your compiler, be sure to change the typedefs in "nudefs.h". If you don't have 8-bit bytes, though, it may not work (most machines do). Header Files: In order for typdefs, #defines, and other constructs to resolve correctly, header files should be included in the following order: #include "nudefs.h" #include <...> /* required system headers */ #include "..." /* other NuLib headers */ If you find additional header files are required when doing a new port, please place them in an "#ifdef compiler_identifier" block. Architecture Specific Code: Any architecture specific code should be #ifdef'd appropriately. The typical format for this is as follows with "/* +PORT+ */" indicating sections of code that might be suitable for platforms not yet supported: #ifdef UNIX ... Unix code segment ... #elif defined(__ORCAC__) ... Orca/C code segment ... #elif defined(APW) ... APW/C code segment ... #elif defined(MSDOS) ... MS-DOS code segment ... #else ... "unknown" arch code segment, if any ... /* +PORT+ */ #endif Notes on UNIX implementation: To compile this on a supported UNIX system, you should be able to just type "make". Currently supported systems are: AIX 3.2.5 with cc v2, xlc v2, and gcc v2.7.2 AIX 4.1 with cc v2, xlc v2, and gcc v2.7.2 HAL Sparc-64 OS with hcc v1.0 and gcc v2.7.2 HPUX with cc v10.10 and gcc v2.7.2 Linux with gcc v2.6.3 and lcc v3.4b Solaris 2.4 with SunPro C v4.0 and gcc v2.7.2 Solaris 2.5.1 with SunPro C v4.0 and gcc v2.7.2 SunOS 4.3 with /usr/5bin/cc and gcc v2.7.2 If you are trying to compile this for an as-yet unsupported system, you will have to modify the "nudefs.h" file as explained in the Configuration section above. Ensure you #define UNIX and any other appropriate macros, such as BSD43 (for a BSD-based system), or SYSV (for a System V platforms). The macros used for supported systems can be used as a guide. Under APW, breaking down the full pathnames into relative pathnames is easy (and should be under MS-DOS as well...). Under UNIX ".." is an actual directory link, so obtaining a fully expanded pathname with no redundancies is difficult. Thus, storing "dir1/../dir1/foo" would appear as "dir1/foo" under APW but "dir1/../dir1/foo" under UNIX. Care must be taken when extracting such files on non-UNIX systems; they are best avoided entirely. One nasty pitfall is using "~/foo" under the C shell... If the UNIX owner access permissions include write permission, the file will be stored as unlocked. If write permission is denied, it will be stored as locked. As far as dates are concerned, the modification and access times will both be set to the modification time. UNIX doesn't really have a create_time field; it has accessed, modified, and "changed". Modified gets reset when the data gets modified; changed gets reset by chmod, chown, link, mknod, rename, unlink, utimes, write, and truncate. Anyway, the "modified" field is set what it should be, but I'm going to let the "changed" and "accessed" fields take care of themselves (in other words, I don't intend to modify them... besides, you can't change the "changed" field anyway). When compiling this on a Sun 3/50, I noticed a problem: the byte ordering for the //gs (65816) and the Sun (68020) are backward. The present version of NuLib will automatically determine the byte ordering and treat data appropriately (although this may fail if the data size definitions are wrong). You may need to deal with the HAS_EFT stuff, especially if your compiler complains that "mode_t" or "off_t" are undefined. Send some mail to me if you can't get it to work at all. Notes on //gs implementation: There is very little //gs-specific code, except where absolutely necessary (time routines, file type handling, etc). GS/OS support is absent (extended files are not handled yet, different file systems are not recognized, and pseudo-mixed-case ProDOS filenames are stored as upper case). Some of the faults belong to APW ... APW and Orca shell-specific code has been avoided where possible. Places where I couldn't easily work around it include wildcard expansion and ERROR(). It was deliberately used in several places to allow the user to STOP() processing with Apple-period. Unfortunately, the startup code (2/start) provided with APW and the methods of argument passing used by ECP-16 and ProSel-16 aren't compatible. This means that you can run NuLib from ECP or ProSel, but you can't pass it any arguments (which pretty much defeats the purpose). This may also be true for Orca/C (it is unverified). Orca/C Notes: Unfortunately, due to various library deficiencies, neither the GNO nor Orca/C version is yet running correctly, although they _do_ compile. I (Devin) plan to complete this ... The large memory model is needed because of the large amount of global storage. Lots of memory for compilations also seems to be needed. It is likely that separate versions will have to be compiled for GNO and Orca/C. The most limiting piece of code right now is that used for traversing directories: The GNO method of using struct dirent code cannot be used under Orca/Shell (stat(2) problems?), and there is a GNO v2.0.4 kernel bug in which NextWildcardGS will not traverse directories ... To make the GNO version, type "dmake". The file "makefile.mk" will be used. To make the Orca/Shell version, type "make.orca". This is a exec shell script that behaves similar to a makefile. APW/C Notes: To make the APW C version, put all the files in one directory, and make a subdirectory called "OBJ\ ". Put the "linked.scr" and "linker.scr" files in OBJ, and then "make.apw". This will compile all the files. When it finishes\ , change to OBJ and "alink linked.scr" (standard linker) or "alink linker.scr" (ZapLink). The makefile used to do this automatically, but with only 1.25MB of RAM you have to exit APW to purge all the memory used by the compiler, and and then restart APW and run the linker. There is a bug (not my fault) when using the P option to print \ a file. The file gets printed on one line for some reason... If you redirect the I/O to a file, everything comes out fine. Weird. Notes on MS-DOS implementation: To make the MS-DOS version, use the nulib.mak and nulib.lnk files with MS C (supplied by Bruce Kahn). The user interface may be slightly different from the UNIX and APW versions, so that MS-DOS users will feel more at home when using the program. The only major deviation is in the handling of subdirectory expansion. A future version may select the ARC/ZOO output format as default. Bugs / Glitches --------------- UNIX lseek uses longs, which are usually four bytes. Signed. If an archive is larger than 2 gigabytes, there may be a problem (cough). This isn't a problem if the system has EFT. Pathnames longer than the #defined maximum (1024 bytes) will not be processed. This is the limit on most machines, and is well in excess of most people's sanity. Pathnames with a null ('\0') in them should generally be avoided. Some partial pathname comparisons may fail because pathname separators vary between operating systems. File naming conventions can result in collisions (ex: "foo+" and "foo~" are unpacked under ProDOS, where both are translated to "foo."). Also, you will probably need to be in the same directory each time you U)pdate an archive, or else the partial pathnames won't match (update requires an EXACT match), and you'll end up with two different copies of the same file. The same file may be added/extracted/whatever more than once if the user enters multiple file selectors on the command line ("nulib av foo.shk file1 file1 file1"). This means that U)pdate could insert the same file twice, etc. NuLib does not at present prevent an archive from being added to itself. This can have unfortunate consequences, especially in conjunction with the M)ove option. The ProDOS three-letter filetype names may or may not be the offical Apple versions. Some users may have problems with things like "$00" because '$' is a csh metacharacter (job control). Error output is informative but ugly (mostly debugging-type messages). Error handling is somewhat fatal in most cases. The code is fairly large, currently around 260K (around 7000 lines of C). It takes a while to compile it, and can be difficult if you only have 1.25MB of RAM (kill your DAs and purge before you link!) Under some systems, using UNIX compress on a file which does not compress will cause the archive's EOF to be larger than it should be. This slack space will be used up if you add more files to the archive (with NuLib anyway; no guarantees about ShrinkIt or GS/ShrinkIt, but there's no reason why they shouldn't work). (Just to make things clear: if the file being compressed doesn't get any smaller, the compression halts and the file is simply stored uncompressed. Because of the way compress works, on some systems the space that would have been occupied by more compressed data is left attached to the file. The ShrinkIt compression does not suffer from this problem. If you add more stuff to the file, NuLib will fill the slack space first, NOT just append to the end of the file). To Do (Maybe Someday) --------------------- This is a wishlist of sorts. Don't hold your breath: - Finish port for Orca/Shell and GNO. - NuLib was updated to version 3.25 without the availability of a compiler for MS-DOS. No doubt this has broken certain portions of the code. The MS-DOS version needs to be updated and verified. - Allow CR <-> LF translation when ADDING files. - Improve GS/OS handling. Need to handle resource forks and file system IDs. - Add to thread methods (insert ASCII messages, etc). - Add different compression methods (LZH?). - Do a port to: Win95/NT OS/2 Author Info ----------- NuLib was written by Andy McFadden . It is currently maintained by Devin Reade . You should send bug reports to Devin. No relation to the author of ShrinkIt and NuFX, Andy Nicholas. This was and continues to be my idea; throw all kudos and blame in my general direction. All code herein is mine, developed from the NuFX Documentation Revisions three through five (the latter from Call -A.P.P.L.E.), except as noted below. Dynamic LZW-I (ShrinkIt) by Kent Dickey. LZW-II compression (LZW-I with table clears) designed by Andy Nicholas. C implementation by Frank Petroski and Kent Dickey (independently and simultaneously). MS-DOS code by Robert B. Hess and Bruce Kahn. The Binary II routines and the unSQueeze code were adapted from the C source by Marcel J.E. Mol (usq.c based on usq2/sq3 by Don Elton). UNIX compress code from COMPRESS v4.3 (see source for detailed author information). Andy McFadden may also be reached via US mail at: Andy McFadden 1474 Andy McFadden 1474 Saskatchewan Dr. Sunnyvale, CA 94087 Andy Nicholas, the author of ShrinkIt and affiliated products (ShrinkIt ][+, UnshrinkIt ][+, GS/ShrinkIt), may be contacted at: Internet : shrinkit@Apple.COM CompuServe : 70771,2615 Genie, AOL : shrinkit The following people contributed in the testing (and in some cases, the development) of NuLib v3.25. Kudos to them: David Empson Dave Huang Nathan Mates Steven Nelson J.L. Walters Tony Ward Legal Stuff ----------- (I'm not sure about all of these, but I'd like to cover all the bases): ShrinkIt is a trademark of L&L Productions, Inc (...or is it?). ARC is owned by SeaWare. Apple is a tradmark of Apple Computer, Inc. MS-DOS is (probably) a trademark of Microsoft, Inc. PKZIP is (probably) a trademark of PKWare. The following attribution applies to distributions which contain a binary of NuLib compiled with Orca/C: This program contains material from the Orca/C Run-Time Libraries, copyright 1987-1996 by Byte Works, Inc. Used with permission. I have not seen source code for ShrinkIt(tm) or for the compression routines used within it, except as provided to me in C by Kent Dickey. Disclaimers, borrowed from Dave Whitney and Andy Nicholas: This program is FREEWARE; both source and binaries may be distributed freely, but not sold. If you wish to include NuLib in the distribution of a commercial product, you will need to get my permission beforehand. Distribute as widely as possible, but please include this documentation with the binaries and/or sources. Copyright (C) 1989-1996 by Andy McFadden. All rights reserved. I (Andy McFadden) MAKE NO WARRANTY ON THIS MANUAL OR SOFTWARE, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO QUALITY, MANUAL'S ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL I BE HELD RESPONSIBLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OF THE SOFTWARE OR INACCURACY IN THE MANUAL. In other words, I have tested the program to the best of my ability, and I find that as distributed by me, it is safe for general use. It isn't necessarily bug-free, and as a result, loss of data, however unlikely, is entirely possible. Use at your own risk, but also for your own enjoyment. (The above disclaimers also apply to others who contribute to the maintenance of this code from time to time.) nulib/nulib.lnk100644 765 144 271 6246126406 12155 0ustar gdrusers nuadd.obj+nublu.obj+nuetc.obj+nuext.obj+numain.obj+nupak.obj+nupdel.obj+ nuread.obj+nushk.obj+nusq.obj+nuview.obj+nucomp.obj NuLib NuLib.Map /STACK:10000 /NOI /EXE /FAR /PACKC ; nulib/nulib.mak100644 765 144 3321 6246126406 12160 0ustar gdrusers # NuLib v3.02 makefile for Microsoft C #=================================================================== # # Standard command line definitions # # Note /DIAPX286 can also be used, but it is not a real indicator # of the system hardware # # Leaving out the /W3 will reduce the flood of warning messages. # #=================================================================== #cp=cl /c /AL /W3 /Ot /Zpei /DIAPX386 cp=cl /c /AL /W3 /Os /Zpei /DIAPX386 #=================================================================== # # Default inference rules # #=================================================================== .c.obj: $(cp) $*.c #=================================================================== # # Dependencies # #=================================================================== nuadd.obj: nuadd.c nudefs.h nuread.h nuview.h nuadd.h nupak.h nuetc.h nublu.obj: nublu.c nudefs.h nuview.h nuadd.h nupak.h nuetc.h nuetc.obj: nuetc.c nudefs.h apwerr.h nuetc.h nuext.obj: nuext.c nudefs.h nuread.h nuext.h nupak.h nuetc.h numain.obj: numain.c nudefs.h nuread.h nuview.h nuadd.h nuext.h nupdel.h \ nublu.h nupak.h nuetc.h nupak.obj: nupak.c nudefs.h nupak.h nuetc.h nucomp.h nucompfn.h nupdel.obj: nupdel.c nudefs.h nuread.h nuadd.h nupak.h nupdel.h nuetc.h nuread.obj: nuread.c nudefs.h crc.h nuread.h nupak.h nuetc.h nushk.obj: nushk.c nudefs.h nuread.h nupak.h nuetc.h nusq.obj: nusq.c nudefs.h nuetc.h nuview.obj: nuview.c nucomp.obj: nucomp.c nudefs.h nucomp.h nucompfn.h NULIB.exe: nuadd.obj nublu.obj nuetc.obj nuext.obj numain.obj nupak.obj \ nupdel.obj nuread.obj nushk.obj nusq.obj nuview.obj nucomp.obj link @NuLib.lnk nulib/nupak.c100644 765 144 36614 6247227103 11667 0ustar gdrusers/* * nupak.c - interface to the compression routines * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nupak.c,v 1.4 1996/11/28 06:16:35 gdr Exp $ */ #define TRY_II #define SEGMENT_NAME "Compress__" #include "nudefs.h" #include #include "nuread.h" /* need THblock */ #include "nucomp.h" /* includes "nucompfn.h" + "types.h" */ #ifdef UNIX #include #endif #ifdef MSDOS /* for file I/O */ # include # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nupak.h" #include "nuetc.h" #define CONVSIZ 1024 long packedSize; /* global - size of file after packing */ onebyt lastseen; /* used in crlf(); must be set by caller */ /* * Make a little spinning thing. * * This just lets the user know that the whole thing hasn't stalled on him. * Prints a character, then backspaces so that the next thing will overwrite * it. * * Currently called by FCopy(), unpak_SHK(), pak_SHK() */ void #ifdef __STDC__ Spin(void) #else Spin() #endif { static char *sp = "/-\\|"; static int posn = 0; posn++; if ((posn < 0) || (posn > 3)) posn = 0; putchar(sp[posn]); putchar('\b'); fflush(stdout); } /* * Convert the end-of-line terminator between systems. * * Compile-time defines determine the value that things are translated to; * the value of "translate" determines what they are translated from. This * will write the contents of the buffer to the passed file descriptor, * altering bytes as necessary. Max buffer size is 64K. Note that the * syntax is the same as for write(); * * This would have been a lot easier without IBM... lastseen is the last * character seen (used only in CRLF translations). This needs to be set * by the caller (FCopy(), extract_files()). * * The putc_ncr() procedure in nusq.c does its own processing; this was * somewhat unavoidable. * * BUGS: This proc will have to be re-written. It would be nice to be * able to pack files with a CRLF translation, not just unpack... but you * can't just do buffer writes for that. It'll take some work, and will * probably appear in the next version. */ unsigned int #ifdef __STDC__ crlf (int dstfd, onebyt *buffer, unsigned int length) #else crlf(dstfd, buffer, length) int dstfd; onebyt *buffer; unsigned int length; #endif { register BOOLEAN doconv; register onebyt *bptr = buffer; register unsigned int idx; static char *procName = "crlf"; unsigned int partial; /* size for partial read/write */ onebyt tobuf[2048]; onebyt *toptr; unsigned int origlength = length; if ((transfrom == -1) && (transto == -1)) { /* no translation necessary */ return (write(dstfd, buffer, length)); } if (transfrom < -1 || transfrom > 2) { fprintf(stderr, "%s: unknown translation type %d\n", prgName, transfrom); fprintf(stderr, "%s: assuming conversion 0 (from CR)\n", prgName); transfrom = 0; } if (transto < -1 || transto > 2) { fprintf(stderr, "%s: unknown translation type %d\n", prgName, transto); fprintf(stderr, "%s: assuming conversion 0 (to CR)\n", prgName); transto = 0; } /* macro defs for system-dependent actions */ #ifdef __appleiigs__ # define DEFCONVFROM if (*bptr == 0x0d) /* CR */ \ doconv = TRUE # define DEFCONVTO *(toptr++) = 0x0d #elif defined(UNIX) # define DEFCONVFROM if (*bptr == 0x0a) /* LF */ \ doconv = TRUE # define DEFCONVTO *(toptr++) = 0x0a #elif defined(MSDOS) # define DEFCONVFROM if ((*bptr == 0x0a) && (lastseen == 0x0d)) { \ doconv = TRUE; \ toptr--; /*already put CR; back up over it*/ \ } \ lastseen = *bptr # define DEFCONVTO *(toptr++) = 0x0d; \ *(toptr++) = 0x0a #else # define DEFCONVFROM if (*bptr == 0x0a) /* LF */ \ doconv = TRUE #endif while (length != 0) { if (length > CONVSIZ) { partial = CONVSIZ; length -= CONVSIZ; } else { partial = length; length = 0; } /* uses an explicit flag rather than "continue" for clarity... */ toptr = tobuf; for (idx = partial; idx > 0; idx--, bptr++) { doconv = FALSE; switch (transfrom) { case -1: /* convert from current system's terminator */ DEFCONVFROM; break; case 0: if (*bptr == 0x0d) /* CR */ doconv = TRUE; break; case 1: if (*bptr == 0x0a) /* LF */ doconv = TRUE; break; case 2: if ((*bptr == 0x0a) && (lastseen == 0x0d)) { doconv = TRUE; toptr--; /*already outputed CR; back up over it*/ } lastseen = *bptr; break; } if (doconv) { switch (transto) { case -1: /* convert to current system's terminator */ DEFCONVTO; break; case 0: *(toptr++) = 0x0d; break; case 1: *(toptr++) = 0x0a; break; case 2: *(toptr++) = 0x0d; *(toptr++) = 0x0a; break; } } else { *(toptr++) = *bptr; } } /* for loop */ if (write(dstfd, tobuf, (toptr-tobuf)) != (toptr-tobuf)) Fatal("Dest write failed", procName); } /* while loop */ return (origlength); } /* * Read a file, and place in another file at current posn. We can't read more * than PAKBUFSIZ at a time, so for some files it will have to be broken down * into pieces. Note PAKBUFSIZ is expected to be an int (defined in nupak.h), * and can't be any larger than read() can handle (64K... unsigned 16-bit int). * * The transl option is present for NuUpdate and NuDelete, which have to * copy old records to a new archive w/o performing translation. */ void #ifdef __STDC__ FCopy (int srcfd, int dstfd, fourbyt length, onebyt *copybuf, BOOLEAN transl) #else FCopy(srcfd, dstfd, length, copybuf, transl) int srcfd; /* source file descriptor (must be open & seek()ed) */ int dstfd; /* destination file descriptor (must be open & seek()ed) */ fourbyt length; /* number of bytes to copy */ onebyt *copybuf; BOOLEAN transl; /* maybe do text translation? */ #endif { unsigned int partial; /* size for partial read/write */ static char *procName = "FCopy"; if (transl) lastseen = '\0'; while (length != 0L) { if (length > (long) PAKBUFSIZ) { partial = (unsigned int) PAKBUFSIZ; length -= (long) PAKBUFSIZ; if (verbose) Spin(); } else { partial = (unsigned int) length; length = 0L; } if (read(srcfd, copybuf, partial) != partial) Fatal("Source read failed", procName); if (transl) { /* do text translation if user wants it */ if (crlf(dstfd, copybuf, partial) != partial) Fatal("Dest write failed (c)", procName); } else { /* NEVER do translation */ if (write(dstfd, copybuf, partial) != partial) Fatal("Dest write failed (w)", procName); } } } /* * Add a range of bytes from one file into another, packing them. * * Set up stuff, then call the appropriate pack routine. Returns the actual * algorithm used (thread_format), since the compression algorithm could * fail, storing the file in uncompressed format instead. The packed length * is stored in a global variable. * * Since we're only using version 0 records, we don't need to propagate the * thread_crc. * * Compression routines must do the following: * - compress data from one file descriptor to another, given two seeked * file descriptors and a length value. They may not rely on EOF conditions * for either file. * - return the packing method actually used. If they cope with failure * by starting over with something different, the successful method should * be returned. Failure may be handled in the switch statement below. */ twobyt #ifdef __STDC__ PackFile (int srcfd, int dstfd, fourbyt thread_eof, int thread_format, onebyt *buffer) #else PackFile(srcfd, dstfd, thread_eof, thread_format, buffer) int srcfd; /* source file descriptor (must be open & seek()ed) */ int dstfd; /* destination file descriptor (must be open & seek()ed) */ fourbyt thread_eof; /* size of input */ int thread_format; /* how to pack the bytes */ onebyt *buffer; /* alloc in main prog so we don't have to each time */ #endif { long length = (long) thread_eof; twobyt retval = thread_format; /* default = successful pack */ long srcposn, dstposn; #if 0 static char *procName = "PackFile"; #endif switch (thread_format) { case 0x0000: /* uncompressed */ if (verbose) { #ifdef SHOW_THREAD_FORMAT printf("storing (%d)...", thread_format); #else printf("storing..."); #endif fflush(stdout); } FCopy(srcfd, dstfd, length, buffer, TRUE); packedSize = length; break; case 0x0001: /* SQUeeze */ if (verbose) { printf("[can't squeeze; storing]..."); fflush(stdout); } else { printf("WARNING: can't squeeze; files stored uncompressed\n"); } FCopy(srcfd, dstfd, length, buffer, TRUE); packedSize = length; retval = 0x0000; /* uncompressed */ break; case 0x0002: /* LZW (ShrinkIt) */ if (verbose) { printf("shrinking..."); fflush(stdout); } /* packedSize set by pak_SHK */ retval = pak_SHK(srcfd, dstfd, length, buffer); break; case 0x0003: /* LZW II (ShrinkIt) */ if (verbose) { printf("[can't do LZW II; storing]..."); fflush(stdout); } else { printf("WARNING: can't do LZW II; files stored uncompressed\n"); } FCopy(srcfd, dstfd, length, buffer, TRUE); packedSize = length; retval = 0x0000; /* uncompressed */ break; case 0x0004: /* UNIX 12-bit compress */ #ifdef NO_UCOMP if (verbose) { printf("[can't do 12-bit UNIX compress; storing]..."); fflush(stdout); } else { printf( "WARNING: can't do 12-bit compress; files stored uncompressed\n"); } FCopy(srcfd, dstfd, length, buffer, TRUE); packedSize = length; retval = 0x0000; /* uncompressed */ #else maxbits = 12; /* global compress parameter */ if (verbose) { printf("compressing..."); fflush(stdout); } /* packedSize set by compress() */ if (u_compress(srcfd, dstfd, length) == OK) retval = 0x0004; else retval = 0x0004; /* FIX this */ #endif break; case 0x0005: /* UNIX 16-bit compress */ #ifdef NO_UCOMP if (verbose) { printf("[can't do 16-bit UNIX compress; storing]..."); fflush(stdout); } else { printf( "WARNING: can't do 16-bit compress; files stored uncompressed\n"); } FCopy(srcfd, dstfd, length, buffer, TRUE); packedSize = length; retval = 0x0000; /* uncompressed */ #else maxbits = 16; /* global compress parameter */ if (verbose) { printf("compressing..."); fflush(stdout); } /* packedSize set by compress() */ srcposn = (long) lseek(srcfd, (off_t) 0, S_REL); /* save posn */ dstposn = (long) lseek(dstfd, (off_t) 0, S_REL); if (u_compress(srcfd, dstfd, length) == OK) { /* compress succeeded */ retval = 0x0005; } else { /* compression failed */ if (verbose) { printf("storing..."); fflush(stdout); } lseek(srcfd, (off_t) srcposn, S_ABS); /* reposn files */ lseek(dstfd, (off_t) dstposn, S_ABS); FCopy(srcfd, dstfd, length, buffer, TRUE); packedSize = length; retval = 0x0000; } #endif break; default: fprintf(stderr, "\nUnknown compression method %d\n", thread_format); fprintf(stderr, "Aborting.\n"); QuitNulib(-1); } return (retval); } /* * Extract a range of bytes from one file into another, unpacking them. * * (hacked to unpack disks, also. Forces the thread_eof to be the total * size of the disk, since ShrinkIt doesn't really define it, esp for DOS 3.3 * disks). * * Set up stuff, then call the appropriate unpack routine. Leaves the srcfd * positioned past the data to be unpacked; the calling routine should not * have to do any seeks. * * Returns TRUE if able to unpack, FALSE if not able to. Note that srcfd * WILL be seeked even if the compression method is not handled. * * New uncompression routines should have the following characteristics: * - they should be able to uncompress a range of bytes from one file * to another given two seeked file descriptors and a length parameter. * - they should return TRUE if they succeed and FALSE otherwise. Special * condition codes can be handled in the switch statement below. */ int #ifdef __STDC__ UnpackFile (int srcfd, int dstfd, THblock *THptr, int thread_format, onebyt *buffer) #else UnpackFile(srcfd, dstfd, THptr, thread_format, buffer) int srcfd; /* source file descriptor (must be open & lseek()ed) */ int dstfd; /* destination file descriptor (must be open & lseek()ed) */ THblock *THptr; /* pointer to thread structure */ int thread_format; /* how to unpack the bytes (NOT THptr->thread_format) */ onebyt *buffer; #endif { long length; fourbyt thread_eof, /* #of bytes to output */ comp_thread_eof; /* #of bytes in source */ twobyt thread_crc; BOOLEAN retval = TRUE; /* default to success */ #if 0 static char *procName = "UnpackFile"; #endif thread_eof = THptr->thread_eof; comp_thread_eof = THptr->comp_thread_eof; thread_crc = THptr->thread_crc; length = (long) comp_thread_eof; /* type checking goes easier */ switch (thread_format) { case 0x0000: /* uncompressed */ if (verbose) { #ifdef SHOW_THREAD_FORMAT printf("extracting (%x)...", thread_format); #else printf("extracting..."); #endif fflush(stdout); } FCopy(srcfd, dstfd, length, buffer, TRUE); break; case 0x0001: /* unSQUeeze */ #ifdef NO_BLU if (verbose) { printf("[can't unsqueeze - aborting]..."); fflush(stdout); } else { printf("ERROR: can't unsqueeze; 'squ' files not extracted\n"); } lseek(srcfd, (off_t)length, S_REL); /* set file posn */ retval = FALSE; #else if (verbose) { printf("unsqueezing..."); fflush(stdout); } unpak_SQU(srcfd, dstfd, length); /* thread_eof not needed */ #endif break; case 0x0002: /* LZW (ShrinkIt) */ if (verbose) { printf("unshrinking (I)..."); fflush(stdout); } unpak_SHK(srcfd, dstfd, comp_thread_eof, thread_eof, buffer, FALSE, thread_crc); break; case 0x0003: /* LZW II (ShrinkIt) */ #ifdef TRY_II if (verbose) { printf("unshrinking (II)..."); fflush(stdout); } unpak_SHK(srcfd, dstfd, comp_thread_eof, thread_eof, buffer, TRUE, thread_crc); #else if (verbose) { printf("[can't unshrink type II - aborting]..."); fflush(stdout); } else { printf( "ERROR: can't unshrink type II; 'sh2' files not extracted\n"); } lseek(srcfd, (off_t)length, S_REL); /* set file posn */ retval = FALSE; #endif break; case 0x0004: /* 12-bit UNIX compress */ #ifdef NO_UCOMP if (verbose) { printf("[can't undo 12-bit UNIX compress - aborting]..."); fflush(stdout); } else { printf( "ERROR: can't undo 12-bit UNIX compress; 'u12' files not extracted\n"); } lseek(srcfd, (off_t)length, S_REL); /* set file posn */ retval = FALSE; #else if (verbose) { printf("uncompressing..."); fflush(stdout); } if (u_decompress(srcfd, dstfd, (long) comp_thread_eof) != OK) retval = FALSE; #endif break; case 0x0005: /* 16-bit UNIX compress */ #ifdef NO_UCOMP if (verbose) { printf("[can't undo 16-bit UNIX compress - aborting]..."); fflush(stdout); } else { printf( "ERROR: can't undo 16-bit UNIX compress; 'u16' files not extracted\n"); } lseek(srcfd, (off_t)length, S_REL); /* set file posn */ retval = FALSE; #else if (verbose) { printf("uncompressing..."); fflush(stdout); } if (u_decompress(srcfd, dstfd, (long) comp_thread_eof) != OK) retval = FALSE; #endif break; default: fprintf(stderr, "Unknown uncompression method %d\n", thread_format); lseek(srcfd, (off_t)length, S_REL); /* set file posn */ retval = FALSE; break; } return (retval); } nulib/nupdel.c100644 765 144 35356 6247227103 12042 0ustar gdrusers/* * nudel.c/nuupd.c - operations which delete/update/freshen a NuFX archive * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nupdel.c,v 1.4 1996/11/28 06:16:35 gdr Exp $ */ #define SEGMENT_NAME "NuMain2___" #include "nudefs.h" #include #include #include #ifdef BSD43 # include #else /* SYSV, APW, MSC */ # include #endif #ifdef UNIX # include # include # include #endif #ifdef APW # include # include /* ? */ # include # include /* APW string ops */ #endif #ifdef MSDOS # include # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuread.h" #include "nuadd.h" /* AddFile(), etc. */ #include "nupak.h" /* uses PAKBUFSIZ */ #include "nupdel.h" #include "nuetc.h" #ifdef __appleiigs__ extern int GnoActive; #endif 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 #ifdef __STDC__ RebuildArchive (int arcfd, ListHdr *archive, char *tmpname, long remaining) #else RebuildArchive (arcfd, archive, tmpname, remaining) int arcfd; ListHdr *archive; char *tmpname; long remaining; #endif { int dstfd; /* destination filename */ onebyt *mptr; RNode *RNodePtr; TNode *TNodePtr; int rec, thread; long size; long master_eof; 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,(mode_t)WPERMS))<0) Fatal("Unable to open dest file", procName); if (lseek(dstfd, (off_t) 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 __appleiigs__ if (!GnoActive && STOP_KEY()) { printf("aborting.\n"); QuitNulib(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"); QuitNulib(-1); } size += (long) THsize; size += TNodePtr->THptr->comp_thread_eof; TNodePtr = TNodePtr->TNext; } if (!RNodePtr->filename[0]) { if (lseek(arcfd, (off_t) 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, (off_t) 0, 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 #ifdef __STDC__ Delete (char *filename, int namecount, char **names) #else Delete(filename, namecount, names) char *filename; int namecount; char **names; #endif { 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); QuitNulib (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 __appleiigs__ if (!GnoActive && STOP_KEY()) { printf("aborting.\n"); QuitNulib (1); } #endif printf(" deleteing archive file.\n"); if (unlink(archive->arc_name) < 0) Fatal("Unable to delete archive", procName); } else { tmpname = MakeTemp(tmpname); #ifdef __appleiigs__ if (!GnoActive && STOP_KEY()) { printf("aborting.\n"); QuitNulib (1); } #endif if (lseek(arcfd, (off_t) 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 #ifdef __STDC__ NuDelete (char *filename, int namecount, char **names, char *options) #else NuDelete (filename, namecount, names, options) char *filename; int namecount; char **names; char *options; #endif { #if 0 static char *procName = "NuDelete"; #endif /* 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 #ifdef __STDC__ Update (ListHdr *archive, int namecount, char **names) #else Update (archive, namecount, names) ListHdr *archive; int namecount; char **names; #endif { int arcfd, dstfd; /* archive file descriptor */ static fileInfoArray FIArray = NULL; 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 (FIArray == NULL) { FIArray = newFileArray(); } 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"); QuitNulib (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 __appleiigs__ if (!GnoActive && STOP_KEY()) { printf("aborting.\n"); QuitNulib (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->vec[idx]->store_name)) { atptr = &RNodePtr->RHptr->mod_when; ftptr = &FIArray->vec[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 __appleiigs__ /* IIgs uses actual filetype; other systems keep old */ FIArray->vec[idx]->fileType = RNodePtr->RHptr->file_type; FIArray->vec[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->vec[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->vec[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); QuitNulib (0); } /* * Rebuild archive file */ if (verbose) printf("Building new archive file...\n"); tmpname = MakeTemp(tmpname); ArcfiCreate(tmpname); master_eof = (long) MHsize; if (lseek(arcfd, (off_t) 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, (off_t) 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"); QuitNulib (-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, (off_t) 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->vec[idx]); } RNodePtr = RNodePtr->RNext; /* move on to next record */ } if (!dofreshen) { for (idx = 0 ; idx < namecount; idx++) { #ifdef __appleiigs__ if (!GnoActive && STOP_KEY()) QuitNulib(1); /* check for OA-. */ #endif if (!FIArray->vec[idx]->marked) { master_eof += AddFile(dstfd, FIArray->vec[idx]); } } } /* build master header */ mptr = MakeMHblock(archive, totalrecs, master_eof); if (lseek(dstfd, (off_t) 0, 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 #ifdef __STDC__ NuUpdate (char *filename, int namecount, char **names, char *options) #else NuUpdate (filename, namecount, names, options) char *filename; int namecount; char **names; char *options; #endif { ListHdr *archive; #if 0 static char *procName = "NuUpdate"; #endif if (*options == 'f') dofreshen = TRUE; else dofreshen = FALSE; /* change T subopt to convert FROM current system TO */ if (transfrom >= 0) { transto = transfrom; transfrom = -1; } archive = NuRead(filename); Update(archive, namecount, names); } nulib/nupak.h100644 765 144 2437 6246126406 11653 0ustar gdrusers/* * nupak.h - declarations for nupak.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * This has function declarations for all of the pack routines; that way we * don't have to include .h files for all of the pack code. * * $Id: nupak.h,v 1.3 1996/11/03 23:01:05 gdr Exp $ */ /* Pack/unpack buffer size; should be as big as read() & malloc() can take */ /* Note: must be AT LEAST 8200 bytes or things may break */ /* Bad things could happen if it's less than 12K */ #define PAKBUFSIZ 0xff80 extern long packedSize; extern onebyt lastseen; extern int UnpackFile __P((int, int, THblock *, int, onebyt *)); extern unsigned int crlf __P((int dstfd, onebyt *buffer, unsigned int length)); extern void Spin __P((void)); extern void FCopy __P((int, int, fourbyt, onebyt *, BOOLEAN)); extern twobyt PackFile __P((int, int, fourbyt, int, onebyt *)); /* pack P8 ShrinkIt format, in nushk.c */ extern long pak_SHK __P((int srcfd, int dstfd, long length, onebyt *copybuf)); extern void unpak_SQU __P((int srcfd, int dstfd, long length)); /* unShrink, in nushk.c */ extern void unpak_SHK __P((int srcfd, int dstfd, fourbyt comp_thread_eof, fourbyt thread_eof, register onebyt *buffer, BOOLEAN use_type2, twobyt thread_crc)); nulib/nuread.c100644 765 144 47520 6247227103 12025 0ustar gdrusers/* * nuread.c - read NuFX archives (header info only) into structures * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuread.c,v 1.4 1996/11/28 06:16:35 gdr Exp $ */ #define SEGMENT_NAME "NuMain____" #define NEED_MASTER_ID /* in nuread.h */ #include "nudefs.h" #include #include #include #include #include #ifdef UNIX # include # include #endif #ifdef MSDOS /* For file IO */ # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #ifdef CRC_TAB # include "crc.h" /* fast CRC lookup */ #endif #include "nuread.h" #include "nupak.h" /* uses PAKBUFSIZ */ #include "nuetc.h" #define UNKNOWN_FN "" /* quick proc to save x00 bytes of static storage */ void #ifdef __STDC__ OtherArc(char *str1, char *str2) #else OtherArc(str1, str2) char *str1, *str2; #endif { fprintf(stderr, "File may be %s; try \"%s\".\n", str1, str2); } /* swap two bytes if HiLo is TRUE */ void #ifdef __STDC__ HiSwap(onebyt *ptr, register onebyt a, register onebyt b) #else HiSwap(ptr, a, b) onebyt *ptr; register onebyt a, b; #endif { register onebyt tmp; if (HiLo) { tmp = ptr[a], ptr[a] = ptr[b], ptr[b] = tmp; } } /* copy bytes from buffer to buffer, reversing byte order if necessary */ void #ifdef __STDC__ BCopy (register onebyt *srcptr, register onebyt *destptr, int num, BOOLEAN order) #else BCopy(srcptr, destptr, num, order) register onebyt *srcptr, *destptr; int num; BOOLEAN order; /* true if byte ordering is important */ #endif { register int i = num--; if (order && HiLo) { while (i--) { /* copy & reverse */ *(destptr+i) = *(srcptr + num - i); /* dest+3 = src + 3 - 3 .. */ } } else if (order) { while (i--) { /* copy only */ *(destptr+i) = *(srcptr + i); } } else { while (i--) { /* byte ordering not important; just copy */ *(destptr+i) = *(srcptr+i); } } } /* * Calculate CRC on a region * * A CRC is the result of a mathematical operation based on the * coefficients of a polynomial when multiplied by X^16 then divided by * the generator polynomial (X^16 + X^12 + X^5 + 1) using modulo two * arithmetic. * * This routine is a slightly modified verison of one found in: * _Advanced Programming Techniques for the Apple //gs Toolbox_ * By Morgan Davis and Dan Gookin (Compute! Publications, Inc.) * It can either calculate the CRC bit-by-bit or use a table. * [ one of the few //gs books worth the money +atm ] */ twobyt #ifdef __STDC__ CalcCRC (twobyt seed, register onebyt *ptr, register int count) #else CalcCRC(seed, ptr, count) twobyt seed; /* initial value for CRC */ register onebyt *ptr; /* pointer to start of data buffer */ register int count; /* number of bytes to scan through - note 64K max */ #endif { #ifndef CRC_TAB register int x; #endif register twobyt CRC = seed; do { #ifndef CRC_TAB CRC ^= *ptr++ << 8; /* XOR hi-byte of CRC w/data */ for (x = 8; x; --x) /* Then, for 8 bit shifts... */ if (CRC & 0x8000) /* Test hi order bit of CRC */ CRC = CRC << 1 ^ 0x1021; /* if set, shift & XOR w/$1021 */ else CRC <<= 1; /* Else, just shift left once. */ #else CRC = updcrc(*ptr++, CRC); /* look up new value in table */ #endif } while (--count); return (CRC); } /* * Test an archive's integrity. * * Reads the entire file, and checks CRCs for certain things. */ void #ifdef __STDC__ NuTest (char *filename, char *options) #else NuTest(filename, options) char *filename; char *options; #endif { ListHdr *archive; onebyt *copybuf; /* buffer for reading record */ int partial; /* size for partial read */ unsigned int rec; RNode *RNodePtr; MHblock *MHptr; TNode *TNodePtr; long hdr_size, total_size, thread_size; int srcfd; /* file descriptor */ int thread; twobyt CRC=0, RecordCRC; long CRCsum = 0L; /* sum of CRCs for all records */ BOOLEAN check_thread_crc; /* TRUE if we want to check a give thread */ static char *procName = "NuTest"; printf("Testing %s", filename); if (verbose) printf("\n"); else { printf("..."); fflush(stdout); } archive = NuRead(filename); /* this catches most errors... */ MHptr = archive->MHptr; RNodePtr = archive->RNodePtr; copybuf = (onebyt *) Malloc(PAKBUFSIZ); if ((srcfd = open(filename, O_RDONLY | O_BINARY)) < 0) Fatal("Unable to close archive", procName); if (lseek(srcfd, (off_t) MHsize, S_ABS) < 0) /* seek past master block */ Fatal("Bad seek (MH)", procName); for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) { if (verbose) printf("Record %d (%s): ", rec, RNodePtr->filename); hdr_size = (long) RNodePtr->RHptr->attrib_count; hdr_size += (long) RNodePtr->filename_length; total_size = hdr_size; TNodePtr = RNodePtr->TNodePtr; for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){ if (TNodePtr == (TNode *) NULL) { fprintf(stderr, "Internal error: Bad thread structure\n"); QuitNulib(-1); } hdr_size += (long) THsize; total_size += (long) THsize; total_size += TNodePtr->THptr->comp_thread_eof; TNodePtr = TNodePtr->TNext; } if (verbose) { printf("total record size = %ld (%d threads)\n", total_size, (int) RNodePtr->RHptr->total_threads); fflush(stdout); } /* read record header */ RecordCRC = 0; while (hdr_size != 0L) { if (hdr_size > (long) PAKBUFSIZ) { partial = (unsigned int) PAKBUFSIZ; hdr_size -= (long) PAKBUFSIZ; } else { partial = (unsigned int) hdr_size; hdr_size = 0L; } if (read(srcfd, copybuf, partial) != partial) { fprintf(stderr, ">>> Read error"); if (verbose) fprintf(stderr, "\n"); else fprintf(stderr, " - record %d (%s)\n", rec, RNodePtr->filename); fprintf(stderr, "Operation aborted.\n"); QuitNulib(-1); } if (verbose) RecordCRC = CalcCRC(CRC, (onebyt *) copybuf, partial); } TNodePtr = RNodePtr->TNodePtr; for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){ if (lseek(srcfd, (off_t) TNodePtr->fileposn, S_ABS) < 0) Fatal("whoops!", procName); thread_size = TNodePtr->THptr->comp_thread_eof; /* decide whether or not to check thread CRCs */ check_thread_crc = FALSE; if (RNodePtr->RHptr->version_number >= 2) /* valid CRCs */ if (TNodePtr->THptr->thread_class == 2) /* data_thread */ check_thread_crc = TRUE; if (RNodePtr->RHptr->version_number == 3) /* CRC of uncom data */ if (TNodePtr->THptr->thread_format != 0x0000) check_thread_crc = FALSE; /* can't check comp */ if (check_thread_crc) CRC = 0xffff; while (thread_size != 0L) { if (thread_size > (long) PAKBUFSIZ) { partial = (unsigned int) PAKBUFSIZ; thread_size -= (long) PAKBUFSIZ; } else { partial = (unsigned int) thread_size; thread_size = 0L; } if (read(srcfd, copybuf, partial) != partial) { fprintf(stderr, ">>> Read error in thread"); if (verbose) fprintf(stderr, " %d\n", thread); else fprintf(stderr, " - record %d (%s), thread %d\n", rec, RNodePtr->filename, thread); fprintf(stderr, "Operation aborted.\n"); QuitNulib(-1); } if (verbose) RecordCRC = CalcCRC(RecordCRC, (onebyt *)copybuf, partial); /* calculate CRC for thread, and compare with thread_crc */ if (check_thread_crc) CRC = CalcCRC(CRC, (onebyt *) copybuf, partial); #ifdef DEBUG printf( "At posn %ld: rec %d/thread %d (%ld bytes) CalcCRC = 0x%.4x (0x%.4x)\n", TNodePtr->fileposn, rec, thread, thread_size, CRC, TNodePtr->THptr->thread_crc ); #endif } /* check and see if CRC matches */ if (check_thread_crc) { if (CRC != TNodePtr->THptr->thread_crc) { fprintf(stderr, ">>> Bad CRC for thread %d", thread); if (verbose) fprintf(stderr, "\n"); else fprintf(stderr, " in record %d\n", rec); } else { if (verbose) printf("--- CRC matched for thread %d\n", thread); } } TNodePtr = TNodePtr->TNext; } if (verbose) { printf("--- CRC for entire record was $%.4x\n", RecordCRC); CRCsum += RecordCRC; } RNodePtr = RNodePtr->RNext; } if (close(srcfd) < 0) Fatal("Unable to close archive", procName); free(copybuf); if (verbose) printf("Sum of CRCs = $%.8lx\n", CRCsum); printf("done.\n"); } /* * Read thread header data, and skip data fields */ static TNode * #ifdef __STDC__ ReadThreads(int fd, RHblock *RHptr, RNode *RNodePtr, twobyt *CRC_ptr) #else ReadThreads(fd, RHptr, RNodePtr, CRC_ptr) int fd; RHblock *RHptr; RNode *RNodePtr; twobyt *CRC_ptr; /* CRC seed; result is returned thru this */ #endif { int i; unsigned int size; BOOLEAN first; TNode *TNodePtr = (TNode *) NULL; TNode *THeadPtr = (TNode *) NULL; THblock *THptr; char filebuf[THsize]; twobyt CRC = *CRC_ptr; static char *procName = "ReadThreads"; RNodePtr->unc_len = 0L; RNodePtr->comp_len = 0L; first = TRUE; for (i = 0; i < RHptr->total_threads; i++) { if (first) { /* create first block, or... */ TNodePtr = (TNode *) Malloc(sizeof(TNode)); THeadPtr = TNodePtr; first = FALSE; } else { /* create next block and go on */ TNodePtr->TNext = (TNode *) Malloc(sizeof(TNode)); TNodePtr = TNodePtr->TNext; } TNodePtr->TNext = (TNode *) NULL; /* Create the thread header block, and read it in */ TNodePtr->THptr = (THblock *) Malloc(sizeof(THblock)); THptr = TNodePtr->THptr; if ((size = read(fd, filebuf, THsize)) < THsize) { /* should be 16 */ printf("read size = %d, THsize = %d\n", size, THsize); Fatal("ReadThread (THblock)", procName); } CRC = CalcCRC(CRC, (onebyt *) filebuf, 16); /* hdr CRC part(s) 5/5 */ /* copy all fields... */ BCopy((onebyt *) filebuf+0, (onebyt *) &THptr->thread_class, 2, TRUE); BCopy((onebyt *) filebuf+2, (onebyt *) &THptr->thread_format, 2, TRUE); BCopy((onebyt *)filebuf+4, (onebyt *) &THptr->thread_kind, 2, TRUE); BCopy((onebyt *)filebuf+6, (onebyt *) &THptr->thread_crc, 2, TRUE); BCopy((onebyt *)filebuf+8, (onebyt *) &THptr->thread_eof, 4, TRUE); BCopy((onebyt *)filebuf+12, (onebyt *) &THptr->comp_thread_eof, 4, TRUE); RNodePtr->unc_len += THptr->thread_eof; RNodePtr->comp_len += THptr->comp_thread_eof; if (THptr->comp_thread_eof > 2097152L) /* SANITY CHECK */ fprintf(stderr, "Sanity check: found comp_thread_eof > 2MB\n"); } /* skip the actual data */ TNodePtr = THeadPtr; for (i = 0; i < RHptr->total_threads; i++) { THptr = TNodePtr->THptr; if ((TNodePtr->fileposn = lseek(fd, (off_t) 0, S_REL)) < 0) Fatal("Bad thread posn lseek()", procName); /* pull filenames out of threads, if present */ if (THptr->thread_class == 0x0003) { /* filename thread */ RNodePtr->filename = (char *) Malloc(THptr->thread_eof +1); if (read(fd, RNodePtr->filename, THptr->thread_eof) < 0) { fprintf(stderr, "Error on thread %d\n", i); Fatal("Unable to read filename", procName); } RNodePtr->filename[THptr->thread_eof] = '\0'; RNodePtr->real_fn_length = THptr->thread_eof; { /* patch to fix bug in ShrinkIt v3.0.0 */ int j, name_len = strlen(RNodePtr->filename); for (j = 0; j < name_len; j++) { RNodePtr->filename[j] &= 0x7f; /* clear hi bit */ } } if (lseek(fd, (off_t) TNodePtr->fileposn, S_ABS) < 0) Fatal("Unable to seek back after fn", procName); } if (lseek(fd, (off_t) THptr->comp_thread_eof, S_REL) < 0) Fatal("Bad skip-thread seek", procName); TNodePtr = TNodePtr->TNext; } *CRC_ptr = CRC; return (THeadPtr); } /* * Read header data from a NuFX archive into memory */ ListHdr * #ifdef __STDC__ NuRead(char *filename) #else NuRead(filename) char *filename; #endif { int fd; /* archive file descriptor */ char namebuf[MAXFILENAME]; int rec, num; BOOLEAN first; twobyt namelen; twobyt CRC; ListHdr *ListPtr; /* List Header struct */ MHblock *MHptr; /* Master Header block */ RNode *RNodePtr = (RNode *) NULL; /* Record Node */ RHblock *RHptr; /* Record Header block */ onebyt filebuf[RECBUFSIZ]; /* must be > RH, MH, or atts-RH size */ static char *procName = "NuRead"; char *cp; ListPtr = (ListHdr *) Malloc(sizeof(ListHdr)); /* create head of list */ ListPtr->arc_name = (char *) Malloc(strlen(filename)+1); /* archive fnam */ strcpy(ListPtr->arc_name, filename); ListPtr->MHptr = (MHblock *) Malloc(sizeof(MHblock)); /* master block */ if ((fd = open(filename, O_RDONLY | O_BINARY)) < 0) { if (errno == ENOENT) { fprintf(stderr, "%s: can't find file '%s'\n", prgName, filename); QuitNulib (-1); } else Fatal("Unable to open archive", procName); } /* create and read the master header block */ MHptr = ListPtr->MHptr; if (read(fd, filebuf, MHsize) < MHsize) { fprintf(stderr, "File '%s' may not be a NuFX archive\n", filename); Fatal("Unable to read Master Header Block", procName); } CRC = CalcCRC(0, (onebyt *) filebuf+8, MHsize-8); /* master header CRC */ /* Copy data to structs, correcting byte ordering if necessary */ BCopy(filebuf+0, (onebyt *) MHptr->ID, 6, FALSE); BCopy(filebuf+6, (onebyt *) &MHptr->master_crc, 2, TRUE); BCopy(filebuf+8, (onebyt *) &MHptr->total_records, 4, TRUE); BCopy(filebuf+12, (onebyt *) &MHptr->arc_create_when, sizeof(Time), FALSE); BCopy(filebuf+20, (onebyt *) &MHptr->arc_mod_when, sizeof(Time), FALSE); BCopy(filebuf+28, (onebyt *) &MHptr->master_version, 2, TRUE); BCopy(filebuf+30, (onebyt *) MHptr->reserved1, 8, FALSE); BCopy(filebuf+38, (onebyt *) &MHptr->master_eof, 4, TRUE); /* m_v $0001 */ BCopy(filebuf+42, (onebyt *) MHptr->reserved2, 6, FALSE); if (strncmp((const char *) MHptr->ID, (const char *) MasterID, 6)) { fprintf(stderr, "\nFile '%s' is not a NuFX archive\n", filename); if ((filebuf[0] == 10) && (filebuf[1] == 71) && (filebuf[2] == 76) && (filebuf[18] == 2)) #ifdef NO_BLU OtherArc("Binary II", "unblu"); #else fprintf(stderr, "File may be Binary II; try 'B' option\n"); #endif if ((filebuf[0] == '\037') && (filebuf[1] == '\036')) OtherArc("packed", "unpack"); if ((filebuf[0] == (onebyt)'\377') && (filebuf[1] == '\037')) OtherArc("compacted", "uncompact"); if ((filebuf[0] == '\037') && (filebuf[1] == (onebyt)'\235')) OtherArc("compressed", "uncompress"); if ((filebuf[0] == 0x76) && (filebuf[1] == 0xff)) OtherArc("SQueezed", "usq"); if ((filebuf[0] == 0x04) && (filebuf[1] == 0x03) && (filebuf[2] == 0x4b) && (filebuf[3] == 0x50)) OtherArc("a ZIP archive", "UnZip"); if (!strncmp((char *) filebuf, "ZOO", 3)) /* zoo */ OtherArc("a ZOO archive", "zoo"); if ((filebuf[0] == 0x1a) && (filebuf[1] == 0x08)) /* arc */ OtherArc("an ARC archive", "arc"); if (!strncmp((char *) filebuf, "SIT!", 4)) /* StuffIt */ OtherArc("a StuffIt archive", "StuffIt (Macintosh)"); if (!strncmp((char *) filebuf, "", 4)) /* system V arch */ OtherArc("a library archive (Sys V)", "ar"); if (!strncmp((char *) filebuf, "!", 7)) OtherArc("a library archive", "ar"); if (!strncmp((char *) filebuf, "#! /bin/sh", 10) || !strncmp((char *) filebuf, "#!/bin/sh", 9)) OtherArc("a shar archive", "/bin/sh"); if (!strncmp((char *) filebuf, "GIF87a", 6)) OtherArc("a GIF picture", "?!?"); /* still need ZIP */ QuitNulib (-1); } if (CRC != MHptr->master_crc) printf("WARNING: Master Header block may be corrupted (bad CRC)\n"); if (MHptr->master_version > MAXMVERS) printf("WARNING: unknown Master Header version, trying to continue\n"); /* main record read loop */ first = TRUE; for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) { if (first) { /* allocate first, or... */ ListPtr->RNodePtr = (RNode *) Malloc(sizeof(RNode)); RNodePtr = ListPtr->RNodePtr; first = FALSE; } else { /* allocate next, and go on */ RNodePtr->RNext = (RNode *) Malloc(sizeof(RNode)); /* next Rnode */ RNodePtr = RNodePtr->RNext; /* move on to next record */ } RNodePtr->RNext = (RNode *) NULL; RNodePtr->RHptr = (RHblock *) Malloc(sizeof(RHblock)); /* alloc blk */ /* expansion here */ RHptr = RNodePtr->RHptr; if (read(fd, filebuf, RHsize) < RHsize) { /* get known stuff */ fprintf(stderr,"%s: error in record %d (at EOF?)\n", prgName, rec); Fatal("Bad RHblock read", procName); } /* rec hdr CRC part 1/5 */ CRC = CalcCRC(0, (onebyt *) filebuf+6, RHsize-6); BCopy(filebuf+0, (onebyt *) RHptr->ID, 4, FALSE); BCopy(filebuf+4, (onebyt *) &RHptr->header_crc, 2, TRUE); BCopy(filebuf+6, (onebyt *) &RHptr->attrib_count, 2, TRUE); BCopy(filebuf+8, (onebyt *) &RHptr->version_number, 2, TRUE); BCopy(filebuf+10, (onebyt *) &RHptr->total_threads, 2, TRUE); BCopy(filebuf+12, (onebyt *) &RHptr->reserved1, 2, TRUE); BCopy(filebuf+14, (onebyt *) &RHptr->file_sys_id, 2, TRUE); BCopy(filebuf+16, (onebyt *) &RHptr->file_sys_info, 1, TRUE); BCopy(filebuf+17, (onebyt *) &RHptr->reserved2, 1, TRUE); BCopy(filebuf+18, (onebyt *) &RHptr->access, 4, TRUE); BCopy(filebuf+22, (onebyt *) &RHptr->file_type, 4, TRUE); BCopy(filebuf+26, (onebyt *) &RHptr->extra_type, 4, TRUE); BCopy(filebuf+30, (onebyt *) &RHptr->storage_type, 2, TRUE); BCopy(filebuf+32, (onebyt *) &RHptr->create_when, sizeof(Time), FALSE); BCopy(filebuf+40, (onebyt *) &RHptr->mod_when, sizeof(Time), FALSE); BCopy(filebuf+48, (onebyt *) &RHptr->archive_when, sizeof(Time), FALSE); BCopy(filebuf+56, (onebyt *) &RHptr->option_size, 2, TRUE); /* expansion here */ if (strncmp((const char *) RHptr->ID, (const char *) RecordID, 4)) { fprintf(stderr, "%s: Found bad record ID (#%d) -- exiting\n", prgName, rec); QuitNulib (-1); } /* read remaining (unknown) attributes into buffer, if any */ num = RHptr->attrib_count - RHsize - 2; if (num > RECBUFSIZ) { fprintf(stderr, "ERROR: attrib_count > RECBUFSIZ\n"); QuitNulib (-1); } if (num > 0) { if (read(fd, filebuf, num) < num) Fatal("Bad xtra attr read", procName); CRC = CalcCRC(CRC, (onebyt *) filebuf, num); /* hdr CRC part 2/5 */ } if (read(fd, (char *) &namelen, 2) < 2) /* read filename len */ Fatal("Bad namelen read", procName); CRC = CalcCRC(CRC, (onebyt *) &namelen, 2); /* rec hdr CRC part 3/5 */ HiSwap((onebyt *) &namelen, 0, 1); /* read filename, and store in struct */ if (namelen > MAXFILENAME) { fprintf(stderr, "ERROR: namelen > MAXFILENAME\n"); QuitNulib (-1); } RNodePtr->filename_length = namelen; if (namelen > 0) { RNodePtr->real_fn_length = namelen; if (read(fd, namebuf, namelen) < namelen) Fatal("Bad namebuf read", procName); /* rec hdr CRC part 4/5 */ CRC = CalcCRC(CRC, (onebyt *) namebuf, namelen); RNodePtr->filename = (char *) Malloc(namelen+1); /* store fname */ BCopy((onebyt *) namebuf, (onebyt *) RNodePtr->filename, namelen, FALSE); RNodePtr->filename[namelen] = '\0'; for (cp = RNodePtr->filename; *cp; cp++) *cp &= 0x7f; /*strip high bits from old-style names*/ } else { RNodePtr->filename = UNKNOWN_FN; RNodePtr->real_fn_length = strlen(UNKNOWN_FN); } RNodePtr->TNodePtr = ReadThreads(fd, RHptr, RNodePtr, &CRC); /* rec hdr CRC part 5/5 calculated by ReadThreads */ if (CRC != RHptr->header_crc) { printf("WARNING: Detected a bad record header CRC\n"); printf(" Rec %d in file '%.60s'\n",rec,RNodePtr->filename); } } /* begin adding new files at this point */ if ((ListPtr->nextposn = lseek(fd, (off_t) 0, S_REL)) < 0) Fatal("Bad final lseek()", procName); if (close(fd) < 0) { Fatal("Bad close", procName); } if (MHptr->master_version > 0x0000) { if ((fourbyt) MHptr->master_eof != (fourbyt) ListPtr->nextposn) { printf("WARNING: master_eof (stored)=%ld, nextposn (actual)=%ld\n", MHptr->master_eof, ListPtr->nextposn); printf( " (master_eof will be fixed if archive is changed)\n"); } } return (ListPtr); } nulib/nupdel.h100644 765 144 630 6246126406 11775 0ustar gdrusers/* * nupdel.h - declarations for NuUpdate and NuDelete * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nupdel.h,v 1.3 1996/11/03 23:01:06 gdr Exp $ */ extern void NuDelete __P((char *filename, int namecount, char **names, char *options)); extern void NuUpdate __P((char *filename, int namecount, char **names, char *options)); nulib/nushk.c100644 765 144 76741 6246126406 11711 0ustar gdrusers/* * nushk.c - P8 ShrinkIt compress/uncompress routines * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nushk.c,v 1.4 1996/11/17 23:22:54 gdr Exp $ */ #define SEGMENT_NAME "Compress__" #include "nudefs.h" #include #include #include #include #ifdef UNIX # include # include #endif #ifdef MSDOS /* For file IO */ # include # include # include # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuread.h" /* need CalcCRC() */ #include "nupak.h" #include "nuetc.h" #ifdef UNIX # if defined(SYSV) || defined(__ORCAC__) # define BCOPY(src, dst, count) memcpy(dst, src, count) # else # define BCOPY(src, dst, count) bcopy(src, dst, count); # endif #else # if defined(APW) || defined(__ORCAC__) # define BCOPY(src, dst, count) memcpy(dst, src, count) # endif # ifdef MSDOS /* you may need to change this to memcpy() */ # define BCOPY(src, dst, count) bcopy(src, dst, count); /*# define BCOPY(src, dst, count) memcpy(dst, src, count)*/ # endif /* +PORT+ */ #endif #define BLKSIZ 4096 /*#define DEBUG *//* do verbose debugging output */ /*#define DEBUG1 *//* debugging output in main routine */ static void ClearTab __P((void)); static int do_LZW __P((onebyt *bufr, int inlen, onebyt *outbuf)); static int do_RLE __P((register onebyt *srcptr, register onebyt *dstptr)); static int get_code __P((void)); static int put_code __P((int code, int ent, onebyt *bfr)); static void undo_LZW __P((unsigned char *buffer, int length)); static void undo_LZW_2 __P((unsigned char *buffer, int length)); static void undo_RLE __P((unsigned char *inbuffer, unsigned char *outbuffer)); static onebyt *ibuf; /* large buffer (usually set to packBuffer) */ onebyt lbuf[BLKSIZ+7]; /* temporary buffer for storing data after LZW */ onebyt rbuf[BLKSIZ+7]; /* temporary buffer for storing data after RLE */ /* * P8 ShrinkIt compression routines * Copyright 1989 Kent Dickey * * C translation by Kent Dickey / Andy McFadden */ #define ESCAPE_CHAR 0xdb #define HSIZE 5119 /* Must be prime */ typedef struct ht { int entry; int prefix; onebyt chr; } ht; struct ht *htab = NULL; /* allocated first time through */ int s_at_bit; int s_at_byte; int mask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff }; int bit_tab[] = { 0,9,10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12 }; /* hash function from UNIX compress */ int hashf[256] = { 0x0000, 0x0204, 0x0408, 0x060c, 0x0810, 0x0a14, 0x0c18, 0x0e1c, 0x0020, 0x0224, 0x0428, 0x062c, 0x0830, 0x0a34, 0x0c38, 0x0e3c, 0x0040, 0x0244, 0x0448, 0x064c, 0x0850, 0x0a54, 0x0c58, 0x0e5c, 0x0060, 0x0264, 0x0468, 0x066c, 0x0870, 0x0a74, 0x0c78, 0x0e7c, 0x0080, 0x0284, 0x0488, 0x068c, 0x0890, 0x0a94, 0x0c98, 0x0e9c, 0x00a0, 0x02a4, 0x04a8, 0x06ac, 0x08b0, 0x0ab4, 0x0cb8, 0x0ebc, 0x00c0, 0x02c4, 0x04c8, 0x06cc, 0x08d0, 0x0ad4, 0x0cd8, 0x0edc, 0x00e0, 0x02e4, 0x04e8, 0x06ec, 0x08f0, 0x0af4, 0x0cf8, 0x0efc, 0x0100, 0x0304, 0x0508, 0x070c, 0x0910, 0x0b14, 0x0d18, 0x0f1c, 0x0120, 0x0324, 0x0528, 0x072c, 0x0930, 0x0b34, 0x0d38, 0x0f3c, 0x0140, 0x0344, 0x0548, 0x074c, 0x0950, 0x0b54, 0x0d58, 0x0f5c, 0x0160, 0x0364, 0x0568, 0x076c, 0x0970, 0x0b74, 0x0d78, 0x0f7c, 0x0180, 0x0384, 0x0588, 0x078c, 0x0990, 0x0b94, 0x0d98, 0x0f9c, 0x01a0, 0x03a4, 0x05a8, 0x07ac, 0x09b0, 0x0bb4, 0x0db8, 0x0fbc, 0x01c0, 0x03c4, 0x05c8, 0x07cc, 0x09d0, 0x0bd4, 0x0dd8, 0x0fdc, 0x01e0, 0x03e4, 0x05e8, 0x07ec, 0x09f0, 0x0bf4, 0x0df8, 0x0ffc, 0x0200, 0x0004, 0x0608, 0x040c, 0x0a10, 0x0814, 0x0e18, 0x0c1c, 0x0220, 0x0024, 0x0628, 0x042c, 0x0a30, 0x0834, 0x0e38, 0x0c3c, 0x0240, 0x0044, 0x0648, 0x044c, 0x0a50, 0x0854, 0x0e58, 0x0c5c, 0x0260, 0x0064, 0x0668, 0x046c, 0x0a70, 0x0874, 0x0e78, 0x0c7c, 0x0280, 0x0084, 0x0688, 0x048c, 0x0a90, 0x0894, 0x0e98, 0x0c9c, 0x02a0, 0x00a4, 0x06a8, 0x04ac, 0x0ab0, 0x08b4, 0x0eb8, 0x0cbc, 0x02c0, 0x00c4, 0x06c8, 0x04cc, 0x0ad0, 0x08d4, 0x0ed8, 0x0cdc, 0x02e0, 0x00e4, 0x06e8, 0x04ec, 0x0af0, 0x08f4, 0x0ef8, 0x0cfc, 0x0300, 0x0104, 0x0708, 0x050c, 0x0b10, 0x0914, 0x0f18, 0x0d1c, 0x0320, 0x0124, 0x0728, 0x052c, 0x0b30, 0x0934, 0x0f38, 0x0d3c, 0x0340, 0x0144, 0x0748, 0x054c, 0x0b50, 0x0954, 0x0f58, 0x0d5c, 0x0360, 0x0164, 0x0768, 0x056c, 0x0b70, 0x0974, 0x0f78, 0x0d7c, 0x0380, 0x0184, 0x0788, 0x058c, 0x0b90, 0x0994, 0x0f98, 0x0d9c, 0x03a0, 0x01a4, 0x07a8, 0x05ac, 0x0bb0, 0x09b4, 0x0fb8, 0x0dbc, 0x03c0, 0x01c4, 0x07c8, 0x05cc, 0x0bd0, 0x09d4, 0x0fd8, 0x0ddc, 0x03e0, 0x01e4, 0x07e8, 0x05ec, 0x0bf0, 0x09f4, 0x0ff8, 0x0dfc, }; /* * Output code to buffer. */ static int #ifdef __STDC__ put_code(int code, int ent, onebyt *bfr) #else put_code(code, ent, bfr) int code, ent; onebyt *bfr; #endif { int lo_byte; register long mycode; int bits; register onebyt *cp; /* opt: points to bfr[s_at_byte] */ bits = bit_tab[(ent >> 8)]; if (((s_at_bit + bits + 7) >> 3) + s_at_byte > BLKSIZ) { return(-1); } mycode = (long)(code & mask[bits]); #ifdef DEBUG2 fprintf(stderr,"Byte: %d, %lx\n", s_at_byte, mycode); #endif /* lo_byte = bfr[s_at_byte] & mask[s_at_bit];*/ cp = bfr + s_at_byte; /* - */ lo_byte = *cp & mask[s_at_bit]; /* - */ if (s_at_bit != 0) { mycode <<= s_at_bit; } /* bfr[s_at_byte++] = (onebyt) lo_byte | (onebyt) (mycode & 0xff);*/ *cp = (onebyt) lo_byte | (onebyt) (mycode & 0xff); /* - */ s_at_byte++, cp++; /* bfr[s_at_byte] = (onebyt) ((mycode >>= 8) & 0xff);*/ *cp = (onebyt) ((mycode >>= 8) & 0xff); /* - */ if ((s_at_bit += bits) >= 16) { /* bfr[++s_at_byte] = (char)((mycode >>= 8) & 0xff);*/ cp++, s_at_byte++; /* - */ *cp = (onebyt) ((mycode >>= 8) & 0xff); /* - */ } s_at_bit &= 0x07; return(0); } /* * Try LZW compression on the buffer. * * Compresses from "buffer" to "outbuf". "inlen" is the #of bytes of data in * "buffer." Returns the #of bytes of data placed into "outbuf", or -1 on * failure. */ static int #ifdef __STDC__ do_LZW (onebyt *bufr, int inlen, onebyt *outbuf) #else do_LZW(bufr, inlen, outbuf) onebyt *bufr; int inlen; onebyt *outbuf; #endif { register int index; register onebyt k; register onebyt *inbuf, *endbuf; register struct ht *htp; /* opt: htab[index] */ int ent, prefix, hashdelta; s_at_byte = 0; s_at_bit =0; ent = 0x101; inbuf = bufr; endbuf = bufr + inlen; k = ((char)*inbuf++); Loop0: prefix = (int)k; Loop1: if (inbuf >= endbuf) { if (put_code(prefix, ent, outbuf) < 0) { return(BLKSIZ+2); } if (s_at_bit == 0) return(s_at_byte); else return(s_at_byte+1); } k = (onebyt)*inbuf++; #ifdef OLD_HASH index = (prefix + (k<<4)) & 0xfff; #else index = prefix ^ hashf[k]; /* note index always < 4096 */ #endif Check_ent: htp = htab + index; if (htp->entry == 0) { /* Entry is 0... */ if (put_code(prefix, ent, outbuf) < 0) { return(-1); /* failed */ } htp->entry = ent++; htp->prefix = prefix; htp->chr = k; goto Loop0; } else if (htp->prefix == prefix) { /* - */ /* Same prefix... */ if (htp->chr == k) { /* It's HERE! Yeah! */ prefix = htp->entry; goto Loop1; } goto Sec_hash; } /* Check for more...secondary hash on index */ else { Sec_hash: #ifdef OLD_HASH /*index = (index + (unsigned int)(k) + 1) % HSIZE;*/ index += (unsigned int)(k) +1; if (index >= HSIZE) index -= HSIZE; #else hashdelta = (0x120 - k) << 2; if (index >= hashdelta) index -= hashdelta; else index += (HSIZE - hashdelta); #endif #ifdef DEBUG2 fprintf(stderr,"New ind: %d, k=%d\n", index, (unsigned int)k); #endif goto Check_ent; } } /* * Clear out the hash table. */ static void #ifdef __STDC__ ClearTab(void) #else ClearTab() #endif { register int i; register struct ht *htp; /* opt: htab[i] */ /* for(i=0; i < HSIZE; i++)*/ /* htab[i].entry = 0;*/ htp = htab; /* - */ for (i = HSIZE; i; htp++, i--) /* - */ htp->entry = 0; /* - */ } /* * Do run-length encoding * * Takes input from srcptr, and writes to dstptr. Maximum expansion is * (BLKSIZ / 2) + (BLKSIZ / 2) * 3 == 2 * BLKSIZ * Output of form char count where count is #of bytes -1. * * This really isn't very pretty, but it works. */ static int #ifdef __STDC__ do_RLE(register onebyt *srcptr, register onebyt *dstptr) #else do_RLE(srcptr, dstptr) register onebyt *srcptr, *dstptr; #endif { #define ALT_RLE /* testing */ #ifndef ALT_RLE register int found, scount /*, dcount*/; register onebyt c, lastc, tlastc; onebyt *dststart = dstptr; c = *(srcptr++); scount = 1; /*dcount = 0;*/ found = 1; /* one char has been found */ lastc = '\0'; while (scount < BLKSIZ) { tlastc = lastc; lastc = c; c = *(srcptr++); scount++; if (found == 1) { /* no run found */ if (c != lastc) { /* no run starting */ if (lastc == ESCAPE_CHAR) { *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = lastc; /*dcount++;*/ *(dstptr++) = 0; /*dcount++;*/ /* found one */ } else { *(dstptr++) = lastc; /*dcount++;*/ } found = 1; } else { found = 2; /* they matched, so two in a row */ } } else if (found == 2) { /* got two, try for three */ if (c != lastc) { /* only got two in a row */ if (lastc == ESCAPE_CHAR) { /* and tlastc as well */ *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = lastc; /*dcount++;*/ *(dstptr++) = 1; /*dcount++;*/ /* found two */ } else { *(dstptr++) = tlastc; /*dcount++;*/ *(dstptr++) = lastc; /*dcount++;*/ } found = 1; } else { /* found 3, got a run going */ found = 3; } } else { /* (found >= 3), got a run going */ if (c == lastc) { /* found another */ found++; } if ((c != lastc) || (found > 256)) { /* end, or too many */ *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = lastc; /*dcount++;*/ *(dstptr++) = (found > 256) ? 255 : found-1; /*dcount++;*/ found = 1; /* c has something other than the run char */ /* or found is 257-256 = 1 */ } } } /* while */ /* reached end of buffer; flush what was left */ if (found == 1) { if (c == ESCAPE_CHAR) { *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = c; /*dcount++;*/ *(dstptr++) = 0; /*dcount++;*/ } else { *(dstptr++) = c; /*dcount++;*/ } } else if (found == 2) { /* maybe have if lastc == c == ESCAPE_CHAR? */ if (lastc == ESCAPE_CHAR) { *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = lastc; /*dcount++;*/ *(dstptr++) = 0; /*dcount++;*/ } else { *(dstptr++) = lastc; /*dcount++;*/ } if (c == ESCAPE_CHAR) { *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = c; /*dcount++;*/ *(dstptr++) = 0; /*dcount++;*/ } else { *(dstptr++) = c; /*dcount++;*/ } } else { /* found >= 3, in the middle of processing a run */ *(dstptr++) = ESCAPE_CHAR; /*dcount++;*/ *(dstptr++) = c; /*dcount++;*/ *(dstptr++) = found-1; /*dcount++;*/ } /* return (dcount);*/ return (dstptr - dststart); #else /*ALT_RLE*/ /* * This was an attempt to write a faster do_RLE routine. However, * the profiler on my machine showed it to be slower than the big * wad of stuff above. I decided to leave the code here in case somebody * wants to play with it. */ register onebyt *scanptr; onebyt *endptr, *dststart; register onebyt c; register int i, count; endptr = srcptr + BLKSIZ; /* where the source ends */ dststart = dstptr; /* where the destination begins */ while (srcptr < endptr) { c = *srcptr; scanptr = srcptr+1; count = 1; while (*scanptr == c && scanptr < endptr) scanptr++, count++; if (count > 3) { i = count; do { *(dstptr++) = ESCAPE_CHAR; *(dstptr++) = c; if (i > 256) { /* was count */ *(dstptr++) = 255; i -= 256; } else { *(dstptr++) = i-1; /* was count-1 */ break; } } while (i > 0); } else { if (c == ESCAPE_CHAR) { /* special case: 1-3 0xDBs */ *(dstptr++) = ESCAPE_CHAR; *(dstptr++) = ESCAPE_CHAR; *(dstptr++) = count-1; /* count == 0 is legal */ } else { i = count; while (i--) *(dstptr++) = c; } } srcptr += count; } #ifdef DEBUG if (srcptr > endptr) printf("BUG: srcptr > endptr in do_RLE\n"); #endif return (dstptr - dststart); #endif /*ALT_RLE*/ } /* * Main compression entry point. * * Returns actual thread_format used. * * Note that "copybuf" should be at least twice as big as BLKSIZ. */ long #ifdef __STDC__ pak_SHK(int srcfd, int dstfd, long length, onebyt *copybuf) #else pak_SHK(srcfd, dstfd, length, copybuf) int srcfd, dstfd; long length; /* uncompressed size */ onebyt *copybuf; #endif { unsigned int partial; /* size for partial read/write */ onebyt *rptr, *out_buf; register int idx; onebyt scratch[8]; long srcposn, /* start in source file */ startposn, /* start in dest file */ endposn; /* end in dest file */ long unc_len = length, comp_len = 0L; twobyt CRC; int rlesize, lzwsize, out_size; /* length after compression */ int sc; /* spin counter */ static char *procName = "pak_SHK"; if (htab == NULL) htab = (struct ht *) Malloc(HSIZE * sizeof(struct ht)); CRC = 0; if ((srcposn = lseek(srcfd, (off_t) 0, S_REL)) < 0) /* only used if */ Fatal("Bad seek (srcposn)", procName); /* compress fails */ if ((startposn = lseek(dstfd, (off_t) 0, S_REL)) < 0) Fatal("Bad seek (startposn)", procName); lseek(dstfd, (off_t) 4, S_REL); /* leave room for 4-byte header */ comp_len += 4L; sc = 0; do { /* have to handle when length == 0L */ if (length > (long) BLKSIZ) { partial = (unsigned int) BLKSIZ; length -= (long) BLKSIZ; } else { partial = (unsigned int) length; length = 0L; for (idx = partial; idx < BLKSIZ; idx++) /* fill in zeroes */ *(copybuf + idx) = 0; } if (partial > 0) { /* should work anyway, but let's be careful */ if (read(srcfd, copybuf, partial) != partial) Fatal("Source read failed", procName); } /* calc CRC on all 4096 bytes */ CRC = CalcCRC(CRC, (onebyt *) copybuf, BLKSIZ); rlesize = do_RLE(copybuf, copybuf + BLKSIZ+1); /* pack 4096 bytes */ if (rlesize < 0x1000) { /* did it pack or expand? */ rptr = copybuf + BLKSIZ+1; /* use packed version */ } else { rlesize = 0x1000; /* just store original */ rptr = copybuf; } ClearTab(); lzwsize = do_LZW(rptr, rlesize, lbuf); /* compress from rle to lzw */ if ((lzwsize > rlesize) || (lzwsize < 0)) { /* lzw failed, use rle'd copy */ scratch[2] = 0; out_size = rlesize; out_buf = rptr; } else { /* lzw succeeded, use it */ scratch[2] = 1; /* LZW on */ out_size = lzwsize; out_buf = lbuf; } scratch[0] = (onebyt) (rlesize & 0x00ff); /* NOT out_size */ scratch[1] = (onebyt) ((rlesize >> 8) & 0x00ff); if (write(dstfd, scratch, 3) != 3) Fatal("Dest hdr write failed", procName); comp_len += 3; comp_len += out_size; if (comp_len > unc_len) goto bad_compress; /* you didn't see this */ if (write(dstfd, out_buf, out_size) != out_size) /* need to do CRLF */ Fatal("Dest write failed", procName); sc++; if (sc == 15) { sc = 0; Spin(); } } while (length != 0L); if ((endposn = lseek(dstfd, (off_t) 0, S_REL)) < 0) Fatal("Bad seek (now)", procName); if (lseek(dstfd, (off_t) startposn, S_ABS) < 0) Fatal("Bad seek (to4)", procName); scratch[0] = (char) CRC; scratch[1] = (char) (CRC >> 8); scratch[2] = 0; scratch[3] = ESCAPE_CHAR; if (write(dstfd, scratch, 4) != 4) Fatal("Dest hdr write failed", procName); if (lseek(dstfd, (off_t) endposn, S_ABS) < 0) Fatal("Bad seek (last)", procName); if (comp_len != endposn - startposn) { printf( "internal error: comp_len=%ld, endposn=%ld, startposn=%ld (%ld)\n", comp_len, endposn, startposn, endposn - startposn); } packedSize = comp_len; return (0x0002); /* SHK packing */ bad_compress: /* I'm too lazy to do a procedure call... */ if (verbose) { printf("storing..."); fflush(stdout); } if (lseek(srcfd, (off_t) srcposn, S_ABS) < 0) Fatal("Bad seek (srcposn in bad_compress)", procName); if (lseek(dstfd, (off_t) startposn, S_ABS) < 0) Fatal("Bad seek (startposn in bad_compress)", procName); FCopy(srcfd, dstfd, unc_len, copybuf, FALSE); packedSize = unc_len; return (0x0000); /* no compression */ } /* * P8 ShrinkIt uncompression routines * * Copyright 1989 Kent Dickey * C translation by Kent Dickey / Andy McFadden * Modifications for LZW-II designed by Andy Nicholas * * C decoder for LZW-II by Frank Petroski / Kent Dickey (simultaneously * and independently). Speed optimizations by Kent Dickey. */ /*static int inf; *//* to make Getc() calls happy */ static BOOLEAN type2; /* true if working with LZW-II format */ static onebyt escape_char; typedef struct { unsigned char chr; int prefix; } Table_ent; static Table_ent Real_tab[BLKSIZ-256]; /* first 256 don't exist */ static Table_ent *Table; static int Mask_tab[17] = { 0x0000, 0x01ff, 0x03ff, 0x03ff, 0x07ff, 0x07ff, 0x07ff, 0x07ff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff }; static int Number[17] = { /* 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,4 };*/ 8,9,10,10,11,11,11,11,12,12,12,12,12,12,12,12,12 }; static onebyt *Stack; /* simulated stack <= 64 for LZW-I, <= 4096 for II */ static int at_bit; static int at_byte; static int entry; #if 0 static int out_bytes; static int stack_ptr; #endif static onebyt last_byte; /* used in get_code */ static int reset_fix; /* fix problem unpacking certain LZW-II archives */ /* fake getc() */ # define Getc() *(ibuf++) /* * Stack operations; used by undo_LZW and undo_LZW_2 */ #ifdef DEBUG # define push(a_byte) \ { \ if (stack_ptr - Stack > 4096) { \ printf("\n*** stack_ptr exceeded 4096 in push() [%d]\n", \ (int) (stack_ptr - Stack));\ exit (-1); \ } \ *(stack_ptr++) = (onebyt) a_byte; \ } #else # define push(a_byte) *(stack_ptr++) = (onebyt) a_byte; #endif #ifdef DEBUG # define dump_stack(buffer) \ { \ printf("--- Going to dump stack, stack_ptr = %d, out_bytes = %d\n", \ (int) (stack_ptr - Stack), out_bytes); \ while (stack_ptr-- > stack_start) { \ *(buffer++) = *stack_ptr; \ } \ } #else # define dump_stack(buffer) \ while (stack_ptr-- > stack_start) { \ *(buffer++) = *stack_ptr; \ } #endif /* * Decipher LZW codes. */ static int #ifdef __STDC__ get_code(void) #else get_code() #endif { register unsigned int num_bits, old_bit, last_bit; long value, mask; /* onebyt byte1, byte2, byte3;*/ /* get compressed chars... */ long byte1, byte2, byte3; /* - */ #ifdef DEBUG printf("ENT: bit=%d byte=%-4d last_byte=$%.2x ", at_bit, at_byte, last_byte); printf("Entry: %.4x \n", entry); #endif num_bits = ((entry+1) >> 8); /* get hi-byte of entry */ /* last_bit = at_bit + Number[num_bits] + 8;*/ last_bit = at_bit + Number[num_bits]; old_bit = at_bit; #ifdef DEBUG if (at_byte >= BLKSIZ) { fprintf(stderr, "at_byte exceeded BLKSIZ (4096) in get_code()\n"); exit (-1); } #endif if (at_bit == 0) last_byte = Getc(); /* byte1 = last_byte;*/ /* first byte = last one used */ byte1 = (long) last_byte; /* - */ last_byte = Getc(); /* - */ /* byte2 = Getc(inf);*/ byte2 = ((long) last_byte) << 8; /* - */ if (last_bit > 16) { /* get 3rd byte if nec. */ /* byte3 = Getc(inf);*/ /* last_byte = byte3;*/ last_byte = Getc(); /* - */ byte3 = ((long) last_byte) << 16; /* - */ } else { byte3 = 0; /* last_byte = byte2;*/ } /* value = ((((long)byte3 << 8) + (long)byte2) << 8) + (long)byte1;*/ value = byte3 + byte2 + byte1; /* - */ mask = (long) Mask_tab[num_bits]; at_byte += (last_bit >> 3); /* new byte */ at_bit = (last_bit & 0x07); #ifdef DEBUG printf("| EX: value=$%.6x mask=$%.4x return=$%.3x\n", value, mask, ((value >> old_bit) & mask)); #endif #ifdef ZERO_SHIFT_BAD if (old_bit) return ((value >> old_bit) & mask); else return (value & mask); /* shifting by zero may be undefined */ #else return ((value >> old_bit) & mask); #endif /*ZERO_SHIFT_BAD*/ } /* * Un-LZW a range of bytes * * Reads data with get_code() and stores the output in "buffer". */ static void #ifdef __STDC__ undo_LZW(unsigned char *buffer, int length) #else undo_LZW(buffer, length) unsigned char *buffer; /* where to put output */ int length; /* uncompressed length of output */ #endif { register int oldc, incode, finalc, ptr; register onebyt *endbuf, *stack_ptr, *stack_start; /* initialize variables */ Table = Real_tab-256; entry = 0x101; /* start at $101 */ at_bit = at_byte = 0; endbuf = buffer + length; stack_start = stack_ptr = Stack; last_byte = 0; /* init last_byte */ oldc = incode = get_code(/*buffer*/); finalc = (oldc & 0xff); *(buffer++) = (onebyt) incode; /* main loop */ while (buffer < endbuf) { incode = ptr = get_code(/*buffer*/); if (ptr >= entry) { /* handle KwKwK case */ push(finalc); ptr = oldc; } while (ptr > 0xff) { /* fill the stack */ push(Table[ptr].chr); ptr = Table[ptr].prefix; } /* ptr is now < 0x100 */ finalc = ptr; *(buffer++) = (onebyt) finalc; while (stack_ptr > stack_start) /* dump the stack */ *(buffer++) = *(--stack_ptr); Table[entry].chr = (finalc & 0xff); /* mask to get unsigned?? byte */ Table[entry].prefix = oldc; entry++; oldc = incode; } } /* * Un-LZW-II a range of bytes * * Reads data with get_code() and stores the output in "buffer". Has * additional code to support LZW-II's table clears. */ static void #ifdef __STDC__ undo_LZW_2(unsigned char *buffer, int length) #else undo_LZW_2(buffer, length) unsigned char *buffer; /* where to put output */ int length; /* uncompressed length of output */ #endif { static int oldc; register int incode, finalc, ptr; register onebyt *endbuf, *stack_ptr, *stack_start; /* * gdr: oldc and oldc_initialized (the latter of which I added as * a concheck due to gcc compilation warnings) used to be auto * variables. I _believe_ that, based on the code in undo_LZW(), * oldc maintains its state from previous cals to undo_LZW_2(). */ #ifndef NDEBUG /* paranoid checks */ static int oldc_initialized = 0; int finalc_initialized = 0; finalc = oldc = 0; #endif /* initialize variables */ at_bit = at_byte = 0; /* out_bytes = 0;*/ /* stack_ptr = 0;*/ endbuf = buffer + length; stack_start = stack_ptr = Stack; last_byte = 0; /* init last_byte */ /* main loop */ /* while (out_bytes < length) {*/ while (buffer < endbuf) { /* - */ if (entry == 0x101 && !reset_fix) { /* table is really empty */ oldc = incode = get_code(/*buffer*/); finalc = (oldc & 0xff); #ifndef NDEBUG oldc_initialized = finalc_initialized = 1; #endif /* *(buffer + out_bytes++) = (unsigned char) incode;*/ *(buffer++) = (onebyt) incode; /* - */ if (buffer >= endbuf) { /* buffer is full? If so, we */ reset_fix = 1; /* want to skip get_code() next time */ break; /* we come through for next chunk */ } } incode = ptr = get_code(/*buffer*/); if (incode == 0x100) { /* Clear table code */ entry = 0x101; /* start at $101 */ Table = Real_tab-256; reset_fix = 0; continue; } if (ptr >= entry) { assert(finalc_initialized && oldc_initialized); push(finalc); ptr = oldc; } while (ptr > 0xff) { push(Table[ptr].chr); ptr = Table[ptr].prefix; } /* ptr is now < 0x100 */ finalc = ptr; #ifndef NDEBUG finalc_initialized = 1; #endif /* push(finalc);*/ /* dump_stack(buffer);*/ *(buffer++) = (onebyt) finalc; /* - */ while (stack_ptr > stack_start) /* - */ *(buffer++) = *(--stack_ptr); /* - */ Table[entry].chr = (finalc & 0xff); /* mask to get unsigned?? byte */ assert(oldc_initialized); Table[entry].prefix = oldc; entry++; oldc = incode; } } /* * Second pass... undo the Run Length Encoding. * * Copy data from inbuffer to outbuffer. Keep going until we've got * exactly BLKSIZ bytes. Note that this uses codes of the form * char count * which is different from some other programs. */ static void #ifdef __STDC__ undo_RLE(unsigned char *inbuffer, unsigned char *outbuffer) #else undo_RLE(inbuffer, outbuffer) unsigned char *inbuffer, *outbuffer; /*int length; *//* how many bytes from LZW; just to make sure... */ #endif { register onebyt c; register int count; /* count is RLE reps */ register onebyt *outbufend; #ifdef DEBUG /*printf("Starting undo_RLE, length = %d\n", length);*/ #endif outbufend = outbuffer + BLKSIZ; while (outbuffer < outbufend) { c = *(inbuffer++); /*length--;*/ if (c == (onebyt) escape_char) { c = *(inbuffer++); /*length--;*/ count = *(inbuffer++); /*length--;*/ while (count-- >= 0) { *(outbuffer++) = c; /*Putc(c, outf);*/ } } else { *(outbuffer++) = c; /*Putc(c, outf);*/ } } if (outbuffer != outbufend) fprintf(stderr, "internal error: bad undo_RLE\n"); #ifdef DEBUG /* printf("Exiting undo_RLE, length = %d (should be 0), total = %d (4096)\n", length, outbufend-outbuffer);*/ #endif } /* * Main entry point. * * This is among the more hellish things I've written. Uses * a large buffer for efficiency reasons, and unpacks a stream of bytes. * * If you find this hard to understand, imagine what it was like to debug. */ void #ifdef __STDC__ unpak_SHK (int srcfd, int dstfd, fourbyt comp_thread_eof, fourbyt thread_eof, register onebyt *buffer, BOOLEAN use_type2, twobyt thread_crc) #else unpak_SHK(srcfd,dstfd,comp_thread_eof,thread_eof,buffer, use_type2, thread_crc) int srcfd, dstfd; fourbyt comp_thread_eof, thread_eof; register onebyt *buffer; BOOLEAN use_type2; /* true if we should expect LZW-II */ twobyt thread_crc; #endif { twobyt CRC, blkCRC; onebyt vol; onebyt *wrbuf; /* points to buffer we're about to write */ short unlen, lzwflag, rleflag, complen; /* should be short */ unsigned int partial, toread, still_in_buf /*, crcsize*/; fourbyt tmp4; /* temporary 4-byte variable */ int cc; static char *procName = "unpak_SHK"; if (Stack == NULL) Stack = (onebyt *) Malloc(4096); type2 = use_type2; if (type2) CRC = 0xffff; /* different CRC for LZW-II */ else CRC = 0; /* initialize variables for LZW-II */ Table = Real_tab-256; entry = 0x101; /* start at $101 */ reset_fix = 0; /* read min(PAKBUFSIZ, comp_thread_eof) bytes into buffer */ if (comp_thread_eof > (fourbyt) PAKBUFSIZ) { toread = (unsigned int) PAKBUFSIZ; comp_thread_eof -= (fourbyt) PAKBUFSIZ; } else { toread = (unsigned int) comp_thread_eof; /* read it all... */ comp_thread_eof = (fourbyt) 0; } /* do initial read */ #ifdef DEBUG1 printf("initial read = %u\n", toread); #endif if ((cc = read(srcfd, buffer, toread)) < toread) { #ifdef DEBUG1 printf("Only read %d bytes\n", cc); #endif Fatal("Bad read during uncompress", procName); } ibuf = buffer; /* set input pointer to start of buffer */ /* get header data */ if (type2) { blkCRC = thread_crc; } else { blkCRC = Getc(); blkCRC += (Getc() << 8); } vol = (char) Getc(); /* disk volume #; not used here */ escape_char = (char) Getc(); /* RLE delimiter */ #ifdef DEBUG1 printf("vol = %d, escape_char = %x\n", vol, escape_char); #endif /* * main loop */ while (thread_eof != (fourbyt) 0) { /* note "unlen" is un-LZWed length (i.e., after RLE) */ if (type2) { unlen = Getc(); unlen += (Getc() << 8); lzwflag = (unlen & 0x8000) ? 1 : 0; /* flag is hi bit */ unlen &= 0x1fff; /* strip extra stuff */ rleflag = (unlen != BLKSIZ); if (lzwflag) { /* will the real length bytes please stand up*/ complen = Getc(); complen += (Getc() << 8); } } else { unlen = Getc(); unlen += (Getc() << 8); lzwflag = Getc(); rleflag = (unlen != BLKSIZ); } #ifdef DEBUG1 printf("Length after RLE = %d ($%.4x)\n", unlen, unlen); printf("LZW flag = %d, RLE flag = %d\n", lzwflag, rleflag); if (lzwflag != 0 && lzwflag != 1) { /* this is weird... */ for (lzwflag = -6; lzwflag < 3; lzwflag++) { printf("foo %d: %.2x\n", lzwflag, *(ibuf+lzwflag)); } } if (type2 && lzwflag) { printf("Length after RLE+LZW = %d ($%.4x)\n", complen, complen); } #endif /* If it looks like we're going to run out of room, shift & read * Mostly a guess; LZW length is less than unlen... This is * complicated and very prone to errors (but we err on the safe side). * tmp4 is the number of bytes between the current ptr and the end; * some (16-bit) compilers yack if it's all one statement. */ tmp4 = (fourbyt) buffer + (fourbyt) PAKBUFSIZ; tmp4 -= (fourbyt) ibuf; if (tmp4 < (unlen + 6)) { /* 6 = 3/4 byte header + two just in case */ still_in_buf = tmp4; #ifdef DEBUG1 printf("--- unlen = %d, space left = %d bytes\n", unlen, still_in_buf); #endif /* BCopy((onebyt *) ibuf, (onebyt *) buffer, still_in_buf, FALSE);*/ BCOPY((onebyt *) ibuf, (onebyt *) buffer, still_in_buf); if (comp_thread_eof != (fourbyt) 0) { /* no read, just shift */ if (comp_thread_eof > ((fourbyt) PAKBUFSIZ - still_in_buf)){ toread = (unsigned int) PAKBUFSIZ - still_in_buf; comp_thread_eof -= (fourbyt) PAKBUFSIZ - still_in_buf; } else { toread = (unsigned int) comp_thread_eof; comp_thread_eof = (fourbyt) 0; } #ifdef DEBUG1 printf("--- reading another %u bytes\n", toread); #endif if (read(srcfd, buffer+still_in_buf, toread) < toread) Fatal("Unable to read [middle]", procName); if (verbose) Spin(); } ibuf = buffer; } /* how much of the buffered data do we really need? */ if (thread_eof > (fourbyt) BLKSIZ) { partial = (unsigned int) BLKSIZ; thread_eof -= (fourbyt) BLKSIZ; } else { partial = (unsigned int) thread_eof; /* last block of file */ thread_eof = (fourbyt) 0; } /* * undo_LZW reads from ibuf (using Getc()) and writes to lbuf * undo_LZW_2 does what undo_LZW does, but for LZW-II. * undo_RLE reads from where you tell it and writes to rbuf * * This is really insane... */ if (lzwflag && rleflag) { if (type2) undo_LZW_2(lbuf, unlen); /* from ibuf -> lbuf */ else undo_LZW(lbuf, unlen); /* from ibuf -> lbuf */ undo_RLE(lbuf, rbuf); /* from lbuf -> rbuf */ wrbuf = rbuf; /* write rbuf */ } else if (lzwflag && !rleflag) { if (type2) undo_LZW_2(lbuf, unlen); /* from ibuf -> lbuf */ else undo_LZW(lbuf, unlen); /* from ibuf -> lbuf */ wrbuf = lbuf; /* write lbuf */ } else if (!lzwflag && rleflag) { undo_RLE(ibuf, rbuf); /* from ibuf -> rbuf */ wrbuf = rbuf; /* write rbuf */ ibuf += unlen; /* have to skip over RLE-only data */ /* normally ibuf is advanced by Getc() calls */ Table = Real_tab-256; /* must clear table if no LZW */ entry = 0x101; /* start at $101 */ reset_fix = 0; } else { wrbuf = ibuf; /* write ibuf */ ibuf += partial; /* skip over uncompressed data */ /* normally ibuf is advanced by Getc() calls */ Table = Real_tab-256; /* must clear table if no LZW */ entry = 0x101; /* start at $101 */ reset_fix = 0; } if (type2) CRC = CalcCRC(CRC, wrbuf, partial); else CRC = CalcCRC(CRC, wrbuf, BLKSIZ); #ifdef DEBUG1 printf("Writing %d bytes.\n", partial); #endif if (crlf(dstfd, wrbuf, partial) < partial) /* write wrbuf */ Fatal("Bad write", procName); } if (CRC != blkCRC) { fprintf(stderr, "WARNING: CRC does not match..."); if (verbose) fprintf(stderr, "CRC is %.4x vs %.4x\n", CRC, blkCRC); else fprintf(stderr, "extract with V suboption to see filenames.\n"); } } nulib/nuread.h100644 765 144 10615 6246126406 12030 0ustar gdrusers/* * nuread.h - linked list structures used for holding NuFX header data, * and structure definitions for archive innards * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * (this will be included by all source files which access NuFX archives) * * $Id: nuread.h,v 1.3 1996/11/03 23:01:06 gdr Exp $ */ /* The NuFX master format version we output, and the maximum we can extract */ #define OURMVERS 2 #define MAXMVERS 2 /* The NuFX record format version we output, and the maximum we can extract */ #define OURVERS 0 #define MAXVERS 3 #ifdef NEED_MASTER_ID /* "NuFile" in alternating ASCII */ static onebyt MasterID[7] = { 0x4e, 0xf5, 0x46, 0xe9, 0x6c, 0xe5, 0x0 }; /* "NuFX" in alternating ASCII */ static onebyt RecordID[5] = { 0x4e, 0xf5, 0x46, 0xd8, 0x0 }; #endif /* * Structure definitions for NuFX innards */ /* master header block */ typedef struct { onebyt ID[6]; twobyt master_crc; fourbyt total_records; Time arc_create_when; Time arc_mod_when; twobyt master_version; onebyt reserved1[8]; fourbyt master_eof; onebyt reserved2[6]; } 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; twobyt total_threads; twobyt reserved1; twobyt file_sys_id; onebyt file_sys_info; onebyt reserved2; fourbyt access; fourbyt file_type; fourbyt extra_type; twobyt storage_type; Time create_when; Time mod_when; Time archive_when; twobyt option_size; /* future expansion here... */ } RHblock; #define RHsize 58 /* sizeof(RHblock) should work, but might not */ #define ATTSIZE 64 /* default attrib_count when creating new */ /* * This buffer must be able to contain three things (not all at once): * - The master header block (size = MHsize) * - The record header block (size = RHsize) * - Attributes not specified in the RHblock (attrib_count - RHsize - 2) * * Currently, it only needs to be 64 bytes. Since it is allocated as local * storage only once during execution, making it reasonably large should * not cause any problems in performance but will make the program stable * if it encounters an archive with a drastically expanded RHblock. */ #define RECBUFSIZ 256 /* thread record */ typedef struct { twobyt thread_class; twobyt thread_format; twobyt thread_kind; twobyt thread_crc; 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; /* filename of record */ twobyt filename_length; /* length of filename (as stored in record hdr) */ twobyt real_fn_length; /* length of filename (actual) */ TNode *TNodePtr; /* points to first thread node */ fourbyt unc_len; /* total uncompressed length of all threads */ fourbyt comp_len; /* total compressed length of all threads */ struct RNode_s *RNext; /* points to next record node */ } RNode; /* head of list */ typedef struct { char *arc_name; /* filename of archive */ MHblock *MHptr; /* points to master header */ RNode *RNodePtr; /* points to first record node */ long nextposn; /* abs. position in file to put next record (for ADD) */ } ListHdr; /* * function declarations */ extern void OtherArc __P((char *, char *)); /* read archive info into memory */ extern ListHdr *NuRead __P((char *)); /* archive integrity check */ extern void NuTest __P((char *, char *)); /* calculate a CRC on a range of bytes */ extern twobyt CalcCRC __P((twobyt, register onebyt *, register int)); /* print a date from a (Time *) struct */ extern char *PrintDate __P((Time *, int)); /* copy bytes: *src, *dest, num, order? */ extern void BCopy __P((register onebyt *, register onebyt *, int, BOOLEAN)); /* swap bytes (maybe): *ptr, src_index, dst_index */ extern void HiSwap __P((onebyt *, register onebyt, register onebyt)); nulib/nusq.c100644 765 144 20003 6247227103 11520 0ustar gdrusers/* * nusq.c - Huffman squeeze/unsqueeze routines * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nusq.c,v 1.4 1996/11/28 06:16:35 gdr Exp $ */ #define SEGMENT_NAME "Compress__" #include "nudefs.h" #include #include #include #ifdef UNIX # include # include #endif #ifdef MSDOS /* For file IO */ # include # include # include # include #endif #if defined(__ORCAC__) && !defined(__GNO__) extern FILE *fdopen(int, char *); #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuetc.h" #include "nuread.h" #include "nupak.h" /* * usq.c - undo Huffman coding * Adapated from code By Marcel J.E. Mol * Based on sq3/usq2 by Don Elton * * 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 #ifdef __STDC__ get_int(FILE *f) #else get_int(f) FILE *f; #endif { twobyt val; val = (twobyt)getc(f); val += (twobyt)getc(f) << 8; return (val); } static int #ifdef __STDC__ getc_usq(FILE *f) #else getc_usq(f) /* get byte from squeezed file */ FILE *f; /* file containing squeezed data */ #endif { register short i; /* tree index */ /* * Follow bit stream in tree to a leaf. */ #if SHRT_MAX == 0x7fff #define CHECK_ONE #else #define CHECK_ONE (i <= 0x7fff) && #endif for (i=0; CHECK_ONE (i>=0); )/* work down(up?) from root */ { #undef CHECK_ONE 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: * * * * With a special case that a count of zero indicates a DLE * as data, not as a repeat marker. */ static void #ifdef __STDC__ putc_ncr(unsigned char c, FILE *t) #else putc_ncr(c, t) /* put NCR coded bytes */ unsigned char c; /* next byte of stream */ FILE *t; /* file to receive data */ #endif { static int lastc; /* last character seen */ /* if converting line terminators, do so now */ if (trbool && (c == fromc)) #ifdef __appleiigs__ c = 0x0d; #elif defined(UNIX) c = 0x0a; #else c = 0x0d; /* No CRLF stuff in unSQueeze... sorry */ #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 #ifdef __STDC__ init_usq(FILE *f) #else init_usq(f) /* initialize Huffman unsqueezing */ FILE *f; /* file containing squeezed data */ #endif { 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 #ifdef BSD43 # include #else /* SYSV, APW, MSC */ # include #endif #ifdef APW # include #endif #if defined(__sun__) && !defined(__SVR4) #include "sunos4.h" #endif #include "nuview.h" #include "nuread.h" #include "nuetc.h" #ifdef __appleiigs__ extern int GnoActive; #endif /* * 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", "Filename_thread" }; /*#define TKn 3*/ /* max #of thread_kinds in a thread_class */ char *TK[TCn][TKn] = { { "ASCII text", "ASCII text (predef size)", "" }, { "Create directory", "", "" }, { "File data_fork", "Disk image", "File resource_fork" }, { "Generic filename", "", "" } }; /* thread_format */ /*#define TFn 6*/ char *TF[TFn] = { "Uncompressed", "SQueezed (SQ/USQ)", "Dynamic LZW Type I (ShrinkIt)", "Dynamic LZW Type II (ShrinkIt)", "12-bit UNIX compress", "16-bit UNIX compress" }; /* brief thread format */ /*#define BTFn 6*/ char *BTF[BTFn] = { "Uncompr", "SQueezed", "LZW/1", "LZW/2", "Unix/12", "Unix/16" }; /* quick thread_format */ /*#define QTFn 6*/ char *QTF[QTFn] = { "unc", "squ", "shk", "sh2", "u12", "u16" }; /* file_sys_id */ /*#define FIDn 14*/ char *FID[FIDn] = { "Reserved/unknown ($00)", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh (MFS)", "Macintosh (HFS)", "LISA file system", "Apple CP/M", "Reserved ($09)", "MS-DOS", "High-Sierra", "ISO 9660", "AppleShare" }; /* 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", "FNT", "FOT", "BA3", "DA3", "WPF", "SOS", "$0D", "$0E", "DIR", "RPD", "RPI", "AFD", "AFM", "AFR", "SCL", "PFS", "$17", "$18", "ADB", "AWP", "ASP", "$1C", "$1D", "$1E", "$1F", "TDM", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "8SC", "8OB", "8IC", "8LD", "P8C", "$2F", "$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", "$3A", "$3B", "$3C", "$3D", "$3E", "$3F", "DIC", "OCR", "FTD", "$43", "$44", "$45", "$46", "$47", "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", "GWP", "GSS", "GDB", "DRW", "GDP", "HMD", "EDU", "STN", "HLP", "COM", "CFG", "ANM", "MUM", "ENT", "DVU", "FIN", "$60", "$61", "$62", "$63", "$64", "$65", "$66", "$67", "$68", "$69", "$6A", "BIO", "$6C", "TDR", "PRE", "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", "WP ", "$A1", "$A2", "$A3", "$A4", "$A5", "$A6", "$A7", "$A8", "$A9", "$AA", "GSB", "TDF", "BDF", "$AE", "$AF", "SRC", "OBJ", "LIB", "S16", "RTL", "EXE", "PIF", "TIF", "NDA", "CDA", "TOL", "DVR", "LDF", "FST", "$BE", "DOC", "PNT", "PIC", "ANI", "PAL", "$C4", "OOG", "SCR", "CDV", "FON", "FND", "ICN", "$CB", "$CC", "$CD", "$CE", "$CF", "$D0", "$D1", "$D2", "$D3", "$D4", "MUS", "INS", "MDI", "SND", "$D9", "$DA", "DBM", "$DC", "DDD", "$DE", "$DF", "LBR", "$E1", "ATK", "$E3", "$E4", "$E5", "$E6", "$E7", "$E8", "$E9", "$EA", "$EB", "$EC", "$ED", "R16", "PAS", "CMD", "$F1", "$F2", "$F3", "$F4", "$F5", "$F6", "$F7", "$F8", "OS ", "INT", "IVR", "BAS", "VAR", "REL", "SYS" }; /* * NuView program */ /* print date from Time structure */ char * #ifdef __STDC__ PrintDate(Time *tptr, int brief) #else PrintDate(tptr, brief) Time *tptr; int brief; #endif { 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, " "); return (buf); } if (!tptr->second && !tptr->minute && !tptr->hour && !tptr->day && !tptr->month && !tptr->year && !tptr->weekDay && !tptr->extra) { strcpy(buf, " [No Date] "); 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'; } if (brief == 2) { /* special case for ARCZOO format */ (void) sprintf(buf2, "%.2d-%s-%.2d %.2d:%.2d%c", (tptr->day)+1, MO[tptr->month], tptr->year, tptr->hour > 12 ? tptr->hour-12 : tptr->hour, tptr->minute, tptr->hour > 12 ? 'p' : 'a'); } else { (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 #ifdef __STDC__ DumpThreads (RNode *RNodePtr) #else DumpThreads(RNodePtr) RNode *RNodePtr; #endif { 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_crc: $%.4x\n", ind, THptr->thread_crc); 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). * Places the format, compressed EOF, and uncompressed EOF in the location * pointed to by the appropriate variables. * * This will probably fail if there are > 32767 threads. */ static twobyt #ifdef __STDC__ ScanThreads (RNode *RNodePtr, twobyt *format, long *dataCEOF, long *dataEOF) #else ScanThreads(RNodePtr, format, dataCEOF, dataEOF) RNode *RNodePtr; twobyt *format; /* format of the data_fork thread */ long *dataCEOF; /* length of the data_fork thread (compressed) */ long *dataEOF; /* length of the data_fork thread (uncompressed) */ #endif { int i; int count; THblock *THptr; TNode *TNodePtr; count = (int) RNodePtr->RHptr->total_threads; *format = 65535; /* default = error */ *dataCEOF = 0L; *dataEOF = 0L; 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; *dataCEOF = THptr->comp_thread_eof; *dataEOF = THptr->thread_eof; return (THptr->thread_kind); } TNodePtr = TNodePtr->TNext; } 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 * A: ARCZOO - Format similar to ARC or ZOO * Z: FULL - Fully detailed output */ void #ifdef __STDC__ NuView(char *filename, char *options) #else NuView(filename, options) char *filename; char *options; #endif { ListHdr *archive; MHblock *MHptr; RHblock *RHptr; RNode *RNodePtr; outtype prtform = PROSHK; int rec; char tmpbuf[80]; /* temporary buffer for sprintf + printf */ twobyt format, datakind; /* PROSHK */ int percent; /* PROSHK & ARCZOO */ long dataCEOF, dataEOF; /* PROSHK */ long total_files = 0L, total_length = 0L, total_complen = 0L; /* ARCZOO */ #ifdef __appleiigs__ /* kill "not used" messages */ char *ptr; #endif #if 0 static char *procName = "NuView"; #endif /* process options ourselves */ switch (options[0]) { case 't': if (INDEX(options+1, 'v')) prtform = PROSHK; /* -tv is same as -v */ else if (INDEX(options+1, 'a')) prtform = ARCZOO; else if (INDEX(options+1, 'z')) prtform = FULL; else prtform = NAMEONLY; break; case 'v': prtform = PROSHK; break; default: fprintf(stderr, "%s internal error: unknown output format\n", prgName); QuitNulib (-1); } archive = NuRead(filename); MHptr = archive->MHptr; /* Print master header info */ if (prtform == NAMEONLY) { /* don't print any info from master header for NAMEONLY */ } else if (prtform == PROSHK) { #ifdef __appleiigs__ /* 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 == ARCZOO) { printf("Name Length Stowage SF Size now"); printf(" Date Time \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_version: $%.4x ", MHptr->master_version); printf("master_crc: $%.4X\n", MHptr->master_crc); printf("total_records: %lu ", MHptr->total_records); if (MHptr->master_version >= 0x0001) { printf("master_eof: %lu\n", MHptr->master_eof); } else { printf("\n"); } 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"); QuitNulib (-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); /* get info on data_fork thread */ datakind = ScanThreads(RNodePtr, &format, &dataCEOF, &dataEOF); 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 */ /* Note RNodePtr->comp_len corresponds to dataCEOF, and */ /* RNodePtr->unc_len corresponds to dataEOF. */ if (!dataCEOF && !dataEOF) { printf("100%% "); /* file is 0 bytes long */ } else if ((!dataEOF && dataCEOF) || (dataEOF && !dataCEOF)) { printf("--- "); /* something weird happened */ } else if (dataEOF < dataCEOF) { printf(">100%% "); /* compression failed?!? */ } else { /* compute from sum of thread lengths (use only data?) */ percent = (dataCEOF * 100) / dataEOF; (void) sprintf(tmpbuf, "%.2d%%", percent); printf("%-4s ", tmpbuf); } if (!dataEOF && dataCEOF) /* weird */ printf(" ????\n"); else printf("%7ld\n", dataEOF); /* was 8ld */ } else if (prtform == ARCZOO) { printf("%-24.24s ", RNodePtr->filename); datakind = ScanThreads(RNodePtr, &format, &dataCEOF, &dataEOF); printf("%8ld ", dataEOF); printf("%-8.8s ", format < BTFn ? BTF[format] : "Unknown"); /* figure out the percent size, and format it appropriately */ /* Note RNodePtr->comp_len corresponds to dataCEOF, and */ /* RNodePtr->unc_len corresponds to dataEOF. */ if (!dataCEOF && !dataEOF) { printf(" 0%% "); /* file is 0 bytes long */ } else if ((!dataEOF && dataCEOF) || (dataEOF && !dataCEOF)) { printf("--- "); /* something weird happened */ } else if (dataEOF < dataCEOF) { printf(" <0%% "); /* compression failed?!? */ } else { /* compute from sum of thread lengths (use only data?) */ percent = 100 - ((dataCEOF * 100) / dataEOF); if (percent == 0 || percent == 100) (void) sprintf(tmpbuf, "%d%%", percent); else (void) sprintf(tmpbuf, "%.2d%%", percent); printf("%4s ", tmpbuf); } printf("%8ld ", dataCEOF); printf("%s\n", PrintDate(&RHptr->mod_when, 2)); total_files++; total_length += dataEOF; total_complen += dataCEOF; } else if (prtform == FULL) { printf("\n---> Information for record %d:\n", rec); printf("Filename: (%d) '%s'\n", RNodePtr->filename_length, RNodePtr->filename); printf("header ID: '%.4s' ", RHptr->ID); printf("version_number: $%.4X ", RHptr->version_number); printf("header_crc: $%.4X\n", RHptr->header_crc); printf("attrib_count: %u ", RHptr->attrib_count); 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", RHptr->file_sys_info); 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)); printf("GS/OS option_size: %.4x\n", RHptr->option_size); /* future expansion... */ } else { printf("%s internal error: undefined output format\n", prgName); QuitNulib (-1); } /* Print thread info */ if (prtform == FULL) DumpThreads(RNodePtr); RNodePtr = RNodePtr->RNext; /* advance to next record */ #ifdef __appleiigs__ if (!GnoActive && STOP_KEY()) QuitNulib (1); /* check for OA-period */ #endif } /* end of archive processing */ if (prtform == ARCZOO) { printf( " === ======== ==== ========\n"); printf("Total "); printf("%3ld ", total_files); printf("%8ld ", total_length); /* figure out the percent size, and format it appropriately */ if (!total_complen && !total_length) { printf(" 0%% "); /* file is 0 bytes long */ } else if ((!total_length && total_complen) || (total_length && !total_complen)) { printf("--- "); /* something weird happened */ } else if (total_length < total_complen) { printf(" <0%% "); /* compression failed?!? */ } else { /* compute from sum of thread lengths (use only data?) */ percent = 100 - (int) ((total_complen * 100L) / total_length); if (percent == 0 || percent == 100) (void) sprintf(tmpbuf, "%d%%", percent); else (void) sprintf(tmpbuf, "%.2d%%", percent); printf("%4s ", tmpbuf); } printf("%8ld\n", total_complen); } else if (prtform == FULL) { printf("\n*** end of file position: %ld\n", archive->nextposn); } /* else do nothing */ } nulib/nuview.h100644 765 144 1312 6246126407 12042 0ustar gdrusers/* * nuview.h - declarations for nuview.c * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * $Id: nuview.h,v 1.3 1996/11/03 23:01:07 gdr Exp $ */ typedef enum { NAMEONLY, PROSHK, ARCZOO, FULL } outtype; /* constant string declarations */ extern char *unknownStr; extern char *WD[]; extern char *MO[]; #define TCn 4 extern char *TC[]; #define TKn 3 extern char *TK[][TKn]; #define TFn 6 extern char *TF[]; #define BTFn 6 extern char *BTF[]; #define QTFn 6 extern char *QTF[]; #define FIDn 14 extern char *FID[]; #define STn 14 extern char *ST[]; extern char *FT[]; extern void NuView __P((char *, char *)); extern char *PrintDate __P((Time *, int)); nulib/sunos4.h100644 765 144 2317 6246126407 11766 0ustar gdrusers/* * This file is provided for compilation under SunOS 4.3, when an ANSI * compiler (such as gcc) is used. The system header files aren't * quite sufficient to eliminate hords of warnings. * * This header file might be useful for other architecture/compiler * combinations as well. If you use it, try not to break compilations * for the remaining combinations. * * $Id: sunos4.h,v 1.1 1996/10/12 19:16:50 gdr Exp $ */ #ifndef SUNOS4_H #define SUNOS4_H #include #ifdef __GNUC__ extern int _flsbuf __P((int, FILE *)); extern int _filbuf __P((FILE *)); #else #endif extern void bcopy __P((char *, char *, int)); extern int fclose __P((FILE *)); extern int fflush __P((FILE *)); extern int fprintf __P((FILE *, const char *, ...)); extern int fread __P((char *, int, int, FILE *)); extern int fseek __P((FILE *, long, int)); extern int fwrite __P((char *, int, int, FILE *)); extern int perror __P((const char *)); extern int printf __P((const char *, ...)); extern int rename __P((const char *, const char *)); extern int tolower __P((int)); extern int setvbuf __P((FILE *, char *, int, int)); extern int sscanf __P((char *, const char *, ...)); extern int system __P((const char *)); #endif nulib/make.orca100644 765 144 2272 6247227101 12137 0ustar gdrusers* * NuLib make script for Orca/C under Orca/Shell * * $Id: make.orca,v 1.2 1996/11/28 06:16:33 gdr Exp $ * unset exit * unset cc * unset cg set list numain nuread nuview nuadd nuext nupdel nupak set list {list} nuetc nublu nushk nusq nucomp getcwd fdopen set rlist nulib if {#} == 0 for i in {list} Newer {i}.a {i}.c if {Status} != 0 set exit on echo compile +e +t {i}.c keep={i} echo compile +e +t {i}.c keep={i} > lastfile compile +e +t {i}.c keep={i} unset exit end end Newer nulib.r nulib.rez if {Status} != 0 set exit on echo compile +e +t nulib.rez keep=nulib echo compile +e +t nulib.rez keep=nulib > lastfile compile +e +t nulib.rez keep=nulib.r unset exit end else set exit on for i echo compile +e +t {i}.c keep={i} > lastfile compile +e +t {i}.c keep={i} end end echo "starting link" for f in {list} unset exit Newer nulib {f}.a if {Status} != 0 set exit delete -W nulib echo link {list} keep=nulib link {list} keep=nulib echo copy -r nulib.r nulib copy -r nulib.r nulib break end end set exit on nulib/apwerr.h100644 765 144 15230 6246126407 12051 0ustar gdrusers/* * apwerr.h - text versions of APW and ProDOS 16 error codes * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@netcom.com) * * (ERROR() didn't cut it, and I'm trying to separate things from the shell.) * * $Id: apwerr.h,v 1.3 1996/11/03 23:01:02 gdr Exp $ */ /* 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" }; nulib/nulib.rez100640 765 144 733 6264126247 12173 0ustar gdrusers/* * $Id: nulib.rez,v 1.3 1997/01/06 07:41:27 gdr Exp $ */ #include "Types.Rez" resource rVersion (0x1, purgeable3, nocrossbank) { { 3, 2, 5, /* version 1.2.0 */ release, /* development|alpha|beta|final|release */ 0 /* non-final release number */ }, verBritain, /* close enough */ "nulib", "NuFX archiver / extractor\n" "Author: Andy McFadden \n" "Maintained by Devin Reade " }; nulib/makefile.mk100640 765 144 4107 6247227101 12455 0ustar gdrusers# # Makefile for NuLib v3.25. This makefile is intended for use # with dmake under GNO/ME. # # $Id: makefile.mk,v 1.2 1996/11/28 06:16:33 gdr Exp $ # # To make a smaller executable, you can exclude the Binary II routines # by setting DEFINES= -DNO_BLU # To exclude the UNIX compression routines, add -DNO_UCOMP # Select appropriate flag... -g for debugging, -O for optimized. OPTIMIZE = -G25 -w -v DEFINES = -D__GNO__ CFLAGS = $(DEFINES) $(OPTIMIZE) LDFLAGS = LIBS = -l ../contrib/src/libc2 HDRS = nudefs.h nuread.h nuview.h nuadd.h nuext.h nupdel.h nupak.h nuetc.h \ nublu.h nucomp.h nucompfn.h SRCS = numain.c nuread.c nuview.c nuadd.c nuext.c nupdel.c nupak.c nuetc.c \ nublu.c nucomp.c nushk.c nusq.c OBJS = numain.o nuread.o nuview.o nuadd.o nuext.o nupdel.o nupak.o nuetc.o \ nublu.o nucomp.o nushk.o nusq.o ARCFILES= README NOTES Makefile make.apw linker.scr linked.scr \ mkshk nulib.mak nulib.lnk $(SRCS) $(HDRS) all: nulib nulib: $(OBJS) nulib.r @purge $(CC) $(CFLAGS) $(OBJS) -o nulib $(LIBS) copyfork nulib.r $@ -r # shar version 3.49 # -c : add "cut here" line at top # -o : base name for output files # -l48 : max size is 48KB, but don't split files # -v : (not used) turn off verbose msgs shar: shar349 -c -osh.files/nulib -l48 $(ARCFILES) tar: tar cvf nulib.tar $(ARCFILES) nulib.doc clean: rm -f $(OBJS) clobber: clean rm -f nulib # # Additional dependancies # nuadd.o:: nudefs.h nuread.h nuadd.h nupak.h nuetc.h nublu.o:: nudefs.h nuview.h nuread.h nuadd.h nupak.h nuetc.h \ nuext.h nublu.h nucomp.o:: nudefs.h nuread.h nupak.h nuetc.h nucomp.h nucompfn.h nuetc.o:: nudefs.h nuetc.h nuext.o:: nudefs.h nuread.h nuext.h nupak.h nuetc.h numain.o:: nudefs.h nuread.h nuview.h nuadd.h nuext.h nupdel.h \ nublu.h nupak.h nuetc.h nupak.o:: nudefs.h nuread.h nucomp.h nucompfn.h nupak.h nuetc.h nupdel.o:: nudefs.h nuread.h nuadd.h nupak.h nupdel.h nuetc.h nuread.o:: nudefs.h crc.h nuread.h nupak.h nuetc.h nushk.o:: nudefs.h nuread.h nupak.h nuetc.h nusq.o:: nudefs.h nuetc.h nuread.h nupak.h nuview.o:: nudefs.h nuview.h nuread.h nuetc.h nulib/fdopen.c100644 765 144 633 6247227100 11751 0ustar gdrusers/* * This is a stub routine that was used to verify that linking was * (otherwise) possible. It needs to be replaced with an addition to * ORCALib. * * $Id: fdopen.c,v 1.1 1996/11/28 06:16:32 gdr Exp $ */ #ifndef __ORCAC__ %%% This file should not be compiled by this architecture. %%% #endif #include #include FILE * fdopen (int fd, char *openMode) { assert(0); return NULL; } nulib/nulib.desc100644 765 144 454 6264125632 12312 0ustar gdrusersName: nulib Version: 3.25 (5 Jan 97) Shell: Unix Author: Andy McFadden. Maintained by Devin Reade. Contact: gdr@eddore.myrias.com Where: /usr/local/bin FTP: ground.isca.uiowa.edu, apple2.caltech.edu This is a NuFX archiver/extractor. It is primarily intended for non-IIgs platforms. nulib/ChangeLog100644 765 144 17037 6247231201 12147 0ustar gdrusers===================== == NuLib ChangeLog == ===================== NuLib v3.25 beta 3 (27 November 1996, Devin Reade ) - Split off modification list into the "ChangeLog" file. - Updated Andy's email address. - Fixed an assert in nushk.c that was failing (unnecessarily) when extracting LZW-II files. - Eliminated "comparison always true" warning in nusq.c - Replaced gets() with fgets() in nuext.c [potential buffer overflow] - Changed (again) the nudefs.h #elif for NetBSD/FreeBSD/BSDI systems. - Updated man page, coalesced and cleaned up the documentation. - Got the Orca/Shell version compiling. fdopen(3) needs to be written. - Some more GNO-specific changes. - Added stack checking under Orca/C. - Did a function rename from Quit-->QuitNulib to avoid name conflicts under Orca/C. NuLib v3.25 beta 2 (18 October 1996, Devin Reade ) - Added support for FreeBSD/NetBSD with gcc v1.42 - Added man page. - Added "make file" for compiling under an unenhanced Orca/Shell (The Orca/Shell port is not yet done.) - The GNO port is running, abeit without Orca/Shell style command line expansion. (Not yet done.) NuLib v3.25 beta 1 (September 1996, Devin Reade ) - Fixed a bug that was causing nulib to dump core: There was a hardcoded limit of 256 files on the command line. Unfortunately, this limit was also applied as the maximum number of files in the archive. Worse yet, there was a section (where one is recursing through subdirs) where the current file count is _not_ checked against the maximum. The result was an array bound being overwritten and a subsequent core dump (or crash on systems without an MMU). This hard limit has been removed; instead, the file count is allowed to grow dynamically. - Fixed some bugs where printf had missing args. - Eliminated some extraneous static variables. (Declared static in a header file, but not used in some files.) - Changed the way the load segment is specified when compiling on the IIgs. Also changed all segment names to be 10 characters long. - #ifdef'd out various unused variables. - Unnested various comments. - ANSIfied the files. They still compile with a non-ANSI compiler, provided that compiler doesn't define __STDC__. - Changed nudefs.h so that, as much as possible, the appropriate #defines are made automagically. - Usage and help screens now only print out the base file name, not the full one. - Added a describe(1) entry and an rversion resource. - Verified compilation for the following systems. This _may_ have broken compilations for some older systems: AIX 3.2.5 with cc v2, xlc v2, and gcc v2.7.2 AIX 4.1 with cc v2, xlc v2, and gcc v2.7.2 HAL Sparc-64 OS with hcc v1.0 and gcc v2.7.2 HPUX with cc v10.10 and gcc v2.7.2 Linux with gcc v2.6.3 and lcc v3.4b Solaris 2.4 with SunPro C v4.0 and gcc v2.7.2 Solaris 2.5.1 with SunPro C v4.0 and gcc v2.7.2 SunOS 4.3 with /usr/5bin/cc and gcc v2.7.2 NuLib v3.24 (January 1993) - Improved MS-DOS filename fixing (now enforce "8 chars '.' 3 chars") - Fixed bug in LZW decompressor NuLib v3.23 (December 1992) - Minor bug fixes for the MS-DOS version (Dale G. Shields) NuLib v3.22 (September 1992) - Added "compress file as if it were a disk" code (provided by somebody whose name I just lost). Seems to work, but it's not 100% tested. - Faster compression - Updated filetype abbreviations NuLib v3.21 - Minor fixes NuLib v3.2 (April 1992) - Lots of minor bug fixes. (I was getting lost in the version numbers so I just upped it to 3.2). Of importance are the bug fixes to the LZW-II decoder and making it compatible with SysV EFT (Expanded Fundamental Types). The latter includes stuff like eight byte file offsets on lseeks. NuLib v3.14 (November 1991) - Finished fixing NeXT probs. Really. (Chris Osborn w/push from Bruce Kahn) - Fixed some minor bugs (Larry W. Virden) NuLib v3.13 - Repaired XENIX directory stuff in "nuadd.c" (Morgan Davis) NuLib v3.12 - Fixed problem with table clears on non-LZW blocks (Frank Petroski) NuLib v3.11 - Added some stuff to make the NeXT happy (Chris Osborn) - Added some stuff to allow it to compile with MS C 6.0. NuLib v3.1 (October 1991) - GS/ShrinkIt LZW-II uncompression (finally!) - All ShrinkIt compression/uncompression routines are about 15% faster - Better compatibility with System V, especially the AT&T 3B2 - Cleaned up code a bit and fixed minor bugs. Nulib v3.03 (February 1991) - Fixed XENIX problems with includes and libs (Ron Higgins). - Fixed bug in directory expansion (Larry W. Virden). NuLib v3.02 - Silenced screaming about bad dates (Larry W. Virden). - Fixed glitches in nulib.lnk and nulib.mak (Bruce Kahn). NuLib v3.01 - Fixed non-compression bug in ShrinkIt LZW (Scott Blackman). NuLib v3.0 (September 1990) - Added ShrinkIt LZW-I compression (replaces "fake" compression used previously). - Added UNIX 12-bit and 16-bit compression. - New archive listing format (similar to ARC and ZOO). - Added "compress" parameter to NULIBOPT environment variable. - Added M suboption for comment ("message") printing. NuLib v2.3 (May 1990 - not released): - Addition of UNIX compress. - Threw in some benchmarks. NuLib v2.2 - v2.22 (Apr 1990): - Second release as NuLib (after a brief vacation). - Fixed incompatibility problems with GS/ShrinkIt and ShrinkIt v3.0. - Added some support for comments. - Unpacks disk archives to files (good for the UNIX Apple ][+ simulator). - Fake compression correctly handles files that don't compress (it used to store them as compressed whether or not they got smaller). - Various minor changes/improvements (more help screens, etc). NuLib v2.1.1 (Nov 1989): - First wide distribution as NuLib. - Fixed command processing bugs. NuLib v2.1 (Nov 1989): - Yet another name change (thanks loads, L&L). - ShrinkIt LZW uncompression added. - MS-DOS code added. - Shell variable used for defaults. - CRLF translation. - Added R, I, and F suboptions. CShrink v2.08 (Oct 1989): - Altered help screens, some commands. - Added recognition of other kinds of files (compressed, shar, etc). - Switched to table lookups for calculating CRC (much faster). CShrink v2.07 (Sep 1989): - Another name change (legal reasons). - UNIX port completed. - Binary II operations are fully functional. - Some compression code added (unSQueeze, fake ShrinkIt pack). - '+' suboption added. - Text translation improved. - Printing of archived files (P option) now works. NuARC v2.03 (Aug 1989): - First NuARC distribution (APW executable only). - Added subdirectory expansion. - Added suboption processing. - Replaced buffered I/O (fopen(), fread(), etc) on files with lower-level read()/write() routines. - Added automatic byte-order determination. - Implemented move, extract all, and update/freshen. - Added Print archived file option. - Added Verbose, Text translation, and Uncompressed storage suboptions. - Wrote this documentation. NuARC v2.0 (Aug 1989): - Added archive manipulation routines (EXtract, Add and Delete for uncompressed archived files). - Added filename-only output format. - Added CRC verification. - Added byte order and data element size checks. - Removed the LAMESEEK option. NuView v1.2 (July 1989): - Major overhaul of all source code to make it work under APW C. - New //gs-specific routines added. - Minor alterations to output format. NuView v1.1 (June 1989): - Major rewrite of the way archives are read (had problems with machines requiring word-alignment of data). - Added thread file position storage to internal archive structure. - Fixed non-(void) sprintf() bug. NuView v1.0 (May 1989): - Initial release. - Works only on a Sun 3/50 running BSD UNIX. nulib/getcwd.c100644 765 144 4430 6247227100 11772 0ustar gdrusers/* * This file is part of the GNO libc replacement written by * Devin Reade . * * $Id: getcwd.c,v 1.1 1996/11/28 06:16:32 gdr Exp $ */ #include #include #include #include #include #include #ifdef __GNO__ #include #endif #define CWD "0:" /* Gsh for GNO v2.0.4 doesn't set prefix 8 ... */ extern int _mapErr(int); char * getcwd(char *buf, size_t size) { GSString255 inputPath; ResultBuf255 outputPath; ExpandPathRecGS rec = { 2, &inputPath, &outputPath, 0 }; int i; size_t length; char *result; outputPath.bufSize = 255; inputPath.length = strlen(CWD); strncpy(inputPath.text, CWD, inputPath.length); ExpandPathGS (&rec); if ((i = toolerror()) != 0) { errno = _mapErr(i); return NULL; } length = outputPath.bufString.length + 1; if (buf == NULL) { /* user provided no buffer */ if (size <= 0) { /* allocate buffer as large as necessary */ if ((result = malloc(length)) == NULL) { return NULL; } } else if (size < length) { /* specified size not large enough; error */ errno = ERANGE; return NULL; } else { /* allocate buffer of requested size */ if ((result = malloc(size)) == NULL) { return NULL; } } } else { /* user provided a buffer */ if (size < length) { errno = ERANGE; return NULL; } result = buf; } strncpy (result, outputPath.bufString.text, length-1); result[length-1] = '\0'; return result; } #ifdef TEST_CASE #include #include #define BUFFERSIZE 1024 #define BUFFERSIZE2 15 int main (int argc, char **argv) { static char buffer[BUFFERSIZE]; static char buffer2[BUFFERSIZE2]; char *p, *buf; int i, len; for (i=0; i<3; i++) { switch (i) { case 0: buf = NULL; len = 0; break; /* should pass */ case 1: buf = buffer; len = BUFFERSIZE; break; /* should pass */ case 2: buf = buffer2; len = BUFFERSIZE2; break; /* should fail */ default: assert(0); } p = getcwd(buf, len); if (p == NULL) { perror("getcwd failed"); } else { printf("cwd is \"%s\"\n", p); } } return 0; } #endif /* TEST_CASE */