Category : Linux Files
Archive   : ZOOSRC.ZIP
Filename : ZOOSRC.TAR

 
Output of file : ZOOSRC.TAR contained in archive : ZOOSRC.ZIP
Checksums000600 000000 000000 00000004200 05037071756 012702 0ustar00rootroot000000 000000 # 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
Copyright000600 000000 000000 00000004160 05037071756 012732 0ustar00rootroot000000 000000
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
Install000600 000000 000000 00000004132 05037071756 012367 0ustar00rootroot000000 000000
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
List000600 000000 000000 00000005222 05037071756 011675 0ustar00rootroot000000 000000 ## 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
README000600 000000 000000 00000000545 05234637104 011714 0ustar00rootroot000000 000000 zoobin.tar.Z and zoosrc.zoo are the source and binary for zoo as ported
to Linux. Because the zoosrc.zoo was far smaller than a tar.Z, and zoo
users will want to use zoo, and the static linked zoo binary may be useful
to people without an hour to compile... use zoobin.tar.Z zoo (static
linked) to unpack the zoosrc.zoo.

complaints to [email protected]
addbfcrc.c000600 000000 000000 00000001524 05037071756 012734 0ustar00rootroot000000 000000 #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;
}
addbftcc.c000600 000000 000000 00000004061 05037071760 012730 0ustar00rootroot000000 000000 #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
addfname.c000600 000000 000000 00000007440 05037071760 012741 0ustar00rootroot000000 000000 #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() */
ar.h000600 000000 000000 00000006132 05234615222 011602 0ustar00rootroot000000 000000 /*$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
#include
#else /* ! ANSI_HDRS */

/* 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 */
#endif /* ! ANSI_HDRS */

/* 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)
asmconst.ai000600 000000 000000 00000001005 05037071760 013167 0ustar00rootroot000000 000000 ; $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
assert.h000600 000000 000000 00000001743 05037071760 012510 0ustar00rootroot000000 000000 /* @(#) 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 */
basename.c000600 000000 000000 00000006155 05037071760 012757 0ustar00rootroot000000 000000 #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);
}
}
bilf.c000600 000000 000000 00000014106 05037071762 012115 0ustar00rootroot000000 000000 /* $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);
}
bsd.c000600 000000 000000 00000005132 05037071762 011750 0ustar00rootroot000000 000000 #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);
}
comment.c000600 000000 000000 00000022573 05037072032 012641 0ustar00rootroot000000 000000 #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() */
crcdefs.c000600 000000 000000 00000004616 05037072032 012606 0ustar00rootroot000000 000000 #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
};
debug.h000600 000000 000000 00000001147 05037072032 012264 0ustar00rootroot000000 000000 /* @(#) 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

decode.c000600 000000 000000 00000002644 05037072032 012417 0ustar00rootroot000000 000000 /*$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;
}
}
}
}
descrip.mms000600 000000 000000 00000010115 05037072034 013171 0ustar00rootroot000000 000000 # 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
encode.c000600 000000 000000 00000016174 05037072034 012436 0ustar00rootroot000000 000000 /*$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 */
errors.i000600 000000 000000 00000001471 05037072034 012515 0ustar00rootroot000000 000000 /* @(#) 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[];

file.fix000600 000000 000000 00000003426 05037072034 012460 0ustar00rootroot000000 000000 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 ");
fiz.1000600 000000 000000 00000007411 05037072036 011703 0ustar00rootroot000000 000000 .\" @(#) 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
fiz.c000600 000000 000000 00000015200 05037072036 011760 0ustar00rootroot000000 000000 #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 */
}
fiz.man000600 000000 000000 00000010203 05037072036 012307 0ustar00rootroot000000 000000


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



generic.c000600 000000 000000 00000004566 05037072040 012614 0ustar00rootroot000000 000000 #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; }

