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.