[comp.sources.unix] v17i066: Zoo archive program, Part03/10

rsalz@uunet.uu.net (Rich Salz) (02/03/89)

Submitted-by: Rahul Dhesi <bsu-cs!dhesi>
Posting-number: Volume 17, Issue 66
Archive-name: zoo2/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 10)."
# Wrapped by rsalz@papaya.bbn.com on Thu Feb  2 18:03:58 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Install' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Install'\"
else
echo shar: Extracting \"'Install'\" \(7622 characters\)
sed "s/^X//" >'Install' <<'END_OF_FILE'
X
X
X                              INSTALLATION
X
X
XThis document explains how to compile and install the zoo archiver.
X
XGenerally, you will not build zoo by directly invoking the supplied
Xmakefile.  Instead, you will execute one of the supplied scripts, or
Xcreate a suitable script.  Each supplied script has a name beginning
Xwith the characters "mk" and is executed with the command
X"sh scriptname" or "csh scriptname".  All the scripts listed below
Xworked correctly with version 1.50 of zoo.  All of them except mkx68 and
Xmkx86 are also known to work correctly for versions 1.71, 2.00, and
X2.01.
X
Xmksysv    This is for any system running System V Release 2 or something
X          reasonably compatible.  It is known to work on the *T&T **IX
X          PC (also known as the 3B1 or the *T&T 7300) running software
X          revision 3.0.  It should also work on more recent versions of
X          Xenix.  On older machine architectures this script may need to
X          be revised to add a `-Ml' switch or equivalent to cause the
X          large memory model to be used.  For Microport System V/AT and
X          Xenix see also descriptions for mkuport, mkx86, and mkx68.
X
Xmkbsd     This is for 4.3BSD.  It is known to work on a VAX-11/785 run-
X          ning 4.3BSD straight from Berkeley.
X
Xmkuport   For Microport System V/AT.  This script includes the -Ml
X          switch so that the large memory model is used.
X
Xmkx68     This script is for Xenix/68000.  It is known to work with zoo
X          version 1.50 on a Radio Shack Model 16 running Xenix version
X          3.01.01.  It takes care of problems in the C compiler and in
X          the include files related to incorrect handling of the `void'
X          data type.  However, since this version of Xenix does not have
X          the memset() library function, the line "#define MEMSET" may
X          first need to be commented out from the group of symbol defin-
X          itions for SYS_V in the file ``options.h''.  You may also need
X          to add the switch "-F 6000" (or some other reasonable value
X          instead of 6000) to the loader to make it allocate a bigger
X          stack.
X
Xmkx86     This script is for Xenix for 80286 systems.  It is known to
X          work (for zoo version 1.50) on an Intel 310/286 running Xenix
X          3.4 and an AT running SCO Xenix 2.2.  It causes the large
X          memory model to be used and sufficient stack space to be allo-
X          cated at load time.
X
Xdescrip.mms This is a makefile suitable for use on VAX/VMS systems with
X          DEC's version of make, called MMS.  It is believed to work on
X          versions 4.5 through 4.7 of VAX/VMS.  The target zoo.exe
X          directs the linker to use the file options.opt so that the
X          shareable library is used.  The target zoobig.exe is identical
X          except that the shareable library is not used, making the exe-
X          cutable program about twice as big.
X
X          Special techniques are needed to work around numerous pecu-
X          liarities in VAX/VMS.  These are described separately in the
X          file ``vmsbugs.doc''.  In particular, the VAX/VMS version of
X          zoo must be used in conjunction with the "bilf.exe" utility,
X          which performs needed file conversions.  The source program
X          bilf.c is included in the current source distribution for zoo.
X
XThe file ``options.h'' defines preprocessor symbols for the various sys-
Xtems.  In most cases, given a reasonably powerful C compiler and
Xlibrary, you will be able to find a combination of options that will
Xwork.  Documentation for these options is in the file ``options.doc''.
X
XOther machine-dependent code and definitions are in machine.h,
Xmachine.c, and portable.h.  Also, the amount of memory used for various
Xarrays can be customized by defining symbols that are described and used
Xin zoomem.h.
X
XThe low-level input/output routines are in portable.c.  In most cases
Xthese will not need to be modified.
X
XThe zoo source code largely conforms to the requirements of Kernighan
Xand Ritchie's book.  Some exceptions are as follows.
X
X   - Variables are believed to be unique in their initial 8 characters.
X     Systems that distinguish fewer than 8 initial characters are
X     currently not supported.
X
X   - Zoo code assumes that members of structures do not have global
X     scope.
X
X   - Long preprocessor symbols are occasionally used.
X
X   - The special value -1 is cast to a pointer of type (FILE *) to pro-
X     vide a distinguished file pointer that is used to signify output to
X     a null file.  This should work on most systems that support the
X     system call sbrk.  Any suitable value may be supplied in place of
X     -1 in zooio.h.
X
XTROUBLESHOOTING.
X
XAs currently configured for **IX variants, zoo uses the access() system
Xcall to check for file existence (see the definition for the symbol
XEXISTS in options.h).  There is some question about the appropriatenes
Xof this, because access() can give the wrong answer when used from a
Xset-user-id program.  If EXISTS is left undefined, zoo uses its own
Xfunction to test for file existence by trying to open the file for read
Xand also for write.
X
XTwo common reasons for crashes when zoo is executed are the following.
X
X   - On machines with older (Intel-style) architectures zoo requires the
X     large memory model.  Compiling with the small memory model will
X     cause problems.  Also, systems that are limited to 64 kilobytes of
X     data and 64 kilobytes of code are not currently supported (but they
X     will be in the future).
X
X   - A generous amount of stack space is needed.  Depending on the sys-
X     tem, this will vary from about 15 kilobytes to about 33 kilobytes.
X     On systems that cannot expand the stack dynamically you will need
X     to specify the size of the stack area at load time.
X
XSPECIAL VERSIONS.  A version (currently 2.01) is available for MS-DOS
Xthat provides better performance due to assembly language routines and
Xalso includes some system-dependent features.  Another version
X(currently 2.00) has been ported by J. Brian Waters for the Amiga.  It
Xincludes several AmigaDOS-dependent features such as preservation of
Xfile times and wildcard expansion.
X
XEXTRACT-ONLY VERSIONS.  For a new system, your first concern should be
Xthe ability to extract and list zoo archives.  For this purpose try com-
Xpiling booz (which stands for Barebones Ooz) (currently version 1.01),
Xwhich can be compiled with three different options requiring different
Xdegrees of compiler sophistication and offering different levels of
Xfeatures.  Unlike zoo, booz will work on systems with less than 64 kilo-
Xbytes of total available memory.  However, unlike zoo, booz uses low-
Xlevel unbuffered file descriptors in **IX style.  This program is not a
Xpart of the standard zoo distribution, because nobody has ever shown any
Xinterest in it.
X
XMachine-dependencies.
X
X   - Currently the only systems supported are those that can read and
X     write in 8-bit units.  The file ``machine.h'' contains a typedef of
X     BYTE, and it must be defined to be an 8-bit quantity.
X
X   - It is not known whether zoo code as it stands will work on a 1's-
X     complement machine.
X
X   - The code assumes that type `int' is at least 16 bits long and type
X     `long' is at least 32 bits long.  There may be some implicit
X     assumptions that type `char' is exactly 8 bits;  I am not sure if
X     this is so.  However, type `BYTE' must be exactly 8 bits long.
X
X   - In accordance with K&R (p 126), zoo code assumes that sizeof(char)
X     equals exactly 1.
X
X                                     -- Rahul Dhesi 1988/08/25
END_OF_FILE
if test 7622 -ne `wc -c <'Install'`; then
    echo shar: \"'Install'\" unpacked with wrong size!