getfile.c000600 000000 000000 00000010705 05037072040 012607 0ustar00rootroot000000 000000 #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);
}
huf.c000600 000000 000000 00000017115 05037072040 011754 0ustar00rootroot000000 000000 /*$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;
}
io.c000600 000000 000000 00000005673 05037072040 011607 0ustar00rootroot000000 000000 /*$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;
}
lzc.asm000600 000000 000000 00000027773 05037072042 012335 0ustar00rootroot000000 000000 title 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

lzc.c000600 000000 000000 00000020311 05037072042 011754 0ustar00rootroot000000 000000 #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");
}
}
lzconst.h000600 000000 000000 00000001076 05037072042 012674 0ustar00rootroot000000 000000 /* @(#) 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 */
lzd.asm000600 000000 000000 00000021670 05037072044 012326 0ustar00rootroot000000 000000 title 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
lzd.c000600 000000 000000 00000072175 05037072046 012000 0ustar00rootroot000000 000000 #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 *outbufp++=(c); \
else \
xwr_dchar(c); \
}

extern char *out_buf_adr; /* output buffer */
extern char *in_buf_adr; /* input buffer */
/* use pointers (not counters) for buffer (for speed) */
static char *outbufp; /* output buffer pointer */
static char *outbuflim; /* output buffer limit */
static char *outbufguard; /* output buffer "guard" */

char memflag = 0; /* memory allocated? flag */
int *head; /* lzw prefix codes */
char *tail; /* lzw suffix codes */
static unsigned cur_code;
static unsigned old_code;
static unsigned in_code;

static unsigned free_code;
static int nbits;
static unsigned max_code;

/* We use a buffer of codes to avoid a function call to unpack each
** one as needed. We allocate an extra slot past the end of the buffer
** and put a CLEAR code in it, to serve as a sentinel. This way we can
** fold the test for code buffer runout into the test for a clear code
** and avoid having an extra test on each code processed. Also, we don't
** always use the code buffer. We can only use it when the input buffer
** is at a byte boundary, and when we know that the codesize won't change
** before we fill the code buffer, and when we know we won't run out of
** bytes in the input buffer before filling the code buffer. So we start
** with the code buffer pointer pointing to the sentinel, and we always
** have it pointing at the sentinel when we can't (for one reason or
** another) be getting our codes from the code buffer. We check for this
** condition whenever we get a CLEAR code, and if so, we get the code
** via the good old rd_dcode() routine.
**
** One other problem with the code buffer approach is that we might get
** a CLEAR code in the middle of the buffer. This means that the next
** code is only 9 bits, but we have probably already unpacked a number of
** larger codes from the input into the buffer before we discover this.
** So we remember where (in the input buffer) the code buffer was filled
** from, and when a CLEAR code is encountered in the buffer (not the
** sentinel at the end) we back up the bit_offset pointer in the input
** buffer, and reset things to start unpacking the 9-bit codes from there.
*/

#define CODEBUF_SIZE 64 /* must be multiple of 8, experiment for best */
static unsigned codebuf[CODEBUF_SIZE+1]; /* code buffer */
static unsigned *codebufp; /* code buffer pointer */
static unsigned *codebuflim; /* code buffer limit */
/* bit offset within the input buffer of where the code buffer began */
static unsigned codebufoffset;

static unsigned masks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff };
static unsigned bit_offset; /* note this only allows max 8K input buffer!!*/

#ifdef UNBUF_IO
#define BLOCKFILE int
#define BLOCKREAD read
#define BLOCKWRITE blockwrite
int read PARMS ((int, VOIDPTR, unsigned));
int write PARMS ((int, VOIDPTR, unsigned));
int blockwrite PARMS ((int, VOIDPTR, unsigned));
#else
#define BLOCKFILE ZOOFILE
#define BLOCKREAD zooread
#define BLOCKWRITE zoowrite
#endif /* UNBUF_IO */

static BLOCKFILE in_f, out_f;

