zoo-2.10.orig/ 40755 1750 1750 0 6271264267 11622 5ustar jamesjameszoo-2.10.orig/Checksums100644 1750 1750 4200 5035113600 13540 0ustar jamesjames# Whole file CRCs generated by Brik v2.0. Use "brik -C" to verify them. # CRC-32 filename # ------ -------- 1667442549 Copyright 359392938 Install 630248997 List 325879421 addbfcrc.c 669949366 addbftcc.c 4137570368 addfname.c 260075838 ar.h 3176247825 asmconst.ai 1968829781 assert.h 2774589019 basename.c 1418550454 bilf.c 3571167278 bsd.c 1744985930 comment.c 1095290529 crcdefs.c 1757282176 debug.h 3021583345 decode.c 73743136 descrip.mms 489796322 encode.c 4075798129 errors.i 3490413857 file.fix 3485210749 fiz.1 3600565988 fiz.c 1774024002 fiz.man 4182972025 generic.c 4010994345 getfile.c 955564271 huf.c 2264840036 io.c 75805716 lzc.asm 3570919889 lzc.c 2349470583 lzconst.h 1707878509 lzd.asm 2897597557 lzd.c 3828693743 lzh.c 2429644475 lzh.h 3979315416 machine.c 182740816 machine.h 535357786 macros.ai 2011785281 makefile 2589398917 makefile.tcc 2126848007 makelist.c 3525602735 maketbl.c 876325461 maketree.c 2551733860 misc.c 2137143154 misc2.c 3638187888 msdos.c 3448357770 mstime.i 31631311 needed.c 1766157868 nextfile.c 199542926 nixmode.i 4077222384 nixtime.i 538776329 options.c 1046541896 options.doc 180668707 options.h 900930479 options.opt 736653532 parse.c 574404514 parse.h 1002254917 portable.c 2748395706 portable.h 2801811069 prterror.c 3802884050 sysv.c 2806576319 turboc.c 3251857396 turboc.cfg 3963527820 various.h 1396445097 version.c 2692606938 vms.c 1336602147 vmsbugs.doc 2881095287 vmsbuild.com 3049809232 vmstime.c 3500434419 zoo.1 2239462961 zoo.c 2894729456 zoo.h 2869866215 zoo.man 2959104574 zooadd.c 3729120263 zooadd2.c 367556730 zoodel.c 3847646036 zooext.c 987202888 zoofilt.c 2253746453 zoofns.h 778874820 zooio.h 1037042734 zoolist.c 879931512 zoomem.h 3513827030 zoopack.c zoo-2.10.orig/Copyright100644 1750 1750 4160 5035113600 13570 0ustar jamesjames COPYRIGHT The following rules apply only to the zoo archiver itself. Currently, all extract-only programs, and all supporting utili- ties, are fully in the public domain and are expected to remain so for the forseeable future. COPYRIGHT STATEMENT FOR ZOO ARCHIVE PROGRAM 1. "This software" refers separately to each existing version, and each existing authorized derivative work, of my zoo archive program as of the date at the bottom of this copyright statement. 2. DISTRIBUTION IN UNMODIFIED FORM: You may copy this software in unmodified form for any purpose, whether commercial or noncommercial, provided that you make no attempt to restrict distribution of it by others. 3. CREATION OF DERIVATIVE WORKS: You may create and distribute derivative works made from any source code files that are part of this software, provided that you (a) preserve all copyright notices and author attributions, (b) do not create, whether deliberately or through negligence, any derivative work that violates the compatibility goals describe in the reference manual for zoo 2.1, (c) do not attempt to restrict the distribution or use of the derivative work by others, (d) make the fully commented source code of the derivative work available to me at no cost if I so request, and make no attempt to restrict the distribution or use of this source code. 4. NO WARRANTY. I make no claim that this software is free of defects. I do not accept any legal obligation to provide any bug fixes or any other type of support whatsoever. I disclaim all liability for damages, whether direct or consequential. 5. EXCEPTIONS: Exceptions to the above conditions are probably possible. Please contact me to negotiate. 6. The prohibition against incompatible derivative works does not necessarily imply that the archiver and the archive format cannot be enhanced. However, if any incompatibility is created, it may be done only with my permission. -- Rahul Dhesi 1991/07/07 zoo-2.10.orig/Install100644 1750 1750 4132 5035113600 13225 0ustar jamesjames INSTALLATION This is version 2.1 of the zoo archiver. It includes improved compression, better online help, VAX/VMS file timestamp preservation, faster uncompression, and other features that are described in the accompanying manual ("zoo.1" or "zoo.man"). The supplied makefile contains a number of targets for selected systems. Type "make help" for help from the makefile. Also, for VAX/VMS systems, see the file vmsbugs.doc for VMS-specific information. The file ``options.h'' defines preprocessor symbols for the various sys- tems. In most cases, given a reasonably powerful C compiler and library, you will be able to find a combination of options that will work. Documentation for these options is in the file ``options.doc''. Other machine-dependent code and definitions are in machine.h, machine.c, and portable.h. Also, the amount of memory used for some arrays can be customized by defining symbols that are described and used in zoomem.h. The low-level input/output routines are in portable.c. In most cases these will not need to be modified. On machines with older (Intel-style) architectures zoo requires the large memory model. Compiling with the small memory model will cause problems. EXTRACT-ONLY VERSION. For a new system, your first concern should be the ability to extract and list zoo archives. For this purpose try com- piling booz (which stands for Barebones Ooz) (currently version 2.0), which is small and portable. It is distributed separately from zoo. KNOWN BUGS 1. The filter mode of zoo 2.1 appears to compresses and uncompresses correctly, but often reports an "Uncompression error" even when uncompression was successful. 2. It is possible for zoo 2.1 to fail to detect an out of disk space situation when adding files to a zoo archive. 3. The MS-DOS version of zoo 2.1 may unnecessarily report an error when extracting a file to standard output. Normal file extraction to disk is not affected. These bugs are expected to be fixed in the next release. -- Rahul Dhesi 1991/07/07 zoo-2.10.orig/List100644 1750 1750 5222 5035113600 12533 0ustar jamesjames## List of files for zoo 2.1 ## ## Here is a list of all files that are part of the zoo 2.1 source ## distribution. ## ## @all: for all systems ## @bsd: BSD ## @sysv: System V ## @vms: VMS ## @gen: Generic **IX systems ## @tcc: Turbo C/MS-DOS ## @doc: Documentation (not source code etc.) ## ## To select all files needed for a specific system, just do a search. ## For example, to find all non-doc files needed for BSD: ## ## egrep '@bsd|@all' list.master | grep -v '@doc' | grep -v '^##' ## Copyright @doc @all Install @doc @all List @doc @all addbfcrc.c @all -@tcc addbftcc.c @tcc addfname.c @all ar.h @all asmconst.ai @tcc assert.h @all basename.c @all bilf.c @vms bsd.c @bsd comment.c @all crcdefs.c @all debug.h @all decode.c @all descrip.mms @vms encode.c @all errors.i @all file.fix @doc @bsd @sysv fiz.1 @doc @all fiz.c @all fiz.man @doc @all generic.c @gen getfile.c @all huf.c @all io.c @all lzc.asm @tcc lzc.c @all lzconst.h @all lzd.asm @tcc lzd.c @all lzh.c @all lzh.h @all machine.c @all machine.h @all macros.ai @tcc makefile @bsd @sysv makefile.tcc @tcc makelist.c @all maketbl.c @all maketree.c @all misc.c @all misc2.c @all msdos.c @all mstime.i @all needed.c @all nextfile.c @all nixmode.i @bsd @sysv nixtime.i @bsd @sysv options.c @all options.doc @doc options.h @all options.opt @vms parse.c @all parse.h @all portable.c @all portable.h @all prterror.c @all sysv.c @sysv turboc.c @tcc turboc.cfg @tcc various.h @all version.c @all vms.c @vms vmsbugs.doc @doc vmsbuild.com @vms vmstime.c @vms zoo.1 @doc zoo.c @all zoo.h @all zoo.man @doc zooadd.c @all zooadd2.c @all zoodel.c @all zooext.c @all zoofilt.c @all zoofns.h @all zooio.h @all zoolist.c @all zoomem.h @all zoopack.c @all zoo-2.10.orig/addbfcrc.c100644 1750 1750 1524 5035113600 13572 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) addbfcrc.c 2.2 88/01/29 17:04:31"; #endif /* LINT */ #include "options.h" /* addbfcrc() accepts a buffer address and a count and adds the CRC for all bytes in the buffer to the global variable crccode using CRC-16. CRC computation algorithm originally from an article by David Schwaderer in the April 1985 issue of PC Tech Journal. Loop optimization done by J. Brian Waters. I claim no copyright over the contents of this file. -- Rahul Dhesi 1986/08/27 */ extern unsigned int crccode; extern unsigned crctab[]; void addbfcrc(buffer,count) register char *buffer; register int count; { register unsigned int localcrc; localcrc = crccode; for (; count--; ) localcrc = (localcrc>>8) ^ crctab[(localcrc ^ (*buffer++)) & 0x00ff]; crccode = localcrc; } zoo-2.10.orig/addbftcc.c100644 1750 1750 4061 5035113600 13573 0ustar jamesjames#pragma inline /* tell turbo assemble to use inline assembly */ #ifndef LINT static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/addbftcc.c,v $\n\ $Id: addbftcc.c,v 1.1 91/07/07 18:40:11 dhesi Exp $"; #endif /* LINT */ extern unsigned int crccode; extern unsigned crctab[]; void addbfcrc(buffer,count) char *buffer; int count; { (void) kbhit(); /* allow keyboard interrupt to occur */ _AX = crccode; /* ax holds crccode value */ _CX = count; /* cx holds byte count */ asm les di,buffer /* es:di holds buffer address */ asm jcxz done /* if zero bytes, just skip */ /* loop begins here */ xloop: asm sub bh,bh asm mov bl,al asm xor bl,es:[di] /* now bx = (crccode xor c) & 0x00ff */ /* next statement shifts _BX left (2-byte items) */ _DX = crctab[_BX]; /* dx <= *buffer == exp2 */ asm sub bh,bh /* bh = 0 */ asm mov bl,ah /* bx <- exp1 */ asm xor bx,dx /* bx <- exp1 xor exp2 */ asm mov ax,bx /* crccode <- exp1 xor exp2 */ asm inc di /* inc buffer pointer */ asm loop xloop /* dec CX, jump if not zero */ /* loop ends here */ crccode = _AX; /* put back calculated CRC value */ done: ; } #if 0 ; The following (edited) code was generated by Turbo C from the ; preceding code. It is supplied here for porting to other systems ; and for user education. _TEXT segment byte public 'CODE' _TEXT ends DGROUP group _DATA,_BSS assume cs:_TEXT,ds:DGROUP _DATA segment word public 'DATA' _DATA ends _BSS segment word public 'BSS' _BSS ends _TEXT segment byte public 'CODE' assume cs:_TEXT _addbfcrc proc near push bp mov bp,sp push di call near ptr _kbhit mov ax,word ptr DGROUP:_crccode mov cx,word ptr [bp+8] les di,[bp+4] jcxz short @1@362 @1@98: sub bh,bh mov bl,al xor bl,es:[di] shl bx,1 mov dx,word ptr DGROUP:_crctab[bx] sub bh,bh mov bl,ah xor bx,dx mov ax,bx inc di loop short @1@98 mov word ptr DGROUP:_crccode,ax @1@362: pop di pop bp ret _addbfcrc endp _TEXT ends extrn _crccode:word extrn _kbhit:near extrn _crctab:word public _addbfcrc end #endif zoo-2.10.orig/addfname.c100644 1750 1750 7440 5035113600 13604 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) addfname.c 2.11 88/02/06 20:17:17"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Adds a filename to global list. (This global list will eventually be searched by the inlist() function.) The second and subsequent parameters suppplied are stored with the name of the file and returned by inlist. */ #include "zooio.h" #include "various.h" #include "zoo.h" #include "zoofns.h" #include "zoomem.h" /* to get LIST_SIZE */ #define FENTRY_BSIZE 80 /* allocation granularity for fentry below */ static struct item **fentry; /* array of ptrs to file information structs */ static unsigned sz_fentry; /* its current size */ static int lastname = 0; /* index of last name */ struct item { /* global filename list entry */ char *fname; long position; unsigned int date; unsigned int time; unsigned vflag; unsigned version_no; }; void addfname(fname, position, date, time, vflag, version_no) char *fname; long position; unsigned int date, time; unsigned vflag; unsigned version_no; { if (lastname == 0) { sz_fentry = FENTRY_BSIZE; fentry = (struct item **) ealloc(sizeof(struct item *) * sz_fentry); fentry[0] = (struct item *) ealloc (sizeof(struct item)); } /* allocated more memory if needed */ if (lastname >= sz_fentry - 3) { sz_fentry += FENTRY_BSIZE; fentry = (struct item **) erealloc(fentry, sizeof(struct item *) * sz_fentry); } fentry[lastname]->fname = str_dup(fname); fentry[lastname]->position = position; fentry[lastname]->date = date; fentry[lastname]->time = time; fentry[lastname]->vflag = vflag; fentry[lastname]->version_no = version_no; lastname++; /* allocate memory for empty entry at end */ fentry[lastname] = (struct item *) ealloc (sizeof(struct item)); } /* addfname */ /* inlist() */ /* Examines global list built by addfname() to see if supplied filename is in the list. If found, returns the file's position within the archive as the function value and the date, time, version flag, and version number as parameters. If not found, returns -1. Also returns the highest version no. seen for this filename and the vflag associated with that version. A simple sequential search is done. If justname is nonzero, then the search is for the filename only without the directory prefix; else it is for the full pathname. */ long inlist (fname, date, time, this_version_no, high_vflag, high_version_no, high_pos, justname) char *fname; unsigned int *date, *time; unsigned *high_vflag; unsigned *this_version_no; unsigned *high_version_no; long *high_pos; int justname; { register int i = 0; *high_version_no = 0; if (justname) fname = nameptr (fname); /* if directory wanted */ fentry[lastname]->fname = fname; /* sentinel */ fentry[lastname]->version_no = 0; #ifdef IGNORECASE #define COMPARE str_icmp #else #define COMPARE strcmp #endif while (COMPARE(fname, (justname ? nameptr (fentry[i]->fname) : fentry[i]->fname)) != 0) { i++; } if (i == lastname) return (-1L); else { int j; *date = fentry[i]->date; *time = fentry[i]->time; *high_pos = fentry[i]->position; *high_vflag = fentry[i]->vflag; for (j = i; j < lastname; j++) { /* find highest version no. for file */ if (COMPARE(fname, (justname ? nameptr (fentry[j]->fname) : fentry[j]->fname)) == 0) { if (*high_version_no < fentry[j]->version_no) { *high_version_no = fentry[j]->version_no; *high_vflag = fentry[j]->vflag; *high_pos = fentry[j]->position; *date = fentry[j]->date; *time = fentry[j]->time; } } } *this_version_no = fentry[i]->version_no; return (fentry[i]->position); } } /* inlist() */ zoo-2.10.orig/ar.h100644 1750 1750 6031 5035113600 12447 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/ar.h,v $*/ /*$Id: ar.h,v 1.17 91/07/09 01:39:50 dhesi Exp $*/ /*********************************************************** ar.h Adapted from "ar" archiver written by Haruhiko Okumura. ***********************************************************/ #include #ifdef ANSI_HDRS # include #endif /* uchar should be 8 bits or more */ /* typedef unsigned char uchar; -- already in zoo.h */ typedef unsigned int uint; /* 16 bits or more */ typedef unsigned short ushort; /* 16 bits or more */ typedef unsigned long ulong; /* 32 bits or more */ /* T_UINT16 must be #defined in options.h to be a 16-bit unsigned integer type */ #ifndef T_UINT16 # include "T_UINT16 not defined" #endif typedef T_UINT16 t_uint16; /* exactly 16 bits */ #ifndef SEEK_SET # define SEEK_SET 0 #endif #ifndef SEEK_CUR # define SEEK_CUR 1 #endif #ifndef SEEK_END # define SEEK_END 2 #endif #ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE # define EXIT_FAILURE 1 #endif /* ar.c */ extern int unpackable; extern ulong origsize, compsize; /* all the prototypes follow here for all files */ /* standard library functions */ #ifndef ANSI_HDRS extern void exit(); extern long ftell(); extern int fseek(); extern int strlen(); extern char *strchr(); extern char *strpbrk(); extern int strcmp(); extern char *strcpy(); extern int memcmp(); extern VOIDPTR malloc(); extern VOIDPTR memcpy(); #endif /* ANSI_HDRS */ /* AR.C */ int get_line PARMS((char *s , int n )); void exitfunc PARMS((int code)); void dlog PARMS((char *fmt, ...)); void d1log PARMS((char *fmt, ...)); void outcf PARMS((FILE *stream, char *buf, int n)); void c1log PARMS((char *buf, int n)); /* DECODE.C */ void decode_start PARMS((void )); int decode PARMS((uint count , uchar buffer [])); /* ENCODE.C */ void encode PARMS((FILE *, FILE *)); /* HUF.C */ void output PARMS((uint c , uint p )); void huf_encode_start PARMS((void )); void huf_encode_end PARMS((void )); uint decode_c PARMS((void )); uint decode_p PARMS((void )); void huf_decode_start PARMS((void )); /* IO.C */ void make_crctable PARMS((void )); void fillbuf PARMS((int n )); uint getbits PARMS((int n )); void putbits PARMS((int n , uint x )); int fread_crc PARMS((uchar *p , int n , FILE *f )); void fwrite_crc PARMS((uchar *p , int n , FILE *f )); void init_getbits PARMS((void )); void init_putbits PARMS((void )); /* MAKETBL.C */ void make_table PARMS((int nchar, uchar bitlen[], int tablebits, ushort table[])); /* MAKETREE.C */ int make_tree PARMS((int nparm, ushort freqparm [], uchar lenparm [], ushort codeparm [])); /* delete */ #ifdef NEED_MEMMOVE # define MOVE_LEFT move_left void move_left(); #else # define MOVE_LEFT memmove extern VOIDPTR memmove(); #endif #if 0 /* global crc variable stuff for use by various routines */ extern t_uint16 crc; #define INIT_CRC 0 /* CCITT: 0xFFFF */ #endif /* for lzh modules and also for ar.c to use in defining buffer size */ #define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */ #define DICSIZ ((unsigned) 1 << DICBIT) zoo-2.10.orig/asmconst.ai100644 1750 1750 1005 5035113600 14032 0ustar jamesjames; $Source: /usr/home/dhesi/zoo/RCS/asmconst.ai,v $ ; $Id: asmconst.ai,v 1.2 91/07/07 09:37:47 dhesi Exp $ ;The contents of this file are hereby released to the public domain. ; -- Rahul Dhesi 1988/08/25 ;Constant values for lzc.asm and lzd.asm maxbits equ 13 clear equ 256 ;Clear code eof equ 257 ;End of file marker first_free equ 258 ;First free code maxmax equ 1 shl maxbits ;Max code + 1 inbufsiz equ 8192 ;size of input buffer outbufsiz equ 8192 ;size of output buffer zoo-2.10.orig/assert.h100644 1750 1750 1743 5035113600 13353 0ustar jamesjames/* @(#) assert.h 2.1 87/12/25 12:21:32 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1991/07/04 Defines a macro assert() that causes an assertion error if the assertion fails. Conditional compilation: If NDEBUG is defined then assert() is defined as null so all assertions vanish else if __FILE__ and __LINE__ are defined then assertions print message including filename and line number else assertions print a message but not the filename and line number endif endif */ #ifdef NDEBUG # define assert(E) #else #undef LINE_FILE #ifdef __LINE__ # ifdef __FILE__ # define LINE_FILE # endif #endif #ifdef LINE_FILE # undef LINE_FILE # define assert(E) \ { if (!(E)) \ prterror ('w',"Assertion error in %s:%d.\n", __FILE__, __LINE__); \ } #else # define assert(E) \ { if (!(E)) \ prterror ('w', "Assertion error.\n"); \ } #endif #endif /* NDEBUG */ zoo-2.10.orig/basename.c100644 1750 1750 6155 5035113600 13622 0ustar jamesjames#ifndef LINT /* @(#) basename.c 2.2 87/12/27 13:42:40 */ static char sccsid[]="@(#) basename.c 2.2 87/12/27 13:42:40"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "zooio.h" #include "zoo.h" #include "parse.h" #include "various.h" #include "zoofns.h" #include "debug.h" #include "assert.h" /* This function strips device/directory information from a pathname and returns just the plain filename */ void basename (pathname, fname) char *pathname; char fname[]; { strcpy (fname, nameptr (pathname)); } /* Set of legal MSDOS filename characters. The working of cvtchr() depends on the order of the first few characters here. In particular, '_' is positioned so '.' gets converted to it. */ static char legal[] = "tabcdefghijklmnopqrs_uvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@^`{}~!#$%&'()-"; /**************** cvtchr() converts a character to a lowercase alphabetic character in a somewhat random way. */ #define cvtchr(ch) legal[(ch & 0xff) % 26] /*************** cleanup() cleans up a string so it contains only legal MSDOS filename characters. Any other characters are converted to an underscore. If the filename is null or if it begins with a dot, it is fixed. All dots are also converted. */ void cleanup (p) char *p; { assert(p != NULL); if (*p == '\0') strcpy (p, "X"); if (*p == '.') *p = '_'; while (*p != '\0') { if (strchr (legal, *p) == NULL) { /* if invalid character */ *p = cvtchr(*p); } p++; } } /* This function strips device/directory information from a pathname, forces the remaining filename to MSDOS format, and returns it. Any illegal characters are fixed. */ void dosname (pathname, fname) char *pathname; char fname[]; { struct path_st path_st; parse (&path_st, pathname); strcpy (fname, path_st.fname); cleanup (fname); #ifdef VER_CH /* remove any trailing extension field */ if (path_st.ext[0] != '\0') strip_ver (path_st.ext); #endif /* extension could have been nulled, so we test again */ if (path_st.ext[0] != '\0') { cleanup (path_st.ext); strcat (fname, "."); strcat (fname, path_st.ext); } #ifdef SPECMOD specfname (fname); #endif } /* rootname() */ /* Accepts a pathname. Returns the root filename, i.e., with both the directory path and the extension stripped. */ void rootname (path, root) char *path, *root; { char *p; static char dot[] = {EXT_CH, '\0'}; strcpy(root, nameptr(path)); /* copy all but path prefix */ p = findlast(root, dot); /* find last dot */ if (p != NULL) /* if found ... */ *p = '\0'; /* ... null it out */ } /* nameptr() */ /* Accepts a pathname. Returns a pointer to the filename within that pathname. */ char *nameptr (path) char *path; { char *t; t = findlast (path, PATH_SEP); /* last char separating device/directory */ debug ((printf ("nameptr: findlast returned ptr to string [%s].\n",t))) if (t == NULL) /* no separator */ return (path); else { return (t+1); } } zoo-2.10.orig/bilf.c100644 1750 1750 14106 5035113600 12776 0ustar jamesjames/* $Source: /usr/home/dhesi/zoo/RCS/bilf.c,v $ */ /* $Id: bilf.c,v 1.2 91/07/07 14:57:06 dhesi Exp $ */ /* This program performs conversion of files between stream-LF format (as used by zoo) and fixed-length record binary format (used for Kermit transfers of zoo archives). This program is: (C) Copyright 1987 Rahul Dhesi. All Rights Reserved. Permission is hereby granted to copy and modify this for any purpose, whether commercial or noncommercial, provided only that the above copyright notice and this paragraph be preserved and included in all copies. -- Rahul Dhesi 1987/07/25 */ #include #include #define STAT_NORM SS$_NORMAL #define STAT_ABORT SS$_ABORT char *strrchr(); char *strdup (); main (argc, argv) int argc; char *argv[]; { char *inname; char *outname; char *option; int status; if (argc < 3 || argc > 4) { printf ("BILF version 1.00 for VAX/VMS by Rahul Dhesi (1987/07/25)\n\n"); printf ("(C) Copyright 1987 Rahul Dhesi, All Rights Reserved\n"); printf ("Permission to use and distribute is granted provided this copyright\n"); printf ("notice is preserved and included in all copies.\n\n"); printf ("Usage: BILF {lb} infile [ outfile ]\n\n"); printf ("Choose one character from within braces. If outfile is not supplied\n"); printf ("it has the same name as infile but a higher version number.\n"); printf ("Options are:\n\n"); printf ("l: Write output file in stream-LF format. This is the format that\n"); printf (" zoo expects all zoo archives to be in. If a zoo archive was\n"); printf (" uploaded to a VAX/VMS system, it will need to be converted to\n"); printf (" stream-LF format before manipulating with zoo.\n\n"); printf ("b: Write output file in fixed-length 512-byte binary record format. Before\n"); printf (" a zoo archive can be downloaded from a VAX/VMS system to a\n"); printf (" microcomputer using VAX/VMS Kermit, it must be converted to\n"); printf (" this binary format. Failure to do so will result in a corrupted\n"); printf (" download.\n"); exit (STAT_NORM); } inname = argv[2]; option = argv[1]; if (argc == 3) { /* use same filename for output */ char *p; outname = strdup (inname); p = strrchr (outname, ';'); /* strip trailing version field */ if (p != NULL) *p = '\0'; } else outname = argv[3]; if (*option == 'l') status = cvtstream (outname, inname); else if (*option == 'b') status = cvtbin (outname, inname); else prterror ('f', "Option %s is invalid\n", option); if (status == -1) prterror ('w', "An error occurred -- output file may be corrupted\n"); exit (STAT_NORM); } #define MYBUFSIZ 8192 /* writes input file to output file in stream format */ int cvtstream (outname, inname) char *outname, *inname; { FILE *infile, *outfile; char buffer[MYBUFSIZ]; int count; infile = fopen (inname, "r"); if (infile == NULL) prterror ('f', "Could not open input file %s\n", inname); outfile = fopen (outname, "w"); if (outfile == NULL) prterror ('f', "Could not open output file %s\n", outname); while ((count = fread (buffer, 1, sizeof (buffer), infile)) > 0) count = fwrite (buffer, 1, count, outfile); close (infile); close (outfile); if (count == -1) return (-1); else return (0); } /* VMS C doesn't have strdup(). */ char *strdup (str) char *str; { char *malloc(); char *newstr = malloc (strlen (str) + 1); if (newstr != NULL) { strcpy (newstr, str); return (newstr); } else return ((char *) NULL); } /* BLKSIZ must correspond to block size specified below in creat() */ #define BLKSIZ 512 /* Writes input file to output in fixed-length BLKSIZ-byte record format. */ #if 1 #include #else #include #endif int convert (); int cvtbin (outname, inname) char *outname, *inname; { int status, inhan, outhan; inhan = open (inname, O_RDONLY); if (inhan == -1) prterror ('f', "Could not open input file %s\n", inname); outhan = creat (outname, 0, "rfm=fix", "mrs=512"); if (outhan == -1) prterror ('f', "Could not open output file %s\n", outname); status = convert (outhan, inhan); close (inhan); close (outhan); return (status); } /* Function convert() reads from inhan and writes to outhan, always writing in BLKSIZ-byte blocks, padding with nulls if necessary */ int convert (outhan, inhan) int inhan, outhan; { char junk[BLKSIZ]; int count; int done = 0; do { count = vmsread (inhan, junk, BLKSIZ); if (count <= 0) break; if (count < BLKSIZ) { int i; for (i = count; i < BLKSIZ; i++) junk[i] = 0; done++; } count = write (outhan, junk, BLKSIZ); if (count == -1) break; } while (!done); if (count == -1) return (-1); else return (0); } /**** Function vmsread() does a standard read() but gets around bugs in the read() function of VAX/VMS C which make it unable to always read the entire amount requested in a single read() call. */ int vmsread (han, buf, amount) int han; char *buf; int amount; { int count; int thiscount; count = 0; while (count != -1 && count < amount) { thiscount = read (han, &buf[count], amount - count); if (thiscount == 0) thiscount = read (han, &buf[count], amount - count); if (thiscount == 0) break; if (thiscount == -1) count = -1; else count += thiscount; } return (count); } prterror (level, msg1, msg2) char level; char *msg1, *msg2; { if (level == 'e' || level == 'w' || level == 'f') printf ("BILF: "); switch (level) { case 'e': printf ("ERROR: "); break; case 'w': printf ("WARNING: "); break; case 'f': printf ("FATAL: "); break; default: prterror ('f', "Internal error in prterror()\n"); } printf (msg1, msg2); if (level == 'f') exit (STAT_ABORT); } zoo-2.10.orig/bsd.c100644 1750 1750 5132 5035113600 12611 0ustar jamesjames#ifndef LINT static char bsdid[]="@(#) bsd.c 2.3 88/01/10 14:45:19"; #endif /* LINT */ /* machine.c for 4.3BSD. */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1987/07/23 */ /* WARNING: This file assumes that ZOOFILE is a standard buffered file. It will have to be modified if ZOOFILE is changed to be an unbuffered file descriptor or to any other kind of file. */ #ifdef UNBUF_IO /* Function tell() returns the current seek position for a file descriptor. 4.3BSD on VAX-11/785 has an undocumented tell() function but it may not exist on all implementations, so we code one here to be on the safe side. It is needed for unbuffered I/O only. */ long lseek PARMS ((int, long, int)); long tell (fd) int fd; { return (lseek (fd, 0L, 1)); } #endif long ftell(); /**************** Function fixfname() converts the supplied filename to a syntax legal for the host system. It is used during extraction. */ char *fixfname(fname) char *fname; { return fname; /* default is no-op */ } /**************** Date and time functions are standard UNIX-style functions. */ #include #include #include /* Function isadir() returns 1 if the supplied handle is a directory, else it returns 0. */ int isadir (f) ZOOFILE f; { struct stat buf; /* buffer to hold file information */ if (fstat (fileno (f), &buf) == -1) { return (0); /* inaccessible -- assume not dir */ } else { if (buf.st_mode & S_IFDIR) return (1); else return (0); } } /* Function gettz() returns the offset from GMT in seconds */ long gettz() { #define SEC_IN_DAY (24L * 60L * 60L) #define INV_VALUE (SEC_IN_DAY + 1L) static long retval = INV_VALUE; /* cache, init to impossible value */ struct timeval tp; struct timezone tzp; if (retval != INV_VALUE) /* if have cached value, return it */ return retval; gettimeofday (&tp, &tzp); /* specific to 4.3BSD */ /* return (tzp.tz_minuteswest * 60); */ /* old incorrect code */ /* Timezone fix thanks to Bill Davidsen */ retval = tzp.tz_minuteswest * 60 - tzp.tz_dsttime * 3600L; return retval; } /* Standard UNIX-compatible time routines */ #include "nixtime.i" /* Standard UNIX-specific file attribute routines */ #include "nixmode.i" #ifndef SEEK_CUR # define SEEK_CUR 1 #endif /* Truncate a file. */ int zootrunc(f) FILE *f; { extern long lseek(); long seekpos; int fd = fileno(f); seekpos = lseek(fd, 0L, SEEK_CUR); if (seekpos >= 0) return ftruncate(fd, seekpos); } zoo-2.10.orig/comment.c100644 1750 1750 22573 5035113600 13533 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) comment.c 2.14 88/01/24 12:42:13"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "portable.h" /* comment() */ /* Updates comments */ /* buffer size for any one comment line */ #define COMMENT_LINE_SIZE 76 #define MAX_COMMENT_SIZE 32767 #include "zooio.h" #include "various.h" #ifndef NOSIGNAL #include #endif #include "zoo.h" #include "zoofns.h" #include "errors.i" void show_comment PARMS ((struct direntry *, ZOOFILE, int, char *)); void get_comment PARMS ((struct direntry *, ZOOFILE, char *)); int needed PARMS ((char *, struct direntry *, struct zoo_header *)); void comment(zoo_path, option) char *zoo_path, *option; { #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); #endif ZOOFILE zoo_file; /* stream for open archive */ long next_ptr; /* pointers to within archive */ long this_dir_offset; /* pointers to within archive */ struct direntry direntry; /* directory entry */ struct zoo_header zoo_header; int matched = 0; /* any files matched? */ unsigned int zoo_date, zoo_time; /* for restoring archive timestamp */ char whichname[PATHSIZE]; /* which name to use */ #ifdef ZOOCOMMENT int acmt = 0; /* if changing archive comment */ #endif /* on entry option points to first letter */ option++; /* skip 'c' */ #ifdef ZOOCOMMENT while (*option != '\0') { if (*option == 'A') { acmt++; /* changing archive comment */ option++; } else prterror ('f', inv_option, *option); } #else if (*option != '\0') prterror ('f', inv_option, *option); #endif /* ZOOCOMMENT */ if ((zoo_file = zooopen (zoo_path, Z_RDWR)) == NOFILE) prterror ('f', could_not_open, zoo_path); /* save archive timestamp */ #ifdef GETUTIME getutime (zoo_path, &zoo_date, &zoo_time); #else gettime (zoo_file, &zoo_date, &zoo_time); #endif /* read header and rewrite with updated version numbers, but ask user to pack archive first if archive comment is to be added and header type is 0 */ #ifdef ZOOCOMMENT if (acmt) rwheader (&zoo_header, zoo_file, 0); else rwheader (&zoo_header, zoo_file, 1); #else rwheader (&zoo_header, zoo_file, 1); #endif #ifdef ZOOCOMMENT /* if archive comment being added, handle it and return */ if (acmt) { void do_acmt PARMS ((struct zoo_header *, ZOOFILE, char *)); do_acmt (&zoo_header, zoo_file, zoo_path); #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, zoo_date, zoo_time); /* restore timestamp */ #else settime (zoo_file, zoo_date, zoo_time); /* restore timestamp */ zooclose (zoo_file); #endif return; } #endif /* ZOOCOMMENT */ /* Loop through and add comments for matching files */ while (1) { this_dir_offset = zootell (zoo_file); /* save pos'n of this dir entry */ readdir (&direntry, zoo_file, 1); /* read directory entry */ next_ptr = direntry.next; /* ptr to next dir entry */ /* exit on end of directory chain or end of file */ if (next_ptr == 0L || feof(stdin)) break; strcpy (whichname, fullpath (&direntry)); /* full pathname */ add_version (whichname, &direntry); /* add version suffix */ /* add comments for matching non-deleted files */ if (!direntry.deleted && needed (whichname, &direntry, &zoo_header)) { matched++; show_comment (&direntry, zoo_file, 1, whichname); get_comment (&direntry, zoo_file, whichname); zooseek (zoo_file, this_dir_offset, 0); #ifndef NOSIGNAL oldsignal = signal (SIGINT, SIG_IGN); #endif fwr_dir (&direntry, zoo_file); #ifndef NOSIGNAL signal (SIGINT, oldsignal); #endif } zooseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */ } /* end while */ #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, zoo_date, zoo_time); /* restore timestamp */ #else settime (zoo_file, zoo_date, zoo_time); /* restore timestamp */ zooclose (zoo_file); #endif if (!matched) printf ("Zoo: %s", no_match); } /* comment */ /* show_comment() */ /* shows comment on screen. If show=1, says "Current comment is..." */ void show_comment (direntry, zoo_file, show, name) struct direntry *direntry; ZOOFILE zoo_file; int show; char *name; /* name of file for which comment is being added */ { if (direntry->cmt_size != 0) { unsigned int i; char ch; int newline = 1; zooseek (zoo_file, direntry->comment, 0); if (show) printf ("Current comment for %s is:\n", name); for (i = 0; i < direntry->cmt_size; i++) {/* show it */ ch = zgetc (zoo_file) & 0x7f; /* 7 bits only */ if (newline) printf (" |"); /* indent and mark comment lines thus */ zputchar (ch); if (ch == '\n') newline = 1; else newline = 0; } if (!newline) /* always terminate with newline */ zputchar ('\n'); } } /* show_comment() */ /* get_comment() */ /* Shows user old comment and updates it */ /* INPUT: direntry points to current directory entry. zoo_file is archive file. this_path is full pathname of file being updated/added. OUTPUT: Comment is added to file and supplied directory entry is updated with comment size and seek position but directory entry is not written to file. Exceptions: If RETURN is hit as first line, previous comment is left unchanged. If /END is hit, previous comment is superseded, even if new comment is null. */ char cmt_prompt[]="[Enter %scomment for %s then type /END]\n"; void get_comment (direntry, zoo_file, this_path) /* update comment */ register struct direntry *direntry; ZOOFILE zoo_file; char *this_path; { unsigned int line_count = 0; /* count of new comment lines */ zooseek (zoo_file, 0L, 2); /* ready to append new comment */ #if 0 fprintf (stderr, "[Enter comment for %s then type /END]\n", this_path); #else fprintf (stderr, cmt_prompt, "", this_path); #endif while (1) { char cmt_line[COMMENT_LINE_SIZE]; int cmt_size; if (fgets (cmt_line, sizeof(cmt_line), stdin) == NULL) break; line_count++; if (line_count == 1) { /* first line typed */ if (!strcmp (cmt_line, "\n")) /* exit if first line blank */ break; direntry->comment = zootell (zoo_file); direntry->cmt_size = 0; } if (!str_icmp (cmt_line, "/end\n")) break; cmt_size = strlen (cmt_line); if (MAX_COMMENT_SIZE - direntry->cmt_size > cmt_size) { direntry->cmt_size += (unsigned int) cmt_size; if (zoowrite (zoo_file, cmt_line, cmt_size) < cmt_size) prterror ('f', disk_full); } } /* end while */ } /* get_comment() */ #ifdef ZOOCOMMENT /* do_acmt() updates archive comment by showing it to user and requesting a new one. Typed input terminates as with file comment, i.e., empty initial line leaves comment unchanged, case-insensitive "/end" terminates input comment. */ void do_acmt (zoo_header, zoo_file, zoo_path) struct zoo_header *zoo_header; ZOOFILE zoo_file; char *zoo_path; { unsigned int line_count = 0; /* count of new comment lines */ void show_acmt PARMS ((struct zoo_header *, ZOOFILE, int)); show_acmt (zoo_header, zoo_file, 1); /* show current archive comment */ zooseek (zoo_file, 0L, 2); /* ready to append new comment */ #if 0 fprintf (stderr, "[Enter archive comment for %s then type /END]\n", zoo_path); #else fprintf (stderr, cmt_prompt, "archive ", zoo_path); #endif while (1) { char cmt_line[COMMENT_LINE_SIZE]; int cmt_size; if (fgets (cmt_line, sizeof(cmt_line), stdin) == NULL) break; line_count++; if (line_count == 1) { /* first line typed */ if (!strcmp (cmt_line, "\n")) /* exit if first line blank */ break; zoo_header->acmt_pos = zootell (zoo_file); zoo_header->acmt_len = 0; } if (!str_icmp (cmt_line, "/end\n")) break; cmt_size = strlen (cmt_line); if (MAX_COMMENT_SIZE - zoo_header->acmt_len > cmt_size) { zoo_header->acmt_len += (unsigned int) cmt_size; if (zoowrite (zoo_file, cmt_line, cmt_size) < cmt_size) prterror ('f', disk_full); } } /* end while */ zooseek (zoo_file, 0L, 0); /* seek back to beginning */ fwr_zooh (zoo_header, zoo_file); /* write update zoo_header */ } /* do_acmt() */ #endif /* ZOOCOMMENT */ /* Prints archive comment. If show==1, says "Current archive comment is:" */ void show_acmt (zoo_header, zoo_file, show) struct zoo_header *zoo_header; ZOOFILE zoo_file; int show; { if (zoo_header->zoo_start != FIXED_OFFSET && zoo_header->acmt_len > 0) { unsigned int i; char ch; int newline = 1; zooseek (zoo_file, zoo_header->acmt_pos, 0); if (show) printf ("Current archive comment is:\n"); for (i = 0; i < zoo_header->acmt_len; i++) {/* show it */ ch = zgetc (zoo_file) & 0x7f; /* 7 bits only */ if (newline) printf (">> "); /* indent and mark comment lines thus */ zputchar (ch); if (ch == '\n') newline = 1; else newline = 0; } if (!newline) /* always terminate with newline */ zputchar ('\n'); } } /* show_acmt() */ zoo-2.10.orig/crcdefs.c100644 1750 1750 4616 5035113600 13460 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) crcdefs.c 2.1 87/12/25 12:21:58"; #endif /* LINT */ #include "options.h" /* Global definitions for CRC calculation. I claim no copyright over the contents of this file. -- Rahul Dhesi 1987/08/27 */ unsigned int crccode; unsigned int crctab[] = { 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0F00, 0xcFc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdF81, 0x1F40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xF001, 0x30c0, 0x3180, 0xF141, 0x3300, 0xF3c1, 0xF281, 0x3240, 0x3600, 0xF6c1, 0xF781, 0x3740, 0xF501, 0x35c0, 0x3480, 0xF441, 0x3c00, 0xFcc1, 0xFd81, 0x3d40, 0xFF01, 0x3Fc0, 0x3e80, 0xFe41, 0xFa01, 0x3ac0, 0x3b80, 0xFb41, 0x3900, 0xF9c1, 0xF881, 0x3840, 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2F80, 0xeF41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaF01, 0x6Fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7F80, 0xbF41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5F00, 0x9Fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8F81, 0x4F40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 }; zoo-2.10.orig/debug.h100644 1750 1750 1147 5035113600 13136 0ustar jamesjames/* @(#) debug.h 2.1 87/12/25 12:22:02 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 defines conditional function calls Usage: The statement debug((printf("y = %d\n", y))) may be placed anywhere where two or more statements could be used. It will print the value of y at that point. Conditional compilation: if DEBUG is defined define the macro debug(X) to execute statement X else define the macro debug(X) to be null endif */ #ifdef DEBUG #define debug(x) x; #else #define debug(x) #endif zoo-2.10.orig/decode.c100644 1750 1750 2644 5035113600 13271 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/decode.c,v $*/ /*$Id: decode.c,v 1.6 91/07/09 01:39:49 dhesi Exp $*/ /*********************************************************** decode.c Adapted from "ar" archiver written by Haruhiko Okumura. ***********************************************************/ #include "options.h" #include "zoo.h" #include "ar.h" #include "lzh.h" extern int decoded; /* from huf.c */ static int j; /* remaining bytes to copy */ void decode_start() { huf_decode_start(); j = 0; decoded = 0; } /* decodes; returns no. of chars decoded */ int decode(count, buffer) uint count; uchar buffer[]; /* The calling function must keep the number of bytes to be processed. This function decodes either 'count' bytes or 'DICSIZ' bytes, whichever is smaller, into the array 'buffer[]' of size 'DICSIZ' or more. Call decode_start() once for each new file before calling this function. */ { static uint i; uint r, c; r = 0; while (--j >= 0) { buffer[r] = buffer[i]; i = (i + 1) & (DICSIZ - 1); if (++r == count) return r; } for ( ; ; ) { c = decode_c(); if (decoded) return r; if (c <= UCHAR_MAX) { buffer[r] = c; if (++r == count) return r; } else { j = c - (UCHAR_MAX + 1 - THRESHOLD); i = (r - decode_p() - 1) & (DICSIZ - 1); while (--j >= 0) { buffer[r] = buffer[i]; i = (i + 1) & (DICSIZ - 1); if (++r == count) return r; } } } } zoo-2.10.orig/descrip.mms100644 1750 1750 10115 5035113600 14061 0ustar jamesjames# derived from: @(#) descrip.mms 2.2 88/01/09 12:10:49 # $Source: /usr/home/dhesi/zoo/RCS/descrip.mms,v $ # $Id: descrip.mms,v 1.9 91/07/07 14:58:21 dhesi Exp $ #Make Zoo for VAX/VMS # #The contents of this makefile are hereby released to the public domain. # -- Rahul Dhesi 1991/07/06 CC = cc CFLAGS = EXTRA = /define=(BIG_MEM,NDEBUG,VMS) ldswitch = #List of all object files created for Zoo ZOOOBJS = addbfcrc.obj, addfname.obj, basename.obj, comment.obj, - crcdefs.obj, decode.obj, encode.obj, getfile.obj, huf.obj, - io.obj, lzc.obj, lzd.obj, lzh.obj, machine.obj, makelist.obj, - maketbl.obj, maketree.obj, misc.obj, misc2.obj, needed.obj, - nextfile.obj, options.obj, parse.obj, portable.obj, prterror.obj, - version.obj, vmstime.obj, zoo.obj, zooadd.obj, zooadd2.obj, - zoodel.obj, zooext.obj, zoolist.obj, zoopack.obj FIZOBJS = fiz.obj, addbfcrc.obj, portable.obj, crcdefs.obj BILFOBJS = bilf.obj .c.obj : $(CC) $(CFLAGS) $(EXTRA) $*.c zoo.exe : $(ZOOOBJS) link/executable=zoo.exe $(ldswitch) $(ZOOOBJS), options/opt # bigger but perhaps more (less?) portable across machines -- # no shared libraries zoobig.exe : $(ZOOOBJS) link/executable=zoobig.exe $(ldswitch) $(ZOOOBJS) fiz : $(FIZOBJS) link/executable=fiz.exe $(ldswitch) $(FIZOBJS), options/opt bilf : $(BILFOBJS) link/executable=bilf.exe $(ldswitch) $(BILFOBJS), options/opt ####################################################################### # DEPENDENCIES -- not guaranteed to be up-to-date ####################################################################### addbfcrc.obj : options.h addfname.obj : options.h various.h zoo.h zoofns.h zooio.h addfname.obj : zoomem.h basename.obj : assert.h debug.h options.h parse.h various.h basename.obj : zoo.h zoofns.h zooio.h comment.obj : errors.i options.h portable.h various.h comment.obj : zoo.h zoofns.h zooio.h crcdefs.obj : options.h decode.obj : ar.h lzh.h options.h zoo.h encode.obj : ar.h errors.i lzh.h encode.obj : options.h zoo.h fiz.obj : options.h portable.h various.h zoo.h zoofns.h fiz.obj : zooio.h getfile.obj : options.h various.h zoo.h zoofns.h zooio.h getfile.obj : zoomem.h huf.obj : ar.h errors.i lzh.h options.h zoo.h io.obj : ar.h errors.i lzh.h options.h portable.h zoo.h io.obj : zooio.h lzc.obj : assert.h debug.h lzconst.h options.h various.h lzc.obj : zoo.h zoofns.h zooio.h zoomem.h lzd.obj : assert.h debug.h lzconst.h options.h various.h lzd.obj : zoo.h zoofns.h zooio.h zoomem.h lzh.obj : ar.h errors.i options.h zoo.h machine.obj : options.h various.h zoo.h zoofns.h zooio.h makelist.obj : assert.h debug.h errors.i options.h makelist.obj : portable.h various.h zoo.h zoofns.h zooio.h maketbl.obj : ar.h lzh.h options.h zoo.h maketree.obj : ar.h lzh.h options.h zoo.h misc.obj : errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h misc2.obj : errors.i options.h portable.h various.h zoo.h misc2.obj : zoofns.h zooio.h zoomem.h msdos.obj : errors.i options.h zoo.h zoofns.h zooio.h needed.obj : debug.h options.h portable.h various.h zoo.h needed.obj : zoofns.h zooio.h nextfile.obj : options.h various.h zoo.h options.obj : errors.i options.h various.h zoo.h zoofns.h options.obj : zooio.h parse.obj : assert.h options.h parse.h various.h zoo.h parse.obj : zoofns.h zooio.h portable.obj : assert.h debug.h machine.h options.h portable.obj : portable.h various.h zoo.h zoofns.h zooio.h prterror.obj : options.h various.h prterror.obj : zoofns.h zooio.h zoo.obj : errors.i options.h various.h zoo.h zoofns.h zoo.obj : zooio.h zoomem.h zooadd.obj : debug.h errors.i options.h parse.h portable.h zooadd.obj : various.h zoo.h zoofns.h zooio.h zoomem.h zooadd2.obj : assert.h debug.h errors.i options.h parse.h zooadd2.obj : various.h zoo.h zoofns.h zooio.h zoodel.obj : errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h zooext.obj : errors.i machine.h options.h parse.h portable.h various.h zoo.h zooext.obj : zoofns.h zooio.h zoofilt.obj : options.h zoolist.obj : errors.i options.h portable.h various.h zoo.h zoolist.obj : zoofns.h zooio.h zoomem.h zoopack.obj : errors.i options.h portable.h various.h zoopack.obj : zoo.h zoofns.h zooio.h zoo-2.10.orig/encode.c100644 1750 1750 16174 5035113600 13326 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/encode.c,v $*/ /*$Id: encode.c,v 1.41 91/07/09 01:39:47 dhesi Exp $*/ /* Adapted from "ar" archiver written by Haruhiko Okumura. */ #include "options.h" #include "zoo.h" #include "ar.h" #include "lzh.h" extern void prterror(); extern char *out_buf_adr; #include #ifdef ANSI_HDRS # include # include #endif #include "errors.i" FILE *lzh_infile; FILE *lzh_outfile; /* sliding dictionary with percolating update */ #define PERCOLATE 1 #define NIL 0 #define MAX_HASH_VAL (3 * DICSIZ + (DICSIZ / 512 + 1) * UCHAR_MAX) typedef short node; static uchar *text, *childcount; static node pos, matchpos, avail, *position, *parent, *prev, *next = NULL; static int remainder, matchlen; #if MAXMATCH <= (UCHAR_MAX + 1) static uchar *level; # define T_LEVEL uchar * #else static ushort *level; # define T_LEVEL ushort * #endif static void allocate_memory() { if (next != NULL) return; /* text = (uchar *) malloc(DICSIZ * 2 + MAXMATCH); */ text = (uchar *) out_buf_adr; /* reuse I/O buffer used elsewhere */ level = (T_LEVEL) malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*level)); childcount = (uchar *)malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*childcount)); #ifdef PERCOLATE position = (node *) malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*position)); #else position = (node *) malloc(DICSIZ * sizeof(*position)); #endif parent = (node *) malloc(DICSIZ * 2 * sizeof(*parent)); prev = (node *) malloc(DICSIZ * 2 * sizeof(*prev)); next = (node *) malloc((MAX_HASH_VAL + 1) * sizeof(*next)); if (next == NULL) prterror('f', no_memory); } static void init_slide() { node i; for (i = DICSIZ; i <= DICSIZ + UCHAR_MAX; i++) { level[i] = 1; #ifdef PERCOLATE position[i] = NIL; /* sentinel */ #endif } for (i = DICSIZ; i < DICSIZ * 2; i++) parent[i] = NIL; avail = 1; for (i = 1; i < DICSIZ - 1; i++) next[i] = i + 1; next[DICSIZ - 1] = NIL; for (i = DICSIZ * 2; i <= MAX_HASH_VAL; i++) next[i] = NIL; } #define HASH(p, c) ((p) + ((c) << (DICBIT - 9)) + DICSIZ * 2) static node child(q, c) node q; uchar c; /* q's child for character c (NIL if not found) */ { node r; r = next[HASH(q, c)]; parent[NIL] = q; /* sentinel */ while (parent[r] != q) r = next[r]; return r; } static void makechild(q, c, r) node q; uchar c; node r; /* Let r be q's child for character c. */ { node h, t; h = HASH(q, c); t = next[h]; next[h] = r; next[r] = t; prev[t] = r; prev[r] = h; parent[r] = q; childcount[q]++; } void split(old) node old; { node new, t; new = avail; avail = next[new]; childcount[new] = 0; t = prev[old]; prev[new] = t; next[t] = new; t = next[old]; next[new] = t; prev[t] = new; parent[new] = parent[old]; level[new] = matchlen; position[new] = pos; makechild(new, text[matchpos + matchlen], old); makechild(new, text[pos + matchlen], pos); } static void insert_node() { node q, r, j, t; uchar c, *t1, *t2; if (matchlen >= 4) { matchlen--; r = (matchpos + 1) | DICSIZ; while ((q = parent[r]) == NIL) r = next[r]; while (level[q] >= matchlen) { r = q; q = parent[q]; } #ifdef PERCOLATE t = q; while (position[t] < 0) { position[t] = pos; t = parent[t]; } if (t < DICSIZ) position[t] = pos | PERC_FLAG; #else t = q; while (t < DICSIZ) { position[t] = pos; t = parent[t]; } #endif } else { q = text[pos] + DICSIZ; c = text[pos + 1]; if ((r = child(q, c)) == NIL) { makechild(q, c, pos); matchlen = 1; return; } matchlen = 2; } for ( ; ; ) { if (r >= DICSIZ) { j = MAXMATCH; matchpos = r; } else { j = level[r]; matchpos = position[r] & ~PERC_FLAG; } if (matchpos >= pos) matchpos -= DICSIZ; t1 = &text[pos + matchlen]; t2 = &text[matchpos + matchlen]; while (matchlen < j) { if (*t1 != *t2) { split(r); return; } matchlen++; t1++; t2++; } if (matchlen >= MAXMATCH) break; position[r] = pos; q = r; if ((r = child(q, *t1)) == NIL) { makechild(q, *t1, pos); return; } matchlen++; } t = prev[r]; prev[pos] = t; next[t] = pos; t = next[r]; next[pos] = t; prev[t] = pos; parent[pos] = q; parent[r] = NIL; next[r] = pos; /* special use of next[] */ } static void delete_node() { #ifdef PERCOLATE node q, r, s, t, u; #else node r, s, t, u; #endif if (parent[pos] == NIL) return; r = prev[pos]; s = next[pos]; next[r] = s; prev[s] = r; r = parent[pos]; parent[pos] = NIL; if (r >= DICSIZ || --childcount[r] > 1) return; #ifdef PERCOLATE t = position[r] & ~PERC_FLAG; #else t = position[r]; #endif if (t >= pos) t -= DICSIZ; #ifdef PERCOLATE s = t; q = parent[r]; while ((u = position[q]) & PERC_FLAG) { u &= ~PERC_FLAG; if (u >= pos) u -= DICSIZ; if (u > s) s = u; position[q] = (s | DICSIZ); q = parent[q]; } if (q < DICSIZ) { if (u >= pos) u -= DICSIZ; if (u > s) s = u; position[q] = s | DICSIZ | PERC_FLAG; } #endif s = child(r, text[t + level[r]]); t = prev[s]; u = next[s]; next[t] = u; prev[u] = t; t = prev[r]; next[t] = s; prev[s] = t; t = next[r]; prev[t] = s; next[s] = t; parent[s] = parent[r]; parent[r] = NIL; next[r] = avail; avail = r; } static void get_next_match() { int n; remainder--; if (++pos == DICSIZ * 2) { #ifdef CHECK_BREAK check_break(); #endif (void) MOVE_LEFT((char *) &text[0], (char *) &text[DICSIZ], DICSIZ + MAXMATCH); n = fread_crc(&text[DICSIZ + MAXMATCH], DICSIZ, lzh_infile); remainder += n; pos = DICSIZ; #ifdef SHOW_DOTS (void) putc('.', stderr); (void) fflush(stderr); #endif } delete_node(); insert_node(); } /* read from infile, compress, write to outfile */ void encode(infile, outfile) FILE *infile; FILE *outfile; { int lastmatchlen; node lastmatchpos; /* make input/output files visible to other functions */ lzh_infile = infile; lzh_outfile = outfile; allocate_memory(); init_slide(); huf_encode_start(); remainder = fread_crc(&text[DICSIZ], DICSIZ + MAXMATCH, lzh_infile); #ifdef SHOW_DOTS (void) putc('.', stderr); (void) fflush(stderr); #endif matchlen = 0; pos = DICSIZ; insert_node(); if (matchlen > remainder) matchlen = remainder; while (remainder > 0 && ! unpackable) { lastmatchlen = matchlen; lastmatchpos = matchpos; get_next_match(); if (matchlen > remainder) matchlen = remainder; if (matchlen > lastmatchlen || lastmatchlen < THRESHOLD) { #if 0 d1log("%c", text[pos-1]); #endif output(text[pos - 1], 0); } else { #if 0 (void) putc('.', stderr); (void) fflush(stderr); #endif #if 0 { int i; d1log("\nlastmatchlen=%d, pos=%d, lastmatchpos=%d", lastmatchlen, pos, lastmatchpos); d1log("\n[%d: ", (int) lastmatchlen); for (i = 0; i < lastmatchlen; i++) d1log("%c", text[lastmatchpos + i]); d1log("]\n"); } #endif output((uint) (lastmatchlen + (UCHAR_MAX + 1 - THRESHOLD)), (uint) ((pos - lastmatchpos - 2) & (DICSIZ - 1))); while (--lastmatchlen > 0) get_next_match(); if (matchlen > remainder) matchlen = remainder; } } huf_encode_end(); } #ifdef NEED_MEMMOVE /* like memmove, but for moving stuff LEFT (downwards in memory) only!! */ void move_left(dest, src, len) char *dest; char *src; int len; { while (len-- > 0) *dest++ = *src++; } #endif /* NEED_MEMMOVE */ zoo-2.10.orig/errors.i100644 1750 1750 1471 5035113600 13365 0ustar jamesjames/* @(#) errors.i 2.4 88/01/31 12:32:46 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ /* defines all the errors as externs. Declarations must be equivalent to those in prterror.c */ /* These declarations must be equivalent to those in prterror.c */ extern char no_match[]; extern char failed_consistency[]; extern char invalid_header[]; extern char internal_error[]; extern char disk_full[]; extern char bad_directory[]; extern char no_memory[]; extern char too_many_files[]; extern char packfirst[]; extern char garbled[]; extern char start_ofs[]; #ifndef OOZ extern char wrong_version[]; extern char cant_process[]; extern char option_ignored[]; extern char inv_option[]; extern char bad_crc[]; #endif extern char could_not_open[]; zoo-2.10.orig/file.fix100644 1750 1750 3426 5035113600 13330 0ustar jamesjames Making the "file" command recognize zoo archives Zoo archives have the following magic number: Beginning at offset 20 decimal, there are four bytes with the values 0xdc, 0xa7, 0xc4, and 0xfd. (But if you call the first byte of a zoo archive byte 1, then the magic bytes will be bytes 21 through 24.) To make the "file" command identify zoo archives, changes can be made as follows. 4.3BSD: See the context diff near the end of this document, suitable for application with the "patch" utility, that works with the 4.3BSD "file" command on a VAX-11/785. I don't know if this will also work under 4.2BSD or with any other implementation of the "file" command or on any other CPU. System V Release 2 (as exemplified by Microport System V/AT): At the end of the file "/etc/magic", add the following line: 20 long 0xfdc4a7dc zoo archive This should work on a little-endian machine, in which the long value 0xfdc4a7dc is stored with the least-significant byte first. For a big- endian machine, you will probably need to replace it with 0xdca7c4fd. This assumes that long occupies 4 bytes. If not, use a data type name that is exactly 4 bytes. ===== Changes needed to make the 4.3BSD "file" command recognize zoo archives. Known to work on a VAX-11/785. *** file.c.old Thu Mar 6 19:34:29 1986 --- file.c Sat Feb 21 19:28:52 1987 *************** *** 172,181 **** --- 172,187 ---- case 070707: printf("cpio data\n"); return; } + if (buf[20] == (char) 0xdc && buf[21] == (char) 0xa7 && + buf[22] == (char) 0xc4 && buf[23] == (char) 0xfd) { + printf ("zoo archive\n"); + return; + } + if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf)) return; if (buf[0] == '\037' && buf[1] == '\235') { if (buf[2]&0x80) printf("block "); zoo-2.10.orig/fiz.1100644 1750 1750 7411 5035113600 12551 0ustar jamesjames.\" @(#) fiz.1 1.2 88/01/31 23:22:04 .\" .\" For formatting with nroff: .\" nroff -man fiz.1 .\" .TH FIZ 1 "Jan 31, 1988" .SH NAME fiz \- analyze damaged zoo archive for data revovery .SH SYNOPSIS .I fiz .RB archive[ .zoo ] .SH DESCRIPTION .I Fiz is used to analyze damaged .I zoo archives and locate directory entries and file data in them. The current version of .I fiz is 2.0 and it is meant to be used in conjunction with .I zoo version 2.0. .I Fiz makes no assumptions about archive structure. Instead, it simply searches the entire subject archive for tag values that mark the locations of directory entries and file data. In a .I zoo archive, a .I directory entry contains information about a stored file such as its name, whether compressed or not, and its timestamp. The .I file data are the actual data for the archived file, and may be either the original data, or the result of compressing the file. .PP For each directory entry found, .I fiz prints where in the archive it is located, the directory path and filename(s) found in it, whether the directory entry appears to be corrupted (indicated by [*CRC Error*]), and the value of the pointer to the file data that is found in the directory entry. For each block of file data found in the archive, .I fiz prints where in the archive the block begins. In the case of an undamaged archive, the pointer to file data found in a directory entry will correspond to where .I fiz actually locates the data. Here is some sample output from .I fiz: .PP .nf **************** 2526: DIR [changes] ==> 95 2587: DATA **************** 3909: DIR [copyrite] ==> 1478 3970: DATA 4769: DATA **************** .fi .sp 1 In such output, .B DIR indicates where .I fiz found a directory entry in the archive, and .B DATA indicates where .I fiz found file data in the archive. Filenames located by .I fiz are enclosed in square brackets, and the notation "==> 95" indicates that the directory entry found by .I fiz at position 2526 has a file data pointer to position 95. In actuality, .I fiz found file data at positions 2587, 3970, and 4769. Since .I fiz found only two directory entries, and each directory entry corresponds to one file, one of the file data positions is an artifact. .PP Once the locations of directory entries and file data are found, the .B @ modifier to .I "zoo's" archive list and extract commands can be used and the archive contents selectively listed or extracted, skipping the damaged portion. This is further described in the documentation for .I zoo(1). .PP In the above case, commands to try giving to .I zoo might be .B x@2526,2587 (extract beginning at position 2526, and get file data from position 2587), .B x@3090,3970 (extract at 3090, get data from 3970) and .B x@3909,4769 (extract at 3909, get data from 4769). Once a correctly-matched directory entry/file data pair is found, .I zoo will in most cases synchronize with and correctly extract all files subsequently found in the archive. Trial and error should allow all undamaged files to be extracted. Also note that self-extracting archives created using .I sez (the Self-Extracting .I Zoo utility for MS-DOS), which are normally executed on an MS-DOS system for extraction, can be extracted on non-MSDOS systems in a similar way. .PP .SH "SEE ALSO" zoo(1) .SH BUGS Random byte patterns can occasionally be incorrectly recognized as tag values. This occurs very rarely, however, and trial and error will usually permit all undamaged data to be extracted. .SH DIAGNOSTICS .I Fiz always exits with a status code of 0. .SH "FUTURE DIRECTIONS" Automation of data recovery from a damaged archive is potentially achievable. However, since damaged archives occur only rarely, .I fiz as it currently stands is unlikely to change much in the near future. .SH AUTHOR Rahul Dhesi zoo-2.10.orig/fiz.c100644 1750 1750 15200 5035113600 12646 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) fiz.c 2.6 88/01/31 23:23:50"; #endif /* LINT */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1987/02/06 */ /* Searches for all directory entries in an archive and prints their offsets. Zoo 1.41 and later may then be asked to extract a specific file by supplying the offset of the file. */ #include "options.h" #include "zooio.h" #include "various.h" #include "zoofns.h" #include "portable.h" /* I/O definitions */ #include "zoo.h" void prtctrl (); void prtch (); main(argc,argv) register int argc; register char **argv; { char *zooname; /* name of archive to be read */ ZOOFILE zoo_file; /* the archive being examined opened for read */ int state; /* to keep track of how much of tag seen */ int inch; /* char just read from archive */ static char usage1[] = "Fiz 2.0 (1987/02/01) public domain Zoo archive repair utility by Rahul Dhesi\n"; static char usage2[] = "Usage: fiz archive[.zoo] (\"fiz -h\" for help)\n"; #ifdef SETBUF /* set stdout to unbuffered */ setbuf (stdout, (char *) NULL); #endif if (argc < 2) { printf("%s%s", usage1, usage2); exit (1); } if (strcmp(argv[1],"-h") == 0) goto givehelp; zooname = argv[1]; /* Add default extension if none supplied */ { char *p, *q; p = zooname + strlen(zooname); /* point to last char */ while (p != zooname && *p != EXT_CH) --p; /* either found EXT_CH or reached beginning of zooname */ if (*p != EXT_CH) { q = malloc(strlen(zooname) + strlen(EXT_DFLT) + 2); if (q == NULL) { printf("Fiz: Ran out of memory.\n"); exit(1); } strcpy(q, zooname); strcat(q, EXT_DFLT); zooname = q; } } zoo_file = zooopen (zooname, Z_READ); if (zoo_file == NOFILE) { printf("Fiz: FATAL: Could not open %s.\n", zooname); exit(1); } #ifdef DOUBLE_SECRET { void oh_well(void); oh_well(); } #endif #define NOSTATE 1 #define HDR_1 0xdc #define HDR_2 0xa7 #define HDR_3 0xc4 #define HDR_4 0xfd #define DAT_1 '@' #define DAT_2 ')' #define DAT_3 '#' #define DAT_4 '(' /* finite state machine implemented here by hand */ state = NOSTATE; while ((inch = zgetc(zoo_file)) != EOF) { inch = inch & 0xff; if (state == NOSTATE) { if (inch == HDR_1) state = HDR_1; else if (inch == DAT_1) state = DAT_1; } else if (state == HDR_1 && inch == HDR_2) state = HDR_2; else if (state == HDR_2 && inch == HDR_3) state = HDR_3; else if (state == HDR_3 && inch == HDR_4) state = HDR_4; else if (state == DAT_1 && inch == DAT_2) state = DAT_2; else if (state == DAT_2 && inch == DAT_3) state = DAT_3; else if (state == DAT_3 && inch == DAT_4) state = DAT_4; else state = NOSTATE; if (state == HDR_4) { /* found archive tag */ long save_pos; struct direntry direntry; save_pos = zootell(zoo_file); zooseek(zoo_file, save_pos-4L, 0); /* back to tag pos */ frd_dir(&direntry, zoo_file); /* read dir entry */ printf("****************\n"); printf ("%8lu: DIR ", save_pos-4L); if (direntry.dirlen > 0) { printf ("["); prtctrl (direntry.dirname); printf ("]"); } printf(" ["); prtctrl (direntry.fname); printf ("]"); if (direntry.namlen > 0) { printf (" ["); prtctrl (direntry.lfname); printf ("]"); } printf (" ==> %4lu", direntry.offset); if (direntry.dir_crc != 0) printf (" [*bad CRC*]"); printf ("\n"); fseek (zoo_file, save_pos, 0); /* try again from there */ } else if (state == DAT_4) { /* file data */ printf ("%8lu: DATA\n", zootell(zoo_file) + 1); } } exit (0); /* don't fall through */ givehelp: /* vi macros: to add printf: :s/^.*$/printf("&\\n");/ To remove printf: :s/^printf("\(.*\)\\n");/\1/ */ printf("Fiz is used to help you recover data from a damaged archive. Fiz searches\n"); printf("the specified archive for directory entries and stored files, and prints the\n"); printf("position of each one found. Each directory entry contains a number that\n"); printf("represents the location in the archive where the file is stored; fiz also\n"); printf("prints this position. All numbers printed are decimal numbers.\n\n"); printf("Use Zoo version 2.00 or higher to list or extract files in the damaged\n"); printf("archive starting at a position identified by fiz. For example, you can\n"); printf("start extracting files from archive \"badarc.zoo\" at position 1098 with the\n"); printf("command:\n\n"); printf(" zoo x@1098 badarc\n\n"); printf("Zoo will ignore the first 1098 bytes of the damaged archive and you should be\n"); printf("able to recover the undamaged files from the rest of the archive. You can\n"); printf("also manually specify where to look for the file data with a command like\n\n"); printf(" zoo x@1098,1153\n\n"); printf("which tells zoo to use the directory entry at position 1098, but to get the\n"); printf("actual file data from position 1153 (and not from where the directory entry\n"); printf("says the data ought to be). See the manuals for fiz and zoo for more details.\n"); exit (0); } /* prtctrl() prints a string with all unprintable characters converted to printable form. To avoid the program running astray trying to print damaged data, no more than MAXPRT characters are printed. Characters with the 8th bit set are printed preceded with ~. Control characters are printed preceded with ^. Both ~ and ^ may preced the character if a control character has the 8th bit set. */ #define MAXPRT 50 void prtctrl (str) char *str; { unsigned int ch; int count; count = 0; while (count < MAXPRT && *str != '\0') { ch = (unsigned) *str; prtch(ch); str++; count++; } } /* Does the actual character printing for prtctrl() */ void prtch(ch) unsigned int ch; { /* assumes ASCII character set */ if (ch < ' ') { /* ^@ through ^_ */ printf("^%c", ch + 0x40); } else if (ch == 0x7f) { /* DEL */ printf("^?"); } else if (ch > 0x7f) { /* 8th bit set */ printf("~"); /* .. so precede with ~ */ prtch(ch & 0x7f); /* slick recursive call */ } else printf("%c", ch); /* plain char */ } zoo-2.10.orig/fiz.man100644 1750 1750 10203 5035113600 13175 0ustar jamesjames FIZ(1) **IX Programmer's Manual FIZ(1) NAME fiz - analyze damaged zoo archive for data revovery SYNOPSIS fiz archive[.zoo] DESCRIPTION Fiz is used to analyze damaged zoo archives and locate directory entries and file data in them. The current ver- sion of fiz is 2.0 and it is meant to be used in conjunction with zoo version 2.0. Fiz makes no assumptions about archive structure. Instead, it simply searches the entire subject archive for tag values that mark the locations of directory entries and file data. In a zoo archive, a direc- tory entry contains information about a stored file such as its name, whether compressed or not, and its timestamp. The file data are the actual data for the archived file, and may be either the original data, or the result of compressing the file. For each directory entry found, fiz prints where in the archive it is located, the directory path and filename(s) found in it, whether the directory entry appears to be cor- rupted (indicated by [*CRC Error*]), and the value of the pointer to the file data that is found in the directory entry. For each block of file data found in the archive, fiz prints where in the archive the block begins. In the case of an undamaged archive, the pointer to file data found in a directory entry will correspond to where fiz actually locates the data. Here is some sample output from fiz: **************** 2526: DIR [changes] ==> 95 2587: DATA **************** 3909: DIR [copyrite] ==> 1478 3970: DATA 4769: DATA **************** In such output, DIR indicates where fiz found a directory entry in the archive, and DATA indicates where fiz found file data in the archive. Filenames located by fiz are enclosed in square brackets, and the notation "==> 95" indicates that the directory entry found by fiz at position 2526 has a file data pointer to position 95. In actuality, fiz found file data at positions 2587, 3970, and 4769. Since fiz found only two directory entries, and each direc- tory entry corresponds to one file, one of the file data positions is an artifact. Printed 2/7/88 Jan 31, 1988 1 FIZ(1) **IX Programmer's Manual FIZ(1) Once the locations of directory entries and file data are found, the @ modifier to zoo's archive list and extract com- mands can be used and the archive contents selectively listed or extracted, skipping the damaged portion. This is further described in the documentation for zoo(1). In the above case, commands to try giving to zoo might be x@2526,2587 (extract beginning at position 2526, and get file data from position 2587), x@3090,3970 (extract at 3090, get data from 3970) and x@3909,4769 (extract at 3909, get data from 4769). Once a correctly-matched directory entry/file data pair is found, zoo will in most cases syn- chronize with and correctly extract all files subsequently found in the archive. Trial and error should allow all undamaged files to be extracted. Also note that self- extracting archives created using sez (the Self-Extracting Zoo utility for MS-DOS), which are normally executed on an MS-DOS system for extraction, can be extracted on non-MSDOS systems in a similar way. SEE ALSO zoo(1) BUGS Random byte patterns can occasionally be incorrectly recog- nized as tag values. This occurs very rarely, however, and trial and error will usually permit all undamaged data to be extracted. DIAGNOSTICS Fiz always exits with a status code of 0. FUTURE DIRECTIONS Automation of data recovery from a damaged archive is poten- tially achievable. However, since damaged archives occur only rarely, fiz as it currently stands is unlikely to change much in the near future. AUTHOR Rahul Dhesi Printed 2/7/88 Jan 31, 1988 2 zoo-2.10.orig/generic.c100644 1750 1750 4566 5035113600 13467 0ustar jamesjames#ifndef LINT static char genericid[]="@(#) generic.c 2.2 88/01/24 12:44:03"; #endif /* LINT */ /* Generic template for machine-dependent functions. The contents of this file are hereby released to the public domain -- Rahul Dhesi 1991/07/05 */ /**************** Date and time functions are assumed to be standard **IX-style functions. */ #include #include #include /* Function isadir() returns 1 if the supplied handle is a directory, else it returns 0. */ int isadir (file) ZOOFILE file; { int handle = fileno(file); struct stat buf; /* buffer to hold file information */ if (fstat (handle, &buf) == -1) { return (0); /* inaccessible -- assume not dir */ } else { if (buf.st_mode & S_IFDIR) return (1); else return (0); } } /**************** Function fixfname() converts the supplied filename to a syntax legal for the host system. It is used during extraction. */ char *fixfname(fname) char *fname; { fname[FNLIMIT] = '\0'; /* Just truncate at filename size limit */ return fname; } /* The function gettz() returns the offset from GMT in seconds, taking into account the local timezone and any daylight savings time. */ /* This version of gettz should be portable to all Unices, although it can't be described as elegant. Users immediately west of the International Date Line (Polynesia, Soviet Far East) may get times out by 24 hours. Contributed by: Ian Phillipps */ long gettz() { #define NOONOFFSET 43200 #define SEC_IN_DAY (24L * 60L * 60L) #define INV_VALUE (SEC_IN_DAY + 1L) static long retval = INV_VALUE; /* cache, init to impossible value */ extern long time(); extern struct tm *localtime(); long now; long noon; struct tm *noontm; if (retval != INV_VALUE) /* if have cached value, return it */ return retval; now = time((long *) 0); /* Find local time for GMT noon today */ noon = now - now % SEC_IN_DAY + NOONOFFSET ; noontm = localtime( &noon ); retval = NOONOFFSET - 60 * ( 60 * noontm->tm_hour - noontm->tm_min ); return retval; #undef NOONOFFSET } /* Standard UNIX-compatible time functions */ #include "nixtime.i" /* Standard UNIX-specific file attribute routines */ #include "nixmode.i" /* Assume no file truncate system call. Ok to be a no-op. */ /*ARGSUSED*/ int zootrunc(f) FILE *f; { return 0; } zoo-2.10.orig/getfile.c100644 1750 1750 10705 5035113600 13502 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) getfile.c 2.7 88/01/24 12:44:23"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* This function copies n characters from the source file to the destination Input: out_f: destination file in_f: source file count: count of characters to copy docrc: 0 if crc not wanted If count is -1, copying is done until eof is encountered. The source file is transferred to the current file pointer position in the destination file, using the handles provided. Function return value is 0 if no error, 2 if write error, and 3 if read error. If docrc is not 0, the global variable crccode is updated via addbfcrc(). This is done even if the output is to the null device. If UNBUF_IO is defined, and if more than UNBUF_LIMIT bytes are being transferred or copying is to end of file, the data transfer is done using low-level read() and write() functions, which must be defined elsewhere. File descriptors are obtained for this purpose using the fileno() macro, which must be provided elsewhere too. This is meant to provide greater efficiency on some systems. The files of type ZOOFILE are synchronized with their file descriptors by doing a reasonable number of seeks and other miscellaneous operations before and after the transfer. Such simultaneous use of buffered and unbuffered files is not portable and should not be used without extensive testing. */ #ifdef UNBUF_IO int read PARMS ((int, VOIDPTR, unsigned)); int write PARMS ((int, VOIDPTR, unsigned)); long lseek PARMS ((int, long, int)); long tell PARMS ((int)); #endif /* UNBUF_IO */ #include "zoo.h" /* satisfy declarations in zooio.h */ #include "zooio.h" #include "various.h" #include "zoofns.h" #include "zoomem.h" int getfile (in_f, out_f, count, docrc) ZOOFILE in_f, out_f; long count; int docrc; { register int how_much; #ifdef UNBUF_IO int in_d, out_d; /* file descriptors for unbuffered I/O */ #endif /* UNBUF_IO */ #ifdef UNBUF_IO if (out_f != NULLFILE && (count == -1 || count > UNBUF_LIMIT)) { in_d = fileno (in_f); /* get .. */ out_d = fileno (out_f); /* ... file descriptors */ /* Synchronize buffered and unbuffered files */ zooseek (in_f, zootell (in_f), 0); zooseek (out_f, zootell (out_f), 0); #if 0 lseek (in_d, zootell (in_f), 0); lseek (out_d, zootell (out_f), 0); #endif if (count == -1) { while ((how_much = read (in_d, out_buf_adr, MEM_BLOCK_SIZE)) > 0) { if (how_much == -1 || write (out_d, out_buf_adr, how_much) != how_much) return (2); if (docrc) addbfcrc (out_buf_adr,how_much); } zooseek (in_f, tell (in_d), 0); /* resynch */ zooseek (out_f, tell (out_d), 0); /* resynch */ #ifndef NDEBUG if (ftell (in_f) != tell (in_d) || ftell (out_f) != tell (out_d)) { prterror ('w', "seek mismatch in copy to EOF\n"); printf ("in_f =%6ld, in_d =%6ld\n", ftell (in_f), tell (in_d)); printf ("out_f=%6ld, out_d=%6ld\n", ftell (out_f), tell (out_d)); } #endif /* NDEBUG */ return (0); } while (count > 0) { if (count > MEM_BLOCK_SIZE) how_much = MEM_BLOCK_SIZE; else how_much = (int) count; count -= how_much; if (read (in_d, out_buf_adr, how_much) != how_much) return (3); if (docrc) addbfcrc (out_buf_adr, how_much); if (write (out_d, out_buf_adr, how_much) != how_much) return (2); } zooseek (in_f, tell (in_d), 0); /* resynch */ zooseek (out_f, tell (out_d), 0); /* resynch */ #ifndef NDEBUG if (ftell (in_f) != tell (in_d) || ftell (out_f) != tell (out_d)) prterror ('w', "seek mismatch in fixed length copy\n"); #endif /* NDEBUG */ return (0); } #endif /* UNBUF_IO */ if (count == -1) { while ((how_much = zooread (in_f, out_buf_adr, MEM_BLOCK_SIZE)) > 0) { if (how_much == -1 || zoowrite (out_f, out_buf_adr, how_much) != how_much) return (2); if (docrc) addbfcrc (out_buf_adr,how_much); } return (0); } while (count > 0) { if (count > MEM_BLOCK_SIZE) how_much = MEM_BLOCK_SIZE; else how_much = (int) count; count -= how_much; if (zooread (in_f, out_buf_adr, how_much) != how_much) return (3); if (docrc) addbfcrc (out_buf_adr, how_much); if (zoowrite (out_f, out_buf_adr, how_much) != how_much) return (2); } return (0); } zoo-2.10.orig/huf.c100644 1750 1750 17115 5035113600 12647 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/huf.c,v $*/ /*$Id: huf.c,v 1.9 91/07/09 01:39:55 dhesi Exp $*/ /*********************************************************** huf.c -- static Huffman Adapted from "ar" archiver written by Haruhiko Okumura. ***********************************************************/ #include "options.h" #include "zoo.h" #include "ar.h" #include "lzh.h" #include "errors.i" extern void prterror(); #ifdef ANSI_HDRS # include #endif #define NP (DICBIT + 1) #define NT (CODE_BIT + 3) #define PBIT 4 /* smallest integer such that (1U << PBIT) > NP */ #define TBIT 5 /* smallest integer such that (1U << TBIT) > NT */ #if NT > NP # define NPT NT #else # define NPT NP #endif int decoded; /* for use in decode.c */ ushort left[2 * NC - 1], right[2 * NC - 1]; static uchar *buf, c_len[NC], pt_len[NPT]; static uint bufsiz = 0, blocksize; static ushort c_freq[2 * NC - 1], c_table[4096], c_code[NC], p_freq[2 * NP - 1], pt_table[256], pt_code[NPT], t_freq[2 * NT - 1]; /***** encoding *****/ static void count_t_freq() { int i, k, n, count; for (i = 0; i < NT; i++) t_freq[i] = 0; n = NC; while (n > 0 && c_len[n - 1] == 0) n--; i = 0; while (i < n) { k = c_len[i++]; if (k == 0) { count = 1; while (i < n && c_len[i] == 0) { i++; count++; } if (count <= 2) t_freq[0] += count; else if (count <= 18) t_freq[1]++; else if (count == 19) { t_freq[0]++; t_freq[1]++; } else t_freq[2]++; } else t_freq[k + 2]++; } } static void write_pt_len(n, nbit, i_special) int n; int nbit; int i_special; { int i, k; while (n > 0 && pt_len[n - 1] == 0) n--; putbits(nbit, (uint) n); i = 0; while (i < n) { k = pt_len[i++]; if (k <= 6) putbits(3, (uint) k); else putbits(k - 3, (uint) (((unsigned) 1 << (k - 3)) - 2)); if (i == i_special) { while (i < 6 && pt_len[i] == 0) i++; putbits(2, (uint) ((i - 3) & 3)); } } } static void write_c_len() { int i, k, n, count; n = NC; while (n > 0 && c_len[n - 1] == 0) n--; putbits(CBIT, (uint) n); i = 0; while (i < n) { k = c_len[i++]; if (k == 0) { count = 1; while (i < n && c_len[i] == 0) { i++; count++; } if (count <= 2) { for (k = 0; k < count; k++) putbits((int) pt_len[0], (uint) pt_code[0]); } else if (count <= 18) { putbits((int) pt_len[1], (uint) pt_code[1]); putbits(4, (uint) (count - 3)); } else if (count == 19) { putbits((int) pt_len[0], (uint) pt_code[0]); putbits((int) pt_len[1], (uint) pt_code[1]); putbits(4, 15); } else { putbits((int) pt_len[2], (uint) pt_code[2]); putbits(CBIT, (uint) (count - 20)); } } else putbits((int) pt_len[k + 2], (uint) pt_code[k + 2]); } } static void encode_c(c) int c; { putbits((int) c_len[c], (uint) c_code[c]); } static void encode_p(p) uint p; { uint c, q; c = 0; q = p; while (q) { q >>= 1; c++; } putbits((int) pt_len[c], (uint) pt_code[c]); if (c > 1) putbits((int) (c - 1), (uint) (p & ((unsigned) 0xFFFF >> (17 - c)))); } static void send_block() { uint i, k, flags, root, pos, size; root = make_tree(NC, c_freq, c_len, c_code); size = c_freq[root]; #if 0 /*debug*/ (void) fprintf(stderr, "\nsize = %u\n", size); #endif putbits(16, size); if (root >= NC) { count_t_freq(); root = make_tree(NT, t_freq, pt_len, pt_code); if (root >= NT) { write_pt_len(NT, TBIT, 3); } else { putbits(TBIT, 0); putbits(TBIT, root); } write_c_len(); } else { putbits(TBIT, 0); putbits(TBIT, 0); putbits(CBIT, 0); putbits(CBIT, root); } root = make_tree(NP, p_freq, pt_len, pt_code); if (root >= NP) { write_pt_len(NP, PBIT, -1); } else { putbits(PBIT, 0); putbits(PBIT, root); } pos = 0; for (i = 0; i < size; i++) { if (i % CHAR_BIT == 0) flags = buf[pos++]; else flags <<= 1; if (flags & ((unsigned) 1 << (CHAR_BIT - 1))) { encode_c((int) (buf[pos++] + ((unsigned) 1 << CHAR_BIT))); k = buf[pos++] << CHAR_BIT; k += buf[pos++]; encode_p(k); } else encode_c((int) buf[pos++]); if (unpackable) return; } for (i = 0; i < NC; i++) c_freq[i] = 0; for (i = 0; i < NP; i++) p_freq[i] = 0; } static uint output_pos, output_mask; void output(c, p) uint c; uint p; { static uint cpos; if ((output_mask >>= 1) == 0) { output_mask = (unsigned) 1 << (CHAR_BIT - 1); if (output_pos >= bufsiz - 3 * CHAR_BIT) { send_block(); if (unpackable) return; output_pos = 0; } cpos = output_pos++; buf[cpos] = 0; } buf[output_pos++] = (uchar) c; c_freq[c]++; if (c >= ((unsigned) 1 << CHAR_BIT)) { buf[cpos] |= output_mask; buf[output_pos++] = (uchar)(p >> CHAR_BIT); buf[output_pos++] = (uchar) p; c = 0; while (p) { p >>= 1; c++; } p_freq[c]++; } } void huf_encode_start() { int i; if (bufsiz == 0) { bufsiz = 16 * (unsigned) 1024; while ((buf = (uchar *) malloc(bufsiz)) == NULL) { bufsiz = (bufsiz / (unsigned) 10) * (unsigned) 9; if (bufsiz < 4 * (unsigned) 1024) prterror('f', no_memory); } } buf[0] = 0; for (i = 0; i < NC; i++) c_freq[i] = 0; for (i = 0; i < NP; i++) p_freq[i] = 0; output_pos = output_mask = 0; init_putbits(); } void huf_encode_end() { if (! unpackable) { send_block(); putbits(CHAR_BIT - 1, 0); /* flush remaining bits */ putbits(16, 0); /* EOF marker */ } } /***** decoding *****/ static void read_pt_len(nn, nbit, i_special) int nn; int nbit; int i_special; { int i, c, n; uint mask; n = getbits(nbit); if (n == 0) { c = getbits(nbit); for (i = 0; i < nn; i++) pt_len[i] = 0; for (i = 0; i < 256; i++) pt_table[i] = c; } else { i = 0; while (i < n) { c = bitbuf >> (BITBUFSIZ - 3); if (c == 7) { mask = (unsigned) 1 << (BITBUFSIZ - 1 - 3); while (mask & bitbuf) { mask >>= 1; c++; } } fillbuf((c < 7) ? 3 : c - 3); pt_len[i++] = c; if (i == i_special) { c = getbits(2); while (--c >= 0) pt_len[i++] = 0; } } while (i < nn) pt_len[i++] = 0; make_table(nn, pt_len, 8, pt_table); } } static void read_c_len() { int i, c, n; uint mask; n = getbits(CBIT); if (n == 0) { c = getbits(CBIT); for (i = 0; i < NC; i++) c_len[i] = 0; for (i = 0; i < 4096; i++) c_table[i] = c; } else { i = 0; while (i < n) { c = pt_table[bitbuf >> (BITBUFSIZ - 8)]; if (c >= NT) { mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8); do { if (bitbuf & mask) c = right[c]; else c = left [c]; mask >>= 1; } while (c >= NT); } fillbuf((int) pt_len[c]); if (c <= 2) { if (c == 0) c = 1; else if (c == 1) c = getbits(4) + 3; else c = getbits(CBIT) + 20; while (--c >= 0) c_len[i++] = 0; } else c_len[i++] = c - 2; } while (i < NC) c_len[i++] = 0; make_table(NC, c_len, 12, c_table); } } uint decode_c() { uint j, mask; if (blocksize == 0) { blocksize = getbits(16); if (blocksize == 0) { #if 0 (void) fprintf(stderr, "block size = 0, decoded\n"); /* debug */ #endif decoded = 1; return 0; } read_pt_len(NT, TBIT, 3); read_c_len(); read_pt_len(NP, PBIT, -1); } blocksize--; j = c_table[bitbuf >> (BITBUFSIZ - 12)]; if (j >= NC) { mask = (unsigned) 1 << (BITBUFSIZ - 1 - 12); do { if (bitbuf & mask) j = right[j]; else j = left [j]; mask >>= 1; } while (j >= NC); } fillbuf((int) c_len[j]); return j; } uint decode_p() { uint j, mask; j = pt_table[bitbuf >> (BITBUFSIZ - 8)]; if (j >= NP) { mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8); do { if (bitbuf & mask) j = right[j]; else j = left [j]; mask >>= 1; } while (j >= NP); } fillbuf((int) pt_len[j]); if (j != 0) j = ((unsigned) 1 << (j - 1)) + getbits((int) (j - 1)); return j; } void huf_decode_start() { init_getbits(); blocksize = 0; } zoo-2.10.orig/io.c100644 1750 1750 5673 5035113600 12462 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/io.c,v $*/ /*$Id: io.c,v 1.14 91/07/09 01:39:54 dhesi Exp $*/ /*********************************************************** io.c -- input/output Adapted from "ar" archiver written by Haruhiko Okumura. ***********************************************************/ #ifdef ANSI_HDRS # include # include #endif #include "options.h" #include "zoo.h" #include "ar.h" #include "lzh.h" #include "zooio.h" /* for NULLFILE */ #include "portable.h" extern void prterror(); #include "errors.i" #define JUST_LZH /* for stand-alone compression */ #if 0 # define CRCPOLY 0xA001 /* ANSI CRC-16 */ /* CCITT: 0x8408 */ # define UPDATE_CRC(c) \ crc = crctable[(crc ^ (c)) & 0xFF] ^ (crc >> CHAR_BIT) static ushort crctable[UCHAR_MAX + 1]; t_uint16 crc; #endif extern FILE *arcfile, *lzh_outfile; t_uint16 bitbuf; int unpackable; ulong compsize, origsize; static uint subbitbuf; static int bitcount; #if 0 void make_crctable() { uint i, j, r; for (i = 0; i <= UCHAR_MAX; i++) { r = i; for (j = 0; j < CHAR_BIT; j++) if (r & 1) r = (r >> 1) ^ CRCPOLY; else r >>= 1; crctable[i] = r; } } #endif void fillbuf(n) /* Shift bitbuf n bits left, read n bits */ int n; { bitbuf <<= n; while (n > bitcount) { bitbuf |= subbitbuf << (n -= bitcount); #ifdef JUST_LZH if (feof(arcfile)) subbitbuf = 0; else subbitbuf = (uchar) zgetc(arcfile); #else if (compsize != 0) { compsize--; subbitbuf = (uchar) zgetc(arcfile); } else subbitbuf = 0; #endif /* JUST_LZH */ bitcount = CHAR_BIT; } bitbuf |= subbitbuf >> (bitcount -= n); } uint getbits(n) int n; { uint x; x = bitbuf >> (BITBUFSIZ - n); fillbuf(n); return x; } void putbits(n, x) /* Write rightmost n bits of x */ int n; uint x; { if (n < bitcount) { subbitbuf |= x << (bitcount -= n); } else { #ifdef JUST_LZH (void) putc((int) (subbitbuf | (x >> (n -= bitcount))), lzh_outfile); compsize++; #else if (compsize < origsize) { (void) zputc((int) (subbitbuf | (x >> (n -= bitcount))), lzh_outfile); compsize++; } else unpackable = 1; #endif /* JUST_LZH */ if (n < CHAR_BIT) { subbitbuf = x << (bitcount = CHAR_BIT - n); } else { #ifdef JUST_LZH (void) putc((int) (x >> (n - CHAR_BIT)), lzh_outfile); compsize++; #else if (compsize < origsize) { (void) zputc((int) (x >> (n - CHAR_BIT)), lzh_outfile); compsize++; } else unpackable = 1; #endif /* JUST_LZH */ subbitbuf = x << (bitcount = 2 * CHAR_BIT - n); } } } extern void addbfcrc(); int fread_crc(p, n, f) uchar *p; int n; FILE *f; { int i; i = n = fread((char *) p, 1, n, f); origsize += n; addbfcrc(p, i); return n; } void fwrite_crc(p, n, f) uchar *p; int n; FILE *f; { if (f != NULLFILE) { if (fwrite((char *) p, 1, n, f) < n) prterror('f', disk_full); } addbfcrc(p, n); } void init_getbits() { bitbuf = 0; subbitbuf = 0; bitcount = 0; fillbuf(BITBUFSIZ); } void init_putbits() { bitcount = CHAR_BIT; subbitbuf = 0; } zoo-2.10.orig/lzc.asm100644 1750 1750 27773 5035113600 13226 0ustar jamesjamestitle Lempel-Ziv Compressor ; $Source: /usr/home/dhesi/zoo/RCS/lzc.asm,v $ ; $Id: lzc.asm,v 1.4 91/07/07 09:36:18 dhesi Exp $ ;Derived from Tom Pfau's public domain assembly code. ;The contents of this file are hereby released to the public domain. ; -- Rahul Dhesi 1988/08/24 UNBUF_IO equ 1 ;use unbuffered I/O public _lzc include asmconst.ai include macros.ai check_gap equ 4000 ;Check ratio every so many bits scale_limit equ 32000 ;scale down if bitsout > scale_limit rat_thresh equ 0ffffh ;don't reset if rat > rat_thresh ;Hash table entry hash_rec struc first dw ? ; First entry with this value next dw ? ; Next entry along chain char db ? ; Suffix char hash_rec ends extrn docrc:near ;Procedure for block CRC in lzd.asm ifdef UNBUF_IO extrn _read:near extrn _blockwrite:near else extrn _zooread:near extrn _zoowrite:near endif ;Declare Segments _text segment byte public 'code' _text ends dgroup group _data assume ds:dgroup,es:dgroup _data segment word public 'data' extrn _out_buf_adr:word ;address of C output buffer extrn _in_buf_adr:word ;address of C input buffer extrn memflag:byte ;got memory? flag save_sp dw ? bytesin dw ? ;count of bytes read bitsout dw ? ;count of bits written ratio dw ? ;recent ratio ratflag db ? ;flag to remind us to check ratio bit_interval dw ? ;interval at which to test ratio input_handle dw ? output_handle dw ? hash_seg dw ? prefix_code dw ? free_code dw ? max_code dw ? nbits dw ? k db ? bit_offset dw ? input_offset dw 0 input_size dw 0 _data ends memory segment para public 'memory' hash label hash_rec memory ends add_code macro local ac1,ac2,ac3 mov bx,free_code ;Get code to use push ds ;point to hash table mov ds,hash_seg or di,di ;First use of this prefix? jz ac1 ;zero means yes mov [si].next,bx ;point last use to new entry jmp short ac2 ac1: mov [si].first,bx ;Point first use to new entry ac2: cmp bx,maxmax ;Have we reached code limit? je ac3 ;equal means yes, just return ;call index ;get address of new entry call_index ;macro for speed mov [si].first,-1 ;initialize pointers mov [si].next,-1 mov [si].char,al ;save suffix char inc es:free_code ;adjust next code ac3: pop ds ;restore seg reg endm read_char macro ;Macro for speed local m$1,m$2,m$3,m$4 inc [bytesin] ;Maintain input byte count for ratio mov di,input_offset ;Anything left in buffer? cmp di,input_size jb m$1 ;less means yes mov cx,inbufsiz call doread ;read block cmp ax,-1 jnz m$3 jmp IO_err ;input error m$3: mov dx,_in_buf_adr ;for docrc call docrc or ax,ax ;Anything left? jz m$2 ;zero means no, finished mov input_size,ax ;Save bytes read mov input_offset,0 ;Point to beginning of buffer mov di,0 m$1: mov si,_in_buf_adr add si,di lodsb ;Read it in inc input_offset ;Adjust pointer clc ;Success jmp short m$4 m$2: stc ;Nothing left m$4: endm ;Start writing code _text segment assume cs:_text,ds:dgroup,es:dgroup,ss:nothing _lzc proc near push bp ;Standard C entry code mov bp,sp push di push si push ds ;Save ds to be sure mov bx,ds mov es,bx ;Get two parameters, both integers, that are input file handle and ;output file handle mov ax,[bp+4] mov [input_handle],ax mov ax,[bp+6] mov [output_handle],ax call compress ;Compress file ;Status received back in AX pop ds pop si ;Standard C return code pop di mov sp,bp pop bp ret _lzc endp compress proc near mov [save_sp],sp ;Save SP in case of error return ;Initialize variables for serial re-entrancy mov [bit_offset],0 mov [input_offset],0 mov [input_size],0 test memflag,0ffH ;Memory allocated? jnz gotmem ;If allocated, continue malloc <((maxmax * 5) / 16 + 20)> ;allocate it jnc here1 jmp MALLOC_err1 here1: mov hash_seg,ax ;Save segment address of mem block mov memflag,0ffh ;Set flag to remind us later gotmem: l1: call init_table ;Initialize the table and some vars mov ax,clear ;Write a clear code call write_code ;call read_char ;Read first char read_char ;macro for speed l4: ;new code to check compression ratio test [ratflag],0FFH ;Time to check ratio? jz rd$1 ;Skip checking if zero call check_ratio rd$1: xor ah,ah ;Turn char into code l4a: mov prefix_code,ax ;Set prefix code ;call read_char ;Read next char read_char ;macro for speed jc l17 ;Carry means eof mov k,al ;Save char in k mov bx,prefix_code ;Get prefix code call lookup_code ;See if this pair in table jnc l4a ;nc means yes, new code in ax ;call add_code ;Add pair to table add_code ;Macro for speed push bx ;Save new code mov ax,prefix_code ;Write old prefix code call write_code pop bx mov al,k ;Get last char cmp bx,max_code ;Exceed code size? jnb l4$ jmp l4 l4$: cmp nbits,maxbits ;Currently less than maxbits? jb l14 ;yes mov ax,clear ;Write a clear code call write_code call init_table ;Reinit table mov al,k ;get last char jmp l4 ;Start over l14: inc nbits ;Increase number of bits shl max_code,1 ;Double max code size jmp l4 ;Get next char l17: mov ax,prefix_code ;Write last code call write_code mov ax,eof ;Write eof code call write_code mov ax,bit_offset ;Make sure buffer is flushed to file cmp ax,0 je OK_ret mov dx,ax ;dx <- ax shr ax,1 shr ax,1 shr ax,1 ;ax <- ax div 8 and dx,07 ;dx <- ax mod 8 ;If extra bits, make sure they get je l17a ;written inc ax l17a: call flush OK_ret: xor ax,ax ;Normal return -- compressed ret IO_err: mov ax,2 ;I/O error return mov sp,[save_sp] ;Restore stack pointer ret MALLOC_err1: ;hash table alloc error mov ax,1 ;Malloc error return mov sp,[save_sp] ;Restore stack pointer ret compress endp init_table proc near mov [bytesin],0 ;Input byte count mov [bitsout],0 ;Output bit count mov [ratio],0 mov [ratflag],0 mov [bit_interval],check_gap mov nbits,9 ;Set code size to 9 mov max_code,512 ;Set max code to 512 push es ;Save seg reg mov es,hash_seg ;Address hash table mov ax,-1 ;Unused flag mov cx,640 ;Clear first 256 entries mov di,offset hash ;Point to first entry rep stosw ;Clear it out pop es ;Restore seg reg mov free_code,first_free ;Set next code to use ret ;done init_table endp write_code proc near push ax ;Save code mov cx,nbits add [bitsout],cx ;Maintain output bit count for ratio sub [bit_interval],cx jg rd$2 ;OK if not reached interval mov [ratflag],1 ;else set flag -- check ratio soon rd$2: mov ax,bit_offset ;Get bit offset mov cx,nbits ;Adjust bit offset by code size add bit_offset,cx mov dx,ax ;dx <- ax shr ax,1 shr ax,1 shr ax,1 ;ax <- ax div 8 and dx,07 ;dx <- ax mod 8 ;Now ax contains byte offset and ;dx contains bit offset within that byte (I think) cmp ax,outbufsiz-4 ;Approaching end of buffer? jb wc1 ;less means no call flush ;Write the buffer push dx ;dx contains offset within byte add dx,nbits ;adjust by code size mov bit_offset,dx ;new bit offset pop dx ;restore dx ;ax is an index into output buffer. Next, ax <- address of buffer[ax] add ax,[_out_buf_adr] mov si,ax ;put in si mov al,byte ptr [si] ;move byte to first position ;put value of al into first byte of output buffer push bx mov bx,[_out_buf_adr] mov [bx],al pop bx xor ax,ax ;Byte offset of zero wc1: add ax,[_out_buf_adr] ;Point into buffer mov di,ax ;Destination pop ax ;Restore code mov cx,dx ;offset within byte xor dx,dx ;dx will catch bits rotated out jcxz wc3 ;If offset in byte is zero, skip shift wc2: shl ax,1 ;Rotate code rcl dx,1 loop wc2 or al,byte ptr [di] ;Grab bits currently in buffer wc3: stosw ;Save data mov al,dl ;Grab extra bits stosb ;and save ret write_code endp flush proc near push ax ;Save all registers push bx ;AX contains number of bytes to write push cx push dx push si ;may not be necessary to save si & di push di push ax ;save byte count push ax ;byte count push _out_buf_adr ;buffer address push output_handle ;zoofile ifdef UNBUF_IO call _blockwrite else call _zoowrite endif add sp,6 pop cx ;recover byte count cmp ax,cx jz here2 jmp IO_err ;I/O error here2: pop di pop si pop dx pop cx pop bx pop ax ret flush endp lookup_code proc near push ds ;Save seg reg mov ds,hash_seg ;point to hash table ;call index ;convert code to address call_index ;macro for speed mov di,0 ;flag mov bx,[si].first cmp bx,-1 ;Has this code been used? je gc4 ;equal means no inc di ;set flag gc2: ;call index ;convert code to address call_index ;macro for speed cmp [si].char,al ;is char the same? jne gc3 ;ne means no clc ;success mov ax,bx ;put found code in ax pop ds ;restore seg reg ret ;done gc3: mov bx,[si].next cmp bx,-1 ;More left with this prefix? je gc4 ;equal means no jmp gc2 ;try again gc4: stc ;not found pop ds ;restore seg reg ret ;done lookup_code endp comment # index proc near mov si,bx ;si = bx * 5 (5 byte hash entries) shl si,1 ;si = bx * 2 * 2 + bx shl si,1 add si,bx ret index endp # end comment check_ratio proc near push ax ; mov dl,'*' ;'*' printed means checking ratio ; call sendout ;Getting ready to check ratios. If bitsout is over scale_limit, ;then we scale down both bitsout and bytesin by a factor ;of 4. This will avoid overflow. mov cx,[bitsout] cmp cx,scale_limit jb scale_ok mov cl,2 shr [bytesin],cl shr [bitsout],cl scale_ok: ;Note MASM bug: "mov ah,high [bytesin]" and ;"mov al,low [bytesin]" don't work. mov ah,byte ptr [bytesin] mov dl,byte ptr [bytesin+1] sub al,al sub dh,dh ;dx:ax = 8 * bitsin = 256 * bytesin mov cx,[bitsout] ;cx <- bitsout or cx,cx ;Division by zero? jnz candivide ;No -- go ahead divide mov ax,0FFFFH ;yes -- assume max poss value jmp short divided candivide: ;Calculate cx as (bytesin * 256) / bitsout = bitsin * 8 / bitsout div cx ;ax <- rat <- dx:ax / cx shl ax,1 shl ax,1 ;rat <- 4 * bytes_in / bytes_out divided: ;Enter here with ax = rat = bitsin / bitsout. ; call print_data ;print info for debugging ;If rat > rat_thresh then ratio is good; do not reset table ; cmp ax,rat_thresh ; ja ratdone ;Compare rat against ratio mov bx,ax ;save rat in bx cmp ax,[ratio] ;cmp rat,ratio jb ratless ;trouble if ratio is now smaller mov ax,[ratio] call mul7 ;ax <- 7 * ratio add ax,bx ;ax = 7 * ratio + rat shr ax,1 shr ax,1 shr ax,1 ;ax = (7 * ratio + rat) / 8 mov [ratio],ax ;ratio = (7 * ratio + rat) / 8 jmp short ratdone ratless: ;ratio is going down, so... mov [bytesin],0 mov [bitsout],0 ; mov dl,'#' ;'#' printed means table reset ; call sendout mov ax,clear ;Write a clear code call write_code call init_table ;Reinit table ratdone: mov [ratflag],0 mov [bit_interval],check_gap pop ax ret check_ratio endp comment # sendout proc near ;char in dl send to console push ax mov ah,02 int 21H pop ax ret sendout endp # end comment mul7 proc near ;multiply ax by 7 push dx mov dx,7 mul dx ;dx:ax <- 7 * ax pop dx ret mul7 endp comment # mul3 proc near ;multiply ax by 3 push dx mov dx,3 mul dx ;dx:ax <- 3 * ax pop dx ret mul3 endp # end comment comment # mul1_125 proc near ;multiply ax by 1.125 push bx mov bx,ax shr bx,1 shr bx,1 shr bx,1 ;bx = n / 8 add ax,bx ;ax <- n + n / 8 pop bx ret mul1_125 endp # end comment comment # print_data proc near ;Debugging -- print bytesin, bitsout, rat, and ratio push ax push bx push cx push dx push ax ;print rat call _prtint add sp,2 push [ratio] ;print ratio call _prtint add sp,2 push [bytesin] call _prtint add sp,2 push [bitsout] call _prtint add sp,2 pop dx pop cx pop bx pop ax ret print_data endp # end comment ;doread reads cx characters and stores them in input buffer ;return value from zooread is returned in ax doread proc near ;reads block push bx push cx push dx push si push di push cx ;byte count push _in_buf_adr ;buffer address push input_handle ;zoofile ifdef UNBUF_IO call _read else call _zooread endif add sp,6 pop di pop si pop dx pop cx pop bx ret doread endp _text ends end zoo-2.10.orig/lzc.c100644 1750 1750 20311 5035113600 12645 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) lzc.c 2.6 88/01/30 18:39:15"; #endif /* LINT */ /* Lempel-Ziv compression. Mostly based on Tom Pfau's assembly language code. The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/12/31 */ #include "options.h" #include "zoo.h" #include "zooio.h" #include "various.h" #include "zoofns.h" /* function definitions */ /* zoomem.h defines IN_BUF_SIZE & OUT_BUF_SIZE */ #include "zoomem.h" #include "debug.h" #include "assert.h" /* lzconst.h contains constants for lzd() and lzc() */ #include "lzconst.h" void init_ctab PARMS((void)); void wr_ccode PARMS((int)); int rd_cch PARMS((void)); int lukup_ccode PARMS((int, int, int *)); void ad_ccode PARMS((int, int, int)); void check_ratio PARMS((void)); void flush_c PARMS((int)); /* interval at which to check ratio */ #define CHECKGAP 4000 #define NEXT_USE 1 #define FIRST_USE 2 #define FOUND 0 struct tabentry { int first; int next; char z_ch; }; extern char *out_buf_adr; extern char *in_buf_adr; extern char memflag; /* memory allocated? */ struct tabentry *table; /* this table also used by lzd.c */ static unsigned int free_code; static int nbits; static unsigned int max_code; static unsigned int bitsout; static int bit_interval; static unsigned int bytesin, ratio, ratflag; static unsigned int in_offset, in_size; static unsigned int bit_offset; #ifdef UNBUF_IO #define BLOCKFILE int #define BLOCKREAD read #define BLOCKWRITE write int read PARMS ((int, VOIDPTR, unsigned)); int write PARMS ((int, VOIDPTR, unsigned)); #else #define BLOCKFILE ZOOFILE #define BLOCKREAD zooread #define BLOCKWRITE zoowrite #endif /* UNBUF_IO */ static BLOCKFILE in_f, out_f; int lzc (input_f, output_f) BLOCKFILE input_f, output_f; { int nextch, prefix_code, k; int status; int where; in_f = input_f; out_f = output_f; bit_offset = in_offset = in_size = 0; if (memflag == 0) { table = (struct tabentry *) ealloc((MAXMAX+10) * sizeof(struct tabentry)); memflag++; } init_ctab(); wr_ccode(CLEAR); nextch = rd_cch(); if (nextch == EOF) { /* note real EOF, not Z_EOF */ wr_ccode (Z_EOF); flush_c ((int) ((bit_offset + 7) / 8)); return (0); /* normal return from compress */ } /* compression loop begins here with nextch holding the next input char */ loop1: if (ratflag != 0) check_ratio(); nextch &= 0xff; /* turn character to code */ assert(nextch < 256); loop2: prefix_code = nextch; nextch = rd_cch(); if (nextch == EOF) { /* note real EOF, not Z_EOF */ wr_ccode (prefix_code); wr_ccode (Z_EOF); flush_c ((int) ((bit_offset + 7) / 8)); return (0); /* normal return from compress */ } nextch &= 0xff; /* force to 8 bits */ assert(nextch < 256); k = nextch; status = lukup_ccode (prefix_code, nextch, &where); if (status == FOUND) { nextch = where; /* where found */ goto loop2; } assert(status == FIRST_USE || status == NEXT_USE); /* reach here with status = FIRST_USE or NEXT_USE */ ad_ccode (status, nextch, where); wr_ccode (prefix_code); nextch = k; if (free_code <= max_code) goto loop1; assert(nbits >= 9 && nbits <= MAXBITS); if (nbits >= MAXBITS) { /* To continue using table after it is full, remove next two lines */ wr_ccode (CLEAR); init_ctab(); goto loop1; } nbits++; assert(nbits >= 9 && nbits <= MAXBITS); max_code = max_code << 1; goto loop1; } /* end lzc() */ void wr_ccode (code) int code; { unsigned int ofs_inbyte, hibits; int byte_offset; #ifdef DEBUG if (code == CLEAR) printf(" CLEAR\n"); #endif assert(nbits >= 9 && nbits <= MAXBITS); bitsout += nbits; /* total number of bits written */ bit_interval -= nbits; if (bit_interval < 0) ratflag = 1; /* time to check ratio */ byte_offset = bit_offset / 8; ofs_inbyte = bit_offset % 8; /* offset within byte */ bit_offset += nbits; /* allowing for new code */ if (byte_offset >= OUTBUFSIZ - 4) { flush_c (byte_offset); bit_offset = ofs_inbyte + nbits; out_buf_adr[0] = out_buf_adr [byte_offset]; byte_offset = 0; } code = code & 0xffff; /* force to 16 bits */ if (ofs_inbyte == 0) out_buf_adr[byte_offset] = code & 0xff; else out_buf_adr[byte_offset] |= (code << ofs_inbyte) & 0xff; hibits = ((unsigned int) code) >> (8 - ofs_inbyte); out_buf_adr[byte_offset+1] = hibits & 0xff; out_buf_adr[byte_offset+2] = (((unsigned int) hibits) >> 8) & 0xff; assert(nbits >= 9 && nbits <= MAXBITS); } /* end wr_ccode() */ void init_ctab() { int i; bytesin = bitsout = ratio = ratflag = 0; bit_interval = CHECKGAP; nbits = 9; max_code = 512; #ifdef COMMENT for (i = 0; i < 256; i++) { #endif for (i = 0; i < MAXMAX+1; i++) { table[i].z_ch = table[i].first = table[i].next = -1; } #ifdef COMMENT /*DEBUG*/ table[MAXMAX].first = table[MAXMAX].next = -1; /*DEBUG*/ table[MAXMAX-1].first = table[MAXMAX-1].next = -1; #endif free_code = FIRST_FREE; } /* end init_ctab() */ int rd_cch() { int count; bytesin++; if (in_offset == in_size) { count = BLOCKREAD (in_f, in_buf_adr, INBUFSIZ); if (count == -1) prterror ('f', "Error reading input file during compression.\n"); addbfcrc (in_buf_adr, count); if (count == 0) { debug((printf("\nEOF on input\n"))) return (EOF); /* real EOF, not Z_EOF */ } in_size = count; debug((printf("\ninput %d chars\n", count))) in_offset = 0; } in_offset++; return (in_buf_adr[in_offset-1] & 0xff); } /* end rd_cch () */ void check_ratio() { #ifdef COMMENT int rat; if (bitsout > 16383) { /* avoid overflow */ bitsout /= 4; bytesin /= 4; } rat = (2 * bitsout) / bytesin; if (1.1 * rat < ratio) { printf("#"); wr_ccode (CLEAR); init_ctab(); bit_interval = CHECKGAP; bitsout = 0; bytesin = 0; ratio = 0; } else ratio = ((ratio << 2) + ((2 * bitsout) / bytesin)) / 5; #else bit_interval = CHECKGAP; bitsout = 0; bytesin = 0; #endif } /* end check_ratio() */ void ad_ccode (status, ch, index) int status, index, ch; { assert(status == FIRST_USE || status == NEXT_USE); #ifdef COMMENT if (free_code >= MAXMAX) /* to fix apparent bug in original */ return; #endif #ifdef COMMENT if (status == NEXT_USE) table[index].next = free_code; else /* else must be FIRST_USE */ table[index].first = free_code; #endif if (status == NEXT_USE) table[index].next = (free_code >= MAXMAX ? -1 : free_code); else /* else must be FIRST_USE */ table[index].first = (free_code >= MAXMAX ? -1 : free_code); #ifdef COMMENT if (free_code < MAXMAX) { #endif if (free_code <= MAXMAX) { table[free_code].first = table[free_code].next = -1; table[free_code].z_ch = ch & 0xff; free_code++; } } /* end ad_ccode() */ int lukup_ccode (index, ch, where) int index; /* where to start looking */ int ch; /* char to look for */ int *where; /* last entry looked at */ { *where = index; index = table[index].first; if (index == -1) { return (FIRST_USE); /* not found, first use */ } else { while (1) { if ((table[index].z_ch & 0xff) == (ch & 0xff)) { *where = index; return (FOUND); } *where = index; index = table[index].next; if (index == -1) { return (NEXT_USE); } } /* end while */ } /* end else */ } /* end lukup_ccode() */ void flush_c (count) int count; { int status; #ifdef DEBUG printf(" ", count); #endif #ifdef CHECK_BREAK check_break(); #endif if (count != 0) { status = BLOCKWRITE (out_f, out_buf_adr, count); if (status == -1) prterror ('f', "Error writing during compression.\n"); } } zoo-2.10.orig/lzconst.h100644 1750 1750 1076 5035113600 13545 0ustar jamesjames/* @(#) lzconst.h 2.1 87/12/25 12:22:30 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/12/31 */ #define INBUFSIZ (IN_BUF_SIZE - 10) /* avoid obo errors */ #define OUTBUFSIZ (OUT_BUF_SIZE - 10) #define MEMERR 2 #define IOERR 1 #define MAXBITS 13 #define CLEAR 256 /* clear code */ #define Z_EOF 257 /* end of file marker */ #define FIRST_FREE 258 /* first free code */ #define MAXMAX 8192 /* max code + 1 */ zoo-2.10.orig/lzd.asm100644 1750 1750 21670 5035113600 13215 0ustar jamesjamestitle Lempel-Ziv Decompressor ; $Source: /usr/home/dhesi/zoo/RCS/lzd.asm,v $ ; $Id: lzd.asm,v 1.3 91/07/07 09:36:23 dhesi Exp $ ;Derived from Tom Pfau's public domain assembly code. ;The contents of this file are hereby released to the public domain. ; -- Rahul Dhesi 1988/08/24 UNBUF_IO equ 1 ;use unbuffered I/O public _lzd,memflag,docrc include asmconst.ai include macros.ai ;Hash table entry hash_rec struc next dw ? ; prefix code char db ? ; suffix char hash_rec ends extrn _addbfcrc:near ;External C function for CRC ifdef UNBUF_IO extrn _read:near extrn _blockwrite:near else extrn _zooread:near extrn _zoowrite:near endif ;Declare segments _text segment byte public 'code' _text ends dgroup group _data assume ds:dgroup,es:dgroup _data segment word public 'data' extrn _out_buf_adr:word ;address of C output buffer extrn _in_buf_adr:word ;address of C input buffer memflag db 0 ;Memory allocated? flag save_bp dw ? save_sp dw ? input_handle dw ? output_handle dw ? hash_seg dw ? cur_code dw ? old_code dw ? in_code dw ? free_code dw first_free ;Note: for re-entrancy, following 3 must be re-initialized each time stack_count dw 0 nbits dw 9 max_code dw 512 fin_char db ? k db ? masks dw 1ffh,3ffh,7ffh,0fffh,1fffh ;Note: for re-entrancy, following 2 must be re-initialized each time bit_offset dw 0 output_offset dw 0 _data ends memory segment para public 'memory' hash label hash_rec memory ends call_index macro mov bp,bx ;bx = bx * 3 (3 byte entries) shl bx,1 ;bp = bx add bx,bp ;bx = bx * 2 + bp endm call_write_char macro local wc$1 mov di,output_offset ;Get offset in buffer cmp di,outbufsiz ;Full? jb wc$1 ;no call write_char_partial sub di,di ;so we add zero in next statement wc$1: add di,[_out_buf_adr] ;di <- buffer address + di stosb ;Store char inc output_offset ;Increment number of chars in buffer endm add_code macro mov bx,free_code ;Get new code ;call index ;convert to address call_index push es ;point to hash table mov es,hash_seg mov al,k ;get suffix char mov es:[bx].char,al ;save it mov ax,old_code ;get prefix code mov es:[bx].next,ax ;save it pop es inc free_code ;set next code endm ;Start coding _text segment assume cs:_text,ds:dgroup,es:dgroup,ss:nothing write_char_partial proc near push cx mov cx,di ;byte count call write_block pop cx mov output_offset,0 ;Restore buffer pointer ret write_char_partial endp _lzd proc near push bp ;Standard C entry code mov bp,sp push di push si push ds ;Save ds to be sure mov [save_bp],bp ;And bp too! mov bx,ds mov es,bx ;Get two parameters, both integers, that are input file handle and ;output file handle mov ax,[bp+4] mov [input_handle],ax mov ax,[bp+6] mov [output_handle],ax call decompress ;Compress file & get status in AX mov bp,[save_bp] ;Restore bp pop ds pop si ;Standard C return code pop di mov sp,bp pop bp ret _lzd endp ;Note: Procedure decompress returns AX=0 for successful decompression and ; AX=1 for I/O error and AX=2 for malloc failure. decompress proc near mov [save_sp],sp ;Save SP in case of error return ;Initialize variables -- required for serial re-entrancy mov [nbits],9 mov [max_code],512 mov [free_code],first_free mov [stack_count],0 mov [bit_offset],0 mov [output_offset],0 test memflag,0ffH ;Memory allocated? jnz gotmem ;If allocated, continue malloc <((maxmax * 3) / 16 + 20)> ;allocate it jnc here1 jmp MALLOC_err here1: mov hash_seg,ax ;Save segment address of mem block mov memflag,0ffh ;Set flag to remind us later gotmem: mov ax,inbufsiz push ax ;byte count push _in_buf_adr ;buffer address push input_handle ;zoofile ifdef UNBUF_IO call _read else call _zooread endif add sp,6 cmp ax,-1 jz IO_err ;I/O error here2: l1: call read_code ;Get a code cmp ax,eof ;End of file? jne l2 ;no cmp output_offset,0 ;Data in output buffer? je OK_ret ;no mov cx,[output_offset] ;byte count call write_block ;write block of cx bytes OK_ret: xor ax,ax ;Normal return -- decompressed ret ;done IO_err: mov ax,2 ;I/O error return mov sp,[save_sp] ;Restore stack pointer ret MALLOC_err: mov ax,1 ;Malloc error return mov sp,[save_sp] ;Restore stack pointer ret l2: cmp ax,clear ;Clear code? jne l7 ;no call init_tab ;Initialize table call read_code ;Read next code mov cur_code,ax ;Initialize variables mov old_code,ax mov k,al mov fin_char,al mov al,k ;call write_char ;Write character call_write_char jmp l1 ;Get next code l7: mov cur_code,ax ;Save new code mov in_code,ax mov es,hash_seg ;Point to hash table cmp ax,free_code ;Code in table? (kkk) jb l11 ;yes mov ax,old_code ;get previous code mov cur_code,ax ;make current mov al,fin_char ;get old last char push ax ;push it inc stack_count ;old code -- two memory references ;l11: ; cmp cur_code,255 ;Code or character? ; jbe l15 ;Char ; mov bx,cur_code ;Convert code to address ;new code -- 0 or 1 memory references mov ax,cur_code l11: ;All paths in must have ax containing cur_code cmp ax,255 jbe l15 mov bx,ax ;end code ;call index call_index mov al,es:2[bx] ;Get suffix char push ax ;push it inc stack_count mov ax,es:[bx] ;Get prefix code mov cur_code,ax ;Save it jmp l11 ;Translate again l15: ;old code ; push ds ;Restore seg reg ; pop es ;new code mov ax,ds ;faster than push/pop mov es,ax ;end code mov ax,cur_code ;Get code mov fin_char,al ;Save as final, k mov k,al push ax ;Push it ;old code ; inc stack_count ; mov cx,stack_count ;Pop stack ;new code -- slightly faster because INC of memory is slow mov cx,stack_count inc cx mov stack_count,cx ;end code jcxz l18 ;If anything there l17: pop ax ;call write_char call_write_char loop l17 ;old code ;l18: ; mov stack_count,cx ;Clear count on stack ;new code -- because stack_count is already zero on earlier "jcxz l18" mov stack_count,cx l18: ;end code ;call add_code ;Add new code to table add_code mov ax,in_code ;Save input code mov old_code,ax mov bx,free_code ;Hit table limit? cmp bx,max_code jb l23 ;Less means no cmp nbits,maxbits ;Still within maxbits? je l23 ;no (next code should be clear) inc nbits ;Increase code size shl max_code,1 ;Double max code l23: jmp l1 ;Get next code decompress endp read_code proc near ;old code ; mov ax,bit_offset ;Get bit offset ; add ax,nbits ;Adjust by code size ; xchg bit_offset,ax ;Swap ; mov dx,ax ;dx <- ax ;new code mov ax,bit_offset mov dx,ax ;dx <- bit_offset add ax,nbits mov bit_offset,ax mov ax,dx ;end code shr ax,1 shr ax,1 shr ax,1 ;ax <- ax div 8 and dx,07 ;dx <- ax mod 8 cmp ax,inbufsiz-3 ;Approaching end of buffer? jb rd0 ;no push dx ;Save offset in byte add dx,nbits ;Calculate new bit offset mov bit_offset,dx mov cx,inbufsiz mov bp,ax ;save byte offset sub cx,ax ;Calculate bytes left add ax,_in_buf_adr mov si,ax mov di,_in_buf_adr rep movsb ;Move last chars down push bp ;byte count push di ;buffer address push input_handle ;zoofile ifdef UNBUF_IO call _read else call _zooread endif add sp,6 cmp ax,-1 jnz here4 jmp IO_err ;I/O error here4: xor ax,ax ;Clear ax pop dx ;Restore offset in byte rd0: add ax,_in_buf_adr mov si,ax lodsw ;Get word mov bx,ax ;Save in AX lodsb ;Next byte mov cx,dx ;Offset in byte jcxz rd2 ;If zero, skip shifts rd1: shr al,1 ;Put code in low (code size) bits of BX rcr bx,1 loop rd1 rd2: mov ax,bx ;put code in ax mov bx,nbits ;mask off unwanted bits sub bx,9 shl bx,1 and ax,masks[bx] ret read_code endp init_tab proc near mov nbits,9 ;Initialize variables mov max_code,512 mov free_code,first_free ret init_tab endp comment # index proc near mov bp,bx ;bx = bx * 3 (3 byte entries) shl bx,1 ;bp = bx add bx,bp ;bx = bx * 2 + bp ret index endp #end comment docrc proc near ;On entry, ax=char count, dx=buffer address. ;Do crc on character count, in buffer. ;****** Update CRC value -- call external C program ;External program is: addbfcrc(buffer, count) ; char *buffer; ; int count; push ax ;SAVE AX push bx ;SAVE BX push cx push dx push ax ;param 2: char count push dx ;param 1: buffer address call _addbfcrc add sp,4 ;Restore 2 params from stack pop dx pop cx pop bx ;RESTORE BX pop ax ;RESTORE AX ret docrc endp write_block proc near ;Input: CX=byte count to write push ax push bx push cx push dx push si ;may not be necessary to save si & di push di push cx ;save count push cx ;count push _out_buf_adr ;buffer push output_handle ;zoofile ifdef UNBUF_IO call _blockwrite else call _zoowrite endif add sp,6 pop cx ;restore count ;ax = actual number of bytes written cmp ax,cx ;all bytes written? je written ;if yes, OK jmp IO_err written: mov dx,_out_buf_adr call docrc ;do crc on ax bytes in buffer dx mov output_offset,0 ;restore buffer ptr to zero pop di pop si pop dx pop cx pop bx pop ax ret write_block endp _text ends end zoo-2.10.orig/lzd.c100644 1750 1750 72175 5035113600 12665 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) lzd.c 2.6 88/01/30 20:39:18"; #endif /* LINT */ /*********************************************************************/ /* This file contains two versions of the lzd() decompression routine. The default is to use a fast version coded by Ray Gardner. If the symbol SLOW_LZD is defined, the older slower one is used. I have tested Ray's code and it seems to be portable and reliable. But if you suspect any problems you can define SLOW_LZD for your system in options.h and cause the older code to be used. --R.D. */ /*********************************************************************/ #include "options.h" #include "zoo.h" #include "zooio.h" #include "various.h" #include "zoofns.h" /* function definitions */ #include "zoomem.h" #include "debug.h" #include "assert.h" #include "lzconst.h" #ifndef SLOW_LZD /* Extensive modifications for speed by Ray Gardner ** Public domain by Raymond D. Gardner 9/26/88 ** ** I apologize for the comments being so dense in places as to impair ** readability, but some of the stuff isn't very obvious and needs ** some explaining. I am also sorry for the messy control structure ** (quite a few labels and goto's) and very long lzd() function, but ** I don't know how to do this any other way without loss of speed. ** ** Ray Gardner ** 6374 S. Monaco Ct. ** Englewood, CO 80111 */ #ifdef ANSI_HDRS # include /* to get memcpy */ #else VOIDPTR memcpy(); #endif #define STACKSIZE 4000 /* allows for about 8Mb string in worst case? */ /* stack grows backwards in this version, using pointers, not counters */ static char *stack; static char *stack_pointer; static char *stack_lim; void init_dtab PARMS((void)); unsigned rd_dcode PARMS((void)); /* void wr_dchar (char); */ /* now a macro */ void ad_dcode PARMS((void)); #ifdef FILTER /* to send data back to zoofilt */ extern unsigned int filt_lzd_word; #endif /* FILTER */ void xwr_dchar PARMS ((char)); static int firstchar PARMS ((int)); static void cbfill PARMS ((void)); /* wr_dchar() is a macro for speed */ #define wr_dchar(c) { \ if (outbufp= 9 && nbits <= 13); if (byte_offset >= INBUFSIZ - 5) { int space_left; assert(byte_offset >= INBUFSIZ - 5); debug((printf ("lzd: byte_offset near end of buffer\n"))) bit_offset = ofs_inbyte + nbits; space_left = INBUFSIZ - byte_offset; ptrb = byte_offset + in_buf_adr; /* point to char */ ptra = in_buf_adr; /* we now move the remaining characters down buffer beginning */ debug((printf ("rd_dcode: space_left = %d\n", space_left))) while (space_left > 0) { *ptra++ = *ptrb++; space_left--; } assert(ptra - in_buf_adr == ptrb - (in_buf_adr + byte_offset)); assert(space_left == 0); if (BLOCKREAD (in_f, ptra, byte_offset) == -1) prterror ('f', "I/O error in lzd:rd_dcode.\n"); byte_offset = 0; } ptra = byte_offset + in_buf_adr; /* NOTE: "word = *((int *) ptra)" would not be independent of byte order. */ word = (unsigned char) *ptra; ptra++; word = word | ( ((unsigned char) *ptra) << 8 ); ptra++; nextch = *ptra; if (ofs_inbyte != 0) { /* shift nextch right by ofs_inbyte bits */ /* and shift those bits right into word; */ word = (word >> ofs_inbyte) | (((unsigned)nextch) << (16-ofs_inbyte)); } return (word & masks[nbits]); } /* rd_dcode() */ void init_dtab() { nbits = 9; max_code = 512; free_code = FIRST_FREE; } /* By making wr_dchar() a macro and calling this routine only on buffer ** full condition, we save a lot of function call overhead. ** We also use pointers instead of counters for efficiency (in the macro). */ void xwr_dchar (ch) char ch; { if (outbufp >= outbuflim) { /* if buffer full */ if (BLOCKWRITE (out_f, out_buf_adr, outbufp - out_buf_adr) != outbufp - out_buf_adr) prterror ('f', "Write error in lzd:wr_dchar.\n"); addbfcrc(out_buf_adr, outbufp - out_buf_adr); /* update CRC */ outbufp = out_buf_adr; /* restore empty buffer */ } assert(outbufp - out_buf_adr < OUTBUFSIZ); *outbufp++ = ch; } /* wr_dchar() */ /* Code buffer fill routines ** ** We use a separate function for each code size. ** Each function unpacks 8 codes from a packed buffer (f) ** to an unpacked buffer (t) ** A lot of code space, but really speeds up bit picking. */ static unsigned char f[13]; /* must be unsigned for right shifts */ static unsigned t[8]; static void cb9fill () { t[0] = (f[0] ) | ((f[1] & 1) << 8); t[1] = (f[1] >> 1) | ((f[2] & 3) << 7); t[2] = (f[2] >> 2) | ((f[3] & 7) << 6); t[3] = (f[3] >> 3) | ((f[4] & 15) << 5); t[4] = (f[4] >> 4) | ((f[5] & 31) << 4); t[5] = (f[5] >> 5) | ((f[6] & 63) << 3); t[6] = (f[6] >> 6) | ((f[7] & 127) << 2); t[7] = (f[7] >> 7) | ((f[8] ) << 1); } static void cb10fill () { t[0] = (f[0] ) | ((f[1] & 3) << 8); t[1] = (f[1] >> 2) | ((f[2] & 15) << 6); t[2] = (f[2] >> 4) | ((f[3] & 63) << 4); t[3] = (f[3] >> 6) | ((f[4] ) << 2); t[4] = (f[5] ) | ((f[6] & 3) << 8); t[5] = (f[6] >> 2) | ((f[7] & 15) << 6); t[6] = (f[7] >> 4) | ((f[8] & 63) << 4); t[7] = (f[8] >> 6) | ((f[9] ) << 2); } static void cb11fill () { t[0] = (f[0] ) | ((f[1] & 7) << 8); t[1] = (f[1] >> 3) | ((f[2] & 63) << 5); t[2] = (f[2] >> 6) | (f[3] << 2) | ((f[4] & 1) << 10); t[3] = (f[4] >> 1) | ((f[5] & 15) << 7); t[4] = (f[5] >> 4) | ((f[6] & 127) << 4); t[5] = (f[6] >> 7) | (f[7] << 1) | ((f[8] & 3) << 9); t[6] = (f[8] >> 2) | ((f[9] & 31) << 6); t[7] = (f[9] >> 5) | ((f[10] ) << 3); } static void cb12fill () { t[0] = (f[0] ) | ((f[1] & 15) << 8); t[1] = (f[1] >> 4) | ((f[2] ) << 4); t[2] = (f[3] ) | ((f[4] & 15) << 8); t[3] = (f[4] >> 4) | ((f[5] ) << 4); t[4] = (f[6] ) | ((f[7] & 15) << 8); t[5] = (f[7] >> 4) | ((f[8] ) << 4); t[6] = (f[9] ) | ((f[10] & 15) << 8); t[7] = (f[10] >> 4) | ((f[11] ) << 4); } static void cb13fill () { t[0] = (f[0] ) | ((f[1] & 31) << 8); t[1] = (f[1] >> 5) | (f[2] << 3) | ((f[3] & 3) << 11); t[2] = (f[3] >> 2) | ((f[4] & 127) << 6); t[3] = (f[4] >> 7) | (f[5] << 1) | ((f[6] & 15) << 9); t[4] = (f[6] >> 4) | (f[7] << 4) | ((f[8] & 1) << 12); t[5] = (f[8] >> 1) | ((f[9] & 63) << 7); t[6] = (f[9] >> 6) | (f[10] << 2) | ((f[11] & 7) << 10); t[7] = (f[11] >> 3) | (f[12] << 5); } /* vector of code buffer fill routines */ void (*cbfillvec[]) PARMS ((void)) = { 0, 0, 0, 0, 0, 0, 0, 0, 0, cb9fill, cb10fill, cb11fill, cb12fill, cb13fill }; /* cbfill -- main code buffer fill routine ** ** moves data from inbuf[] to f[] ** then calls via vector to unpack to t[] ** then moves from t[] to codebuf[] ** A lot of moving around, but still faster than a lot of shifting and ** masking via variables (at least on a micro -- don't know about VAXen) ** Uses memcpy() for block move */ static void cbfill () { char *inbp; inbp = in_buf_adr + bit_offset / 8; codebufp = codebuf; while ( codebufp < codebuflim ) { memcpy((VOIDPTR) f, inbp, nbits); (*cbfillvec[nbits])(); memcpy((VOIDPTR) codebufp, (VOIDPTR) t, 8 * sizeof(unsigned int)); inbp += nbits; codebufp += 8; } bit_offset += nbits * CODEBUF_SIZE; } /* The following is used in the KwKwK case because it's a pretty rare ** case, and doing it this way avoids the overhead of remembering the ** "finchar" (first input character) of every string */ static int firstchar(code) /* find first character of a code */ int code; { while ( code > 255 ) code = head[code]; return code; } int lzd(input_f, output_f) BLOCKFILE input_f, output_f; /* input & output files */ { in_f = input_f; /* make it avail to other fns */ out_f = output_f; /* ditto */ nbits = 9; max_code = 512; free_code = FIRST_FREE; bit_offset = 0; outbuflim = out_buf_adr + OUTBUFSIZ; /* setup out buffer limit */ outbufguard = outbuflim - 12; /* for checking avail. room in outbuf */ /* note must allow for as many characters as we special-case (8) */ /* used 12 for extra fudge factor (Rahul does it, so I can too) */ outbufp = out_buf_adr; /* setup output buffer ptr */ codebufp = codebuflim = &codebuf[CODEBUF_SIZE]; /* code buf ptr & limit */ *codebuflim = CLEAR; /* phony CLEAR sentinel past end of code buffer */ if (BLOCKREAD (in_f, in_buf_adr, INBUFSIZ) == -1) /* fill input buffer */ return(IOERR); if (memflag == 0) { head = (int *) ealloc((MAXMAX+10) * sizeof(int)); tail = (char *) ealloc((MAXMAX+10) * sizeof(char)); stack = (char *) ealloc (sizeof (unsigned) * STACKSIZE + 20); memflag++; } stack_pointer = stack_lim = stack + STACKSIZE; /* setup stack ptr, limit*/ init_dtab(); /* initialize table */ loop: cur_code = *codebufp++; /* get code from code buffer */ goteof: /* special case for CLEAR then Z_EOF, for 0-length files */ if (cur_code == Z_EOF) { debug((printf ("lzd: Z_EOF\n"))) if (outbufp != out_buf_adr) { if (BLOCKWRITE (out_f, out_buf_adr, outbufp - out_buf_adr) != outbufp - out_buf_adr) prterror ('f', "Output error in lzd().\n"); addbfcrc(out_buf_adr, outbufp - out_buf_adr); } #ifdef FILTER /* get next two bytes and put them where zoofilt can find them */ /* nbits known to be in range 9..13 */ bit_offset = ((bit_offset + 7) / 8) * 8; /* round up to next byte */ filt_lzd_word = rd_dcode(); filt_lzd_word |= (rd_dcode() << nbits); filt_lzd_word &= 0xffff; #endif return (0); } assert(nbits >= 9 && nbits <= 13); if (cur_code == CLEAR) { /* was it sentinel or real CLEAR ? */ if ( codebufp > codebuflim ) { /* it was the sentinel */ if ( bit_offset % 8 == 0 && /* if we're on byte boundary and */ /* codesize won't change before codebuf is filled and */ /* codebuf can be filled without running out of inbuf */ free_code + CODEBUF_SIZE < max_code && bit_offset / 8 + (CODEBUF_SIZE * 13 / 8) < INBUFSIZ - 10 ) { codebufoffset = bit_offset; /* remember where we were when */ cbfill(); /* we filled the code buffer */ codebufp = codebuf; /* setup code buffer pointer */ goto loop; /* now go get codes from code buffer */ } /* otherwise, use rd_dcode to get code */ codebufp = codebuflim; /* reset codebuf ptr to sentinel */ cur_code = rd_dcode(); /* get code via rd_dcode() */ if ( cur_code != CLEAR ) /* if it's not CLEAR */ goto got_code; /* then go handle it */ } else { /* else it's really a CLEAR code, not sentinel */ /* reset bit_offset to get next code in input buf after CLEAR code */ bit_offset = codebufoffset + (codebufp - codebuf) * nbits; } codebufp = codebuflim; /* set code buf ptr to sentinel */ debug((printf ("lzd: CLEAR\n"))) init_dtab(); /* init decompression table, etc. */ old_code = cur_code = rd_dcode(); /* get next code after CLEAR */ if (cur_code == Z_EOF) /* special case for 0-length files */ goto goteof; wr_dchar(cur_code); /* write it out */ goto loop; /* and get next code */ } got_code: /* we got a code and it's not a CLEAR */ if (cur_code == Z_EOF) { debug((printf ("lzd: Z_EOF\n"))) if (outbufp != out_buf_adr) { if (BLOCKWRITE (out_f, out_buf_adr, outbufp - out_buf_adr) != outbufp - out_buf_adr) prterror ('f', "Output error in lzd().\n"); addbfcrc(out_buf_adr, outbufp - out_buf_adr); } return (0); } in_code = cur_code; /* save original code */ if (cur_code >= free_code) { /* if code not in table (kkk) */ cur_code = old_code; /* previous code becomes current */ /* push first character of old code */ *--stack_pointer = firstchar(old_code); goto unwind; /* and go "unwind" the current code */ } /* (use general unwind because the stack isn't empty now) */ /* Unwind a code. The basic idea is to use a sort of loop-unrolling ** approach to really speed up the processing by treating the codes ** which represent short strings (the vast majority of codes) as ** special cases. Avoid a lot of stack overflow checking safely. */ if (cur_code > 255) { /* if cur_code is not atomic */ *--stack_pointer = tail[cur_code]; /* push its tail code */ cur_code = head[cur_code]; /* and replace with its head code */ } else { /* else 1-byte string */ if ( outbufp > outbufguard ) /* if outbuf near end, */ goto write_stack; /* write via general routine */ *outbufp++ = cur_code; /* we got space, put char out */ goto add_code; /* add code to table */ } if (cur_code > 255) { /* if cur_code is not atomic */ *--stack_pointer = tail[cur_code]; /* push its tail code */ cur_code = head[cur_code]; /* and replace with its head code */ } else { /* else 2-byte string */ if ( outbufp > outbufguard ) /* if outbuf near end, */ goto write_stack; /* write via general routine */ *outbufp++ = cur_code; /* we got space, put char out, and */ goto move_1_char; /* go move rest of stack to outbuf */ } if (cur_code > 255) { /* if cur_code is not atomic */ *--stack_pointer = tail[cur_code]; /* push its tail code */ cur_code = head[cur_code]; /* and replace with its head code */ } else { /* else 3-byte string */ if ( outbufp > outbufguard ) /* if outbuf near end, */ goto write_stack; /* write via general routine */ *outbufp++ = cur_code; /* we got space, put char out, and */ goto move_2_char; /* go move rest of stack to outbuf */ } /* we handle codes representing strings of 4 thru 8 bytes similarly */ if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 4-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_3_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 5-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_4_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 6-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_5_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 7-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_6_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 8-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_7_char; } /* Here for KwKwK case and strings longer than 8 bytes */ /* Note we have to check stack here, but not elsewhere */ unwind: while (cur_code > 255) { /* if code, not character */ *--stack_pointer = tail[cur_code]; /* push suffix char */ if (stack_pointer < stack+12) prterror ('f', "Stack overflow in lzd().\n"); cur_code = head[cur_code]; /* head of code is new code */ } /* General routine to write stack with check for output buffer full */ write_stack: assert(nbits >= 9 && nbits <= 13); wr_dchar(cur_code); /* write this code, don't need to stack it first */ while ( stack_pointer < stack_lim ) { wr_dchar(*stack_pointer++); } goto add_code; /* now go add code to table */ /* Here to move strings from stack to output buffer */ /* only if we know we have enough room in output buffer */ /* because (outbufp <= outbufguard) */ move_7_char: *outbufp++ = *stack_pointer++; move_6_char: *outbufp++ = *stack_pointer++; move_5_char: *outbufp++ = *stack_pointer++; move_4_char: *outbufp++ = *stack_pointer++; move_3_char: *outbufp++ = *stack_pointer++; move_2_char: *outbufp++ = *stack_pointer++; move_1_char: *outbufp++ = *stack_pointer++; assert(stack_pointer == stack_lim); /* I haven't tested this! rdg */ /* add_code is now inline to avoid overhead of function call on */ /* each code processed */ add_code: assert(nbits >= 9 && nbits <= 13); assert(free_code <= MAXMAX+1); tail[free_code] = cur_code; /* save suffix char */ head[free_code] = old_code; /* save prefix code */ free_code++; assert(nbits >= 9 && nbits <= 13); if (free_code >= max_code) { if (nbits < MAXBITS) { debug((printf("lzd: nbits was %d\n", nbits))) nbits++; assert(nbits >= 9 && nbits <= 13); debug((printf("lzd: nbits now %d\n", nbits))) max_code = max_code << 1; /* double max_code */ debug((printf("lzd: max_code now %d\n", max_code))) } } old_code = in_code; assert(nbits >= 9 && nbits <= 13); goto loop; } /* lzd() */ #else /* SLOW_LZD defined, so use following instead */ /*********************************************************************/ /* Original slower lzd(). */ /*********************************************************************/ /* Lempel-Ziv decompression. Mostly based on Tom Pfau's assembly language code. The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ #define STACKSIZE 4000 struct tabentry { unsigned next; char z_ch; }; void init_dtab PARMS((void)); unsigned rd_dcode PARMS((void)); void wr_dchar PARMS((int)); void ad_dcode PARMS((void)); #ifdef FILTER /* to send data back to zoofilt */ extern unsigned int filt_lzd_word; #endif /* FILTER */ static unsigned stack_pointer = 0; static unsigned *stack; #define push(x) { \ stack[stack_pointer++] = (x); \ if (stack_pointer >= STACKSIZE) \ prterror ('f', "Stack overflow in lzd().\n");\ } #define pop() (stack[--stack_pointer]) extern char *out_buf_adr; /* output buffer */ extern char *in_buf_adr; /* input buffer */ char memflag = 0; /* memory allocated? flag */ extern struct tabentry *table; /* hash table from lzc.c */ static unsigned cur_code; static unsigned old_code; static unsigned in_code; static unsigned free_code; static int nbits; static unsigned max_code; static char fin_char; static char k; static unsigned masks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff }; static unsigned bit_offset; static unsigned output_offset; #ifdef UNBUF_IO #define BLOCKFILE int #define BLOCKREAD read #define BLOCKWRITE blockwrite int read PARMS ((int, VOIDPTR, unsigned)); int write PARMS ((int, VOIDPTR, unsigned)); #else #define BLOCKFILE ZOOFILE #define BLOCKREAD zooread #define BLOCKWRITE zoowrite #endif /* UNBUF_IO */ static BLOCKFILE in_f, out_f; int lzd(input_f, output_f) BLOCKFILE input_f, output_f; /* input & output file handles */ { in_f = input_f; /* make it avail to other fns */ out_f = output_f; /* ditto */ nbits = 9; max_code = 512; free_code = FIRST_FREE; stack_pointer = 0; bit_offset = 0; output_offset = 0; if (BLOCKREAD (in_f, in_buf_adr, INBUFSIZ) == -1) return(IOERR); if (memflag == 0) { table = (struct tabentry *) ealloc((MAXMAX+10) * sizeof(struct tabentry)); stack = (unsigned *) ealloc (sizeof (unsigned) * STACKSIZE + 20); memflag++; } init_dtab(); /* initialize table */ loop: cur_code = rd_dcode(); goteof: /* special case for CLEAR then Z_EOF, for 0-length files */ if (cur_code == Z_EOF) { debug((printf ("lzd: Z_EOF\n"))) if (output_offset != 0) { if (BLOCKWRITE (out_f, out_buf_adr, output_offset) != output_offset) prterror ('f', "Output error in lzd().\n"); addbfcrc(out_buf_adr, output_offset); } #ifdef FILTER /* get next two bytes and put them where zoofilt can find them */ /* nbits known to be in range 9..13 */ bit_offset = ((bit_offset + 7) / 8) * 8; /* round up to next byte */ filt_lzd_word = rd_dcode(); filt_lzd_word |= (rd_dcode() << nbits); filt_lzd_word &= 0xffff; #endif return (0); } assert(nbits >= 9 && nbits <= 13); if (cur_code == CLEAR) { debug((printf ("lzd: CLEAR\n"))) init_dtab(); fin_char = k = old_code = cur_code = rd_dcode(); if (cur_code == Z_EOF) /* special case for 0-length files */ goto goteof; wr_dchar(k); goto loop; } in_code = cur_code; if (cur_code >= free_code) { /* if code not in table (kkk) */ cur_code = old_code; /* previous code becomes current */ push(fin_char); } while (cur_code > 255) { /* if code, not character */ push(table[cur_code].z_ch); /* push suffix char */ cur_code = table[cur_code].next; /* := .code */ } assert(nbits >= 9 && nbits <= 13); k = fin_char = cur_code; push(k); while (stack_pointer != 0) { wr_dchar(pop()); } assert(nbits >= 9 && nbits <= 13); ad_dcode(); old_code = in_code; assert(nbits >= 9 && nbits <= 13); goto loop; } /* lzd() */ /* rd_dcode() reads a code from the input (compressed) file and returns its value. */ unsigned rd_dcode() { register char *ptra, *ptrb; /* miscellaneous pointers */ unsigned word; /* first 16 bits in buffer */ unsigned byte_offset; char nextch; /* next 8 bits in buffer */ unsigned ofs_inbyte; /* offset within byte */ ofs_inbyte = bit_offset % 8; byte_offset = bit_offset / 8; bit_offset = bit_offset + nbits; assert(nbits >= 9 && nbits <= 13); if (byte_offset >= INBUFSIZ - 5) { int space_left; #ifdef CHECK_BREAK check_break(); #endif assert(byte_offset >= INBUFSIZ - 5); debug((printf ("lzd: byte_offset near end of buffer\n"))) bit_offset = ofs_inbyte + nbits; space_left = INBUFSIZ - byte_offset; ptrb = byte_offset + in_buf_adr; /* point to char */ ptra = in_buf_adr; /* we now move the remaining characters down buffer beginning */ debug((printf ("rd_dcode: space_left = %d\n", space_left))) while (space_left > 0) { *ptra++ = *ptrb++; space_left--; } assert(ptra - in_buf_adr == ptrb - (in_buf_adr + byte_offset)); assert(space_left == 0); if (BLOCKREAD (in_f, ptra, byte_offset) == -1) prterror ('f', "I/O error in lzd:rd_dcode.\n"); byte_offset = 0; } ptra = byte_offset + in_buf_adr; /* NOTE: "word = *((int *) ptra)" would not be independent of byte order. */ word = (unsigned char) *ptra; ptra++; word = word | ( ((unsigned char) *ptra) << 8 ); ptra++; nextch = *ptra; if (ofs_inbyte != 0) { /* shift nextch right by ofs_inbyte bits */ /* and shift those bits right into word; */ word = (word >> ofs_inbyte) | (((unsigned)nextch) << (16-ofs_inbyte)); } return (word & masks[nbits]); } /* rd_dcode() */ void init_dtab() { nbits = 9; max_code = 512; free_code = FIRST_FREE; } void wr_dchar (ch) int ch; { if (output_offset >= OUTBUFSIZ) { /* if buffer full */ #ifdef CHECK_BREAK check_break(); #endif if (BLOCKWRITE (out_f, out_buf_adr, output_offset) != output_offset) prterror ('f', "Write error in lzd:wr_dchar.\n"); addbfcrc(out_buf_adr, output_offset); /* update CRC */ output_offset = 0; /* restore empty buffer */ } assert(output_offset < OUTBUFSIZ); out_buf_adr[output_offset++] = ch; /* store character */ } /* wr_dchar() */ /* adds a code to table */ void ad_dcode() { assert(nbits >= 9 && nbits <= 13); assert(free_code <= MAXMAX+1); table[free_code].z_ch = k; /* save suffix char */ table[free_code].next = old_code; /* save prefix code */ free_code++; assert(nbits >= 9 && nbits <= 13); if (free_code >= max_code) { if (nbits < MAXBITS) { debug((printf("lzd: nbits was %d\n", nbits))) nbits++; assert(nbits >= 9 && nbits <= 13); debug((printf("lzd: nbits now %d\n", nbits))) max_code = max_code << 1; /* double max_code */ debug((printf("lzd: max_code now %d\n", max_code))) } } } #endif /* ! SLOW_LZD */ zoo-2.10.orig/lzh.c100644 1750 1750 2347 5035113600 12643 0ustar jamesjames/* $Id: lzh.c,v 1.15 91/07/06 19:18:51 dhesi Exp $ */ /* lzh compression and uncompression interface module */ #include "options.h" #include "zoo.h" #include "ar.h" #include "errors.i" FILE *arcfile; extern void prterror(); extern char *out_buf_adr; /* address of buffer */ int lzh_encode(infile, outfile) FILE *infile; FILE *outfile; { extern void encode(); encode(infile, outfile); return 0; } /* lzh_decode decodes its input and sends it to output. Should return error status or byte count, but currently returns 0. */ #undef COUNT_BYTES /* define for debugging */ int lzh_decode(infile, outfile) FILE *infile; FILE *outfile; { int n; extern int decoded; #ifdef COUNT_BYTES int bytes_decoded = 0; /*debug*/ /* count bytes after decoding */ #endif arcfile = infile; /* stream to be decoded */ decode_start(); while (!decoded) { n = decode((uint) DICSIZ, out_buf_adr); /* n = count of chars decoded */ #ifdef COUNT_BYTES bytes_decoded += n; /*debug*/ #endif #ifdef CHECK_BREAK check_break(); #endif fwrite_crc(out_buf_adr, n, outfile); #ifdef SHOW_DOTS (void) putc('.', stderr); (void) fflush(stderr); #endif } #ifdef COUNT_BYTES (void) fprintf(stderr, "bytes decoded = %d\n", bytes_decoded); #endif return 0; } zoo-2.10.orig/lzh.h100644 1750 1750 1646 5035113600 12651 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/lzh.h,v $*/ /*$Id: lzh.h,v 1.3 91/07/09 01:39:23 dhesi Exp $*/ /* Adapted from "ar" archiver written by Haruhiko Okumura. */ /* Define some things if they aren't defined in header files */ #ifndef CHAR_BIT # define CHAR_BIT 8 #endif #ifndef UCHAR_MAX # define UCHAR_MAX 255 #endif /* io.c */ extern FILE *arcfile, *lzh_infile, *lzh_infile; extern t_uint16 bitbuf; #define BITBUFSIZ (CHAR_BIT * sizeof bitbuf) /* encode.c and decode.c */ #define MATCHBIT 8 /* bits for MAXMATCH - THRESHOLD */ #define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */ #define THRESHOLD 3 /* choose optimal value */ #define PERC_FLAG ((unsigned) 0x8000) /* huf.c */ #define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD) /* alphabet = {0, 1, 2, ..., NC - 1} */ #define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */ #define CODE_BIT 16 /* codeword length */ extern ushort left[], right[]; zoo-2.10.orig/machine.c100644 1750 1750 3065 5035113600 13450 0ustar jamesjames#ifndef LINT /* @(#) machine.c 2.3 88/01/02 01:21:44 */ static char sccsid[]="@(#) machine.c 2.3 88/01/02 01:21:44"; #endif /* LINT */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/12/31 */ /* This file is in two parts. */ #include "options.h" #include "zooio.h" #include "zoo.h" #include "zoofns.h" #include "various.h" /***********************************************************************/ /* PART 1. FOR UNBUFFERED I/O ONLY. DO NOT CHANGE. */ /***********************************************************************/ #ifdef UNBUF_IO int write PARMS ((int, VOIDPTR, unsigned)); /* blockwrite() is like write() except that it ignores all output to file descriptor -2, which stands for the null file. */ int blockwrite (fd, buf, count) int fd; #ifdef VOIDPTR VOIDPTR buf; #else char *buf; #endif /* VOIDPTR */ unsigned count; { if (fd == -2) return (count); else return (write (fd, buf, count)); } #endif /***********************************************************************/ /* PART 2. FOR EACH SPECIFIC SYSTEM, INCLUDE A C FILE HERE. */ /***********************************************************************/ #ifdef SYS_V #include "sysv.c" #endif #ifdef GENERIC #include "generic.c" #endif #ifdef BSD4_3 #include "bsd.c" #endif #ifdef DLC #include "generic.c" #endif #ifdef VMS #include "vms.c" #endif #ifdef MSC #include "ERROR -- NOT SUPPORTED" #endif #ifdef TURBOC #ifdef PORTABLE #include "generic.c" #else #include "turboc.c" #endif #endif zoo-2.10.orig/machine.h100644 1750 1750 2055 5035113600 13453 0ustar jamesjames/* @(#) machine.h 2.1 87/12/25 12:22:43 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ /* This file holds definitions that usually do not change between different systems, except when using REALLY strange systems. But options.h and machine.c hold stuff that does change quite a bit. */ /* MAXLONG is the maximum size of a long integer. Right now it doesn't have to be accurate since it's only used within zooext() to fake infinite disk space. */ #define MAXLONG ((unsigned long) (~0L)) /* Type BYTE must hold exactly 8 bits. The code will collapse badly if BYTE is anything other than exactly 8 bits. To avoid sign extension when casting BYTE to a longer size, it must be declared unsigned. For machine- independence, Zoo does all I/O of archive headers and directory entries in units of BYTE. The actual file data are not written in units of BYTE, however, so portability may not be absolute. */ typedef unsigned char BYTE; /* type corresponding to an 8-bit byte */ zoo-2.10.orig/macros.ai100644 1750 1750 561 5035113600 13455 0ustar jamesjames; $Source: /usr/home/dhesi/zoo/RCS/macros.ai,v $ ; $Id: macros.ai,v 1.2 91/07/07 09:37:52 dhesi Exp $ ;procedure index, used in-line to save some microseconds call_index macro mov si,bx ;si = bx * 5 (5 byte hash entries) shl si,1 ;si = bx * 2 * 2 + bx shl si,1 add si,bx endm malloc macro siz ifdif , mov bx,siz endif mov ah,48h int 21h endm zoo-2.10.orig/makefile100644 1750 1750 23770 5035113600 13425 0ustar jamesjames# derived from: @(#) makefile 2.2 88/01/27 19:37:59 # $Id: makefile,v 1.22 91/07/09 04:10:38 dhesi Exp $ # Make Zoo # #The contents of this makefile are hereby released to the public domain. # -- Rahul Dhesi 1991/07/05 # # This makefile expects two macro names, `CFLAGS' and `EXTRA', to hold # all the switches to be supplied to the C compiler. It also expects # a macro `LDFLAGS' to hold the switch for the loader when invoked. # The macro "MODEL" holds switches needed for both compile and link, # such as "memory model" for Intel and Z8000 processors. OPTIM is the # optimize option and may be set on the make command line to -O2 or # whatever your compiler thinks is nice. # # To run lint, select an appropriate lint_* target (e.g. "make lint_sysv"). MAKE = make # needed for some systems e.g. older BSD CC = cc CFLAGS = MODEL = EXTRA = -DBIG_MEM -DNDEBUG LINTFLAGS = -DLINT OPTIM = -O DESTDIR = /usr/local/bin #List of all object files created for Zoo ZOOOBJS = addbfcrc.o addfname.o basename.o comment.o crcdefs.o \ getfile.o lzc.o lzd.o machine.o makelist.o misc.o misc2.o \ nextfile.o needed.o options.o parse.o portable.o prterror.o \ version.o zoo.o zooadd.o zooadd2.o zoodel.o zooext.o zoofilt.o \ zoolist.o zoopack.o io.o lzh.o maketbl.o maketree.o huf.o \ encode.o decode.o FIZOBJS = fiz.o addbfcrc.o portable.o crcdefs.o .c.o : $(CC) $(CFLAGS) $(MODEL) $(EXTRA) $*.c all : @echo 'There is no default. Please specify an appropriate target from' @echo 'the makefile, or type "make help" for more information' help : @echo "Possible targets are as follows. Please examine the makefile" @echo "for more information." @echo ' ' @echo "generic: generic **IX environment, minimal functionlity" @echo "bsd: 4.3BSD or reasonable equivalent" @echo "bsdansi: 4.3BSD with ANSI C" @echo "ultrix: ULTRIX 4.1" @echo "convex: Convex C200 series" @echo "sysv: System V Release 2 or 3; or SCO Xenix" @echo "scodos: Cross-compiler under SCO Xenix/UNIX for MS-DOS" @echo "xenix286: Older Xenix/286 (not tested)" @echo "xenix68k: Xenix/68000 (not tested)" @echo ' ' @echo "install: Move zoo to $(DESTDIR)/tzoo (alpha test)" @echo "inst_beta: Move zoo to $(DESTDIR)/bzoo (beta test)" @echo "inst_prod: Move zoo to $(DESTDIR)/zoo (production)" @echo ' ' @echo "lint_sysv: Run lint for System V" @echo "lint_bsd: Run lint for 4.3BSD" @echo "lint_generic: Run lint for generic **IX" @echo "lint_turboc: Run lint under **IX for checking Turbo C/MSDOS code" # install alpha zoo as "tzoo" install: mv zoo $(DESTDIR)/tzoo # install beta zoo as "bzoo" inst_beta: mv zoo $(DESTDIR)/bzoo # install production zoo as "zoo" inst_prod: mv zoo $(DESTDIR)/zoo # executable targets TARGETS = zoo fiz ####################################################################### # SYSTEM-SPECIFIC TARGETS ####################################################################### # A generic system -- may have less than full functionality. # Compile with -g, since debugging will probably be needed. generic: $(MAKE) CFLAGS="-c -g -DGENERIC" $(TARGETS) # Reasonably generic BSD 4.3 bsd: $(MAKE) CFLAGS="-c $(OPTIM) -DBSD4_3" $(TARGETS) # ULTRIX 4.1 ultrix: $(MAKE) CFLAGS="-c $(OPTIM) -DULTRIX" $(TARGETS) # BSD with ANSI C - works on MIPS and Ultrix/RISC compilers bsdansi: $(MAKE) CFLAGS="-c $(OPTIM) -DBSD4_3 -DANSI_HDRS" $(TARGETS) # Convex C200 series convex: $(MAKE) CFLAGS="-c $(OPTIM) -DBSD4_3 -DANSI_HDRS" $(TARGETS) # SysV.2, V.3, SCO Xenix sysv: $(MAKE) CFLAGS="-c $(OPTIM) -DSYS_V" $(TARGETS) # DOS version cross compiled from SCO Xenix/UNIX scodos: $(MAKE) CFLAGS="-c $(OPTIM) -DTURBOC -DANSI_HDRS -DBIG_MEM" \ EXTRA="-dos -Ml" LDFLAGS="-o zoo.exe" $(TARGETS) # Tested for zoo 2.01 on: Xenix 3.4 on Greg Laskin's Intel 310/286; # SCO Xenix 2.2 on Robert Cliff's AT. # `-Ml' for large memory model, `-M2' to generate code for 80286 cpu, # `-F xxxx' for xxxx (hex) bytes of stack space. xenix286: @echo "Warning: xenix286 is not fully functional" $(MAKE) CFLAGS="-c $(OPTIM) -DSYS_V" \ MODEL="-Ml -M2 -Md" \ LDFLAGS="-s -n -Md -Mt500 -F 5000" $(TARGETS) # Radio Shack Model 16 with Xenix/68000 3.01.01. "-DM_VOID" tells not # to try to do a typedef of `void'. "-Dvoid=int" because compiler doesn't # know about `void'. `-s -n' strips and makes it shareable. Used to work # with zoo 2.01; not tested with 2.1. xenix68k: $(MAKE) CFLAGS="-c $(OPTIM) -DSYS_V -DM_VOID -Dvoid=int" \ LDFLAGS="-s -n" $(TARGETS) ####################################################################### # CLEANUP TARGETS ####################################################################### # standard clean -- remove all transient files clean : rm -f core a.out $(ZOOOBJS) $(FIZOBJS) # object clean only -- just remove object files objclean: rm -f *.o ####################################################################### # BINARY TARGETS ####################################################################### zoo: $(ZOOOBJS) $(CC) -o zoo $(MODEL) $(LDFLAGS) $(ZOOOBJS) fiz: $(FIZOBJS) $(CC) -o fiz $(MODEL) $(LDFLAGS) $(FIZOBJS) ####################################################################### # SELECTED TARGETS FOR LINT ####################################################################### # generic system V lint_sysv: echo $(ZOOOBJS) | sed -e 's/\.o/.c/g' | \ xargs lint -DSYS_V $(EXTRA) $(LINTFLAGS) | \ grep -v 'possible pointer alignment problem' # generic BSD lint_bsd: echo $(ZOOOBJS) | sed -e 's/\.o/.c/g' | \ xargs lint -DBSD4_3 $(EXTRA) $(LINTFLAGS) | \ grep -v 'possible pointer alignment problem' # generic **IX lint_generic: echo $(ZOOOBJS) | sed -e 's/\.o/.c/g' | \ xargs lint -DGENERIC $(EXTRA) $(LINTFLAGS) | \ grep -v 'possible pointer alignment problem' # Cross-lint for checking Turbo C code under **IX. For checking only; # compilation requires separate makefile called "makefile.tcc" lint_turboc: echo $(ZOOOBJS) turboc.c | sed -e 's/\.o/.c/g' | \ xargs lint -DTURBOC -DCROSS_LINT $(EXTRA) $(LINTFLAGS) ####################################################################### # DEPENDENCIES ####################################################################### # DO NOT DELETE THIS LINE -- it marks the beginning of this dependency list addbfcrc.o: options.h addfname.o: /usr/include/stdio.h options.h various.h zoo.h zoofns.h zooio.h addfname.o: zoomem.h basename.o: /usr/include/stdio.h assert.h debug.h options.h parse.h various.h basename.o: zoo.h zoofns.h zooio.h bsd.o: /usr/include/sys/stat.h /usr/include/sys/time.h bsd.o: /usr/include/sys/types.h nixmode.i nixtime.i comment.o: /usr/include/signal.h /usr/include/stdio.h comment.o: /usr/include/sys/signal.h errors.i options.h portable.h various.h comment.o: zoo.h zoofns.h zooio.h crcdefs.o: options.h decode.o: /usr/include/stdio.h ar.h lzh.h options.h zoo.h encode.o: /usr/include/assert.h /usr/include/stdio.h ar.h errors.i lzh.h encode.o: options.h zoo.h fiz.o: /usr/include/stdio.h options.h portable.h various.h zoo.h zoofns.h fiz.o: zooio.h generic.o: /usr/include/sys/stat.h /usr/include/sys/types.h generic.o: /usr/include/time.h nixmode.i nixtime.i getfile.o: /usr/include/stdio.h options.h various.h zoo.h zoofns.h zooio.h getfile.o: zoomem.h huf.o: /usr/include/stdio.h ar.h errors.i lzh.h options.h zoo.h io.o: /usr/include/stdio.h ar.h errors.i lzh.h options.h portable.h zoo.h io.o: zooio.h lzc.o: /usr/include/stdio.h assert.h debug.h lzconst.h options.h various.h lzc.o: zoo.h zoofns.h zooio.h zoomem.h lzd.o: /usr/include/stdio.h assert.h debug.h lzconst.h options.h various.h lzd.o: zoo.h zoofns.h zooio.h zoomem.h lzh.o: /usr/include/stdio.h ar.h errors.i options.h zoo.h machine.o: /usr/include/stdio.h options.h various.h zoo.h zoofns.h zooio.h makelist.o: /usr/include/stdio.h assert.h debug.h errors.i options.h makelist.o: portable.h various.h zoo.h zoofns.h zooio.h maketbl.o: /usr/include/stdio.h ar.h lzh.h options.h zoo.h maketree.o: /usr/include/stdio.h ar.h lzh.h options.h zoo.h misc.o: /usr/include/signal.h /usr/include/stdio.h /usr/include/sys/signal.h misc.o: errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h misc2.o: /usr/include/stdio.h errors.i options.h portable.h various.h zoo.h misc2.o: zoofns.h zooio.h zoomem.h msdos.o: /usr/include/stdio.h errors.i options.h zoo.h zoofns.h zooio.h needed.o: /usr/include/stdio.h debug.h options.h portable.h various.h zoo.h needed.o: zoofns.h zooio.h nextfile.o: /usr/include/stdio.h options.h various.h zoo.h options.o: /usr/include/stdio.h errors.i options.h various.h zoo.h zoofns.h options.o: zooio.h parse.o: /usr/include/stdio.h assert.h options.h parse.h various.h zoo.h parse.o: zoofns.h zooio.h portable.o: /usr/include/stdio.h assert.h debug.h machine.h options.h portable.o: portable.h various.h zoo.h zoofns.h zooio.h prterror.o: /usr/include/stdio.h /usr/include/varargs.h options.h various.h prterror.o: zoofns.h zooio.h sysv.o: /usr/include/sys/stat.h /usr/include/sys/types.h /usr/include/time.h sysv.o: nixmode.i nixtime.i turboc.o: /usr/include/signal.h /usr/include/stdio.h /usr/include/sys/signal.h vms.o: /usr/include/time.h vmstime.o: /usr/include/stdio.h zoo.o: /usr/include/stdio.h errors.i options.h various.h zoo.h zoofns.h zoo.o: zooio.h zoomem.h zooadd.o: /usr/include/stdio.h debug.h errors.i options.h parse.h portable.h zooadd.o: various.h zoo.h zoofns.h zooio.h zoomem.h zooadd2.o: /usr/include/stdio.h assert.h debug.h errors.i options.h parse.h zooadd2.o: various.h zoo.h zoofns.h zooio.h zoodel.o: /usr/include/signal.h /usr/include/stdio.h /usr/include/sys/signal.h zoodel.o: errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h zooext.o: /usr/include/signal.h /usr/include/stdio.h /usr/include/sys/signal.h zooext.o: errors.i machine.h options.h parse.h portable.h various.h zoo.h zooext.o: zoofns.h zooio.h zoofilt.o: options.h zoolist.o: /usr/include/stdio.h errors.i options.h portable.h various.h zoo.h zoolist.o: zoofns.h zooio.h zoomem.h zoopack.o: /usr/include/signal.h /usr/include/stdio.h zoopack.o: /usr/include/sys/signal.h errors.i options.h portable.h various.h zoopack.o: zoo.h zoofns.h zooio.h zoo-2.10.orig/makefile.tcc100644 1750 1750 10612 5035113600 14164 0ustar jamesjames# $Source: /usr/home/dhesi/zoo/RCS/makefile.tcc,v $ # $Id: makefile.tcc,v 1.6 91/07/07 18:39:28 dhesi Exp $ # Make Zoo -- works with Turbo C++ 1.0 under MS-DOS and # Don Kneller's NDMAKE version 4.31. # # compile is tcc (Turbo C++ 1.0) CC = tcc # assembler is tasm AS = tasm ASFLAGS = CFLAGS = -c -DTURBOC -DLINT # char representing memory model (l = large, c = compact) MCHAR = c # # model = -m$(MCHAR) # compiler switch CRT0 = c:\tc\lib\c0$(MCHAR).obj # C runtime object STDLIB = \tc\lib\c$(MCHAR).lib # C standard library EXTRA = -DBIG_MEM -DNDEBUG OPTIM = -O .SUFFIXES : .exe .obj .asm .c # Object files for zoo ZOOOBJS = addbftcc.obj addfname.obj basename.obj comment.obj \ crcdefs.obj getfile.obj lzc.obj lzd.obj machine.obj \ makelist.obj misc.obj misc2.obj nextfile.obj needed.obj \ options.obj parse.obj portable.obj prterror.obj \ version.obj zoo.obj zooadd.obj zooadd2.obj zoodel.obj \ zooext.obj zoofilt.obj zoolist.obj zoopack.obj \ io.obj lzh.obj maketbl.obj maketree.obj huf.obj \ encode.obj decode.obj \ msdos.obj # Object files for fiz FIZOBJS = fiz.obj addbftcc.obj portable.obj crcdefs.obj ################################################################# # default rule for assembly and compilation ################################################################# ## assembly ## .asm.obj : ## $(AS) $(ASFLAGS) $*.asm # C compilation .c.obj : $(CC) $(CFLAGS) $(model) $(EXTRA) $*.c ################################################################# # final link ################################################################# zoo.exe: $(ZOOOBJS) link /c /m /s $(CRT0) \ $(ZOOOBJS),zoo.exe,zoo.map,$(STDLIB) ################################################################# # miscellaneous targets: install and cleanup ################################################################# install: zoo.exe copy zoo.exe \bin\tzoo.exe clean : del *.obj ################################################################# # dependencies ################################################################# addfname.obj: options.h various.h zoo.h zoofns.h zooio.h zoomem.h basename.obj: assert.h debug.h options.h parse.h various.h basename.obj: zoo.h zoofns.h zooio.h comment.obj: errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h crcdefs.obj: options.h decode.obj: ar.h lzh.h options.h zoo.h encode.obj: ar.h errors.i lzh.h options.h zoo.h fiz.obj: options.h portable.h various.h zoo.h zoofns.h zooio.h generic.obj: nixmode.i nixtime.i getfile.obj: options.h various.h zoo.h zoofns.h zooio.h zoomem.h huf.obj: ar.h errors.i lzh.h options.h zoo.h io.obj: ar.h errors.i lzh.h options.h portable.h zoo.h zooio.h lzc.obj: assert.h debug.h lzconst.h options.h various.h lzc.obj: zoo.h zoofns.h zooio.h zoomem.h lzd.obj: assert.h debug.h lzconst.h options.h various.h lzd.obj: zoo.h zoofns.h zooio.h zoomem.h lzh.obj: ar.h errors.i options.h zoo.h machine.obj: options.h various.h zoo.h zoofns.h zooio.h makelist.obj: assert.h debug.h errors.i options.h makelist.obj: portable.h various.h zoo.h zoofns.h zooio.h maketbl.obj: ar.h lzh.h options.h zoo.h maketree.obj: ar.h lzh.h options.h zoo.h misc.obj: errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h misc2.obj: errors.i options.h portable.h various.h zoo.h misc2.obj: zoofns.h zooio.h zoomem.h msdos.obj: errors.i options.h zoo.h zoofns.h zooio.h needed.obj: debug.h options.h portable.h various.h zoo.h needed.obj: zoofns.h zooio.h nextfile.obj: options.h various.h zoo.h options.obj: errors.i options.h various.h zoo.h zoofns.h zooio.h parse.obj: assert.h options.h parse.h various.h zoo.h parse.obj: zoofns.h zooio.h portable.obj: assert.h debug.h machine.h options.h portable.obj: portable.h various.h zoo.h zoofns.h zooio.h prterror.obj: options.h various.h zoofns.h zooio.h zoo.obj: errors.i options.h various.h zoo.h zoofns.h zoo.obj: zooio.h zoomem.h zooadd.obj: debug.h errors.i options.h parse.h portable.h zooadd.obj: various.h zoo.h zoofns.h zooio.h zoomem.h zooadd2.obj: assert.h debug.h errors.i options.h parse.h zooadd2.obj: various.h zoo.h zoofns.h zooio.h zoodel.obj: errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h zooext.obj: errors.i machine.h options.h parse.h portable.h various.h zoo.h zooext.obj: zoofns.h zooio.h zoofilt.obj: options.h zoolist.obj: errors.i options.h portable.h various.h zoo.h zoolist.obj: zoofns.h zooio.h zoomem.h zoopack.obj: errors.i options.h portable.h various.h zoopack.obj: zoo.h zoofns.h zooio.h zoo-2.10.orig/makelist.c100644 1750 1750 14066 5035113600 13700 0ustar jamesjames#ifndef LINT /* @(#) makelist.c 2.3 88/01/24 12:46:44 */ static char sccsid[]="@(#) makelist.c 2.3 88/01/24 12:46:44"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "portable.h" #include "errors.i" #include "zoo.h" #include "zooio.h" #include "various.h" #include "zoofns.h" #include "assert.h" #include "debug.h" char *nameptr PARMS((char *)); void modpath PARMS((char *)); /*******************/ /* makelist() gets all pathnames corresponding to a set of filespecs and adds them to a list. Not more than "flistsize" pathnames are added. Into `longest' it returns the length of the longest name added, or zero if none added. Files ignore1, ignore2, and ignore3 are not added to the list. A file that is a device/directory is also not added to the list. However, if ignore1 is NULL, both these tests are skipped and all files will be added to the list. */ void makelist (argc, argv, flist, flistsize, ignore1, ignore2, ignore3, longest) int argc; /* number of filespec supplied */ char *argv[]; /* array of pointers to supplied filespecs */ register char *flist[]; /* array of pointers to filenames we will add */ int flistsize; /* home many names we can use */ char *ignore1, *ignore2, *ignore3; /* files to exclude from list */ int *longest; /* length of longest name in list */ { char *this_path; /* current pathname */ int fptr; /* pointer to within flist */ register int i, j; /* loop counters */ #ifdef WILDCARD char *pat_name; /* filename part of pattern */ #endif int gap; /* for Shell sort */ flistsize--; /* allow for one terminating NULL entry */ fptr = *longest = 0; assert(argc > 0); #define WCLEN 4 /* length needed for wildcard, and a little extra */ while (argc > 0) { #ifdef WILDCARD int argok = 0; /* arg not matched yet */ #endif char *this_arg; this_arg = emalloc (strlen (*argv) + WCLEN); strcpy (this_arg, *argv); /* Initialize fileset 0. Select all files -- we will later filter out the ones wanted */ #ifdef FOLD str_lwr (this_arg); #endif #ifdef WILDCARD pat_name = str_dup (nameptr (this_arg)); /* pattern without path */ #ifdef VER_CH /* trailing version field */ { static char version_field[] = " *"; char *p; p = strrchr (pat_name, VER_CH); if (p == NULL) { *version_field = VER_CH; pat_name = newcat (pat_name, version_field); /* adds trailing ";*" */ } } #endif /* replace filename by wildcard; however, if argument ends in slash, then simply append wildcard so we get all files in that directory */ #ifdef FORCESLASH fixslash (this_arg); /* convert backslashes to slashes */ #endif if (*lastptr(this_arg) == *(char *) PATH_CH) { strcat (this_arg, WILDCARD); pat_name = "*"; /* and select all files */ } else #ifdef SPEC_WILD spec_wild (this_arg); #else strcpy (nameptr (this_arg), WILDCARD); #endif /* SPEC_WILD */ #endif /* WILDCARD */ nextfile (0, this_arg, 0); while (fptr < flistsize && (this_path = nextfile(1, (char *) NULL, 0)) != NULL) { char *this_name = nameptr (this_path); modpath (this_path); /* do any needed changes to path */ #ifdef IGNORECASE #define COMPARE str_icmp #else #define COMPARE strcmp #endif if (ignore1 != NULL) { if (samefile (this_name,ignore1) || /* exclude ignored files */ samefile (this_name,ignore2) || samefile (this_name,ignore3)) continue; #ifdef CHEKUDIR if (isuadir(this_path)) continue; #else /* CHEKUDIR */ # ifdef CHEKDIR if (isfdir(this_path)) continue; # endif /* CHEKDIR */ #endif /* CHEKUDIR */ } /* end if ignore1 ! = NULL */ /* If WILDCARD is defined (e.g. AmigaDOS, MS-DOS, VAX/VMS), then nextfile() returns all filenames and we must now select the ones we need by pattern matching. If WILDCARD is not defined (e.g. **IX), filenames have already been selected by the shell and need not be tested again. */ #ifdef WILDCARD if (match_half (this_name,pat_name) || match_half (pat_name, "?-?") && /* character range */ *this_name >= *pat_name && *this_name <= pat_name[2]) #endif { #ifdef WILDCARD argok = 1; /* remember arg matched */ #endif flist[fptr++] = str_dup (this_path); if (*longest < strlen(this_path)) *longest = strlen(this_path); } } /* end while */ #ifdef WILDCARD if (argok == 0) { /* no match for argument */ prterror ('e', "Could not open %s\n", *argv); } #endif argc--; argv++; } /* fptr is now 1 + index of last item in array */ if (this_path != NULL && fptr >= flistsize) prterror ('w', too_many_files, flistsize); #ifndef DONT_SORT /* Shell sort -- K&R p. 58 */ for (gap = fptr/2; gap > 0; gap /= 2) for (i = gap; i < fptr; i++) for (j = i - gap; j >= 0 && strcmp(flist[j],flist[j+gap]) > 0; j -= gap) { char *t = flist[j]; flist[j] = flist[j+gap]; flist[j+gap] = t; } #endif /* DONT_SORT */ fptr--; /* fptr is now index of last item in array */ /* Remove duplicates */ for (i = 0; i < fptr; i++) { while (i>= jutbits; weight[i] = (unsigned) 1 << (tablebits - i); } while (i <= 16) { weight[i] = (unsigned) 1 << (16 - i); i++; } i = start[tablebits + 1] >> jutbits; if (i != (ushort)((unsigned) 1 << 16)) { k = 1 << tablebits; while (i != k) table[i++] = 0; } avail = nchar; mask = (unsigned) 1 << (15 - tablebits); for (ch = 0; ch < nchar; ch++) { if ((len = bitlen[ch]) == 0) continue; nextcode = start[len] + weight[len]; if (len <= tablebits) { for (i = start[len]; i < nextcode; i++) table[i] = ch; } else { k = start[len]; p = &table[k >> jutbits]; i = len - tablebits; while (i != 0) { if (*p == 0) { right[avail] = left[avail] = 0; *p = avail++; } if (k & mask) p = &right[*p]; else p = &left[*p]; k <<= 1; i--; } *p = ch; } start[len] = nextcode; } } zoo-2.10.orig/maketree.c100644 1750 1750 5424 5035113600 13642 0ustar jamesjames/*$Source: /usr/home/dhesi/zoo/RCS/maketree.c,v $*/ /*$Id: maketree.c,v 1.6 91/07/09 01:39:51 dhesi Exp $*/ /*********************************************************** maketree.c -- make Huffman tree Adapted from "ar" archiver written by Haruhiko Okumura. ***********************************************************/ #include "options.h" #include "zoo.h" #include "ar.h" #include "lzh.h" static int n, heapsize; static short heap[NC + 1]; static ushort *freq, *sortptr, len_cnt[17]; static uchar *len; static void count_len(i) /* call with i = root */ int i; { static int depth = 0; if (i < n) len_cnt[(depth < 16) ? depth : 16]++; else { depth++; count_len((int) left [i]); count_len((int) right[i]); depth--; } } static void make_len(root) int root; { int i, k; uint cum; for (i = 0; i <= 16; i++) len_cnt[i] = 0; count_len(root); cum = 0; for (i = 16; i > 0; i--) cum += len_cnt[i] << (16 - i); while (cum != ((unsigned) 1 << 16)) { (void) fprintf(stderr, "17"); len_cnt[16]--; for (i = 15; i > 0; i--) { if (len_cnt[i] != 0) { len_cnt[i]--; len_cnt[i+1] += 2; break; } } cum--; } for (i = 16; i > 0; i--) { k = len_cnt[i]; while (--k >= 0) len[*sortptr++] = i; } } static void downheap(i) int i; /* priority queue; send i-th entry down heap */ { int j, k; k = heap[i]; while ((j = 2 * i) <= heapsize) { if (j < heapsize && freq[heap[j]] > freq[heap[j + 1]]) j++; if (freq[k] <= freq[heap[j]]) break; heap[i] = heap[j]; i = j; } heap[i] = k; } static void make_code(j, length, code) int j; uchar length[]; ushort code[]; { int i; ushort start[18]; start[1] = 0; for (i = 1; i <= 16; i++) start[i + 1] = (start[i] + len_cnt[i]) << 1; for (i = 0; i < j; i++) code[i] = start[length[i]]++; } int make_tree(nparm, freqparm, lenparm, codeparm) int nparm; ushort freqparm[]; uchar lenparm[]; ushort codeparm[]; /* make tree, calculate len[], return root */ { int i, j, k, avail; n = nparm; freq = freqparm; len = lenparm; avail = n; heapsize = 0; heap[1] = 0; for (i = 0; i < n; i++) { len[i] = 0; if (freq[i]) heap[++heapsize] = i; } if (heapsize < 2) { codeparm[heap[1]] = 0; return heap[1]; } for (i = heapsize / 2; i >= 1; i--) downheap(i); /* make priority queue */ sortptr = codeparm; do { /* while queue has at least two entries */ i = heap[1]; /* take out least-freq entry */ if (i < n) *sortptr++ = i; heap[1] = heap[heapsize--]; downheap(1); j = heap[1]; /* next least-freq entry */ if (j < n) *sortptr++ = j; k = avail++; /* generate new node */ freq[k] = freq[i] + freq[j]; heap[1] = k; downheap(1); /* put into queue */ left[k] = i; right[k] = j; } while (heapsize > 1); sortptr = codeparm; make_len(k); make_code(nparm, lenparm, codeparm); return k; /* return root */ } zoo-2.10.orig/misc.c100644 1750 1750 22717 5035113600 13024 0ustar jamesjames#ifndef LINT /* derived from: misc.c 2.6 88/08/15 16:17:23 */ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/misc.c,v $\n\ $Id: misc.c,v 1.8 91/07/09 01:54:08 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Miscellaneous functions needed by Zoo but not by Ooz */ #include "zoo.h" #include "zooio.h" #include "various.h" #include "errors.i" #include "zoofns.h" #ifndef NOSIGNAL #include #endif #ifdef NEEDCTYP #include #else #include "portable.h" #endif int ver_too_high PARMS((struct zoo_header *)); /* calc_ofs() is given a string that (supposedly) begins with a string of digits. It returns a corresponding numeric value. If no such string, it aborts the program with a fatal error message. */ long calc_ofs(str) char *str; { long retval; char *p; retval = 0L; p = str; /* save for error message */ while (isdigit(*str)) { retval = retval * 10L + (*str-'0'); str++; } if (*str != '\0') prterror ('f', "Invalid number %s\n", p); return (retval); } /* choosefname() decides which filename to use. If a long filename is present, and if the syntax is that of UNIX, MS-DOS or the portable form, we use it; else we use the short filename. */ char *choosefname(direntry) struct direntry *direntry; { char *retptr; /* pointer to name that we will return */ switch (direntry->system_id) { case SYSID_NIX: case SYSID_PORTABLE: case SYSID_MS: retptr = (direntry->namlen != 0) ? direntry->lfname : direntry->fname; break; default: retptr = direntry->fname; break; } return (retptr); } /* choosefname() */ /* combine() combines a directory name and a filename, making sure the two are separated by a path separator */ char *combine(result, dirname, fname) char result[], *dirname, *fname; { *result = '\0'; if (*dirname != '\0') { #ifdef DIR_LBRACK /* hack for VMS */ strcat (result, DIR_LBRACK); /* "/" => "[", "./" => "[." others => "[." */ if (dirname[0] == '/') { /* absolute path => "[" */ strcat (result, dirname + 1); } else if (dirname[0] == '.' && dirname[1] == '/') { strcat (result, CUR_DIR); strcat (result, dirname + 2); } else { strcat (result, CUR_DIR); strcat (result, dirname); } /* folowing #ifdef block ought to be outside #ifdef DIR_LBRACK, and for loop should then start with p=result. This is currently just a hack for VMS. */ #ifdef DIR_SEP if (DIR_SEP != '/') { /* if char separating dirs is not "/", */ char *p; for (p = result+2; *p != '\0'; p++) /* change it to underscore */ if (*p == DIR_SEP) *p = '_'; } #endif { char *p; for (p = result; *p != '\0'; p++) if (*p == '/') *p = '.'; } #else strcat (result, dirname); #endif if (*lastptr(result) != *PATH_CH) strcat(result, PATH_CH); } strcat(result, fname); return (result); } /* fullpath() accepts a pointer to a directory entry and returns the combined directory name + filename. The long filename is used if available, else the short filename is used. */ char *fullpath (direntry) struct direntry *direntry; { static char result[PATHSIZE]; combine (result, direntry->dirlen != 0 ? direntry->dirname : "", (direntry->namlen != 0) ? direntry->lfname : direntry->fname ); return (result); } /* ver_too_high returns true if version of provided archive header is too high for us to manipulate archive */ int ver_too_high (header) struct zoo_header *header; { return (header->major_ver > MAJOR_VER || (header->major_ver == MAJOR_VER && header->minor_ver > MINOR_VER)); } /* rwheader() reads archive header, checks consistency, makes sure its version number is not too high, updates it if too low, and seeks to beginning of first directory entr. If `preserve' is 1, it preserves the header type; if `preserve' is 0, it gives a fatal error message if type is 0. */ void rwheader (header, zoo_file, preserve) register struct zoo_header *header; ZOOFILE zoo_file; int preserve; { frd_zooh (header, zoo_file); if ((header->zoo_start + header->zoo_minus) != 0L) prterror ('f', failed_consistency); if (ver_too_high (header)) prterror ('f', wrong_version, header->major_ver, header->minor_ver); if (preserve == 0 && header->type == 0) prterror ('f', packfirst); /* We reach here if the archive version is not too high. Now, if it isn't the same as ours, we bring it up to ours so the modified archive will be safe from previous versions of Zoo */ if (header->major_ver != MAJOR_VER || header->minor_ver != MINOR_VER) { header->major_ver = MAJOR_VER; header->minor_ver = MINOR_VER; zooseek (zoo_file, 0L, 0); /* seek to beginning */ fwr_zooh (header, zoo_file); } zooseek (zoo_file, header->zoo_start, 0); /* seek to where data begins */ } /* rwheader */ /* writedir() write a directory entry with keyboard interrupt disabled */ void writedir (direntry, zoo_file) struct direntry *direntry; ZOOFILE zoo_file; { #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); oldsignal = signal (SIGINT, SIG_IGN); #endif if (fwr_dir (direntry, zoo_file) == -1) prterror ('f', disk_full); #ifndef NOSIGNAL signal (SIGINT, oldsignal); #endif } /* readdir() reads a directory entry from an archive. If the directory entry is invalid and if fail is 1, it causes a fatal error; else it returns. Return value is 0 if no error else -1; */ int readdir (direntry, zoo_file, fail) /* read directory entry */ register struct direntry *direntry; ZOOFILE zoo_file; int fail; /* 0 -> return, 1 -> abort on error */ { if (frd_dir (direntry, zoo_file) < 0) { if (fail) { prterror ('f', bad_directory); } else return (-1); } if (direntry->zoo_tag != ZOO_TAG) { if (fail) prterror ('f', bad_directory); else return (-1); } return (0); } /* use pointer version below */ #ifdef COMMENT /* instr() searches a string for a substring */ instr (s, t) /* return index of string t in string s, -1 if none */ char s[], t[]; /* .. from K&R page 67 */ { int i; register int j, k; for (i = 0; s[i] != '\0'; i++) { for (j = i, k = 0; t[k] != '\0' && s[j]==t[k]; j++, k++) ; if (t[k] == '\0') return (i); } return (-1); } #endif /* COMMENT */ /* instr() searches a string for a substring */ /* from J. Brian Waters */ int instr (s, t) /* return the position of t in s, -1 if none */ char *s, *t; /* a pointer version of K&R index function p.67 */ { /* renamed to instr() to avoid conflicts with C RTL - JBW */ register char *i, *j, *k; for (i = s; *i; i++) { for (j = i, k = t; (*k) && (*j++ == *k); k++) ; if (!*k) return ((int) (i - s)); } return(-1); } /* cfactor() calculates the compression factor given a directory entry */ int cfactor (org_size, size_now) long org_size, size_now; { register int size_factor; while ((unsigned long) org_size > 32000) { /* avoid later overflow */ org_size = (unsigned long) org_size / 1024; size_now = (unsigned long) size_now / 1024; } if (org_size == 0) /* avoid division by zero */ size_factor = 0; else { size_factor = (int) ( (1000 * ((unsigned long) org_size - (unsigned long) size_now) ) / org_size + 5 ) / 10; } return (size_factor); } /*********** str_dup() duplicates a string using dynamic memory. */ char *str_dup (str) register char *str; { return (strcpy (emalloc (strlen(str)+1), str)); } /************** cmpnum() compares two pairs of unsigned integers and returns a negative, zero, or positive value as the comparison yields less than, equal, or greater than result. Each pair of unsigned integers is considered to be the more significant and the less significant half of a longer unsigned number. Note: cmpnum is used to compare dates and times. */ int cmpnum (hi1, lo1, hi2, lo2) register unsigned int hi1, hi2; unsigned int lo1, lo2; { if (hi1 != hi2) return (hi1 > hi2 ? 1 : -1); else { if (lo1 == lo2) return (0); else return (lo1 > lo2 ? 1 : -1); } } /*******************/ /* writenull() */ /* writes a null directory entry to an open archive */ void writenull (file, length) ZOOFILE file; int length; { #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); #endif struct direntry newentry; memset ((char *) &newentry, 0, sizeof (newentry)); newentry.zoo_tag = ZOO_TAG; newentry.type = 2; /* Force entry to be the required length plus possibly 2 stray bytes by dividing up the needed padding into dirlen and namlen. */ if (length > SIZ_DIRL) newentry.dirlen = newentry.namlen = (length-SIZ_DIRL)/2 + 2; else newentry.dirlen = newentry.namlen = 0; #ifndef NOSIGNAL oldsignal = signal (SIGINT, SIG_IGN); #endif if (fwr_dir (&newentry, file) == -1) prterror ('f', disk_full); #ifndef NOSIGNAL signal (SIGINT, oldsignal); #endif } #ifdef FORCESLASH /*******************/ /* fixslash() changes all "\" characters in the supplied string to "/". */ void fixslash (str) char *str; { register char *p; for (p = str; *p != '\0'; p++) if (*p == '\\') *p = '/'; } #endif /* FORCESLASH */ zoo-2.10.orig/misc2.c100644 1750 1750 20613 5035113600 13077 0ustar jamesjames#ifndef LINT /* @(#) misc2.c 2.7 88/01/24 12:47:36 */ static char sccsid[]="@(#) misc2.c 2.7 88/01/24 12:47:36"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Miscellaneous routines */ #include "portable.h" #include "zooio.h" #include "various.h" #include "errors.i" #include "zoomem.h" #include "zoo.h" #include "zoofns.h" /* only for malloc */ void makepath PARMS((char *)); /**********************/ /* memerr() */ /* Give error message on memory error and abort */ void memerr(i) unsigned int i; { #ifdef OOZ prterror ('f', no_memory, "", ""); #else if (i != 0) prterror ('f', no_memory); else prterror('f', "needed %u bytes: %s", no_memory); #endif } /**********************/ /* emalloc() allocates memory like malloc() does (and it calls malloc). However, it automatically calls the error function memerr() if memory couldn't be allocated. It also assumes that memory will never be freed and conserves it by allocating memory in large chunks and then partitioning it out with no administrative overhead. This avoids many problems due to various bugs in various implementations of malloc, and also avoids a very high amount of malloc overhead for repeated allocations to store numerous filenames etc. The down side is that we can't use free(). WARNING: No alignment of allocated memory is attempted, so memory allocated through emalloc should be used only for storing strings. For allocating memory for other data types use ealloc(). */ VOIDPTR emalloc (size) unsigned int size; { #define BLOCK_SIZE 512 /* memory allocation granularity */ #ifdef USE_MALLOC /* Pass on memory requests to malloc() */ char *ptr; if ((ptr = malloc (size)) == NULL) memerr(size); return (ptr); #else static char *memptr; static unsigned avail = 0; unsigned malloc_incr; char *retval; if (size == 0) return (NULL); /* if not enough space avail get some more */ if (avail < size) { malloc_incr = BLOCK_SIZE; if (malloc_incr < size) malloc_incr = size; while (malloc_incr >= size && (memptr = malloc (malloc_incr)) == NULL) malloc_incr = (malloc_incr / 6) * 5; avail = malloc_incr; } if (avail < size) memerr(size); /* no return from this */ retval = memptr; memptr += size; avail -= size; return (retval); #endif /* end of not USE_MALLOC */ } /**********************/ /* ealloc() is just a wrapper around malloc(), which causes memerr() to be called if memory cannot be allocated. All memory requests are passed on to malloc. Allocated memory can later be freed. */ VOIDPTR ealloc(size) unsigned int size; { char *ptr; if ((ptr = malloc (size)) == NULL) memerr(size); return ptr; } /**********************/ /* erealloc() is a wrapper around realloc() the way ealloc is a wrapper around malloc(). It calls memerr() on error. */ VOIDPTR erealloc(p, size) VOIDPTR p; unsigned int size; { char *ptr; if ((ptr = realloc (p, size)) == NULL) memerr(size); return ptr; } /**********************/ /* putstr() This function prints a string to standard output. If the received string pointer is NULL, it is handled safely. This function is here for historical reasons: Ooz was once coded to not use printf under MSDOS to save space, and at that time putstr() printed a string without using printf. It should eventually be eliminated and all calls to it replaced with calls to printf directly. */ void putstr (str) register char *str; { if (str == NULL) return; printf ("%s", str); } /**********************/ /* exists() This function checks the existence of a file. If the symbol EXISTS is defined, that is called as a macro and supplied the filename. It must return 1 if the file exists and 0 if it does not. If EXISTS is not defined, exists() tests to see if the file can be opened for reading or writing; if so, it returns 1 else it returns 0. Because of the delay between the time existence is checked and the time Zoo creates a files, a race condition exists. It would be better to use open() with the O_EXCL flag but that will not work for many systems. */ int exists (fname) char *fname; { #ifdef EXISTS return EXISTS(fname); #else ZOOFILE f; if ( (f = zooopen (fname, Z_READ )) != NOFILE || (f = zooopen (fname, Z_WRITE)) != NOFILE ) { zooclose (f); return (1); } else return (0); #endif /* ifdef EXISTS */ } /**************** newcat() allocates enough space to concatenate two strings then returns a pointer to the concatenated result */ char *newcat (r, s) char *r, *s; { char *temp = emalloc (strlen (r) + strlen (s) + 2); /* 1 spare */ strcpy (temp, r); strcat (temp, s); return (temp); } /* Creates a path */ void makepath(path) char *path; { char tmppath[PATHSIZE]; char *slashpos; if (path == NULL) return; while (*lastptr(path) == *(char *) PATH_CH) /* remove trailing slashes */ *lastptr(path) = '\0'; if (*path == '\0') return; slashpos = findlast(path, PATH_CH); /* find last slash */ if (slashpos == NULL) { /* if not, just create dir. */ MKDIR(path); return; } else { /* otherwise... */ if (slashpos == path) { /* if leading slash */ MKDIR(slashpos); /* make that directory */ return; /* and done */ } else { strcpy(tmppath,path); /* save path */ *slashpos = '\0'; /* split into prefix & suffix */ #ifdef DEBUG printf("making path from [%s]\n", path); #endif makepath(path); /* make path from prefix */ #ifdef DEBUG printf("making dir from [%s]\n", tmppath); #endif MKDIR(tmppath); /* make dir from suffix */ } } } /* makepath() */ /* If no extension in filename add supplied extension */ char *addext (fname, ext) char *fname; char *ext; { if (strchr (nameptr (fname), EXT_CH) == NULL) return (newcat (fname, ext)); else return (fname); } #ifdef VER_CH /* remove any trailing extension field */ char *strip_ver (fname) char *fname; { char *p = strchr (fname, VER_CH); if (p != NULL) *p = '\0'; } #endif /* Function samefile() compares two filenames to see if they are the same file. Just strcmp() or str_icmp() could have been used, except that if the filenames have trailing version fields, we want to compare those always equal. samefile() is called by routines that want to avoid adding an archive to itself. */ int samefile (f1, f2) char *f1; char *f2; { #ifdef IGNORECASE #define COMPARE str_icmp #else #define COMPARE strcmp #endif #ifdef VER_CH char tf1[LFNAMESIZE]; char tf2[LFNAMESIZE]; strcpy (tf1, f1); strcpy (tf2, f2); strip_ver (tf1); /* strip version fields */ strip_ver (tf2); return (COMPARE (tf1, tf2) == 0); #else /* if no version fields, just use strcmp(i) */ return (COMPARE (f1, f2) == 0); #endif } #ifdef USE_ASCII int isdigit (c) int c; { return (c >= '0' && c <= '9'); } int isupper (c) int c; { return (c >= 'A' && c <= 'Z'); } int toascii (c) int c; { return (c & 0x7f); } int tolower (c) int c; { return (isupper(c) ? (c | 0x20) : c); } #endif #ifdef GETTZ /**************** Function tzadj() accepts a directory entry and adjusts its timestamp to reflect its timezone. Uses function mstime() from mstime.i and mstonix() from nixtime.i. */ long mstonix(); long gettz(); #include "mstime.i" /* get mstime() */ void tzadj (direntry) struct direntry *direntry; { long diff_tz; long longtime; if (direntry->tz == NO_TZ) /* none stored */ return; diff_tz = (long) direntry->tz * (3600/4) - gettz(); /* diff. in seconds */ longtime = mstonix (direntry->date, direntry->time) + diff_tz; /* adj tz */ mstime (longtime, &direntry->date, &direntry->time); } #endif /* GETTZ */ /* how long an int can be in text form -- allow 64-bit ints */ #define INT_TEXT 21 /* Function add_version adds a version suffix to a filename, given the directory entry corresponding to the file */ void add_version (fname, direntry) char *fname; struct direntry *direntry; { char verstr[INT_TEXT]; /* string buffer for conversion to text */ if (direntry->vflag & VFL_ON) { sprintf (verstr, "%u", direntry->version_no); strcat (fname, VER_DISPLAY); strcat (fname, verstr); } } zoo-2.10.orig/msdos.c100644 1750 1750 4362 5035113600 13172 0ustar jamesjames/* msdos.c */ /* Highly system-dependent routines go here */ /* settime() */ /* Accepts a date/time in DOS format and sets the file time. Returns 1 if OK, 0 if error */ #include "options.h" #include "zoo.h" #include "zooio.h" /* to satisfy declarations in zoofns.h */ #include "zoofns.h" #include "errors.i" #include /* to get fileno() */ /* register definitions specific for Turbo C */ union REGS { struct { unsigned ax, bx, cx, dx, si, di, carry, flags; } x; struct { unsigned char al, ah, bl, bh, cl, ch, dl, dh; } h; }; int settime (file,date,time) ZOOFILE file; unsigned date, time; { extern intdos(); union REGS regs; regs.h.ah = 0x57; /* DOS FileTimes call */ regs.h.al = 0x01; /* set date/time request */ regs.x.bx = fileno (file); /* get handle */ regs.x.cx = time; regs.x.dx = date; /* first flush file so later write won't occur on close */ fflush (file); intdos (®s, ®s); if (regs.x.carry != 0) return (0); else return (1); } /* settime */ /* gets date and time of file */ gettime (file,date,time) ZOOFILE file; unsigned *date, *time; { union REGS regs; regs.h.ah = 0x57; /* DOS FileTimes call */ regs.h.al = 0x00; /* get date/time request */ regs.x.bx = fileno (file); /* get handle */ intdos (®s, ®s); *time = regs.x.cx; *date = regs.x.dx; if (regs.x.carry != 0) return (0); else return (1); } /* settime */ /* space() */ /* Returns free space in bytes on disk n (0 = default, 1 = A, etc.). Returns 0 if drive number is invalid. Before getting disk space, the function requests DOS to flush its internal buffers */ unsigned long space (drive, alloc_size) int drive; int *alloc_size; { unsigned long free_space; union REGS regs; regs.h.ah = 0x0d; /* disk reset DOS call */ intdos (®s, ®s); regs.h.ah = 0x36; /* GetFreeSpace DOS call */ regs.h.dl = drive; intdos (®s, ®s); /* space = clusters * sectors/cluster * bytes/sector. */ /* ax=0xFFFF on error */ /* cluster size = sectors/cluster * bytes/sector */ *alloc_size = regs.x.ax * regs.x.cx; /* space = cluster * alloc_size */ if (regs.x.ax == 0xffff) return (0L); /* invalid drive */ else { free_space = ((unsigned long) regs.x.bx) * *alloc_size; return (free_space); } } zoo-2.10.orig/mstime.i100644 1750 1750 5454 5035113600 13354 0ustar jamesjames#ifndef LINT static char mstimeid[]="@(#) mstime.i 2.2 88/01/24 12:47:58"; #endif /* LINT */ /* (C) Copyright 1987 Rahul Dhesi -- All rights reserved */ #define BASEYEAR 1970 /**************** Function mstime() converts time in seconds since January 1 of BASEYEAR to MS-DOS format date and time. */ mstime(longtime, date, time) long longtime; /* input: seconds since Jan 1, BASEYEAR */ int *date, *time; /* output: MS-DOS format date and time */ { static int daysinmo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; #define FEBRUARY 1 int year, month, day, hour, min, sec; long secsinhour, secsinday, secsinyear, secsinleapyear; int leapyear; /* is this a leap year? */ int done; /* control variable */ secsinhour = (long) (60 * 60); /* seconds in an hour */ secsinday = 24 * secsinhour; /* seconds in a day */ secsinyear = 365 * secsinday; /* seconds in a year */ secsinleapyear = secsinyear + secsinday; /* seconds in a leap year */ #ifdef DEBUG printf("mstime: input longtime = %ld\n", longtime); #endif /* We can't handle dates before 1970 so force longtime positive */ if (longtime < 0) longtime = 0; /* Step through years from BASEYEAR onwards, subtracting number of seconds in each, stopping just before longtime would become negative. */ year = BASEYEAR; done = 0; while (!done) { long yearlength; leapyear = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); if (leapyear) yearlength = secsinleapyear; else yearlength = secsinyear; if (longtime >= yearlength) { longtime -= yearlength; year++; } else done++; } /* Now `year' contains year and longtime contains remaining seconds */ daysinmo[FEBRUARY] = leapyear ? 29 : 28; month = 0; /* range is 0:11 */ while (longtime > daysinmo[month] * secsinday) { longtime = longtime - daysinmo[month] * secsinday; month++; } month++; /* range now 1:12 */ day = longtime / secsinday; /* day of month, range 0:30 */ longtime = longtime % secsinday; day++; /* day of month, range 1:31 */ hour = longtime / secsinhour; /* hours, range 0:23 */ longtime = longtime % secsinhour; min = longtime / 60L; /* minutes, range 0:59 */ longtime = longtime % 60L; sec = longtime; /* seconds, range 0:59 */ #ifdef DEBUG printf("mstime: date = %4d/%02d/%02d time = %02d:%02d:%02d\n", year, month, day, hour, min, sec); if (leapyear) printf("(leap year)\n"); #endif if (year < 1980) year = 1980; *date = day + (month << 5) + ((year - 1980) << 9); *time = (sec / 2) + (min << 5) + (hour << 11); } zoo-2.10.orig/needed.c100644 1750 1750 20112 5035113600 13300 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) needed.c 2.16 88/01/31 15:54:37"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #define STRCMP(s1,op,s2) (strcmp(s1,s2) op 0) #include "options.h" /* Accepts a filename from an archive and returns 1 if a command-line argument filename matches it. Otherwise returns 0. Returns 1 if no arguments were supplied (so by default, all files will be extracted */ #include "zoo.h" #ifdef NEEDCTYP #include /* for tolower() */ #else #include "portable.h" #endif #include "zooio.h" #include "zoofns.h" #include "various.h" #include "debug.h" extern int next_arg; /* filenames start at this position */ extern int arg_count; /* count of arguments supplied to program */ extern char **arg_vector; /* vector of arguments supplied to program */ /* Uses FIRST_ARG in zoo.h, so must be recompiled when switching between Ooz and Zoo */ int needed(pathname, direntry, header) char *pathname; struct direntry *direntry; struct zoo_header *header; { register int i; register char *arg; char *justname; char arg_copy[PATHSIZE]; /* working copy of an argument */ char path_copy[PATHSIZE]; /* working copy of pathname */ char *p; /* a temporary pointer */ char *q; /* a temporary pointer */ /* if no filenames supplied, match latest version of each (but match any version if versions not enabled) */ if (arg_count <= FIRST_ARG && (!(header->vdata & VFL_ON) || !(direntry->vflag & VFL_ON) || (direntry->vflag & VFL_LAST))) { return (1); /* .. then all files are needed */ } /* count backwards and stop if '+' is encountered */ for (i = arg_count-1; i >= next_arg; i--) { arg = arg_vector[i]; #ifdef FOLD str_lwr(pathname); str_lwr(arg); #endif #ifdef DEBUG printf("needed: testing [%s] and [%s]\n", pathname, arg); #endif if (STRCMP(arg,==,"+")) return (0); /* If the argument contains a slash, the match fails if the path prefixes don't match */ if (strchr(arg, *(char *)PATH_CH) != NULL) { /* found slash */ strcpy(arg_copy,arg); strcpy(path_copy,pathname); p = findlast(arg_copy, PATH_CH); if (p != NULL) *p = '\0'; else { p = findlast (arg_copy, VER_INPUT); if (p != NULL) *p = '\0'; } p = findlast(path_copy, PATH_CH); if (p != NULL) *p = '\0'; else { p = findlast (path_copy, VER_DISPLAY); if (p != NULL) *p = '\0'; } if (!match_half(path_copy, arg_copy)) { #ifdef DEBUG printf ("needed(): match failed for [%s] and [%s]\n", path_copy, arg_copy); #endif continue; /* no match this time in loop */ } } /* We reach here either if the pattern had no slashes, or if it had a slash but the path prefixes matched. Now we will test to see if the filename parts match. If the argument contains VER_INPUT character, then this separates the filename from a version number, and only that specific version will match. If not, then only the latest version will match. However, if the argument has a version character but nothing following it, that matches all versions. Also, version 0 matches only the latest version and version ^0 matches all versions except the latest one. */ strcpy (arg_copy, arg); /* local copy of argument */ strcpy (path_copy, pathname); /* local copy of pathname */ p = findlast(arg_copy, VER_INPUT); /* p is version in argument */ q = findlast(path_copy, VER_DISPLAY); /* q is version in archive */ if (p != NULL && p != lastptr(arg_copy)) {/* nonnull version in arg */ if (q != NULL) { /* nonnull ver. in archive */ char *pp = p+1; /* point to actual version */ char *qq = q+1; if (STRCMP(pp, ==, "0") && !(direntry->vflag & VFL_LAST) || STRCMP(pp, ==, "^0") && (direntry->vflag & VFL_LAST)) { debug(("needed: no match versions [%s] and [%s]\n", qq, pp)) continue; } if (STRCMP(pp, !=, "0") && STRCMP(pp, !=, "^0") && !match_half (qq, pp)) { debug(("needed: no match versions [%s] and [%s]\n", qq, pp)) continue; /* no match this loop */ } } } /* Special case test: If argument has version but no filename, then filename is assumed to match */ if (p == arg_copy) { /* 1st char is version char */ return (1); /* .. so declare a match */ } /* Reach here if argument has no version character, or if argument has version character and it matches version in pathname. Now we check to see if argument has no version character and if pathname is latest version. If so, the versions do match; if not, then the match fails. But if version numbering is not enabled, then versions always match. If the match fails, we do a "continue", else we fall through and proceed to test the filenames. (Note: It is intuitively better to first compare filenames and then see if versions match, but since they are both just independent fields, it's equally correct to compare versions first, as we are doing here, and then see if filenames match. It may even be more efficient.) */ if (p == NULL && /* no version char typed */ !( /* NOT */ (direntry->vflag & VFL_ON) == 0 || /* no versions */ (direntry->vflag & VFL_LAST) || /* .. or latest version */ q == NULL /* .. or no version char */ ) ) { #ifdef DEBUG printf("needed: fail--no version typed and not latest version\n"); #endif continue; /* match fails */ } /* versions match and we fall through */; /* reach here if versions match -- so strip them and compare rest */ if (p != NULL) *p = '\0'; /* strips version from arg_copy */ if (q != NULL) *q = '\0'; /* strips version from path_copy */ justname = nameptr(path_copy); /* filename without any pathname */ if (match_half (justname, nameptr(arg_copy))) return (1); #ifdef DEBUG printf ("needed: fname-only match failed [%s] and [%s]\n", justname, nameptr(arg_copy)); #endif /* try for a character range */ if (match_half (arg, "?-?")) { /* character range given */ if (arg[0] <= *justname && arg[2] >= *justname) return (1); } } return (0); } /* needed */ /***********************/ /* match_half() compares a pattern with a string. Wildcards accepted in the pattern are: "*" for zero or more arbitrary characters; "?" for any one characters. Unlike the MS-DOS wildcard match, "*" is correctly handled even if it isn't at the end of the pattern. ".' is not special. Originally written by Jeff Damens of Columbia University Center for Computing Activities. Taken from the source code for C-Kermit version 4C. */ int match_half (string, pattern) register char *string, *pattern; { char *psave,*ssave; /* back up pointers for failure */ psave = ssave = NULL; while (1) { #ifdef IGNORECASE for (; tolower(*pattern) == tolower(*string); pattern++,string++ ) /* skip first */ #else for (; *pattern == *string; pattern++,string++) /* skip first */ #endif /* IGNORECASE */ if (*string == '\0') return(1); /* end of strings, succeed */ if (*string != '\0' && *pattern == '?') { pattern++; /* '?', let it match */ string++; } else if (*pattern == '*') { /* '*' ... */ psave = ++pattern; /* remember where we saw it */ ssave = string; /* let it match 0 chars */ } else if (ssave != NULL && *ssave != '\0') { /* if not at end */ /* ...have seen a star */ string = ++ssave; /* skip 1 char from string */ pattern = psave; /* and back up pattern */ } else return(0); /* otherwise just fail */ } } zoo-2.10.orig/nextfile.c100644 1750 1750 16644 5035113600 13711 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) nextfile.c 2.2 87/12/26 12:23:43"; #endif /* LINT */ #include "options.h" /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved */ /* Functions to collect filenames from command line etc. Nextfile() is used by both Atoz and Zoo. Wildcard expansion by nextfile() is specific to MS-DOS and this implementation is specific to Microsoft C. If the symbol PORTABLE is defined, nextfile() becomes effectively a no-op that will return the original filespec the first time and NULL subsequently. */ #define FMAX 3 /* Number of different filename patterns */ #ifndef OK_STDIO #include #define OK_STDIO #endif #include "various.h" #include "zoo.h" /* solely to define PATHSIZE */ #ifdef PORTABLE #ifndef SPECNEXT /* If portable version, nextfile() is effectively a no-op and any wildcard expansion must be done by the runtime system before the command line is received by this program */ char *nextfile (what, filespec, fileset) int what; /* whether to initialize or match */ register char *filespec; /* filespec to match if initializing */ register int fileset; /* which set of files */ { static int first_time [FMAX+1]; static char saved_fspec [FMAX+1][PATHSIZE]; /* our own copy of filespec */ if (what == 0) { strcpy (saved_fspec[fileset], filespec); /* save the filespec */ first_time[fileset] = 1; return NULL; } if (first_time[fileset]) { first_time[fileset] = 0; return saved_fspec[fileset]; } else { return NULL; } } #endif /* SPECNEXT */ #else /* if not PORTABLE then */ #include #include #include "assert.h" /* macro definition: assert() macro */ void fcbpath PARMS((struct ffblk *, char *, char *)); /*******************/ /* nextfile() returns the name of the next source file matching a filespec. INPUT what: A flag specifying what to do. If "what" is 0, nextfile() initializes itself. If "what" is 1, nextfile() returns the next matching filename. filespec: The filespec, usually containing wildcard characters, that specifies which files are needed. If "what" is 0, filespec must be the filespec for which matching filenames are needed. If "what" is 1, nextfile() does not use "filespec" and "filespec" should be NULL to avoid an assertion error during debugging. fileset: nextfile() can keep track of more than one set of filespecs. The fileset specifies which filespec is being matched and therefore which set of files is being considered. "fileset" can be in the range 0:FMAX. Initialization of one fileset does not affect the other filesets. OUTPUT IF what == 0 THEN return value is NULL ELSE IF what == 1 THEN IF a matching filename is found THEN return value is pointer to matching filename including supplied path ELSE IF at least one file matched previously but no more match THEN return value is NULL ELSE IF supplied filespec never matched any filename THEN IF this is the first call with what == 1 THEN return value is pointer to original filespec ELSE return value is NULL END IF END IF END IF END IF NOTE Initialization done when "what"=0 is not dependent on the correctness of the supplied filespec but simply initializes internal variables and makes a local copy of the supplied filespec. If the supplied filespec was illegal, the only effect is that the first time that nextfile() is called with "what"=1, it will return the original filespec instead of a matching filename. That the filespec was illegal will become obvious when the caller attempts to open the returned filename for input/output and the open attempt fails. USAGE HINTS nextfile() can be used in the following manner: char *filespec; -- will point to filespec char *this_file; -- will point to matching filename filespec = parse_command_line(); -- may contain wildcards FILE *stream; nextfile (0, filespec, 0); -- initialize fileset 0 while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) { stream = fopen (this_file, "whatever"); if (stream == NULL) printf ("could not open %s\n", this_file); else perform_operations (stream); } */ char *nextfile (what, filespec, fileset) int what; /* whether to initialize or match */ register char *filespec; /* filespec to match if initializing */ register int fileset; /* which set of files */ { static struct ffblk ffblk[FMAX+1]; static int first_time [FMAX+1]; static char pathholder [FMAX+1][PATHSIZE]; /* holds a pathname to return */ static char saved_fspec [FMAX+1][PATHSIZE];/* our own copy of filespec */ int ffretval; /* return value from findfirst() or findnext() */ assert(fileset >= 0 && fileset <= FMAX); if (what == 0) { assert(filespec != NULL); strcpy (saved_fspec[fileset], filespec); /* save the filespec */ first_time[fileset] = 1; return (NULL); } assert(what == 1); assert(filespec == NULL); assert(first_time[fileset] == 0 || first_time[fileset] == 1); if (first_time[fileset]) /* first time -- initialize etc. */ ffretval = findfirst(saved_fspec[fileset], &ffblk[fileset], 0); else ffretval = findnext(&ffblk[fileset]); if (ffretval != 0) { /* if error status */ if (first_time[fileset]) { /* if file never matched then */ first_time[fileset] = 0; return (saved_fspec[fileset]);/* return original filespec */ } else { /* else */ first_time[fileset] = 0; /* */ return (NULL); /* return (NULL) for no more */ } } else { /* a file matched */ first_time[fileset] = 0; /* add path info */ fcbpath (&ffblk[fileset], saved_fspec[fileset], pathholder[fileset]); return (pathholder[fileset]); /* matching path */ } } /* nextfile */ /*******************/ /* fcbpath() accepts a pointer to an ffblk structure, a character pointer to a pathname that may contain wildcards, and a character pointer to a buffer. Copies into buffer the path prefix from the pathname and the filename prefix from the ffblk so that it forms a complete path. */ void fcbpath (ffblk, old_path, new_path) struct ffblk *ffblk; char *old_path; register char *new_path; { register int i; int length, start_pos; strcpy(new_path, old_path); /* copy the whole thing first */ length = strlen(new_path); i = length - 1; /* i points to end of path */ while (i >= 0 && new_path[i] != '/' && new_path[i] != '\\' && new_path[i] != ':') i--; /* either we found a "/", "\", or ":", or we reached the beginning of the name. In any case, i points to the last character of the path part. */ start_pos = i + 1; for (i = 0; i < 13; i++) new_path[start_pos+i] = ffblk->ff_name[i]; new_path[start_pos+13] = '\0'; } #endif /* PORTABLE */ zoo-2.10.orig/nixmode.i100644 1750 1750 2147 5035113600 13515 0ustar jamesjames#ifndef LINT /* @(#) nixmode.i 1.2 88/01/24 12:48:57 */ static char modeid[]="@(#) nixmode.i 1.2 88/01/24 12:48:57"; #endif /* (C) Copyright 1988 Rahul Dhesi -- All rights reserved UNIX-specific routines to get and set file attribute. These might be usable on other systems that have the following identical things: fileno(), fstat(), chmod(), sys/types.h and sys/stat.h. */ /* Get file attributes. Currently only the lowest nine of the **IX mode bits are used. Also we return bit 23=0 and bit 22=1, which means use portable attribute format, and use attribute value instead of using default at extraction time. */ unsigned long getfattr (f) ZOOFILE f; { int fd; struct stat buf; /* buffer to hold file information */ fd = fileno(f); if (fstat (fd, &buf) == -1) return (NO_FATTR); /* inaccessible -- no attributes */ else return (unsigned long) (buf.st_mode & 0x1ffL) | (1L << 22); } /* Set file attributes. Only the lowest nine bits are used. */ int setfattr (f, a) char *f; /* filename */ unsigned long a; /* atributes to set */ { return (chmod (f, (int) (a & 0x1ff))); } zoo-2.10.orig/nixtime.i100644 1750 1750 6552 5035113600 13533 0ustar jamesjames#ifndef LINT static char nixtimeid[]="@(#) nixtime.i 2.3 88/01/24 12:49:28"; #endif /* LINT */ /* Time handling routines for UNIX systems. These are included by the file machine.c as needed. The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/12/31 */ struct tm *localtime(); /***************** Function gettime() gets the date and time of the file handle supplied. Date and time is in MSDOS format. */ int gettime (file, date, time) ZOOFILE file; unsigned *date, *time; { struct stat buf; /* buffer to hold file information */ struct tm *tm; /* will hold year/month/day etc. */ int handle; handle = fileno(file); if (fstat (handle, &buf) == -1) { prterror ('w', "Could not get file time\n"); *date = *time = 0; } else { tm = localtime (&buf.st_mtime); /* get info about file mod time */ *date = tm->tm_mday + ((tm->tm_mon + 1) << 5) + ((tm->tm_year - 80) << 9); *time = tm->tm_sec / 2 + (tm->tm_min << 5) + (tm->tm_hour << 11); } } /***************** Function setutime() sets the date and time of the filename supplied. Date and time is in MSDOS format. It assumes the existence of a function mstonix() that accepts MSDOS format time and returns **IX format time, and a function gettz() that returns the difference (localtime - gmt) in seconds, taking daylight savings time into account. */ int setutime(path,date,time) char *path; unsigned int date, time; { long mstonix(); long gettz(); long utimbuf[2]; utimbuf[0] = utimbuf[1] = gettz() + mstonix (date, time); return (utime (path, utimbuf)); } /**************** Function mstonix() accepts an MSDOS format date and time and returns a **IX format time. No adjustment is done for timezone. */ long mstonix (date, time) unsigned int date, time; { int year, month, day, hour, min, sec, daycount; long longtime; /* no. of days to beginning of month for each month */ static int dsboy[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; if (date == 0 && time == 0) /* special case! */ return (0L); /* part of following code is common to zoolist.c */ year = (((unsigned int) date >> 9) & 0x7f) + 1980; month = ((unsigned int) date >> 5) & 0x0f; day = date & 0x1f; hour = ((unsigned int) time >> 11)& 0x1f; min = ((unsigned int) time >> 5) & 0x3f; sec = ((unsigned int) time & 0x1f) * 2; /* DEBUG and leap year fixes thanks to Mark Alexander */ #ifdef DEBUG printf ("mstonix: year=%d month=%d day=%d hour=%d min=%d sec=%d\n", year, month, day, hour, min, sec); #endif /* Calculate days since 1970/01/01 */ daycount = 365 * (year - 1970) + /* days due to whole years */ (year - 1969) / 4 + /* days due to leap years */ dsboy[month-1] + /* days since beginning of this year */ day-1; /* days since beginning of month */ if (year % 4 == 0 && year % 400 != 0 && month >= 3) /* if this is a leap year and month */ daycount++; /* is March or later, add a day */ /* Knowing the days, we can find seconds */ longtime = daycount * 24L * 60L * 60L + hour * 60L * 60L + min * 60 + sec; return (longtime); } zoo-2.10.orig/options.c100644 1750 1750 3522 5035113600 13535 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) options.c 2.1 87/12/25 12:23:56"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved */ /* Here we define routines specific to only a few systems. Routines are selected based on defined symbols. Routines specific to only one system are in machine.c for the appropriate system. */ #include "options.h" #include "zooio.h" #include "various.h" #include "zoo.h" #include "zoofns.h" #include "errors.i" #ifdef REN_LINK /* rename using link() followed by unlink() */ /* The following code assumes that if unlink() returns nonzero, then the attempt to unlink failed. If unlink() ever returns nonzero after actually unlinking the file, then the file being renamed will be lost!!! Test this thoroughly. It is assumed that link() and unlink() return zero if no error else nonzero. */ int chname (newname, oldname) char *newname, *oldname; { int status; if (link (oldname, newname) == 0) { /* if we can create new name */ status = unlink (oldname); /* unlink old one */ if (status != 0) { /* if unlink of old name failed */ unlink (newname); /* cancel new link */ return (-1); /* return error */ } else return (0); } else /* couldn't create new link */ return (-1); } #else /* else not REN_LINK */ int chname (newname, oldname) char *newname, *oldname; { #ifdef REN_STDC if (rename(oldname, newname) != 0) /* ANSI standard */ #else if (rename(newname, oldname) != 0) /* its reverse */ #endif return (-1); else return (0); } #endif /* end of not REN_LINK */ /* Standard exit handler; not used if specific system defines its own. */ #ifndef SPECEXIT void zooexit (status) int status; { exit (status); } #endif zoo-2.10.orig/options.doc100644 1750 1750 37566 5035113600 14117 0ustar jamesjames/* derived from: options.doc 1.4 88/08/22 15:24:59 */ /* $Source: /usr/home/dhesi/zoo/RCS/options.doc,v $ */ /* $Id: options.doc,v 1.5 91/07/09 02:53:10 dhesi Exp $ */ Documentation about the file options.h. The file options.h defines various symbols and macros that are needed to ensure system-independence. The basic philosophy is to use a distinct symbol for each attribute that varies from machine to machine. Then, for each new system, we define symbols corresponding to its attributes. Thus, ideally, the only place in Zoo code that we actually use the name of a machine is in this file, in portable.h, and possibly in machine.h and options.c. Everywhere else in the code we only use names of attributes. LOOK IN THE FOLLOWING FILES WHEN MAKING CHANGES TO SUPPORT A NEW SYSTEM: options.h, portable.h, machine.c ALSO GLANCE AT THESE FILES TO MAKE SURE THEY WILL WORK: zooio.h, machine.h Machine names: MSC Microsoft C under MS-DOS (not currently in use) TURBOC Turbo C++ 1.0 under MS-DOS (works, compiled version is separately distributed) SYS_V Most releases of System V (works) VMS VAX/VMS 5.4 (works, stream-LF files only) BSD4_3 4.3BSD an most derivatives (works) MCH_AMIGA AmigaDOS Aztec/Manx C (not tested; compiled version will eventually follow) MERGED OR MIXED SYSTEMS. Many vendors of **IX systems take one of the two (System V or BSD) and add features from the other. In some cases they do a terrible job of reconciling irreconcilable differences between the two, such that the merged system will now compile neither System V stuff nor BSD stuff. If you are dealing with such a system, try compiling with both BSD4_3 and SYS_V in turn, and see if one of them works. If not, then go through the list of compilation symbols below and pick a set that matches your system. ------------------------------------------------------------------------ NOTE: The term "zoofile" below refers to an open file of type ZOOFILE. Currently this is defined to be equivalent to a standard buffered file pointer of type "ZOOFILE *" but this could change in the future. Dependence on exact definition of ZOOFILE is localized to a few files: options.h, portable.h, portable.c, and machine.c. ------------------------------------------------------------------------ Attributes of systems: CHEKDIR Test each supplied filename and if it is a directory or other special type of file, do not try to add it to an archive. If CHEKDIR is defined, then machine.c must also contain function isadir() that tests a supplied zoofile and returns 1 if it corresponds to a directory or other special type of file, else 0. CHEKUDIR Like CHEKDIR but use function isuadir() that tests a pathname, not a zoofile. Both CHEKDIR and CHEKUDIR may be defined, if both functions isadir() and isuadir() are available; in this case zoo code will use both and will execute slightly faster. (However, simultaneous definition of CHEKDIR and CHEKUDIR has not been tested.) DISK_CH If defined, must hold the value of a character that separates a disk name from the rest of the pathname. All characters up to and including this character will be removed from a pathname before it is stored in an archive. Usually a colon (':'). EXISTS If defined, is assumed to be a macro that accepts a filename and returns an int value of 1 if the file exists and 0 if it doesn't. If not defined, existence of files is tested by attempting to open them for read or write access. FATTR If defined, file attributes will be preserved. A function getfattr(f) must also exist that returns the attributes of a zoofile f (or of a pathname f, if the symbol FATTR_FNAME is also defined); and a function setfattr(f, a) must exist that sets the attributes of a file with pathname f to the value a. For more details see the source code in sysv.c and bsd.c. Currently the attribute value a is required to be in the zoo portable format. The lowest nine bits of this format correspond to the **IX mode bits described for chmod(2) and these are the only bits currently used. FATTR_FNAME If defined, and if FATTR is also defined, zoo code will obtain the attributes of a file by calling the function getfattr(f) and supplying it with filename f. If FATTR_FNAME is not defined, then getfattr(f) is supplied a zoofile f. ANSI_PROTO Use ANSI-style function prototypes declarations. VOIDPTR The type of a generic pointer, as returned by malloc(). This should be defined as void * in an ANSI C environment. In most other environments it will be char *. LINT If defined, SCCS identifier strings will not be included in the generated code. This will make the code smaller and will also avoid complaints from lint about unused variables. This symbol should be defined in the Makefile, NOT in `options.h', otherwise it will not be fully effective. FOLD Fold filenames to lowercase. Define this for case-insensitive filesystems FPUTCHAR If defined, a library function fputchar() is assumed available that is like fput() but is a function, not a macro, to save space. If not defined Zoo uses its own fputchar() function. PORTABLE Use portable functions --- define for every system except MS-DOS PURIFY When filenames are being read from standard input, ignore all characters begining with the first blank or tab encountered. This will allow filenames to be fed from a program that produces lines containing filenames followed by other information that should be ignored. Should be defined for most non-**IX systems. DONT_SORT Don't sort filename arguments -- files will be stored in the exact order in which names are supplied on the command line. Not currently used for any system, but could be used if memory is really tight. NOENUM Compiler does not support enumerations FNLIMIT Pathname length limit for this system NEEDCTYP If defined, tells the code to include the header file ctype.h for use by character conversion macros. If and only if NEEDCTYP is not defined, macros or appropriate function declarations can be put in portable.h. Zoo uses isupper(), isdigit(), toascii(), and tolower(). If NEEDCTYP is not defined, the symbol USE_ASCII can be defined to cause zoo to assume the ASCII character set and use its own isupper(), isdigit(), toascii(), and tolower() functions, possibly making the executable code smaller. USE_ASCII See description of NEEDCTYP. USE_ASCII should not be defined if NEEDCTYP is defined, else there may be conflicts between macro and function names. NIXTIME If defined, a function setutime() must be defined that will set the date and time of a file whose pathname is supplied. If not defined, a function settime() must be defined that will do the same for a zoofile. GETUTIME If defined, a function getutime() must be defined that will return the MS-DOS format date and time of the specified filename. If this symbol is not defined, then a function gettime() must be defined that will do the same for a zoofile instead of a filename. NOSIGNAL Don't use signals because library doesn't support them T_SIGNAL The data type returned by a signal handler. Historically "int", but "void" in ANSI C. PATH_CH The character that separates the directory name from the filename in a pathname. String value. PATH_SEP The set of characters that may separate preceding directory/device information from the filename. String value. EXT_SEP is the union of PATH_SEP and the set of characters separating a filename extension from the rest of the filename. String value. EXT_CH Character that separates base part of filename from extension. Char value. NEED_MEMSET If defined, zoo will define its own equivalent of memset(). if not defined, zoo will try to link with a standard library function memset(). EXT_DFLT default extension for archives. String. Currently ".zoo". NIXFNAME If defined, PATH_CH, PATH_SEP, EXT_SEP, EXT_CH, and EXT_DFLT get defined to conform to **IX conventions and should not be separately defined MSFNAME if defined, PATH_CH, PATH_SEP, EXT_SEP, EXT_CH, EXT_DFLT, and DISK_CH get defined to conform to MS-DOS conventions and should not be separately defined (not currently implemented) FORCESLASH If defined any backslashes in names of files will be converted to slashes before the files are added to an archive. This is useful for MSDOS-like systems that accept both slashes and backslashes, since the standard archive format allows only slashes as directory separators. REN_LINK Rename a file by using link() followed by unlink() (e.g. Xenix, System V) REN_STDC Use ANSI standard rename function: "int rename(old, new)" (e.g. 4.3BSD, Turbo C). Note: define exactly one of REN_LINK, REN_REV, and REN_STDC. REN_REV Use reverse rename function: "int rename(new, old)" (e.g. Microsoft C) SETMODE Change mode of standard output to binary when piping output, then change it back to text. Macros MODE_BIN(zoofile) and MODE_TEXT(zoofile) must also be defined. Probably specific to MS-DOS. SETBUF Standard output should be set to be unbuffered so output shows up quickly. SPECNEXT If defined, a machine-dependent function nextfile() must be defined that will expand wildcards in a supplied pathname. If not defined, any wildcard expansion must have been done before the command line parameters are supplied to the program. For details see the file nextfile.c. SPECEXIT Custom exit handler is needed. A function called zooexit() must be defined. If SPECEXIT is not defined, zoo uses its own zooexit() function which simply calls exit(). SPECINIT If defined, zoo's main() function will call spec_init() before doing anything else. Any system-specific initialization may be done at this point. GETTZ If defined, a function gettz() must also be defined that will return the current timezone, in seconds west of GMT, as a long value. Currently such a function is already defined in files bsd.c and sysv.c. If and only if GETTZ is defined, zoo will store the current timezone for each file that is archived, and will list the timezone for each file that has one when it lists archive contents. ALWAYS_INT In function prototypes for fgetc(), fread(), and fwrite(), traditional practice made certain arguments int, though they ought to be char and unsigned respectively. If ALWAYS_INT is defined, prototypes will use int only, else the correct types are used. NO_STDIO_FN Defining this symbol will cause declarations of fputc(), fread(), and fwrite() to not be done by the zoo header files. Reported necessary for VMS; may also help in other environments. IO_MACROS If defined, some portable I/O functions are defined as macros, saving space. ZOOCOMMENT If defined, archive comments are fully enabled. If not defined, zoo code will be smaller at the cost that archive comments will be listed but cannot be updated. COMPILATION WITHOUT ZOOCOMMENT DEFINED HAS NOT YET BEEN TESTED. TRACE_IO This is for debugging. If defined, it will cause code to be compiled that will trace all archive header and directory entry I/O by showing it on the screen in human-readable format. The tracing will then occur if any Expert command given to zoo is preceded by a colon. E.g., if compiled with TRACE_IO on and given the command "zoo :l xyz", zoo will give a directory listing of xyz.zoo exactly as it would with "zoo l xyz" except that all archive header and directory entry reads and writes will be shown on the screen. The tracing code is localized to the files zoo.c and portable.c, so just these two files can be compiled afresh when TRACE_IO is turned on or switched off. NOTE: The symbol TRACE_LIST, internal to the file "zoolist.c", enables debugging information too. Do not define both TRACE_IO and TRACE_LIST because (a) a symbol conflict will occur and (b) the debugging information will be duplicated. UNBUF_IO If defined, some I/O is done using low-level system calls read() and write(). To do this, the low-level file descriptor is synchronized with the buffered zoofile before such I/O is done. To do this, read(), write(), and lseek() system calls must be available and the fileno() macro must return the file descriptor for a buffered file. This is not portable and should definitely not be done by most end users. If UNBUF_IO is defined, also defined must be a symbol UNBUF_LIMIT with a numerical value that specifies the threshold over which unbuffered I/O should be used. For example, if the value of UNBUF_LIMIT is 512, then any I/O on a zoofile that reads or writes more than 512 bytes will be done using read() or write() system calls. The use of unbuffered I/O with a threshold in the range 512 to 1024 can enhance performance by up to 50%. The corruption of data is a serious matter. Do not define UNBUF_IO unless you are willing to exhaustively test the compiled code on your system to make sure it works, and accept full responsibility for any adverse consequences. Some standard I/O libraries may attempt to optimize the working of fseek() on files opened for read access only, and cause UNBUF_IO to fail. UNBUF_LIMIT Needed if and only if UNBUF_IO is defined. Holds a numeric value. All I/O done in blocks that are larger than UNBUF_LIMIT bytes will be done unbuffered. See UNBUF_IO. FILTER If defined, code will be compiled in to enable the fc and fd commands (compress or decompress, reading standard input and writing to standard output). These commands are useful only on systems that allow programs to easily act as filters. VER_DISPLAY The character that will separate filenames from generation numbers in listings of archive contents. Must be a single character in double quotes. VER_INPUT The characters that will be accepted as separating filenames from generation numbers when typed as an argument to select specific files from an archive. String value. May include one or more characters; any of them may then be typed and will work. NOSTRCHR Although 4.3BSD as distributed from Berkeley includes strchr() and strrchr() library functions, 4.2BSD and similar systems may not. If so, defining NOSTRCHR will cause zoo to use index() and rindex() instead. STDARG, VARARGS. How to invoke functions that accept a variable number of arguments. Define one of these. STDARG causes the ANSI-style header stdarg.h to be used. VARARGS causes the **IX-style varargs.h header to be used. If you define STDARG, you must also define ANSI_PROTO (see above). DIRECT_CONVERT. Zoo archives use a canonical little-endian byte order, and functions are portably defined to convert between this and the internal format used by an implementation. If the symbol DIRECT_CONVERT is defined, the zoo code will not bother doing this portable conversion, but simply assume that the machine's internal format is the same as the canonical byte order used in zoo archives. DIRECT_CONVERT should be defined *only* if your implementation uses: little-endian byte order, 2-byte ints, and 4-byte longs. If there is any doubt whatsoever, don't define DIRECT_CONVERT; the overhead of portable conversion is not significant. SZ_SCREEN. If this symbol is not defined, a screen height of 24 lines is assumed by the multiscreen help. If desired, this symbol can be defined to some other nonnegative value of screen height. NEED_MEMMOVE. If defined, zoo will define its own equivalent of memmove(). If not defined, zoo will try to link with a standard library function memmove(). NEED_VPRINTF. If this symbol is defined, zoo will use its own jury- rigged vprintf function. If this symbol is not defined, zoo will try to link with vprintf in the standard library. zoo-2.10.orig/options.h100644 1750 1750 20422 5035113600 13560 0ustar jamesjames/* @(#) options.h 2.22 88/08/24 15:27:36 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1991/07/06 For documentation about this file, see options.doc. */ #define ZOO /* always defined */ #define PORTABLE /* always defined */ #define ZOOCOMMENT /* always defined */ /***********************************************************************/ /* SYSTEM V (should be compatible with most releases) */ /***********************************************************************/ #ifdef SYS_V #define FILTER #define IO_MACROS #define EXISTS(f) (access(f, 00) == 0) #define FNLIMIT 14 #define CHEKDIR #define NIXTIME #define NIXFNAME #define NEEDCTYP #define NOENUM #define REN_LINK #define SETBUF #define GETTZ #define FATTR #define T_SIGNAL void #define VARARGS #define NEED_MEMMOVE /* #define NEED_MEMCPY */ #define T_UINT16 unsigned short /* must be 16 bit unsigned */ #define HAVE_ISATTY /* #define NEED_VPRINTF */ #endif /* SYS_V */ /***********************************************************************/ /* Turbo C++ 1.0 under MS-DOS */ /***********************************************************************/ #ifdef TURBOC #undef PORTABLE #define ANSI_HDRS #define USE_ASCII #define SPECINIT #define SPECEXIT #define PURIFY #define DISK_CH ':' #define IGNORECASE #define WILDCARD "*.*" #define FOLD #define FORCESLASH #define FNLIMIT 12 #define CUR_DIR "." #define PATH_SEP ":/\\" #define EXT_SEP ":/\\." #define SETMODE /* 0x8000 and 0x4000 taken from for Turbo C */ #define MODE_BIN(f) setmode(fileno(f), 0x8000) #define MODE_TEXT(f) setmode(fileno(f), 0x4000) #define NEED_STDIO #define ANSI_PROTO #define VOIDPTR void * #define REN_STDC #define STDARG #define T_UINT16 unsigned short /* must be 16 bit unsigned */ /* #define UNBUF_IO */ /* #define UNBUF_LIMIT 512 */ #define T_SIGNAL void #define DIRECT_CONVERT #define STDARG #define CHECK_BREAK #define check_break kbhit #define HAVE_ISATTY #ifdef PORTABLE /* for testing only */ # define SPECNEXT # define NIXTIME # undef WILDCARD #endif #endif /* TURBOC */ /***********************************************************************/ /* Older BSD 4.3 and most derivatives */ /***********************************************************************/ #ifdef BSD4_3 #define NOSTRCHR /* not really needed for 4.3BSD */ #define FILTER #define IO_MACROS #define EXISTS(f) (access(f, 00) == 0) #define FNLIMIT 1023 #define CHEKDIR #define NIXTIME #define NIXFNAME #define NEEDCTYP #define NOENUM #define REN_STDC #define SETBUF #define GETTZ #define FATTR #define T_SIGNAL int #define VARARGS #define NEED_MEMMOVE #define T_UINT16 unsigned short /* must be 16 bit unsigned */ #define HAVE_ISATTY #define NEED_VPRINTF /* older BSDs only; newer ones have vprintf */ #endif /* BSD4_3 */ /* Ultrix 4.1 */ #ifdef ULTRIX #define NO_STDIO_FN /* avoid declaring certain stdio functions */ #define NOSTRCHR /* needed? */ #define FILTER #define IO_MACROS #define EXISTS(f) (access(f, 00) == 0) #define FNLIMIT 1023 #define CHEKDIR #define NIXTIME #define NIXFNAME #define NEEDCTYP #define NOENUM #define REN_STDC #define SETBUF #define GETTZ #define FATTR #define T_SIGNAL void #define VARARGS #define NEED_MEMMOVE #define T_UINT16 unsigned short /* must be 16 bit unsigned */ #define HAVE_ISATTY /* #define NEED_VPRINTF */ #define BSD4_3 /* for I/O definitions */ #endif /* ULTRIX */ /***********************************************************************/ /* Newer BSD 4.4 (projected) */ /***********************************************************************/ #ifdef BSD4_4 /* #define NOSTRCHR */ #define FILTER #define IO_MACROS #define EXISTS(f) (access(f, 00) == 0) #define FNLIMIT 1023 #define CHEKDIR #define NIXTIME #define NIXFNAME #define NEEDCTYP /* #define NOENUM */ #define REN_STDC #define SETBUF #define GETTZ #define FATTR #define T_SIGNAL void /* #define VARARGS */ /* #define NEED_MEMMOVE */ #define T_UINT16 unsigned short /* must be 16 bit unsigned */ #define HAVE_ISATTY /* #define NEED_VPRINTF */ #endif /* BSD4_4 */ /***********************************************************************/ /* VAX/VMS version 5.3 or so */ /***********************************************************************/ #ifdef VMS /* Select VMS pre-4.6 or later next line. Pre-4.6 library does not have rename() and memset() so zoo defines its own; 4.6 has these, so we must use them, else VMS library functions will conflict with our own. */ # if 0 /* Make this 1 for VMS version 4.5 or earlier */ # define NEED_VMS_RENAME /* used in vms.c */ # define NEED_MEMSET # endif #define REN_STDC #define IO_MACROS #define SPEC_WILD #define EXT_ANYWAY #define VER_CH ';' #define SPECEXIT #define CHEKUDIR #define FNLIMIT 78 #define DIR_SEP '.' /* separates dir fields */ #define DISK_CH ':' #define DIR_LBRACK "[" /* left bracketing symbol dir dir name */ #define PATH_CH "]" #define PATH_SEP ":]" #define EXT_SEP ":]." #define CUR_DIR "." #define NIXTIME #define NEEDCTYP #define NOENUM #define IGNORECASE #define SPECMOD #define SPECNEXT #define WILDCARD "*.*" #define FOLD #define NO_STDIO_FN #define T_SIGNAL void #define T_UINT16 unsigned short /* must be 16 bit unsigned */ #define VARARGS #endif /* VMS */ /***********************************************************************/ /* AMIGA, SOME VERSION -- NOT TESTED, MAY NEED PORTING */ /***********************************************************************/ #ifdef MCH_AMIGA #define PURIFY #define DISK_CH ':' #define SPECNEXT #define WILDCARD "*" #define IGNORECASE #define FNLIMIT 30 #define NEEDCTYP #define CUR_DIR "." #define PATH_SEP ":/" #define EXT_SEP ":/." #define NOSIGNAL #define REN_STDC #define NOENUM #define SETBUF #define CHEKUDIR #define GETUTIME #define NIXTIME #endif /***********************************************************************/ /* GENERIC **IX SYSTEM -- GOOD STARTING POINT FOR YOURS */ /***********************************************************************/ #ifdef GENERIC /* #define SPECNEXT */ /* #define IGNORECASE */ #define FNLIMIT 14 #define NEEDCTYP #define CUR_DIR "." #define PATH_SEP "/" #define EXT_SEP "/." /* #define NOSIGNAL */ /* REN_LINK is UNIX-specific. Can't find a generic rename() function */ #define REN_LINK #define NOENUM /* #define SETBUF */ #define CHEKDIR #define NIXTIME #define HAVE_ISATTY #define NEED_MEMMOVE #endif /* GENERIC */ /***********************************************************************/ /* REST OF THIS FILE SHOULD NOT NEED ANY CHANGES */ /***********************************************************************/ /***********************************************************************/ /* Common filename conventions for **IX systems */ /***********************************************************************/ #ifdef NIXFNAME #define CUR_DIR "." #define PATH_SEP "/" #define EXT_CH '.' #define EXT_SEP "/." #define EXT_DFLT ".zoo" #endif /* Compensate for strchr/index differences */ #ifdef NOSTRCHR #define strchr index #define strrchr rindex #endif /* let non-**IX lints under **IX work (see makefile) */ #ifdef CROSS_LINT # undef ANSI_HDRS # undef ANSI_PROTO # ifdef STDARG # undef STDARG # define VARARGS # endif /* STDARG */ #endif /* assume certain defaults */ #ifndef VOIDPTR # define VOIDPTR char * #endif #ifndef VER_DISPLAY # define VER_DISPLAY ";" #endif #ifndef VER_INPUT # define VER_INPUT ":;" #endif #ifndef PATH_CH # define PATH_CH "/" #endif #ifndef EXT_CH # define EXT_CH '.' #endif #ifndef EXT_DFLT # define EXT_DFLT ".zoo" #endif #ifndef STDARG # ifndef VARARGS # define VARARGS # endif #endif #ifndef T_SIGNAL # define T_SIGNAL int #endif #ifdef STDARG # ifdef VARARGS # include "DO NOT DEFINE BOTH STDARG AND VARARGS" # endif #endif /* We supply a default for T_UINT16 if it is not defined. But this value is critical, so we compile in a runtime check. */ #ifndef T_UINT16 # define T_UINT16 unsigned short # define CHECK_TUINT /* will do runtime check for correct size */ #endif /* ANSI compatibility in declarations -- see zoofns.h for usage */ #ifndef PARMS # ifdef ANSI_PROTO # define PARMS(x) x # else # define PARMS(x) () # endif #endif zoo-2.10.orig/options.opt100644 1750 1750 34 5035113600 14050 0ustar jamesjamessys$share:vaxcrtl.exe/share zoo-2.10.orig/parse.c100644 1750 1750 13010 5035113600 13165 0ustar jamesjames#ifndef LINT static char sccsid[]="@(#) parse.c 2.1 87/12/25 12:24:10"; #endif /* LINT */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ #include "options.h" #include "zoo.h" #include "zooio.h" #include "various.h" #include "zoofns.h" #include "parse.h" #include "assert.h" /* parse() accepts a filename and return its component parts in a structure. The component parts are: disk drive, path prefix, root name of filename, and extension. If DISK_CH is not defined, it is assumed that filenames may be preceded with a disk prefix terminated by the character DISK_CH. The first character of the disk prefix, followed by DISK_CH, is returned in the drive field. If the symbol DISK_CH is defined, a null string is returned in the disk field. */ void parse (path_st, fname) register struct path_st *path_st; char *fname; { char tempname[LFNAMESIZE]; /* working copy of supplied fname */ char *namep; /* points to relevant part of tempname */ char *p; strcpy (tempname, fname); #ifdef DEBUG printf ("parse: supplied name is [%s].\n", tempname); #endif #ifndef DISK_CH path_st->drive[0] = '\0'; namep = tempname; /* points to pathname+filename */ #else path_st->drive[0] = '\0'; p = strchr (tempname, DISK_CH); /* point to first ':' */ if (p != NULL) { path_st->drive[0] = *tempname;/* use only first char of drive name */ path_st->drive[1] = DISK_CH; path_st->drive[2] = '\0'; namep = ++p; /* point to pathname+filename */ } else { path_st->drive[0] = '\0'; namep = tempname; /* points to pathname+filename */ } #endif /* end of not DISK_CH */ /* Note: findlast() finds last occurrence in the subject string of any one of a set of chars */ /* save the long filename */ p = findlast (namep, PATH_SEP); /* if path separator found, copy next char onwards; else entire string */ strncpy (path_st->lfname, (p != NULL) ? p+1 : namep, LFNAMESIZE); path_st->lfname[LFNAMESIZE-1] = '\0'; /* force null termination */ #ifdef DEBUG printf ("parse: path = [%s] long filename = [%s]\n", namep, path_st->lfname); #endif /* Separate out the extension */ p = findlast (namep, EXT_SEP); /* look for . or / */ if (p != NULL && *p != EXT_CH) /* found .? */ p = NULL; /* ... if not, ignore / */ #ifdef DEBUG if (p == NULL) printf ("parse: no extension found for [%s]\n", namep); else printf ("parse: extension for [%s] is [%s]\n", namep, p); #endif path_st->ext[0] = '\0'; /* assume no extension */ if (p != NULL) { /* found extension */ strncpy (path_st->ext, (p+1), EXTLEN); /* save extension */ path_st->ext[EXTLEN] = '\0'; /* force termination */ *p = '\0'; /* null out extension */ } /* separate out root of filename if any */ p = findlast (namep, PATH_SEP); if (p != NULL) { ++p; strncpy (path_st->fname, p, ROOTSIZE); /* save filename */ *p = '\0'; /* null out filename */ } else { strncpy (path_st->fname, namep, ROOTSIZE); *namep = '\0'; /* null out filename */ } path_st->fname[ROOTSIZE] = '\0'; /* force termination */ /* what remains, whether null or not, is the path prefix */ path_st->dir[0] = '\0'; /* in case *namep is '\0' */ strncpy (path_st->dir, namep, PATHSIZE); /* remove trailing path-separater from directory name, but don't remove it if it is also the leading separater */ { int n; n = strlen(path_st->dir); if (n != 1) path_st->dir[n-1] = '\0'; } #ifdef DEBUG printf ("parse: path prefix = [%s].\n", namep); #endif /* if extension is null, and if long filename contains more than ROOTSIZE characters, transfer some of them to extension */ if (path_st->ext[0] == '\0' && strlen(path_st->lfname) > ROOTSIZE) { strncpy(path_st->ext, &path_st->lfname[ROOTSIZE], EXTLEN); path_st->ext[3] = '\0'; } } /*******************/ /* findlast() finds last occurrence in provided string of any of the characters except the null character in the provided set. If found, return value is pointer to character found, else it is NULL. */ char *findlast (str, set) register char *str; /* subject string */ char *set; /* set of characters to look for */ { register char *p; if (str == NULL || set == NULL || *str == '\0' || *set == '\0') return (NULL); p = lastptr (str); /* pointer to last char of string */ assert(p != NULL); while (p != str && strchr (set, *p) == NULL) { --p; } /* either p == str or we found a character or both */ if (strchr (set, *p) == NULL) return (NULL); else return (p); } /*******************/ /* lastptr() returns a pointer to the last non-null character in the string, if any. If the string is null it returns NULL */ char *lastptr (str) register char *str; /* string in which to find last char */ { register char *p; if (str == NULL) prterror ('f', "lastptr: received null pointer\n"); if (*str == '\0') return (NULL); p = str; while (*p != '\0') /* find trailing null char */ ++p; --p; /* point to just before it */ return (p); } zoo-2.10.orig/parse.h100644 1750 1750 1300 5035113600 13151 0ustar jamesjames/* @(#) parse.h 2.1 87/12/25 12:24:15 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ /* defines structure used in call to parse() */ #define XTRA 2 /* extra space to avoid off-by-one errors */ struct path_st { char drive[2+1+XTRA]; /* drive name */ char dir[PATHSIZE+1+XTRA]; /* path prefix */ char fname[8+1+XTRA]; /* root name of filename */ char lfname[LFNAMESIZE+1+XTRA]; /* long filename */ char ext[EXTLEN+1+XTRA]; /* extension */ }; #ifdef LINT_ARGS void parse (struct path_st *, char *); #else void parse(); #endif zoo-2.10.orig/portable.c100644 1750 1750 52155 5035113600 13700 0ustar jamesjames#ifndef LINT /* @(#) portable.c 2.24 88/08/24 01:22:06 */ static char sccsid[]="@(#) portable.c 2.24 88/08/24 01:22:06"; #endif /* LINT */ #include "options.h" /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ /********************** portable.c contains functions needed to make Zoo portable to various implementations of C. Note: Provided a 2's complement machine is used, all functions in this file are themselves machine-independent and need not be changed when implementing Zoo on a different machine. Some code will choke on 1's complement machines--I think. For machine-dependent declarations see files "machine.h" and "options.h". For machine-dependent functions see file "machine.c" */ #include "zoo.h" #include "zooio.h" #include "various.h" #include "zoofns.h" #include "machine.h" #include "debug.h" #include "assert.h" #ifdef NEEDCTYP #include /* for tolower() */ #endif #include "portable.h" #ifdef TRACE_IO extern int verbose; #endif /* Functions defined for use within this file only. */ long to_long PARMS((BYTE[])); int to_int PARMS((BYTE[])); void b_to_zooh PARMS((struct zoo_header *, BYTE[])); void b_to_dir PARMS((struct direntry *, BYTE[])); int dir_to_b PARMS((BYTE[], struct direntry *)); void zooh_to_b PARMS((BYTE[], struct zoo_header *)); void splitlong PARMS((BYTE[], long)); void splitint PARMS((BYTE[], int)); #ifdef TRACE_IO void show_h PARMS ((struct zoo_header *)); void show_dir PARMS ((struct direntry *)); #endif /* TRACE_IO */ extern unsigned int crccode; /************************************************************************/ /* I/O functions */ /************************************************************************/ /* some functions get defined only if they aren't already macros */ #ifndef zooread int zooread (file, buffer, count) ZOOFILE file; char *buffer; int count; { return (fread (buffer, 1, count, file)); } #endif /* zooread */ #ifndef FIZ #ifndef zoowrite int zoowrite (file, buffer, count) ZOOFILE file; char *buffer; int count; { if (file == NULLFILE) return (count); else return (fwrite (buffer, 1, count, file)); } #endif /* zoowrite */ ZOOFILE zoocreate (fname) char *fname; { return ((ZOOFILE) fopen (fname, Z_NEW)); } #endif /* FIZ */ #ifndef zooseek long zooseek (file, offset, whence) ZOOFILE file; long offset; int whence; { return (fseek (file, offset, whence)); } #endif /* zooseek */ ZOOFILE zooopen (fname, option) char *fname; char *option; { return ((ZOOFILE) fopen (fname, option)); } #ifndef zootell long zootell (file) ZOOFILE file; { return ftell (file); } #endif /* zootell */ int zooclose (file) ZOOFILE file; { return fclose (file); } /********************** low_ch() is a macro that returns a lowercased char; it may be used with any char, whether or not it is uppercase. It will be used below by one or two functions. */ #define low_ch(c) (isupper(c) ? tolower(c) : c) /************************************************************************/ /*** Following are functions that make up for various implementations ***/ /*** of C not having certain library routines. ***/ /************************************************************************/ #ifndef FIZ /********************** str_lwr() converts a string to lowercase and returns a pointer to the string */ char *str_lwr (str) char *str; { register char *s; s = str; while (*s != '\0') { *s = toascii(*s); *s = low_ch(*s); s++; } return (str); } /********************** str_icmp() compares strings just like strcmp() but it does it without regard to case. */ int str_icmp (s1, s2) register char *s1, *s2; { for ( ; low_ch(*s1) == low_ch(*s2); s1++, s2++) if (*s1 == '\0') return(0); return(low_ch(*s1) - low_ch(*s2)); } #ifdef NEED_MEMSET /********************** memset() it sets the first "count" bytes of "dest" to the character "c" and returns a pointer to "dest". */ VOIDPTR memset (dest, c, count) register VOIDPTR dest; int c; unsigned count; { register unsigned i; for (i = 0; i < count; i++) { *((char *) (dest + i)) = c; } return dest; } #endif /* NEED_MEMSET */ #ifdef NEED_MEMCPY /********************** memcpy() copies "count" bytes from "src" to "dest" and returns a pointer to "dest". Not necessarily safe for overlapping moves. */ VOIDPTR memcpy(dest, src, count) register VOIDPTR dest; register VOIDPTR src; unsigned count; { VOIDPTR savedest = dest; while (count > 0) { *((char *) dest++) = *((char *) src++); count--; } } #endif /* NEED_MEMCPY */ #ifndef FPUTCHAR /********************** fputchar() writes a character to stdout. It is identical to putchar but is a function, not a macro. */ int fputchar (c) int c; { return (fputc(c, stdout)); } #endif /* FPUTCHAR */ #endif /* FIZ */ /***********************************************************************/ /*** Following are declarations and functions that are written in a ***/ /*** machine-independent way but they implement machine-dependent ***/ /*** activities ***/ /***********************************************************************/ #ifndef DIRECT_CONVERT /********************** to_long() converts four consecutive bytes, in order of increasing significance, to a long integer. It is used to make Zoo independent of the byte order of the system. */ long to_long(data) BYTE data[]; { return (long) ((unsigned long) data[0] | ((unsigned long) data[1] << 8) | ((unsigned long) data[2] << 16) | ((unsigned long) data[3] << 24)); } #ifndef FIZ /******************** splitlong() converts a long integer to four consecutive BYTEs in order of increasing significance. */ void splitlong(bytes, bigword) BYTE bytes[]; long bigword; { int i; for (i = 0; i < 4; i++) { bytes[i] = bigword & 0xff; bigword = (unsigned long) bigword >> 8; } } #endif /* FIZ */ /******************* splitint() converts an integer to two consecutive BYTEs in order of increasing significance. */ void splitint(bytes, word) BYTE bytes[]; int word; { bytes[0] = word & 0xff; word = (unsigned int) word >> 8; bytes[1] = word & 0xff; } /********************** to_int() converts two consecutive bytes, in order of increasing significance, to an integer, in a machine-independent manner */ int to_int(data) BYTE data[]; { return (int) ((unsigned int) data[0] | ((unsigned int) data[1] << 8)); } #else /* else of ifndef DIRECT_CONVERT */ long to_long(data) BYTE data[]; { return ( * (long *) data ); } #ifndef FIZ /******************** splitlong() converts a long integer to four consecutive BYTEs in order of increasing significance. */ void splitlong(bytes, bigword) BYTE bytes[]; long bigword; { * (long *) bytes = bigword; } #endif /* FIZ */ /******************* splitint() converts an integer to two consecutive BYTEs in order of increasing significance. */ void splitint(bytes, word) BYTE bytes[]; int word; { * (int *) bytes = word; } /********************** to_int() converts two consecutive bytes, in order of increasing significance, to an integer. */ int to_int(data) BYTE data[]; { return (*(int *) data); } #endif /* ifndef DIRECT_CONVERT .. else ... */ #ifndef FIZ /********************** Function frd_zooh() reads the header of a Zoo archive in a machine- independent manner, from a ZOOFILE. */ int frd_zooh(zoo_header, zoo_file) struct zoo_header *zoo_header; ZOOFILE zoo_file; { int status; BYTE bytes[SIZ_ZOOH]; /* canonical header representation */ #ifdef TRACE_IO if (verbose) { printf("At file position [%8lx] ", ftell(zoo_file)); } #endif status = zooread (zoo_file, (char *) bytes, SIZ_ZOOH); b_to_zooh (zoo_header, bytes); /* convert array to structure */ #ifdef TRACE_IO if (verbose) { printf("frd_zooh: reading\n"); show_h(zoo_header); } #endif if (status < MINZOOHSIZ) return (-1); else return (0); } #endif /* FIZ */ /********************** Function frd_dir() reads a directory entry in a machine-independent manner, from a ZOOFILE. */ int frd_dir(direntry, zoo_file) struct direntry *direntry; ZOOFILE zoo_file; { int status; BYTE bytes[MAXDIRSIZE]; /* big enough to hold variable part too */ /* To simplify things, we read the maximum possible size of the directory entry including the variable size and discard what is not needed */ #ifdef TRACE_IO if (verbose) { printf("At file position [%8lx] ", ftell(zoo_file)); } #endif status = zooread (zoo_file, (char *) bytes, MAXDIRSIZE); if (status < SIZ_DIR) return (-1); b_to_dir (direntry, bytes); #ifdef TRACE_IO if (verbose) { printf("frd_dir: reading\n"); show_dir(direntry); } #endif return (0); } #ifndef FIZ /*********************** Function fwr_dir() writes a directory entry in a machine-independent manner to a ZOOFILE. Return value is -1 on error, else 0. */ int fwr_dir(direntry, zoo_file) struct direntry *direntry; ZOOFILE zoo_file; { int size; BYTE bytes[MAXDIRSIZE]; assert (direntry->type <= 2); size = dir_to_b (bytes, direntry); #ifdef TRACE_IO if (verbose) { printf("At file position [%8lx] ", ftell(zoo_file)); printf("fwr_dir: writing\n"); show_dir(direntry); } #endif if (zoowrite (zoo_file, (char *) bytes, size) != size) return (-1); else return (0); } /*********************** Function fwr_zooh() writes an archive header in a machine-independent manner to a ZOOFILE. Return value is -1 if error else 0. */ int fwr_zooh(zoo_header, zoo_file) struct zoo_header *zoo_header; ZOOFILE zoo_file; { BYTE bytes[SIZ_ZOOH]; /* was SIZ_DIR -- probably a typo */ int hsize; /* how much to write -- depends on header type */ hsize = MINZOOHSIZ; /* in case it's an old type 0 header */ if (zoo_header->type > 0) /* but if it's a newer header... */ hsize = SIZ_ZOOH; /* ...size of new type 1 header */ zooh_to_b (bytes, zoo_header); if (zoowrite (zoo_file, (char *) bytes, hsize) != hsize) return (-1); else return (0); } /*********************** b_to_zooh() converts an array of BYTE to a zoo_header structure. */ void b_to_zooh (zoo_header, bytes) struct zoo_header *zoo_header; BYTE bytes[]; { int i; for (i = 0; i < SIZ_TEXT; i++) /* copy text */ zoo_header->text[i] = bytes[TEXT_I + i]; zoo_header->zoo_tag = to_long(&bytes[ZTAG_I]); /* copy zoo_tag */ zoo_header->zoo_start = to_long(&bytes[ZST_I]); /* copy zoo_start */ zoo_header->zoo_minus = to_long(&bytes[ZSTM_I]); zoo_header->major_ver = bytes[MAJV_I]; /* copy versions */ zoo_header->minor_ver = bytes[MINV_I]; /* default is no archive comment and a header type of 0 */ zoo_header->type = 0; zoo_header->acmt_pos = 0L; zoo_header->acmt_len = 0; zoo_header->vdata = 0; if (zoo_header->zoo_start != FIXED_OFFSET) { /* if newer header */ zoo_header->type = bytes[HTYPE_I]; zoo_header->acmt_pos = to_long(&bytes[ACMTPOS_I]); zoo_header->acmt_len = to_int(&bytes[ACMTLEN_I]); zoo_header->vdata = bytes[HVDATA_I]; } } /*********************** zooh_to_b() converts a zoo_header structure to an array of BYTE. */ void zooh_to_b (bytes, zoo_header) struct zoo_header *zoo_header; BYTE bytes[]; { int i; for (i = 0; i < SIZ_TEXT; i++) /* copy text */ bytes[TEXT_I + i] = zoo_header->text[i]; splitlong (&bytes[ZTAG_I], zoo_header->zoo_tag); splitlong (&bytes[ZST_I], zoo_header->zoo_start); splitlong (&bytes[ZSTM_I], zoo_header->zoo_minus); bytes[MAJV_I] = zoo_header->major_ver; /* copy versions */ bytes[MINV_I] = zoo_header->minor_ver; bytes[HTYPE_I] = zoo_header->type; /* header type */ if (zoo_header->type > 0) { splitlong (&bytes[ACMTPOS_I], zoo_header->acmt_pos); /* comment posn */ splitint (&bytes[ACMTLEN_I], zoo_header->acmt_len); /* comment len */ bytes[HVDATA_I] = zoo_header->vdata; /* version data */ } } /* zooh_to_b() */ /************************ dir_to_b() converts a directory entry structure to an array of BYTE. */ int dir_to_b (bytes, direntry) struct direntry *direntry; BYTE bytes[]; { int i; int cursize; int fixsize; int totalsize; splitlong(&bytes[DTAG_I], direntry->zoo_tag); bytes[DTYP_I] = direntry->type ; bytes[PKM_I] = direntry->packing_method ; splitlong(&bytes[NXT_I], direntry->next); splitlong(&bytes[OFS_I], direntry->offset); splitint(&bytes[DAT_I], direntry->date); splitint(&bytes[TIM_I], direntry->time); splitint(&bytes[CRC_I], direntry->file_crc); splitlong(&bytes[ORGS_I], direntry->org_size); splitlong(&bytes[SIZNOW_I], direntry->size_now); bytes[DMAJ_I] = direntry->major_ver; bytes[DMIN_I] = direntry->minor_ver; bytes[DEL_I] = direntry->deleted; bytes[STRUC_I] = direntry->struc; splitlong(&bytes[CMT_I], direntry->comment); splitint(&bytes[CMTSIZ_I], direntry->cmt_size); for (i = 0; i < FNM_SIZ; i++) bytes[FNAME_I + i] = direntry->fname[i]; bytes[TZ_I] = NO_TZ; /* assume unknown */ bytes[NAMLEN_I] = 0; bytes[DIRLEN_I] = 0; cursize = SIZ_DIR; /* to count size of directory */ fixsize = SIZ_DIR; /* size of fixed part */ assert (direntry->type <= 2); if (direntry->type == 2) { /* handle stuff relevant to type 2 */ cursize = SIZ_DIRL; fixsize = SIZ_DIRL; bytes[TZ_I] = direntry->tz; assert(direntry->namlen < 256 && direntry->namlen >= 0); cursize += 2; /* space for namlen and dirlen */ if (direntry->namlen != 0) { bytes[NAMLEN_I] = direntry->namlen; for (i = 0; i < direntry->namlen; i++) bytes[LFNAME_I+i] = direntry->lfname[i]; cursize += direntry->namlen; } assert(direntry->dirlen < 256 && direntry->dirlen >= 0); if (direntry->dirlen != 0) { bytes[DIRLEN_I] = direntry->dirlen; for (i = 0; i < direntry->dirlen; i++) bytes[cursize+i] = direntry->dirname[i]; cursize += direntry->dirlen; } /* Can't store system id if no namlen & dirlen...BUG!...now fixed. Fortunately, system_id was always 0 so far so it probably got interpreted as namlen=0 and dirlen=0 (2 bytes) */ splitint(&bytes[cursize], direntry->system_id); cursize += 2; bytes[cursize] = direntry->fattr & 0xff; /* byte 0 */ splitint(&bytes[cursize+1], (int) (direntry->fattr >> 8)); /* 1 & 2 */ cursize += 3; bytes[cursize] = (direntry->vflag & 0xff); /* version flag */ splitint(&bytes[cursize+1], direntry->version_no); /* version number */ cursize += 3; } splitint(&bytes[VARDIRLEN_I], direntry->var_dir_len); assert(cursize == ((bytes[DIRLEN_I] > 0 || bytes[NAMLEN_I] > 0) ? 2 : 0) + fixsize + bytes[DIRLEN_I] + bytes[NAMLEN_I] ); /* total size of dir entry is size of fixed part + size of var. part */ totalsize = fixsize + direntry->var_dir_len; /* Do CRC assuming CRC field is zero, and stuff CRC into field. */ splitint(&bytes[DCRC_I], 0); /* fill with zeroes */ crccode = 0; /* avoid mixing pointers to signed and unsigned char */ addbfcrc((char *) bytes, totalsize); /* update CRC */ splitint(&bytes[DCRC_I], crccode); /* return total length of directory entry */ return (totalsize); } /* dir_to_b() */ #endif /* FIZ */ /* b_to_dir() converts bytes to directory entry structure. The CRC of the directory bytes, if any, is checked and a zero or nonzero value is returned in direntry->dir_crc according as the check is good or bad */ void b_to_dir(direntry, bytes) struct direntry *direntry; BYTE bytes[]; { int i; int sysid_offs; /* temp variable */ unsigned int savecrc; direntry->zoo_tag = to_long(&bytes[DTAG_I]); direntry->type = bytes[DTYP_I]; direntry->packing_method = bytes[PKM_I]; direntry->next = to_long(&bytes[NXT_I]); direntry->offset = to_long(&bytes[OFS_I]); direntry->date = to_int(&bytes[DAT_I]); direntry->time = to_int(&bytes[TIM_I]); direntry->file_crc = to_int(&bytes[CRC_I]); direntry->org_size = to_long(&bytes[ORGS_I]); direntry->size_now = to_long(&bytes[SIZNOW_I]); direntry->major_ver = bytes[DMAJ_I]; direntry->minor_ver = bytes[DMIN_I]; direntry->deleted = bytes[DEL_I]; direntry->struc = bytes[STRUC_I]; direntry->comment = to_long(&bytes[CMT_I]); direntry->cmt_size = to_int(&bytes[CMTSIZ_I]); /* for now, versions not implemented */ direntry->vflag = 0; direntry->version_no = 0; for (i = 0; i < FNM_SIZ; i++) direntry->fname[i] = bytes[FNAME_I + i]; /* start by assuming variable part is zero bytes */ direntry->var_dir_len = direntry->dir_crc = 0; direntry->namlen = direntry->dirlen = 0; direntry->lfname[0] = direntry->dirname[0] = '\0'; direntry->tz = NO_TZ; /* assume unknown */ direntry->system_id = SYSID_NIX; /* default system_id if not present */ direntry->fattr = NO_FATTR; /* assume none */ assert (direntry->type <= 2); if (direntry->type == 2) { direntry->var_dir_len = to_int(&bytes[VARDIRLEN_I]); assert(direntry->var_dir_len <= MAXDIRSIZE); if (direntry->var_dir_len > MAXDIRSIZE) direntry->var_dir_len = MAXDIRSIZE; direntry->tz = bytes[TZ_I]; if (direntry->var_dir_len > 0) direntry->namlen = bytes[NAMLEN_I]; if (direntry->var_dir_len > 1) direntry->dirlen = bytes[DIRLEN_I]; for (i = 0; i < direntry->namlen; i++) direntry->lfname[i] = bytes[LFNAME_I + i]; for (i = 0; i < direntry->dirlen; i++) direntry->dirname[i] = bytes[DIRNAME_I + direntry->namlen + i]; sysid_offs = DIRNAME_I + direntry->namlen + i; /* offset of system id */ if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 2) { direntry->system_id = to_int(&bytes[sysid_offs]); } if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 4) { direntry->fattr = ((unsigned long) bytes[sysid_offs + 2]) | ((unsigned long) bytes[sysid_offs + 3] << 8) | ((unsigned long) bytes[sysid_offs + 4] << 16); } if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 7) { direntry->vflag = bytes[sysid_offs + 5]; direntry->version_no = to_int(&bytes[sysid_offs + 6]); } /* do CRC calculation */ savecrc = (unsigned int) to_int(&bytes[DCRC_I]); crccode = 0; splitint(&bytes[DCRC_I], 0); addbfcrc((char *) bytes, SIZ_DIRL + direntry->var_dir_len); direntry->dir_crc = crccode - savecrc; } } #ifdef FILTER #define TWOBYTES 2 /* better than literal 2; figure out why */ /* rdint() reads two bytes from standard input in archive order */ int rdint (val) unsigned int *val; { BYTE bytes[TWOBYTES]; if (zooread (STDIN, bytes, TWOBYTES) == TWOBYTES) { *val = to_int(bytes); return (0); } else return (1); } /* wrint() writes an unsigned int to standard output in archive order */ int wrint (val) unsigned int val; { BYTE bytes[TWOBYTES]; splitint (bytes, val); if (zoowrite (STDOUT, bytes, TWOBYTES) == TWOBYTES) return (0); else return (1); } #endif /* FILTER */ #ifdef TRACE_IO /* dump contents of archive header */ void show_h (zoo_header) struct zoo_header *zoo_header; { int i; printf ("Header text:\n"); for (i = 0; i < SIZ_TEXT; i++) { /* ASSUMES ASCII TEXT */ int c; c = zoo_header->text[i]; if (c >= ' ' && c < 0x7f) putchar (c); else { putchar ('^'); putchar (i & 0x40); } } putchar('\n'); printf ("zoo_tag = [%8lx] zoo_start = [%8lx] zoo_minus = [%8lx]\n", zoo_header->zoo_tag, zoo_header->zoo_start, zoo_header->zoo_minus); printf ("major_ver.minor_ver = [%d.%d]\n", zoo_header->major_ver, zoo_header->minor_ver); if (zoo_header->zoo_start != FIXED_OFFSET) { printf ("type = [%d] ", zoo_header->type); printf ("acmt_pos = [%8lx] acmt_len = [%4x] vdata = [%2x]", zoo_header->acmt_pos, zoo_header->acmt_len, zoo_header->vdata); printf ("\n"); } printf ("---------\n"); } /* dump contents of directory entry */ void show_dir (direntry) struct direntry *direntry; { printf ("Directory entry for file [%s][%s]:\n", direntry->fname, direntry->lfname); printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n", direntry->zoo_tag, (int) direntry->type, (int) direntry->packing_method, direntry->next, direntry->offset); printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n", direntry->org_size, direntry->size_now, (int) direntry->major_ver, (int) direntry->minor_ver); printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n", (int) direntry->struc, (int) direntry->deleted, direntry->comment, direntry->cmt_size); printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n", direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc); printf ("system_id = [%d] dirlen = [%d] namlen = [%d] fattr=[%24lx]\n", direntry->system_id, direntry->dirlen, direntry->namlen, direntry->fattr); printf ("vflag = [%4x] version_no = [%4x]\n", direntry->vflag, direntry->version_no); if (direntry->dirlen > 0) printf ("dirname = [%s]\n", direntry->dirname); printf ("---------\n"); } #endif /* TRACE_IO */ zoo-2.10.orig/portable.h100644 1750 1750 5141 5035113600 13656 0ustar jamesjames/* @(#) portable.h 2.3 87/12/26 12:25:49 */ /* @(#) portable.h 2.4 88/08/24 00:56:43 */ /* Definitions for portable I/O The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 DEFINITIONS IN THIS FILE Symbols: Z_WRITE, Z_READ, and Z_RDWR are the parameters to supply to zooopen() and to open an existing file for write, read, and read-write respectively. Z_NEW is the parameter to supply to zoocreate() to open an existing file or create a new file for write and read. The file must be opened in binary format, with no newline translation of any kind. Macros or functions: zgetc(x) reads a character from ZOOFILE x. zputc(c, f) writes a character to a ZOOFILE x. zputchar(c) writes a character c to standard output. MKDIR(x) creates a directory x. */ /* Borland's Turbo C. */ #ifdef TURBOC /* options for zooopen(), zoocreate() */ #define Z_WRITE "r+b" #define Z_READ "rb" #define Z_RDWR "r+b" #define Z_NEW "w+b" #define zgetc(x) getc(x) #define zputc(c, f) putc(c, f) #define zputchar(c) putchar(c) #define MKDIR(x) mkdir(x) int mkdir PARMS((char *)); #endif /* Microsoft C 3.0 */ #ifdef MSC /* options for zooopen(), zoocreate() */ #define Z_WRITE "r+b" #define Z_READ "rb" #define Z_RDWR "r+b" #define Z_NEW "w+b" #define zgetc(x) getc(x) #define zputc(c, f) putc(c, f) #define zputchar(c) putchar(c) #define MKDIR(x) mkdir(x) int mkdir (char *); #endif #ifdef VMS #define Z_WRITE "r+" #define Z_READ "r" #define Z_RDWR "r+" #define Z_NEW "w+b" #define zgetc(x) getc(x) #define zputc(c, f) putc(c, f) #define zputchar(c) putchar(c) #define MKDIR(x) vmsmkdir (x, 0) #endif #ifdef GENERIC /* **IX I/O, but MKDIR() is a no-operation */ #define NIX_IO /* standard **IX I/O */ #define MKDIR(x) #endif /* **IX System V release 2.1 */ #ifdef SYS_V #define NIX_IO /* standard **IX I/O */ #define MKDIR(x) mkdir(x) /* define this in sysv.c */ #endif /* Xenix */ #ifdef XENIX #define NIX_IO /* standard **IX I/O */ #endif /* 4.3BSD */ #ifdef BSD4_3 #define NIX_IO /* standard **IX I/O */ #define MKDIR(x) mkdir(x, 0777) #endif /* Amiga */ #ifdef MCH_AMIGA # include "MCH_AMIGA NEEDS REVISION" #endif /* Standard **IX I/O definitions */ #ifdef NIX_IO /* options for zooopen(), zoocreate() */ #define Z_WRITE "r+" #define Z_READ "r" #define Z_RDWR "r+" #define Z_NEW "w+" #define zgetc(x) getc(x) #define zputc(c, f) putc(c, f) #define zputchar(c) putchar(c) #endif /* NIX_IO */ zoo-2.10.orig/prterror.c100644 1750 1750 21606 5035113600 13744 0ustar jamesjames#ifndef LINT /* @(#) prterror.c 2.8 88/01/31 18:48:17 */ static char sccsid[]="@(#) prterror.c 2.8 88/01/31 18:48:17"; #endif /* LINT */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ #include "options.h" #ifndef OK_STDIO #include #define OK_STDIO #endif #include "various.h" #include "zooio.h" #include "zoofns.h" #ifdef NEEDCTYP # include /* for isdigit() */ #endif #ifdef STDARG # include #else # ifdef VARARGS # include # else # include "MUST DEFINE STDARG OR VARARGS" # endif #endif #ifdef NEED_VPRINTF static int zvfprintf(); #endif /* General error handler. Input format: parameter 1: 'w', 'e', or 'f'. 'm': message 'M': message without preceding identification 'w': WARNING 'e': ERROR 'f': FATAL 'F': FATAL but program doesn't exist immediately All text printed is preceded by "Zoo: " or "Ooz: " depending upon conditional compilation, except in the case of 'M' messages which are printed without any text being added. For messages, the text supplied is printed if and only if the global variable "quiet" is zero. Control then returns to the caller. For warnings, errors, and fatal errors, the variable "quiet" is used as follows. Warning messages are suppressed if quiet > 1; error messages are suppressed if quiet > 2. Fatal error messages are never suppressed--doing so would be a bit risky. For warnings and errors, the error message is preceded by the "WARNING:" or "ERROR". The error message is printed and control returns to the caller. For fatal errors, the error message is preceded by "FATAL:" and an error message is printed. If the option was 'f', the program exits with a status of 1. If the option was 'F', control returns to the caller and it is assumed that the caller will do any cleaning up necessary and then exit with an error status. parameter 2: The format control string for printf. remining parameters: passed on to vprintf(). All messages, whether informative or error, are sent to standard output via printf. It might be a good idea to eventually send 'e' and 'f' class messages to the standard error stream. Best would be some way of telling if standard output and standard error are not the same device, so that we could always send error messages to standard error, and also duplicate them to standard output if different from standard error. This is one thing that VMS seems to be capable of doing. There seems to be no way of doing this in the general case. */ extern int quiet; /* These declarations must be equivalent to those in errors.i */ char no_match[] = "No files matched.\n"; char failed_consistency[] = "Archive header failed consistency check.\n"; char invalid_header[] = "Invalid or corrupted archive.\n"; char internal_error[]="Internal error.\n"; char disk_full[] = "I/O error or disk full.\n"; char bad_directory[] = "Directory entry in archive is invalid.\n"; char no_memory[] = "Ran out of memory.\n"; char too_many_files[] = "Some filenames ignored -- can only handle %d.\n"; char packfirst[] = "Old format archive -- please pack first with P command.\n"; char garbled[] = "Command is garbled.\n"; char start_ofs[] = "Starting at %ld (offset %ld)\n"; #ifndef OOZ char wrong_version[]= "Zoo %d.%d or later is needed to fully manipulate this archive.\n"; char cant_process[] = "The rest of the archive (%lu bytes) cannot be processed.\n"; char option_ignored[] = "Ignoring option %c.\n"; char inv_option[] = "Option %c is invalid.\n"; char bad_crc[] = "\007Bad CRC, %s probably corrupted\n"; #endif #ifdef OOZ char could_not_open[] = "Could not open "; #else char could_not_open[] = "Could not open %s.\n"; #endif #ifdef STDARG void prterror(int level, char *format, ...) #else /*VARARGS*/ void prterror(va_alist) va_dcl #endif { va_list args; char string[120]; /* local format string */ #ifdef VARARGS int level; char *format; #endif #ifdef STDARG va_start(args, format); #else va_start(args); level = va_arg(args, int); format = va_arg(args, char *); #endif *string = '\0'; /* get a null string to begin with */ #ifdef OOZ strcpy (string, "Ooz: "); #else strcpy (string, "Zoo: "); #endif switch (level) { case 'M': *string = '\0'; /* fall through to 'm' */ case 'm': if (quiet) return; break; case 'w': if (quiet > 1) return; strcat (string, "WARNING: "); break; case 'e': if (quiet > 2) return; strcat (string, "ERROR: "); break; case 'F': case 'f': strcat (string, "FATAL: "); break; default: prterror ('f', internal_error); /* slick recursive call */ } strcat (string, format); /* just append supplied format string */ /* and print the whole thing */ #ifdef NEED_VPRINTF (void) zvfprintf(stdout, string, args); #else (void) vprintf(string, args); #endif fflush (stdout); if (level == 'f') /* and abort on fatal error 'f' but not 'F' */ zooexit (1); } #ifdef NEED_VPRINTF /* Some systems don't have vprintf; if so, we roll our own. The following has been adapted from a Usenet posting by Jef Poskanzer . This is a portable mini-vfprintf that depends only on fprintf. We don't call this routine vfprintf to avoid unexpected conflicts with any library routine of the same name, notwithstanding the fact that we will usually use it only when there is no conflict. Also, even though we only need vprintf, the routine used here implements vfprintf. This will allow future uses as needed when output is to be sent to a stream other than stdout. */ /* Whether to support double. Better not to, because it may cause math stuff to be linked in */ #undef NEED_DOUBLE static int zvfprintf(stream, format, args) FILE *stream; char *format; va_list args; { char *ep; char fchar; char tformat[512]; int do_long; /* whether to print as long (l format suffix) */ int do_star; /* * used in format => get width from argument */ int star_size; /* size arg corresponding to "*" format */ int i; long l; unsigned u; unsigned long ul; char *s; #ifdef NEED_DOUBLE double d; #endif while (*format != '\0') { if (*format != '%') { /* Not special, just write out the char. */ putc(*format, stream); ++format; } else { do_star = 0; do_long = 0; ep = format + 1; /* Skip over all the field width and precision junk. */ if (*ep == '-') ++ep; if (*ep == '0') ++ep; while (isdigit(*ep)) ++ep; if (*ep == '.') { ++ep; while (isdigit(*ep)) ++ep; } if (*ep == '#') ++ep; if (*ep == '*') { do_star = 1; star_size = va_arg(args, int); /* get * argument */ ++ep; } if (*ep == 'l') { do_long = 1; ++ep; } /* Here's the field type. Extract it, and copy this format ** specifier to a temp string so we can add an end-of-string. */ fchar = *ep; (void) strncpy(tformat, format, ep - format + 1); tformat[ep - format + 1] = '\0'; /* Now do a one-argument printf with the format string we have isolated. If the * format was used, we will also supply the additional parameter star_size, which we have already obtained from the variable argument list. */ switch (fchar) { case 'd': if (do_long) { l = va_arg(args, long); if (do_star) (void) fprintf(stream, tformat, star_size, l); else (void) fprintf(stream, tformat, l); } else { i = va_arg(args, int); if (do_star) (void) fprintf(stream, tformat, star_size, i); else (void) fprintf(stream, tformat, i); } break; case 'o': case 'x': case 'u': if (do_long) { ul = va_arg(args, unsigned long); if (do_star) (void) fprintf(stream, tformat, star_size, ul); else (void) fprintf(stream, tformat, ul); } else { u = va_arg(args, unsigned); if (do_star) (void) fprintf(stream, tformat, star_size, u); else (void) fprintf(stream, tformat, u); } break; case 'c': i = (char) va_arg(args, int); if (do_star) (void) fprintf(stream, tformat, star_size, i); else (void) fprintf(stream, tformat, i); break; case 's': s = va_arg(args, char *); if (do_star) (void) fprintf(stream, tformat, star_size, s); else (void) fprintf(stream, tformat, s); break; #ifdef NEED_DOUBLE case 'e': case 'f': case 'g': d = va_arg(args, double); if (do_star) (void) fprintf(stream, tformat, star_size, d); else (void) fprintf(stream, tformat, d); break; #endif case '%': putc('%', stream); break; default: return -1; } /* Resume formatting on the next character. */ format = ep + 1; } } va_end(args); return 0; } #endif /*NEED_VPRINTF*/ zoo-2.10.orig/sysv.c100644 1750 1750 7770 5035113600 13057 0ustar jamesjames#ifndef LINT /* @(#) sysv.c 2.5 88/01/10 14:47:24 */ static char sysvid[]="@(#) sysv.c 2.5 88/01/10 14:47:24"; #endif /* LINT */ /* machine.c for System V */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/12/31 */ #ifdef UNBUF_IO /* do not use */ /* Function tell() returns the current seek position for a file descriptor. Microport System V/AT has an undocumented tell() library function (why?) but the **IX PC doesn't, so we code one here. It is needed for unbuffered I/O only. */ long lseek PARMS ((int, long, int)); long tell (fd) int fd; { return (lseek (fd, 0L, 1)); } #endif /* UNBUF_IO */ /**************** Date and time functions are standard **IX-style functions. "nixtime.i" will be included by machine.c. */ #include #include #include /* Function isadir() returns 1 if the supplied handle is a directory, else it returns 0. */ int isadir (file) ZOOFILE file; { int handle = fileno(file); struct stat buf; /* buffer to hold file information */ if (fstat (handle, &buf) == -1) { return (0); /* inaccessible -- assume not dir */ } else { if (buf.st_mode & S_IFDIR) return (1); else return (0); } } /**************** Function fixfname() converts the supplied filename to a syntax legal for the host system. It is used during extraction. */ char *fixfname(fname) char *fname; { return (fname); /* default is no-op */ } extern long timezone; /* defined by library routine */ long time (); struct tm *localtime (); /* Function gettz(), returns the offset from GMT in seconds of the local time, taking into account daylight savings time */ #if 1 /* Following should work for System V */ long gettz() { #define SEC_IN_DAY (24L * 60L * 60L) #define INV_VALUE (SEC_IN_DAY + 1L) static long retval = INV_VALUE; /* cache, init to impossible value */ struct tm *tm; long clock; if (retval != INV_VALUE) /* if have cached value, return it */ return retval; clock = time ((long *) 0); tm = localtime (&clock); retval = timezone - tm->tm_isdst*3600; return retval; } #else /* This version of gettz should be portable to all Unices, although it can't be described as elegant. Users immediately west of the International Date Line (Polynesia, Soviet Far East) may get times out by 24 hours. Contributed by: Ian Phillipps */ /* Function gettz(), returns the offset from GMT in seconds */ long gettz() { #define NOONOFFSET 43200 #define SEC_IN_DAY (24L * 60L * 60L) #define INV_VALUE (SEC_IN_DAY + 1L) static long retval = INV_VALUE; /* cache, init to impossible value */ extern long time(); extern struct tm *localtime(); long now; long noon; struct tm *noontm; if (retval != INV_VALUE) /* if have cached value, return it */ return retval; now = time((long *) 0); /* Find local time for GMT noon today */ noon = now - now % SEC_IN_DAY + NOONOFFSET ; noontm = localtime( &noon ); retval = NOONOFFSET - 60 * ( 60 * noontm->tm_hour - noontm->tm_min ); return retval; #undef NOONOFFSET } #endif /* Standard **IX-compatible time functions */ #include "nixtime.i" /* Standard **IX-specific file attribute routines */ #include "nixmode.i" /* Make a directory. System V has no system call accessible to ordinary users to make a new directory. Hence we spawn a shell and hope /bin/mkdir is there. Since /bin/mkdir gives a nasty error message if it fails, we call it only if nothing already exists by the name of the needed directory. */ int mkdir(dirname) char *dirname; { char cmd[PATHSIZE+11+1]; /* room for "/bin/mkdir " used below + 1 spare */ if (!exists(dirname)) { strcpy(cmd, "/bin/mkdir "); strcat(cmd, dirname); return (system(cmd)); } return (0); } /* No file truncate system call in older System V. If yours has one, add it here -- see bsd.c for example. It's ok for zootrunc to be a no-op. */ /*ARGSUSED*/ int zootrunc(f) FILE *f; { return 0; } zoo-2.10.orig/turboc.c100644 1750 1750 4017 5035113600 13340 0ustar jamesjames/* @(#) turboc.c 1.2 87/06/21 16:08:54 */ int _stklen = 30000; /* stack size in bytes */ void _setenvp() {} /* don't initialize environment pointer etc. */ #include /* to get fileno() */ /* following not needed any more since zoocreate() is fixed in portable.c */ /* unsigned _fmode = O_BINARY; */ void dosname PARMS((char *, char *)); #ifdef ANSI_HDRS # include #else char *strcpy PARMS((char *, char *)); #endif #include /* register definitions specific for Turbo C */ union REGS { struct { unsigned ax, bx, cx, dx, si, di, carry, flags; } x; struct { unsigned char al, ah, bl, bh, cl, ch, dl, dh; } h; }; /**************** function zootrunc() truncates a file at the current seek position. */ int zootrunc (f) FILE *f; { int handle = fileno(f); extern long tell(); extern int chsize(); return chsize(handle, tell(handle)); } /**************** Function fixfname() converts the supplied filename to a syntax legal for the host system. It is used during extraction. */ char *fixfname(fname) char *fname; { char tmpname[PATHSIZE]; dosname (nameptr(fname), tmpname); strcpy(fname,tmpname); return(fname); } static int set_break (int flag) { extern int intdos(); int retval; union REGS regs; regs.x.ax = 0x3300; /* get ctrl-break flag */ intdos (®s, ®s); retval = regs.h.dl; /* retval is old value of setting */ regs.x.ax = 0x3301; /* set ctrl-break flag */ regs.h.dl = flag; /* status to set to */ intdos (®s, ®s); return (retval); } static int break_flag; void zooexit (int status) { set_break (break_flag); /* restore control_break setting */ exit (status); } void gentab (void); void spec_init(void) { break_flag = set_break (0); signal (SIGINT, zooexit); /* install our own control-C handler */ } #ifndef fileno /* To allow compilation with -A (for testing), which makes fileno() unavailable, we define a function here by that name. This may be compiler-specific for Turbo C++ 1.0. */ int fileno(f) FILE *f; { return f->fd; } #endif /* ! fileno */ zoo-2.10.orig/turboc.cfg100644 1750 1750 161 5035113600 13631 0ustar jamesjames-IC:\TC\INCLUDE -LC:\TC\LIB -a -f- -k- -v- -G -O -Z -c -O -wrvl -wamb -wamp -wnod -wstv -wuse -wcln -wsig -wucp zoo-2.10.orig/various.h100644 1750 1750 4061 5035113600 13536 0ustar jamesjames/* @(#) various.h 2.3 87/12/27 14:44:34 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ /* This files gives definitions for most external functions used by Zoo. If ANSI_PROTO is defined, ANSI-style function prototypes are used, else normal K&R function declarations are used. Note: Always precede this file with an include of stdio.h because it uses the predefined type FILE. */ #ifndef PARMS #ifdef ANSI_PROTO #define PARMS(x) x #else #define PARMS(x) () #endif #endif #ifdef ANSI_HDRS /* if not defined in stdio.h */ # include # include #else FILE *fdopen PARMS ((int, char *)); FILE *fopen PARMS ((char *, char *)); char *fgets PARMS ((char *, int, FILE *)); char *gets PARMS ((char *)); VOIDPTR malloc PARMS ((unsigned int)); VOIDPTR realloc PARMS ((char *, unsigned int)); char *strcat PARMS ((char *, char *)); char *strchr PARMS ((char *, int)); char *strcpy PARMS ((char *, char *)); char *strncat PARMS ((char *, char *, unsigned int)); char *strncpy PARMS ((char *, char *, unsigned int)); char *strrchr PARMS ((char *, int)); int fclose PARMS ((FILE *)); int fflush PARMS ((FILE *)); int fgetc PARMS ((FILE *)); int fgetchar PARMS (()); int fprintf PARMS ((FILE *, char *, ...)); int fputchar PARMS ((int)); int fputs PARMS ((char *, FILE *)); #ifndef NO_STDIO_FN # ifdef ALWAYS_INT int fputc PARMS ((int, FILE *)); int fread PARMS ((VOIDPTR, int, int, FILE *)); int fwrite PARMS ((VOIDPTR, int, int, FILE *)); # else int fputc PARMS ((char, FILE *)); int fread PARMS ((VOIDPTR, unsigned, unsigned, FILE *)); int fwrite PARMS ((VOIDPTR, unsigned, unsigned, FILE *)); # endif /* ALWAYS_INT */ #endif /* NO_STDIO_FN */ int fseek PARMS ((FILE *, long, int)); int printf PARMS ((char *, ...)); int rename PARMS ((char *, char *)); int setmode PARMS ((int, int)); int strcmp PARMS ((char *, char *)); int strncmp PARMS ((char *, char *, unsigned int)); int unlink PARMS ((char *)); long ftell PARMS ((FILE *)); unsigned int strlen PARMS ((char *)); #endif /* ! ANSI_HDRS */ zoo-2.10.orig/version.c100644 1750 1750 157 5035113600 13510 0ustar jamesjames/* derived from: version.c 2.9 1988/08/25 12:43:57 */ char version[] = "zoo 2.1 $Date: 91/07/09 02:10:34 $"; zoo-2.10.orig/vms.c100644 1750 1750 24003 5035113600 12664 0ustar jamesjames#ifndef LINT /* derived from: @(#) vms.c 2.2 88/01/09 03:47:52 */ static char vmsid[]="$Source: /usr/home/dhesi/zoo/RCS/vms.c,v $\n\ $Id: vms.c,v 1.10 91/07/07 14:41:17 dhesi Exp $"; #endif /* LINT */ /* Support routines for VAX/VMS. */ #include #include /* our own version of NULL; avoid any interaction with system defn. but don't require inclusion of stdio.h */ #define NILPTR 0 /* Function isuadir() returns 1 if the supplied filename is a directory, else it returns 0. */ int isuadir (file) char *file; { struct stat buf; /* buffer to hold file information */ if (stat (file, &buf) == -1) { return (0); /* inaccessible -- assume not dir */ } else { if (buf.st_mode & S_IFDIR) return (1); else return (0); } } /**************** Function fixfname() converts the supplied filename to a syntax legal for the host system. It is used during extraction. We allow a maximum of one dot in the filename, and it must not be at the beginning. We also truncate the number of charac- ters preceding and following the dot to at most 39. */ char *strchr(); char *fixfname(fname) char *fname; { char *p; char *dotpos; static char legal[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_.0123456789"; /* convert all characters to legal characters */ for (p = fname; *p != '\0'; p++) if (strchr (legal, *p) == 0) { if (*p == '-' || *p == ' ') *p = '_'; else *p = legal [ *p % 26 ]; } /* first char can't be dot */ if (*fname == '.') *fname = 'X'; /* find embedded dot if any */ dotpos = strchr (fname, '.'); if (dotpos != NILPTR) { for (p = dotpos+1; *p != '\0'; p++) /* remove 2nd dot onwards */ if (*p == '.') *p = '_'; if (dotpos - fname + 1 > 39) { /* more than 39 before dot not allowed */ char *q; p = fname + 39; q = dotpos; while (*p++ = *q++) /* the notational convenience is considerable */ ; dotpos = strchr (fname, '.'); } if (strlen (dotpos + 1) > 39) /* more than 39 after dot not allowed */ *(dotpos + 39 + 1) = '\0'; } else *(fname + 39) = '\0'; /* no dots, just truncate to 39 characters */ return (fname); } /* Function gettz(), returns the offset from GMT in seconds of the local time, taking into account daylight savings time -- or it would, if VAX/VMS knew about timezones! It's just a no-op. */ long gettz() { return 0L; } struct tm *localtime(); /***************** Function gettime() gets the date and time of the file handle supplied. Date and time is in MSDOS format. This function duplicated from nixtime.i. */ int gettime (file, date, time) ZOOFILE file; unsigned *date, *time; { struct stat buf; /* buffer to hold file information */ struct tm *tm; /* will hold year/month/day etc. */ int handle; handle = fileno(file); if (fstat (handle, &buf) == -1) { prterror ('w', "Could not get file time\n"); *date = *time = 0; } else { tm = localtime (&buf.st_mtime); /* get info about file mod time */ *date = tm->tm_mday + ((tm->tm_mon + 1) << 5) + ((tm->tm_year - 80) << 9); *time = tm->tm_sec / 2 + (tm->tm_min << 5) + (tm->tm_hour << 11); } } /* Function unlink() will delete a file using the VMS C delete() function. */ int unlink (fname) char *fname; { return (delete (fname)); } /* Function zooexit() receives attempts at exit. It always invokes exit() with status=1. */ void zooexit (status) int status; { exit (1); } /* Function rename() renames a file. Thanks to Owen Anthony (was at one time). */ #include #ifdef NEED_VMS_RENAME /* if not using VMS 4.6 library rename() */ int rename (old_name, new_name) char *old_name; char *new_name; { int status; struct dsc$descriptor_s file1, file2; file1.dsc$w_length = strlen (old_name); /* descriptor for old name */ file1.dsc$a_pointer = old_name; file1.dsc$b_class = DSC$K_CLASS_S; file1.dsc$b_dtype = DSC$K_DTYPE_T; file2.dsc$w_length = strlen (new_name); /* descriptor for new name */ file2.dsc$a_pointer = new_name; file2.dsc$b_class = DSC$K_CLASS_S; file2.dsc$b_dtype = DSC$K_DTYPE_T; status = LIB$RENAME_FILE (&file1, &file2); return ((status & ~1) == 1); } #endif /* VMS_RENAME */ /* Function specfname() modifies filenames before they are stored in an archive. Currently we remove any trailing version field, and then any trailing dot. */ char *specfname (fname) char *fname; { char *p; p = strchr (fname, ';'); if (p != NILPTR) *p = '\0'; if (*fname != '\0') { p = fname + strlen (fname) - 1; /* point to last char */ if (*p == '.') /* remove any trailing dot */ *p = '\0'; } return (fname); } /* Function specdir() modifies directory names before they are stored in an archive. We remove any leading device name or logical name and and the [ and ] that bracket any directory name. Then we change any dots in the directory name to slashes. */ #if 0 /* test stub that just truncates dir to null string */ char *specdir (fname) char *fname; { *fname = '\0'; return (fname); } #else char *specdir (fname) char *fname; { char *p; char tmpstr[LFNAMESIZE]; p = strchr (fname, ':'); /* remove chars upto and including : */ if (p != NILPTR) { strcpy (tmpstr, p+1); strcpy (fname, tmpstr); } p = strchr (fname, '['); /* remove chars upto and including [ */ if (p != NILPTR) { strcpy (tmpstr, p+1); strcpy (fname, tmpstr); } p = strchr (fname, ']'); /* truncate at ] */ if (p != NILPTR) { if (*(p+1) != '\0') prterror ('w', "Trailing garbage in directory name\n"); *p = '\0'; } for (p = fname; *p != '\0'; p++) /* change dots to slashes */ if (*p == '.') *p = '/'; /* make sure there is a leading slash -- just a hack for now */ if (*fname != '/') { strcpy (tmpstr, fname); strcpy (fname, "/"); strcat (fname, tmpstr); } #ifdef DEBUG printf ("dir name transformed to \"%s\"\n", fname); #endif } #endif #define FMAX 3 /* Number of different filename patterns */ char *nextfile (what, filespec, fileset) int what; /* whether to initialize or match */ register char *filespec; /* filespec to match if initializing */ register int fileset; /* which set of files */ { int status; char *p; /* temp ptr */ struct dsc$descriptor_s d_fwild, d_ffound; static int first_time [FMAX+1]; static char saved_fspec [FMAX+1][PATHSIZE]; /* our own copy of filespec */ static char found_fspec [FMAX+1][PATHSIZE]; /* matched filename */ static unsigned long context [FMAX+1]; /* needed by VMS */ if (what == 0) { strcpy (saved_fspec[fileset], filespec); /* save the filespec */ first_time[fileset] = 1; return (0); } /* Reach here if what is not 0, so it must be 1 */ /* Create a descriptor for the wildcarded filespec */ d_fwild.dsc$w_length = strlen (saved_fspec[fileset]); d_fwild.dsc$a_pointer = saved_fspec[fileset]; d_fwild.dsc$b_class = DSC$K_CLASS_S; d_fwild.dsc$b_dtype = DSC$K_DTYPE_T; d_ffound.dsc$w_length = sizeof (found_fspec[fileset]); d_ffound.dsc$a_pointer = found_fspec[fileset]; d_ffound.dsc$b_class = DSC$K_CLASS_S; d_ffound.dsc$b_dtype = DSC$K_DTYPE_T; if (first_time[fileset]) { first_time[fileset] = 0; context[fileset] = 0L; /* tell VMS this is first search */ } status = LIB$FIND_FILE (&d_fwild, &d_ffound, &context[fileset]); status = status & 1; /* use only lowest bit */ if (status == 0) { LIB$FIND_FILE_END (&context[fileset]); return ((char *) 0); } else { found_fspec[fileset][d_ffound.dsc$w_length] = '\0'; /* just in case */ p = found_fspec[fileset]; while (*p != ' ' && *p != '\0') p++; if (*p != '\0') *p = '\0'; return (found_fspec[fileset]); } } /* Function vmsmkdir() converts the received directory name into VMS format and then creates a directory. */ int vmsmkdir (subdir) char *subdir; { char *lastptr(); char *p; char tmp[LFNAMESIZE]; p = subdir; /* leading "/" => "[", otherwise => "[." */ if (*p == '/') { strcpy (tmp, "["); p++; } else { strcpy (tmp, "[."); while (*p == '/' || *p == '.') p++; } strcat (tmp, p); /* VMS doesn't like dots in directory names, so we convert them to underscores. Leave first two characters untouched, because we don't want to corrupt a leading "[." into "[_". */ for (p = tmp + 2; *p != '\0'; p++) if (*p == '.') *p = '_'; /* convert all slashes to dots */ for (p = tmp; *p != '\0'; p++) if (*p == '/') *p = '.'; /* Remove any trailing dot */ p = lastptr (tmp); if (*p == '.') *p = '\0'; /* append closing bracket */ strcat (tmp, "]"); #if 0 printf ("\nmaking directory \"%s\"\n", tmp); #endif return (mkdir (tmp, 0)); } /* Function spec_wild() transforms a pattern supplied on the command line into one suitable for wildcard expansion in the most efficient way possible. We change each "?" to "%" but let "*" remain unchanged. We also append a ".*" if the pattern contains no dot, so "*" will be interpreted as "*.*" for VMS globbing. */ char *spec_wild (arg) char *arg; { char *p; #ifdef DEBUG printf ("spec_wild: arg = [%s]\n", arg); #endif if (*lastptr (arg) == ']') /* add *.* if no filename */ strcat (arg, "*.*"); p = nameptr (arg); /* point p to filename part */ /* if no dot in name append ".*" */ if (strchr (p, '.') == NILPTR) strcat (p, ".*"); for ( ; *p != '\0'; p++) /* change every "?" to "%" */ if (*p == '?') *p = '%'; #ifdef DEBUG printf ("spec_wild: arg changed to [%s]\n", arg); #endif return (arg); } int zootrunc(f) FILE *f; { return 0; } zoo-2.10.orig/vmsbugs.doc100644 1750 1750 44230 5035113600 14074 0ustar jamesjames Zoo 2.0 on VAX/VMS by Rahul Dhesi The zoo archiver is used to create and maintain archives containing mul- tiple files that may be stored in compressed format. Consult the zoo manual for more details. This document describes those features of VAX/VMS zoo that are specific to the VAX/VMS implementation. INSTALLATION The file "descrip.mms" is a makefile suitable for use with DEC's imple- mentation of make, called MMS. To avoid any confusion, delete the file called "makefile" as that is not for VAX/VMS systems and it might con- fuse MMS. With all source files in the current directory, simply type MMS and wait while all files get compiled and linked. Then give the command "mms fiz" to build "fiz.exe", and "mms blif" to build "bilf.exe". If your system does not have MMS, execute the "vmsbuild.com" script. The result should be the executable program, "zoo.exe", "fiz.exe", and "bilf.exe". Optionally, the command "mms zoobig.exe" will create a version of the executable that is linked without the shareable library. This may be more portable if you intend to transfer it to an VMS system that does not have its own C compiler. But "zoobig.exe" will be about twice the size of "zoo.exe". To run zoo, bilf, and fiz, you will need to set up symbols by giving commands similar to the following, either by typing them at the system prompt or by putting them in your "login.com" file. $ zoo :== $ user$disk:[userdir]zoo.exe $ fiz :== $ user$disk:[userfir]fiz.exe $ bilf :== $ user$disk:[userdir]bilf.exe In place of "user$disk" use the name of the device on which your login directory is located, and instead of "userdir" use the name of the directory in which you have placed the executable programs "zoo.exe" and "fiz.exe". WARNING -- VMS BUGS VAX/VMS peculiarities cause unusual bahavior. - VMS C does not preserve uppercase characters in a command line. To specify a command containing an uppercase character, enclose the command in double quotes. For example, the command zoo aM stuff * will not work under VMS. To make this command work under VMS, use double quotes like this: zoo "aM" stuff * - For most text files that are not in stream-LF format, VMS returns an incorrect file size to zoo. This will be evident if you use the "f" modifier to tell zoo to archive files without compression. Files that were in stream-LF format will be stored with the correct size; other text files will be stored with an incorrect value for the original size of the file. When such files are extracted, however, they are extracted in stream-LF format, which is the only file format that VMS seems to handle correctly. Thus, so far as I can determine, no file con- tents are actually lost, and the only evidence of the problem is that in archive listings, files stored without compression may still appear to be compressed by about 1 to 5 percent, or occasion- ally by some meaningless value. - VAX/VMS uses many different types of file structures. Zoo creates archives in stream-LF format, and all archives used by zoo in any way must be in this format. It is dangerous to use zoo on an archive that is in any other format, because it may permanently corrupt the archive contents. Thus, if you have uploaded an archive to a VMS system using Kermit, do not try to manipulate it with zoo until you have converted it to stream-LF format. File conversion instructions are given later in this document. - The VAX/VMS batch system causes the C statement fflush(stdout); to become equivalent to: printf("\n"); The result is that if files are added to a zoo archive from a batch run, the batch log will look very strange and contain spurious new- lines. ARCHIVING SELECTED FILES Zoo can read filenames from standard input. This allows you to use an external program to generate a list of files to be archived. When this list is fed to zoo, it will archive only the selected files. For this example, assume that files are to be archived in an archive called "backups.zoo". To achieve redirection of input under VAX/VMS, the following steps are necessary: 1. Create a file containing the filenames to be archived. Suppose this file is called "names.lis". 2. Redirect zoo's standard input thus: $ define /user_mode SYS$INPUT names.lis 3. Invoke zoo thus: $ zoo "aI" backups This command line will cause zoo to read a list of filenames from its standard input, and archive them into "backups.zoo". Since the logical name SYS$INPUT was changed to refer to the file "names.lis", zoo will read filenames from that file. A good way of creating a list of files to be archived is to use the vms "directory" command. Include at least the switches shown: $ directory /noheading /notrailing /column=1 /output=names.lis This tells VMS to produce a list of filenames, one per line, and to store the resulting output in the file "names.lis". You can also add additional selection options. For example, to select all files that have been modified in the last 12 hours: $ dir/nohead/notrail/col=1/out=names.lis/since=-12:00/modified A good way to decrease the effort is to create a symbol as follows: $ select:=="dir/nohead/notrail/col=1/out=names.lis/modified/since=" Now you can archive all *.c files modified in the last 60 minutes by giving the following commands: $ select -1:00:00 *.c $ define/user sys$input names.lis $ zoo "aI" backups FILE TRANSFERS WITH KERMIT Zoo archives can be uploaded to a VAX/VMS system and downloaded from it using Kermit. Due to VMS limitations, some file conversions must be done to avoid a corrupted zoo archive. Zoo always expects zoo archives to be in stream-LF format. However, the standard VAX/VMS Kermit does not create stream-LF files, and treats them as text files when it reads them, resulting in corrupted downloads. Thus you must handle Kermit transfers with care. The following discus- sions refers solely to the standard Kermit-32, which I believe is from the Stevens Institute of Technology. If the following instructions are carefully followed, you should be able to transfer zoo archives between a VAX/VMS system and a microcomputer running Kermit. KERMIT UPLOADS: To transfer a zoo archive from a microcomputer to a VAX/VMS system, do the following. 1. Invoke VAX/VMS Kermit as shown below. It will prompt you with the string "Kermit-32>". Give it a command as shown to tell it to receive a binary file: $ kermit Kermit-32> set file type binary Kermit-32> set block-check 3 Kermit-32> receive Note: Do not use the command "set file type fixed". In most cases it will not work. The command to set the block-check is optional, but tells Kermit to use a 16-bit CRC, which is much more reliable than the default 6- bit CRC. Use this command if your version of Kermit does not use a 16-bit CRC by default. 2. At this point, VAX/VMS Kermit is waiting for you to send it a file. Now tell your local Kermit to send the file. On an MS-DOS system, using MS-Kermit, you would do this by first typing the local escape sequence to get to the local mode, where the prompt is "MS- Kermit>", then telling your local Kermit to send the zoo archive as a binary file. A typical sequence of commands is: (type escape sequence to get back to local mode) MS-Kermit> set eof noctrl-z MS-Kermit> send stuff.zoo It is important that your local Kermit send the zoo archive as a binary file, not a text file. How you do this depends on your sys- tem; on MS-DOS systems it suffices to give say "set eof noctrl-z". 3. Wait until the Kermit upload is complete. Then tell your local Kermit to go into terminal mode (usually by giving the command CON- NECT), and exit from VAX/VMS Kermit with the command EXIT. A typi- cal sequence is: MS-Kermit> connect (stuff from MS-Kermit printed...) (hit carriage return if necessary to get the next prompt) Kermit-32> exit $ Now you are back at the VAX/VMS prompt. At this point, you must convert the uploaded zoo archive, which is currently in binary for- mat, to stream-LF format so that it can be used by VAX/VMS zoo. You do this by using the Bilf utility, which can convert files between binary and stream-LF formats. Give the command: $ bilf l stuff.zoo 4. After Bilf has done the conversion, you will have a new generation of stuff.zoo that is in stream-LF format. Now you can manipulate it normally with VAX/VMS zoo. DON'T TRY TO USE ZOO TO MANIPULATE AN UPLOADED ARCHIVE WITHOUT PERFORM- ING THE CONVERSION TO STREAM-LF FORMAT, ELSE YOU MAY PERMANENTLY DESTROY ARCHIVE CONTENTS. KERMIT DOWNLOADS: Before downloading a zoo archive from VAX/VMS to a microcomputer, you must convert it to binary format. Then use VMS Kermit normally. A sample sequence is shown. 1. Convert the zoo archive to binary format. $ bilf b stuff.zoo 2. Invoke VMS Kermit and tell it to send the file. $ kermit Kermit-32> set block-check 3 Kermit-32> send stuff.zoo 3. Get back to your local Kermit and tell it to receive a binary file. (type escape sequence to get into local mode) MS-Kermit> set eof noctrl-z MS-Kermit> receive (transfer takes place) FILE TRANSFER SUMMARY Here are pictorial summaries of the steps involved in performing file transfers of zoo archives using Kermit. ====================================================================== DOWNLOADS: files on a VMS system to be archived using zoo | archive created | using zoo.exe | or zoobig.exe | on a VMS system | v zoo archive on VMS bilf b zoo archive on VMS, in in fixed-length <---------------- in stream-LF format binary format | | | archive transferred | from VMS to microcomputer | using Kermit; receiving | Kermit must be told this | is a binary file; sending | Kermit may need to be told too | v zoo archive on microcomputer system ====================================================================== UPLOADS: zoo archive on microcomputer system | | | archive uploaded to VMS using Kermit; | receiving Kermit on VMS must be given | command "set file type binary" | (NOTE: "set file type fixed" will | usually not work); sending Kermit | must be told this is a binary file | v zoo archive on VMS, bilf l zoo archive on VMS, in in variable-length ----------------> in stream-LF format binary format | | extract | normally using | zoo on VMS | v files extracted from zoo archive on a VMS system ====================================================================== ENSURING ARCHIVE INTEGRITY After performing a transfer of a zoo archive using Kermit (and perform- ing any file conversion necessary for VMS), make it a habit to immedi- ately test the integrity of the transferred archive with the -test com- mand of zoo, illustrated for VMS: $ zoo -test stuff In addition, also get a listing of the archive contents: $ zoo -list stuff If neither command reports an error, it is reasonable to assume that archive integrity was not harmed by the Kermit transfer. The -test command tests the integrity of each stored file. The -list command tests the integrity of the internal archive structure. Both are checked using separate cyclic redundancy codes, one for each archived file, and one for each directory entry in the archived. (Actually, the -list command ignores deleted entries, so if the archive contains any, use the "ld" command instead.) WILDCARDS All implementations of zoo on all systems use the same wildcard charac- ters: "*" matches any sequence of zero or more characters, and "?" matches any one character. ADDING FILES: For specifying directory names when adding files, use the usual VAX/VMS syntax. Thus, to recursively archive all files in the current directory and all its subdirectories, the command syntax is: $ zoo a stuff [...]* The character range wildcard of the form "c-c" is also available, which will select all files beginning with the specified character range. For example, $ zoo a stuff [...]a-d [...]x-z will archive all files beginning with the characters a through d, and with the characters x through z, in the current directory and all its subdirectories. A side-effect of this is that during addition to archives, dots in filenames must be explicitly matched. Thus to add all files with an extension of DOC, you would type: $ zoo a stuff *.doc and "*doc" will not work. As a special case, a trailing "*.*" in any filename you specify can always be replaced by just a trailing "*". The safest rule to follow when adding files is to always specify the dot in each filename. EXTRACTING FILES: During extraction, both the directory name and the filename must be specified according to zoo syntax. Thus you could say $ zoo x stuff [*xyz*]*.doc to extract all archived files with filenames that match "*.doc" and that contain the string "xyz" in the directory name. Note that VMS syntax for selecting directories won't work here: $ zoo x stuff [...]*.doc ! won't work for extraction If you do not specify the directory name at all, zoo will only perform the match against filenames; thus $ zoo x stuff *.doc will extract all files matching *.doc regardless of the directory name. Also note that if you specify extraction of "*.*", as in $ zoo x stuff *.* it will result in the extraction of files whose filename contains at least one dot. Similarly, the command $ zoo x stuff *_* will select all filename containing at least one underscore. To extract all files, specify no filename, e.g. $ zoo x stuff or use "*" rather than "*.*". SAFEST RULE OF THUMB: WHEN SELECTING FILES ON DISK, SPECIFY THE DOT IN EACH FILENAME; WHEN SELECTING FILES INSIDE A ZOO ARCHIVE, SPECIFY A DOT ONLY IF YOU NEED ONE. But to select all files, you can always just use "*". FILE GENERATIONS When a file is added to an archive, the generation number (if any) that it is given in the archive is not related to the generation number it had in the VAX/VMS filesystem. At extraction time a new version is always created for an extracted file. The overwrite option ("O") does not cause overwriting, but simply suppresses the warning message that zoo normally gives when it finds that a file about to be extracted already exists. FILE STRUCTURES At extraction time, zoo preserves all data bytes in binary files, and stores all text files as lines of text terminated with linefeeds. The internal file structure maintained by DEC's RMS is not currently preserved. (Support for this is planned for the distant future.) Thus, the following two types of files can be safely archived and restored: - All text files are extracted in stream-LF format. Most VMS utili- ties that accept text files will accept such files. The EDT edi- tor may complain, but will still work. - VMS executable files, when stored and then extracted, are extracted in stream-LF format. Such files can be restored to their original state using Bilf with the "b" option. (However, current versions of VAX/VMS seem to be able to load and execute stream-LF files, so conversion may not be necessary.) HANDLING VMS EXECUTABLE FILES. You can archive an executable program called "xyz.exe": $ zoo a stuff xyz.exe $ delete xyz.exe;* Now the only copy of xyz.exe is in the archive "stuff.zoo". Extract it: $ zoo x stuff xyz.exe The extracted copy of "xyz.exe" is in stream-LF format and VMS may or may not execute it. Now we convert it back to fixed-length record for- mat thus: $ bilf b xyz.exe $ purge xyz.exe Now "xyz.exe" has been converted to binary format and can be executed. It should be identical to the original copy of "xyz.exe" that was archived. TEXT FILES FROM OTHER SYSTEMS. A text file archived on a different computer system will use either linefeeds, or carriage returns plus linefeeds, as line terminators. Text files with linfeeds only can be be extracted and used exactly as if they had been archived on a VAX/VMS system. Text files containing carriage returns plus linefeeds will, when extracted, contain a spurious carriage return at the end of each line. This extra carriage return can be removed using EDT's "substi- tute" command while in screen mode. Simply replace all carriage returns with nothing. The VMS C compiler currently appears to accept trailing carriage returns in files without any trouble. Text files trasnferred from MS-DOS or CP/M or similar systems may con- tain a trailing control Z character. This may cause problems on VMS and should be edited out with a text editor. -- Rahul Dhesi 1988/02/04 Revised 1991/07/07 zoo-2.10.orig/vmsbuild.com100644 1750 1750 7505 5035113600 14230 0ustar jamesjames$! VMSBUILD.COM for ZOO 2.10 $! $! Adapted from similar script for zoo 2.01 that was contributed by $! Steve Roseman $! Lehigh University Computing Center $! LUSGR@VAX1.CC.Lehigh.EDU $! $ write sys$output "Compiling zoo..." $ write sys$output "$ cc addbfcrc.c" $ cc/nolist addbfcrc.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc addfname.c" $ cc/nolist addfname.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc basename.c" $ cc/nolist basename.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc comment.c" $ cc/nolist comment.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc crcdefs.c" $ cc/nolist crcdefs.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc decode.c" $ cc/nolist decode.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc encode.c" $ cc/nolist encode.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc getfile.c" $ cc/nolist getfile.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc huf.c" $ cc/nolist huf.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc io.c" $ cc/nolist io.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc lzc.c" $ cc/nolist lzc.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc lzd.c" $ cc/nolist lzd.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc lzh.c" $ cc/nolist lzh.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc machine.c" $ cc/nolist machine.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc makelist.c" $ cc/nolist makelist.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc maketbl.c" $ cc/nolist maketbl.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc maketree.c" $ cc/nolist maketree.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc misc.c" $ cc/nolist misc.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc misc2.c" $ cc/nolist misc2.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc needed.c" $ cc/nolist needed.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc nextfile.c" $ cc/nolist nextfile.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc options.c" $ cc/nolist options.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc parse.c" $ cc/nolist parse.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc portable.c" $ cc/nolist portable.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc prterror.c" $ cc/nolist prterror.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc version.c" $ cc/nolist version.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc vmstime.c" $ cc/nolist vmstime.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zoo.c" $ cc/nolist zoo.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zooadd.c" $ cc/nolist zooadd.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zooadd2.c" $ cc/nolist zooadd2.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zoodel.c" $ cc/nolist zoodel.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zooext.c" $ cc/nolist zooext.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zoolist.c" $ cc/nolist zoolist.c/define=(BIG_MEM,NDEBUG,VMS) $ write sys$output "$ cc zoopack.c" $ cc/nolist zoopack.c/define=(BIG_MEM,NDEBUG,VMS) $ $ $ write sys$output "Linking zoo..." $ link /executable=zoo.exe - addbfcrc.obj, addfname.obj, basename.obj, comment.obj, - crcdefs.obj, decode.obj, encode.obj, getfile.obj, huf.obj, - io.obj, lzc.obj, lzd.obj, lzh.obj, machine.obj, makelist.obj, - maketbl.obj, maketree.obj, misc.obj, misc2.obj, needed.obj, - nextfile.obj, options.obj, parse.obj, portable.obj, prterror.obj, - version.obj, vmstime.obj, zoo.obj, zooadd.obj, zooadd2.obj, - zoodel.obj, zooext.obj, zoolist.obj, zoopack.obj, - options/opt $ $ write sys$output "Building fiz..." $ cc/nolist fiz.c $ link /executable=fiz.exe fiz.obj, addbfcrc.obj, portable.obj, - crcdefs.obj, options/opt $ write sys$output "Building bilf..." $ cc/nolist bilf.c $ link /executable=bilf.exe bilf.obj, options/opt $ $! delete *.obj.* zoo-2.10.orig/vmstime.c100644 1750 1750 14410 5035113600 13544 0ustar jamesjames/* vmstime.c */ #ifndef LINT static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/vmstime.c,v $\n\ $Id: vmstime.c,v 1.6 91/07/06 12:20:26 dhesi Exp $"; #endif /* This file was graciously supplied by Randal Barnes to support preservation of file timestamps under VAX/VMS. I claim no copyright on the contents of this file. I assume that neither do its authors. However, if you adapt this code for your own use, I recommend preserving author attributions. -- Rahul Dhesi 1991/07/04 */ /* * This module sets a VAX/VMS file's creation and revision date/time to a * specified date/time. * * Inputs Type Description * ------ ---- ----------- * path char * Name of file to be modified * date int Binary formatted date to be applied to the file * time int Binary formatted time to be applied to the file * * Outputs Type Description * ------- ---- ----------- * Modified file * * Randy Magnuson - (612) 542-5052 * Randal Barnes - (612) 542-5021 * Honeywell Inc. - Military Avionics Division * April 12, 1990 */ #include #include #include #include #include #include #include int setutime (char *path, unsigned int date, unsigned int time) { char EName [NAM$C_MAXRSS], /* Expanded String Area */ RName [NAM$C_MAXRSS], /* Resultant String Area */ date_str [50]; /* Holds intermediate ASCII date/time */ short iosb [4]; /* I/O status block for sys calls */ int status, /* Condition code for sys calls, etc. */ i, /* Temp index for looping thru arrays */ chan, /* Channel to device containing file */ Cdate [2], /* VMS binary time - creation date */ Rdate [2], /* VMS binary time - revision date */ datetimecontext = 0, /* Context for time conv. lib calls */ intime = LIB$K_INPUT_FORMAT, /* Constant for time lib calls */ intdate [2]; /* VMS binary time - temp */ struct FAB Fab; /* RMS File Access Block */ struct NAM Nam; /* RMS Name Block */ static struct fibdef Fib; /* RMS File Information Block */ struct atrdef Atr [] = /* File attribute struct */ { { sizeof (Cdate), ATR$C_CREDATE, &Cdate [0] }, /* Creation date */ { sizeof (Rdate), ATR$C_REVDATE, &Rdate [0] }, /* Revision date */ { 0, 0, 0 } }; struct dsc$descriptor devnam = /* Device name descriptor */ { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &Nam.nam$t_dvi [1] }; struct dsc$descriptor FibDesc = /* File ID descriptor */ { sizeof (Fib), 0, 0, &Fib }; struct dsc$descriptor_s FileName = /* File name descriptor */ { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 }; /* Time conversion format specification */ $DESCRIPTOR (datetimeformat, "|!Y4!MN0!D0|!H04!M0!S0!C2|"); /* String descriptor for intermediate date/time string */ $DESCRIPTOR (date_desc, date_str); /* * Fill out our File Access Block, Name Block, and Extended Attribute Block so * we can parse the file name. */ Fab = cc$rms_fab; Nam = cc$rms_nam; Fab.fab$l_fna = path; Fab.fab$b_fns = strlen (path); Fab.fab$l_nam = &Nam; Nam.nam$l_esa = &EName; Nam.nam$b_ess = sizeof (EName); Nam.nam$l_rsa = &RName; Nam.nam$b_rss = sizeof (RName); /* * Do a parse and search to fill out the NAM block. */ status = sys$parse(&Fab); if (!(status & 1)) return 0; status = sys$search(&Fab); if (!(status & 1)) return 0; /* * Open a channel to the device that the file resides on. */ devnam.dsc$w_length = Nam.nam$t_dvi [0]; status = SYS$ASSIGN (&devnam, &chan, 0, 0); if (!(status & 1)) return 0; /* * Initialize the FIB */ Fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_NORECORD; for (i = 0; i < 3; i++) { Fib.fib$r_fid_overlay.fib$w_fid [i] = Nam.nam$w_fid [i]; Fib.fib$r_did_overlay.fib$w_did [i] = Nam.nam$w_did [i]; } /* * Set up the file name descriptor for the QIO */ FileName.dsc$a_pointer = Nam.nam$l_name; FileName.dsc$w_length = Nam.nam$b_name + Nam.nam$b_type + Nam.nam$b_ver; /* * Use the IO$_ACCESS function to return info about the file. */ status = SYS$QIOW (0, chan, IO$_ACCESS, &iosb, 0, 0, &FibDesc, &FileName, 0, 0, 0, 0); if (!(status & 1)) return 0; status = iosb [0]; if (!(status & 1)) return 0; /* * Set up a date/time format that we can easily convert to - "YYMMDD HHMMSS" */ status = LIB$INIT_DATE_TIME_CONTEXT (&datetimecontext, &intime, &datetimeformat); if (!(status & 1)) return 0; /* * Convert the MS-DOS time ints to our ASCII format. */ date_desc.dsc$w_length = sprintf (date_str, "%04d%02d%02d %02d%02d%02d00", ((date >> 9) & 0x7f) + 1980, /* year */ (date >> 5) & 0x0f, /* month */ date & 0x1f, /* day */ (time >> 11)& 0x1f, /* hour */ (time >> 5) & 0x3f, /* min */ (time & 0x1f) * 2); /* sec */ /* * Convert our ASCII formatted date/time to VMS internal time format */ status = LIB$CONVERT_DATE_STRING (&date_desc, &intdate, &datetimecontext); if (!(status & 1)) return 0; /* * Fill in the creation date and revision date fields in the Extended Attribute * Block with the date and time from the zoo file. */ Cdate [0] = Rdate [0] = intdate [0]; Cdate [1] = Rdate [1] = intdate [1]; /* * Modify the file */ status = SYS$QIOW (0, chan, IO$_MODIFY, &iosb, 0, 0, &FibDesc, &FileName, 0, 0, &Atr, 0); if (!(status & 1)) return 0; status = iosb [0]; if (!(status & 1)) return 0; /* * Okee dokee. */ return 1; } zoo-2.10.orig/zoo.1100644 1750 1750 133135 5035113600 12633 0ustar jamesjames.\" derived from: @(#) zoo.1 2.44 88/08/25 16:05:30 */ .\" $Source: /usr/home/dhesi/zoo/RCS/zoo.1,v $ .\" $Id: zoo.1,v 1.4 91/07/09 02:25:41 dhesi Exp $ .\" .\" For formatting with nroff: .\" tbl zoo.1 | nroff -man | col .\" It should be possible to use troff instead of nroff but I haven't .\" confirmed this. R.D. .\" .na .TH ZOO 1 "July 7, 1991" .AT 3 .de sh .br .ne 5 .PP \fB\\$1\fR .PP .. .SH NAME zoo \- manipulate archives of files in compressed form .SH SYNOPSIS .B zoo .RB { acfDeghHlLPTuUvVx }[ aAcCdEfghImMnNoOpPqSu1:/.@n+\-= ] archive [file] ... .sp 0 .B zoo \-command archive [file] ... .sp 0 .B zoo h .SH DESCRIPTION .I Zoo is used to create and maintain collections of files in compressed form. It uses a Lempel-Ziv compression algorithm that gives space savings in the range of 20% to 80% depending on the type of file data. .I Zoo can store and selectively extract multiple generations of the same file. Data can be recovered from damaged archives by skipping the damaged portion and locating undamaged data with the help of .I fiz(1). .PP This documentation is for version 2.1. Changes from previous versions are described in the section labelled .BR CHANGES . .PP The command .I zoo .B h gives a summary of commands. Extended multiscreen help can be obtained with .I zoo .BR H . .PP .I Zoo will not add an archive to itself, nor add the archive's backup (with .B .bak extension to the filename) to the archive. .PP .I Zoo has two types of commands: Expert commands, which consist of one command letter followed by zero or more modifier characters, and Novice commands, which consist of a hyphen (`\-') followed by a command word that may be abbreviated. Expert commands are case-sensitive but Novice commands are not. .PP When .I zoo adds a file to an existing archive, the default action is to maintain one generation of each file in an archive and to mark any older generation as deleted. A limit on the number of generations to save can be specified by the user for an entire archive, or for each file individually, or both. .I Zoo deletes a stored copy of an added file if necessary to prevent the number of stored generations from exceeding the user-specified limit. .PP Deleted files may be later undeleted. Archives may be packed to recover space occupied by deleted files. .PP All commands assume that the archive name ends with the characters .B .zoo unless a different extension is supplied. .PP .B Novice commands .PP Novice commands may be abbreviated to a hyphen followed by at least one command character. Each Novice command works in two stages. First, the command does its intended work. Then, if the result was that one or more files were deleted in the specified archive, the archive is packed. If packing occurs, the original unpacked archive is always left behind with an extension of .BR .bak . .PP No Novice command ever stores the directory prefix of a file. .PP The Novice commands are as follows. .PP .TP 8 .B \-add Adds the specified files to the archive. .PP .TP .B \-freshen Adds a specified file to the archive if and only if an older file by the same name already exists in the archive. .PP .TP .B \-delete Deletes the specified files from the archive. .PP .TP .B \-update Adds a specified file to the archive either: if an older file by the same name already exists in the archive or: if a file by the same name does not already exist in the archive. .PP .TP .B \-extract Extracts the specified files from the archive. If no file is specified all files are extracted. .PP .TP .B \-move Equivalent to .B \-add except that source files are deleted after addition. .PP .TP .B \-print Equivalent to .B \-extract except that extracted data are sent to standard output. .PP .TP .B \-list Gives information about the specified archived files including any attached comments. If no files are specified all files are listed. Deleted files are not listed. .PP .TP .B \-test Equivalent to .B \-extract except that the extracted data are not saved but any errors encountered are reported. .PP .TP .B \-comment Allows the user to add or update comments attached to archived files. When prompted, the user may: type a carriage return to skip the file, leaving any current comment unchanged; or type a (possibly null) comment of up to 32,767 characters terminated by .B /end (case-insensitive) on a separate line; or type the end-of-file character (normally control D) to skip all remaining files. .PP .TP .B \-delete Deletes the specified files. .PP .ne 16 .nf The correspondence between Novice and Expert commands is as follows. .PP .\" Table formatting for troff thanks to Bill Davidsen .sp .TS H tab(@); l l l. Novice@@Equivalent Command@Description@Expert Command _ \-add@add files to archive@aP: \-extract@extract files from archive@x \-move@move files to archive@aMP: \-test@test archive integrity@xNd \-print@extract files to standard output@xp \-delete@delete files from archive@DP \-list@list archive contents@VC \-update@add new or newer files@aunP: \-freshen@by add newer files@auP: \-comment@add comments to files@c .TE .fi .PD .PP .sh "Expert commands" The general format of expert commands is: .PP .I zoo .RB { acfDeghHlLPTuUvVx }[ aAcCdEfghImMnNoOpPqSu1:/.@n+\-= ] archive [file] ... .PP The characters enclosed within {} are commands. Choose any one of these. The characters enclosed within [] just to the right of the {} are modifiers and zero or more of these may immediately follow the command character. All combinations of command and modifier characters may not be valid. .PP Files are added to an archive with the command: .PP .I zoo .RB { au }[ cfhIMnPqu:+\- ] archive [file] ... .PP Command characters are: .PP .TP .B a Add each specified file to archive. Any already-archived copy of the file is deleted if this is necessary to avoid exceeding the user-specified limit on the number of generations of the file to maintain in the archive. .PP .TP .B u Do an update of the archive. A specified file is added to the archive only if a copy of it is already in the archive and the copy being added is newer than the copy already in the archive. .PP The following modifiers are specific to these commands. .PP .TP .B M Move files to archive. This makes .I zoo delete (unlink) the original files after they have been added to the archive. Files are deleted after addition of all files to the archive is complete and after any requested packing of the archive has been done, and only if .I zoo detected no errors. .PP .TP .B n Add new files only. A specified file is added only if it isn't already in the archive. .PP .TP .B h Use the high performance compression algorithm. This option may be used with either the add (a) or filter (f) commands to gain extra compression at the expense of using somewhat more processor time. Extracting files compressed with the method is usually slightly faster than those saved with the default method. .PP .TP .B P Pack archive after files have been added. .PP .TP .B u Applied to the .B a command, this modifier makes it behave identically to the .B u command. .sp 1 The combination of the .B n modifier with the .B u modifier or .B u command causes addition of a file to the archive either if the file is not already in the archive, .I or if the file is already in the archive but the archived copy is older than the copy being added. .PP .TP .B : Do not store directory names. In the absence of this modifier .I zoo stores the full pathname of each archived file. .PP .TP .B I Read filenames to be archived from standard input. .I Zoo will read its standard input and assume that each line of text contains a filename. Under AmigaDOS and the **IX family, the entire line is used. Under MS-DOS and VAX/VMS, .I zoo assumes that the filename is terminated by a blank, tab, or newline; thus it is permissible for the line of text to contain more than one field separated by white space, and only the first field will be used. .sp 1 Under the **IX family of operating systems, .I zoo can be used as follows in a pipeline: .IP "" 10 find . \-print | .I zoo aI sources .IP "" 5 .sp 1 If the .B I modifier is specified, no filenames may be supplied on the command line itself. .PP .TP .BR + , \- These modifiers take effect only if the .B a command results in the creation of a new archive. .B + causes any newly-created archive to have generations enabled. .B \- is provided for symmetry and causes any newly-created archive to have generations disabled; this is also the default if neither .B + nor .B \- is specified. .PP Files are extracted from an archive with the command: .sp 1 .I zoo .RB { ex }[ dNoOpqS./@ ] archive [file] ... .PP The .B e and .B x commands are synonymous. If no file was specified, all files are extracted from the archive. .PP The following modifiers are specific to the e and x commands: .PP .TP .B N Do not save extracted data but report any errors encountered. .PP .TP .B O Overwrite files. Normally, if a file being extracted would overwrite an already-existing file of the same name, .I zoo asks you if you really want to overwrite it. You may answer the question with `y', which means yes, overwrite; or `n', which means no, don't overwrite; or `a', which means assume the answer is `y' for this and all subsequent files. The .B O modifier makes .I zoo assume that files may always be overwritten. Neither answering the question affirmatively nor using .B O alone will cause read-only files to be overwritten. .sp 1 On **IX systems, however, doubling this modifier as .B OO will force .I zoo to unconditionally overwrite any read-protected files with extracted files if it can do so. .sp 1 The .B O, N, and .B p modifiers are mutually exclusive. .PP .TP .B S Supersede newer files on disk with older extracted files. Unless this modifier is used, .I zoo will not overwrite a newer existing file with an older extracted file. .PP .TP .B o This is equivalent to the .B O modifier if and only if it is given at least twice. It is otherwise ignored. .PP .TP .B p Pipe extracted data to standard output. Error messages are piped to standard output as well. However, if a bad CRC is detected, an error message is sent both to standard error and to standard output. .PP .TP .B / Extract to original pathname. Any needed directories must already exist. In the absence of this modifier all files are extracted into the current directory. If this modifier is doubled as .BR // , required directories need not exist and are created if necessary. .PP The management of multiple generations of archived files is done with the commands: .sp 1 .B zoo \fBgl\fR[\fR\fBAq\fR]{\fR\fB+\-=\fR}\fR\fBnumber .B archive files .. .sp 0 .B zoo \fBgc\fR[\fR\fBq\fR]{\fR\fB+\-=\fR}\fR\fBnumber .B archive files .. .sp 0 .B zoo .BR gA [ q ] "\- archive" .sp 0 .B zoo .BR gA [ q ] "+ archive" .sp 1 The first form, .BR gl , adjusts the generation limit of selected files by the specified value. If the form .B "=n" is used, where n is a decimal number, this sets the generation limit to the specified value. If .B + or .B \- are used in placed of .B = the effect is to increment or decrement the generation limit by the specified value. For example, the command .IP "" 5 .B "zoo gl=5 xyz :" .IP "" 0 sets the generation limit of each file in the archive .B xyz.zoo to a value of 5. The command .IP "" 5 .B "zoo gl\-3 xyz :" .IP "" 0 decrements the generation limit of each file in the archive to 3 less than it currently is. .sp 1 If the .B A modifier is used, the archive-wide generation limit is adjusted instead. .sp 1 The number of generations of a file maintained in an archive is limited by the file generation limit, or the archive generation limit, whichever is lower. As a special case, a generation limit of 0 stands for no limit. Thus the default file generation limit of 0 and archive generation limit of 3 limits the number of generations of each file in a newly-created archive to three. .sp 1 The generation limit specified should be in the range 0 through 15; any higher numbers are interpreted modulo 16. .PP The second form of the command, using .BR gc , adjusts the generation count of selected files. Each file has a generation count of 1 when it is first added to an archive. Each time a file by the same name is added again to an archive, it receives a generation count that is one higher than the highest generation count of the archived copy of the file. The permissible range of generation counts is 1 through 65535. If repeated manipulations of an archive result in files having very high generation counts, they may be set back to lower numbers with the .B gc command. The syntax of the command is analogous to the syntax of the .B gl command, except that the .B A modifier is not applicable to the .B gc command. .PP The third form, .BR "gA\-" , disables generations in an archive. Generations are off when an archive is first created, but may be enabled with the fourth form of the command, .BR "gA+" . When generations are disabled in an archive, .I zoo will not display generation numbers in archive listings or maintain multiple generations. Generations can be re-enabled at any time, though manipulation of an archive with repeated interspersed .B "gA\-" and .B "gA+" commands may result in an archive whose behavior is not easily understandable. .PP Archived files are listed with the command: .sp 1 .I zoo .RB { lLvV }[ aAcCdfgmqvV@/1+\- ] .RB archive[ .zoo ] [file] ... .PP .TP .B l Information presented includes the date and time of each file, its original and current (compressed) sizes, and the percentage size decrease due to compression (labelled CF or compression factor). If a file was added to the archive in a different timezone, the difference between timezones is shown in hours as a signed number. As an example, if the difference is listed as +3, this means that the file was added to the archive in a timezone that is 3 hours west of the current timezone. The file time listed is, however, always the original timestamp of the archived file, as observed by the user who archived the file, expressed as that user's local time. (Timezone information is stored and displayed only if the underlying operating system knows about timezones.) .sp 1 If no filename is supplied all files are listed except deleted files. .sp 1 .I Zoo selects which generation(s) of a file to list according to the following algorithm. .sp 1 If no filename is supplied, only the latest generation of each file is listed. If any filenames are specified, and a generation is specified for an argument, only the requested generation is listed. If a filename is specified ending with the generation character (`:' or `;'), all generations of that file are listed. Thus a filename argument of the form .B zoo.c will cause only the latest generation of .I zoo.c to be listed; an argument of the form .B "zoo.c:4" will cause generation 4 of .I zoo.c to be listed; and an argument of the form .B "zoo.c:" or .B "zoo.c:*" will cause all generations of .I zoo.c to be listed. .PP .TP .B L This is similar to the .B l command except that all supplied arguments must be archives and all non-deleted generations of all files in each archive appear in the listing. .sp 1 On **IX systems, on which the shell expands arguments, if multiple archives are to be listed, the .B L command must be used. On other systems (VAX/VMS, AmigaDOS, MSDOS) on which wildcard expansion is done internally by .I zoo, wildcards may be used in the archive name, and a multiple archive listing obtained, using the .B l command. .PP .TP .B v This causes any comment attached to the archive to be listed in addition to the other information. .PP .TP .B V This causes any comment attached to the archive and also any comment attached to each file to be listed. .sp 1 Both the .B V and .B v command characters can also be used as modifiers to the .B l and .B L commands. .PP In addition to the general modifiers described later, the following modifiers can be applied to the archive list commands. .PP .TP .B a This gives a single-line format containing both each filename and the name of the archive, sorted by archive name. It is especially useful with the .B L command, since the result can be further sorted on any field to give a master listing of the entire contents of a set of archives. .PP .TP .B A This causes any comment attached to the archive to be listed. .PP .TP .B g This modifier causes file generation information to be listed about the archive. For each file listed, the user-specified generation limit, if any, is listed. For example, `3g' for a file means that the user wants no more than three generations of the file to be kept. In archives created by older versions of .I zoo, the listing will show `\-g', meaning that no generation information is kept and multiple generations of the file are not being maintained. .sp 1 In addition to the generation information for each file, the archive-wide generation limit, if any, is shown at the end of the listing. If generations have been disabled by the user, this is so indicated, for example: .IP "" 10 Archive generation limit is 3 (generations off). .IP "" 5 For more information about generations see the description of the .B g command. .PP .TP .B m This modifier is currently applicable to **IX systems only. It causes the mode bits (file protection code) of each file to be listed as a three-digit octal number. Currently .I zoo preserves only the lowest nine mode bits. Their meanings are as described in the **IX documentation for the .I chmod(1) command. .PP .TP .B C This modifier causes the stored cyclic redundancy code (CRC) for each archived file to be shown as a four-digit hexadecimal number. .PP .TP .B 1 This forces one filename to be listed per line. It is most useful in combination with the .B f modifier. .TP .B / This forces any directory name to be always listed, even in fast columnized listings that do not normally include any directory names. .PP .TP .BR + , \- The .B \- modifier causes trailing generation numbers to be omitted from filenames. The .B + modifier causes the trailing generation numbers to be shown, which is also the default if neither .B \- nor .B + is specified. .PP Files may be deleted and undeleted from an archive with the following commands: .sp 1 .I zoo .RB { DU }[ Pq1 ] archive file ... .PP The .B D command deletes the specified files and the .B U command undeletes the specified files. The .B 1 modifier (the digit one, not the letter ell) forces deletion or undeletion of at most one file. If multiple instances of the same file exist in an archive, use of the .B 1 modifier may allow selective extraction of one of these. .PP Comments may be added to an archive with the command: .sp 1 .I zoo .BR c [ A ] archive .PP Without the modifier .BR A , this behaves identically to the .B \-comment command. With the modifier .BR A , the command serves to add or update the comment attached to the archive as a whole. This comment may be listed with the .B lA, LA, v, and V commands. Applying the .B cA command to an archive that was created with an older version of .I zoo will result in an error message requesting that the user first pack the archive with the .B P command. This reorganizes the archive and creates space for the archive comment. .PP The timestamp of an archive may be adjusted with the command: .sp 1 .I zoo .BR T [ q ] archive .PP .I Zoo normally attempts to maintain the timestamp of an archive to reflect the age of the newest file stored in it. Should the timestamp ever be incorrect it can be fixed with the .B T command. .PP An archive may be packed with the command: .sp 1 .I zoo .BR P [ EPq ] archive .PP If the backup copy of the archive already exists, .I zoo will refuse to pack the archive unless the .B P modifier is also given. The .B E modifier causes .I zoo not to save a backup copy of the original archive after packing. A unique temporary file in the current directory is used to initially hold the packed archive. This file will be left behind if packing is interrupted or if for some reason this file cannot be renamed to the name of the original archive when packing is complete. .PP Packing removes any garbage data appended to an archive because of Xmodem file transfer and also recovers any wasted space remaining in an archive that has been frequently updated or in which comments were replaced. Packing also updates the format of any archive that was created by an older version of .I zoo so that newer features (e.g. archive-wide generation limit, archive comment) become fully available. .PP .I Zoo can act as a pure compression or uncompression filter, reading from standard input and writing to standard output. This is achieved with the command: .sp 1 .I zoo .BR f { cu } [ h ] .PP where .B c specifies compression, .B u specifies uncompression, and .B h used in addition requests the high-performance compression be used. A CRC value is used to check the integrity of the data. The compressed data stream has no internal archive structure and contains multiple files only if the input data stream was already structured, as might be obtained, for example, from .I tar or .I cpio. .PP Modem transfers can be speeded up with these commands: .IP "" 10 .I zoo .B fc < file | .I sz ... .I rz | .I zoo .B fu > file .IP "" 5 .PP .sh "General modifiers" .PP The following modifiers are applicable to several commands: .PP .TP .B c Applied to the .B a and .B u commands, this causes the user to be prompted for a comment for each file added to the archive. If the file being added has replaced, or is a newer generation of, a file already in the archive, any comment attached to that file is shown to the user and becomes attached to the newly-added file unless the user changes it. Possible user responses are as described for the .B \-comment command. Applied to the archive list command .BR l , the .B c modifier causes the listing of any comments attached to archived files. .PP .TP .BR \ . In conjunction with .B / or .B // this modifier causes any extracted pathname beginning with `/' to be interpreted relative to the current directory, resulting in the possible creation of a subtree rooted at the current directory. In conjunction with the command .B P the .B . modifier causes the packed archive to be created in the current directory. This is intended to allow users with limited disk space but multiple disk drives to pack large archives. .PP .TP .B d Most commands that act on an archive act only on files that are not deleted. The .B d modifier makes commands act on both normal and deleted files. If doubled as .BR dd , this modifier forces selection only of deleted files. .PP .TP .B f Applied to the .B a and .B u commands, the .B f modifier causes fast archiving by adding files without compression. Applied to .B l it causes a fast listing of files in a multicolumn format. .PP .TP .B q Be quiet. Normally .I zoo lists the name of each file and what action it is performing. The .B q modifier suppresses this. When files are being extracted to standard output, the .B q modifier suppresses the header preceding each file. When archive contents are being listed, this modifier suppresses any header and trailer. When a fast columnized listing is being obtained, this modifier causes all output to be combined into a single set of filenames for all archives being listed. .sp 1 When doubled as .BR qq , this modifier suppresses WARNING messages, and when tripled as .BR qqq , ERROR messages are suppressed too. FATAL error messages are never suppressed. .PP .sh "Recovering data from damaged archives" The .B @ modifier allows the user to specify the exact position in an archive where .I zoo should extract a file from, allowing damaged portions of an archive to be skipped. This modifier must be immediately followed by a decimal integer without intervening spaces, and possibly by a comma and another decimal integer, giving a command of the form .B l@m or .B l@m,n (to list archive contents) or .B x@m or .B x@m,n (to extract files from an archive). Listing or extraction begin at position .B m in the archive. The value of .B m must be the position within the archive of an undamaged directory entry. This position is usually obtained from .I fiz(1) version 2.0 or later. .sp 1 If damage to the archive has shortened or lengthened it, all positions within the archive may be changed by some constant amount. To compensate for this, the value of .B n may be specified. This value is also usually obtained from .I fiz(1). It should be the position in the archive of the file data corresponding to the directory entry that has been specified with .BR m . Thus if the command .B x@456,575 is given, it will cause the first 456 bytes of the archive to be skipped and extraction to begin at offset 456; in addition, .I zoo will attempt to extract the file data from position 575 in the archive instead of the value that is found in the directory entry read from the archive. For example, here is some of the output of .I fiz when it acts on a damaged .I zoo archive: .sp 1 .nf **************** 2526: DIR [changes] ==> 95 2587: DATA **************** 3909: DIR [copyrite] ==> 1478 3970: DATA 4769: DATA **************** .fi .sp 1 In such output, .B DIR indicates where .I fiz found a directory entry in the archive, and .B DATA indicates where .I fiz found file data in the archive. Filenames located by .I fiz are enclosed in square brackets, and the notation "==> 95" indicates that the directory entry found by .I fiz at position 2526 has a file data pointer to position 95. (This is clearly wrong, since file data always occur in an archive .I after their directory entry.) In actuality, .I fiz found file data at positions 2587, 3970, and 4769. Since .I fiz found only two directory entries, and each directory entry corresponds to one file, one of the file data positions is an artifact. .PP .sp 1 In this case, commands to try giving to .I zoo might be .B x@2526,2587 (extract beginning at position 2526, and get file data from position 2587), .B x@3090,3970 (extract at 3090, get data from 3970) and .B x@3909,4769 (extract at 3909, get data from 4769). Once a correctly-matched directory entry/file data pair is found, .I zoo will in most cases synchronize with and correctly extract all files subsequently found in the archive. Trial and error should allow all undamaged files to be extracted. Also note that self-extracting archives created using .I sez (the Self-Extracting .I Zoo utility for MS-DOS), which are normally executed on an MS-DOS system for extraction, can be extracted on non-MSDOS systems using .I "zoo's" damaged-archive recovery method using the .B @ modifier. .PP .sh "Wildcard handling" Under the **IX family of operating systems, the shell normally expands wildcards to a list of matching files. Wildcards that are meant to match files within an archive must therefore be escaped or quoted. When selecting files to be added to an archive, wildcard conventions are as defined for the shell. When selecting files from within an archive, wildcard handling is done by .I zoo as described below. .PP Under MS-DOS and AmigaDOS, quoting of wildcards is not needed. All wildcard expansion of filenames is done by .I zoo, and wildcards inside directory names are expanded only when listing or extracting files but not when adding them. .PP The wildcard syntax interpreted by .I zoo is limited to the following characters. .PP .TP .B * Matches any sequence of zero or more characters. .PP .TP .B \? Matches any single character. .sp 1 Arbitrary combinations of .B * and .B ? are allowed. .PP .TP .B / If a supplied pattern contains a slash anywhere in it, then the slash separating any directory prefix from the filename must be matched explicitly. If a supplied pattern contains no slashes, the match is selective only on the filename. .PP .TP .B c\-c Two characters separated by a hyphen specify a character range. All filenames beginning with those characters will match. The character range is meaningful only by itself or preceded by a directory name. It is not specially interpreted if it is part of a filename. .PP .TP .B ": and ;" These characters are used to separate a filename from a generation number and are used when selecting specific generations of archived files. If no generation character is used, the filename specified matches only the latest generation of the file. If the generation character is specified, the filename and the generation are matched independently by .I "zoo's" wildcard mechanism. If no generation is specified following the .B ":" or .B ";" character, all generations of that file will match. As a special case, a generation number of .B 0 matches only the latest generation of a file, while .B ^0 matches all generations of a file except the latest one. If no filename is specified preceding the generation character, all filenames will match. As a corollary, the generation character by itself matches all generations of all files. .PP MS-DOS users should note that .I zoo does not treat the dot as a special character, and it does not ignore characters following an asterisk. Thus .B * matches all filenames; .B *.* matches filenames containing a dot; .B *_* matches filenames containing an underscore; and .B *z matches all filenames that end with the character .BR z , whether or not they contain a dot. .PP .sh "Usage hints" The Novice command set in .I zoo is meant to provide an interface with functionality and format that will be familiar to users of other similar archive utilities. In keeping with this objective, the Novice commands do not maintain or use any subdirectory information or allow the use of .I "zoo's" ability to maintain multiple generations of files. For this reason, users should switch to exclusively using the Expert commands as soon as possible. .PP Although the Expert command set is quite large, it should be noted that in almost every case, all legal modifiers for a command are fully orthogonal. This means that the user can select any combination of modifiers, and when they act together, they will have the intuitively obvious effect. Thus the user need only memorize what each modifier does, and then can combine them as needed without much further thought. .PP For example, consider the .B a command which is used to add files to an archive. By itself, it simply adds the specified files. To cause only already-archived files to be updated if their disk copies have been modified, it is only necessary to add the .B u modifier, making the command .BR au . To cause only new files (i.e., files not already in the archive) to be added, the .B n modifier is used to create the command .BR an . To cause .I both already-archived files to be updated and new files to be added, the .B u and .B n modifiers can be used together, giving the command .BR aun . Since the order of modifiers is not significant, the command could also be .BR anu . .PP Further, the .B c modifier can be used to cause .I zoo to prompt the user for a comment to attach to each file added. And the .B f modifier can cause fast addition (addition without compression). It should be obvious then that the command .B auncf will cause .I zoo to update already-archived files, add new files, prompt the user for comments, and do the addition of files without any compression. Furthermore, if the user wishes to move files to the archive, i.e., delete the disk copy of each file after it is added to the archive, it is only necessary to add the .B M modifier to the command, so it becomes .BR auncfM . And if the user also wishes to cause the archive to be packed as part of the command, thus recovering space from any files that are replaced, the command can be modified to .B auncfMP by adding the .B P modifier that causes packing. .PP Similarly, the archive listing commands can be built up by combining modifiers. The basic command to list the contents of an archive is .BR l . If the user wants a fast columnized listing, the .B f modifier can be added to give the .B lf command. Since this listing will have a header giving the archive name and a trailer summarizing interesting information about the archive, such as the number of deleted files, the user may wish to "quieten" the listing by suppressing these; the relevant modifier is .BR q , which when added to the command gives .BR lfq . If the user wishes to see the **IX mode (file protection) bits, and also information about multiple generations, the modifiers .B m (show mode bits) and .B g (show generation information) can be added, giving the command .BR lfqmg . If the user also wishes to see an attached archive comment, the modifier .B A (for archive) will serve. Thus the command .B lfqmgA will give a fast columnized listing of the archive, suppressing any header and trailer, showing mode bits and generation information, and showing any comment attached to the archive as a whole. If in addition individual comments attached to files are also needed, simply append the .B c modifier to the command, making it .BR lfqmgAc . The above command will not show any deleted files, however; to see them, use the .B d modifier, making the command .B lfqmgAcd (or double it as in .B lfqmgAcdd if .I only the deleted files are to be listed). And if the user also wishes to see the CRC value for each file being listed, the modifier .B C will do this, as in the command .BR lfqmgAcdC , which gives a fast columnized listing of all files, including deleted files, showing any archive comment and file comments, and file protection codes and generation information, as well as the CRC value of each file. .PP Note that the above command .B lfqmgAcdC could also be abbreviated to .B VfqmgdC because the command .B V is shorthand for .B lcA (archive listing with all comments shown). Similarly the command .B v is shorthand for .BR lA (archive listing with archive comment shown). Both .B V and .B v can be used as modifiers to any of the other archive listing commands. .PP .sh "Generations" By default, .I zoo assumes that only the latest generation of a specified file is needed. If generations other than the latest one need to be selected, this may be done by specifying them in the filename. For example, the name .B stdio.h would normally refer to the latest generation of the file .I stdio.h stored in a .I zoo archive. To get an archive listing showing all generations of .I stdio.h in the archive, the specification .B stdio.h:* could be used (enclosed in single quotes if necessary to protect the wildcard character .B * from the shell). Also, .B stdio.h:0 selects only the latest generation of .I stdio.h, while .B stdio.h:^0 selects all generations except the latest one. The .B : character here separates the filename from the generation number, and the character .B * is a wildcard that matches all possible generations. For convenience, the generation itself may be left out, so that the name .B stdio.h: (with the .B : but without a generation number or a wildcard) matches all generations exactly as .B stdio.h:* does. .PP If a generation is specified but no filename is present, as in .BR :5 , .BR :* , or just .BR : , all filenames of the specified generation will be selected. Thus .B :5 selects generation 5 of each file, and .B :* and .B : select all generations of all files. .PP It is important to note that .I "zoo's" idea of the latest generation of a file is not based upon searching the entire archive. Instead, whenever .I zoo adds a file to an archive, it is marked as being the latest generation. Thus, if the latest generation of a file is deleted, then .I no generation of that file is considered the latest any more. This can be surprising to the user. For example, if an archive already contains the file .I stdio.h:5 and a new copy is added, appearing in the archive listing as .I stdio.h:6, and then .I stdio.h:6 is deleted, the remaining copy .I stdio.h:5 will no longer be considered to be the latest generation, and the file .I stdio.h:5, even if undeleted, will no longer appear in an archive listing unless generation 5 (or every generation) is specifically requested. This behavior will likely be improved in future releases of .I zoo. .SH FILES xXXXXXX \- temporary file used during packing .sp 0 .RB archive_name. bak \- backup of archive .SH "SEE ALSO" compress(1), fiz(1) .SH BUGS When files are being added to an archive on a non-MS-DOS system, it is possible for .I zoo to fail to detect a full disk and hence create an invalid archive. This bug will be fixed in a future release. .PP Files with generation counts that wrap around from 65535 to 1 are not currently handled correctly. If a file's generation count reaches a value close to 65535, it should be manually set back down to a low number. This may be easily done with a command such as .BR gc\-65000 , which subtracts 65000 from the generation count of each specified file. This problem will be fixed in a future release. .PP Although .I zoo on **IX systems preserves the lowest nine mode bits of regular files, it does not currently do the same for directories. .PP Currently .I "zoo's" handling of the characters .B : and .B ; in filenames is not robust, because it interprets these to separate a filename from a generation number. A quoting mechanism will eventually be implemented. .PP Standard input cannot be archived nor can a created archive be sent to standard output. Spurious error messages may appear if the filename of an archive is too long. .PP Since .I zoo never archives any file with the same name as the archive or its backup (regardless of any path prefixes), care should be taken to make sure that a file to be archived does not coincidentally have the same name as the archive it is being added to. It usually suffices to make sure that no file being archived is itself a .I zoo archive. (Previous versions of .I zoo sometimes tried to add an archive to itself. This bug now seems to be fixed.) .PP Only regular files are archived; devices and empty directories are not. Support for archiving empty directories and for preserving directory attributes is planned for the near future. .PP Early versions of MS-DOS have a bug that prevents "." from referring to the root directory; this leads to anomalous results if the extraction of paths beginning with a dot is attempted. .PP VAX/VMS destroys case information unless arguments are enclosed in double quotes. For this reason if a command given to .I zoo on a VAX/VMS system includes any uppercase characters, it must be enclosed in double quotes. Under VAX/VMS, .I zoo does not currently restore file timestamps; this will be fixed as soon as I figure out RMS extended attribute blocks, or DEC supplies a utime() function, whichever occurs first. Other VMS bugs, related to file structures, can often be overcome by using the program .I bilf.c that is supplied with .I zoo. .PP It is not currently possible to create a .I zoo archive containing all .I zoo archives that do not contain themselves. .SH DIAGNOSTICS Error messages are intended to be self-explanatory and are divided into three categories. WARNINGS are intended to inform the user of an unusual situation, such as a CRC error during extraction, or .BR \-freshen ing of an archive containing a file newer than one specified on the command line. ERRORS are fatal to one file, but execution continues with the next file if any. FATAL errors cause execution to be aborted. The occurrence of any of these causes an exit status of 1. Normal termination without any errors gives an exit status of 0. (Under VAX/VMS, however, to avoid an annoying message, .I zoo always exits with an error code of 1.) .SH COMPATIBILITY All versions of .I zoo on all systems are required to create archives that can be extracted and listed with all versions of .I zoo on all systems, regardless of filename and directory syntax or archive structure; furthermore, any version of .I zoo must be able to fully manipulate all archives created by all lower-numbered versions of .I zoo on all systems. So far as I can tell, this upward compatibility (all manipulations) and downward compatiblity (ability to extract and list) is maintained by .I zoo versions up to 2.01. Version 2.1 adds the incompatibility that if high-performance compression is used, earlier versions cannot extract files compressed with version 2.1. This is the only incompatibility that is permissible. You are forbidden, with the force of copyright law, to create from the .I zoo source code any derivative work that violates this compatibility goal, whether knowingly or through negligence. If any violation of this compatibility goal is observed, this should be considered a serious problem and reported to me. .SH CHANGES Here is a list of changes occurring from version 1.50 to version 2.01. In parentheses is given the version in which each change occurred. .TP \- (1.71) New modifiers to the list commands permit optional suppression of header and trailer information, inclusion of directory names in columnized listings, and fast one-column listings. .TP \- (1.71) Timezones are handled. .TP \- (1.71) A bug was fixed that had made it impossible to individually update comments for a file whose name did not correspond to MS-DOS format. .TP \- (1.71) A change was made that now permits use of the shared library on the **IX PC. .TP \- (1.71) VAX/VMS is now supported reasonably well. .TP \- (2.00) A comment may now be attached to the archive itself. .TP \- (2.00) The \fBOO\fR option allows forced overwriting of read-only files. .TP \- (2.00) \fIZoo\fR will no longer extract a file if a newer copy already exists on disk; the .B S option will override this. .TP \- (2.00) File attributes are preserved for **IX systems. .TP \- (2.00) Multiple generations of the same file are supported. .TP \- (2.00) \fIZoo\fR will now act as a compression or decompression filter on a stream of data and will use a CRC value to check the integrity of a data stream that is uncompressed. .TP \- (2.00) A bug was fixed that caused removal of a directory link if files were moved to an archive by the superuser on a **IX system. .TP \- (2.00) The data recovery modifier .B @ was greatly enhanced. Self-extracting archives created for MS-DOS systems can now be extracted by .I zoo on any system with help from .I fiz(1). .TP \- (2.01) A bug was fixed that had caused the first generation of a file to sometimes unexpectedly show up in archive listings. .TP \- (2.01) A bug was fixed that had caused the MS-DOS version to silently skip files that could not be extracted because of insufficient disk space. .TP \- (2.01) A bug was fixed that had sometimes made it impossible to selectively extract a file by specifying its name, even though all files could be extracted from the archive by not specifying any filenames. This occurred when a file had been archived on a longer-filename system (e.g. AmigaDOS) and extraction was attempted on a shorter-filename system (e.g. MS-DOS). .TP \- (2.01) A change was made that will make zoo preserve the mode (file protection) of a zoo archive when it is packed. This is effective only if zoo is compiled to preserve and restore file attributes. Currently this is so only for **IX systems. .TP \- (2.01) A bug was fixed that had caused an update of an archive to not always add all newer files. .TP \- (2.01) Blanks around equal signs in commands given to "make" were removed from the mk* scripts for better compatiblity with more **IX implementations including Sun's. .TP \- (2.1) Compression is now greatly improved if the "h" option is used. .TP \- (2.1) The default behavior is to preserve full pathnames during extraction. .TP \- (2.1) On some systems, extraction of files using the older (default) compression method is greatly speeded up. .TP \- (2.1) Extended multiscreen help is available. .TP \- (2.1) Memory allocation is improved, so that the MS-DOS version will not prematurely abort when updating a large archive. .TP \- (2.1) The VAX/VMS version preserves file timestamps during extraction. .TP \- (2.1) The default archive-wide generation limit, when generations are enabled, is 3. .SH "FUTURE DIRECTIONS" A revised version of .I zoo is in the works that will be able to write newly-created archives to standard output and will support multivolume archives. It will be upward and downward compatible with this version of .I zoo. .SH ACKNOWLEDGEMENTS The .I zoo archiver was initially developed using Microsoft C 3.0 on a PC clone manufactured by Toshiba of Japan and almost sold by Xerox. Availability of the following systems was helpful in achieving portability: Paul Homchick's Compaq running Microport System V/AT; The Eskimo BBS somewhere in Oregon running Xenix/68000; Greg Laskin's system 'gryphon' which is an Intel 310 running Xenix/286; Ball State University's AT&T 3B2/300, UNIX PC, and VAX-11/785 (4.3BSD and VAX/VMS) systems. In addition J. Brian Waters provided feedback to help me make the code compilable on his Amiga using Manx/Aztec C. The executable version 2.0 for MS-DOS is currently compiled with Borland's Turbo C++ 1.0. .PP Thanks are due to the following people and many others too numerous to mention. .PP J. Brian Waters , who has worked diligently to port .I zoo to AmigaDOS, created Amiga-specific code, and continues keeping it updated. .PP Paul Homchick , who provided numerous detailed reports about some nasty bugs. .PP Bill Davidsen , who provided numerous improvements to this manual, contributed multiscreen help, and provided many useful bug reports, bug fixes, code improvements, and suggestions. .PP Mark Alexander , who provided me with some bug fixes. .PP Haruhiko Okumura, who wrote the .I ar archiver and some excellent compression code, which I adapted for use in .I zoo. .PP Randal L. Barnes , who (with Randy Magnuson) wrote the code to support the preservation of file timestamps under VAX/VMS. .PP Raymond D. Gardner, who contributed replacement uncompression code that on some systems is twice as fast as the original. .PP Greg Yachuk and Andre Van Dalen, who independently modified MS-DOS .I zoo to support multivolume archives. (This support is not yet in this official release.) .SH AUTHOR Rahul Dhesi zoo-2.10.orig/zoo.c100644 1750 1750 37332 5035113600 12677 0ustar jamesjames#ifndef LINT /* derived from: zoo.c 2.24 88/01/29 00:55:09 */ static char sccsid[]="$Id: zoo.c,v 1.21 91/07/09 02:36:40 dhesi Exp $"; #endif /* LINT */ #if 0 #define TRACEI(item) printf("line %d: %s= %d\n", __LINE__, #item, item) #define TRACES(item) printf("line %d: %s= [%s]\n", __LINE__, #item, item) #endif extern char version[]; /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved (C) Copyright 1991 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "zooio.h" #include "various.h" #include "zoo.h" #include "zoofns.h" #include "errors.i" #include "zoomem.h" static void ms_help(); static void wait_return(); #ifdef TRACE_IO int verbose = 0; #endif int instr PARMS ((char *, char *)); char *out_buf_adr; /* points to memory allocated for output buffer(s) */ char *in_buf_adr; /* points to memory allocated for input buffer */ /* static declarations */ int quiet = 0; /* whether to be quiet */ int next_arg = FIRST_ARG; /* filenames start at this position */ int arg_count; /* count of arguments supplied to program */ char **arg_vector; /* vector of arguments supplied to program */ main(argc,argv) register int argc; register char **argv; { char *zooname; /* synonym for argv[2] -- to make life easier */ #ifndef OOZ static char incorrect_args[] = "Incorrect number of arguments.\n"; int filecount; /* how many filespecs supplied */ #endif /* OOZ */ #ifdef OOZ #else /* else not OOZ */ static char usage[] = "Usage: zoo {acDeglLPTuUvx}[aAcCdEfInmMNoOpPqu1:/.@n] archive file\n(\"zoo h\" for help, \"zoo H\" for extended help)\n"; static char nov_usage[] = "\nNovice usage: zoo -cmd archive[.zoo] file... where -cmd is one of these:\n"; char *option; static char nov_cmds[] = /* ADD=0EXT=5 MOV=14TES=20PRI=26 DEL=33 LIS=41UPD=47 FRE=55 COMMENT=64 */ "-add -extract -move -test -print -delete -list -update -freshen -comment\n"; #ifdef NOENUM #define NONE -1 #define ADD 0 #define EXTRACT 5 #define MOVE 14 #define TEST 20 #define PRINT 26 #define DELETE 33 #define LIST 41 #define UPDATE 47 #define FRESHEN 55 #define COMMENT 64 int cmd = NONE; #else enum choice { NONE = -1, ADD = 0, EXTRACT = 5, MOVE = 14, TEST = 20, PRINT = 26, DELETE = 33, LIST = 41, UPDATE = 47, FRESHEN = 55, COMMENT = 64 }; enum choice cmd = NONE; /* assume no Novice command */ #endif #endif /* end of not OOZ */ #ifdef SPECINIT void spec_init PARMS ((void)); spec_init(); /* system-specific startup code */ #endif /* make sure T_UINT16 is an unsigned 16-bit type, exactly. This code is included only if T_UINT16 was defined by default at the end of options.h. */ #ifdef CHECK_TUINT { T_UINT16 i; int status = 0; i = ((unsigned) 1) << 15; if (i < 0) status = 1; if (i != ((unsigned) 1) << 15) status = 1; i *= 2; if (i != 0) status = 1; if (status != 0) prterror('w', "Configuration problem: T_UINT16 is not 16 bits\n"); } #endif arg_count = argc; arg_vector = argv; zooname = argv[FIRST_ARG-1]; /* points to name or archive */ #ifdef OOZ if (argc < 2) { putstr (usage1); putstr (usage2); zooexit (1); } #else /* else not OOZ */ if (argc < 2) goto show_usage; filecount = argc - 3; option = str_dup(argv[1]); #ifdef TRACE_IO if (*option == ':') { /* for debugging output */ verbose++; option++; /* hide the : from other functions */ } #endif #ifdef WAIT_PROMPT if (*option == 'w') { option++; /* hide w from other functions */ wait_return(); } #endif /* WAIT_PROMPT */ if (*option == 'H') ms_help(option); if (*option == 'h' || *option == 'H') goto bigusage; if (strchr("-acDegflLPTuUvVx", *option) == NULL) goto give_list; if (*option == '-') { #ifdef NOENUM cmd = instr (nov_cmds, str_lwr(option)); #else cmd = (enum choice) instr (nov_cmds, str_lwr(option)); #endif if (strlen(option) < 2 || cmd == NONE) goto show_usage; if ( ((cmd == ADD || cmd == MOVE || cmd == FRESHEN || cmd == UPDATE || cmd == DELETE) && argc < 4) || ((cmd == EXTRACT || cmd == TEST || cmd == LIST || cmd == PRINT || cmd == COMMENT) && argc < 3)) { fprintf (stderr, incorrect_args); goto show_usage; } } else { char *wheresI; /* will be null if I option not supplied */ if ( ( strchr("au",*option) && ( (((wheresI = strchr(option,'I')) != 0) && argc != 3) || wheresI==NULL && argc < 4 ) ) || strchr("DU",*option) && argc < 4 || strchr("cexlvVL",*option) && argc < 3 || strchr("TP",*option) && argc != 3 || (*option == 'f' && argc != 2) || (*option == 'g' && (strchr(option,'A') == NULL && argc < 4 || strchr(option,'A') != NULL && argc != 3 ) ) ) { fprintf (stderr, incorrect_args); goto show_usage; } } #endif /* end of not OOZ */ #ifndef OOZ /* if not doing a list and no extension in archive name, add default extension */ if (*option != 'f' && cmd != LIST && strchr("lvVL", *option) == NULL && strchr(nameptr (zooname), EXT_CH) == NULL) zooname = newcat (zooname, EXT_DFLT); #endif /* Here we allocate a large block of memory for the duration of the program. lzc() and lzd() will use half of it each. Routine getfile() will use all of it. Routine decode() will use the first 8192 bytes of it. Routine encode() will use all of it. */ /* fudge/2 fudge/2 ** [______________||________________|] ** output buffer input buffer */ out_buf_adr = ealloc (MEM_BLOCK_SIZE); in_buf_adr = out_buf_adr + OUT_BUF_SIZE + (FUDGE/2); #ifdef OOZ zooext(zooname, "\0"); /* just extract -- no fancy stuff */ zooexit (0); /* and exit normally */ #else /* else not OOZ -- parse command line and invoke a routine */ if (cmd != NONE) { switch (cmd) { case ADD: zooadd (zooname, filecount, &argv[3], "aP:"); break; case FRESHEN: zooadd (zooname, filecount, &argv[3], "auP:"); break; case UPDATE: zooadd (zooname, filecount, &argv[3], "aunP:"); break; case MOVE: zooadd (zooname, filecount, &argv[3], "aMP:"); break; case EXTRACT: zooext (zooname, "x"); break; case TEST: zooext (zooname, "xNd"); break; case PRINT: zooext (zooname, "xp"); break; case DELETE: zoodel (zooname, "DP",1); break; case LIST: zoolist (&argv[2], "VC", argc-2); break; case COMMENT: comment (zooname, "c"); break; default: goto show_usage; } } else switch (*option) { case 'a': case 'u': case 'T': zooadd (zooname, filecount, &argv[3], option); break; #ifdef FILTER case 'f': zoofilt (option); break; #endif /* FILTER */ case 'D': zoodel (zooname, option, 1); break; case 'U': zoodel (zooname, option, 0); break; case 'g': zoodel (zooname, option, 2); break; case 'v': case 'V': case 'l': zoolist(&argv[2], option, 1); break; case 'L': zoolist(&argv[2], option, argc-2); break; case 'e': case 'x': zooext(zooname, option); break; case 'P': zoopack (zooname, option); break; case 'c': comment (zooname, option); break; default: goto give_list; } zooexit (0); /* don't fall through */ /* usage list including Novice commands */ show_usage: fprintf (stderr, "%s\n\n%s%s%s", version, usage, nov_usage, nov_cmds); zooexit (1); /* brief usage list */ give_list: fprintf (stderr, usage); zooexit (1); /* help screen */ bigusage: printf("\n\n\n\n\n\n\n\n"); printf ("Zoo archiver, %s\n", version); printf("(C) Copyright 1991 Rahul Dhesi -- Noncommercial use permitted\n"); printf (usage); printf ("\nChoose a command from within {} and zero or more modifiers from within [].\n"); printf ("E.g.: `zoo a save /bin/*' will archive all files in /bin into save.zoo.\n"); printf ("(Please see the user manual for a complete description of commands.)\n\n"); printf (nov_usage); printf (nov_cmds); printf ("\n\n\n\n"); wait_return(); /* print msg & wait for RETURN */ printf ("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf (usage); printf (" Commands in {} mean: |Modifiers in [] mean:\n"); printf (" a add files | a show archive name(s) in listing\n"); printf (" c update comments | A apply g or c to archive\n"); printf (" D delete stored files | c add/list comments\n"); printf (" e,x extract files | d extract/list deleted files too\n"); printf (" g adj. gen. limit/count | dd extract/list only deleted files\n"); printf (" l,L,v,V list filenames | E erase backup after packing\n"); printf (" P pack archive | f fast add (no compression) or list\n"); printf (" T fix archive datestamp | M move when adding (erase original)\n"); printf (" u add only newer files | n add only files not already in archive\n"); printf (" U undelete stored files | N send extracted data to Nowhere\n"); #ifdef FILTER printf (" f act as filter | c/u compress/uncompress as filter\n"); #endif /* FILTER */ printf (" ----------------------------- O don't ask \"Overwrite?\"\n"); printf (" q be quiet p pipe extracted data to standard output\n"); printf (" : don't store dir names /,// extract full pathnames\n"); printf (" . pack to current dir I add filenames read from stdin\n"); printf (" C show file CRC value +/- enable/disable generations\n"); printf (" S overwrite newer files g list generation limits\n"); printf (" P pack after adding @n start extract/list at position n\n"); #ifdef FATTR printf (" m list file modes OO overwrite read-only files\n"); #endif /* FATTR */ printf (" C change archive cmnt h use high-compression method\n"); #endif /* end of not OOZ */ /* NOTE: if allowed to fall through and return without an exit() statement, it was printing garbage--corrupted stack? Why--bug in Microsoft C? */ zooexit (1); return 1; /* keep lint & compilers happy */ } /* multi-screen help facility thanks to Bill Davidsen */ /* help screens */ static char *scrn1[] = { "", "command line format:", " zoo {command}[options] archive files(s)", "", "Commands:", " a add files", " u - update, replace only if file is newer than saved version", " n - new, add if file is not in archive", " f - fast, don't compress at all", " h - high performance compressor, slower than default", " M - move files to archive, delete after saving", " c - add a comment to each file added", " C - add a comment to the archive as a whole", " : - strip directory names, save filenames only", " q - quiet (qq suppresses warnings, qqq suppresses nonfatal errors too)", " P - pack after adding, remove overwritten or deleted files", " (leaves a .bak file, use PP to overwrite it)", " I - read filenames from standard input", " + - enable generations", (char *)NULL }; static char *scrn2[] = { "", " e extract files", " x extract files", " : - extract to current directory (ignore pathnames)", " . - make absolute pathnames relative to current directory", " (name /etc/hosts becomes ./etc/hosts)", " / - extract to subdirs, // create subdirs as needed - default", " (the sequence :/ may be used to use but not create subdirs)", " q - quiet", " d - extract deleted files, too. dd extract *only* deleted files", " N - extract to nowhere. Used to test the archive with xN or xNq", " p - extract for pipe to standard output. Use q to avoid header", "", #ifdef FATTR " O - overwrite without asking, OO overwrites readonly files", #else " O - overwrite without asking", #endif " S - overwrite superceded (newer) files", (char *)NULL }; static char *scrn3[] = { "", " l list archive info", " L list info for multiple archives", " v list verbose file info and archive comment", " V list verbose file info, archive and file comments", " v - verbose (same as v command, used with L for multiple files", " V - verbose with file comments", " C - show CRC", " a - show archive name in file listing (useful with L)", #ifdef FATTR " m - mode, show file modes in octal", #endif " d - show deleted files", " q - quiet, shows only file info, no comments or headers", " f - fast, lists only filename, no pathname, multiple columns", " 1 - one column output (for the f option)", "", " c comment changes, change or add comments to listed files", " (changes all file comments if no files given)", " A - only change archive comment", (char *)NULL }; static char *scrn4[] = { "", " P pack archive, remove deleted or overwritten files", " E - erase the .bak file when done", "", " D delete files by name", " P - pack after deletion, use PP if .bak file exists", " q - quiet", "", " T timestamp adjust, make archive age of newest file", "", " g generation commands", " l - set generation limit on files", " A - apply limit to archive rather than a file (with gl)", "", " f filter, copy stdin to stdout with [de]compression", " c - compress", " u - uncompress", " h - use the high compression method", (char *)NULL }; static char *scrn5[] = { "", "Examples:", "", "# just add a few files", " zoo a arch file1 files", "# add C source files in subdirectories", " zoo a test part1/*.c part2/*.c", "# add documentation files with high compression", " zoo ah test *.doc", "", "# extract all files", " zoo x test", "# extract files into the current directory", " zoo x: test", "# extract a single file and sort before listing", " zoo xp test users.lst | sort", "", "# list the contents and archive comments", " zoo v arch", "# list all files in all archives", " zoo L xxx.zoo /doc/*.zoo ../*.zoo", (char *)NULL }; static char **screens[] = { scrn1, /* intro and add */ scrn2, /* extract */ scrn3, /* list commands */ scrn4, /* other commands */ scrn5, /* add and extract examples */ (char **)NULL }; /* multi-screen help routine */ static void ms_help(options) char *options; { #ifndef SZ_SCREEN /* screen size can be overridden in options.h */ # define SZ_SCREEN 24 #endif int scrnlen = SZ_SCREEN; char ***curscreen, **curline; int linecount; /* if "Hnn" output in nn line format */ if (++options) sscanf(options, "%d", &scrnlen); if (scrnlen < 2) scrnlen = SZ_SCREEN; /* loop thru screens */ for (curscreen = screens; *curscreen != NULL; ++curscreen) { printf("\n\n\n\n"); linecount = scrnlen; curline = *curscreen; while (*curline != NULL) { printf("%s\n", *(curline++)); --linecount; } /* slew page */ while (--linecount != 0) putchar('\n'); wait_return(); /* print msg & wait for RETURN */ } exit(0); } /* wait_return prints a message, then waits until user hits RETURN key, then returns. Special cases: (a) if not interactive (as tested with isatty() if available), it returns immediately; (b) while waiting for RETURN, if EOF occurs, it causes zooexit(0) */ static void wait_return() { #ifdef HAVE_ISATTY if (!isatty(fileno(stdout)) || !isatty(fileno(stdin))) return; #endif (void) printf("Hit RETURN (or ENTER) key to continue..."); for ( ; ;) { int key; key = getchar(); if (key == EOF) zooexit(0); if (key == '\n' || key == '\r') return; } } zoo-2.10.orig/zoo.h100644 1750 1750 23775 5035113600 12712 0ustar jamesjames/* derived from: zoo.h 2.16 88/01/27 23:21:36 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ /* Global data structures and also some information about archive structure. Among other things, the archive header contains: (a) A text message. In the MS-DOS version this message is terminated by control Z. This allows naive users to type the archive to the screen and see a brief but meaningful message instead of garbage. The contents of the text message are however not used by Zoo and they may be anything. In particular, the text message may identify the type or archive or the particular computer system it was created on. When an archive is packed by any version of Zoo, the text message is changed to the text message used by that version. For example, if Zoo 1.10 packs an archive created by Zoo 1.31, the text message changes to "Zoo 1.10 archive.". This was once considered a shortcoming, but it is now an essential feature, because packing will also update an old archiver header structure into a new one. (b) A four-byte tag that identifies all Zoo archives. This helps prevent arbitrary binary files from being treated as Zoo archives. The tag value is arbitrary, but seemed to be unlikely to occur in an executable file. The same tag value is used to identify each directory entry. (c) A long pointer to where in the file the archive starts. This pointer is stored along with its negation for consistency checking. It is hoped that if the archive is damaged, both the pointer and its negation won't be damaged and at least one would still be usable to tell us where the data begins. (d) A two-byte value giving the major and minor version number of the minimum version of Zoo that is needed to fully manipulate the archive. As the archive structure is modified, this version number may increase. Currently version 1.71 of Zoo creates archives that may be fully manipulated by version 1.40 onwards. (e) With zoo 2.00 addtional fields have been added in the archive header to store information about the archive comment and generation limit. Version numbering: The directory entry of each file will contain the minimum version number of Zoo needed to extract that file. As far as possible, version 1.00 of Zoo will be able to extract files from future version archives. */ #define H_TYPE 1 /* archive header type */ /* Define major and minor version numbers */ #define MAJOR_VER 2 /* needed to manipulate archive */ #define MINOR_VER 0 /* version needed to extract packing method 1 */ #define MAJOR_EXT_VER 1 #define MINOR_EXT_VER 0 /* version needed to extract packing method 2 */ #define MAJOR_LZH_VER 2 #define MINOR_LZH_VER 1 #define CTRL_Z 26 /* should be 0xFDC4A7DCUL but many c compilers don't recognize UL at end */ #define ZOO_TAG ((unsigned long) 0xFDC4A7DCL) /* A random choice */ #define TEXT "ZOO 2.10 Archive.\032" /* Header text for archive. */ #define SIZ_TEXT 20 /* Size of header text */ #define PATHSIZE 256 /* Max length of pathname */ #define FNAMESIZE 13 /* Size of DOS filename */ #define LFNAMESIZE 256 /* Size of long filename */ #define ROOTSIZE 8 /* Size of fname without extension */ #define EXTLEN 3 /* Size of extension */ #define FILE_LEADER "@)#(" /* Allowing location of file data */ #define SIZ_FLDR 5 /* 4 chars plus null */ #define MAX_PACK 2 /* max packing method we can handle */ #define BACKUP_EXT ".bak" /* extension of backup file */ #ifdef OOZ #define FIRST_ARG 2 #endif #ifdef ZOO #define FIRST_ARG 3 /* argument position of filename list */ #endif typedef unsigned char uchar; /* WARNING: Static initialization in zooadd.c or zooext.c depends on the order of fields in struct zoo_header */ struct zoo_header { char text[SIZ_TEXT]; /* archive header text */ unsigned long zoo_tag; /* identifies archives */ long zoo_start; /* where the archive's data starts */ long zoo_minus; /* for consistency checking of zoo_start */ uchar major_ver; uchar minor_ver; /* minimum version to extract all files */ uchar type; /* type of archive header */ long acmt_pos; /* position of archive comment */ unsigned int acmt_len; /* length of archive comment */ unsigned int vdata; /* byte in archive; data about versions */ }; struct direntry { unsigned long zoo_tag; /* tag -- redundancy check */ uchar type; /* type of directory entry. always 1 for now */ uchar packing_method; /* 0 = no packing, 1 = normal LZW */ long next; /* pos'n of next directory entry */ long offset; /* position of this file */ unsigned int date; /* DOS format date */ unsigned int time; /* DOS format time */ unsigned int file_crc; /* CRC of this file */ long org_size; long size_now; uchar major_ver; uchar minor_ver; /* minimum version needed to extract */ uchar deleted; /* will be 1 if deleted, 0 if not */ uchar struc; /* file structure if any */ long comment; /* points to comment; zero if none */ unsigned int cmt_size; /* length of comment, 0 if none */ char fname[FNAMESIZE]; /* filename */ int var_dir_len; /* length of variable part of dir entry */ uchar tz; /* timezone where file was archived */ unsigned int dir_crc; /* CRC of directory entry */ /* fields for variable part of directory entry follow */ uchar namlen; /* length of long filename */ uchar dirlen; /* length of directory name */ char lfname[LFNAMESIZE]; /* long filename */ char dirname[PATHSIZE]; /* directory name */ unsigned int system_id; /* Filesystem ID */ unsigned long fattr; /* File attributes -- 24 bits */ unsigned int vflag; /* version flag bits -- one byte in archive */ unsigned int version_no; /* file version number if any */ }; /* Values for direntry.system_id */ #define SYSID_NIX 0 /* UNIX and similar filesystems */ #define SYSID_MS 1 /* MS-DOS filesystem */ #define SYSID_PORTABLE 2 /* Portable syntax */ /* Structure of header of small archive containing just one file */ #define TINYTAG 0x07FE /* magic number */ #ifndef PORTABLE struct tiny_header { /* one-file small archive */ int tinytag; /* magic number */ char type; /* always 1 for now */ char packing_method; unsigned int date; unsigned int time; unsigned int file_crc; long org_size; long size_now; char major_ver; char minor_ver; unsigned int cmt_size; /* length of comment, 0 if none */ char fname[FNAMESIZE]; /* filename */ }; #endif /* ifndef PORTABLE */ #define FIXED_OFFSET 34 /* zoo_start in old archives */ #define MINZOOHSIZ 34 /* minimum size of archive header */ #define SIZ_ZOOH 42 /* length of current archive header */ /* offsets of items within the canonical zoo archive header */ #define TEXT_I 0 /* text in header */ #define ZTAG_I 20 /* zoo tag */ #define ZST_I 24 /* start offset */ #define ZSTM_I 28 /* negative of start offset */ #define MAJV_I 32 /* major version */ #define MINV_I 33 /* minor version */ #define HTYPE_I 34 /* archive header type */ #define ACMTPOS_I 35 /* position of archive comment */ #define ACMTLEN_I 39 /* length of archive comment */ #define HVDATA_I 41 /* version data */ /* offsets of items within the canonical directory entry structure */ #define SIZ_DIR 51 /* length of type 1 directory entry */ #define SIZ_DIRL 56 /* length of type 2 directory entry */ #define DTAG_I 0 /* tag within directory entry */ #define DTYP_I 4 /* type of directory entry */ #define PKM_I 5 /* packing method */ #define NXT_I 6 /* pos'n of next directory entry */ #define OFS_I 10 /* position (offset) of this file */ #define DAT_I 14 /* DOS format date */ #define TIM_I 16 /* DOS format time */ #define CRC_I 18 /* CRC of this file */ #define ORGS_I 20 /* original size */ #define SIZNOW_I 24 /* size now */ #define DMAJ_I 28 /* major version number */ #define DMIN_I 29 /* minor version number */ #define DEL_I 30 /* deleted or not */ #define STRUC_I 31 /* file structure */ #define CMT_I 32 /* comment [offset] */ #define CMTSIZ_I 36 /* comment size */ #define FNAME_I 38 /* filename */ #define VARDIRLEN_I 51 /* length of var. direntry */ #define TZ_I 53 /* timezone */ #define DCRC_I 54 /* CRC of directory entry */ #define FNM_SIZ 13 /* size of stored filename */ /* Offsets within variable part of directory entry */ #define NAMLEN_I (SIZ_DIRL + 0) #define DIRLEN_I (SIZ_DIRL + 1) #define LFNAME_I (SIZ_DIRL + 2) #define DIRNAME_I LFNAME_I /* plus length of filename */ /* Total size of fixed plus variable directory recognized currently: One byte each for dirlen and namlen, 256 each for long filename and directory name, 2 for system id, 3 for file attributes, 1 for version flag, 2 for version number, plus a fudge factor of 5. */ #define MAXDIRSIZE (SIZ_DIRL+1+1+256+256+2+3+1+2+5) /* Value used to stuff into timezone field if it is not known */ #define NO_TZ 127 /* Value for no file attributes */ #define NO_FATTR 0L /* version flag bits */ #define VFL_ON 0x80 /* enable version numbering */ #define VFL_GEN 0x0f /* generation count */ #define VFL_LAST 0x40 /* last generation of this file */ /* default generation value for archive */ #define GEN_DEFAULT 3 /* max generation count, file or archive */ #define MAXGEN 0x0f /* version mask to prune down to correct size on large-word machines */ #define VER_MASK 0xffff zoo-2.10.orig/zoo.man100644 1750 1750 141606 5035113600 13250 0ustar jamesjames ZOO(1) REFERENCE MANUAL ZOO(1) NAME zoo - manipulate archives of files in compressed form SYNOPSIS zoo {acfDeghHlLPTuUvVx}[aAcCdEfghImMnNoOpPqSu1:/.@n+-=] archive [file] ... zoo -command archive [file] ... zoo h DESCRIPTION Zoo is used to create and maintain collections of files in compressed form. It uses a Lempel-Ziv compression algorithm that gives space savings in the range of 20% to 80% depend- ing on the type of file data. Zoo can store and selectively extract multiple generations of the same file. Data can be recovered from damaged archives by skipping the damaged por- tion and locating undamaged data with the help of fiz(1). This documentation is for version 2.1. Changes from previ- ous versions are described in the section labelled CHANGES. The command zoo h gives a summary of commands. Extended multiscreen help can be obtained with zoo H. Zoo will not add an archive to itself, nor add the archive's backup (with .bak extension to the filename) to the archive. Zoo has two types of commands: Expert commands, which con- sist of one command letter followed by zero or more modifier characters, and Novice commands, which consist of a hyphen (`-') followed by a command word that may be abbreviated. Expert commands are case-sensitive but Novice commands are not. When zoo adds a file to an existing archive, the default action is to maintain one generation of each file in an archive and to mark any older generation as deleted. A limit on the number of generations to save can be specified by the user for an entire archive, or for each file indivi- dually, or both. Zoo deletes a stored copy of an added file if necessary to prevent the number of stored generations from exceeding the user-specified limit. Deleted files may be later undeleted. Archives may be packed to recover space occupied by deleted files. All commands assume that the archive name ends with the characters .zoo unless a different extension is supplied. Novice commands Novice commands may be abbreviated to a hyphen followed by at least one command character. Each Novice command works in two stages. First, the command does its intended work. Then, if the result was that one or more files were deleted in the specified archive, the archive is packed. If packing occurs, the original unpacked archive is always left behind with an extension of .bak. No Novice command ever stores the directory prefix of a file. The Novice commands are as follows. -add Adds the specified files to the archive. -freshen Adds a specified file to the archive if and only if an older file by the same name already exists in the archive. -delete Deletes the specified files from the archive. -update Adds a specified file to the archive either: if an older file by the same name already exists in the archive or: if a file by the same name does not already exist in the archive. -extract Extracts the specified files from the archive. If no file is specified all files are extracted. -move Equivalent to -add except that source files are deleted after addition. -print Equivalent to -extract except that extracted data are sent to standard output. -list Gives information about the specified archived files including any attached comments. If no files are specified all files are listed. Deleted files are not listed. -test Equivalent to -extract except that the extracted data are not saved but any errors encountered are reported. -comment Allows the user to add or update comments attached to archived files. When prompted, the user may: type a carriage return to skip the file, leaving any current comment unchanged; or type a (possibly null) comment of up to 32,767 characters terminated by /end (case- insensitive) on a separate line; or type the end-of- file character (normally control D) to skip all remain- ing files. -delete Deletes the specified files. The correspondence between Novice and Expert commands is as follows. Novice Equivalent Command Description Expert Command ____________________________________________________________ -add add files to archive aP: -extract extract files from archive x -move move files to archive aMP: -test test archive integrity xNd -print extract files to standard output xp -delete delete files from archive DP -list list archive contents VC -update add new or newer files aunP: -freshen by add newer files auP: -comment add comments to files c Expert commands The general format of expert commands is: zoo {acfDeghHlLPTuUvVx}[aAcCdEfghImMnNoOpPqSu1:/.@n+-=] archive [file] ... The characters enclosed within {} are commands. Choose any one of these. The characters enclosed within [] just to the right of the {} are modifiers and zero or more of these may immediately follow the command character. All combinations of command and modifier characters may not be valid. Files are added to an archive with the command: zoo {au}[cfhIMnPqu:+-] archive [file] ... Command characters are: a Add each specified file to archive. Any already- archived copy of the file is deleted if this is neces- sary to avoid exceeding the user-specified limit on the number of generations of the file to maintain in the archive. u Do an update of the archive. A specified file is added to the archive only if a copy of it is already in the archive and the copy being added is newer than the copy already in the archive. The following modifiers are specific to these commands. M Move files to archive. This makes zoo delete (unlink) the original files after they have been added to the archive. Files are deleted after addition of all files to the archive is complete and after any requested packing of the archive has been done, and only if zoo detected no errors. n Add new files only. A specified file is added only if it isn't already in the archive. h Use the high performance compression algorithm. This option may be used with either the add (a) or filter (f) commands to gain extra compression at the expense of using somewhat more processor time. Extracting files compressed with the method is usually slightly faster than those saved with the default method. P Pack archive after files have been added. u Applied to the a command, this modifier makes it behave identically to the u command. The combination of the n modifier with the u modifier or u command causes addition of a file to the archive either if the file is not already in the archive, or if the file is already in the archive but the archived copy is older than the copy being added. : Do not store directory names. In the absence of this modifier zoo stores the full pathname of each archived file. I Read filenames to be archived from standard input. Zoo will read its standard input and assume that each line of text contains a filename. Under AmigaDOS and the **IX family, the entire line is used. Under MS-DOS and VAX/VMS, zoo assumes that the filename is terminated by a blank, tab, or newline; thus it is permissible for the line of text to contain more than one field separated by white space, and only the first field will be used. Under the **IX family of operating systems, zoo can be used as follows in a pipeline: find . -print | zoo aI sources If the I modifier is specified, no filenames may be supplied on the command line itself. +,- These modifiers take effect only if the a command results in the creation of a new archive. + causes any newly-created archive to have generations enabled. - is provided for symmetry and causes any newly-created archive to have generations disabled; this is also the default if neither + nor - is specified. Files are extracted from an archive with the command: zoo {ex}[dNoOpqS./@] archive [file] ... The e and x commands are synonymous. If no file was speci- fied, all files are extracted from the archive. The following modifiers are specific to the e and x com- mands: N Do not save extracted data but report any errors encountered. O Overwrite files. Normally, if a file being extracted would overwrite an already-existing file of the same name, zoo asks you if you really want to overwrite it. You may answer the question with `y', which means yes, overwrite; or `n', which means no, don't overwrite; or `a', which means assume the answer is `y' for this and all subsequent files. The O modifier makes zoo assume that files may always be overwritten. Neither answer- ing the question affirmatively nor using O alone will cause read-only files to be overwritten. On **IX systems, however, doubling this modifier as OO will force zoo to unconditionally overwrite any read- protected files with extracted files if it can do so. The O, N, and p modifiers are mutually exclusive. S Supersede newer files on disk with older extracted files. Unless this modifier is used, zoo will not overwrite a newer existing file with an older extracted file. o This is equivalent to the O modifier if and only if it is given at least twice. It is otherwise ignored. p Pipe extracted data to standard output. Error messages are piped to standard output as well. However, if a bad CRC is detected, an error message is sent both to standard error and to standard output. / Extract to original pathname. Any needed directories must already exist. In the absence of this modifier all files are extracted into the current directory. If this modifier is doubled as //, required directories need not exist and are created if necessary. The management of multiple generations of archived files is done with the commands: zoo gl[Aq]{+-=}number archive files .. zoo gc[q]{+-=}number archive files .. zoo gA[q]- archive zoo gA[q]+ archive The first form, gl, adjusts the generation limit of selected files by the specified value. If the form =n is used, where n is a decimal number, this sets the generation limit to the specified value. If + or - are used in placed of = the effect is to increment or decrement the generation limit by the specified value. For example, the command zoo gl=5 xyz : sets the generation limit of each file in the archive xyz.zoo to a value of 5. The command zoo gl-3 xyz : decrements the generation limit of each file in the archive to 3 less than it currently is. If the A modifier is used, the archive-wide generation limit is adjusted instead. The number of generations of a file maintained in an archive is limited by the file generation limit, or the archive gen- eration limit, whichever is lower. As a special case, a generation limit of 0 stands for no limit. Thus the default file generation limit of 0 and archive generation limit of 3 limits the number of generations of each file in a newly- created archive to three. The generation limit specified should be in the range 0 through 15; any higher numbers are interpreted modulo 16. The second form of the command, using gc, adjusts the gen- eration count of selected files. Each file has a generation count of 1 when it is first added to an archive. Each time a file by the same name is added again to an archive, it receives a generation count that is one higher than the highest generation count of the archived copy of the file. The permissible range of generation counts is 1 through 65535. If repeated manipulations of an archive result in files having very high generation counts, they may be set back to lower numbers with the gc command. The syntax of the command is analogous to the syntax of the gl command, except that the A modifier is not applicable to the gc com- mand. The third form, gA-, disables generations in an archive. Generations are off when an archive is first created, but may be enabled with the fourth form of the command, gA+. When generations are disabled in an archive, zoo will not display generation numbers in archive listings or maintain multiple generations. Generations can be re-enabled at any time, though manipulation of an archive with repeated inter- spersed gA- and gA+ commands may result in an archive whose behavior is not easily understandable. Archived files are listed with the command: zoo {lLvV}[aAcCdfgmqvV@/1+-] archive[.zoo] [file] ... l Information presented includes the date and time of each file, its original and current (compressed) sizes, and the percentage size decrease due to compression (labelled CF or compression factor). If a file was added to the archive in a different timezone, the difference between timezones is shown in hours as a signed number. As an example, if the difference is listed as +3, this means that the file was added to the archive in a timezone that is 3 hours west of the current timezone. The file time listed is, however, always the original timestamp of the archived file, as observed by the user who archived the file, expressed as that user's local time. (Timezone information is stored and displayed only if the underlying operating system knows about timezones.) If no filename is supplied all files are listed except deleted files. Zoo selects which generation(s) of a file to list according to the following algorithm. If no filename is supplied, only the latest generation of each file is listed. If any filenames are specified, and a generation is specified for an argu- ment, only the requested generation is listed. If a filename is specified ending with the generation char- acter (`:' or `;'), all generations of that file are listed. Thus a filename argument of the form zoo.c will cause only the latest generation of zoo.c to be listed; an argument of the form zoo.c:4 will cause generation 4 of zoo.c to be listed; and an argument of the form zoo.c: or zoo.c:* will cause all generations of zoo.c to be listed. L This is similar to the l command except that all sup- plied arguments must be archives and all non-deleted generations of all files in each archive appear in the listing. On **IX systems, on which the shell expands arguments, if multiple archives are to be listed, the L command must be used. On other systems (VAX/VMS, AmigaDOS, MSDOS) on which wildcard expansion is done internally by zoo, wildcards may be used in the archive name, and a multiple archive listing obtained, using the l com- mand. v This causes any comment attached to the archive to be listed in addition to the other information. V This causes any comment attached to the archive and also any comment attached to each file to be listed. Both the V and v command characters can also be used as modifiers to the l and L commands. In addition to the general modifiers described later, the following modifiers can be applied to the archive list com- mands. a This gives a single-line format containing both each filename and the name of the archive, sorted by archive name. It is especially useful with the L command, since the result can be further sorted on any field to give a master listing of the entire contents of a set of archives. A This causes any comment attached to the archive to be listed. g This modifier causes file generation information to be listed about the archive. For each file listed, the user-specified generation limit, if any, is listed. For example, `3g' for a file means that the user wants no more than three generations of the file to be kept. In archives created by older versions of zoo, the list- ing will show `-g', meaning that no generation informa- tion is kept and multiple generations of the file are not being maintained. In addition to the generation information for each file, the archive-wide generation limit, if any, is shown at the end of the listing. If generations have been disabled by the user, this is so indicated, for example: Archive generation limit is 3 (generations off). For more information about generations see the descrip- tion of the g command. m This modifier is currently applicable to **IX systems only. It causes the mode bits (file protection code) of each file to be listed as a three-digit octal number. Currently zoo preserves only the lowest nine mode bits. Their meanings are as described in the **IX documentation for the chmod(1) command. C This modifier causes the stored cyclic redundancy code (CRC) for each archived file to be shown as a four- digit hexadecimal number. 1 This forces one filename to be listed per line. It is most useful in combination with the f modifier. / This forces any directory name to be always listed, even in fast columnized listings that do not normally include any directory names. +,- The - modifier causes trailing generation numbers to be omitted from filenames. The + modifier causes the trailing generation numbers to be shown, which is also the default if neither - nor + is specified. Files may be deleted and undeleted from an archive with the following commands: zoo {DU}[Pq1] archive file ... The D command deletes the specified files and the U command undeletes the specified files. The 1 modifier (the digit one, not the letter ell) forces deletion or undeletion of at most one file. If multiple instances of the same file exist in an archive, use of the 1 modifier may allow selective extraction of one of these. Comments may be added to an archive with the command: zoo c[A] archive Without the modifier A, this behaves identically to the -comment command. With the modifier A, the command serves to add or update the comment attached to the archive as a whole. This comment may be listed with the lA, LA, v, and V commands. Applying the cA command to an archive that was created with an older version of zoo will result in an error message requesting that the user first pack the archive with the P command. This reorganizes the archive and creates space for the archive comment. The timestamp of an archive may be adjusted with the com- mand: zoo T[q] archive Zoo normally attempts to maintain the timestamp of an archive to reflect the age of the newest file stored in it. Should the timestamp ever be incorrect it can be fixed with the T command. An archive may be packed with the command: zoo P[EPq] archive If the backup copy of the archive already exists, zoo will refuse to pack the archive unless the P modifier is also given. The E modifier causes zoo not to save a backup copy of the original archive after packing. A unique temporary file in the current directory is used to initially hold the packed archive. This file will be left behind if packing is interrupted or if for some reason this file cannot be renamed to the name of the original archive when packing is complete. Packing removes any garbage data appended to an archive because of Xmodem file transfer and also recovers any wasted space remaining in an archive that has been frequently updated or in which comments were replaced. Packing also updates the format of any archive that was created by an older version of zoo so that newer features (e.g. archive- wide generation limit, archive comment) become fully avail- able. Zoo can act as a pure compression or uncompression filter, reading from standard input and writing to standard output. This is achieved with the command: zoo f{cu}[h where c specifies compression, u specifies uncompression, and h used in addition requests the high-performance compression be used. A CRC value is used to check the integrity of the data. The compressed data stream has no internal archive structure and contains multiple files only if the input data stream was already structured, as might be obtained, for example, from tar or cpio. Modem transfers can be speeded up with these commands: zoo fc < file | sz ... rz | zoo fu > file General modifiers The following modifiers are applicable to several commands: c Applied to the a and u commands, this causes the user to be prompted for a comment for each file added to the archive. If the file being added has replaced, or is a newer generation of, a file already in the archive, any comment attached to that file is shown to the user and becomes attached to the newly-added file unless the user changes it. Possible user responses are as described for the -comment command. Applied to the archive list command l, the c modifier causes the list- ing of any comments attached to archived files. . In conjunction with / or // this modifier causes any extracted pathname beginning with `/' to be interpreted relative to the current directory, resulting in the possible creation of a subtree rooted at the current directory. In conjunction with the command P the . modifier causes the packed archive to be created in the current directory. This is intended to allow users with limited disk space but multiple disk drives to pack large archives. d Most commands that act on an archive act only on files that are not deleted. The d modifier makes commands act on both normal and deleted files. If doubled as dd, this modifier forces selection only of deleted files. f Applied to the a and u commands, the f modifier causes fast archiving by adding files without compression. Applied to l it causes a fast listing of files in a multicolumn format. q Be quiet. Normally zoo lists the name of each file and what action it is performing. The q modifier suppresses this. When files are being extracted to standard output, the q modifier suppresses the header preceding each file. When archive contents are being listed, this modifier suppresses any header and trailer. When a fast columnized listing is being obtained, this modifier causes all output to be com- bined into a single set of filenames for all archives being listed. When doubled as qq, this modifier suppresses WARNING messages, and when tripled as qqq, ERROR messages are suppressed too. FATAL error messages are never suppressed. Recovering data from damaged archives The @ modifier allows the user to specify the exact position in an archive where zoo should extract a file from, allowing damaged portions of an archive to be skipped. This modifier must be immediately followed by a decimal integer without intervening spaces, and possibly by a comma and another decimal integer, giving a command of the form l@m or l@m,n (to list archive contents) or x@m or x@m,n (to extract files from an archive). Listing or extraction begin at position m in the archive. The value of m must be the position within the archive of an undamaged directory entry. This position is usually obtained from fiz(1) version 2.0 or later. If damage to the archive has shortened or lengthened it, all positions within the archive may be changed by some constant amount. To compensate for this, the value of n may be specified. This value is also usually obtained from fiz(1). It should be the position in the archive of the file data corresponding to the directory entry that has been specified with m. Thus if the command x@456,575 is given, it will cause the first 456 bytes of the archive to be skipped and extraction to begin at offset 456; in addition, zoo will attempt to extract the file data from position 575 in the archive instead of the value that is found in the directory entry read from the archive. For example, here is some of the output of fiz when it acts on a damaged zoo archive: **************** 2526: DIR [changes] ==> 95 2587: DATA **************** 3909: DIR [copyrite] ==> 1478 3970: DATA 4769: DATA **************** In such output, DIR indicates where fiz found a directory entry in the archive, and DATA indicates where fiz found file data in the archive. Filenames located by fiz are enclosed in square brackets, and the notation "==> 95" indicates that the directory entry found by fiz at position 2526 has a file data pointer to position 95. (This is clearly wrong, since file data always occur in an archive after their directory entry.) In actuality, fiz found file data at positions 2587, 3970, and 4769. Since fiz found only two directory entries, and each directory entry corresponds to one file, one of the file data positions is an artifact. In this case, commands to try giving to zoo might be x@2526,2587 (extract beginning at position 2526, and get file data from position 2587), x@3090,3970 (extract at 3090, get data from 3970) and x@3909,4769 (extract at 3909, get data from 4769). Once a correctly-matched directory entry/file data pair is found, zoo will in most cases syn- chronize with and correctly extract all files subsequently found in the archive. Trial and error should allow all undamaged files to be extracted. Also note that self- extracting archives created using sez (the Self-Extracting Zoo utility for MS-DOS), which are normally executed on an MS-DOS system for extraction, can be extracted on non-MSDOS systems using zoo's damaged-archive recovery method using the @ modifier. Wildcard handling Under the **IX family of operating systems, the shell nor- mally expands wildcards to a list of matching files. Wild- cards that are meant to match files within an archive must therefore be escaped or quoted. When selecting files to be added to an archive, wildcard conventions are as defined for the shell. When selecting files from within an archive, wildcard handling is done by zoo as described below. Under MS-DOS and AmigaDOS, quoting of wildcards is not needed. All wildcard expansion of filenames is done by zoo, and wildcards inside directory names are expanded only when listing or extracting files but not when adding them. The wildcard syntax interpreted by zoo is limited to the following characters. * Matches any sequence of zero or more characters. ? Matches any single character. Arbitrary combinations of * and ? are allowed. / If a supplied pattern contains a slash anywhere in it, then the slash separating any directory prefix from the filename must be matched explicitly. If a supplied pattern contains no slashes, the match is selective only on the filename. c-c Two characters separated by a hyphen specify a charac- ter range. All filenames beginning with those charac- ters will match. The character range is meaningful only by itself or preceded by a directory name. It is not specially interpreted if it is part of a filename. : and ; These characters are used to separate a filename from a generation number and are used when selecting specific generations of archived files. If no generation char- acter is used, the filename specified matches only the latest generation of the file. If the generation char- acter is specified, the filename and the generation are matched independently by zoo's wildcard mechanism. If no generation is specified following the : or ; charac- ter, all generations of that file will match. As a special case, a generation number of 0 matches only the latest generation of a file, while ^0 matches all gen- erations of a file except the latest one. If no filename is specified preceding the generation charac- ter, all filenames will match. As a corollary, the generation character by itself matches all generations of all files. MS-DOS users should note that zoo does not treat the dot as a special character, and it does not ignore characters fol- lowing an asterisk. Thus * matches all filenames; *.* matches filenames containing a dot; *_* matches filenames containing an underscore; and *z matches all filenames that end with the character z, whether or not they contain a dot. Usage hints The Novice command set in zoo is meant to provide an inter- face with functionality and format that will be familiar to users of other similar archive utilities. In keeping with this objective, the Novice commands do not maintain or use any subdirectory information or allow the use of zoo's abil- ity to maintain multiple generations of files. For this reason, users should switch to exclusively using the Expert commands as soon as possible. Although the Expert command set is quite large, it should be noted that in almost every case, all legal modifiers for a command are fully orthogonal. This means that the user can select any combination of modifiers, and when they act together, they will have the intuitively obvious effect. Thus the user need only memorize what each modifier does, and then can combine them as needed without much further thought. For example, consider the a command which is used to add files to an archive. By itself, it simply adds the speci- fied files. To cause only already-archived files to be updated if their disk copies have been modified, it is only necessary to add the u modifier, making the command au. To cause only new files (i.e., files not already in the archive) to be added, the n modifier is used to create the command an. To cause both already-archived files to be updated and new files to be added, the u and n modifiers can be used together, giving the command aun. Since the order of modifiers is not significant, the command could also be anu. Further, the c modifier can be used to cause zoo to prompt the user for a comment to attach to each file added. And the f modifier can cause fast addition (addition without compression). It should be obvious then that the command auncf will cause zoo to update already-archived files, add new files, prompt the user for comments, and do the addition of files without any compression. Furthermore, if the user wishes to move files to the archive, i.e., delete the disk copy of each file after it is added to the archive, it is only necessary to add the M modifier to the command, so it becomes auncfM. And if the user also wishes to cause the archive to be packed as part of the command, thus recovering space from any files that are replaced, the command can be modified to auncfMP by adding the P modifier that causes packing. Similarly, the archive listing commands can be built up by combining modifiers. The basic command to list the contents of an archive is l. If the user wants a fast columnized listing, the f modifier can be added to give the lf command. Since this listing will have a header giving the archive name and a trailer summarizing interesting information about the archive, such as the number of deleted files, the user may wish to "quieten" the listing by suppressing these; the relevant modifier is q, which when added to the command gives lfq. If the user wishes to see the **IX mode (file protection) bits, and also information about multiple gen- erations, the modifiers m (show mode bits) and g (show gen- eration information) can be added, giving the command lfqmg. If the user also wishes to see an attached archive comment, the modifier A (for archive) will serve. Thus the command lfqmgA will give a fast columnized listing of the archive, suppressing any header and trailer, showing mode bits and generation information, and showing any comment attached to the archive as a whole. If in addition individual comments attached to files are also needed, simply append the c modifier to the command, making it lfqmgAc. The above com- mand will not show any deleted files, however; to see them, use the d modifier, making the command lfqmgAcd (or double it as in lfqmgAcdd if only the deleted files are to be listed). And if the user also wishes to see the CRC value for each file being listed, the modifier C will do this, as in the command lfqmgAcdC, which gives a fast columnized listing of all files, including deleted files, showing any archive comment and file comments, and file protection codes and generation information, as well as the CRC value of each file. Note that the above command lfqmgAcdC could also be abbrevi- ated to VfqmgdC because the command V is shorthand for lcA (archive listing with all comments shown). Similarly the command v is shorthand for lA (archive listing with archive comment shown). Both V and v can be used as modifiers to any of the other archive listing commands. Generations By default, zoo assumes that only the latest generation of a specified file is needed. If generations other than the latest one need to be selected, this may be done by specify- ing them in the filename. For example, the name stdio.h would normally refer to the latest generation of the file stdio.h stored in a zoo archive. To get an archive listing showing all generations of stdio.h in the archive, the specification stdio.h:* could be used (enclosed in single quotes if necessary to protect the wildcard character * from the shell). Also, stdio.h:0 selects only the latest genera- tion of stdio.h, while stdio.h:^0 selects all generations except the latest one. The : character here separates the filename from the generation number, and the character * is a wildcard that matches all possible generations. For con- venience, the generation itself may be left out, so that the name stdio.h: (with the : but without a generation number or a wildcard) matches all generations exactly as stdio.h:* does. If a generation is specified but no filename is present, as in :5, :*, or just :, all filenames of the specified genera- tion will be selected. Thus :5 selects generation 5 of each file, and :* and : select all generations of all files. It is important to note that zoo's idea of the latest gen- eration of a file is not based upon searching the entire archive. Instead, whenever zoo adds a file to an archive, it is marked as being the latest generation. Thus, if the latest generation of a file is deleted, then no generation of that file is considered the latest any more. This can be surprising to the user. For example, if an archive already contains the file stdio.h:5 and a new copy is added, appear- ing in the archive listing as stdio.h:6, and then stdio.h:6 is deleted, the remaining copy stdio.h:5 will no longer be considered to be the latest generation, and the file stdio.h:5, even if undeleted, will no longer appear in an archive listing unless generation 5 (or every generation) is specifically requested. This behavior will likely be improved in future releases of zoo. FILES xXXXXXX - temporary file used during packing archive_name.bak - backup of archive SEE ALSO compress(1), fiz(1) BUGS When files are being added to an archive on a non-MS-DOS system, it is possible for zoo to fail to detect a full disk and hence create an invalid archive. This bug will be fixed in a future release. Files with generation counts that wrap around from 65535 to 1 are not currently handled correctly. If a file's genera- tion count reaches a value close to 65535, it should be manually set back down to a low number. This may be easily done with a command such as gc-65000, which subtracts 65000 from the generation count of each specified file. This problem will be fixed in a future release. Although zoo on **IX systems preserves the lowest nine mode bits of regular files, it does not currently do the same for directories. Currently zoo's handling of the characters : and ; in filenames is not robust, because it interprets these to separate a filename from a generation number. A quoting mechanism will eventually be implemented. Standard input cannot be archived nor can a created archive be sent to standard output. Spurious error messages may appear if the filename of an archive is too long. Since zoo never archives any file with the same name as the archive or its backup (regardless of any path prefixes), care should be taken to make sure that a file to be archived does not coincidentally have the same name as the archive it is being added to. It usually suffices to make sure that no file being archived is itself a zoo archive. (Previous ver- sions of zoo sometimes tried to add an archive to itself. This bug now seems to be fixed.) Only regular files are archived; devices and empty direc- tories are not. Support for archiving empty directories and for preserving directory attributes is planned for the near future. Early versions of MS-DOS have a bug that prevents "." from referring to the root directory; this leads to anomalous results if the extraction of paths beginning with a dot is attempted. VAX/VMS destroys case information unless arguments are enclosed in double quotes. For this reason if a command given to zoo on a VAX/VMS system includes any uppercase characters, it must be enclosed in double quotes. Under VAX/VMS, zoo does not currently restore file timestamps; this will be fixed as soon as I figure out RMS extended attribute blocks, or DEC supplies a utime() function, which- ever occurs first. Other VMS bugs, related to file struc- tures, can often be overcome by using the program bilf.c that is supplied with zoo. It is not currently possible to create a zoo archive con- taining all zoo archives that do not contain themselves. DIAGNOSTICS Error messages are intended to be self-explanatory and are divided into three categories. WARNINGS are intended to inform the user of an unusual situation, such as a CRC error during extraction, or -freshening of an archive containing a file newer than one specified on the command line. ERRORS are fatal to one file, but execution continues with the next file if any. FATAL errors cause execution to be aborted. The occurrence of any of these causes an exit status of 1. Normal termination without any errors gives an exit status of 0. (Under VAX/VMS, however, to avoid an annoying mes- sage, zoo always exits with an error code of 1.) COMPATIBILITY All versions of zoo on all systems are required to create archives that can be extracted and listed with all versions of zoo on all systems, regardless of filename and directory syntax or archive structure; furthermore, any version of zoo must be able to fully manipulate all archives created by all lower-numbered versions of zoo on all systems. So far as I can tell, this upward compatibility (all manipulations) and downward compatiblity (ability to extract and list) is maintained by zoo versions up to 2.01. Version 2.1 adds the incompatibility that if high-performance compression is used, earlier versions cannot extract files compressed with version 2.1. This is the only incompatibility that is permissible. You are forbidden, with the force of copyright law, to create from the zoo source code any derivative work that violates this compatibility goal, whether knowingly or through negligence. If any violation of this compatibility goal is observed, this should be considered a serious prob- lem and reported to me. CHANGES Here is a list of changes occurring from version 1.50 to version 2.01. In parentheses is given the version in which each change occurred. - (1.71) New modifiers to the list commands permit optional suppression of header and trailer information, inclusion of directory names in columnized listings, and fast one-column listings. - (1.71) Timezones are handled. - (1.71) A bug was fixed that had made it impossible to individually update comments for a file whose name did not correspond to MS-DOS format. - (1.71) A change was made that now permits use of the shared library on the **IX PC. - (1.71) VAX/VMS is now supported reasonably well. - (2.00) A comment may now be attached to the archive itself. - (2.00) The OO option allows forced overwriting of read-only files. - (2.00) Zoo will no longer extract a file if a newer copy already exists on disk; the S option will over- ride this. - (2.00) File attributes are preserved for **IX systems. - (2.00) Multiple generations of the same file are sup- ported. - (2.00) Zoo will now act as a compression or decompres- sion filter on a stream of data and will use a CRC value to check the integrity of a data stream that is uncompressed. - (2.00) A bug was fixed that caused removal of a direc- tory link if files were moved to an archive by the superuser on a **IX system. - (2.00) The data recovery modifier @ was greatly enhanced. Self-extracting archives created for MS-DOS systems can now be extracted by zoo on any system with help from fiz(1). - (2.01) A bug was fixed that had caused the first gen- eration of a file to sometimes unexpectedly show up in archive listings. - (2.01) A bug was fixed that had caused the MS-DOS ver- sion to silently skip files that could not be extracted because of insufficient disk space. - (2.01) A bug was fixed that had sometimes made it impossible to selectively extract a file by specifying its name, even though all files could be extracted from the archive by not specifying any filenames. This occurred when a file had been archived on a longer- filename system (e.g. AmigaDOS) and extraction was attempted on a shorter-filename system (e.g. MS-DOS). - (2.01) A change was made that will make zoo preserve the mode (file protection) of a zoo archive when it is packed. This is effective only if zoo is compiled to preserve and restore file attributes. Currently this is so only for **IX systems. - (2.01) A bug was fixed that had caused an update of an archive to not always add all newer files. - (2.01) Blanks around equal signs in commands given to "make" were removed from the mk* scripts for better compatiblity with more **IX implementations including Sun's. - (2.1) Compression is now greatly improved if the "h" option is used. - (2.1) The default behavior is to preserve full path- names during extraction. - (2.1) On some systems, extraction of files using the older (default) compression method is greatly speeded up. - (2.1) Extended multiscreen help is available. - (2.1) Memory allocation is improved, so that the MS-DOS version will not prematurely abort when updating a large archive. - (2.1) The VAX/VMS version preserves file timestamps during extraction. - (2.1) The default archive-wide generation limit, when generations are enabled, is 3. FUTURE DIRECTIONS A revised version of zoo is in the works that will be able to write newly-created archives to standard output and will support multivolume archives. It will be upward and down- ward compatible with this version of zoo. ACKNOWLEDGEMENTS The zoo archiver was initially developed using Microsoft C 3.0 on a PC clone manufactured by Toshiba of Japan and almost sold by Xerox. Availability of the following systems was helpful in achieving portability: Paul Homchick's Compaq running Microport System V/AT; The Eskimo BBS somewhere in Oregon running Xenix/68000; Greg Laskin's system 'gryphon' which is an Intel 310 running Xenix/286; Ball State University's AT&T 3B2/300, UNIX PC, and VAX-11/785 (4.3BSD and VAX/VMS) systems. In addition J. Brian Waters provided feedback to help me make the code compilable on his Amiga using Manx/Aztec C. The executable version 2.0 for MS-DOS is currently compiled with Borland's Turbo C++ 1.0. Thanks are due to the following people and many others too numerous to mention. J. Brian Waters , who has worked diligently to port zoo to AmigaDOS, created Amiga-specific code, and continues keeping it updated. Paul Homchick , who provided numerous detailed reports about some nasty bugs. Bill Davidsen , who provided numerous improvements to this manual, contributed mul- tiscreen help, and provided many useful bug reports, bug fixes, code improvements, and suggestions. Mark Alexander , who provided me with some bug fixes. Haruhiko Okumura, who wrote the ar archiver and some excel- lent compression code, which I adapted for use in zoo. Randal L. Barnes , who (with Randy Magnuson) wrote the code to support the preservation of file timestamps under VAX/VMS. Raymond D. Gardner, who contributed replacement uncompres- sion code that on some systems is twice as fast as the original. Greg Yachuk and Andre Van Dalen, who independently modified MS-DOS zoo to support multivolume archives. (This support is not yet in this official release.) AUTHOR Rahul Dhesi zoo-2.10.orig/zooadd.c100644 1750 1750 63320 5035113600 13344 0ustar jamesjames#ifndef LINT /* derived from: zooadd.c 2.34 88/08/15 10:53:11 */ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zooadd.c,v $\n\ $Id: zooadd.c,v 1.10 91/07/08 23:48:39 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved (C) Copyright 1991 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Adds files specified in parameter-list to archive zoo_path. */ #define LONGEST 20 /* assumed length of longest filename */ #include "zoomem.h" /* to define MAXADD */ #include "zoo.h" #include "zooio.h" #include "various.h" #include "parse.h" #include "debug.h" #include "portable.h" #include "zoofns.h" #include "errors.i" extern int break_hit; extern int quiet; void show_comment PARMS ((struct direntry *, ZOOFILE, int, char *)); void dosname PARMS ((char *, char *)); void modpath PARMS ((char *)); void opts_add PARMS ((char *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *)); int ver_too_high PARMS ((struct zoo_header *)); void get_comment PARMS ((struct direntry *, ZOOFILE, char *)); void copyfields PARMS ((struct direntry *, struct tiny_header *)); void storefname PARMS ((struct direntry *, char *, int)); char *choosefname PARMS ((struct direntry *)); extern struct zoo_header zoo_header; extern char file_leader[]; extern unsigned int crccode; void zooadd(zoo_path, argc, argv, option) char *zoo_path; /* pathname of zoo archive to add to */ int argc; /* how many filespecs supplied */ char **argv; /* array of pointers to filespecs */ char *option; /* option string */ { char *whichname; /* which name to show user */ char **flist; /* list of ptrs to input fnames */ int fptr; /* will point to within flist */ ZOOFILE this_file; /* file to add */ char zoo_fname[LFNAMESIZE]; /* basename of archive itself */ char zoo_bak[LFNAMESIZE]; /* name of archive's backup */ char this_fname[LFNAMESIZE]; /* just filename of file to add */ char latest_name[LFNAMESIZE]; /* latest name in archive */ long last_old = 0L; /* last direntry in old chain */ ZOOFILE zoo_file; /* stream for open archive */ char *this_path; /* pathname of file to add */ #ifdef NOENUM #define NEW_ZOO 1 #define OLD_ZOO 2 int zoo_status; #else enum {NEW_ZOO, OLD_ZOO} zoo_status; /* newly created or not */ #endif long this_dir_offset; /* pointers to within archive */ long save_position; /* pointer to within archive */ long prev_pos; /* posn of prev file of same name */ struct direntry direntry; /* directory entry */ struct direntry dir2entry; /* spare */ int status; /* error status */ int success; /* successful addition of file? */ int addcount = 0; /* number added */ int update=0; /* only files already in archive */ int suppress=0; /* suppress compression */ int new=0; /* add only files not in archive */ int zootime = 0; /* just set archive time */ int add_comment = 0; /* add comment */ int add_global_comment = 0; /* archive comment */ int pack = 0; /* pack after adding */ int need_dir = 1; /* store directories too */ int delcount = 0; /* count of deleted entries */ int exit_status = 0; /* exit status to set */ unsigned int latest_date = 0; /* to set time on archive itself */ unsigned int latest_time = 0; /* .. same */ int move = 0; /* delete after adding to archive */ int longest; /* length of longest pathname added */ int firstfile = 1; /* first file being added? */ int z_fmt = 0; /* look for Z format files? */ int inargs = 0; /* read filenames from stdin? */ #ifndef PORTABLE struct tiny_header tiny_header; /* for Z format archives */ #endif unsigned this_version_no; /* version no. of old file */ unsigned high_vflag; /* version flag of old file */ unsigned high_version_no; /* highest version no of this file */ long high_pos; /* offset of file w/highest ver no */ unsigned int fgens; /* gens. to preserve -- file */ unsigned int zgens; /* gens. to preserve -- archive */ long oldcmtpos; /* to save old comment */ unsigned int oldcmtsiz; /* to save old comment */ int genson = 0; /* whether to turn generations on */ int use_lzh = 0; /* whether to use lzh compression */ /* on entry option points to first letter */ opts_add (option, &zootime, &quiet, &suppress, &move, &new, &pack, &update, &add_comment, &z_fmt, &need_dir, &inargs, &genson, &use_lzh, &add_global_comment); /* POSSIBLE RACE CONDITION BETWEEN TESTING EXISTENCE AND CREATING FILE */ if (exists (zoo_path)) { zoo_file = zooopen (zoo_path, Z_RDWR); zoo_status = OLD_ZOO; } else { if (!zootime) zoo_file = zoocreate (zoo_path); else zoo_file = NOFILE; /* don't create if just setting time */ zoo_status = NEW_ZOO; } if (zoo_file == NOFILE) prterror ('f', could_not_open, zoo_path); basename(zoo_path, zoo_fname); /* get basename of archive */ rootname (zoo_path, zoo_bak); /* name without extension */ strcat (zoo_bak, BACKUP_EXT); /* name of backup of this archive */ /* Now we prepare the archive for adding one or more files. If the archive has just been created, we write the archive header */ addfname ("",0L,0,0,0,0); /* initialize table of files already in archive */ if (zoo_status == NEW_ZOO) { /* newly-created archive */ if (genson) /* if no generations needed */ zoo_header.vdata = (VFL_ON|GEN_DEFAULT); /* generations on */ fwr_zooh (&zoo_header, zoo_file); zgens = GEN_DEFAULT; zooseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */ } else { /* read header and rewrite with updated version numbers, preserving header type */ rwheader (&zoo_header, zoo_file, 1); zgens = zoo_header.vdata & VFL_GEN; /* get archive generations */ /* initialize latest_name to null string */ /* NOTE: latest_name is not currently used for anything, but may be used in the future for inserting files into the archive in alphabetic order. */ *latest_name = '\0'; /* Skip existing files but add them to a list. The variable last_old gets the tail of the old chain of directory entries */ skip_files (zoo_file, &latest_date, &latest_time, &delcount, latest_name, &last_old); } /* The file pointer is now positioned correctly to add a file to archive, unless the null directory entry is too short. This will be fixed below. */ /* If we are just setting time, do it and run. */ if (zootime) { #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, latest_date, latest_time); #else settime (zoo_file, latest_date, latest_time); zooclose (zoo_file); #endif prterror ('m', "Archive time adjusted.\n"); zooexit (0); } /* make list of files, excluding archive and its backup */ longest = LONGEST; flist = (char **) ealloc(MAXADD); if (!inargs) { makelist(argc, argv, flist, MAXADD-2, zoo_fname, zoo_bak, ".", &longest); /* ^^ ^^ ^^ exclude */ } fptr = 0; /* ready to get filename (if makelist() was called) or to begin adding filenames (if reading them from stdin) */ while (1) { unsigned int this_date, this_time; int INLIST; /* boolean */ int RECENT; /* boolean */ int danger; /* if update requested and disk copy is out of date */ if (inargs) { again: /* loop back if filename was same as archive name or its backup */ this_path = getstdin(); /* pathname from stdin, in static area */ if (this_path != NULL) { if (samefile (nameptr(zoo_fname),nameptr(this_path)) || samefile (nameptr(zoo_bak),nameptr(this_path))) goto again; /* don't add archive to itself */ modpath (this_path); /* if moving files, add to list for later deletion; if list overflows, terminate addition loop and give warning message */ if (move) { if (fptr >= MAXADD-2) { prterror ('w', too_many_files, MAXADD-2); this_path = NULL; } else flist[fptr++] = str_dup (this_path); } } } else { this_path = flist[fptr++]; } /* exit the addition loop when no more pathnames are left */ if (this_path == NULL) { /* in case stdin was being read, make sure flist is NULL-terminated */ flist[fptr] = NULL; break; } basename (this_path, this_fname); /* get just filename for later */ this_file = zooopen(this_path, Z_READ); if (this_file == NOFILE) { prterror ('e', could_not_open, this_path); exit_status++; continue; } #ifndef PORTABLE /* Test to see if this is a Z format file. We assume the file is Z format if (a) tag is correct and (b) type is 1 and (c) embedded filename is not longer than FNAMESIZE. */ if (z_fmt) { zooread (this_file, (char *) &tiny_header, sizeof(tiny_header)); if (tiny_header.tinytag == TINYTAG && tiny_header.type == 1 && strlen (tiny_header.fname) <= FNAMESIZE) /* ok */ ; else { zooclose (this_file); prterror ('e', "File %s does not have Z format.\n", this_fname); exit_status++; continue; } } #endif /* get file time; also fix name */ #ifndef PORTABLE if (z_fmt) { direntry.date = tiny_header.date; direntry.time = tiny_header.time; strcpy (direntry.fname, tiny_header.fname); direntry.dirlen = direntry.namlen = 0; } else { #endif /* Get timstamp of file being added */ #ifdef GETUTIME getutime (this_path, &direntry.date, &direntry.time); #else gettime (this_file, &direntry.date, &direntry.time); #endif /* save file attributes */ #ifdef FATTR /* we expect getfattr() to set all attr. bits; currently only the portable format is recognized */ { # ifdef FATTR_FNAME unsigned long getfattr PARMS ((char *); direntry.fattr = getfattr (this_path); # else unsigned long getfattr PARMS ((ZOOFILE)); direntry.fattr = getfattr (this_file); # endif /* FATTR_FNAME */ } #else direntry.fattr = NO_FATTR; /* none */ #endif /* FATTR */ #ifdef FOLD str_lwr(this_fname); #endif dosname (this_fname, direntry.fname); /* MSDOS filename */ /* Store long filename into direntry.lfname iff it is different from MSDOS filename. Also store directory name if need_dir is true. Moved out of zooadd() so zooadd() doesn't get too big for optimization. */ storefname (&direntry, this_path, need_dir); #ifndef PORTABLE } #endif #ifdef DEBUG printf ("zooadd: direntry.lfname = [%s] direntry.dirname = [%s]\n", direntry.lfname, direntry.dirname); #endif /* if update option, then we add file if it is already in the archive AND the archived file is older */ /* The following logic was derived from a Karnaugh map so it may be hard to understand. Essentially, if U=update requested, N=new files requested, I=file is already in archive, and R=file being archived is more recent than file already in archive, then the boolean equation is: add = U' (N' + I') + U (IR + I'N) */ /* Get the filename to use for this addition. */ whichname = choosefname(&direntry); /* Get position in archive of any old file of same name, ignoring any directory prefix if need_dir is not true. Also get its date, time, version flag, and version number. */ prev_pos = inlist (fullpath (&direntry), &this_date, &this_time, &this_version_no, &high_vflag, &high_version_no, &high_pos, !need_dir); /* define DBG_INLIST for debugging by printing values returned by inlist() */ #ifdef DBG_INLIST printf ("FROM inlist(): prev_pos=%ld, high_pos=%ld\n", prev_pos, high_pos); printf ("this_version_no=%u, high_vflag=%4x, high_version_no=%u\n", this_version_no, high_vflag, high_version_no); #endif INLIST = prev_pos > 0; /* already in archive if positive value */ if (INLIST) { int result; result = cmpnum (direntry.date, direntry.time, this_date, this_time); RECENT = result > 0; danger = result < 0; } else danger = 0; /* And RECENT is undefined and should not be used */ if ( !update && (!new || !INLIST) || update && (INLIST && RECENT || !INLIST && new) ) ; /* then continue and add file */ else { if (update && danger) prterror ('w', "Archived copy of %s is newer.\n", whichname); zooclose (this_file); continue; /* cycle back, skip this file */ } #ifdef CHEKDIR /* Don't add if this is a directory */ if (isadir (this_file)) { zooclose (this_file); continue; } #else # ifdef CHEKUDIR /* Don't add if this is a directory */ if (isuadir (this_path)) { zooclose (this_file); continue; } # endif /* CHEKUDIR */ #endif /* CHEKDIR */ /* Create directory entry for new file (but don't add just yet) */ /* NOTE: we already got file date and time above for update option */ /* add tag, type, timezone, struc, system_id, and var_dir_len */ newdir (&direntry); if (!genson && zoo_status == NEW_ZOO || (zoo_header.vdata & VFL_ON) == 0) { direntry.vflag = 0; direntry.version_no = 0; } /* Write a null direntry entry. Thus, if an error occurs or the program is interrupted, the end of the archive will still be meaningful. Special check needed for first one written. */ direntry.next = direntry.offset = 0L; /* trailing null entry */ this_dir_offset = zootell (zoo_file); if (!firstfile) { writedir (&direntry, zoo_file); } else { /* Before adding the first file to the archive, we must make sure that the previous directory chain (if any) is properly terminated with a null entry of the right size. If this is a new archive, we simply write a new null entry of the right size. If this is an existing archive, we must check the size of the previous trailing null entry. If it is too small, we will back up to the most recent real directory entry and change its .next field to point to end of file. */ if (zoo_status == NEW_ZOO) { writedir (&direntry, zoo_file); /* write null dir entry */ } else { struct direntry tmpentry; long tmppos; int oldlen, newlen; tmppos = zootell (zoo_file); frd_dir (&tmpentry, zoo_file); #define DIRLEN(x) ((x.type<2) ? SIZ_DIR : (SIZ_DIRL+x.var_dir_len)) oldlen = DIRLEN(tmpentry); /* get length of direntry */ newlen = DIRLEN(direntry); /* ditto */ if (newlen > oldlen) { /* trouble */ zooseek (zoo_file, last_old, 0); /* back to previous entry */ frd_dir (&tmpentry, zoo_file); zooseek (zoo_file, 0L, 2); /* get EOF position */ tmpentry.next = zootell (zoo_file); /* point to EOF */ zooseek (zoo_file, last_old, 0); /* back to previous entry */ writedir (&tmpentry, zoo_file); /* update it */ zooseek (zoo_file, 0L, 2); /* to EOF ... */ this_dir_offset = zootell (zoo_file); writedir (&direntry, zoo_file); /* ...write null dir entry */ } else zooseek (zoo_file, tmppos, 0); /* long enough -- let it be */ } /* if (zoo_status == NEW_ZOO) ... */ } /* if (!firstfile) ... */ /* Now `this_dir_offset' is where the next directory entry will go */ /* first file added goes at EOF to avoid overwriting comments */ if (firstfile) { zooseek (zoo_file, 0L, 2); /* EOF */ direntry.offset = zootell (zoo_file) + SIZ_FLDR; } else { direntry.offset = this_dir_offset + SIZ_DIRL + direntry.var_dir_len + SIZ_FLDR; } if (use_lzh) { direntry.major_ver = MAJOR_LZH_VER; /* minimum version number needed */ direntry.minor_ver = MINOR_LZH_VER; /* .. to extract */ } else { direntry.major_ver = MAJOR_EXT_VER; /* minimum version number needed */ direntry.minor_ver = MINOR_EXT_VER; /* .. to extract */ } direntry.deleted = 0; /* not deleted, naturally */ direntry.comment = 0L; /* no comment (yet) */ direntry.cmt_size = 0; /* .. so no size either */ save_position = direntry.offset; /* save position in case of error */ (void) zooseek (zoo_file, direntry.offset - SIZ_FLDR, 0); (void) zoowrite (zoo_file, file_leader, SIZ_FLDR); #ifdef PORTABLE prterror ('m', "%-*s -- ", longest, this_path); #else if (z_fmt) prterror ('m', "%-12s <== %-*s -- ", direntry.fname, longest, this_path); else prterror ('m', "%-*s -- ", longest, this_path); #endif /* PORTABLE */ crccode = 0; #ifndef PORTABLE if (z_fmt) { direntry.packing_method = tiny_header.packing_method; zooseek (this_file, (long) (sizeof(tiny_header)+tiny_header.cmt_size), 0); status = getfile (this_file, zoo_file, tiny_header.size_now, 1); } else #endif if (suppress) { /* suppress compression */ direntry.packing_method = 0; /* no compression */ status = getfile (this_file, zoo_file, -1L, 1); } else { #ifdef UNBUF_IO /* unbuffered I/O */ long lseek PARMS ((int, long, int)); long tell PARMS ((int)); int this_fd, zoo_fd; #endif if (use_lzh) direntry.packing_method = 2; else direntry.packing_method = 1; #ifdef UNBUF_IO #include "UNBUF_IO not currently supported" this_fd = fileno (this_file); /* get .. */ zoo_fd = fileno (zoo_file); /* ... file descriptors */ zooseek (zoo_file, zootell (zoo_file), 0); /* synch */ zooseek (this_file, zootell (this_file), 0); /* synch */ status = lzc(this_fd, zoo_fd); /* add with compression */ zooseek (zoo_file, tell (zoo_fd), 0); /* resynch */ zooseek (this_file, tell (this_fd), 0); /* resynch */ #else if (use_lzh) status = lzh_encode(this_file, zoo_file); else status = lzc(this_file, zoo_file); #endif /* UNBUF_IO */ } if (status != 0) { /* if I */ ++exit_status; /* remember error */ if (status == 1) prterror ('F', no_memory); else if (status == 2) prterror ('F', disk_full); else if (status == 3) prterror ('F', "Read error.\n"); else prterror ('F', internal_error); success = 0; } else { direntry.next = zootell (zoo_file); direntry.size_now = direntry.next - direntry.offset; /* find and store original size of file just compressed */ /*DEBUG VMS*/ zooseek (this_file, 0L, 2); /* seek to EOF */ direntry.org_size = zootell (this_file); /* should be EOF already */ /* If the compressed one is bigger, just copy */ if (direntry.size_now >= direntry.org_size && /* if II */ direntry.packing_method != 0) { zooseek (zoo_file, save_position, 0); /* ..restore file pointer */ zootrunc (zoo_file); /* ..truncate file */ direntry.packing_method = 0; /* ..and just copy */ zooseek (this_file, 0L, 0); /* (but rewind first!) */ crccode = 0; /* re-start crc from 0 */ status = getfile (this_file, zoo_file, -1L, 1); if (status != 0) { /* if III */ success = 0; printf (disk_full); exit_status++; } else { success = 1; direntry.next = zootell (zoo_file); direntry.size_now = direntry.next - direntry.offset; } /* end if III */ } else { success = 1; } /* end if II */ } /* end if I */ if (success) { /* file successfully added */ addcount++; /* how many added */ direntry.file_crc = crccode; /* remember most recent date and time */ if (cmpnum (direntry.date,direntry.time,latest_date,latest_time) > 0) { latest_date = direntry.date; latest_time = direntry.time; } #if 0 /* mark any previous version of this file in archive as deleted */ dir2entry.comment = 0L; /* for later use assigning to direntry */ dir2entry.cmt_size = 0; #endif if (!z_fmt) prterror ('M', " (%2d%%) ", cfactor (direntry.org_size, direntry.size_now)); oldcmtsiz = 0; /* assume no old comment */ oldcmtpos = 0L; if (prev_pos > 0) { /* in archive */ int delold = 0; /* delete old? */ /* if versions active both archive-wide and for file */ if ((zoo_header.vdata & VFL_ON) && (high_vflag & VFL_ON)) { /* next test is optimization, to avoid redundant I/O */ if (high_pos != prev_pos || this_version_no == 1) { /* prev highest is no longer highest so adjust vflag */ long save_pos = zootell (zoo_file); /*DEBUG*/ zooseek (zoo_file, high_pos, 0); readdir (&dir2entry, zoo_file, 1); oldcmtpos = dir2entry.comment; oldcmtsiz = dir2entry.cmt_size; dir2entry.vflag &= (~VFL_LAST); /* no longer highest */ zooseek (zoo_file, high_pos, 0); writedir (&dir2entry, zoo_file); zooseek (zoo_file, save_pos, 0); /*DEBUG*/ } direntry.version_no = high_version_no + 1; /* ..one higher */ direntry.vflag = high_vflag; /* now see if we need to delete older version */ fgens = high_vflag & VFL_GEN; if (fgens == 0) fgens = zgens; if (zgens != 0 && zgens < fgens) fgens = zgens; if (fgens != 0 && direntry.version_no - this_version_no >= fgens) { delold = 1; prterror ('M', "replaced+\n"); } else prterror ('M', "added+\n"); } else { prterror ('M', "replaced\n"); delold = 1; } if (delold) { /* deleting old file */ long save_pos = zootell (zoo_file); /*DEBUG*/ ++delcount; /* remember to pack */ zooseek (zoo_file, prev_pos, 0); readdir (&dir2entry, zoo_file, 1); if (dir2entry.cmt_size != 0) { /* propagate latest comment */ oldcmtpos = dir2entry.comment; oldcmtsiz = dir2entry.cmt_size; } dir2entry.deleted = 1; /* mark as deleted */ /* following line is optimization if only 1 generation */ dir2entry.vflag &= (~VFL_LAST); /* no longer highest */ zooseek (zoo_file, prev_pos, 0); writedir (&dir2entry, zoo_file); zooseek (zoo_file, save_pos, 0); /*DEBUG*/ } } else /* not in archive */ prterror ('M', "added\n"); /* Preserve any old comment if we replaced or superseded the file */ direntry.comment = oldcmtpos; direntry.cmt_size = oldcmtsiz; #ifndef PORTABLE /* Copy comment if any from Z format file */ if (z_fmt && tiny_header.cmt_size != 0) { zooseek (this_file, (long) sizeof(tiny_header), 0); /* to comment */ direntry.comment = zootell (zoo_file); direntry.cmt_size = tiny_header.cmt_size; /* 4th param is 0 for no CRC */ getfile (this_file, zoo_file, (long) tiny_header.cmt_size, 0); direntry.next = zootell (zoo_file); } #endif /* if user requested comments, any previous comment in a Z format file may now be manually overwritten */ if (add_comment && !feof (stdin)) { show_comment (&direntry, zoo_file, 1, whichname); get_comment (&direntry, zoo_file, this_path); direntry.next = zootell (zoo_file); /* update .next ptr */ } /* end if */ #ifndef PORTABLE /* if adding Z format archive, copy relevant fields from its header */ if (z_fmt) { /* moved out to shorten code & allow optimizer to work */ copyfields (&direntry, &tiny_header); } #endif debug((printf ("zooadd: our new .next = [%lx].\n", direntry.next))) { long savepos = zootell (zoo_file); /* save position */ zooseek (zoo_file, this_dir_offset, 0); writedir (&direntry, zoo_file); zooseek (zoo_file, savepos, 0); /* restore position */ } } else { /* file was not properly added */ zooseek (zoo_file, save_position, 0); /* ..restore file pointer */ zootrunc (zoo_file); /* ..truncate file */ } /* end if */ zooclose (this_file); if (!success) break; firstfile = 0; } /* end for */ save_position = zootell (zoo_file); /* Write a null direntry entry */ zooseek (zoo_file, save_position, 0); writenull (zoo_file, MAXDIRSIZE); zootrunc (zoo_file); /* truncate */ #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, latest_date, latest_time); #else settime (zoo_file, latest_date, latest_time); zooclose (zoo_file); #endif if (!addcount) { /* no files added */ prterror ('m', "No files added.\n"); if (zoo_status == NEW_ZOO) unlink (zoo_path); } else { if (delcount && pack) { /* pack if user asked and found deleted entries */ prterror ('M', "-----\nPacking..."); zoopack (zoo_path, "PP"); prterror ('M', "done\n"); } /* If files to move & we added some and no error so far, delete originals */ if (move && !exit_status) if (kill_files (flist, longest) != 0) exit_status++; } /* right here we handle archive comment */ if (add_global_comment) { comment(zoo_path, "_A"); add_global_comment = 0; } if (exit_status) zooexit (1); } /* end zoo_add */ zoo-2.10.orig/zooadd2.c100644 1750 1750 21066 5035113600 13427 0ustar jamesjames#ifndef LINT /* derived from: zooadd2.c 2.14 88/01/27 10:40:32 */ static char sccsid[]="$Id: zooadd2.c,v 1.5 91/07/04 13:33:55 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "zoo.h" #ifndef OK_STDIO #include #define OK_STDIO #endif #include "various.h" #include "zooio.h" #include "zoofns.h" #include "errors.i" #include "assert.h" #include "debug.h" #include "parse.h" /* Miscellaneous routines to support zooadd(). */ /**************** This function is called with zoo_file positioned to the first directory entry in an archive. It skips past all existing files, counts the number of deleted files, saves the latest data and time encountered, and adds all filenames encountered to a global list. The long filename is added if available, else the MSDOS filename is added. */ void skip_files (zoo_file, latest_date, latest_time, delcount, latest_name, latest_pos) ZOOFILE zoo_file; unsigned int *latest_date, *latest_time; int *delcount; char latest_name[]; long *latest_pos; { long save_offset, next_ptr; struct direntry direntry; struct direntry *drp = &direntry; *latest_pos = 0L; do { /* read a directory entry */ save_offset = zootell (zoo_file); /* save pos'n of this dir entry */ readdir (&direntry, zoo_file, 1); /* read directory entry */ if (drp->next == 0L) { /* END OF CHAIN */ zooseek (zoo_file, save_offset, 0); /* back up */ break; /* EXIT on end of chain */ } else *latest_pos = save_offset; /* remember most recent date and time, for files not marked deleted */ if (!drp->deleted) if (drp->date > *latest_date || (drp->date == *latest_date && drp->time > *latest_time)) { *latest_date = drp->date; *latest_time = drp->time; } next_ptr = drp->next; /* ptr to next dir entry */ if (drp->deleted) ++(*delcount); /* count deleted entries */ /* add name of file and position of direntry into global list */ /* but only if the entry is not deleted */ if (!drp->deleted) { #ifdef FOLD /* IS THIS REALLY NEEDED? IF SO, WHAT ABOUT drp->lfname? */ str_lwr(drp->fname); #endif /* add full pathname to global list */ strcpy (latest_name, fullpath (drp)); addfname (latest_name, save_offset, drp->date, drp->time, drp->vflag, drp->version_no); } zooseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */ } while (next_ptr != 0L); /* loop terminates on null ptr */ } /*******************/ /* kill_files() deletes all files in the supplied list of pointers to filenames */ int kill_files (flist, pathlength) char *flist[]; /* list of ptrs to input fnames */ int pathlength; /* length of longest pathname */ { int status = 0; int fptr; prterror ('M', "-----\nErasing added files...\n"); for (fptr = 0; flist[fptr] != NULL; fptr++) { #ifdef CHEKUDIR if (isuadir(flist[fptr])) continue; #else /* CHEKUDIR */ # ifdef CHEKDIR if (isfdir(flist[fptr])) continue; # endif /* CHEKDIR */ #endif /* CHEKUDIR */ prterror ('m', "%-*s -- ", pathlength, flist[fptr]); if (unlink (flist[fptr]) == 0) { prterror ('M', "erased\n"); } else { prterror ('w', "Could not erase %s.\n", flist[fptr]); status = 1; } } return (status); } #ifndef PORTABLE /*******************/ void copyfields (drp, thp) struct direntry *drp; struct tiny_header *thp; { drp->org_size = thp->org_size; drp->file_crc = thp->file_crc; drp->size_now = thp->size_now; drp->major_ver = thp->major_ver; drp->minor_ver = thp->minor_ver; } #endif /*******************/ /* processes option switches for zooadd() */ void opts_add (option, zootime, quiet, suppress, move, new, pack, update, add_comment, z_fmt, need_dir, inargs, genson, use_lzh, arch_cmnt) char *option; int *zootime, *quiet, *suppress, *move, *new, *pack, *update, *add_comment, *z_fmt, *need_dir, *inargs, *genson, *use_lzh, *arch_cmnt; { if (*option == 'T') { (*zootime)++; option++; while (*option) { switch (*option) { case 'q': (*quiet)++; break; default: prterror ('f', inv_option, *option); } option++; } } while (*option) { switch (*option) { case 'a': break; case 'h': (*use_lzh)++; break; /* use lzh compression */ case 'f': (*suppress)++; break; /* suppress compression */ case 'M': (*move)++; break; /* delete files after adding them */ case 'n': (*new)++; break; /* add only files not in archive */ case 'P': (*pack)++; break; /* pack after adding */ case 'u': (*update)++; break; /* add only files already in archive */ case 'q': (*quiet)++; break; /* be quiet */ case 'c': (*add_comment)++; break; /* add comment */ case ':': *need_dir = 0; break; /* don't store directories */ case 'I': (*inargs)++; break; /* get filenames from stdin */ case 'C': (*arch_cmnt)++; break; /* do an archive comment */ /* #ifdef PORTABLE */ /* avoid Turbo C warning about unused param */ case 'z': (*z_fmt)++; break; /* look for Z format files */ /* #endif */ case '+': *genson = 1; break; case '-': *genson = 0; break; default: prterror ('f', inv_option, *option); } option++; } /* end while */ if (*suppress && *use_lzh) prterror ('f', "\"f\" and \"h\" can't both be used\n"); } /* Stores long filename into direntry.lfname iff it is different from MSDOS filename. Also stores directory name if need_dir is true. Moved out of zooadd() so zooadd() doesn't get too big for optimization. */ void storefname (direntry, this_path, need_dir) struct direntry *direntry; char *this_path; int need_dir; { struct path_st path_st; parse (&path_st, this_path); direntry->lfname[0] = '\0'; direntry->namlen = 0; #ifdef SPECMOD specfname (path_st.lfname); specdir (path_st.dir); #endif if (strcmp(path_st.lfname,direntry->fname) != 0) { strcpy (direntry->lfname, path_st.lfname); /* full filename */ direntry->namlen = strlen(direntry->lfname) + 1; } if (need_dir) { strcpy (direntry->dirname, path_st.dir); /* directory name */ direntry->dirlen = strlen(direntry->dirname) + 1; if (direntry->dirlen == 1) /* don't store trailing null alone */ direntry->dirlen = 0; } else { direntry->dirname[0] = '\0'; direntry->dirlen = 0; } } /* Function getsdtin() gets a pathname from standard input, cleans it if necessary by removing any following blanks/tabs and other junk, and returns it in a static area that is overwritten by each call. */ char *getstdin() { char *chptr; /* temp pointer */ static char tempname[PATHSIZE]; do { if (fgets (tempname, PATHSIZE, stdin) == NULL) return (NULL); /* remove trailing blank, tab, newline */ for (chptr = tempname; *chptr != '\0'; chptr++) { if ( /* PURIFY means remove trailing blanks/tabs and all subsequent chars */ #ifdef PURIFY *chptr == '\t' || *chptr == ' ' || #endif *chptr == '\n' /* always remove trailing \n */ ) { *chptr = '\0'; break; } } } while (*tempname == '\0'); /* get a nonempty line */ #ifdef FOLD str_lwr (tempname); #endif return (tempname); } /* Function newdir() adds some default information to a directory entry. This will be a new directory entry added to an archive. */ void newdir (direntry) register struct direntry *direntry; { #ifdef GETTZ long gettz(); #endif direntry->zoo_tag = ZOO_TAG; direntry->type = 2; /* type is now 2 */ #ifdef GETTZ direntry->tz = (uchar) (gettz() / (15 * 60)); /* seconds => 15-min units */ #else direntry->tz = NO_TZ; /* timezone unknown */ #endif direntry->struc = 0; /* unstructured file */ direntry->system_id = SYSID_NIX; /* identify **IX filesystem */ direntry->vflag = VFL_ON|VFL_LAST; /* latest version */ direntry->version_no = 1; /* begin with version 1 */ /* 1 for namlen, 1 for dirlen, 2 for system id, 3 for attributes, 1 for version flag and 2 for version number */ direntry->var_dir_len = direntry->dirlen + direntry->namlen + 10; } zoo-2.10.orig/zoodel.c100644 1750 1750 22714 5035113600 13362 0ustar jamesjames#ifndef LINT /* @(#) zoodel.c 2.19 88/02/06 21:23:36 */ /*$Source: /usr/home/dhesi/zoo/RCS/zoodel.c,v $*/ /*$Id: zoodel.c,v 1.4 91/07/09 01:54:11 dhesi Exp $*/ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zoodel.c,v $\n\ $Id: zoodel.c,v 1.4 91/07/09 01:54:11 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Deletes or undeletes entries from an archive. choice=1 requests deletion and choice=0 requests undeletion. */ #include "zoo.h" #include "portable.h" #ifndef OK_STDIO #include #define OK_STDIO #endif #include "various.h" /* may not be needed */ #include "zooio.h" #include "zoofns.h" #include "errors.i" #ifndef NOSIGNAL #include #endif int needed PARMS((char *, struct direntry *, struct zoo_header *)); int ver_too_high PARMS((struct zoo_header *)); extern int quiet; void zoodel (zoo_path, option, choice) char *zoo_path; char *option; int choice; { #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); /* to save previous SIGINT handler */ #endif int delcount = 0; /* how many entries we [un]deleted */ char matchname[PATHSIZE]; /* will hold full pathname */ register ZOOFILE zoo_file; struct zoo_header zoo_header; struct direntry direntry; unsigned int latest_date = 0; /* so we can set time of archive later */ unsigned int latest_time = 0; int pack = 0; /* pack after deletion? */ int file_deleted = 0; /* any files deleted? */ int one = 0; /* del/undel one file only */ int done; /* loop control */ int action; /* delete/undelete or adjust generation */ int subopt; /* sub option to action */ long gencount; /* generation count */ int doarchive = 0; /* whether to adjust archive gen count */ unsigned valtoshow; /* value to show in informative message */ int dodel = 0; /* selection of deleted files */ int selected; /* if current direntry selected */ /* values for action */ #define NO_ACTION 0 /* nothing */ #define DEL_UNDEL 1 /* delete or undelete file */ #define ADJ_LIM 2 /* adjust generation limit */ #define ADJ_GCNT 3 /* adjust generation count */ #define GEN_ON 4 /* turn on generations */ #define GEN_OFF 5 /* turn off generations */ /* values for subopt */ #define SET 0 #define INC 1 action = NO_ACTION; if (*option == 'g') { while (*(++option)) { switch (*option) { case 'A': doarchive = 1; break; case 'q': quiet++; break; case 'l': action = ADJ_LIM; break; case 'c': action = ADJ_GCNT; break; case '=': subopt = SET; gencount = calc_ofs (++option); if (action == ADJ_GCNT && gencount == 0) prterror ('f', "Generation count must be nonzero.\n"); goto opts_done; case '+': if (action == NO_ACTION) { if (option[1] =='\0') { action = GEN_ON; goto opts_done; } else prterror ('f', garbled); } else { subopt = INC; gencount = calc_ofs (++option); goto opts_done; } case '-': if (action == NO_ACTION) { if (option[1] =='\0') { action = GEN_OFF; goto opts_done; } else prterror ('f', garbled); } else { subopt = INC; gencount = - calc_ofs (++option); goto opts_done; } case 'd': dodel++; break; default: prterror ('f', garbled); } /* end switch */ } /* end while */ /* if normal exit from while loop, it means bad command string */ prterror ('f', garbled); opts_done: /* jump here from exit in while loop above */ if (action == NO_ACTION) prterror ('f', garbled); } else { action = DEL_UNDEL; while (*(++option)) { switch (*option) { case 'P': pack++; break; /* pack after adding */ case 'q': quiet++; break; /* be quiet */ case '1': one++; break; /* del or undel only one file */ default: prterror ('f', inv_option, *option); } } /* end while */ } /* Open archive for read/write/binary access. It must already exist */ if ((zoo_file = zooopen (zoo_path, Z_RDWR)) == NOFILE) { prterror ('f', could_not_open, zoo_path); } /* read archive header */ frd_zooh (&zoo_header, zoo_file); if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L) prterror ('f', failed_consistency); if (ver_too_high (&zoo_header)) prterror ('f', wrong_version, zoo_header.major_ver, zoo_header.minor_ver); if (doarchive) { /* manipulate archive gen val */ unsigned zoo_date, zoo_time; #ifdef GETUTIME getutime (zoo_path, &zoo_date, &zoo_time); /* save archive timestamp */ #else gettime (zoo_file, &zoo_date, &zoo_time); #endif if (zoo_header.type == 0) prterror ('f', packfirst); if (action == ADJ_LIM) { unsigned newgencount; if (subopt == SET) newgencount = (unsigned) gencount; else /* INC */ newgencount = (zoo_header.vdata & VFL_GEN) + (unsigned) gencount; newgencount &= VFL_GEN; /* reduce to allowed bits */ zoo_header.vdata &= (~VFL_GEN); zoo_header.vdata |= newgencount; prterror ('M', "Archive generation limit is now %u\n", newgencount); } else if (action == GEN_ON) { zoo_header.vdata |= VFL_ON; prterror ('M', "Archive generations on\n"); } else if (action == GEN_OFF) { zoo_header.vdata &= (~VFL_ON); prterror ('M', "Archive generations off\n"); } else prterror ('f', garbled); zooseek (zoo_file, 0L, 0); /* back to begining of file */ fwr_zooh (&zoo_header, zoo_file); #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, zoo_date, zoo_time); /* restore archive timestamp */ #else settime (zoo_file, zoo_date, zoo_time); zooclose (zoo_file); #endif return; } zooseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */ done = 0; /* loop not done yet */ while (1) { long this_dir_offset; this_dir_offset = zootell (zoo_file); /* save pos'n of this dir entry */ frd_dir (&direntry, zoo_file); if (direntry.zoo_tag != ZOO_TAG) { prterror ('f', bad_directory); } if (direntry.next == 0L) { /* END OF CHAIN */ break; /* EXIT on end of chain */ } /* select directory entry if it matches criteria */ selected = ( (action == DEL_UNDEL && direntry.deleted != choice) || (action != DEL_UNDEL && (dodel && direntry.deleted || (dodel < 2 && !direntry.deleted)) ) ); /* WARNING: convention of choice=1 for deleted entry must be same as in direntry definition in zoo.h */ /* Test for "done" so if "one" option requested, [un]del only 1 file */ /* But we go through the whole archive to adjust archive time */ strcpy (matchname, fullpath (&direntry)); /* get full pathname */ if (zoo_header.vdata & VFL_ON) add_version (matchname, &direntry); /* add version suffix */ if (!done && selected && needed(matchname, &direntry, &zoo_header)) { prterror ('m', "%-14s -- ", matchname); delcount++; if (action == DEL_UNDEL) { direntry.deleted = choice; if (choice) file_deleted++; /* remember if any files actually deleted */ } else { /* ADJ_LIM or ADJ_GENCNT */ if (direntry.vflag & VFL_ON) { /* skip if no versions */ if (action == ADJ_LIM) { unsigned newgencount; if (subopt == SET) newgencount = (unsigned) gencount; else /* INC */ newgencount = (int) (direntry.vflag & VFL_GEN) + (int) gencount; newgencount &= VFL_GEN; direntry.vflag &= (~VFL_GEN); direntry.vflag |= newgencount; valtoshow = newgencount; } else { /* ADJ_GCNT */ if (subopt == SET) direntry.version_no = (unsigned) gencount; else /* INC */ direntry.version_no += (int) gencount; direntry.version_no &= VER_MASK; /* avoid extra bits */ valtoshow = direntry.version_no; } } } zooseek (zoo_file, this_dir_offset, 0); #ifndef NOSIGNAL oldsignal = signal (SIGINT, SIG_IGN); /* disable ^C for write */ #endif if (fwr_dir (&direntry, zoo_file) == -1) prterror ('f', "Could not write to archive\n"); #ifndef NOSIGNAL signal (SIGINT, oldsignal); #endif if (action == DEL_UNDEL) prterror ('M', choice ? "deleted\n" : "undeleted\n"); else { if (direntry.vflag & VFL_ON) prterror ('M', "adjusted to %u\n", valtoshow); else prterror ('M', "no generations\n"); } if (one) done = 1; /* if 1 option, done after 1 file */ } /* remember most recent date and time if entry is not deleted */ if (!direntry.deleted) if (direntry.date > latest_date || (direntry.date == latest_date && direntry.time > latest_time)) { latest_date = direntry.date; latest_time = direntry.time; } zooseek (zoo_file, direntry.next, 0); /* ..seek to next dir entry */ } /* endwhile */ if (!delcount) printf ("Zoo: No files matched.\n"); else { #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, latest_date, latest_time); #else #if 0 fflush (zoo_file); /* superstition: might help time stamp */ #endif settime (zoo_file, latest_date, latest_time); #endif } #ifndef NIXTIME zooclose (zoo_file); #endif if (file_deleted && pack) { /* pack if files were deleted and user asked */ prterror ('M', "-----\nPacking..."); zoopack (zoo_path, "PP"); prterror ('M', "done\n"); } } zoo-2.10.orig/zooext.c100644 1750 1750 53277 5035113600 13426 0ustar jamesjames#ifndef LINT /* derived from: zooext.c 2.21 88/08/24 02:39:04 */ /*$Source: /usr/home/dhesi/zoo/RCS/zooext.c,v $*/ /*$Id: zooext.c,v 1.9 91/07/09 01:54:13 dhesi Exp $*/ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zooext.c,v $\n\ $Id: zooext.c,v 1.9 91/07/09 01:54:13 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved (C) Copyright 1991 Rahul Dhesi -- All rights reserved */ /* Extract file from archive. Extracts files specified in parameter-list from archive zoo_path. If none specified, extracts all files from archive. */ #include "options.h" #include "zoo.h" #include "parse.h" /* defines struct for parse() */ #include "portable.h" /* portable I/O definitions */ #include "machine.h" /* machine-specific declarations */ #include "zooio.h" #include "various.h" #ifndef NOSIGNAL #include #endif #include "zoofns.h" #ifdef MODE_BIN /* will need fileno() from stdio.h */ # include #endif void makepath PARMS((char *)); int needed PARMS((char *, struct direntry *, struct zoo_header *)); void putstr PARMS((char *)); #ifdef FATTR int setfattr PARMS ((char *, unsigned long)); #endif /* FATTR */ extern int quiet; #include "errors.i" /* Following two are used by ctrl_c() also, hence declared here */ char extfname[LFNAMESIZE]; /* filename of extracted file */ char prtfname[LFNAMESIZE]; /* name of extracted file on screen */ static ZOOFILE this_file; /* file to extract */ static int tofile; /* true if not pipe or null device */ extern unsigned int crccode; extern char *out_buf_adr; /* address of output buffer */ void zooext(zoo_path, option) char *zoo_path, *option; { char *whichname; /* which name to extract */ char matchname[PATHSIZE]; /* for pattern matching only */ #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); /* to save previous SIGINT handler */ #endif ZOOFILE zoo_file; /* open archive */ long next_ptr; /* pointer to within archive */ struct zoo_header zoo_header; /* header for archive */ int status; /* error status */ int exit_status = 0; /* exit status */ int error_message; /* Whether to give error message */ unsigned long disk_space; /* disk space left */ int matched = 0; /* Any files matched? */ int overwrite = 0; /* force overwrite of files? */ int supersede = 0; /* supersede newer files? */ int needdel = 0; /* extract deleted files too */ int usepath = 2; /* use path for extraction */ int todot = 0; /* extract relative to . */ int badcrc_count = 0; /* how many files with bad CRC */ int bad_header = 0; /* to avoid spurious messages later */ long fiz_ofs = 0; /* offset where to start */ long dat_ofs = 0; /* .. and offset of file data */ int pipe = 0; /* are we piping output? */ int null_device = 0; /* are we sending to null device? */ #ifndef PORTABLE int fast_ext = 0; /* fast extract as *.?Z? */ int alloc_size; /* disk allocation unit size */ #endif struct direntry direntry; /* directory entry */ int first_dir = 1; /* first dir entry seen? */ static char extract_ver[] = "Zoo %d.%d is needed to extract %s.\n"; static char no_space[] = "Insufficient disk space to extract %s.\n"; while (*option) { switch (*option) { #ifndef PORTABLE case 'z': fast_ext++; break; #endif case 'x': case 'e': break; case 'N': null_device++; break; case 'O': overwrite += 2; break; case 'o': overwrite++; break; case 'p': pipe++; break; case 'S': supersede++; break; case 'd': needdel++; break; case 'q': quiet++; break; case ':': usepath = 0; break; case '/': usepath++; break; case '.': todot++; break; case '@': /* if @m,n specified, fiz_ofs = m, dat_ofs = n */ { char *comma_pos; ++option; comma_pos = strchr(option, ','); if (comma_pos != NULL) { dat_ofs = calc_ofs (comma_pos + 1); *comma_pos = '\0'; } fiz_ofs = calc_ofs(option); goto no_more; } default: prterror ('f', inv_option, *option); /* break; */ } option++; } no_more: /* come from exit in while loop above */ if (overwrite == 1) /* must be at least 2 to begin with */ overwrite--; if (null_device && pipe) { prterror ('f', inv_option, 'p'); pipe = 0; } if (overwrite && pipe) prterror ('w', option_ignored, 'O'); #ifndef PORTABLE if (null_device && fast_ext) { prterror ('w', inv_option, 'N'); null_device = 0; } #endif tofile = !pipe && !null_device; /* sending to actual file */ zoo_file = zooopen(zoo_path, Z_READ); if (zoo_file == NOFILE) prterror ('f', could_not_open, zoo_path); if (fiz_ofs != 0L) { /* if offset specified, start there */ prterror ('m', start_ofs, fiz_ofs, dat_ofs); zooseek (zoo_file, fiz_ofs, 0); } else { /* read header */ frd_zooh (&zoo_header, zoo_file); if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L) { prterror ('w', failed_consistency); bad_header++; exit_status = 1; } zooseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */ } #ifndef PORTABLE disk_space = space (0, &alloc_size); /* remember disk space left */ #else disk_space = MAXLONG; /* infinite disk space */ #endif /* if piping output we open the output device just once */ if (null_device) { this_file = NULLFILE; } else if (pipe) this_file = STDOUT; /* standard output */ while (1) { frd_dir (&direntry, zoo_file); if (direntry.zoo_tag != ZOO_TAG) { long currpos, zoolength; prterror ('F', invalid_header); /* Note: if header was bad, there's no point trying to find how many more bytes aren't processed -- our seek position is likely very wrong */ if (!bad_header) if ((currpos = zootell (zoo_file)) != -1L) if (zooseek (zoo_file, 0L, 2) != -1) if ((zoolength = zootell (zoo_file)) != -1L) printf (cant_process, zoolength - currpos); zooexit (1); } if (direntry.next == 0L) { /* END OF CHAIN */ break; /* EXIT on end of chain */ } /* when first direntry read, change dat_ofs from abs. pos. to rel. offset */ if (first_dir && dat_ofs != 0) { dat_ofs -= direntry.offset; first_dir = 0; } next_ptr = direntry.next + dat_ofs; /* ptr to next dir entry */ whichname = choosefname(&direntry); /* which filename */ whichname = str_dup(whichname); /* bug fix */ fixfname(whichname); /* fix syntax */ strcpy (matchname, fullpath (&direntry)); /* get full pathname */ if (zoo_header.vdata & VFL_ON) add_version (matchname, &direntry); /* add version suffix */ /* if extraction to subtree rooted at curr dir, modify pathname */ #if 0 #ifdef DIR_LBRACK if (todot && direntry.dirname[0] == *DIR_LBRACK && direntry.dirname[1] != *CUR_DIR) { char tmpstr[PATHSIZE]; strcpy (tmpstr, DIR_LBRACK); strcat (tmpstr, CUR_DIR); strcat (tmpstr, &direntry.dirname[1]); strcpy (direntry.dirname, tmpstr); } #endif #endif /* hard-coded '/' should be eventually removed */ if (todot && *direntry.dirname == '/') { char tmpstr[PATHSIZE]; strcpy(tmpstr, direntry.dirname); strcpy(direntry.dirname,CUR_DIR); strcat(direntry.dirname, tmpstr); } /* matchname now holds the full pathname for pattern matching */ if ( ( (needdel && direntry.deleted) || (needdel < 2 && !direntry.deleted) ) && needed(matchname, &direntry, &zoo_header)) { matched++; /* update count of files extracted */ if (direntry.major_ver > MAJOR_LZH_VER || (direntry.major_ver == MAJOR_LZH_VER && direntry.minor_ver > MINOR_LZH_VER)) { prterror ('e', extract_ver, direntry.major_ver, direntry.minor_ver, whichname); exit_status = 1; goto loop_again; } /* If extracting to null device, or if user requested extraction of entire path, include any directory name in filename. If extraction to current directory requested, and if extfname begins with path separator, fix it */ strcpy (extfname, whichname); if ((usepath || null_device) && direntry.dirlen != 0) { combine(extfname, direntry.dirname, whichname); if (usepath > 1 && !null_device) makepath(direntry.dirname); /* make dir prefix */ } strcpy(prtfname, extfname); if (zoo_header.vdata & VFL_ON) add_version (prtfname, &direntry); if (tofile) { int present = 0; #ifndef PORTABLE /* if Z format (fast) extraction, extension is created as follows: for no current extension, new extension is "zzz"; for current extension "a", new extension is "azz"; for current extension "ab", new extension is "azb"; and for current extension "abc", new extension is "azc". */ if (fast_ext) { int length; struct path_st path_st; parse (&path_st, extfname); /* split filename */ strcpy (extfname, path_st.fname); /* just root filename */ length = strlen (path_st.ext); strcat (extfname, "."); if (length == 0) strcat (extfname, "zzz"); /* no ext -> .zzz */ else if (length == 1) { strcat (extfname, path_st.ext); strcat (extfname, "zz"); /* *.? -> *.?zz */ } else { /* length is 2 or 3 */ if (length == 2) /* allow .aa, .ab, etc. */ path_st.ext[2] = path_st.ext[1]; path_st.ext[1] = 'z'; strcat (extfname, path_st.ext); /* *.?? -> *.?z? */ } strcpy(prtfname, direntry.fname); add_version (prtfname, &direntry); } #endif /* ifndef PORTABLE */ /* don't extract if archived file is older than disk copy */ if (!supersede && exists(extfname)) { unsigned int ddate, dtime; #ifdef GETUTIME getutime (extfname, &ddate, &dtime); #else ZOOFILE tfile; ddate = dtime = 0xffff; /* assume maximum */ tfile = zooopen(extfname, Z_READ); if (tfile == NOFILE) goto loop_again; gettime (tfile, &ddate, &dtime); zooclose (tfile); #endif if (cmpnum (direntry.date, direntry.time, ddate, dtime) <= 0) { prterror ('m', "%-14s -- skipped\n", prtfname); goto loop_again; } } if (overwrite) { this_file = zoocreate (extfname); #ifdef FATTR /* if can't open file, and OO option, make it writable first */ if (this_file == NOFILE && overwrite >= 4 && (direntry.fattr >> 22) == 1 && exists(extfname)) { setfattr (extfname, (unsigned long) (1L << 7) | direntry.fattr); this_file = zoocreate (extfname); } #endif /* FATTR */ } else { if (exists (extfname)) { present = 1; this_file = NOFILE; } else this_file = zoocreate (extfname); } error_message = 1; if (this_file == NOFILE) { if (present == 1) { /* if file exists already */ char ans[20]; /* answer to "Overwrite?" */ do { #ifdef EXT_ANYWAY printf ("%s exists; extract anyway? [Yes/No/All] ", extfname); #else printf ("Overwrite %s (Yes/No/All)? ", extfname); #endif fflush (stdin); fgets (ans, sizeof(ans), stdin); str_lwr (ans); } while (*ans != 'y' && *ans != 'n' && *ans != 'a'); if (*ans == 'a') overwrite++; if (*ans == 'y' || *ans == 'a') { this_file = zoocreate(extfname); error_message = 1; /* give error message if open fails */ } else { error_message = 0; /* user said 'n', so no error message */ } } else { error_message = 1; /* Real error -- give error message */ } } /* end if */ } /* end if */ if (this_file == NOFILE) { /* file couldn't be opened */ if (error_message == 1) { prterror ('e', "Can't open %s for output.\n", extfname); exit_status = 1; #ifndef PORTABLE /* if error was due to full disk, abort */ if (space(0, &alloc_size) < alloc_size) prterror ('f', disk_full); #endif } } else if (zooseek (zoo_file, (direntry.offset + dat_ofs), 0) == -1L) { prterror ('e', "Could not seek to file data.\n"); exit_status = 1; close_file (this_file); } else { #ifndef PORTABLE /* check msdos's free disk space if we seem to be running low (within 1 cluster of being full) */ if (tofile && disk_space < direntry.org_size + alloc_size) { disk_space = space (0, &alloc_size); if (disk_space < alloc_size) { close_file (this_file); unlink (extfname); prterror ('f', disk_full); } } #endif if (tofile && disk_space < direntry.org_size) { #ifdef PORTABLE ; #else prterror ('e', no_space, prtfname); unlink (extfname); /* delete any created file */ #endif /* portable */ } else { #ifndef PORTABLE if (fast_ext) { /* fast ext -> create header */ void make_tnh PARMS((struct tiny_header *, struct direntry *)); struct tiny_header tiny_header; make_tnh(&tiny_header, &direntry); zoowrite (this_file, (char *) &tiny_header, sizeof(tiny_header)); if (direntry.cmt_size != 0) { /* copy comment */ long save_pos; save_pos = zootell (zoo_file); zooseek (zoo_file, direntry.comment, 0); getfile (zoo_file, this_file, (long) direntry.cmt_size, 0); zooseek (zoo_file, save_pos, 0); } } #endif /* ifndef PORTABLE */ crccode = 0; /* Initialize CRC before extraction */ if (!pipe) { #ifdef PORTABLE prterror ('m', "%-14s -- ", prtfname); #else if (fast_ext) prterror ('m', "%-12s ==> %-12s -- ", prtfname, extfname); else prterror ('m', "%-12s -- ", prtfname); #endif /* PORTABLE */ } else { /* must be pipe */ prterror ('M',"\n\n********\n%s\n********\n",prtfname); #ifdef SETMODE MODE_BIN(this_file); /* make std output binary so ^Z won't cause error */ #endif } #ifndef NOSIGNAL if (tofile) { oldsignal = signal (SIGINT, SIG_IGN); if (oldsignal != SIG_IGN) signal (SIGINT, ctrl_c); /* Trap ^C & erase partial file */ } #endif /* not NOSIGNAL */ if (direntry.packing_method == 0) /* 4th param 1 means CRC update */ status = getfile (zoo_file, this_file, direntry.size_now, 1); #ifndef PORTABLE else if (fast_ext) /* 4th param 0 means no CRC update */ status = getfile (zoo_file, this_file, direntry.size_now, 0); #endif else if (direntry.packing_method == 1) { #ifdef UNBUF_IO #include "ERROR" /* NOT PORTABLE -- DO NOT TRY THIS AT HOME */ long lseek PARMS ((int, long, int)); long tell PARMS ((int)); int this_fd, zoo_fd; /* get file descriptors */ this_fd = null_device ? -2 : fileno (this_file); zoo_fd = fileno (zoo_file); zooseek (zoo_file, zootell (zoo_file), 0); /* synch */ lseek (zoo_fd, zootell (zoo_file), 0); /* ..again */ if (!null_device) { zooseek (this_file, zootell (this_file), 0); /* synch */ lseek (this_fd, zootell (this_file), 0); /* ..again */ } status = lzd(zoo_fd, this_fd); /* uncompress */ zooseek (zoo_file, tell (zoo_fd), 0); /* resynch */ if (!null_device) zooseek (this_file, tell (this_fd), 0);/* resynch */ #else status = lzd (zoo_file, this_file); /* uncompress */ #endif } else if (direntry.packing_method == 2) { status = lzh_decode (zoo_file, this_file); } else { prterror ('e', "File %s: impossible packing method.\n", whichname); unlink(extfname); goto loop_again; } #ifndef NOSIGNAL if (tofile) signal (SIGINT, oldsignal); #endif /* not NOSIGNAL */ #ifdef SETMODE if (pipe) MODE_TEXT(this_file); /* restore text mode */ #endif if (tofile) { /* set date/time of file being extracted */ #ifdef GETTZ void tzadj(); /* adjust for original timezone */ tzadj (&direntry); #endif #ifdef NIXTIME close_file (this_file); setutime (extfname, direntry.date, direntry.time); #else settime (this_file, direntry.date, direntry.time); close_file (this_file); #endif #ifdef FATTR /* Restore file attributes. Bit 23==1 means system-specific; we currently don't recognize this. Bit 23==0 means use portable format, in which case bit 22==0 means ignore attributes. Thus attributes are ignored if both bits 23 and 22 are zero, which is the effect of a zero-filled file attribute field. Currently we restore file attributes if and only if bit 23==0 and bit 22==1. */ if ((direntry.fattr >> 22) == 1) { setfattr (extfname, direntry.fattr); } #endif /* FATTR */ } /* end of if (tofile) ... */ if (status != 0) { exit_status = 1; if (tofile) unlink (extfname); if (status == 2) { /* was 1 (wrong) */ memerr(0); /* To avoid spurious errors due to ^Z being sent to screen, we don't check for I/O error if output was piped */ } else if (!pipe && (status == 2 || status == 3)) { prterror ('e', no_space, prtfname); } } else { /* file extracted, so update disk space. */ /* we subtract the original size of the file, rounded UP to the nearest multiple of the disk allocation size. */ #ifndef PORTABLE { unsigned long temp; temp = (direntry.org_size + alloc_size) / alloc_size; disk_space -= temp * alloc_size; } #endif if ( #ifndef PORTABLE !fast_ext && #endif direntry.file_crc != crccode ) { badcrc_count++; exit_status = 1; if (!pipe) { if (!null_device) prterror ('M', "extracted "); prterror ('w', bad_crc, prtfname); } else { /* duplicate to standard error */ static char stars[] = "\n******\n"; putstr (stars); prterror ('w', bad_crc, prtfname); putstr (stars); fprintf (stderr, "WARNING: "); fprintf (stderr, bad_crc, prtfname); } } else if (!pipe) prterror ('M', null_device ? "OK\n" : "extracted\n"); } /* end if */ } /* end if */ } /* end if */ } /* end if */ loop_again: zooseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */ } /* end while */ close_file (zoo_file); if (!matched) putstr (no_match); if (badcrc_count) { prterror ('w', "%d File(s) with bad CRC.\n", badcrc_count); } else if (null_device) prterror ('m', "Archive seems OK.\n"); zooexit (exit_status); } /* end zooext */ /* close_file() */ /* closes a file if and only if we aren't sending output to a pipe or to the null device */ void close_file (file) ZOOFILE file; { if (tofile) zooclose (file); } /* Ctrl_c() is called if ^C is hit while a file is being extracted. It closes the files, deletes it, and exits. */ T_SIGNAL ctrl_c() { #ifndef NOSIGNAL signal (SIGINT, SIG_IGN); /* ignore any more */ #endif zooclose (this_file); unlink (extfname); zooexit (1); } #ifndef PORTABLE /* make_tnh copies creates a tiny_header */ void make_tnh (tiny_header, direntry) struct tiny_header *tiny_header; struct direntry *direntry; { tiny_header->tinytag = TINYTAG; tiny_header->type = 1; tiny_header->packing_method = direntry->packing_method; tiny_header->date = direntry->date; tiny_header->time = direntry->time; tiny_header->file_crc = direntry->file_crc; tiny_header->org_size = direntry->org_size; tiny_header->size_now = direntry->size_now; tiny_header->major_ver = direntry->major_ver; tiny_header->minor_ver = direntry->minor_ver; tiny_header->cmt_size = direntry->cmt_size; strcpy (tiny_header->fname, direntry->fname); } #endif /* ifndef PORTABLE */ zoo-2.10.orig/zoofilt.c100644 1750 1750 4203 5035113600 13525 0ustar jamesjames/* derived from: zoofilt.c 1.8 88/01/30 23:47:05 */ #ifndef LINT static char sccsid[]="@(#) $Id: zoofilt.c,v 1.5 91/07/09 01:54:15 dhesi Exp $"; #endif /* (C) Copyright 1988 Rahul Dhesi -- All rights reserved (C) Copyright 1991 Rahul Dhesi -- All rights reserved Filter mode -- compress or decompress standard input and write to standard output. */ #include "options.h" #ifdef FILTER #include "zooio.h" #include "errors.i" #include "zoofns.h" /* action */ #define COMPRESS 0 #define UNCOMPRESS 1 #define FTAG ((unsigned int) 0x5a32) /* magic number */ extern unsigned int crccode; int rdint PARMS((unsigned int *)); /* read an unsigned int */ int wrint PARMS((unsigned int)); /* write an unsigned int */ /* global variable used to pass two bytes (CRC value) back from lzd to here */ unsigned int filt_lzd_word; void zoofilt (option) char *option; { int choice; /* what to do -- [de]compress */ unsigned int filetag; /* tag stored in input */ int stat1, stat2, stat3; /* status codes */ int use_lzh = 0; /* use lzh instead */ extern lzc(), lzh_encode(); /* possible encoders */ extern lzd(), lzh_decode(); /* and decoders */ while (*++option) { switch (*option) { case 'c': choice = COMPRESS; break; case 'u': choice = UNCOMPRESS; break; case 'h': use_lzh = 1; break; default: prterror ('f', inv_option, *option); /* fatal error -- abort */ } } crccode = 0; /* needed whether compressing or uncompressing */ switch (choice) { case COMPRESS: stat1 = wrint (FTAG); stat2 = (use_lzh ? lzh_encode : lzc) (STDIN, STDOUT); stat3 = wrint (crccode); if (stat1 == 0 && stat2 == 0 && stat3 == 0) zooexit (0); else { fprintf (stderr, "Zoo: FATAL: Compression error.\n"); zooexit (1); } break; case UNCOMPRESS: stat1 = rdint (&filetag); if (stat1 != 0 || filetag != FTAG) zooexit (1); stat2 = (use_lzh ? lzh_decode : lzd) (STDIN, STDOUT); if (stat2 == 0 && filt_lzd_word == crccode) zooexit (0); else { fprintf (stderr, "Zoo: FATAL: Uncompression error.\n"); zooexit (1); } break; } } /* zoofilt */ #endif /* FILTER */ zoo-2.10.orig/zoofns.h100644 1750 1750 6537 5035113600 13376 0ustar jamesjames/* @(#) zoofns.h 2.5 88/01/16 19:03:13 */ /* @(#) zoofns.h 2.7 88/01/27 19:39:18 */ /* The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ /* Defines function declarations for all Zoo functions */ #ifndef PARMS #ifdef LINT_ARGS #define PARMS(x) x #else #define PARMS(x) () #endif #endif /* :.,$s/(PARMS\(.*\));/PARMS\1;/ */ #ifdef ANSI_HDRS #include #else char *memset PARMS ((char *, int, unsigned)); #endif /* ANSI_HDRS */ long calc_ofs PARMS ((char *)); char *addext PARMS ((char *, char *)); char *combine PARMS ((char[], char *, char *)); VOIDPTR emalloc PARMS ((unsigned int)); VOIDPTR ealloc PARMS ((unsigned int)); VOIDPTR erealloc PARMS ((VOIDPTR, unsigned int)); char *findlast PARMS ((char *, char *)); char *fixfname PARMS ((char *)); char *getstdin PARMS ((void)); char *lastptr PARMS ((char *)); char *nameptr PARMS ((char *)); char *newcat PARMS ((char *, char *)); char *nextfile PARMS ((int, char *, int)); int cfactor PARMS ((long, long)); int chname PARMS ((char *, char *)); int cmpnum PARMS ((unsigned int, unsigned int, unsigned int, unsigned int)); T_SIGNAL ctrl_c PARMS ((void)); int exists PARMS ((char *)); int getfile PARMS ((ZOOFILE, ZOOFILE, long, int)); int getutime PARMS ((char *, unsigned *, unsigned *)); int gettime PARMS ((ZOOFILE, unsigned *, unsigned *)); T_SIGNAL handle_break PARMS ((void)); #ifdef USE_ASCII int isupper PARMS ((int)); int isdigit PARMS ((int)); #endif /* USE_ASCII */ int kill_files PARMS ((char *[], int)); #ifdef UNBUF_IO int lzc PARMS ((int, int)); int lzd PARMS ((int, int)); #else int lzc PARMS ((ZOOFILE, ZOOFILE)); int lzd PARMS ((ZOOFILE, ZOOFILE)); #endif int lzh_encode PARMS((FILE *infile, FILE *outfile)); int lzh_decode PARMS((FILE *infile, FILE *outfile)); int match_half PARMS ((char *, char *)); int samefile PARMS ((char *, char *)); int settime PARMS ((ZOOFILE, unsigned, unsigned)); int setutime PARMS ((char *, unsigned, unsigned)); int str_icmp PARMS ((char *, char *)); #ifdef USE_ASCII int tolower PARMS ((int)); int toascii PARMS ((int)); #endif /* USE_ASCII */ void zooexit PARMS ((int)); long inlist PARMS ((char *, unsigned int *, unsigned int *, unsigned *, unsigned *, unsigned *, long *, int)); unsigned long space PARMS ((int, int *)); void addbfcrc PARMS ((char *, int)); void addfname PARMS ((char *, long, unsigned int, unsigned int, unsigned, unsigned)); void add_version PARMS ((char *, struct direntry *)); void basename PARMS ((char *, char [])); void break_off PARMS ((void)); void close_file PARMS ((ZOOFILE)); void comment PARMS ((char *, char *)); void extension PARMS ((char *, char [])); void exit PARMS ((int)); void fixslash PARMS ((char *)); void makelist PARMS ((int, char *[], char *[], int, char *, char *, char *, int *)); void memerr PARMS ((unsigned int)); void prterror PARMS ((int, char *, ...)); void rootname PARMS ((char *, char *)); void skip_files PARMS ((ZOOFILE, unsigned int *, unsigned int *, int *, char [], long *)); void writenull PARMS ((ZOOFILE, int)); void zooadd PARMS ((char *, int, char **, char *)); void zoodel PARMS ((char *, char *, int)); void zoofilt PARMS ((char *)); void zooext PARMS ((char *, char *)); void zoolist PARMS ((char **, char *, int)); void zoopack PARMS ((char *, char *)); char *str_dup PARMS ((char *)); char *str_lwr PARMS ((char *)); zoo-2.10.orig/zooio.h100644 1750 1750 3623 5035113600 13210 0ustar jamesjames/* @(#) zooio.h 2.7 88/01/27 19:39:24 */ /* Declarations for portable I/O The contents of this file are hereby placed in the public domain. -- Rahul Dhesi 1988/01/24 */ #ifndef OK_STDIO #include #define OK_STDIO #endif #ifndef PARMS #ifdef LINT_ARGS #define PARMS(x) x #else #define PARMS(x) () #endif #endif /* In theory, all I/O using buffered files could be replaced with unbuffered I/O simply by changing the following definitions. This has not been tried out yet, and there may be some remaining holes in the scheme. On systems with limited memory, it might prove necessary to use unbuffered I/O only. */ typedef FILE *ZOOFILE; #define NOFILE ((ZOOFILE) 0) #define NULLFILE ((ZOOFILE) -1) /* or any unique value */ #define STDOUT stdout #ifdef FILTER #define STDIN stdin #endif #ifdef IO_MACROS #define zooread(file, buffer, count) fread (buffer, 1, count, file) #define zoowrite(file, buffer, count) \ (file == NULLFILE ? count : fwrite (buffer, 1, count, file)) #define zooseek(file, offset, whence) fseek (file, offset, whence) #define zootell(file) ftell (file) #else int zooread PARMS((ZOOFILE, char *, int)); int zoowrite PARMS((ZOOFILE, char *, int)); long zooseek PARMS((ZOOFILE, long, int)); long zootell PARMS((ZOOFILE)); #endif /* IO_MACROS */ ZOOFILE zooopen PARMS((char *, char *)); ZOOFILE zoocreate PARMS((char *)); int zooclose PARMS((ZOOFILE)); int zootrunc PARMS((ZOOFILE)); char *choosefname PARMS((struct direntry *)); char *fullpath PARMS((struct direntry *)); int frd_zooh PARMS((struct zoo_header *, ZOOFILE)); int frd_dir PARMS((struct direntry *, ZOOFILE)); int fwr_dir PARMS((struct direntry *, ZOOFILE)); int fwr_zooh PARMS((struct zoo_header *, ZOOFILE)); int readdir PARMS((struct direntry *, ZOOFILE, int)); void rwheader PARMS((struct zoo_header *, ZOOFILE, int)); void newdir PARMS((struct direntry *)); void writedir PARMS((struct direntry *, ZOOFILE)); zoo-2.10.orig/zoolist.c100644 1750 1750 44704 5035113600 13574 0ustar jamesjames#ifndef LINT /* derived from: zoolist.c 2.27 88/08/15 11:03:16 */ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zoolist.c,v $\n\ $Id: zoolist.c,v 1.4 91/07/09 01:54:16 dhesi Exp $"; #endif /* LINT */ /* If TRACE_LIST is defined, any list command may be followed by 'D' to show verbose information about each directory entry in the archive. Do not define both TRACE_LIST and TRACE_IO else a symbol conflict will occur and in any case duplicate information will be dumped. */ /* #define TRACE_LIST */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "portable.h" #include "zoomem.h" /* to get ZOOCOUNT */ /* Lists files in archive */ #include "zoo.h" #include "errors.i" #include "zooio.h" #include "various.h" #include "zoofns.h" #ifdef TRACE_LIST void show_dir PARMS ((struct direntry *direntry)); static int trace_list = 0; #endif /* TRACE_LIST */ static char tot_fmt[] = "%8lu %3u%% %8lu %4d file"; static char tot_line[] = /* "------------ -------- --- -------- --------- --------\n"; */ "-------- --- -------- --------- --------\n"; static char dbl_percent[] = "Archive %s: %s"; extern int quiet; /* assumed initialized to zero */ void show_comment PARMS((struct direntry *, ZOOFILE, int, char *)); int ver_too_high PARMS((struct zoo_header *)); int needed PARMS((char *, struct direntry *, struct zoo_header *)); void printtz PARMS((int)); void zoolist (argv, option, argc) char **argv, *option; int argc; { char whichname[PATHSIZE]; /* which name to use */ char *this_zoo; /* currently matched archive name */ register ZOOFILE zoo_file; char *flist[ZOOCOUNT]; /* list of ptrs to input archive names */ int fptr; /* will point to within list of archive names */ struct direntry direntry; struct zoo_header zoo_header; int size_factor; unsigned long tot_org_siz = 0L, tot_siz_now = 0L; int tot_sf; int file_count = 0; int del_count = 0; /* number of deleted entries */ int bad_pack; /* 1 if packing method is unknown */ static char *month_list="000JanFebMarAprMayJunJulAugSepOctNovDec"; static char dashes[] = "------------\n"; int year, month, day, hours, min, sec; int list_deleted = 0; /* list deleted files too */ int fast = 0; /* fast list */ long fiz_ofs = 0; /* offset where to start */ long dat_ofs = 0; /* ... data offset of file data */ int verb_list = 0; /* if verbose listing needed */ int show_name = 0; /* if archive name to be included in listing */ int show_crc = 0; /* if crc should be listed */ int zoocount = 1; /* number of archives to list */ int biglist = 0; /* multiarchive listing */ int one_col = 0; /* one column listing requested */ int showdir = 0; /* show directory name in fast listing */ int longest; /* length of longest archive name */ int talking; /* opposite of quiet */ int column = 0; /* for column printing */ int first_ever = 1; /* first time ever -- very special case */ int neednl = 0; /* whether to print a newline */ int need_acmt = 0; /* show archive comment */ int show_gen = 0; /* show generation count */ int genson = 1; /* enable/disable generations */ #ifdef FATTR int show_mode = 0; /* show file protection */ #endif int first_dir = 1; /* if first direntry -- to adjust dat_ofs */ while (*option) { switch (*option) { case 'a': show_name++; break; #ifdef TRACE_LIST case 'D': trace_list++; break; #endif /* TRACE_LIST */ case 'd': list_deleted++; break; case 'f': fast++; break; case 'g': show_gen++; break; case '/': showdir++; break; case 'A': case 'v': need_acmt++; break; case 'V': need_acmt++; /* fall through */ case 'c': verb_list++; break; case 'C': show_crc++; break; case 'l': break; case 'L': biglist++; zoocount = argc; break; #ifdef FATTR case 'm': show_mode++; break; #endif case '1': one_col++; break; case '+': genson = 1; break; case '-': genson = 0; break; /* following code same as in zooext.c */ case '@': /* if @m,n specified, fiz_ofs = m, dat_ofs = n */ { char *comma_pos; ++option; comma_pos = strchr(option, ','); if (comma_pos != NULL) { dat_ofs = calc_ofs (comma_pos + 1); *comma_pos = '\0'; } fiz_ofs = calc_ofs(option); goto no_more; } case 'q': quiet++; break; default: prterror ('w', option_ignored, *option); } option++; } no_more: /* come from exit from while loop above */ if (fast && show_name) { /* don't allow 'a' with 'f' */ show_name = 0; prterror ('w', option_ignored, 'a'); } talking = !quiet; /* for convenience */ #ifdef WILDCARD /* For each archive name supplied, if it is not a char range and does not contain a dot, append "*.zoo". */ { int i; for (i = 0; i < argc; i++) { if (strchr (nameptr (argv[i]), EXT_CH) == NULL && !match_half (nameptr (argv[0]), "?-?")) argv[i] = newcat (argv[i], "*.zoo"); } } #endif makelist (zoocount, argv, flist, ZOOCOUNT-2, (char *) NULL,".","..", &longest); /* ^argc ^argv ^list_pointer ^max_no_files ^exclude */ for (fptr = 0; (this_zoo = flist[fptr]) != NULL; fptr++) { int ercount; /* count of errors */ int entrycount; /* count of directory entries */ int expl_deleted; /* explain what D means */ int expl_comment; /* explain what comment means */ int expl_ver; /* Explain what V means */ int expl_star; /* Explain what * means */ int first_time; /* first time through loop for an archive */ ercount = entrycount = del_count = expl_deleted = expl_comment = expl_ver = expl_star = 0; if (talking) column = 0; /* if quiet, names will run together */ first_time = 1; #ifndef WILDCARD /* Add default extension if none supplied */ if (strchr (nameptr (this_zoo), EXT_CH) == NULL) this_zoo = newcat (this_zoo, EXT_DFLT); #endif zoo_file = zooopen (this_zoo, Z_READ); if (zoo_file == NOFILE) { prterror ('e', could_not_open, this_zoo); continue; } else if (!show_name && talking) printf ("\nArchive %s:\n", this_zoo); if (fiz_ofs != 0L) { /* if offset specified, start there */ prterror ('m', start_ofs, fiz_ofs, dat_ofs); zooseek (zoo_file, fiz_ofs, 0); } else { if (frd_zooh (&zoo_header, zoo_file) == -1 || zoo_header.zoo_tag != ZOO_TAG) { prterror ('e', dbl_percent, this_zoo, invalid_header); goto loop_end; } #if 0 if (talking && (!show_name || verb_list || need_acmt)) #else if (need_acmt && talking) #endif { void show_acmt PARMS ((struct zoo_header *, ZOOFILE, int)); show_acmt (&zoo_header, zoo_file, 0); /* show archive comment */ } /* Seek to the beginning of the first directory entry */ if (zooseek (zoo_file, zoo_header.zoo_start, 0) != 0) { ercount++; prterror ('e', dbl_percent, this_zoo, bad_directory); goto loop_end; } if (!show_name && ver_too_high (&zoo_header)) { ercount++; if (ercount < 2) prterror ('M', wrong_version, zoo_header.major_ver, zoo_header.minor_ver); } } /* end if (fiz_ofs !- 0L) */ /* Now we print information about each file in the archive */ if (!show_name) { /* initialize for each file only if not disk catalog */ tot_org_siz = 0L; tot_siz_now = 0L; file_count = 0; del_count = 0; } while (1) { if (readdir (&direntry, zoo_file, 0) == -1) { prterror ('F', dbl_percent, this_zoo, bad_directory); goto givesummary; } if (direntry.zoo_tag != ZOO_TAG) { long currpos, zoolength; prterror ('F', dbl_percent, this_zoo, invalid_header); if ((currpos = zootell (zoo_file)) != -1L) if (zooseek (zoo_file, 0L, 2) == 0) if ((zoolength = zootell (zoo_file)) != -1L) printf (cant_process, zoolength - currpos); goto givesummary; } if (direntry.next == 0L) /* EXIT on end of chain */ break; else entrycount++; /* Number of directory entries */ /* first direntry read, change dat_ofs from abs. pos. to rel. offset */ if (first_dir && dat_ofs != 0) { dat_ofs -= direntry.offset; first_dir = 0; } direntry.next += dat_ofs; /* allow for user-specified offset */ if (direntry.comment != 0L) direntry.comment += dat_ofs; /* so show_comment finds it */ if (direntry.deleted) ++del_count; #ifdef TRACE_LIST if (trace_list) show_dir (&direntry); #endif /* TRACE_LIST */ /* Into `whichname' put the filename to display. Use long filename if it exists, else use short filename. */ strcpy (whichname, fullpath (&direntry)); if (zoo_header.vdata & VFL_ON) add_version (whichname, &direntry); /* add version suffix */ #ifdef DEBUG printf("matching against [%s] and [%s]\n", nameptr(whichname), whichname); #endif if ( ( (list_deleted && direntry.deleted) || (list_deleted < 2 && !direntry.deleted) ) && (biglist || needed(whichname, &direntry, &zoo_header))) { /* if generations forced off, then strip added version field */ if (!genson) { /* HORRENDOUSLY INEFFICIENT AND REPETITIOUS */ char *ver_pos; ver_pos = findlast (whichname, VER_DISPLAY); if (ver_pos != NULL) *ver_pos = '\0'; } file_count++; if (direntry.packing_method > MAX_PACK) { bad_pack = 1; expl_ver = 1; } else bad_pack = 0; size_factor = cfactor (direntry.org_size, direntry.size_now); year = ((unsigned int) direntry.date >> 9) & 0x7f; month = ((unsigned int) direntry.date >> 5) & 0x0f; day = direntry.date & 0x1f; hours = ((unsigned int) direntry.time >> 11)& 0x1f; min = ((unsigned int) direntry.time >> 5) & 0x3f; sec = ((unsigned int) direntry.time & 0x1f) * 2; /* Alignment in columns is a horrendously complex undertaking. */ if (fast) { int space_left; int namelen; int next_col; #if 0 if ( (quiet && !first_ever || !first_time) && one_col) fputchar ('\n'); first_ever = 0; #endif /* If we are showing directories, whichname already contains the full pathname string. Else we only use the filename as follows: long filename if possible, else short filename */ if (!showdir) { strcpy (whichname, (direntry.namlen != 0) ? direntry.lfname : direntry.fname); if (genson && zoo_header.vdata & VFL_ON) add_version (whichname, &direntry); /* add version suffix */ } namelen = strlen (whichname); #define MARGIN 78 #define COL_WIDTH 16 #if 1 /* if not enough space left, move to next line */ if (!one_col && column != 0) { space_left = MARGIN - column; if (namelen > space_left) { neednl = 1; column = 0; } } #endif if ( (quiet && !first_ever || !first_time) && (neednl || one_col)) printf ("\n"); first_ever = 0; neednl = 0; printf("%s", whichname); fflush (stdout); /* move to next column stop */ column += namelen; next_col = ((column + (COL_WIDTH - 1)) / COL_WIDTH) * COL_WIDTH; if (next_col - column < 2) /* need at least 2 spaces */ next_col += COL_WIDTH; if (next_col > MARGIN) { neednl = 1; column = 0; } else { if (!one_col) printf ("%*s", (next_col - column), " "); column = next_col; } } else { if (talking && first_time && !show_name) {/*print archive header */ printf ("Length CF Size Now Date Time\n"); printf (tot_line); } printf ("%8lu %3u%% %8lu %2d %-.3s %02d %02d:%02d:%02d", direntry.org_size, size_factor, direntry.size_now, day, &month_list[month*3], (day && month) ? (year+80) % 100 : 0, hours, min, sec); tot_org_siz += direntry.org_size; tot_siz_now += direntry.size_now; #ifdef GETTZ printtz ((int) direntry.tz); /* show timezone */ #else printf (" "); #endif if (show_crc) printf ("%04x ", direntry.file_crc); if (show_gen) { if (direntry.vflag & VFL_ON) printf ("%2dg ", direntry.vflag & VFL_GEN); else printf ("--g "); } if (direntry.cmt_size) { expl_comment++; printf ("C"); } else printf (" "); if (direntry.deleted) { expl_deleted++; printf ("D"); } else printf (" "); if (list_deleted) printf (" "); if (show_name) printf ("%-*s ", longest, this_zoo); #ifdef FATTR if (show_mode) { if (direntry.fattr == 0) printf ("--- "); else if ((direntry.fattr >> 22) == 1) printf ("%03o ", direntry.fattr & 0x1ff); else printf ("??? "); } #endif /* FATTR */ /* new code to get around a common compiler bug */ printf ("%s", whichname); if (direntry.dir_crc != 0) { expl_star++; printf ("*"); } if (bad_pack) printf (" (V%d.%d)", direntry.major_ver, direntry.minor_ver); printf ("\n"); } first_time = 0; /* if verbose listing requested show any comment. f overrrides v */ if (verb_list && !fast) show_comment (&direntry, zoo_file, 0, (char *) NULL); } /* end if (lots of conditions) */ /* ..seek to next dir entry */ zooseek (zoo_file, direntry.next, 0); } /* end while */ givesummary: if (fast && talking) { if (file_count) { if (del_count || (show_gen && zoo_header.type > 0)) printf ("\n-----\n"); else fputchar ('\n'); } if (del_count) printf ("%d deleted.\n", del_count); if (show_gen && zoo_header.type > 0) { printf ("Generation limit %u", zoo_header.vdata & VFL_GEN); if ((zoo_header.vdata & VFL_ON) == 0) printf (" (off).\n"); else printf (".\n"); } } /* end if (fast && talking) */ if (talking && !show_name) { if (!fast && file_count) { tot_sf = cfactor (tot_org_siz, tot_siz_now); printf (tot_line); printf (tot_fmt, tot_org_siz, tot_sf, tot_siz_now, file_count); if (file_count > 1) printf ("s\n"); else printf ("\n"); if (del_count || expl_ver || expl_deleted || expl_comment || expl_star || (show_gen && (zoo_header.type > 0))) printf (dashes); } if (!fast) { if (del_count) { if (expl_deleted) printf ("D: deleted file.\n"); else { if (del_count == 1) printf ("There is 1 deleted file.\n"); else printf ("There are %d deleted files.\n", del_count); } } } if (expl_comment && !fast && !verb_list) printf ("C: file has attached comment.\n"); if (expl_ver && !fast) printf ("V: minimum version of Zoo needed to extract this file.\n"); if (expl_star && !fast) printf ("*: directory entry may be corrupted.\n"); if (!file_count) printf ("Zoo: %s", no_match); if (!entrycount && !fiz_ofs) printf ("(The archive is empty.)\n"); if (show_gen && (zoo_header.type > 0) && !fast) { printf ("Archive generation limit is %u", zoo_header.vdata & VFL_GEN); if ((zoo_header.vdata & VFL_ON) == 0) printf (" (generations off).\n"); else printf (".\n"); } } /* end if (talking && !show_name) */ loop_end: /* jump here on badly structured archive */ zooclose (zoo_file); } /* end for */ if (talking && show_name) { if (file_count) { tot_sf = cfactor (tot_org_siz, tot_siz_now); printf (tot_line); printf (tot_fmt, tot_org_siz, tot_sf, tot_siz_now, file_count); if (file_count > 1) printf ("s\n"); else printf ("\n"); } } else if (fast && quiet) fputchar ('\n'); if (!file_count) zooexit (1); /* Consider it an error if there were no files */ } /* zoolist() */ #ifdef GETTZ void printtz (file_tz) int file_tz; { long gettz(); int diff_tz; /* timezone difference */ if (file_tz == NO_TZ) /* if no timezone stored ..*/ printf (" "); /* .. just pad with blanks */ else { diff_tz = (file_tz / 4) - (int) (gettz() / 3600); if (diff_tz == 0) printf (" "); /* print nothing if same */ else if (diff_tz > 0) /* else print signed difference */ printf ("+%1d ", diff_tz); else printf ("-%1d ", -diff_tz); } } #endif /* FOLLOWING CODE IS FOR DEBUGGING ONLY. IT IS COMPILED IN ONLY IF THE SYMBOL TRACE_LIST IS DEFINED */ #ifdef TRACE_LIST /* code copied from portable.c near end */ /* dump contents of directory entry */ void show_dir (direntry) struct direntry *direntry; { printf ("Directory entry for file [%s][%s]:\n", direntry->fname, direntry->lfname); printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n", direntry->zoo_tag, (int) direntry->type, (int) direntry->packing_method, direntry->next, direntry->offset); printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n", direntry->org_size, direntry->size_now, (int) direntry->major_ver, (int) direntry->minor_ver); printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n", (int) direntry->struc, (int) direntry->deleted, direntry->comment, direntry->cmt_size); printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n", direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc); printf ("system_id = [%d] dirlen = [%d] namlen = [%d] fattr=[%24lx]\n", direntry->system_id, direntry->dirlen, direntry->namlen, direntry->fattr); printf ("vflag = [%4x] version_no = [%4x]\n", direntry->vflag, direntry->version_no); if (direntry->dirlen > 0) printf ("dirname = [%s]\n", direntry->dirname); printf ("---------\n"); } #endif /* TRACE_IO */ zoo-2.10.orig/zoomem.h100644 1750 1750 3147 5035113600 13360 0ustar jamesjames/* derived from: zoomem.h 2.1 87/12/25 12:26:18 */ /* $Path$ */ /* $Id: zoomem.h,v 1.3 91/07/09 01:43:06 dhesi Exp $ */ /* (C) Copyright 1991 Rahul Dhesi -- All rights reserved Defines parameters used for memory allocation. */ /* ZOOCOUNT is the number of archive names that may be matched by the archive filespec specified for a list. MAXADD is the number of filenames that may be added to an archive at one go. The total number of files that an archive may contain is not determined by MAXADD but is determined by available memory. */ #ifdef SMALL_MEM #define ZOOCOUNT (30) #define MAXADD (100) #endif #ifdef MED_MEM #define ZOOCOUNT (50) #define MAXADD (200) #endif #ifdef BIG_MEM #define ZOOCOUNT (400) #define MAXADD (4000) #endif /* Customizable sizes */ #ifdef SPEC_MEM #define ZOOCOUNT (100) #define MAXADD (400) #endif extern char *out_buf_adr; /* global I/O buffer */ /*************************************************************/ /* DO NOT CHANGE THE REST OF THIS FILE. */ /*************************************************************/ /* The main I/O buffer (called in_buf_adr in zoo.c) is reused in several places. */ #define IN_BUF_SIZE 8192 #define OUT_BUF_SIZE 8192 /* MEM_BLOCK_SIZE must be no less than (2 * DICSIZ + MAXMATCH) (see ar.h and lzh.h for values). The buffer of this size will also hold an input buffer of IN_BUF_SIZE and an output buffer of OUT_BUF_SIZE. FUDGE is a fudge factor, to keep some spare and avoid off-by-one errors. */ #define FUDGE 8 #define MEM_BLOCK_SIZE (8192 + 8192 + 256 + 8) zoo-2.10.orig/zoopack.c100644 1750 1750 32014 5035113600 13526 0ustar jamesjames#ifndef LINT /* derived from: @(#) zoopack.c 2.16 88/08/22 15:51:20 */ /*$Source: /usr/home/dhesi/zoo/RCS/zoopack.c,v $*/ /*$Id: zoopack.c,v 1.5 91/07/09 01:54:17 dhesi Exp $*/ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zoopack.c,v $\n\ $Id: zoopack.c,v 1.5 91/07/09 01:54:17 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Packs an archive. The sequence is: 1. Copy all files from current archive to new one. 2. If the user didn't want a backup, delete the old archive else rename it to same name with extension of .BAK. 3. Rename temporary archive to old name. */ /* define this to make packing noisless */ #define QUIETPACK 1 #include "portable.h" #include "zooio.h" #include "various.h" #include "zoo.h" #include "zoofns.h" #include "errors.i" #ifndef NOSIGNAL #include #endif char *mktemp PARMS((char *)); struct zoo_header zoo_header = { TEXT, ZOO_TAG, (long) SIZ_ZOOH, (long) (-SIZ_ZOOH), MAJOR_VER, MINOR_VER, H_TYPE, 0L, /* comment position */ 0, /* comment length */ GEN_DEFAULT /* generations */ }; char file_leader[] = FILE_LEADER; extern int quiet; int break_hit; int ver_too_high PARMS((struct zoo_header *)); void zoopack(zoo_path, option) char *zoo_path, *option; { char temp_file[PATHSIZE]; static char xes[]="XXXXXX"; /* template for temp file */ #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); #endif register ZOOFILE zoo_file; /* archive */ ZOOFILE new_file; /* destination archive */ long next_ptr; /* pointer to within archive */ long new_dir_pos; /* ditto */ struct direntry direntry; /* directory entry */ struct zoo_header old_zoo_header; /* just for reading old header */ int status; /* error status */ int nobackup = 0; /* keep backup */ int force = 0; /* force overwrite of old backup */ int extcount = 0; /* how many files moved */ char backup_name[PATHSIZE]; /* name of backup */ int bad_header = 0; /* if archive has bad header */ int latest_date = 0; /* latest date on any file moved */ int latest_time = 0; /* ...likewise */ int curr_dir = 0; /* create backup in curr dir */ static char partial_msg[] = "Partially packed archive left in %s.\n"; #ifdef FATTR unsigned long zoofattr; /* zoo archive protection */ int setfattr PARMS ((char *, unsigned long)); unsigned long getfattr /* params below */ # ifdef FATTR_FNAME PARMS ((char *)); # else PARMS ((ZOOFILE)); # endif /* FATTR_FNAME */ #endif /* FATTR */ while (*option) { switch (*option) { case 'P': force++; break; case 'E': nobackup++; break; case 'q': quiet++; break; case '.': curr_dir++; break; default: prterror ('f', inv_option, *option); } option++; } if (force == 1) /* force only if P was doubled */ force--; zoo_path = addext (zoo_path, EXT_DFLT); /* add default extension */ /* Create a backup name by replacing any extension by backup extension. */ strcpy (backup_name, zoo_path); { char *temp; if ((temp = strrchr (backup_name,EXT_CH)) != 0) /* if dot found */ strcpy (temp, BACKUP_EXT); /* replace old extension */ else strcat (backup_name, BACKUP_EXT); /* else just append */ } /* Open original archive for read-write access. Although we will only read from it and never write to it, we want to avoid packing an archive that is read-only, since presumably the user didn't want to risk changing it in any way. */ zoo_file = zooopen(zoo_path, Z_RDWR); if (zoo_file == NOFILE) prterror ('f', could_not_open, zoo_path); /* If possible, save protection code of old archive for propagation to new */ #ifdef FATTR # ifdef FATTR_FNAME zoofattr = getfattr (zoo_path); # else zoofattr = getfattr (zoo_file); # endif /* FATTR_FNAME */ #endif /* FATTR */ /* Read the header of the old archive. */ frd_zooh(&old_zoo_header, zoo_file); if ((old_zoo_header.zoo_start + old_zoo_header.zoo_minus) != 0L) { prterror ('w', failed_consistency); ++bad_header; /* remember for future error message */ } /* Refuse to pack it if its version number is higher than we can accept */ if (ver_too_high (&old_zoo_header)) prterror ('f', wrong_version, old_zoo_header.major_ver, old_zoo_header.minor_ver); /* Now see if the archive already exists with the backup extension. If so, give an error message and abort. However, we skip this test if the user specified overwriting the backup */ if (!force) { if (exists (backup_name)) prterror ('f', "File %s already exists. Delete it or use PP option.\n", backup_name); } /* Open the new archive by a temporary name. If not otherwise specified, we open the new archive in the same directory as the original. But if the curr_dir switch was given, we just put XXXXXX into temp_file. */ if (!curr_dir) { strcpy (temp_file, zoo_path); /* original archive name */ *nameptr (temp_file) = '\0'; /* ... minus original filename */ strcat (temp_file, xes); /* ... plus XXXXXX */ } else { strcpy (temp_file, xes); } mktemp (temp_file); /* ... and make unique */ new_file = zoocreate (temp_file); if (new_file == NOFILE) prterror ('f', "Could not create temporary file %s.\n", temp_file); /* If old_zoo_header greater than type 0, we update zoo_header as follows: new archive comment will be just after archive header; zoo_start will point to just beyond archive comment. But if old_zoo_header is of type 0, we leave zoo_header unchanged. However, we always unconditionally update the header type to be type H_TYPE. (Note: zoo_header.type is initialized to H_TYPE in the global declaration of zoo_header.) */ if (old_zoo_header.type > 0) { zoo_header.zoo_start = SIZ_ZOOH + old_zoo_header.acmt_len; zoo_header.zoo_minus = -zoo_header.zoo_start; zoo_header.acmt_pos = SIZ_ZOOH; /* new comment just after header */ zoo_header.acmt_len = old_zoo_header.acmt_len; zoo_header.vdata = old_zoo_header.vdata; } else /* keep generations off if using old format archive */ zoo_header.vdata &= (~VFL_ON); /* Write the header of the new archive, updated with our own data */ fwr_zooh (&zoo_header, new_file); /* copy archive comment */ if (old_zoo_header.acmt_len != 0) { zooseek (zoo_file, old_zoo_header.acmt_pos, 0); /* find archive comment */ getfile (zoo_file, new_file, (long) zoo_header.acmt_len, 0); /* copy it */ } /* WARNING: CHECK FOR SEEK BEYOND END OF FILE */ zooseek (new_file, zoo_header.zoo_start, 0); /* position to add files */ zooseek (zoo_file, old_zoo_header.zoo_start, 0); /* seek to where data begins */ /* Now we loop through the old archive's files and add each to the new archive. The only changes needed are to update the .next and .offset fields of the directory entry. */ while (1) { frd_dir(&direntry, zoo_file); if (direntry.zoo_tag != ZOO_TAG) { long currpos, zoolength; prterror ('F', bad_directory); if (bad_header) { /* bad headers means don't save temp file */ zooclose (new_file); unlink (temp_file); } else { writenull (new_file, MAXDIRSIZE); /* write final null entry */ printf (partial_msg, temp_file); if ((currpos = ftell (zoo_file)) != -1L) if (zooseek (zoo_file, 0L, 2) == 0) if ((zoolength = ftell (zoo_file)) != -1L) printf (cant_process, zoolength - currpos); } zooexit (1); } if (direntry.next == 0L) { /* END OF CHAIN */ break; /* EXIT on end of chain */ } next_ptr = direntry.next; /* ptr to next dir entry */ if (!direntry.deleted) { #ifdef QUIETPACK /* nothing */ #else prterror ('m', "%-14s -- ", direntry.namlen > 0 ? direntry.lfname : direntry.fname); #endif if (zooseek (zoo_file, direntry.offset, 0) == -1L) { prterror ('f', "Could not seek to file data.\n"); } else { extcount++; /* update count of files extracted */ /* write a directory entry for this file */ new_dir_pos = zootell (new_file); /* new direntry pos in new archive */ /* Write a null directory entry to preserve integrity in case of program being interrupted. Note: I don't think it is necessary to save direntry.next but I haven't checked. */ { long oldnext; oldnext = direntry.next; direntry.next = 0L; fwr_dir(&direntry, new_file); direntry.next = oldnext; } zooseek (zoo_file, direntry.offset, 0); /* where to start copying */ /* Write file leader and remember position of new file data */ (void) zoowrite (new_file, file_leader, SIZ_FLDR); direntry.offset = zootell (new_file); status = getfile (zoo_file, new_file, direntry.size_now, 0); /* if no error copy any comment attached to file */ if (status == 0 && direntry.cmt_size != 0) { zooseek (zoo_file, direntry.comment, 0); /* seek to old comment */ direntry.comment = zootell (new_file); /* location of new comment */ status = getfile (zoo_file, new_file, (long) direntry.cmt_size, 0); } if (status != 0) { if (status == 1) { memerr(0); } else if (status == 2 || status == 3) { prterror ('F', disk_full); printf (partial_msg, temp_file); zooexit (1); } else prterror ('f', internal_error); } else { if (latest_date < direntry.date || (latest_date == direntry.date && latest_time < direntry.time)) { latest_date = direntry.date; latest_time = direntry.time; } } direntry.next = zootell (new_file); zooseek (new_file, new_dir_pos, 0); /* position to write direntry */ break_hit = 0; #ifndef NOSIGNAL oldsignal = signal (SIGINT, SIG_IGN); if (oldsignal != SIG_IGN) signal (SIGINT, handle_break); #endif /* Bug fix thanks to Mark Alexander */ if (fwr_dir (&direntry, new_file) != -1 && zoowrite (new_file, file_leader, SIZ_FLDR) == SIZ_FLDR) { #ifdef QUIETPACK /* prterror ('M', "."); */ ; #else prterror ('M', "moved\n"); #endif } else prterror ('f', "Write to temporary packed archive %s failed.\n", temp_file); #ifndef NOSIGNAL signal (SIGINT, oldsignal); #endif if (break_hit) zooexit (1); zooseek (new_file, direntry.next, 0); /* back to end of new archive */ } /* end if (lseek ... */ } /* end if (!direntry.deleted) */ zooseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */ } /* end while */ zooclose (zoo_file); /* write a final null entry */ writenull (new_file, MAXDIRSIZE); #ifdef NIXTIME zooclose (new_file); setutime (temp_file, latest_date, latest_time); #else settime (new_file, latest_date, latest_time); /* adjust its time */ zooclose (new_file); #endif /* Important note: At this point, it is assumed that the archive was packed and written to a new file without error. If control reaches here without the new archive having been written properly, then loss of data due to deletion of the original file could occur. In other words, if something went wrong, execution MUST NOT reach here. */ if (extcount == 0) { unlink (temp_file); prterror ('m', "No files moved.\n"); } else { /* (a) if user requested, delete original, else rename it to *.bak. (b) rename temp file to same base name as zoo_file. */ #ifdef QUIETPACK /* prterror('M', "\n"); */ #endif unlink (backup_name); /* remove any previous backup in any case */ if (nobackup) unlink (zoo_path); else chname (backup_name, zoo_path); /* if we are packing into current directory, we will rename temp file to same basename but without the preceding pathname */ if (curr_dir) zoo_path = nameptr (zoo_path); /* strip pathname */ if (chname (zoo_path, temp_file)) { prterror ('w', "Renaming error. Packed archive is now in %s.\n", temp_file); zooexit (1); } /* Set protection on packed archive -- after renaming, since some OSs might not allow renaming of read-only files */ #ifdef FATTR setfattr (zoo_path, zoofattr); #endif /* FATTR */ } /* end if */ } /* end zoopack() */ /* handle_break() */ /* Sets break_hit to 1 when called */ T_SIGNAL handle_break() { #ifndef NOSIGNAL signal (SIGINT, SIG_IGN); /* ignore future control ^Cs for now */ break_hit = 1; #endif }