[comp.sources.unix] v17i071: Zoo archive program, Part08/10

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

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

#! /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 8 (of 10)."
# Wrapped by rsalz@papaya.bbn.com on Thu Feb  2 18:04:04 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'portable.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'portable.c'\"
else
echo shar: Extracting \"'portable.c'\" \(21282 characters\)
sed "s/^X//" >'portable.c' <<'END_OF_FILE'
X#ifndef LINT
X/* @(#) portable.c 2.24 88/08/24 01:22:06 */
Xstatic char sccsid[]="@(#) portable.c 2.24 88/08/24 01:22:06";
X#endif /* LINT */
X
X#include "options.h"
X/*
XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
X(C) Copyright 1988 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#include "zooio.h"
X
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#include "portable.h"
X
X#ifdef TRACE_IO
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
X#ifdef TRACE_IO
Xvoid show_h PARMS ((struct zoo_header *));
Xvoid show_dir PARMS ((struct direntry *));
X#endif /* TRACE_IO */
X
Xextern unsigned int crccode;
X
X/************************************************************************/
X/* I/O functions */
X/************************************************************************/
X
X/* some functions get defined only if they aren't already macros */
X
X#ifndef zooread
Xint zooread (file, buffer, count)
XZOOFILE file; char *buffer; int count;
X{ return (fread (buffer, 1, count, file)); }
X#endif /* zooread */
X
X#ifndef FIZ
X#ifndef zoowrite
Xint zoowrite (file, buffer, count)
XZOOFILE file; char *buffer; int count;
X{ 
X	if (file == NULLFILE)
X	   return (count);
X	else
X		return (fwrite (buffer, 1, count, file)); 
X}
X#endif /* zoowrite */
X
XZOOFILE zoocreate (fname)
Xchar *fname;
X{ return ((ZOOFILE) fopen (fname, Z_NEW)); }
X
X/* truncates a file -- can be empty */
X/* force use of argument to keep Turbo C happy */
Xint zootrunc (file) ZOOFILE file; {return ((int) file); }
X#endif /* FIZ */
X
X#ifndef zooseek
Xlong zooseek (file, offset, whence)
XZOOFILE file; long offset; int whence;
X{ return (fseek (file, offset, whence)); }
X#endif /* zooseek */
X
XZOOFILE zooopen (fname, option)
Xchar *fname; char *option;
X{ return ((ZOOFILE) fopen (fname, option)); }
X
X#ifndef zootell
Xlong zootell (file)
XZOOFILE file;
X{ return ftell (file); }
X#endif /* zootell */
X
Xint zooclose (file)
XZOOFILE file;
X{ return fclose (file); }
X
X/************************************************************************/
X/*** Following are functions that make up for various implementations ***/
X/*** of C not having certain library routines.                        ***/
X/************************************************************************/
X
X#ifndef FIZ
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   return (dest);
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#endif /* FIZ */
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 TURBOC
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#ifndef FIZ
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#endif /* FIZ */
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 TURBOC */
X
Xlong to_long(data)
XBYTE data[];
X{
X   return ( * (long *) data );
X}
X
X#ifndef FIZ
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#endif /* FIZ */
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 TURBOC .. else ... */
X
X#ifndef FIZ
X/**********************
XFunction frd_zooh() reads the header of a Zoo archive in a machine-
Xindependent manner, from a ZOOFILE.
X*/
Xint frd_zooh(zoo_header, zoo_file)
Xstruct zoo_header *zoo_header;
XZOOFILE zoo_file;
X{
X   int status;
X   BYTE bytes[SIZ_ZOOH];         /* canonical header representation */
X#ifdef TRACE_IO
X   if (verbose) {
X      printf("At file position [%8lx] ", ftell(zoo_file));
X   }
X#endif
X   status = zooread (zoo_file, (char *) bytes, SIZ_ZOOH);
X   b_to_zooh (zoo_header, bytes);   /* convert array to structure */
X#ifdef TRACE_IO
X   if (verbose) {
X      printf("frd_zooh: reading\n");
X      show_h(zoo_header);
X   }
X#endif
X   if (status < MINZOOHSIZ)
X      return (-1);
X   else
X      return (0);
X}
X#endif /* FIZ */
X
X/**********************
XFunction frd_dir() reads a directory entry in a machine-independent manner,
Xfrom a ZOOFILE.
X*/
Xint frd_dir(direntry, zoo_file) 
Xstruct direntry *direntry; 
XZOOFILE 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 TRACE_IO
X   if (verbose) {
X      printf("At file position [%8lx] ", ftell(zoo_file));
X   }
X#endif
X   status = zooread (zoo_file, (char *) bytes, MAXDIRSIZE);
X   if (status < SIZ_DIR)
X      return (-1);
X   b_to_dir (direntry, bytes);
X#ifdef TRACE_IO
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 fwr_dir() writes a directory entry in a machine-independent manner
Xto a ZOOFILE.  Return value is -1 on error, else 0.
X*/
Xint fwr_dir(direntry, zoo_file)
Xstruct direntry *direntry;
XZOOFILE zoo_file;
X{
X   int size;
X   BYTE bytes[MAXDIRSIZE];
X   assert (direntry->type <= 2);
X   size = dir_to_b (bytes, direntry);
X#ifdef TRACE_IO
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 (zoowrite (zoo_file, (char *) bytes, size) != size)
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 ZOOFILE.  Return value is -1 if error else 0.
X*/
Xint fwr_zooh(zoo_header, zoo_file)
Xstruct zoo_header *zoo_header;
XZOOFILE zoo_file;
X{
X   BYTE bytes[SIZ_ZOOH];	/* was SIZ_DIR -- probably a typo */
X	int hsize;					/* how much to write -- depends on header type */
X	hsize = MINZOOHSIZ;				/* in case it's an old type 0 header */
X	if (zoo_header->type > 0)		/* but if it's a newer header... */
X		hsize = SIZ_ZOOH;				/* ...size of new type 1 header */
X   zooh_to_b (bytes, zoo_header);
X   if (zoowrite (zoo_file, (char *) bytes, hsize) != hsize)
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	/* default is no archive comment and a header type of 0 */
X	zoo_header->type = 0;
X	zoo_header->acmt_pos = 0L;
X	zoo_header->acmt_len = 0;
X	zoo_header->vdata		= 0;
X	if (zoo_header->zoo_start != FIXED_OFFSET) {			/* if newer header */
X		zoo_header->type = bytes[HTYPE_I];
X		zoo_header->acmt_pos = to_long(&bytes[ACMTPOS_I]);
X		zoo_header->acmt_len = to_int(&bytes[ACMTLEN_I]);
X		zoo_header->vdata		= bytes[HVDATA_I];
X	}
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	bytes[HTYPE_I] =	zoo_header->type;						/* header type */
X	if (zoo_header->type > 0) {
X		splitlong (&bytes[ACMTPOS_I], zoo_header->acmt_pos);	/* comment posn */
X		splitint (&bytes[ACMTLEN_I], zoo_header->acmt_len);	/* comment len */
X		bytes[HVDATA_I] = zoo_header->vdata;					/* version data */
X	}
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	int totalsize;
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		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		/* Can't store system id if no namlen & dirlen...BUG!...now fixed.
X			Fortunately, system_id was always 0 so far so it probably
X			got interpreted as namlen=0 and dirlen=0 (2 bytes) */
X      splitint(&bytes[cursize], direntry->system_id);
X		cursize += 2;
X		bytes[cursize] = direntry->fattr & 0xff;		  					/* byte 0 */
X		splitint(&bytes[cursize+1], (int) (direntry->fattr >> 8));  /* 1 & 2 */
X		cursize += 3;
X		bytes[cursize] = (direntry->vflag & 0xff);			/* version flag */
X		splitint(&bytes[cursize+1], direntry->version_no);	/* version number */
X		cursize += 3;
X   }
X
X   splitint(&bytes[VARDIRLEN_I], direntry->var_dir_len);
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	/* total size of dir entry is size of fixed part + size of var. part */
X	totalsize = fixsize + direntry->var_dir_len;
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   /* avoid mixing pointers to signed and unsigned char */
X   addbfcrc((char *) bytes, totalsize); 		/* update CRC */
X   splitint(&bytes[DCRC_I], crccode);
X
X   /* return total length of directory entry */
X   return (totalsize);
X
X} /* dir_to_b() */
X#endif /* 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	int sysid_offs;			/* temp variable */
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 now, versions not implemented */
X	direntry->vflag = 0;
X	direntry->version_no = 0;
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	direntry->fattr = NO_FATTR;			/* assume none */
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		sysid_offs = DIRNAME_I + direntry->namlen + i;	/* offset of system id */
X		if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 2) {
X			direntry->system_id = to_int(&bytes[sysid_offs]);
X		}
X		if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 4) {
X			direntry->fattr = ((unsigned long) bytes[sysid_offs + 2]) |
X									((unsigned long) bytes[sysid_offs + 3] << 8) |
X									((unsigned long) bytes[sysid_offs + 4] << 16);
X		}
X		if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 7) {
X			direntry->vflag = bytes[sysid_offs + 5];
X			direntry->version_no = to_int(&bytes[sysid_offs + 6]);
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((char *) bytes, SIZ_DIRL + direntry->var_dir_len);
X      direntry->dir_crc = crccode - savecrc;
X   }
X}
X
X#ifdef FILTER
X#define TWOBYTES	2	/* better than literal 2;  figure out why */
X
X/* rdint() reads two bytes from standard input in archive order */
Xint rdint (val)
Xunsigned int *val;
X{
X	BYTE bytes[TWOBYTES];
X	if (zooread (STDIN, bytes, TWOBYTES) == TWOBYTES) {
X		*val = to_int(bytes);
X		return (0);
X	} else
X		return (1);
X}
X
X/* wrint() writes an unsigned int to standard output in archive order */
Xint wrint (val)
Xunsigned int val;
X{
X	BYTE bytes[TWOBYTES];
X	splitint (bytes, val);
X	if (zoowrite (STDOUT, bytes, TWOBYTES) == TWOBYTES)
X		return (0);
X	else
X		return (1);
X}
X#endif /* FILTER */
X
X#ifdef TRACE_IO
X/* dump contents of archive header */
Xvoid show_h (zoo_header)
Xstruct zoo_header *zoo_header;
X{
X   int i;
X   printf ("Header text:\n");
X   for (i = 0; i < SIZ_TEXT;  i++) {      /* ASSUMES ASCII TEXT */
X      int c;
X      c = zoo_header->text[i];
X      if (c >= ' ' && c < 0x7f)
X         putchar (c);
X      else {
X         putchar ('^');
X         putchar (i & 0x40);
X      }
X   }
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	if (zoo_header->zoo_start != FIXED_OFFSET) {
X		printf ("type = [%d] ", zoo_header->type);
X		printf ("acmt_pos = [%8lx] acmt_len = [%4x] vdata = [%2x]",
X					zoo_header->acmt_pos, zoo_header->acmt_len, zoo_header->vdata);
X		printf ("\n");
X	}
X   printf ("---------\n");
X}
X
X/* dump contents of directory entry */
Xvoid show_dir (direntry)
Xstruct direntry *direntry;
X{
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] fattr=[%24lx]\n", 
X		direntry->system_id, direntry->dirlen, direntry->namlen, direntry->fattr);
X	printf ("vflag = [%4x] version_no = [%4x]\n",
X				direntry->vflag, direntry->version_no);
X   if (direntry->dirlen > 0)
X      printf ("dirname = [%s]\n", direntry->dirname);
X   printf ("---------\n");
X}
X#endif   /* TRACE_IO */
END_OF_FILE
if test 21282 -ne `wc -c <'portable.c'`; then
    echo shar: \"'portable.c'\" unpacked with wrong size!
