rs@uunet.UU.NET (Rich Salz) (08/18/87)
Submitted-by: iuvax!bsu-cs!dhesi@seismo.CSS.GOV (Rahul Dhesi) Posting-number: Volume 11, Issue 13 Archive-name: zoo/Part04 #! /bin/sh # # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Readme.1st # portable.c # portable.h # prterror.c # sysv.c # various.h # version.c # version.h # zoo.1 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Readme.1st' then echo shar: "will not over-write existing file 'Readme.1st'" else sed 's/^X//' << \SHAR_EOF > 'Readme.1st' X X READ ME FIRST X XHere is version 1.51 of the zoo archiver in C source form. X XThe zoo archiver provides most of the functionality of the utilities X"tar" and "cpio" with some restrictions (file protections and Xmultiple links are not currently preserved and archives cannot be Xread from standard input or sent to standard ouput); in addition, it Xsupports storage of files in compressed form. Long filenames of up Xto 255 characters can be handled. X XAll implementations create compatible archives. Thus it is possible Xto move files, and file hierarchies, between dissimilar systems. X XThis package includes files as listed below. X XThe following are general information files: X XBugs Known bugs in zoo 1.51 XChanges Changes from version 1.41 to version 1.51 XCopyright Copyright policy XInstall Installation sugestions XReadme.1st You're reading this Xzoo.1 User manual for formatting with tbl and nroff/troff Xzoo.man Formatted user manual X XThe following makefile and make scripts are used for building zoo: X Xmakefile mkgenric mksysvsh mkx68 Xmkbsd mksysv mkuport mkx86 X XThe following are the source files in C: X Xaddbfcrc.c lzc.c options.c zoo.h Xaddfname.c lzconst.h options.h zooadd.c Xassert.h lzd.c parse.c zooadd2.c Xbasename.c machine.c parse.h zoodel.c Xbsd.c machine.h portable.c zooext.c Xcomment.c makelist.c portable.h zoofns.h Xcrcdefs.c misc.c prterror.c zoolist.c Xdebug.h misc2.c sysv.c zoomem.h Xerrors.i mstime.i various.h zoopack.c Xfiz.c needed.c version.c Xgeneric.c nextfile.c version.h Xgetfile.c nixtime.i zoo.c X XOther programs of interest, not part of this package, are: X X - [AmigaDOS] zoo 1.42b is the current latest version for AmigaDOS, X ported by J. Brian Waters X X - [MS-DOS] zoo 1.50 is distributed as an executable file and X documentation. X X - [MS-DOS] Sez 2.20 is the current version of Sez, the self- X extracting zoo utility, which can convert any zoo archive into X an executable file that will extract itself when executed X X - [MS-DOS] Atoz 1.11 is a program that will help do automated X conversion of archives, libraries, and squeezed files from any X other format into zoo format X X - [MS-DOS] Looz 2.00 is a program that will list, extract, X and test zoo archives, and also extract archived programs X directly into memory for immediate execution. X X - [VAX/VMS] Vooz 1.00 permits zoo archives to be extracted under X VAX/VMS X X - [Generic] Booz 1.01 is a small, fast zoo extractor that needs X a C compiler with much less functionality that needed by the X full zoo code X X -- Rahul Dhesi 1987/07/12 SHAR_EOF fi if test -f 'portable.c' then echo shar: "will not over-write existing file 'portable.c'" else sed 's/^X//' << \SHAR_EOF > 'portable.c' X#ifndef LINT Xstatic char sccsid[]="@(#) portable.c 1.5 87/05/03 16:01:05"; X#endif /* LINT */ X X#include "options.h" X/* XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved X*/ X/********************** Xportable.c contains functions needed to make Zoo portable to various Ximplementations of C. X XNote: Provided a 2's complement machine is used, all functions in Xthis file are themselves machine-independent and need not be changed Xwhen implementing Zoo on a different machine. Some code will choke Xon 1's complement machines--I think. X XFor machine-dependent declarations see files "machine.h" and "options.h". X XFor machine-dependent functions see file "machine.c" X*/ X X/* See if we could just use these for MSC */ X#ifdef MSC X#ifndef PORTABLE X#define PORTABLE X#endif X#endif X X X#ifdef PORTABLE X#include <stdio.h> X#include "various.h" X#include "zoofns.h" X X#include "machine.h" X#include "zoo.h" X#include "debug.h" X#include "assert.h" X X#ifdef NEEDCTYP X#include <ctype.h> /* for tolower() */ X#endif X X#ifdef DEBUG Xextern int verbose; X#endif X X/* Functions defined for use within this file only. */ X#ifdef LINT_ARGS Xlong to_long (BYTE[]); Xint to_int (BYTE[]); Xvoid b_to_zooh(struct zoo_header *, BYTE[]); Xvoid b_to_dir(struct direntry *, BYTE[]); Xint dir_to_b(BYTE[], struct direntry *); Xvoid zooh_to_b(BYTE[], struct zoo_header *); Xvoid splitlong(BYTE[], long); Xvoid splitint(BYTE[], int); X#else Xlong to_long (); Xint to_int (); Xvoid b_to_zooh(); Xvoid b_to_dir(); Xint dir_to_b(); Xvoid zooh_to_b(); Xvoid splitlong(); Xvoid splitint(); X#endif X Xextern unsigned int crccode; X X X/************************************************************************/ X/*** Following are functions that make up for various implementations ***/ X/*** of C not having certain library routines. ***/ X/************************************************************************/ X X#ifndef STRLWR X/********************** Xstrlwr() converts a string to lowercase and returns a pointer to the string X*/ Xchar *strlwr (str) Xchar *str; X{ X register char *s; X s = str; X while (*s != '\0') { X *s = toascii(*s); X if (isupper(*s)) X *s = tolower(*s); X s++; X } X return (str); X} X#endif /* STRLWR */ X X/********************** Xstrcmpi() compares strings just like strcmp() but it does it without regard to Xcase. X*/ Xint strcmpi (s1, s2) Xregister char *s1, *s2; X{ X for ( ; tolower(*s1) == tolower(*s2); s1++, s2++) X if (*s1 == '\0') X return(0); X return(tolower(*s1) - tolower(*s2)); X} X X#ifndef MEMSET X/********************** Xmemset() exists in Microsoft C and UNIX System V but not in Xenix. It sets Xthe first "cnt" bytes of "dest" to the character "c" and returns a pointer to X"dest". X*/ Xchar *memset (dest, c, cnt) Xchar *dest; Xint c; Xunsigned cnt; X{ X register unsigned i; X for (i = 0; i < cnt; i++) { X *(dest + i) = c; X } X} X#endif /* MEMSET */ X X#ifndef FPUTCHAR X/********************** Xfputchar() writes a character to stdout. It is identical to putchar Xbut is a function, not a macro. X*/ Xint fputchar (c) Xint c; X{ X return (fputc(c, stdout)); X} X#endif /* FPUTCHAR */ X X#ifndef TELL X/********************** Xtell() returns the current position of the file handle supplied X*/ Xlong tell (handle) Xint handle; X{ X return (lseek (handle, 0L, 1)); /* seek to current position */ X} X#endif /* TELL */ X X/***********************************************************************/ X/*** Following are declarations and functions that are written in a ***/ X/*** machine-independent way but they implement machine-dependent ***/ X/*** activities ***/ X/***********************************************************************/ X X#ifndef MSC X/********************** Xto_long() converts four consecutive bytes, in order of increasing Xsignificance, to a long integer. It is used to make Zoo independent of the Xbyte order of the system. X*/ Xlong to_long(data) XBYTE data[]; X{ X return (long) ((unsigned long) data[0] | ((unsigned long) data[1] << 8) | X ((unsigned long) data[2] << 16) | ((unsigned long) data[3] << 24)); X} X X/******************** Xsplitlong() converts a long integer to four consecutive BYTEs in order Xof increasing significance. X*/ Xvoid splitlong(bytes, bigword) XBYTE bytes[]; Xlong bigword; X{ X int i; X for (i = 0; i < 4; i++) { X bytes[i] = bigword & 0xff; X bigword = (unsigned long) bigword >> 8; X } X} X X/******************* Xsplitint() converts an integer to two consecutive BYTEs in order Xof increasing significance. X*/ Xvoid splitint(bytes, word) XBYTE bytes[]; Xint word; X{ X bytes[0] = word & 0xff; X word = (unsigned int) word >> 8; X bytes[1] = word & 0xff; X} X X/********************** Xto_int() converts two consecutive bytes, in order of increasing Xsignificance, to an integer, in a machine-independent manner X*/ Xint to_int(data) XBYTE data[]; X{ X return (int) ((unsigned int) data[0] | ((unsigned int) data[1] << 8)); X} X X#else /* else of ifndef MSC */ X Xlong to_long(data) XBYTE data[]; X{ X return ( * (long *) data ); X} X X/******************** Xsplitlong() converts a long integer to four consecutive BYTEs in order Xof increasing significance. X*/ Xvoid splitlong(bytes, bigword) XBYTE bytes[]; Xlong bigword; X{ X * (long *) bytes = bigword; X} X X/******************* Xsplitint() converts an integer to two consecutive BYTEs in order Xof increasing significance. X*/ Xvoid splitint(bytes, word) XBYTE bytes[]; Xint word; X{ X * (int *) bytes = word; X} X X/********************** Xto_int() converts two consecutive bytes, in order of increasing Xsignificance, to an integer. X*/ Xint to_int(data) XBYTE data[]; X{ X return (*(int *) data); X} X X#endif /* ifndef MSC .. else ... */ X X X#ifndef FIZ X/********************** XFunction frd_zooh() reads the header of a Zoo archive in a machine- Xindependent manner, from a FILE. X*/ Xint frd_zooh(zoo_header, zoo_file) Xstruct zoo_header *zoo_header; XFILE *zoo_file; X{ X int status; X BYTE bytes[SIZ_ZOOH]; /* canonical header representation */ X#ifdef DEBUG X if (verbose) { X printf("At file position [%8lx] ", ftell(zoo_file)); X } X#endif X status = fread ((char *) bytes, 1, SIZ_ZOOH, zoo_file); X b_to_zooh (zoo_header, bytes); /* convert array to structure */ X#ifdef DEBUG X if (verbose) { X printf("frd_zooh: reading\n"); X show_h(zoo_header); X } X#endif X if (status < SIZ_ZOOH) X return (-1); X else X return (0); X} X#endif /* ifndef FIZ */ X X X/********************** XFunction frd_dir() reads a directory entry in a machine-independent manner, Xfrom a FILE. X*/ Xint frd_dir(direntry, zoo_file) Xstruct direntry *direntry; XFILE *zoo_file; X{ X int status; X BYTE bytes[MAXDIRSIZE]; /* big enough to hold variable part too */ X X /* To simplify things, we read the maximum possible size of the X directory entry including the variable size and discard what is not X needed */ X#ifdef DEBUG X if (verbose) { X printf("At file position [%8lx] ", ftell(zoo_file)); X } X#endif X status = fread ((char *) bytes, 1, MAXDIRSIZE, zoo_file); X if (status < SIZ_DIR) X return (-1); X b_to_dir (direntry, bytes); X#ifdef DEBUG X if (verbose) { X printf("frd_dir: reading\n"); X show_dir(direntry); X } X#endif X return (0); X} X X#ifndef FIZ X/********************** XFunction rd_zooh() reads a Zoo archive header in a machine-dependent manner, Xfrom a file handle. X*/ Xint rd_zooh (header, zoo_han) Xstruct zoo_header *header; Xint zoo_han; X{ X int status; X BYTE bytes[SIZ_ZOOH]; X#ifdef DEBUG X if (verbose) { X printf("At file position [%8lx] ", tell(zoo_han)); X } X#endif X status = read (zoo_han, (char *) bytes, SIZ_ZOOH); X b_to_zooh (header, bytes); X#ifdef DEBUG X if (verbose) { X printf("rd_zooh: reading\n"); X show_h(header); X } X#endif X return (status); X} X X/********************** XFunction rd_dir() reads a directory entry in a machine-independent manner Xfrom a handle. X*/ Xint rd_dir(direntry, zoo_han) Xstruct direntry *direntry; Xint zoo_han; X{ X int status; X BYTE bytes[MAXDIRSIZE]; /* big enough to hold variable part too */ X /* To simplify things, we read the maximum possible size of the X directory entry including the variable size and discard what is not X needed */ X#ifdef DEBUG X if (verbose) { X printf("At file position [%8lx] ", tell(zoo_han)); X } X#endif X status = read (zoo_han, (char *) bytes, MAXDIRSIZE); X if (status < SIZ_DIR) X return (-1); X b_to_dir (direntry, bytes); X#ifdef DEBUG X if (verbose) { X printf("rd_dir: reading\n"); X show_dir(direntry); X } X#endif X return (0); X} X X/*********************** XFunction fwr_dir() writes a directory entry in a machine-independent manner Xto a FILE. Return value is -1 on error, else 0. X*/ Xint fwr_dir(direntry, zoo_file) Xstruct direntry *direntry; XFILE *zoo_file; X{ X int size; X BYTE bytes[MAXDIRSIZE]; X assert (direntry->type <= 2); X size = dir_to_b (bytes, direntry); X#ifdef DEBUG X if (verbose) { X printf("At file position [%8lx] ", ftell(zoo_file)); X printf("fwr_dir: writing\n"); X show_dir(direntry); X } X#endif X X if (fwrite ((char *) bytes, 1, size, zoo_file) != size) X return (-1); X else X return (0); X} X X/*********************** XFunction wr_dir() writes a directory entry in a machine-independent manner Xto a handle. Return value is -1 on error else 0. X*/ Xint wr_dir(direntry, zoo_han) Xstruct direntry *direntry; Xint zoo_han; X{ X int size; X BYTE bytes[MAXDIRSIZE]; X assert (direntry->type <= 2); X size = dir_to_b (bytes, direntry); X#ifdef DEBUG X if (verbose) { X printf("At file position [%8lx] ", tell(zoo_han)); X printf("wr_dir: writing\n"); X show_dir(direntry); X } X#endif X if (write (zoo_han, (char *) bytes, size) != size) X return (-1); X else X return (0); X} X X/*********************** XFunction wr_zooh() writes an archive header in a machine-independent manner Xto a handle. Return value -1 if error else 0. X*/ Xint wr_zooh(zoo_header, zoo_han) Xstruct zoo_header *zoo_header; Xint zoo_han; X{ X BYTE bytes[SIZ_DIR]; X zooh_to_b (bytes, zoo_header); X if (write (zoo_han, (char *) bytes, SIZ_ZOOH) != SIZ_ZOOH) X return (-1); X else X return (0); X} X X/*********************** XFunction fwr_zooh() writes an archive header in a machine-independent manner Xto a FILE. Return value is -1 if error else 0. X*/ Xint fwr_zooh(zoo_header, zoo_file) Xstruct zoo_header *zoo_header; XFILE *zoo_file; X{ X BYTE bytes[SIZ_DIR]; X zooh_to_b (bytes, zoo_header); X if (fwrite ((char *) bytes, 1, SIZ_ZOOH, zoo_file) != SIZ_ZOOH) X return (-1); X else X return (0); X} X X/*********************** Xb_to_zooh() converts an array of BYTE to a zoo_header structure. X*/ Xvoid b_to_zooh (zoo_header, bytes) Xstruct zoo_header *zoo_header; XBYTE bytes[]; X{ X int i; X for (i = 0; i < SIZ_TEXT; i++) /* copy text */ X zoo_header->text[i] = bytes[TEXT_I + i]; X zoo_header->zoo_tag = to_long(&bytes[ZTAG_I]); /* copy zoo_tag */ X zoo_header->zoo_start = to_long(&bytes[ZST_I]); /* copy zoo_start */ X zoo_header->zoo_minus = to_long(&bytes[ZSTM_I]); X zoo_header->major_ver = bytes[MAJV_I]; /* copy versions */ X zoo_header->minor_ver = bytes[MINV_I]; X} X X/*********************** Xzooh_to_b() converts a zoo_header structure to an array of BYTE. X*/ Xvoid zooh_to_b (bytes, zoo_header) Xstruct zoo_header *zoo_header; XBYTE bytes[]; X{ X int i; X for (i = 0; i < SIZ_TEXT; i++) /* copy text */ X bytes[TEXT_I + i] = zoo_header->text[i]; X splitlong (&bytes[ZTAG_I], zoo_header->zoo_tag); X splitlong (&bytes[ZST_I], zoo_header->zoo_start); X splitlong (&bytes[ZSTM_I], zoo_header->zoo_minus); X bytes[MAJV_I] = zoo_header->major_ver; /* copy versions */ X bytes[MINV_I] = zoo_header->minor_ver; X} /* zooh_to_b() */ X X/************************ Xdir_to_b() converts a directory entry structure to an array of BYTE. X*/ Xint dir_to_b (bytes, direntry) Xstruct direntry *direntry; XBYTE bytes[]; X{ X int i; X int cursize; X int fixsize; X splitlong(&bytes[DTAG_I], direntry->zoo_tag); X bytes[DTYP_I] = direntry->type ; X bytes[PKM_I] = direntry->packing_method ; X splitlong(&bytes[NXT_I], direntry->next); X splitlong(&bytes[OFS_I], direntry->offset); X splitint(&bytes[DAT_I], direntry->date); X splitint(&bytes[TIM_I], direntry->time); X splitint(&bytes[CRC_I], direntry->file_crc); X splitlong(&bytes[ORGS_I], direntry->org_size); X splitlong(&bytes[SIZNOW_I], direntry->size_now); X bytes[DMAJ_I] = direntry->major_ver; X bytes[DMIN_I] = direntry->minor_ver; X bytes[DEL_I] = direntry->deleted; X bytes[STRUC_I] = direntry->struc; X splitlong(&bytes[CMT_I], direntry->comment); X splitint(&bytes[CMTSIZ_I], direntry->cmt_size); X for (i = 0; i < FNM_SIZ; i++) X bytes[FNAME_I + i] = direntry->fname[i]; X bytes[TZ_I] = NO_TZ; /* assume unknown */ X bytes[NAMLEN_I] = 0; X bytes[DIRLEN_I] = 0; X X cursize = SIZ_DIR; /* to count size of directory */ X fixsize = SIZ_DIR; /* size of fixed part */ X assert (direntry->type <= 2); X if (direntry->type == 2) { /* handle stuff relevant to type 2 */ X cursize = SIZ_DIRL; X fixsize = SIZ_DIRL; X bytes[TZ_I] = direntry->tz; X assert(direntry->namlen < 256 && direntry->namlen >= 0); X if (direntry->namlen > 0 || direntry->dirlen > 0) X cursize += 2; /* space for namlen and dirlen */ X if (direntry->namlen > 0) { X bytes[NAMLEN_I] = direntry->namlen; X for (i = 0; i < direntry->namlen; i++) X bytes[LFNAME_I+i] = direntry->lfname[i]; X cursize += direntry->namlen; X } X assert(direntry->dirlen < 256 && direntry->dirlen >= 0); X if (direntry->dirlen > 0) { X bytes[DIRLEN_I] = direntry->dirlen; X for (i = 0; i < direntry->dirlen; i++) X bytes[cursize+i] = direntry->dirname[i]; X cursize += direntry->dirlen; X } X splitint(&bytes[cursize], direntry->system_id); X } X X /* Total length of directory entry is now cursize. */ X splitint(&bytes[VARDIRLEN_I], cursize - fixsize); X assert(cursize == X ((bytes[DIRLEN_I] > 0 || bytes[NAMLEN_I] > 0) ? 2 : 0) + X fixsize + bytes[DIRLEN_I] + bytes[NAMLEN_I] X ); X X /* Do CRC assuming CRC field is zero, and stuff CRC into field. */ X splitint(&bytes[DCRC_I], 0); /* fill with zeroes */ X crccode = 0; X addbfcrc(bytes, cursize); /* update CRC */ X splitint(&bytes[DCRC_I], crccode); X X /* return total length of directory entry */ X return (cursize); X X X} /* dir_to_b() */ X#endif /* ifndef FIZ */ X X/* b_to_dir() converts bytes to directory entry structure. The CRC of the Xdirectory bytes, if any, is checked and a zero or nonzero value is returned Xin direntry->dir_crc according as the check is good or bad */ X Xvoid b_to_dir(direntry, bytes) Xstruct direntry *direntry; XBYTE bytes[]; X{ X int i; X unsigned int savecrc; X direntry->zoo_tag = to_long(&bytes[DTAG_I]); X direntry->type = bytes[DTYP_I]; X direntry->packing_method = bytes[PKM_I]; X direntry->next = to_long(&bytes[NXT_I]); X direntry->offset = to_long(&bytes[OFS_I]); X direntry->date = to_int(&bytes[DAT_I]); X direntry->time = to_int(&bytes[TIM_I]); X direntry->file_crc = to_int(&bytes[CRC_I]); X direntry->org_size = to_long(&bytes[ORGS_I]); X direntry->size_now = to_long(&bytes[SIZNOW_I]); X direntry->major_ver = bytes[DMAJ_I]; X direntry->minor_ver = bytes[DMIN_I]; X direntry->deleted = bytes[DEL_I]; X direntry->struc = bytes[STRUC_I]; X direntry->comment = to_long(&bytes[CMT_I]); X direntry->cmt_size = to_int(&bytes[CMTSIZ_I]); X for (i = 0; i < FNM_SIZ; i++) X direntry->fname[i] = bytes[FNAME_I + i]; X X /* start by assuming variable part is zero bytes */ X direntry->var_dir_len = direntry->dir_crc = 0; X direntry->namlen = direntry->dirlen = 0; X direntry->lfname[0] = direntry->dirname[0] = '\0'; X direntry->tz = NO_TZ; /* assume unknown */ X direntry->system_id = SYSID_NIX; /* default system_id if not present */ X X assert (direntry->type <= 2); X if (direntry->type == 2) { X direntry->var_dir_len = to_int(&bytes[VARDIRLEN_I]); X assert(direntry->var_dir_len <= MAXDIRSIZE); X if (direntry->var_dir_len > MAXDIRSIZE) X direntry->var_dir_len = MAXDIRSIZE; X direntry->tz = bytes[TZ_I]; X if (direntry->var_dir_len > 0) X direntry->namlen = bytes[NAMLEN_I]; X if (direntry->var_dir_len > 1) X direntry->dirlen = bytes[DIRLEN_I]; X for (i = 0; i < direntry->namlen; i++) X direntry->lfname[i] = bytes[LFNAME_I + i]; X for (i = 0; i < direntry->dirlen; i++) X direntry->dirname[i] = bytes[DIRNAME_I + direntry->namlen + i]; X if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 2) { X direntry->system_id = to_int(&bytes[DIRNAME_I+direntry->namlen+i]); X } X /* do CRC calculation */ X savecrc = (unsigned int) to_int(&bytes[DCRC_I]); X crccode = 0; X splitint(&bytes[DCRC_I], 0); X addbfcrc(bytes, SIZ_DIRL + direntry->var_dir_len); X direntry->dir_crc = crccode - savecrc; X } X} X X#ifdef DEBUG X/* dump contents of archive header */ Xshow_h (zoo_header) Xstruct zoo_header *zoo_header; X{ X int i; X printf ("Header text:\n"); X for (i = 0; i < SIZ_TEXT-1; i++) /* all but trailing ^Z */ X putchar(zoo_header->text[i]); X putchar('\n'); X printf ("zoo_tag = [%8lx] zoo_start = [%8lx] zoo_minus = [%8lx]\n", X zoo_header->zoo_tag, zoo_header->zoo_start, X zoo_header->zoo_minus); X printf ("major_ver.minor_ver = [%d.%d]\n", X zoo_header->major_ver, zoo_header->minor_ver); X printf ("---------\n"); X} X X/* dump contents of directory entry */ Xshow_dir (direntry) Xstruct direntry *direntry; X{ X int i; X printf ("Directory entry for file [%s][%s]:\n", X direntry->fname, direntry->lfname); X printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n", X direntry->zoo_tag, (int) direntry->type, X (int) direntry->packing_method, direntry->next, X direntry->offset); X printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n", X direntry->org_size, direntry->size_now, X (int) direntry->major_ver, (int) direntry->minor_ver); X printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n", X (int) direntry->struc, (int) direntry->deleted, direntry->comment, X direntry->cmt_size); X printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n", X direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc); X printf ("system_id = [%d] dirlen = [%d] namlen = [%d]\n", X direntry->system_id, direntry->dirlen, direntry->namlen); X if (direntry->dirlen > 0) X printf ("dirname = [%s]\n", direntry->dirname); X printf ("---------\n"); X} X#endif /* DEBUG */ X X#endif /* PORTABLE */ SHAR_EOF fi if test -f 'portable.h' then echo shar: "will not over-write existing file 'portable.h'" else sed 's/^X//' << \SHAR_EOF > 'portable.h' X/* @(#) portable.h 1.3 87/05/03 16:01:22 */ X X/* Definitions for portable I/O X XThe contents of this file are hereby released to the public domain. X X -- Rahul Dhesi 1986/11/14 X XDefinitions are: X XOPEN binary open XCREATE binary create XOPEN_T text open XCREATE_T text create X XPlus flags for fopen(). X*/ X X/* XMicrosoft C. The only difference between I/O flags for standard UNIX I/O Xand Microsoft C is that Microsoft C requires the "O_BINARY" flag in open() Xand the "rb" string instead of "r" in fopen(). These are needed to prevent Xthe library from doing LF <--> CR LF translation. X*/ X X#ifdef MSC X#define P_RDWR S_IWRITE | S_IREAD X#define F_WRITE O_WRONLY X#define F_READ O_RDONLY X#define F_RDWR O_RDWR X#define FRDSTR "rb" /* readonly string for fopen() */ X#define FRWSTR "r+b" /* read/write string for fopen() */ X#define CREATE(x,y) open (x, y|O_CREAT|O_TRUNC|O_BINARY, P_RDWR) X#define OPEN(x,y) open (x, y|O_BINARY) X#define CREATE_T(x,y) open (x, y|O_CREAT|O_TRUNC, P_RDWR) X#define OPEN_T(x,y) open (x, y) X#define MKDIR(x) mkdir(x) X#endif X X#ifdef DLC X#define F_WRITE O_WRONLY X#define F_READ O_RDONLY X#define F_RDWR O_RDWR X#define FRDSTR "rb" /* readonly string for fopen() */ X#define FRWSTR "r+b" /* read/write string for fopen() */ X#define CREATE(x,y) open (x, 0) X#define OPEN(x,y) open (x, y) X#define MKDIR(x) mkdir(x) X#endif X X X#ifdef GENERIC X/* UNIX I/O, but MKDIR() is a no-operation */ X#define NIX_IO /* standard UNIX I/O */ X#define MKDIR(x) X#endif X X/* UNIX System V release 2.1 */ X#ifdef SYS_V X#define NIX_IO /* standard UNIX I/O */ X#define MKDIR(x) mkdir(x) /* define this in sysv.c */ X#endif X X/* Xenix release 3.0 */ X#ifdef XENIX X#define NIX_IO /* standard UNIX I/O */ X#endif X X/* 4.3BSD */ X#ifdef BSD4_3 X#define NIX_IO /* standard UNIX I/O */ X#define MKDIR(x) mkdir(x, 0777) X#endif X X/* Amiga */ X#ifdef MCH_AMIGA X/* Need to define a macro to make a new directory */ X#define MKDIR(x) {} X#define NIX_IO X#endif X X/* Standard UNIX I/O definitions */ X#ifdef NIX_IO X/* #define P_RDWR S_IWRITE | S_IREAD */ X#define P_RDWR 0644 X#define F_WRITE O_WRONLY X#define F_READ O_RDONLY X#define F_RDWR O_RDWR X#define FRDSTR "r" /* readonly string for fopen() */ X#define FRWSTR "r+" /* read/write string for fopen() */ X#define CREATE(x,y) open (x, y|O_CREAT|O_TRUNC, P_RDWR) X#define OPEN(x,y) open (x, y) X#define CREATE_T(x,y) open (x, y|O_CREAT|O_TRUNC, P_RDWR) X#define OPEN_T(x,y) open (x, y) X#endif /* NIX_IO */ X X/* VAX/VMS version 4.3. Not yet tested. */ X#ifdef VMS X#define P_RDWR 0 /* use user's default protection */ X#define F_WRITE O_RDWR /* VAX/VMS random write requires O_RDWR */ X#define F_READ O_RDONLY X#define F_RDWR O_RDWR X#define FRDSTR "r" /* readonly string for fopen() */ X#define FRWSTR "r+" /* read/write string for fopen() */ X#define CREATE(x,y) open (x, y|O_CREAT|O_TRUNC, P_RDWR) X#define OPEN(x,y) open (x, y) X#define CREATE_T(x,y) open (x, y|O_CREAT|O_TRUNC, P_RDWR) X#define OPEN_T(x,y) open (x, y) X#endif X X/* MIX C compiler for MS-DOS. Follows K&R closely. Not yet tested. */ X#ifdef MIX X#define P_RDWR 0 X#define F_WRITE 1 X#define F_READ 0 X#define F_RDWR 2 X#define FRDSTR "r" X#define FRWSTR "r+" X#define CREATE(x,y) creat (x,y) X#define OPEN(x,y) open (x,y) X#define CREATE_T(x,y) creat (x,y) X#define OPEN_T(x,y) open (x,y) X#endif X SHAR_EOF fi if test -f 'prterror.c' then echo shar: "will not over-write existing file 'prterror.c'" else sed 's/^X//' << \SHAR_EOF > 'prterror.c' X#ifndef LINT Xstatic char sccsid[]="@(#) prterror.c 1.4 87/05/21 11:37:59"; X#endif /* LINT */ X X/* XThe contents of this file are hereby released to the public domain. X X -- Rahul Dhesi 1986/11/14 X X*/ X#include "options.h" X#include <stdio.h> /* to make various.h includable */ X#include "various.h" X/* General error handler. Input format: X X parameter 1: 'w', 'e', or 'f'. X X 'm': message X 'M': message without preceding identification X 'w': WARNING X 'e': ERROR X 'f': FATAL X 'F': FATAL but program doesn't exist immediately X X All text printed is preceded by "Zoo: " or "Ooz: " depending X upon conditional compilation, except in the case of 'M' messages X which are printed without any text being added. X X For messages, the text supplied is printed if and only if the global X variable "quiet" is zero. Control then returns to the caller. X X For warnings, errors, and fatal errors, the variable "quiet" is ignored. X X For warnings and errors, the error message is preceded by the "WARNING:" X or "ERROR". The error message is printed and control returns to the X caller. X X For fatal errors, the error message is preceded by "FATAL:" and an X error message is printed. If the option was 'f', the program exits with X a status of 1. If the option was 'F', control returns to the caller and X it is assumed that the caller will do any cleaning up necessary and then X exit with an error status. X X parameter 2: The format control string for printf. X parameters 3 and 4 are passed along to printf. X X Note: printf() is always supplied parameters 3 and 4, even if they were X not on the parameter list passed to prterror(). It is assumed that X printf() will only use as many as are specified by the format string. X There is a small chance that on some machines, this will cause some X kind of stack exception (e.g. if the hardware maintains tag bits in X each word on the stack and doesn't allow certain types of data to X be arbitrarily accessed). This is just a theory so far. X*/ X Xextern int quiet; X X/* These declarations must be equivalent to those in errors.i */ Xchar no_match[] = "No files matched.\n"; Xchar failed_consistency[] = "Archive header failed consistency check.\n"; Xchar invalid_header[] = "Invalid or corrupted archive.\n"; Xchar internal_error[]="Internal error.\n"; Xchar disk_full[] = "I/O error or disk full.\n"; Xchar bad_directory[] = "Directory entry in archive is invalid.\n"; Xchar no_memory[] = "Ran out of memory.\n"; Xchar too_many_files[] = "Some filenames ignored -- can only handle %d.\n"; X X#ifndef OOZ Xchar wrong_version[]= X "Zoo %d.%d or later is needed to fully\nmanipulate this archive.\n"; Xchar cant_process[] = X "The rest of the archive (%lu bytes) cannot be processed.\n"; Xchar option_ignored[] = "Ignoring option %c.\n"; Xchar inv_option[] = "Option %c is invalid.\n"; Xchar bad_crc[] = "\007Bad CRC, %s probably corrupted\n"; X#endif X X#ifdef OOZ Xchar could_not_open[] = "Could not open "; X#else Xchar could_not_open[] = "Could not open %s.\n"; X#endif X X/*VARARGS2*/ Xprterror(level, format, a, b, c) Xregister int level; Xchar *format, *a, *b, *c; X X{ X char string[120]; /* local format string */ X *string = '\0'; /* get a null string to begin with */ X X#ifdef OOZ X strcpy (string, "Ooz: "); X#else X strcpy (string, "Zoo: "); X#endif X X switch (level) { X case 'M': *string = '\0'; /* fall through to 'm' */ X case 'm': if (quiet) return; break; X case 'w': strcat (string, "WARNING: "); break; X case 'e': strcat (string, "ERROR: "); break; X case 'F': X case 'f': strcat (string, "FATAL: "); break; X default: prterror ('f', internal_error); /* slick recursive call */ X } X X strcat (string, format); /* just append supplied message */ X X#ifdef OOZ X putstr (string); X putstr (a); X putstr (b); X#else X printf (string, a, b, c); /* and print the whole thing */ X fflush (stdout); X#endif X X if (level == 'f') /* and abort on fatal error 'f' but not 'F' */ X exit (1); X} X SHAR_EOF fi if test -f 'sysv.c' then echo shar: "will not over-write existing file 'sysv.c'" else sed 's/^X//' << \SHAR_EOF > 'sysv.c' X#ifndef LINT Xstatic char sysvid[]="@(#) sysv.c 1.3 87/06/19 22:21:30"; X#endif /* LINT */ X X/* machine.c for System V */ X X/* XThe contents of this file are hereby released to the public domain. X X -- Rahul Dhesi 1986/12/31 X*/ X X/**************** Xfunction trunc() truncates a file. X*/ X Xint trunc (handle) Xint handle; X{ X} X X/**************** XDate and time functions are standard UNIX-style functions. "nixtime.i" Xwill be included by machine.c. X*/ X X#include <sys/types.h> X#include <sys/stat.h> X#include <time.h> X X/* Function isadir() returns 1 if the supplied handle is a directory, Xelse it returns 0. X*/ X Xint isadir (handle) Xint handle; X{ X struct stat buf; /* buffer to hold file information */ X if (fstat (handle, &buf) == -1) { X return (0); /* inaccessible -- assume not dir */ X } else { X if (buf.st_mode & S_IFDIR) X return (1); X else X return (0); X } X} X X/**************** XFunction fixfname() converts the supplied filename to a syntax Xlegal for the host system. It is used during extraction. X*/ X Xchar *fixfname(fname) Xchar *fname; X{ X return (fname); /* default is no-op */ X} X Xextern long timezone; /* defined by library routine */ Xextern int daylight; X X/* Function gettz(), returns the offset from GMT in seconds of the Xlocal time, taking into account daylight savings time */ Xlong gettz() X{ X tzset(); X /* X Timezone fix thanks to Bill Davidsen <wedu@ge-crd.ARPA> X {uunet | philabs | seismo!rochester}!steinmetz!crdos1!davidsen X */ X return (timezone - daylight*3600); X} X X/* Standard UNIX-compatible time functions */ X#include "nixtime.i" X X/* XMake a directory. System V has no system accessible to ordinary Xusers to make a new directory. Hence we spawn a shell and hope X/bin/mkdir is there. Since /bin/mkdir gives a nasty error message Xif it fails, we call it only if nothing already exists by the Xname of the needed directory. X*/ X Xint mkdir(dirname) Xchar *dirname; X{ X char cmd[PATHSIZE+7]; X if (!exists(dirname)) { X strcpy(cmd, "/bin/mkdir "); X strcat(cmd, dirname); X return (system(cmd)); X } X} SHAR_EOF fi if test -f 'various.h' then echo shar: "will not over-write existing file 'various.h'" else sed 's/^X//' << \SHAR_EOF > 'various.h' X/* @(#) various.h 1.2 87/05/03 16:01:39 */ X X/* XThe contents of this file are hereby released to the public domain. X X -- Rahul Dhesi 1986/11/14 X*/ X X/* XThis files gives definitions for most external functions used by Zoo. XIf LINT_ARGS is defined, ANSI-style function prototypes are used, else Xnormal K&R function declarations are used. X XNote: Always precede this file with an include of stdio.h because it uses Xthe predefined type FILE. X*/ X X#ifdef LINT_ARGS XFILE *fdopen (int, char *); XFILE *fopen (char *, char *); Xchar *fgets (char *, int, FILE *); Xchar *gets (char *); Xchar *malloc (unsigned int); Xchar *realloc (char *, unsigned int); Xchar *strcat (char *, char *); Xchar *strchr (char *, int); Xchar *strcpy (char *, char *); Xchar *strdup (char *); Xchar *strlwr (char *); Xchar *strncat (char *, char *, unsigned int); Xchar *strncpy (char *, char *, unsigned int); Xchar *strrchr (char *, int); Xint trunc (int); Xint close (int); Xint creat (char *, int); Xint fclose (FILE *); Xint fflush (FILE *); Xint fgetc (FILE *); Xint fgetchar (); Xint fprintf (FILE *, char *,); Xint fputc (int, FILE *); Xint fputchar (int); Xint fputs (char *, FILE *); Xint fread (char *, int, int, FILE *); Xint fseek (FILE *, long, int); Xint fwrite (char *, int, int, FILE *); Xint open (char *, int,); Xint printf (char *,); Xint read (int, char *, unsigned int); Xint rename (char *, char *); Xint setmode (int, int); Xint strcmp (char *, char *); Xint strncmp (char *, char *, unsigned int); Xint unlink (char *); Xint write (int, char *, unsigned int); Xlong ftell (FILE *); Xlong lseek (int, long, int); Xlong tell (int); Xunsigned int strlen (char *); X X#else X XFILE *fdopen (); XFILE *fopen (); Xchar *fgets (); Xchar *gets (); Xchar *malloc (); Xchar *realloc (); Xchar *strcat (); Xchar *strchr (); Xchar *strcpy (); Xchar *strdup (); Xchar *strlwr (); Xchar *strncat (); Xchar *strncpy (); Xchar *strrchr (); Xint trunc (); Xint close (); Xint creat (); Xint fclose (); Xint fflush (); Xint fgetc (); Xint fgetchar (); Xint fprintf (); Xint fputc (); Xint fputchar (); Xint fputs (); Xint fread (); Xint fseek (); Xint fwrite (); Xint open (); Xint printf (); Xint read (); Xint rename (); Xint setmode (); Xint strcmp (); Xint strncmp (); Xint unlink (); Xint write (); Xlong ftell (); Xlong lseek (); Xlong tell (); Xunsigned int strlen (); X#endif SHAR_EOF fi if test -f 'version.c' then echo shar: "will not over-write existing file 'version.c'" else sed 's/^X//' << \SHAR_EOF > 'version.c' X/* @(#) version.c 1.7 1987/07/12 13:04:47 */ Xchar version[] = "version 1.51 (1987/07/12 13:04:47)"; SHAR_EOF fi if test -f 'version.h' then echo shar: "will not over-write existing file 'version.h'" else sed 's/^X//' << \SHAR_EOF > 'version.h' X/* @(#) version.h 1.5 Compiled: 1987/07/12 13:04:46 */ X#define VERSION "INTERNAL VERSION 87/07/12 13:04:46" SHAR_EOF fi if test -f 'zoo.1' then echo shar: "will not over-write existing file 'zoo.1'" else sed 's/^X//' << \SHAR_EOF > 'zoo.1' X.\" @(#) zoo.1 1.17 87/07/12 23:13:15 */ X.\" X.\" For formatting with nroff: X.\" tbl zoo.1 | nroff -man | col X.\" It should be possible to use troff instead of nroff but I haven't X.\" confirmed this. R.D. X.\" X.TH ZOO 1 "Jul 12, 1987" X.AT 3 X.de sh X.br X.ne 5 X.PP X\fB\\$1\fR X.PP X.. X.SH NAME Xzoo \- manipulate archives of files in compressed form X.SH SYNOPSIS X.B zoo X.RB { acDehlLPTuUvx }[ cdEfInMNoOpPquv1:./@ ] Xarchive [file] ... X.sp 0 X.B zoo \-command Xarchive [file] ... X.sp 0 X.B zoo h X.SH DESCRIPTION X.I Zoo Xis used to create and maintain collections of files in compressed form. XIt uses a Lempel-Ziv compression algorithm that gives space savings Xin the range of 20% to 80% depending on the type of file data. X.PP XThe command X.I zoo X.B h Xgives summary of commands. X.PP X.I Zoo Xwill not add an archive to itself, nor add the Xarchive's backup (with X.B .bak Xextension to the filename) to the archive. X.PP X.I Zoo Xhas two types of commands: Expert commands, which consist of one command Xletter followed by zero or more modifier characters, and Novice commands, Xwhich consist of a hyphen (`-') followed by a command word that may Xbe abbreviated. Expert commands are case-sensitive but Novice commands Xare not. X.PP XWhen X.I zoo Xadds a file to an existing archive, it marks as deleted any Xalready-archived file with the same name. (Directory prefixes are Xsignificant in this comparison if and only if directory names are Xbeing stored.) XDeleted files may be later undeleted. XArchives may be packed to recover space occupied by deleted files. X.PP XAll commands assume that the archive name ends with the characters X.B .zoo Xunless a different extension is supplied. X.PP X.B Novice commands X.PP XNovice commands may be abbreviated to a hyphen followed by at least Xone command character. Each Novice command works in two stages. XFirst, the command does its intended work. Then, if the result was Xthat one or more files were deleted in the specified archive, the Xarchive is packed. If packing occurs, the original unpacked archive Xis always left behind with an extension of X.B .bak. X.PP XNo Novice command ever stores the directory prefix of a file. XWhen a Novice command is used to add a file to an archive, any Xalready-archived file with the same name, regardless of the Xdirectory prefix, is marked deleted. X.PP XThe Novice commands are as follows. X.PP X.TP 8 X.B \-add XAdds the specified files to the archive. X.PP X.TP X.B \-freshen XAdds a specified file to the archive if and only if an older file by Xthe same name already exists in the archive. X.PP X.TP X.B \-delete XDeletes the specified files from the archive. X.PP X.TP X.B \-update XAdds a specified file to the archive either: if an older file by Xthe same name already exists in the archive or: if a file by the Xsame name does not already exist in the archive. X.PP X.TP X.B \-extract XExtracts the specified files from the archive. If no file is specified Xall files are extracted. X.PP X.TP X.B \-move XEquivalent to X.B \-add Xexcept that source files are deleted after addition. X.PP X.TP X.B \-print XEquivalent to X.B \-extract Xexcept that extracted data are sent to standard output. X.PP X.TP X.B \-list XGives information about the specified archived files including any Xattached comments. If no files are Xspecified all files are listed. Deleted files are not listed. X.PP X.TP X.B \-test XEquivalent to X.B \-extract Xexcept that the extracted data are not saved but any errors encountered Xare reported. X.PP X.TP X.B \-comment XAllows the user to add or update comments attached to archived files. XWhen prompted, the user may: type a carriage return to skip the file, Xleaving any Xcurrent comment unchanged; or type a (possibly null) comment of up Xto 65,535 characters terminated Xby X.B /end X(case-insensitive) on Xa separate line; or type the end-of-file character (normally control D) Xto skip all remaining files. X.PP X.TP X.B \-delete XDeletes the specified files. X.PP X.ne 16 X.nf XThe correspondence between Novice and Expert commands is as follows. X.PP X.\" Table formatting for troff thanks to Bill Davidsen <wedu@ge-crd.ARPA> X.sp X.in \nW-1 X.TS H Xtab(@); Xl l l. XNovice@@Equivalent XCommand@Description@Expert Command X_ X-add@add files to archive@aP: X-extract@extract files from archive@x X-move@move files to archive@aMP: X-test@test archive integrity@xNd X-print@extract files and send to standard output@xp X-delete@delete files from archive@DP X-list@list information about archived files@v X-update@update archive by adding new or newer files@aunP: X-freshen@freshen archive by adding newer files@auP: X-comment@allows user to attach comments to files@c X.TE X.in X.fi X.PD X.PP X.sh "Expert commands" XThe general format of expert commands is: X.PP X.I zoo X.RB { acDehlPTuUvx }[ cdEfInMNoOpPquv1:./@ ] Xarchive [file] ... X.PP XThe characters enclosed within {} are commands. Choose any one of Xthese. The characters enclosed within [] just to the right of the {} Xare modifiers and zero or more of these may immediately follow the Xcommand character. All combinations of command and modifier characters Xmay not be valid. X.PP XFiles are added to an archive with the command: X.PP X.I zoo X.RB { au }[ cfIMnPqu: ] Xarchive [file] ... X.PP XCommand characters are: X.PP X.TP X.B a XAdd each specified file to archive. Any already-archived file with the Xsame name is marked as deleted. X.PP X.TP X.B u XDo an update of the archive. A specified file is added to the Xarchive only if a copy of it is already in the archive and the copy Xbeing added is newer than the copy already in the archive. X.PP XThe following modifiers are specific to these commands. X.PP X.TP X.B M XMove files to archive. This makes X.I zoo Xdelete (unlink) the original files after they have been added to the Xarchive. Files are deleted after addition of all files to the archive is Xcomplete and after any requested packing of the archive has been done, Xand only if X.I zoo Xdetected no errors. X.PP X.TP X.B n XAdd new files only. A specified file is added only if it isn't Xalready in the archive. X.PP X.TP X.B P XPack archive after files have been added. X.PP X.TP X.B u XApplied to the X.B a Xcommand, this modifier makes it behave identically to the X.B u Xcommand. X.sp 1 XThe combination of the X.B n Xmodifier with the X.B u Xmodifier or X.B u Xcommand causes addition of a file to the archive either Xif the file is not already in the archive, X.I or Xif the file is already in the archive but the archived Xcopy is older than the copy being added. X.PP X.TP X.B : XDo not store directory names. In the absence of this modifier X.I zoo Xstores the full pathname of each archived file. X.PP X.TP X.B I XRead filenames to be archived from standard input. X.I Zoo Xwill read Xits standard input and assume that each line of text contains a Xfilename. Under the **IX family, the entire line is used. Under XMS-DOS and AmigaDOS, X.I zoo Xassumes that the filename is terminated by a blank, tab, Xor newline; thus it is permissible for the line of text to Xcontain more than one field separated by white space, and only the Xfirst field will be used. X.sp 1 XUnder the **IX family of operating systems, X.I zoo Xcan be used as follows in a pipeline: X.IP "" 10 Xfind . -print | zoo aI sources X.IP "" 5 X.sp 1 XIf the X.B I Xmodifier is specified, no filenames may be supplied on the command Xline itself. X.PP XFiles are extracted from an archive with the command: X.sp 1 X.I zoo X.RB { ex }[ dNoOpq./@ ] Xarchive [file] ... X.PP XThe X.B e Xand X.B x Xcommands are synonymous. If no file was specified, all files are Xextracted from the archive. X.PP XThe following modifiers are specific to the e and x commands: X.PP X.TP X.B N XDo not save extracted data but report any errors encountered. X.PP X.TP X.B O XOverwrite files. Normally, if a file being extracted would Xoverwrite an already-existing file of the same name, X.I zoo Xasks you if Xyou really want to overwrite it. You may answer the question with X`y', which means yes, overwrite; or `n', which means no, don't Xoverwrite; or `a', which means assume the answer is `y' for this Xand all subsequent files. The X.B O Xmodifier makes X.I zoo Xassume that files Xmay always be overwritten. X.sp 1 XThe X.B O, N, Xand X.B p Xmodifiers are mutually exclusive. X.PP X.TP X.B o XThis is equivalent to the X.B O Xmodifier if and only if it Xis given at least twice. It is otherwise ignored. X.PP X.TP X.B p XPipe extracted data to standard output. Error messages are piped to Xstandard output as well. However, if a bad CRC is detected, an error Xmessage is sent both to standard error and to standard output. X.PP X.TP X.B / XExtract to original pathname. Any needed directories must already Xexist. In the absence of this modifier all files are extracted into Xthe current directory. If this modifier is doubled as X.BR // , Xneeded directories need not exist and are created if necessary. X.PP XArchived files are listed with the command: X.sp 1 X.I zoo X.RB { lLv }[ adfv@ ] X.RB archive[ .zoo ] X[file] ... X.PP X.TP X.B l XInformation presented includes the date and time of each file, its Xoriginal and current (compressed) sizes, and the percentage Xsize decrease due to compression (labelled CF or compression factor). XIf no filename is supplied all files are listed except deleted files. X.PP X.TP X.B L XThis is identical to the X.B l Xcommand except that all supplied arguments must be archives and the contents of each are listed. X.PP X.TP X.B v XThis causes a verbose listing, which additionally shows Xany comment attached to each file. Using the X.B v Xmodifier with the X.B l Xcommand has the same effect. X.PP XThe following modifier is specific to the archive list commands: X.PP X.TP X.B a XThis gives a single-line format containing both each filename and the Xname of the archive, sorted by archive name. It is especially useful Xwith the X.B L Xcommand, since the result can be further sorted on any field to give a Xmaster listing of the entire contents of a set of archives. X.PP XFiles may be deleted and undeleted from an archive with the following Xcommands: X.sp 1 X.I zoo X.RB { DU }[ Pq1 ] Xarchive file ... X.PP XThe X.B D Xcommand deletes the specified files and the X.B U Xcommand undeletes the specified files. The X.B 1 Xmodifier (the digit one, not the letter ell) forces deletion or undeletion Xof at most one file. If multiple instances of the same file exist Xin an archive, use of the X.B 1 Xmodifier may allow selective extraction of one of these. X.PP XComments may be added to an archive with the command: X.sp 1 X.I zoo X.B c Xarchive X.PP XThis behaves identically to the X.B \-comment Xcommand. X.PP XThe timestamp of an archive may be adjusted with the command: X.sp 1 X.I zoo X.BR T [ q ] Xarchive X.PP X.I Zoo Xnormally attempts to maintain the timestamp of an archive to reflect Xthe age of the newest file stored in it. Should the timestamp ever be Xincorrect it can be fixed with the X.B T Xcommand. X.PP XAn archive may be packed with the command: X.sp 1 X.I zoo X.BR P [ EPq ] Xarchive X.PP XIf the backup copy of the archive already exists, X.I zoo Xwill refuse to Xpack the archive unless the X.B P Xmodifier is also given. The X.B E Xmodifier causes X.I zoo Xnot to save a backup copy of the original archive Xafter packing. A unique temporary file in the current directory Xis used to initially hold the packed archive. This file will be Xleft behind if packing is interrupted or if for some reason this Xfile cannot be renamed to the name of the original archive when Xpacking is complete. X.PP XPacking removes any garbage data appended to an archive because of XXmodem file transfer and also recovers space used by comments Xthat were replaced. X.PP X.sh "General modifiers" X.PP XThe following modifiers are applicable to several commands: X.PP X.TP X.B c XApplied to the X.B a Xand X.B u Xcommands, this causes the user to be prompted Xfor a comment for each file added to the archive. If the file Xbeing added has replaced a file already in the archive, any comment Xattached to the replaced file is shown to the user and becomes Xattached to the newly-added file unless the user changes it. XPossible user responses are as described for the X.B \-comment Xcommand. Applied to the archive list command X.B l, Xthe X.B c Xmodifier causes the listing of any comments attached to archived files. X.PP X.TP X.B \. XIn conjunction with X.B / Xor X.B // Xthis modifier causes any extracted pathname beginning with `/' to be Xinterpreted relative to the current directory, resulting in Xthe possible creation of a subtree rooted at the current directory. XIn conjunction with the command X.B P Xthe X.B . Xmodifier causes the packed archive to be created in the current Xdirectory. This is intended to allow users with limited disk Xspace but multiple disk drives to pack large archives. X.PP X.TP X.B d XMost commands that act on an archive act only on files that are Xnot deleted. The X.B d Xmodifier makes commands act on both normal and deleted files. If Xdoubled as X.B dd, Xthis modifier forces selection only of deleted files. X.PP X.TP X.B f XApplied to the X.B a Xand X.B u Xcommands, the X.B f Xmodifier causes fast archiving by adding files without compression. XApplied to X.B l Xit causes a fast listing of files in a multicolumn format. X.PP X.TP X.B q XBe quiet. Normally X.I zoo Xlists the name of each file and what action it is performing. The X.B q Xmodifier suppresses this. When files are being extracted to standard Xoutput, the X.B q Xmodifier suppresses the header preceding each file. X.sp 1 XError messages are Xnever suppressed. X.PP X.TP X.B @ XExtract or list beginning at position n, where n is a decimal number Xfollowing the X.B @ Xsign without any intervening spaces. This may be used to recover Xdata from a damaged archive by skipping the damaged part. The Xnumber specified must be the position within the archive of an Xundamaged directory entry. This position is usually obtained from X.I fiz(1). X.PP X.sh "Wildcard handling" XUnder the **IX family of operating systems, Xthe shell normally expands wildcards to a list of matching files. Wildcards Xthat are meant to match files within an archive must therefore Xbe escaped or quoted. When selecting files to be added to an archive, Xwildcard conventions are as defined for the shell. When selecting Xfiles from within an archive, wildcard handling is done by X.I zoo Xas described below. X.PP XUnder MS-DOS and AmigaDOS, quoting of wildcards is not needed. XAll wildcard expansion of filenames is done by X.I zoo, Xand wildcards inside directory names are expanded only Xwhen listing or extracting files but not when adding them. X.PP XThe wildcard syntax interpreted by X.I zoo Xis limited to the following characters. X.PP X.TP X.B * XMatches any sequence of zero or more characters. X.PP X.TP X.B \? XMatches any single character. X.sp 1 XArbitrary combinations of X.B * Xand X.B ? Xare allowed. X.PP X.TP X.B / XIf a supplied pattern contains a slash anywhere in it, then the Xslash separating any directory prefix from the filename must be Xmatched explicitly. If a supplied pattern contains Xno slashes, the match is selective only on the filename. X.PP X.TP X.B c-c XTwo characters separated by a hyphen specify a character range. All Xfilenames beginning with those characters will match. The character Xrange is meaningful only by itself or preceded by a directory name. XIt is not specially interpreted if it is part of a filename. X.PP XMS-DOS users should note that X.I zoo Xdoes not treat the dot as Xa special character, and it does not ignore characters following Xan asterisk. Thus X.B * Xmatches all filenames; X.B *.* Xmatches Xfilenames containing a dot; X.B *_* Xmatches filenames Xcontaining an underscore; and X.B *z Xmatches all filenames Xthat end with the character X.B z, Xwhether or not they contain Xa dot. X.SH FILES XxXXXXXX \- temporary file used during packing X.sp 0 X.RB archive_name. bak X\- backup of archive X.SH "SEE ALSO" Xcompress(1), fiz(1) X.SH BUGS XStandard input cannot be archived nor can a created archive be sent Xto standard output. Spurious error messages may appear if the Xfilename of an archive is too long. X.PP XSince X.I zoo Xnever archives any file with the same name as the archive or its Xbackup (regardless of any path prefixes), care should be taken Xto make sure that a file to be archived does not coincidentally have Xthe same name as the archive it is being added to. It usually suffices Xto make sure that no file being archived is itself a X.I zoo Xarchive. X.PP XOnly regular files are archived; directories and devices are not. X.PP XEarly versions of MS-DOS have a bug that prevents "." from referring Xto the root directory; this leads to anomalous results if the Xextraction of paths beginning with a dot is attempted. X.PP XIt is not currently possible to create a X.I zoo Xarchive containing all X.I zoo Xarchives that do not contain themselves. X.SH DIAGNOSTICS XError messages are intended to be self-explanatory and are divided into Xthree categories. WARNINGS are intended to inform the user of an Xunusual situation, such as a CRC error during extraction, or X.BR \-freshen ing Xof an archive containing a file newer than one specified on Xthe command line. ERRORS are fatal to one file, but execution Xcontinues with the next file if any. FATAL errors cause execution to Xbe aborted. The occurrence of any of these causes an exit status of X1. Normal termination without any errors gives an exit status of 0. X.SH "FUTURE DIRECTIONS" XA revised version of X.I zoo Xis in the works which will allow numbering of multiple versions of a Xfile and automatically perform end-of-line conversion for text files Xmoved between dissimilar systems. It will be upward and downward Xcompatible with existing versions of X.I zoo. X.SH THANKS XThanks are due to: X.PP XPaul Homchick, who provided numerous detailed reports about some Xnasty bugs. X.PP XBill Davidsen, who fixed X.I "zoo's" Xhandling of daylight savings time Xand also provided changes to make this manual format correctly Xwith X.I troff. X.SH AUTHOR XRahul Dhesi SHAR_EOF fi exit 0 # End of shell archive -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi -- Rich $alz Cronus Project, BBN Labs rsalz@bbn.com Moderator, comp.sources.unix sources@uunet.uu.net