fi
# end of 'Install'
fi
if test -f 'bilf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bilf.c'\"
else
echo shar: Extracting \"'bilf.c'\" \(6109 characters\)
sed "s/^X//" >'bilf.c' <<'END_OF_FILE'
X/*
XThis program performs conversion of files between stream-LF format
X(as used by zoo) and fixed-length record binary format (used for Kermit
Xtransfers of zoo archives).
X
XThis program is:
X   (C) Copyright 1987 Rahul Dhesi.
X   All Rights Reserved.
X
XPermission is hereby granted to copy and modify this for any purpose,
Xwhether commercial or noncommercial, provided only that the above
Xcopyright notice and this paragraph be preserved and included
Xin all copies.
X
X                                 -- Rahul Dhesi 1987/07/25
X*/
X
X#include <stdio.h>
X#include <ssdef.h>
X#define STAT_NORM SS$_NORMAL
X#define STAT_ABORT SS$_ABORT
X
Xchar *strrchr();
Xchar *strdup ();
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{
X   char *inname;
X   char *outname;
X   char *option;
X   int status;
X
X   if (argc < 3 || argc > 4) {
X      printf ("BILF version 1.00 for VAX/VMS by Rahul Dhesi (1987/07/25)\n\n");
X      printf ("(C) Copyright 1987 Rahul Dhesi,  All Rights Reserved\n");
X      printf ("Permission to use and distribute is granted provided this copyright\n"); 
X      printf ("notice is preserved and included in all copies.\n\n");
X      printf ("Usage:  BILF {lb} infile [ outfile ]\n\n");
X      printf ("Choose one character from within braces.  If outfile is not supplied\n");
X      printf ("it has the same name as infile but a higher version number.\n");
X      printf ("Options are:\n\n");
X      printf ("l:  Write output file in stream-LF format.  This is the format that\n");
X      printf ("    zoo expects all zoo archives to be in.  If a zoo archive was\n");
X      printf ("    uploaded to a VAX/VMS system, it will need to be converted to\n");
X      printf ("    stream-LF format before manipulating with zoo.\n\n");
X      printf ("b:  Write output file in fixed-length 512-byte binary record format.  Before\n");
X      printf ("    a zoo archive can be downloaded from a VAX/VMS system to a\n");
X      printf ("    microcomputer using VAX/VMS Kermit, it must be converted to\n");
X      printf ("    this binary format.  Failure to do so will result in a corrupted\n");
X      printf ("    download.\n");
X      exit (STAT_NORM);
X   }
X
X   inname = argv[2];
X   option = argv[1];
X
X   if (argc == 3) {                    /* use same filename for output */
X      char *p;
X      outname = strdup (inname);
X      p = strrchr (outname, ';');      /* strip trailing version field */
X      if (p != NULL)
X         *p = '\0';
X   } else
X      outname = argv[3];
X
X   if (*option == 'l')
X      status = cvtstream (outname, inname);
X   else if (*option == 'b')
X      status = cvtbin (outname, inname);
X   else
X      prterror ('f', "Option %s is invalid\n", option);
X   if (status == -1)
X      prterror ('w', "An error occurred -- output file may be corrupted\n");
X   exit (STAT_NORM);
X}
X
X#define  MYBUFSIZ    8192
X
X/* writes input file to output file in stream format */
Xint cvtstream (outname, inname)
Xchar *outname, *inname;
X{
X   FILE *infile, *outfile;
X   char buffer[MYBUFSIZ];
X   int count;
X
X   infile = fopen (inname, "r");
X   if (infile == NULL)
X      prterror ('f', "Could not open input file %s\n", inname);
X   outfile = fopen (outname, "w");
X   if (outfile == NULL)
X      prterror ('f', "Could not open output file %s\n", outname);
X
X   while ((count = fread (buffer, 1, sizeof (buffer), infile)) > 0)
X      count = fwrite (buffer, 1, count, outfile);
X
X   close (infile); close (outfile);
X   if (count == -1)
X      return (-1);
X   else
X      return (0);
X}
X
X/*
XVMS C doesn't have strdup().
X*/
Xchar *strdup (str)
Xchar *str;
X{
X   char *malloc();
X   char *newstr = malloc (strlen (str) + 1);
X   if (newstr != NULL) {
X      strcpy (newstr, str);
X      return (newstr);
X   } else
X      return ((char *) NULL);
X}
X
X/* BLKSIZ must correspond to block size specified below in creat() */
X#define BLKSIZ 512
X
X/*
XWrites input file to output in fixed-length BLKSIZ-byte record format.
X*/
X
X#if 1
X#include <file.h>
X#else
X#include <fcntl.h>
X#endif
X
Xint convert ();
X
Xint cvtbin (outname, inname)
Xchar *outname, *inname;
X{
X   int status, inhan, outhan;
X   inhan = open (inname, O_RDONLY);
X   if (inhan == -1)
X      prterror ('f', "Could not open input file %s\n", inname);
X   outhan = creat (outname, 0, "rfm=fix", "mrs=512");
X   if (outhan == -1)
X      prterror ('f', "Could not open output file %s\n", outname);
X   status = convert (outhan, inhan);
X   close (inhan);
X   close (outhan);
X   return (status);
X}
X
X/*
XFunction convert() reads from inhan and writes to outhan, always
Xwriting in BLKSIZ-byte blocks, padding with nulls if necessary
X*/
X
Xint convert (outhan, inhan)
Xint inhan, outhan;
X{
X   char junk[BLKSIZ];
X   int count;
X   int done = 0;
X   do {
X      count = vmsread (inhan, junk, BLKSIZ);
X      if (count <= 0)
X         break;
X      if (count < BLKSIZ) {
X         int i;
X         for (i = count; i < BLKSIZ; i++)
X            junk[i] = 0;
X         done++;
X      }
X      count = write (outhan, junk, BLKSIZ);
X      if (count == -1)
X         break;
X   } while (!done);
X   if (count == -1)
X      return (-1);
X   else
X      return (0);
X}
X
X/**** Function vmsread() does a standard read() but gets around bugs
Xin the read() function of VAX/VMS C which make it unable to always
Xread the entire amount requested in a single read() call.
X*/
Xint vmsread (han, buf, amount)
Xint han;
Xchar *buf;
Xint amount;
X{
X   int count;
X   int thiscount;
X   count = 0;
X   while (count != -1 && count < amount) {
X      thiscount = read (han, &buf[count], amount - count);
X      if (thiscount == 0)
X         thiscount = read (han, &buf[count], amount - count);
X      if (thiscount == 0)
X          break;
X      if (thiscount == -1)
X         count = -1;
X      else
X         count += thiscount;
X   }
X   return (count);
X}
X
Xprterror (level, msg1, msg2)
Xchar level;
Xchar *msg1, *msg2;
X{
X   if (level == 'e' || level == 'w' || level == 'f')
X      printf ("BILF: ");
X
X   switch (level) {
X      case 'e': printf ("ERROR: ");    break;
X      case 'w': printf ("WARNING: ");  break;
X      case 'f': printf ("FATAL: ");    break;
X      default:  prterror ('f', "Internal error in prterror()\n");
X   }
X
X   printf (msg1, msg2);
X   if (level == 'f')
X      exit (STAT_ABORT);
X}
END_OF_FILE
if test 6109 -ne `wc -c <'bilf.c'`; then
    echo shar: \"'bilf.c'\" unpacked with wrong size!