/* 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;

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 */
lzh.c000600 000000 000000 00000002347 05037072050 011771 0ustar00rootroot000000 000000 /* $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;
}
lzh.h000600 000000 000000 00000001646 05037072050 011777 0ustar00rootroot000000 000000 /*$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[];
machine.c000600 000000 000000 00000003065 05037072052 012600 0ustar00rootroot000000 000000 #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
machine.h000600 000000 000000 00000002055 05037072052 012603 0ustar00rootroot000000 000000 /* @(#) 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 */

macros.ai000600 000000 000000 00000000561 05037072052 012625 0ustar00rootroot000000 000000 ; $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

make.err000600 000000 000000 00000006470 05233110176 012460 0ustar00rootroot000000 000000 make CFLAGS="-c -O -DSYS_V -DANSI_HDRS -traditional" zoo fiz
cc -c -O -DSYS_V -DANSI_HDRS -traditional -DBIG_MEM -DNDEBUG addbfcrc.c
cc -c -O -DSYS_V -DANSI_HDRS -traditional -DBIG_MEM -DNDEBUG addfname.c
In file included from addfname.c:16:
zooio.h:31: warning: `NOFILE' redefined
/usr/include/stdio.h:59: warning: this is the location of the previous definition
In file included from various.h:27, from addfname.c:17:
/usr/include/string.h:12: parse error before `void'
/usr/include/string.h:13: parse error before `void'
/usr/include/string.h:15: parse error before `char'
/usr/include/string.h:16: parse error before `char'
/usr/include/string.h:20: parse error before `const'
/usr/include/string.h:21: parse error before `const'
/usr/include/string.h:21: warning: conflicting types for built-in function `memcpy'
/usr/include/string.h:22: parse error before `const'
/usr/include/string.h:23: parse error before `void'
/usr/include/string.h:25: parse error before `void'
/usr/include/string.h:27: parse error before `char'
/usr/include/string.h:28: parse error before `const'
/usr/include/string.h:29: parse error before `char'
/usr/include/string.h:30: parse error before `char'
/usr/include/string.h:31: parse error before `char'
/usr/include/string.h:32: parse error before `const'
/usr/include/string.h:33: parse error before `char'
/usr/include/string.h:34: parse error before `char'
/usr/include/string.h:35: parse error before `char'
/usr/include/string.h:35: warning: conflicting types for built-in function `strlen'
/usr/include/string.h:36: parse error before `const'
/usr/include/string.h:37: parse error before `char'
/usr/include/string.h:38: parse error before `const'
/usr/include/string.h:39: parse error before `char'
/usr/include/string.h:40: parse error before `char'
/usr/include/string.h:42: parse error before `char'
/usr/include/string.h:43: parse error before `char'
/usr/include/string.h:44: parse error before `const'
/usr/include/string.h:45: parse error before `const'
/usr/include/string.h:48: parse error before `char'
/usr/include/string.h:50: parse error before `void'
In file included from various.h:28, from addfname.c:17:
/usr/include/stdlib.h:35: syntax error before `void'
/usr/include/stdlib.h:38: parse error before `char'
/usr/include/stdlib.h:39: parse error before `char'
/usr/include/stdlib.h:40: parse error before `char'
/usr/include/stdlib.h:41: parse error before `char'
/usr/include/stdlib.h:42: parse error before `char'
/usr/include/stdlib.h:44: parse error before `char'
/usr/include/stdlib.h:73: parse error before `char'
/usr/include/stdlib.h:74: parse error before `char'
/usr/include/stdlib.h:75: parse error before `char'
/usr/include/stdlib.h:76: parse error before `void'
/usr/include/stdlib.h:78: parse error before `void'
/usr/include/stdlib.h:80: parse error before `void'
/usr/include/stdlib.h:90: parse error before `char'
/usr/include/stdlib.h:91: parse error before `char'
/usr/include/stdlib.h:94: parse error before `char'
/usr/include/stdlib.h:112: parse error before `char'
/usr/include/stdlib.h:115: parse error before `const'
/usr/include/stdlib.h:121: parse error before `const'
/usr/include/stdlib.h:123: parse error before `const'
/usr/include/stdlib.h:136: parse error before `char'
/usr/include/stdlib.h:138: parse error before `char'
make[1]: *** [addfname.o] Error 1
make: *** [linux] Error 1
makefile000600 000000 000000 00000020661 05234636344 012542 0ustar00rootroot000000 000000 # 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 "linux: Linux 0.96cPL2, gcc 2.2.2"
@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)

