[comp.sources.unix] v11i013: File archive program, Part04/07

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