fi
# end of 'bilf.c'
fi
if test -f 'fiz.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fiz.c'\"
else
echo shar: Extracting \"'fiz.c'\" \(6864 characters\)
sed "s/^X//" >'fiz.c' <<'END_OF_FILE'
X#ifndef LINT
Xstatic char sccsid[]="@(#) fiz.c 2.6 88/01/31 23:23:50";
X#endif /* LINT */
X
X/*
XThe contents of this file are hereby released to the public domain.
X
X                                   -- Rahul Dhesi 1987/02/06
X*/
X
X/*
XSearches for all directory entries in an archive and prints their
Xoffsets.  Zoo 1.41 and later may then be asked to extract a specific
Xfile by supplying the offset of the file.
X*/
X
X#include "options.h"
X#include "zooio.h"
X#include "various.h"
X#include "zoofns.h"
X#include "portable.h"         /* I/O definitions */
X#include "zoo.h"
X
X#ifdef LINT_ARGS
Xvoid prtctrl (char *);
Xvoid prtch (unsigned int);
X#else
Xvoid prtctrl ();
Xvoid prtch ();
X#endif
X
Xmain(argc,argv)
Xregister int argc;
Xregister char **argv;
X{
X   char *zooname;          /* name of archive to be read */
X   ZOOFILE zoo_file;       /* the archive being examined opened for read */
X   int state;              /* to keep track of how much of tag seen */
X   int inch;               /* char just read from archive */
X
X   static char usage1[] = "Fiz 2.0 (1987/02/01) public domain Zoo archive repair utility by Rahul Dhesi\n";
X   static char usage2[] = "Usage:  fiz archive[.zoo]  (\"fiz -h\" for help)\n";
X
X#ifdef SETBUF
X/* set stdout to unbuffered */
Xsetbuf (stdout, (char *) NULL);
X#endif
X
X   if (argc < 2) {
X      printf("%s%s", usage1, usage2);
X      exit (1);
X   }
X
X   if (strcmp(argv[1],"-h") == 0)
X      goto givehelp;
X
X   zooname = argv[1];
X
X   /* Add default extension if none supplied */
X   {
X      char *p, *q;
X      p = zooname + strlen(zooname);         /* point to last char */
X      while (p != zooname && *p != EXT_CH)
X         --p;
X      /* either found EXT_CH or reached beginning of zooname */
X      if (*p != EXT_CH) {
X         q = malloc(strlen(zooname) + strlen(EXT_DFLT) + 2);
X         if (q == NULL) {
X            printf("Fiz:  Ran out of memory.\n");
X            exit(1);
X         }
X         strcpy(q, zooname);
X         strcat(q, EXT_DFLT);
X         zooname = q;
X      }
X   }
X
X   zoo_file = zooopen (zooname, Z_READ);
X   if (zoo_file == NOFILE) {
X      printf("Fiz:  FATAL:  Could not open %s.\n", zooname);
X      exit(1);
X   }
X
X#ifdef DOUBLE_SECRET
X	{ void oh_well(void); oh_well(); }
X#endif
X
X#define  NOSTATE  1
X#define  HDR_1   0xdc
X#define  HDR_2   0xa7
X#define  HDR_3   0xc4
X#define  HDR_4   0xfd
X
X#define	DAT_1   '@'
X#define	DAT_2   ')'
X#define	DAT_3   '#'
X#define	DAT_4   '('
X
X/* finite state machine implemented here by hand */
X
X   state = NOSTATE;
X   while ((inch = zgetc(zoo_file)) != EOF) {
X      inch = inch & 0xff;
X      if (state == NOSTATE) {
X			if (inch == HDR_1)
X				state = HDR_1;
X			else if (inch == DAT_1)
X				state = DAT_1;
X		} else if (state == HDR_1 && inch == HDR_2)
X         state = HDR_2;
X      else if (state == HDR_2 && inch == HDR_3)
X         state = HDR_3;
X      else if (state == HDR_3 && inch == HDR_4)
X         state = HDR_4;
X		else if (state == DAT_1 && inch == DAT_2)
X			state = DAT_2;
X		else if (state == DAT_2 && inch == DAT_3)
X			state = DAT_3;
X		else if (state == DAT_3 && inch == DAT_4)
X			state = DAT_4;
X      else
X         state = NOSTATE;
X
X      if (state == HDR_4) {           						/* found archive tag */
X         long save_pos;
X         struct direntry direntry;
X         save_pos = zootell(zoo_file);
X         zooseek(zoo_file, save_pos-4L, 0);				/* back to tag pos */
X         frd_dir(&direntry, zoo_file);						/* read dir entry */
X         printf("****************\n");
X
X         printf ("%8lu: DIR ", save_pos-4L);
X
X         if (direntry.dirlen > 0) {
X            printf ("[");
X            prtctrl (direntry.dirname);
X            printf ("]");
X         }
X
X         printf(" [");
X         prtctrl (direntry.fname);
X         printf ("]");
X
X         if (direntry.namlen > 0) {
X            printf (" [");
X            prtctrl (direntry.lfname);
X            printf ("]");
X         }
X			printf (" ==> %4lu", direntry.offset);
X         if (direntry.dir_crc != 0)
X            printf (" [*bad CRC*]");
X         printf ("\n");
X         fseek (zoo_file, save_pos, 0);         /* try again from there */
X      } else if (state == DAT_4) {				/* file data */
X         printf ("%8lu: DATA\n", zootell(zoo_file) + 1);
X		}
X   }
Xexit (0);      /* don't fall through */
X
Xgivehelp:
X
X/*
Xvi macros:
Xto add printf:
X:s/^.*$/printf("&\\n");/
XTo remove printf:
X:s/^printf("\(.*\)\\n");/\1/
X*/
Xprintf("Fiz is used to help you recover data from a damaged archive.  Fiz searches\n");
Xprintf("the specified archive for directory entries and stored files, and prints the\n");
Xprintf("position of each one found.  Each directory entry contains a number that\n");
Xprintf("represents the location in the archive where the file is stored;  fiz also\n");
Xprintf("prints this position.  All numbers printed are decimal numbers.\n\n");
X
Xprintf("Use Zoo version 2.00 or higher to list or extract files in the damaged\n");
Xprintf("archive starting at a position identified by fiz.  For example, you can\n");
Xprintf("start extracting files from archive \"badarc.zoo\" at position 1098 with the\n");
Xprintf("command:\n\n");
X
Xprintf("     zoo x@1098 badarc\n\n");
X
Xprintf("Zoo will ignore the first 1098 bytes of the damaged archive and you should be\n");
Xprintf("able to recover the undamaged files from the rest of the archive.  You can\n");
Xprintf("also manually specify where to look for the file data with a command like\n\n");
X
Xprintf("     zoo x@1098,1153\n\n");
X
Xprintf("which tells zoo to use the directory entry at position 1098, but to get the\n");
Xprintf("actual file data from position 1153 (and not from where the directory entry\n");
Xprintf("says the data ought to be).  See the manuals for fiz and zoo for more details.\n");
X
Xexit (0);
X}
X
X/*
Xprtctrl() prints a string with all unprintable characters converted
Xto printable form.  To avoid the program running astray trying to
Xprint damaged data, no more than MAXPRT characters are printed.
XCharacters with the 8th bit set are printed preceded with ~.  Control
Xcharacters are printed preceded with ^.  Both ~ and ^ may preced
Xthe character if a control character has the 8th bit set.
X*/
X#define  MAXPRT      50
X
Xvoid prtctrl (str)
Xchar *str;
X{
X   unsigned int ch;
X   int count;
X   count = 0;
X
X   while (count < MAXPRT && *str != '\0') {
X      ch = (unsigned) *str;
X      prtch(ch);
X      str++;
X      count++;
X   }
X}
X
X/*
XDoes the actual character printing for prtctrl()
X*/
Xvoid prtch(ch)
Xunsigned int ch;
X{
X   /* assumes ASCII character set */
X   if (ch < ' ') {                        /* ^@ through ^_ */
X      printf("^%c", ch + 0x40);
X   } else if (ch == 0x7f) {               /* DEL */
X      printf("^?");
X   } else if (ch > 0x7f) {                /* 8th bit set */
X      printf("~");                        /* .. so precede with ~ */
X      prtch(ch & 0x7f);                   /* slick recursive call */
X   } else
X      printf("%c", ch);                   /* plain char */
X}
END_OF_FILE
if test 6864 -ne `wc -c <'fiz.c'`; then
    echo shar: \"'fiz.c'\" unpacked with wrong size!