# Linux 0.96c, gcc 2.2.2
linux:
$(MAKE) \
CFLAGS="-c -O2 -DBSD4_3 -DANSI_HDRS -DLINUX" \
$(TARGETS)

# linux as above, static linked
linux_s:
$(MAKE) \
CFLAGS="-c -O2 -DBSD4_3 -DANSI_HDRS -DLINUX" \
LDFLAGS="-static" $(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: zooio.h
addfname.o: zoomem.h
basename.o: various.h
basename.o: zoo.h zoofns.h zooio.h
bsd.o: /usr/include/sys/time.h
bsd.o: nixmode.i nixtime.i
comment.o: /usr/include/stdio.h
comment.o: various.h
comment.o: zoo.h zoofns.h zooio.h
crcdefs.o: options.h
decode.o: zoo.h
encode.o: errors.i lzh.h
encode.o: options.h zoo.h
fiz.o: zoofns.h
fiz.o: zooio.h
generic.o: /usr/include/sys/types.h
generic.o: nixmode.i nixtime.i
getfile.o: zooio.h
getfile.o: zoomem.h
huf.o: zoo.h
io.o: zoo.h
io.o: zooio.h
lzc.o: various.h
lzc.o: zoo.h zoofns.h zooio.h zoomem.h
lzd.o: various.h
lzd.o: zoo.h zoofns.h zooio.h zoomem.h
lzh.o: zoo.h
machine.o: zooio.h
makelist.o: errors.i options.h
makelist.o: portable.h various.h zoo.h zoofns.h zooio.h
maketbl.o: zoo.h
maketree.o: zoo.h
misc.o: /usr/include/sys/signal.h
misc.o: errors.i options.h portable.h various.h zoo.h zoofns.h zooio.h
misc2.o: zoo.h
misc2.o: zoofns.h zooio.h zoomem.h
msdos.o: zooio.h
needed.o: zoo.h
needed.o: zoofns.h zooio.h
nextfile.o: zoo.h
options.o: zoofns.h
options.o: zooio.h
parse.o: zoo.h
parse.o: zoofns.h zooio.h
portable.o: options.h
portable.o: portable.h various.h zoo.h zoofns.h zooio.h
prterror.o: options.h various.h
prterror.o: zoofns.h zooio.h
sysv.o: /usr/include/time.h
sysv.o: nixmode.i nixtime.i
turboc.o: /usr/include/sys/signal.h
vms.o: /usr/include/time.h
vmstime.o: /usr/include/stdio.h
zoo.o: zoofns.h
zoo.o: zooio.h zoomem.h
zooadd.o: portable.h
zooadd.o: various.h zoo.h zoofns.h zooio.h zoomem.h
zooadd2.o: parse.h
zooadd2.o: various.h zoo.h zoofns.h zooio.h
zoodel.o: /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/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: zoo.h
zoolist.o: zoofns.h zooio.h zoomem.h
zoopack.o: /usr/include/stdio.h
zoopack.o: various.h
zoopack.o: zoo.h zoofns.h zooio.h
makefile.tcc000600 000000 000000 00000010612 05037072054 013276 0ustar00rootroot000000 000000 # $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
makelist.c000600 000000 000000 00000014066 05037072054 013012 0ustar00rootroot000000 000000 #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 for (j = i; j < fptr; j++)
flist[j] = flist[j+1];
fptr--;
}
}

flist[++fptr] = NULL; /* NULL entry terminates list */
}