fi
# end of 'portable.c'
fi
if test -f 'zooext.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'zooext.c'\"
else
echo shar: Extracting \"'zooext.c'\" \(21819 characters\)
sed "s/^X//" >'zooext.c' <<'END_OF_FILE'
X#ifndef LINT
X/* @(#) zooext.c 2.21 88/08/24 02:39:04 */
Xstatic char sccsid[]="@(#) zooext.c 2.21 88/08/24 02:39:04";
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/* Extract file from archive.  Extracts files specified in parameter-list
X   from archive zoo_path.  If none specified, extracts all files from
X   archive. */
X
X#include "zoo.h"
X#include "parse.h"      /* defines struct for parse() */
X
X#include "portable.h"   /* portable I/O definitions */
X#include "machine.h"    /* machine-specific declarations */
X
X#include "zooio.h"
X#include "various.h"
X
X#ifndef NOSIGNAL
X#include <signal.h>
X#endif
X
X#include "zoofns.h"
X
X#ifdef LINT_ARGS
Xint makepath (char *);
Xint needed (char *, struct direntry *, struct zoo_header *);
Xvoid putstr (char *);
X#else
Xint needed ();
Xint makepath ();
Xvoid putstr ();
X#endif
X
X#ifdef FATTR
Xint setfattr PARMS ((char *, unsigned long));
X#endif /* FATTR */
X
Xextern int quiet;
X
X#include "errors.i"
X
X/* Following two are used by ctrl_c() also, hence declared here */
Xchar extfname[LFNAMESIZE];             /* filename of extracted file */
Xchar prtfname[LFNAMESIZE];             /* name of extracted file on screen */
Xstatic ZOOFILE this_file;              /* file to extract */
X
Xstatic int tofile;                     /* true if not pipe or null device */
Xextern unsigned int crccode;
Xextern char *out_buf_adr;              /* address of output buffer */
X
Xvoid zooext(zoo_path, option)
Xchar *zoo_path, *option;
X{
Xchar *whichname;                          /* which name to extract */
Xchar matchname[PATHSIZE];                 /* for pattern matching only */
X#ifndef NOSIGNAL
Xint (*oldsignal)();        /* to save previous SIGINT handler */
X#endif
XZOOFILE zoo_file;                         /* open archive */
Xlong next_ptr;                            /* pointer to within archive */
Xstruct zoo_header zoo_header;             /* header for archive */
Xint status;                               /* error status */
Xint exit_status = 0;								/* exit status */
Xint error_message;								/* Whether to give error message */
Xunsigned long disk_space;                 /* disk space left */
Xint matched = 0;                          /* Any files matched? */
Xint overwrite = 0;                        /* force overwrite of files? */
Xint supersede = 0;								/* supersede newer files? */
Xint needdel = 0;                          /* extract deleted files too */
Xint usepath = 0;                          /* use path for extraction */
Xint todot = 0;                            /* extract relative to . */
Xint badcrc_count = 0;                     /* how many files with bad CRC */
Xint bad_header = 0;                       /* to avoid spurious messages later */
Xlong fiz_ofs = 0;                         /* offset where to start */
Xlong dat_ofs = 0;									/* .. and offset of file data */
Xint pipe = 0;                             /* are we piping output? */
Xint null_device = 0;                      /* are we sending to null device? */
X#ifndef PORTABLE
Xint fast_ext = 0;                         /* fast extract as *.?Z? */
Xint alloc_size;                           /* disk allocation unit size */
X#endif
Xstruct direntry direntry;                 /* directory entry */
Xint first_dir = 1;								/* first dir entry seen? */
X
Xstatic char extract_ver[] = "Zoo %d.%d is needed to extract %s.\n";
Xstatic char no_space[] = "Insufficient disk space to extract %s.\n";
X
Xwhile (*option) {
X   switch (*option) {
X#ifndef PORTABLE
X      case 'z': fast_ext++; break;
X#endif
X      case 'x':
X      case 'e': break;
X      case 'N': null_device++; break;
X      case 'O': overwrite += 2; break;
X      case 'o': overwrite++; break;
X      case 'p': pipe++; break;
X		case 'S': supersede++; break;
X      case 'd': needdel++; break;
X      case 'q': quiet++; break;
X      case '/': usepath++; break;
X      case '.': todot++; break;
X      case '@': 	/* if @m,n specified, fiz_ofs = m, dat_ofs = n */
X			{
X				char *comma_pos;
X				++option;
X				comma_pos = strchr(option, ',');
X				if (comma_pos != NULL) {
X					dat_ofs = calc_ofs (comma_pos + 1);
X					*comma_pos = '\0';
X				}
X				fiz_ofs = calc_ofs(option); 
X				goto no_more;
X			}
X      default:
X         prterror ('f', inv_option, *option);
X         /* break; */
X   }
X   option++;
X}
X
Xno_more: /* come from exit in while loop above */
X
X
Xif (overwrite == 1)                 /* must be at least 2 to begin with */
X   overwrite--;
X
Xif (null_device && pipe) {
X   prterror ('f', inv_option, 'p');
X   pipe = 0;
X}
X
Xif (overwrite && pipe)
X   prterror ('w', option_ignored, 'O');
X
X#ifndef PORTABLE
Xif (null_device && fast_ext) {
X   prterror ('w', inv_option, 'N');
X   null_device = 0;
X}
X#endif
X
Xtofile = !pipe && !null_device;     /* sending to actual file */
X
Xzoo_file = zooopen(zoo_path, Z_READ);
X
Xif (zoo_file == NOFILE)
X   prterror ('f', could_not_open, zoo_path);
X
Xif (fiz_ofs != 0L) {                /* if offset specified, start there */
X	prterror ('m', start_ofs, fiz_ofs, dat_ofs);
X   zooseek (zoo_file, fiz_ofs, 0);
X} else {
X   /* read header */
X   frd_zooh (&zoo_header, zoo_file);
X   if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L) {
X      prterror ('w', failed_consistency);
X      bad_header++;
X		exit_status = 1;
X   }
X   zooseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */
X}
X
X#ifndef PORTABLE
Xdisk_space = space (0, &alloc_size);         /* remember disk space left */
X#else
Xdisk_space = MAXLONG;              /* infinite disk space */
X#endif
X
X/* if piping output we open the output device just once */
Xif (null_device) {
X   this_file = NULLFILE;
X} else if (pipe)
X   this_file = STDOUT;    /* standard output */
X
Xwhile (1) {
X   frd_dir (&direntry, zoo_file);
X   if (direntry.zoo_tag != ZOO_TAG) {
X      long currpos, zoolength;
X		prterror ('F', invalid_header);
X
X		/* Note:  if header was bad, there's no point trying to find
X			how many more bytes aren't processed -- our seek position is
X			likely very wrong */
X
X		if (!bad_header)
X			if ((currpos = zootell (zoo_file)) != -1L)
X				if (zooseek (zoo_file, 0L, 2) != -1)
X					if ((zoolength = zootell (zoo_file)) != -1L)
X						printf (cant_process, zoolength - currpos);              
X		zooexit (1);
X   }
X   if (direntry.next == 0L) {                /* END OF CHAIN */
X      break;                                 /* EXIT on end of chain */
X   }
X	/* when first direntry read, change dat_ofs from abs. pos. to rel. offset */
X	if (first_dir && dat_ofs != 0) {
X		dat_ofs -= direntry.offset;
X		first_dir = 0;
X	}
X   next_ptr = direntry.next + dat_ofs;       /* ptr to next dir entry */
X
X   whichname = choosefname(&direntry);       /* which filename */
X	whichname = strdup(whichname);				/* bug fix */
X   fixfname(whichname);                      /* fix syntax */
X	strcpy (matchname, fullpath (&direntry));	/* get full pathname */
X	if (zoo_header.vdata & VFL_ON)
X		add_version (matchname, &direntry);		/* add version suffix */
X
X/* if extraction to subtree rooted at curr dir, modify pathname */
X#if 0
X#ifdef DIR_LBRACK
X   if (todot && direntry.dirname[0] == *DIR_LBRACK &&
X                direntry.dirname[1] != *CUR_DIR)      {
X      char tmpstr[PATHSIZE];
X      strcpy (tmpstr, DIR_LBRACK);
X      strcat (tmpstr, CUR_DIR);
X      strcat (tmpstr, &direntry.dirname[1]);
X      strcpy (direntry.dirname, tmpstr);
X   }
X#endif
X#endif
X
X   /* hard-coded '/' should be eventually removed */
X   if (todot && *direntry.dirname == '/') { 
X      char tmpstr[PATHSIZE];
X      strcpy(tmpstr, direntry.dirname);
X      strcpy(direntry.dirname,CUR_DIR);
X      strcat(direntry.dirname, tmpstr);
X   }
X
X   /* matchname now holds the full pathname for pattern matching */
X
X   if ( ( (needdel && direntry.deleted) ||
X            (needdel < 2 && !direntry.deleted)
X        ) && needed(matchname, &direntry, &zoo_header)) {
X      matched++;           /* update count of files extracted */
X
X      if (direntry.major_ver > MAJOR_EXT_VER ||
X         (direntry.major_ver == MAJOR_EXT_VER && 
X            direntry.minor_ver > MINOR_EXT_VER)) {
X            prterror ('e', extract_ver, direntry.major_ver, 
X                           direntry.minor_ver, whichname);
X				exit_status = 1;
X            goto loop_again;
X      }
X
X      /* 
X      If extracting to null device, or if user requested extraction
X      of entire path, include any directory name in filename.
X      If extraction to current directory requested, and if extfname
X      begins with path separator, fix it */
X
X      strcpy (extfname, whichname);
X      if ((usepath || null_device) && direntry.dirlen != 0) {
X         combine(extfname, direntry.dirname, whichname);
X         if (usepath > 1 && !null_device)
X            makepath(direntry.dirname);         /* make dir prefix */
X      }
X
X		strcpy(prtfname, extfname);
X		if (zoo_header.vdata & VFL_ON)
X			add_version (prtfname, &direntry);
X
X      if (tofile) {
X         int present = 0;
X
X#ifndef PORTABLE
X         /* 
X         if Z format (fast) extraction, extension is created as
X         follows:  for no current extension, new extension is "zzz";
X         for current extension "a", new extension is "azz";  for 
X         current extension "ab", new extension is "azb";  and for
X         current extension "abc", new extension is "azc".
X         */
X           
X         if (fast_ext) {
X            int length;
X            struct path_st path_st;
X            parse (&path_st, extfname);         /* split filename */
X            strcpy (extfname, path_st.fname);   /* just root filename */
X            length = strlen (path_st.ext);
X            strcat (extfname, ".");
X            if (length == 0)
X               strcat (extfname, "zzz");        /* no ext -> .zzz */
X            else if (length == 1) {
X               strcat (extfname, path_st.ext);
X               strcat (extfname, "zz");         /* *.?    -> *.?zz */
X            } else { /* length is 2 or 3 */
X               if (length == 2)                 /* allow .aa, .ab, etc. */
X                  path_st.ext[2] = path_st.ext[1];
X               path_st.ext[1] = 'z';
X               strcat (extfname, path_st.ext);  /* *.??   -> *.?z? */
X            }
X				strcpy(prtfname, direntry.fname);
X				add_version (prtfname, &direntry);
X         }
X#endif   /* ifndef PORTABLE */
X
X			/* don't extract if archived file is older than disk copy */
X			if (!supersede && exists(extfname)) {
X				unsigned int ddate, dtime;
X#ifdef GETUTIME
X				getutime (extfname, &ddate, &dtime);
X#else
X				ZOOFILE tfile;
X				ddate = dtime = 0xffff;					/* assume maximum */
X				tfile = zooopen(extfname, Z_READ);
X				if (tfile == NOFILE)
X					goto loop_again;
X				gettime (tfile, &ddate, &dtime);
X				zooclose (tfile);
X#endif
X				if (cmpnum (direntry.date, direntry.time, ddate, dtime) <= 0) {
X					prterror ('m', "%-14s -- skipped\n", prtfname);
X					goto loop_again;
X				}
X			}
X
X         if (overwrite) {
X            this_file = zoocreate (extfname);
X#ifdef FATTR
X				/* if can't open file, and OO option, make it writable first */
X				if (this_file == NOFILE && overwrite >= 4 && 
X						(direntry.fattr >> 22) == 1 && exists(extfname)) {
X					setfattr (extfname, (unsigned long) (1L << 7) | direntry.fattr);
X					this_file = zoocreate (extfname);
X				}
X#endif /* FATTR */
X         } else {
X            if (exists (extfname)) {
X               present = 1;
X               this_file = NOFILE;
X            } else
X               this_file = zoocreate (extfname);
X         }
X			error_message = 1;
X         if (this_file == NOFILE) {
X            if (present == 1) {      /* if file exists already */
X					char ans[20];          /* answer to "Overwrite?" */
X               do {
X#ifdef EXT_ANYWAY
X                  printf ("%s exists; extract anyway? [Yes/No/All] ",
X                           extfname);
X#else
X                  printf ("Overwrite %s (Yes/No/All)? ", extfname);
X#endif
X                  fflush (stdin);
X                  fgets (ans, sizeof(ans), stdin);
X                  strlwr (ans);
X               } while (*ans != 'y' && *ans != 'n' && *ans != 'a');
X   
X               if (*ans == 'a')
X                  overwrite++;
X               if (*ans == 'y' || *ans == 'a') {
X                  this_file = zoocreate(extfname);
X                  error_message = 1; /* give error message if open fails */
X               } else {
X                  error_message = 0; /* user said 'n', so no error message */
X               }
X            } else {
X               error_message = 1;   /* Real error -- give error message */
X            }
X         } /* end if */
X      } /* end if */
X
X      if (this_file == NOFILE) {         /* file couldn't be opened */
X         if (error_message == 1) {
X            prterror ('e', "Can't open %s for output.\n", extfname);
X				exit_status = 1;
X
X#ifndef PORTABLE
X            /* if error was due to full disk, abort */
X            if (space(0, &alloc_size) < alloc_size)
X               prterror ('f', disk_full);
X#endif
X
X         }
X      } else if (zooseek (zoo_file, (direntry.offset + dat_ofs), 0) == -1L) {
X         prterror ('e', "Could not seek to file data.\n");
X			exit_status = 1;
X         close_file (this_file);
X      } else {
X#ifndef PORTABLE
X         /* check msdos's free disk space if we seem to be running low 
X            (within 1 cluster of being full) */
X         if (tofile && disk_space < direntry.org_size + alloc_size) {
X            disk_space = space (0, &alloc_size);
X            if (disk_space < alloc_size) {
X               close_file (this_file);
X               unlink (extfname);
X               prterror ('f', disk_full);
X            }              
X         }
X#endif
X         if (tofile && disk_space < direntry.org_size) {
X#ifdef PORTABLE
X            ;
X#else
X				prterror ('e', no_space, prtfname);
X            unlink (extfname);               /* delete any created file */
X#endif   /* portable */
X
X         } else { 
X
X#ifndef PORTABLE
X            if (fast_ext) {            /* fast ext -> create header */
X#ifdef LINT_ARGS
X               void make_tnh (struct tiny_header *, struct direntry *);
X#else
X               void make_tnh();
X#endif
X               struct tiny_header tiny_header;
X               make_tnh(&tiny_header, &direntry);
X               zoowrite (this_file, (char *) &tiny_header, sizeof(tiny_header));
X
X               if (direntry.cmt_size != 0) { /* copy comment */
X                  long save_pos;
X                  save_pos = zootell (zoo_file);
X                  zooseek (zoo_file, direntry.comment, 0);
X                  getfile (zoo_file, this_file, 
X                          (long) direntry.cmt_size, 0);
X                  zooseek (zoo_file, save_pos, 0);
X               }
X            }
X#endif /* ifndef PORTABLE */
X
X            crccode = 0;      /* Initialize CRC before extraction */
X               if (!pipe) {
X#ifdef PORTABLE
X                  prterror ('m', "%-14s -- ", prtfname);
X#else
X                  if (fast_ext)
X                     prterror ('m', "%-12s ==> %-12s -- ", 
X                        prtfname,  extfname);
X                  else
X                     prterror ('m', "%-12s -- ", prtfname);
X#endif /* PORTABLE */
X
X               } else {            /* must be pipe */
X                  prterror ('M',"\n\n********\n%s\n********\n",prtfname);
X
X#ifdef SETMODE
X                  MODE_BIN(this_file);           /* make std output binary so
X                                                   ^Z won't cause error */
X#endif
X               }
X#ifndef NOSIGNAL
X            if (tofile)
X               {
X                  oldsignal = signal (SIGINT, SIG_IGN);
X                  if (oldsignal != SIG_IGN) 
X                     signal (SIGINT, ctrl_c); /* Trap ^C & erase partial file */
X               }
X#endif /* not NOSIGNAL */
X
X            if (direntry.packing_method == 0)
X               /* 4th param 1 means CRC update */
X               status = getfile (zoo_file, this_file, direntry.size_now, 1);
X
X#ifndef PORTABLE
X            else if (fast_ext)
X               /* 4th param 0 means no CRC update */
X               status = getfile (zoo_file, this_file, direntry.size_now, 0);
X#endif
X
X            else if (direntry.packing_method == 1) {
X#ifdef UNBUF_IO
X					/* NOT PORTABLE -- DO NOT TRY THIS AT HOME */
X					long lseek PARMS ((int, long, int));
X					long tell PARMS ((int));
X					int this_fd, zoo_fd;
X			
X					/* get file descriptors */
X					this_fd = null_device ? -2 : fileno (this_file);
X					zoo_fd = fileno (zoo_file);
X
X					zooseek (zoo_file, zootell (zoo_file), 0);	/* synch */
X					lseek (zoo_fd, zootell (zoo_file), 0);			/* ..again */
X					if (!null_device) {
X						zooseek (this_file, zootell (this_file), 0);	/* synch */
X						lseek (this_fd, zootell (this_file), 0);		/* ..again */
X					}
X			      status = lzd(zoo_fd, this_fd);			/* uncompress */
X					zooseek (zoo_file, tell (zoo_fd), 0);	/* resynch	*/
X					if (!null_device)
X						zooseek (this_file, tell (this_fd), 0);/* resynch	*/
X#else
X               status = lzd (zoo_file, this_file); 	/* uncompress */
X#endif
X            } else {
X               prterror ('e', "File %s:  impossible packing method.\n",
X                  whichname);
X                  unlink(extfname);
X                  goto loop_again;
X            }
X
X
X#ifndef NOSIGNAL
X            if (tofile)
X               signal (SIGINT, oldsignal);
X#endif /* not NOSIGNAL */
X
X#ifdef SETMODE
X            if (pipe)
X               MODE_TEXT(this_file);          /* restore text mode */
X#endif
X   
X            if (tofile) {
X               /* set date/time of file being extracted */
X#ifdef GETTZ
X					void tzadj();
X					/* adjust for original timezone */
X					tzadj (&direntry);
X#endif
X#ifdef NIXTIME
X               close_file (this_file);
X               setutime (extfname, direntry.date, direntry.time);
X#else
X               settime (this_file, direntry.date, direntry.time);
X               close_file (this_file);
X#endif
X#ifdef FATTR
X/* Restore file attributes. Bit 23==1 means system-specific; we currently 
Xdon't recognize this.  Bit 23==0 means use portable format, in which case 
Xbit 22==0 means ignore attributes.  Thus attributes are ignored if both 
Xbits 23 and 22 are zero, which is the effect of a zero-filled file 
Xattribute field.  Currently we restore file attributes if and only if
Xbit 23==0 and bit 22==1. */
X
X					if ((direntry.fattr >> 22) == 1) {
X						setfattr (extfname, direntry.fattr);
X					}
X#endif /* FATTR */
X            } /* end of if (tofile) ... */
X            if (status != 0) {
X					exit_status = 1;
X               if (tofile)
X                  unlink (extfname);
X               if (status == 1) {
X                  memerr();
X               /* To avoid spurious errors due to ^Z being sent to screen,
X                  we don't check for I/O error if output was piped */
X               } else if (!pipe && (status == 2 || status == 3)) {
X                     prterror ('e', no_space, prtfname);
X               }
X            } else {
X               /* file extracted, so update disk space.  */
X               /* we subtract the original size of the file, rounded
X                  UP to the nearest multiple of the disk allocation
X                  size. */
X#ifndef PORTABLE
X               {
X                  unsigned long temp;
X                  temp = (direntry.org_size + alloc_size) / alloc_size;
X                  disk_space -= temp * alloc_size;
X               }
X#endif
X
X               if (
X#ifndef PORTABLE
X					      !fast_ext && 
X#endif
X							direntry.file_crc != crccode
X						) {
X                  badcrc_count++;
X						exit_status = 1;
X                  if (!pipe) {
X                     if (!null_device)
X                        prterror ('M', "extracted   ");
X                     prterror ('w', bad_crc, prtfname);
X                  }
X                  else {   /* duplicate to standard error */
X                     static char stars[] = "\n******\n";
X                     putstr (stars);
X                     prterror ('w', bad_crc, prtfname);
X                     putstr (stars);
X                     fprintf (stderr, "WARNING:  ");
X                     fprintf (stderr, bad_crc, prtfname);
X                  }
X               } else
X                  if (!pipe)
X                     prterror ('M', null_device ? "OK\n" : "extracted\n");
X
X            } /* end if */
X         } /* end if */
X      } /* end if */
X   } /* end if */
X
Xloop_again:
X   zooseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */
X} /* end while */
X
Xclose_file (zoo_file);
Xif (!matched)
X   putstr (no_match);
X
Xif (badcrc_count) {
X   prterror ('w', "%d File(s) with bad CRC.\n", badcrc_count);
X} else if (null_device)
X   prterror ('m', "Archive seems OK.\n");
X
Xzooexit (exit_status);
X
X} /* end zooext */
X
X/* close_file() */
X/* closes a file if and only if we aren't sending output to 
X   a pipe or to the null device */
X
Xvoid close_file (file)
XZOOFILE file;
X{
X   if (tofile)
X      zooclose (file);
X}
X
X/* Ctrl_c() is called if ^C is hit while a file is being extracted.
X   It closes the files, deletes it, and exits. */
Xint ctrl_c()
X{
X#ifndef NOSIGNAL
X   signal (SIGINT, SIG_IGN);     /* ignore any more */
X#endif
X   zooclose (this_file);
X   unlink (extfname);
X   zooexit (1);
X}
X
X#ifndef PORTABLE
X/* make_tnh copies creates a tiny_header */
Xvoid make_tnh (tiny_header, direntry)
Xstruct tiny_header *tiny_header;
Xstruct direntry *direntry;
X{
X   tiny_header->tinytag = TINYTAG;
X   tiny_header->type = 1;
X   tiny_header->packing_method = direntry->packing_method;
X   tiny_header->date = direntry->date;
X   tiny_header->time = direntry->time;
X   tiny_header->file_crc = direntry->file_crc;
X   tiny_header->org_size = direntry->org_size;
X   tiny_header->size_now = direntry->size_now;
X   tiny_header->major_ver = direntry->major_ver;
X   tiny_header->minor_ver = direntry->minor_ver;
X   tiny_header->cmt_size = direntry->cmt_size;
X   strcpy (tiny_header->fname, direntry->fname);
X} 
X#endif /* ifndef PORTABLE */
END_OF_FILE
if test 21819 -ne `wc -c <'zooext.c'`; then
    echo shar: \"'zooext.c'\" unpacked with wrong size!
fi
# end of 'zooext.c'
fi
echo shar: End of archive 8 \(of 10\).
cp /dev/null ark8isdone
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.