fi
# end of 'fiz.c'
fi
if test -f 'makelist.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makelist.c'\"
else
echo shar: Extracting \"'makelist.c'\" \(6233 characters\)
sed "s/^X//" >'makelist.c' <<'END_OF_FILE'
X#ifndef LINT
X/* @(#) makelist.c 2.3 88/01/24 12:46:44 */
Xstatic char sccsid[]="@(#) makelist.c 2.3 88/01/24 12:46:44";
X#endif /* LINT */
X
X/*
XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
X*/
X
X#include "options.h"
X#include "portable.h"
X#include "errors.i"
X#include "zoo.h"
X#include "zooio.h"
X#include "various.h"
X
X#include "zoofns.h"
X#include "assert.h"
X#include "debug.h"
X
X#ifdef LINT_ARGS
Xchar *nameptr (char *);
Xvoid modpath (char *);
X#else
Xchar *nameptr();
Xvoid modpath ();
X#endif
X
X/*******************/
X/*
Xmakelist() gets all pathnames corresponding to a set of filespecs and
Xadds them to a list.  Not more than "flistsize" pathnames are added.
XInto `longest' it returns the length of the longest name added, or
Xzero if none added.
X
XFiles ignore1, ignore2, and ignore3 are not added to the list.
XA file that is a device/directory is also not added to the list.
X
XHowever, if ignore1 is NULL, both these tests are skipped and all files
Xwill be added to the list.
X*/
X
Xvoid makelist (argc, argv, flist, flistsize, ignore1, ignore2, ignore3, longest)
Xint argc;               /* number of filespec supplied */
Xchar *argv[];           /* array of pointers to supplied filespecs */
Xregister char *flist[]; /* array of pointers to filenames we will add */
Xint flistsize;          /* home many names we can use */
Xchar *ignore1, *ignore2, *ignore3; /* files to exclude from list */
Xint *longest;        /* length of longest name in list */
X{
X   char *this_path;        /* current pathname */
X   int fptr;               /* pointer to within flist */
X   register int i, j;      /* loop counters */
X
X#ifdef WILDCARD
X   char *pat_name;         /* filename part of pattern */
X#endif
X
X   int gap;                /* for Shell sort */
X   
X   flistsize--;            /* allow for one terminating NULL entry */
X   fptr = *longest = 0;
X
X   assert(argc > 0);
X
X#define WCLEN	4	/* length needed for wildcard, and a little extra */
X
X   while (argc > 0) {
X#ifdef WILDCARD
X		int argok = 0;											/* arg not matched yet */
X#endif
X      char *this_arg;
X		this_arg = emalloc (strlen (*argv) + WCLEN);
X		strcpy (this_arg, *argv);
X
X      /* Initialize fileset 0.  Select all files -- we will later
X	 		filter out the ones wanted */
X#ifdef FOLD
X      strlwr (this_arg);
X#endif
X
X#ifdef WILDCARD
X      pat_name = strdup (nameptr (this_arg));		/* pattern without path */
X#ifdef VER_CH /* trailing version field */
X{
X   static char version_field[] = " *";
X   char *p;
X   p = strrchr (pat_name, VER_CH);
X   if (p == NULL) {
X      *version_field = VER_CH;
X      pat_name = newcat (pat_name, version_field); /* adds trailing ";*" */
X   }
X}
X#endif
X		/*
X		replace filename by wildcard;  however, if argument ends in slash, 
X		then simply append wildcard so we get all files in that directory
X		*/
X#ifdef FORCESLASH
X			fixslash (this_arg);				/* convert backslashes to slashes */
X#endif
X
X		if (*lastptr(this_arg) == *PATH_CH) {
X			strcat (this_arg, WILDCARD);
X			pat_name = "*";					/* and select all files */
X		} else
X#ifdef SPEC_WILD
X			spec_wild (this_arg);
X#else
X      	strcpy (nameptr (this_arg), WILDCARD);
X#endif /* SPEC_WILD */
X#endif /* WILDCARD */
X
X      nextfile (0, this_arg, 0);
X      while (fptr < flistsize && 
X            (this_path = nextfile(1, (char *) NULL, 0)) != NULL) {
X         char *this_name = nameptr (this_path);
X			modpath (this_path);					/* do any needed changes to path */
X
X#ifdef IGNORECASE
X#define	COMPARE	strcmpi
X#else
X#define	COMPARE	strcmp
X#endif
X			if (ignore1 != NULL) {
X				if (samefile (this_name,ignore1)  ||    /* exclude ignored files */
X					 samefile (this_name,ignore2)  ||
X					 samefile (this_name,ignore3))
X					continue;
X
X#ifdef CHEKUDIR
X				if (isuadir(this_path))
X					continue;
X#else /* CHEKUDIR */
X# ifdef CHEKDIR
X				if (isfdir(this_path))
X					continue;
X# endif /* CHEKDIR */
X#endif /* CHEKUDIR */
X			} /* end if ignore1 ! = NULL */
X
X/* 
XIf WILDCARD is defined (e.g. AmigaDOS, MS-DOS, VAX/VMS), then nextfile()
Xreturns all filenames and we must now select the ones we need by pattern
Xmatching.  If WILDCARD is not defined (e.g. **IX), filenames have already been
Xselected by the shell and need not be tested again. 
X*/
X#ifdef WILDCARD
X			if (match_half (this_name,pat_name) ||
X				match_half (pat_name, "?-?") &&     /* character range */
X					*this_name >= *pat_name && *this_name <= pat_name[2])
X#endif
X			{
X#ifdef WILDCARD
X				argok = 1;									/* remember arg matched */
X#endif
X				flist[fptr++] = strdup (this_path);
X				if (*longest < strlen(this_path))
X					*longest = strlen(this_path);
X			}
X
X		} /* end while */
X#ifdef WILDCARD
X		if (argok == 0) {									/* no match for argument */
X			prterror ('e', "Could not open %s\n", *argv);
X		}
X#endif
X      argc--;
X      argv++;
X   }
X   /* fptr is now 1 + index of last item in array */
X
X   if (this_path != NULL && fptr >= flistsize)
X      prterror ('w', too_many_files, flistsize);
X#ifndef  DONT_SORT
X   /* Shell sort -- K&R p. 58 */
X   for (gap = fptr/2; gap > 0; gap /= 2)
X      for (i = gap; i < fptr; i++)
X         for (j = i - gap; j >= 0 && 
X            strcmp(flist[j],flist[j+gap]) > 0; j -= gap) {
X            char *t = flist[j]; flist[j] = flist[j+gap]; flist[j+gap] = t;
X         }
X#endif /* DONT_SORT */
X
X   fptr--;     /* fptr is now index of last item in array */
X
X   /* Remove duplicates */
X   for (i = 0; i < fptr; i++) {
X      while (i<fptr && COMPARE(flist[i],flist[i+1]) == 0) {
X         for (j = i; j < fptr; j++)
X            flist[j] = flist[j+1];
X         fptr--;
X      }
X   }
X
X   flist[++fptr] = NULL;      /* NULL entry terminates list */
X}
X
X/*******
Xmodpath() makes any changes needed before pathname is stored;
Xcurrently these could involve folding it to lower case and
Xconverting backslashes to forward slashes
X*/
X
X/*ARGUSED*/
Xvoid modpath (path)
Xchar *path;
X{
X#ifdef FOLD
X	strlwr (path);
X#endif
X
X#ifdef FORCESLASH
X	fixslash (path);				/* convert backslashes to slashes */
X#endif
X}
X
X#ifdef CHEKDIR
X/* Function isfdir returns 1 if pathname is a directory else 0 */
Xint isfdir (this_path)
Xchar *this_path;
X{
X	int dir;
X	ZOOFILE f;  
X	f = zooopen (this_path, Z_READ);
X	if (f == NOFILE)
X		return 0;
X	else {
X		dir = isadir(f);  zooclose(f);
X	}
X	return (dir);
X}
X#endif
END_OF_FILE
if test 6233 -ne `wc -c <'makelist.c'`; then
    echo shar: \"'makelist.c'\" unpacked with wrong size!