/*******
modpath() makes any changes needed before pathname is stored;
currently these could involve folding it to lower case and
converting backslashes to forward slashes
*/

/*ARGSUSED*/
void modpath (path)
char *path;
{
#ifdef FOLD
str_lwr (path);
#endif

#ifdef FORCESLASH
fixslash (path); /* convert backslashes to slashes */
#endif
}

#ifdef CHEKDIR
/* Function isfdir returns 1 if pathname is a directory else 0 */
int isfdir (this_path)
char *this_path;
{
int dir;
ZOOFILE f;
f = zooopen (this_path, Z_READ);
if (f == NOFILE)
return 0;
else {
dir = isadir(f); zooclose(f);
}
return (dir);
}
#endif
maketbl.c000600 000000 000000 00000003454 05037072054 012617 0ustar00rootroot000000 000000 /*$Source: /usr/home/dhesi/zoo/RCS/maketbl.c,v $*/
/*$Id: maketbl.c,v 1.8 91/07/09 01:39:52 dhesi Exp $*/
/***********************************************************
maketbl.c -- make table for decoding

Adapted from "ar" archiver written by Haruhiko Okumura.
***********************************************************/
#include "options.h"
#include "zoo.h"
#include "ar.h"
#include "lzh.h"

extern void prterror();

void make_table(nchar, bitlen, tablebits, table)
int nchar;
uchar bitlen[];
int tablebits;
ushort table[];
{
ushort count[17], weight[17], start[18], *p;
uint i, k, len, ch, jutbits, avail, nextcode, mask;

for (i = 1; i <= 16; i++) count[i] = 0;
for (i = 0; i < nchar; i++) count[bitlen[i]]++;

start[1] = 0;
for (i = 1; i <= 16; i++)
start[i + 1] = start[i] + (count[i] << (16 - i));
if (start[17] != (ushort)((unsigned) 1 << 16))
prterror('f', "Bad decode table\n");

jutbits = 16 - tablebits;
for (i = 1; i <= tablebits; i++) {
start[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;
}
}
maketree.c000600 000000 000000 00000005424 05037072056 012776 0ustar00rootroot000000 000000 /*$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 */
}
misc.c000600 000000 000000 00000022717 05037072056 012140 0ustar00rootroot000000 000000 #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 */
misc2.c000600 000000 000000 00000020613 05037072056 012213 0ustar00rootroot000000 000000 #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);
}
}
msdos.c000600 000000 000000 00000004362 05037072060 012321 0ustar00rootroot000000 000000 /* 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);
}
}
mstime.i000600 000000 000000 00000005454 05037072060 012503 0ustar00rootroot000000 000000 #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);
}
needed.c000600 000000 000000 00000020112 05037072060 012407 0ustar00rootroot000000 000000 #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 */
}
}

nextfile.c000600 000000 000000 00000016644 05037072062 013022 0ustar00rootroot000000 000000 #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 */
nixmode.i000600 000000 000000 00000002147 05037072062 012646 0ustar00rootroot000000 000000 #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)));
}
nixtime.i000600 000000 000000 00000006552 05037072062 012664 0ustar00rootroot000000 000000 #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);
}
options.c000600 000000 000000 00000003522 05037072062 012666 0ustar00rootroot000000 000000 #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
options.doc000600 000000 000000 00000037566 05037072064 013232 0ustar00rootroot000000 000000 /* 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.
options.h000600 000000 000000 00000020422 05037072064 012673 0ustar00rootroot000000 000000 /* @(#) 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
options.opt000600 000000 000000 00000000034 05037072064 013243 0ustar00rootroot000000 000000 sys$share:vaxcrtl.exe/share
parse.c000600 000000 000000 00000013010 05037072066 012302 0ustar00rootroot000000 000000 #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);
}
parse.h000600 000000 000000 00000001300 05037072066 012306 0ustar00rootroot000000 000000 /* @(#) 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
portable.c000600 000000 000000 00000052155 05037072066 013015 0ustar00rootroot000000 000000 #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 */
portable.h000600 000000 000000 00000005141 05037072070 013006 0ustar00rootroot000000 000000 /* @(#) 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 */
prterror.c000600 000000 000000 00000021606 05037072070 013054 0ustar00rootroot000000 000000 #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*/
sysv.c000600 000000 000000 00000007770 05037072072 012211 0ustar00rootroot000000 000000 #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; }