fi
# end of 'makelist.c'
fi
if test -f 'misc2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'misc2.c'\"
else
echo shar: Extracting \"'misc2.c'\" \(7457 characters\)
sed "s/^X//" >'misc2.c' <<'END_OF_FILE'
X#ifndef LINT
X/* @(#) misc2.c 2.7 88/01/24 12:47:36 */
Xstatic char sccsid[]="@(#) misc2.c 2.7 88/01/24 12:47:36";
X#endif /* LINT */
X
X/*
XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
X*/
X#include "options.h"
X/* Miscellaneous routines */
X#include "portable.h"
X#include "zooio.h"
X#include "various.h"
X#include "zoofns.h"     /* only for malloc */
X#include "errors.i"
X#include "zoomem.h"
X#include "zoo.h"
X
X#ifdef LINT_ARGS
Xint makepath (char *);
X#else
Xint makepath ();
X#endif
X
X
X/**********************/
X/* memerr() */
X/* Give error message on memory error and abort */
Xvoid memerr()
X{
X#ifdef OOZ
X   prterror ('f', no_memory, "", "");
X#else
X   prterror ('f', no_memory);
X#endif
X}
X
X/**********************/
X/*
Xemalloc() allocates memory like malloc() does, except that it automatically
Xcalls the error function memerr() if memory couldn't be allocated.  It also
Xassumes (unless small memory allocation is being done) that memory will
Xnever be freed and conserves it by allocating memory in large chunks
Xand then partitioning it out with no administrative overhead.
X*/
X
Xchar *emalloc (size)
Xunsigned int size;
X{
X#define  BLOCK_SIZE  512      /* memory allocation granularity */
X
X#ifdef USE_MALLOC
X/* Pass on memory requests to malloc() */
X   char *ptr;
X   if ((ptr = malloc (size)) == NULL)
X      memerr();
X   return (ptr);
X#else
X   static char *memptr;
X   static unsigned avail = 0;
X   unsigned malloc_incr;
X   char *retval;
X
X   if (size == 0)
X      return (NULL);
X
X   /* if not enough space avail get some more */
X   if (avail < size) {
X      malloc_incr = BLOCK_SIZE;
X      if (malloc_incr < size)
X         malloc_incr = size;
X      while (malloc_incr >= size && (memptr = malloc (malloc_incr)) == NULL)
X         malloc_incr = (malloc_incr / 6) * 5;
X      avail = malloc_incr;
X   }
X
X   if (avail < size)
X      memerr();                              /* no return from this */
X   retval = memptr;
X   memptr += size;
X   avail -= size;
X   return (retval);
X#endif  /* end of not USE_MALLOC */
X}
X
X/**********************/
X/* putstr()
XThis function prints a string to standard output.  If the received
Xstring pointer is NULL, it is handled safely.  This function is here
Xfor historical reasons:  Ooz was once coded to not use printf under
XMSDOS to save space, and at that time putstr() printed a string
Xwithout using printf.  It should eventually be eliminated and all
Xcalls to it replaced with calls to printf directly.
X*/
Xputstr (str)
Xregister char *str;
X{
X   if (str == NULL)
X      return;
X	printf ("%s", str);
X}
X
X/**********************/
X/* exists()
XThis function checks the existence of a file.  
X
XIf the symbol EXISTS is defined, that is called as a macro and
Xsupplied the filename.  It must return 1 if the file exists and
X0 if it does not.
X
XIf EXISTS is not defined, exists() tests to see if the file can be 
Xopened for reading or writing;  if so, it returns 1 else it returns 0. 
X
XBecause of the delay between the time existence is checked and the time Zoo
Xcreates a files, a race condition exists.  It would be better to
Xuse open() with the O_EXCL flag but that will not work for many
Xsystems.
X*/
X
Xint exists (fname)
Xchar *fname;
X{
X#ifdef EXISTS
X	return EXISTS(fname);
X#else
X   ZOOFILE f;
X
X   if ( (f = zooopen (fname, Z_READ )) != NOFILE ||
X		  (f = zooopen (fname, Z_WRITE)) != NOFILE ) {
X      zooclose (f);
X      return (1);
X   } else
X      return (0);
X#endif /* ifdef EXISTS */
X}
X
X/****************
Xnewcat() allocates enough space to concatenate two strings then returns
Xa pointer to the concatenated result */
X
Xchar *newcat (r, s)
Xchar *r, *s;
X{
X   char *temp = emalloc (strlen (r) + strlen (s) + 2); /* 1 spare */
X   strcpy (temp, r);
X   strcat (temp, s);
X   return (temp);
X}
X
X
X/* Creates a path */
Xint makepath(path)
Xchar *path;
X{
X   char tmppath[PATHSIZE];
X   char *slashpos;
X   if (path == NULL)
X      return;
X   while (*lastptr(path) == *PATH_CH)     /* remove trailing slashes */
X      *lastptr(path) = '\0';
X   if (*path == '\0')
X      return;
X
X   slashpos = findlast(path, PATH_CH);    /* find last slash */
X   if (slashpos == NULL) {                /* if not, just create dir. */
X      MKDIR(path);
X      return;
X   } else {                               /* otherwise...         */
X      if (slashpos == path) {             /* if leading slash */
X         MKDIR(slashpos);                 /* make that directory */
X         return;                          /* and done */
X      } else {
X         strcpy(tmppath,path);            /* save path */
X         *slashpos = '\0';                /* split into prefix & suffix */
X#ifdef DEBUG
X         printf("making path from [%s]\n", path);
X#endif
X         makepath(path);                     /* make path from prefix */
X#ifdef DEBUG
X         printf("making dir from [%s]\n", tmppath);
X#endif
X         MKDIR(tmppath);                  /* make dir from suffix */
X      }
X   }
X} /* makepath() */
X
X/*
XIf no extension in filename add supplied extension
X*/
Xchar *addext (fname, ext)
Xchar *fname;
Xchar *ext;
X{
X   if (strchr (nameptr (fname), EXT_CH) == NULL)
X      return (newcat (fname, ext));
X   else
X      return (fname);
X}
X
X#ifdef VER_CH       /* remove any trailing extension field */
Xchar *strip_ver (fname)
Xchar *fname;
X{
X   char *p = strchr (fname, VER_CH);
X   if (p != NULL)
X      *p = '\0';
X}
X#endif
X
X/*
XFunction samefile() compares two filenames to see if they are the
Xsame file.  Just strcmp() or strcmpi() could have been used, except
Xthat if the filenames have trailing version fields, we want to
Xcompare those always equal.  samefile() is called by routines
Xthat want to avoid adding an archive to itself.
X*/
Xint samefile (f1, f2)
Xchar *f1;
Xchar *f2;
X{
X#ifdef IGNORECASE
X#define COMPARE strcmpi
X#else
X#define COMPARE strcmp
X#endif
X
X#ifdef VER_CH
X   char tf1[LFNAMESIZE];
X   char tf2[LFNAMESIZE];
X   strcpy (tf1, f1);
X   strcpy (tf2, f2);
X   strip_ver (tf1);   /* strip version fields */
X   strip_ver (tf2);
X   return (COMPARE (tf1, tf2) == 0);
X#else
X/* if no version fields, just use strcmp(i) */
X   return (COMPARE (f1, f2) == 0);
X#endif
X}
X
X#ifdef USE_ASCII
Xint isdigit (c)
Xchar c;
X{
X	return (c >= '0' && c <= '9');
X}
Xint isupper (c)
Xchar c;
X{
X	return (c >= 'A' && c <= 'Z');
X}
X
Xint toascii (c)
Xchar c;
X{
X	return (c & 0x7f);
X}
X
Xint tolower (c)
Xchar c;
X{
X	return (isupper(c) ? (c | 0x20) : c);
X}
X#endif
X
X#ifdef GETTZ
X/****************
XFunction tzadj() accepts a directory entry and adjusts its timestamp
Xto reflect its timezone.  Uses function mstime() from mstime.i
Xand mstonix() from nixtime.i.
X*/
X
Xlong mstonix();
Xlong gettz();
X#include "mstime.i"	/* get mstime() */
X
Xvoid tzadj (direntry)
Xstruct direntry *direntry;
X{
X	long diff_tz;
X	long longtime;
X	if (direntry->tz == NO_TZ)		/* none stored */
X		return;
X	diff_tz = (long) direntry->tz * (3600/4) - gettz(); /* diff. in seconds */
X	longtime = mstonix (direntry->date, direntry->time) + diff_tz; /* adj tz */
X	mstime (longtime, &direntry->date, &direntry->time);
X}
X#endif /* GETTZ */
X
X/* how long an int can be in text form -- allow 64-bit ints */
X#define INT_TEXT 21
X
X/* Function add_version adds a version suffix to a filename, given
Xthe directory entry corresponding to the file */
Xvoid add_version (fname, direntry)
Xchar *fname;
Xstruct direntry *direntry;
X{
X	char verstr[INT_TEXT];	/* string buffer for conversion to text */
X	if (direntry->vflag & VFL_ON) {
X		sprintf (verstr, "%u", direntry->version_no);
X		strcat (fname, VER_DISPLAY);
X		strcat (fname, verstr);
X	}
X}
END_OF_FILE
if test 7457 -ne `wc -c <'misc2.c'`; then
    echo shar: \"'misc2.c'\" unpacked with wrong size!
fi
# end of 'misc2.c'
fi
if test -f 'parse.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'parse.c'\"
else
echo shar: Extracting \"'parse.c'\" \(5640 characters\)
sed "s/^X//" >'parse.c' <<'END_OF_FILE'
X#ifndef LINT
Xstatic char sccsid[]="@(#) parse.c 2.1 87/12/25 12:24:10";
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
X#include "options.h"
X#include "zoo.h"
X#include "zooio.h"
X#include "various.h"
X#include "zoofns.h"
X
X#include "parse.h"
X#include "assert.h"
X
X/*
Xparse() accepts a filename and return its component parts in a structure.
XThe component parts are:  disk drive, path prefix, root name of filename, 
Xand extension.  
X
XIf DISK_CH is not defined, it is assumed that filenames may be
Xpreceded with a disk prefix terminated by the character DISK_CH.
XThe first character of the disk prefix, followed by DISK_CH,
Xis returned in the drive field.
X
XIf the symbol DISK_CH is defined, a null string is returned in the
Xdisk field.
X*/
Xvoid parse (path_st, fname)
Xregister struct path_st *path_st;
Xchar *fname;
X{
X   char tempname[LFNAMESIZE];       /* working copy of supplied fname */
X   char *namep;                   /* points to relevant part of tempname */
X
X   char *p;
X   strcpy (tempname, fname);
X
X#ifdef DEBUG
Xprintf ("parse:  supplied name is [%s].\n", tempname);
X#endif
X
X#ifndef DISK_CH
X   path_st->drive[0] = '\0';
X   namep = tempname;           /* points to pathname+filename */
X#else
X   path_st->drive[0] = '\0';
X   p = strchr (tempname, DISK_CH);      /* point to first ':' */
X
X   if (p != NULL) {
X      path_st->drive[0] = *tempname;/* use only first char of drive name */
X      path_st->drive[1] = DISK_CH;
X      path_st->drive[2] = '\0';
X      namep = ++p;                /* point to pathname+filename */
X   } else {
X      path_st->drive[0] = '\0';
X      namep = tempname;           /* points to pathname+filename */
X   }
X#endif /* end of not DISK_CH */
X   
X   /* Note:  findlast() finds last occurrence in the subject string of 
X      any one of a set of chars */
X
X   /* save the long filename */
X   p = findlast (namep, PATH_SEP);
X
X   /* if path separator found, copy next char onwards; else entire string */
X   strncpy (path_st->lfname,
X               (p != NULL) ? p+1 : namep,
X               LFNAMESIZE);
X   path_st->lfname[LFNAMESIZE-1] = '\0';     /* force null termination */
X
X#ifdef DEBUG
Xprintf ("parse:  path = [%s] long filename = [%s]\n", 
X         namep, path_st->lfname);
X#endif
X
X/* Separate out the extension */
Xp = findlast (namep, EXT_SEP);						/* look for . or /		*/
Xif (p != NULL && *p != EXT_CH)						/* found .?					*/
X	p = NULL;												/* ... if not, ignore / */
X
X#ifdef DEBUG
Xif (p == NULL)
X   printf ("parse:  no extension found for [%s]\n", namep);
Xelse
X   printf ("parse:  extension for [%s] is [%s]\n", namep, p);
X#endif
X   
X   path_st->ext[0] = '\0';                      /* assume no extension  */
X   if (p != NULL) {                             /* found extension      */
X      strncpy (path_st->ext, (p+1), EXTLEN);    /* save extension       */
X      path_st->ext[EXTLEN] = '\0';              /* force termination    */
X      *p = '\0';                                /* null out extension   */
X   }
X
X   /* separate out root of filename if any */
X   p = findlast (namep, PATH_SEP);
X
X   if (p != NULL) {
X      ++p;
X      strncpy (path_st->fname, p, ROOTSIZE);  /* save filename        */
X      *p = '\0';               /* null out filename */
X   } else {
X      strncpy (path_st->fname, namep, ROOTSIZE);
X      *namep = '\0';                   /* null out filename    */
X   }
X   path_st->fname[ROOTSIZE] = '\0';           /* force termination    */
X
X   /* what remains, whether null or not, is the path prefix */
X   path_st->dir[0] = '\0';             /* in case *namep is '\0' */
X
X   strncpy (path_st->dir, namep, PATHSIZE);
X
X   /* remove trailing path-separater from directory name, but don't
X      remove it if it is also the leading separater */
X   { 
X      int n;
X      n = strlen(path_st->dir);
X      if (n != 1)
X         path_st->dir[n-1] = '\0';
X   }
X
X#ifdef DEBUG
Xprintf ("parse:  path prefix = [%s].\n", namep);
X#endif
X   /* if extension is null, and if long filename contains more than
X      ROOTSIZE  characters, transfer some of them to extension */
X   if (path_st->ext[0] == '\0' && strlen(path_st->lfname) > ROOTSIZE) {
X      strncpy(path_st->ext, &path_st->lfname[ROOTSIZE], EXTLEN);
X      path_st->ext[3] = '\0';
X   }
X}
X
X/*******************/
X/* 
Xfindlast() finds last occurrence in provided string of any of the characters
Xexcept the null character in the provided set.
X
XIf found, return value is pointer to character found, else it is NULL.
X*/
X
Xchar *findlast (str, set)
Xregister char *str;        /* subject string     */
Xchar *set;                 /* set of characters to look for */
X
X{
X   register char *p;
X
X   if (str == NULL || set == NULL || *str == '\0' || *set == '\0')
X      return (NULL);
X
X   p = lastptr (str);   /* pointer to last char of string */
X   assert(p != NULL);
X
X   while (p != str && strchr (set, *p) == NULL) {
X      --p;
X   }                 
X
X   /* either p == str or we found a character or both */
X   if (strchr (set, *p) == NULL)
X      return (NULL);
X   else
X      return (p);
X}
X
X/*******************/
X/*
Xlastptr() returns a pointer to the last non-null character in the string, if
Xany.  If the string is null it returns NULL
X*/
X
Xchar *lastptr (str)
Xregister char *str;                 /* string in which to find last char */
X{
X   register char *p;
X   if (str == NULL)
X      prterror ('f', "lastptr:  received null pointer\n");
X   if (*str == '\0')
X      return (NULL);
X   p = str;
X   while (*p != '\0')            /* find trailing null char */
X      ++p;
X   --p;                          /* point to just before it */
X   return (p);
X}
END_OF_FILE
if test 5640 -ne `wc -c <'parse.c'`; then
    echo shar: \"'parse.c'\" unpacked with wrong size!