turboc.c000600 000000 000000 00000004017 05037072072 012472 0ustar00rootroot000000 000000 /* @(#) 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 */
turboc.cfg000600 000000 000000 00000000161 05037072072 013003 0ustar00rootroot000000 000000 -IC:\TC\INCLUDE
-LC:\TC\LIB
-a -f- -k- -v- -G -O -Z -c -O
-wrvl -wamb -wamp -wnod -wstv -wuse -wcln -wsig -wucp
various.h000600 000000 000000 00000004061 05037072072 012670 0ustar00rootroot000000 000000 /* @(#) 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 */

version.c000600 000000 000000 00000000157 05037072072 012662 0ustar00rootroot000000 000000 /* derived from: version.c 2.9 1988/08/25 12:43:57 */
char version[] =
"zoo 2.1 $Date: 91/07/09 02:10:34 $";
vms.c000600 000000 000000 00000024003 05037072072 011776 0ustar00rootroot000000 000000 #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; }
vmsbugs.doc000600 000000 000000 00000044230 05037072074 013210 0ustar00rootroot000000 000000

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
vmsbuild.com000600 000000 000000 00000007505 05037072076 013366 0ustar00rootroot000000 000000 $! VMSBUILD.COM for ZOO 2.10
$!
$! Adapted from similar script for zoo 2.01 that was contributed by
$! Steve Roseman
$! Lehigh University Computing Center
$! [email protected]
$!
$ 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.*
vmstime.c000600 000000 000000 00000014410 05037072076 012662 0ustar00rootroot000000 000000 /* 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.1000600 000000 000000 00000133135 05037072100 011715 0ustar00rootroot000000 000000 .\" 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.c000600 000000 000000 00000037332 05037072102 012003 0ustar00rootroot000000 000000 #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.h000600 000000 000000 00000023775 05037072102 012016 0ustar00rootroot000000 000000 /* 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.man000600 000000 000000 00000141606 05037072106 012340 0ustar00rootroot000000 000000
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
zooadd.c000600 000000 000000 00000063320 05037072114 012453 0ustar00rootroot000000 000000 #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 */
zooadd2.c000600 000000 000000 00000021066 05037072116 012540 0ustar00rootroot000000 000000 #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;
}
zoodel.c000600 000000 000000 00000022714 05037072116 012473 0ustar00rootroot000000 000000 #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");
}

}
zooext.c000600 000000 000000 00000053277 05037072120 012532 0ustar00rootroot000000 000000 #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 */
zoofilt.c000600 000000 000000 00000004203 05037072120 012651 0ustar00rootroot000000 000000 /* 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 */
zoofns.h000600 000000 000000 00000006537 05037072120 012522 0ustar00rootroot000000 000000 /* @(#) 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 *));

zooio.h000600 000000 000000 00000003745 05234605734 012355 0ustar00rootroot000000 000000 /* @(#) 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;
/* try undefining this for LINUX */
#ifdef LINUX
#undef NOFILE
#endif /* LINUX */
#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));
zoolist.c000600 000000 000000 00000044704 05037072124 012704 0ustar00rootroot000000 000000 #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 */
zoomem.h000600 000000 000000 00000003147 05037072124 012510 0ustar00rootroot000000 000000 /* 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)

zoopack.c000600 000000 000000 00000032014 05037072124 012636 0ustar00rootroot000000 000000 #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
}


  3 Responses to “Category : Linux Files
Archive   : ZOOSRC.ZIP
Filename : ZOOSRC.TAR

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/