fi
# end of 'parse.c'
fi
if test -f 'prterror.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'prterror.c'\"
else
echo shar: Extracting \"'prterror.c'\" \(5399 characters\)
sed "s/^X//" >'prterror.c' <<'END_OF_FILE'
X#ifndef LINT
X/* @(#) prterror.c 2.8 88/01/31 18:48:17 */
Xstatic char sccsid[]="@(#) prterror.c 2.8 88/01/31 18:48:17";
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#ifndef	OK_STDIO
X#include <stdio.h>
X#define	OK_STDIO
X#endif
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 used
X	as follows.  Warning messages are suppressed if quiet > 1;  error
X	messages are suppressed if quiet > 2.  Fatal error messages are 
X	never suppressed--doing so would be a bit risky.
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
X   (a) printf() is always supplied parameters 3 through 6, even if they 
X	were not on the parameter list passed to prterror().  It is assumed 
X	that printf() will only use as many as are specified by the format 
X	string.  There is a small chance that on some machines, this will cause 
X	some kind of stack exception (e.g. if the hardware maintains tag 
X	bits in each word on the stack and doesn't allow certain types of 
X	data to be arbitrarily accessed).  This is just a theory so far.
X
X	(b) Parameter passing relies on consecutive small parameters being
X	properly interpreted as a single larger parameter when needed.
X	Eventually var_args should be used, but not all systems probably
X	have it at the moment.
X
X	(c) All messages, whether informative or error, are sent to standard
X	output via printf.  It might be a good idea to eventually send 'e' and
X	'f' class messages to the standard error stream.  Best would be
X	some way of telling if standard output and standard error are not
X	the same device, so that we could always send error messages to
X	standard error, and also duplicate them to standard output if 
X	different from standard error.  There seems to be no way
X	of doing this in the general case.
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";
Xchar packfirst[] = "Old format archive -- please pack first with P command.\n";
Xchar garbled[] = "Command is garbled.\n";
Xchar start_ofs[] = "Starting at %ld (offset %ld)\n";
X
X#ifndef OOZ
Xchar wrong_version[]=
X   "Zoo %d.%d or later is needed to fully manipulate 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#ifdef LINT_ARGS
X/* defined in zoofns.h but we don't want to include that and waste time */
Xvoid prterror (int, char *, MORE);
Xvoid zooexit (int);
X#endif
X
X
X/*VARARGS2*/
Xvoid prterror(level, format, a, b, c, d)
Xregister int level;
Xchar *format, *a, *b, *c, *d;
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': 
X			if (quiet > 1) return;
X			strcat (string, "WARNING:  "); break;
X      case 'e': 
X			if (quiet > 2) return;
X			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   printf (string, a, b, c, d);   /* and print the whole thing */
X	fflush (stdout);
X
X   if (level == 'f')       /* and abort on fatal error 'f' but not 'F' */
X      zooexit (1);
X}
END_OF_FILE
if test 5399 -ne `wc -c <'prterror.c'`; then
    echo shar: \"'prterror.c'\" unpacked with wrong size!
fi
# end of 'prterror.c'
fi
echo shar: End of archive 3 \(of 10\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 10 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.