home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff281.lzh
/
MRMan
/
zcat.c
< prev
Wrap
C/C++ Source or Header
|
1989-11-20
|
36KB
|
1,203 lines
static char sccsid[] = "@(#)compress.c @(#)compress.c 5.9 (Berkeley) 5/11/86";
/*
* Compress - data compression program Modified by Mark Rinfret for
* conditional compilation as "zcat".
*/
#define min(a,b) ((a>b) ? b : a)
#ifndef BITS
# define BITS 16 /* default is 16 bits */
#endif
#if BITS == 16
# define HSIZE 69001 /* 95% occupancy */
#endif
#if BITS == 15
# define HSIZE 35023 /* 94% occupancy */
#endif
#if BITS == 14
# define HSIZE 18013 /* 91% occupancy */
#endif
#if BITS == 13
# define HSIZE 9001 /* 91% occupancy */
#endif
#if BITS <= 12
# define HSIZE 5003 /* 80% occupancy */
#endif
/*
* a code_int must be able to hold 2**BITS values of type int, and also -1
*/
typedef long int code_int;
typedef long int count_int;
typedef unsigned char char_type;
char_type magic_header[] = {"\037\235"}; /* 1F 9D */
/* Defines for third byte of header */
#define BIT_MASK 0x1f
#define BLOCK_MASK 0x80
/*
* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is a
* fourth header byte (for expansion).
*/
#define INIT_BITS 9 /* initial number of bits/code */
static char rcs_ident[] = "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
#include <stdio.h>
#include <ctype.h>
#include <stat.h>
#include <time.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <functions.h>
#define ARGVAL() (*++(*argv) || (--argc && *++argv))
int n_bits; /* number of bits/code */
int maxbits = BITS; /* user settable max # bits/code */
code_int maxcode; /* maximum code, given n_bits */
code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */
#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
/* extern int errno; */
count_int *htab;
unsigned short *codetab;
#define htabof(i) htab[i]
#define codetabof(i) codetab[i]
code_int hsize = HSIZE; /* for dynamic table sizing */
count_int fsize;
/*
* To save much memory, we overlay the table used by compress() with those
* used by decompress(). The tab_prefix table is the same size and type as
* the codetab. The tab_suffix table needs 2**BITS characters. We get this
* from the beginning of htab. The output stack uses the rest of htab, and
* contains characters. There is plenty of room for any possible stack
* (stack used to be 8000 characters).
*/
#define tab_prefixof(i) codetabof(i)
#define tab_suffixof(i) ((char_type *)(htab))[i]
#define de_stack ((char_type *)&tab_suffixof(1<<BITS))
code_int free_ent = 0; /* first unused entry */
int exit_stat = 0; /* per-file status */
int perm_stat = 0; /* permanent status */
code_int getcode();
Usage()
{
fprintf(stderr, "Usage: compress [-fvcd] [-b maxbits] [file ...]\n");
}
int nomagic = 0; /* Use a 3-byte magic number header, unless
* old file */
#ifdef ZCAT
int zcat_flg = 1; /* Write output on stdout, supress messages */
#else
int zcat_flg = 0; /* Write output on stdout, suppress messages */
#endif
int precious = 1; /* Don't unlink output file on interrupt */
int quiet = 1; /* don't tell me about compression */
/*
* block compression parameters -- after all codes are used up, and
* compression rate changes, start over.
*/
int block_compress = BLOCK_MASK;
int clear_flg = 0;
long int ratio = 0;
#define CHECK_GAP 10000 /* ratio check interval */
count_int checkpoint = CHECK_GAP;
/*
* the next two codes should not be changed lightly, as they must not lie
* within the contiguous general code space.
*/
#define FIRST 257 /* first free entry */
#define CLEAR 256 /* table clear output code */
int force = 0;
char ofname[100];
int (*oldint) ();
#ifdef ZCAT
int do_decomp = 1;
#else
int do_decomp = 0;
#endif
/*****************************************************************
* TAG( main )
*
* Algorithm from "A Technique for High Performance Data Compression",
* Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
*
* Usage: compress [-dfvc] [-b bits] [file ...]
* Inputs:
* -d: If given, decompression is done instead.
*
* -c: Write output on stdout, don't remove original.
*
* -b: Parameter limits the max number of bits/code.
*
* -f: Forces output file to be generated, even if one already
* exists, and even if no space is saved by compressing.
* If -f is not used, the user will be prompted if stdin is
* a tty, otherwise, the output file will not be overwritten.
*
* -v: Write compression statistics
*
* file ...: Files to be compressed. If none specified, stdin
* is used.
* Outputs:
* file.Z: Compressed form of file with same mode, owner, and utimes
* or stdout (if stdin used as input)
*
* Assumptions:
* When filenames are given, replaces with the compressed version
* (.Z suffix) only if the file decreases in size.
* Algorithm:
* Modified Lempel-Ziv method (LZW). Basically finds common
* substrings and replaces them with a variable size code. This is
* deterministic, and can be done on the fly. Thus, the decompression
* procedure needs no input table, but tracks the way the table was built.
*/
main(argc, argv)
register int argc;
char **argv;
{
int overwrite = 0; /* Do not overwrite unless given -f
* flag */
char tempname[100];
char **filelist, **fileptr;
char *cp, *rindex(), *strcpy(), *malloc();
struct stat statbuf;
extern onintr(), oops();
freopen("*", "r+", stderr);
htab = (count_int *) malloc(HSIZE * sizeof(count_int));
codetab = (unsigned short *) malloc(HSIZE * sizeof(unsigned short));
if (htab == NULL || codetab == NULL) {
perror("compress");
exit(1);
}
filelist = fileptr = (char **) (malloc(argc * sizeof(*argv)));
*filelist = NULL;
if ((cp = rindex(argv[0], '/')) != 0) {
cp++;
} else {
cp = argv[0];
}
#ifndef ZCAT
if (strcmp(cp, "uncompress") == 0) {
do_decomp = 1;
} else if (strcmp(cp, "zcat") == 0) {
do_decomp = 1;
zcat_flg = 1;
}
#endif
/*
* Argument Processing All flags are optional. -D => debug -V => print
* Version; debug verbose -d => do_decomp -v => unquiet -f => force
* overwrite of output file -n => no header: useful to uncompress old
* files -b maxbits => maxbits. If -b is specified, then maxbits MUST be
* given also. -c => cat all output to stdout -C => generate output
* compatible with compress 2.0. if a string is left, must be an input
* filename.
*/
for (argc--, argv++; argc > 0; argc--, argv++) {
if (**argv == '-') { /* A flag argument */
while (*++(*argv)) {/* Process all flags in this arg */
switch (**argv) {
#ifndef ZCAT
case 'V':
version();
break;
case 'v':
quiet = 0;
break;
case 'd':
do_decomp = 1;
break;
case 'f':
case 'F':
overwrite = 1;
force = 1;
break;
case 'n':
nomagic = 1;
break;
case 'C':
block_compress = 0;
break;
case 'b':
if (!ARGVAL()) {
fprintf(stderr, "Missing maxbits\n");
Usage();
exit(1);
}
maxbits = atoi(*argv);
goto nextarg;
case 'c':
zcat_flg = 1;
break;
case 'q':
quiet = 1;
break;
#endif
default:
fprintf(stderr, "Unknown flag: '%c'; ", **argv);
Usage();
exit(1);
}
}
} else { /* Input file name */
*fileptr++ = *argv; /* Build input file list */
*fileptr = NULL;
/* process nextarg; */
}
nextarg:continue;
}
if (maxbits < INIT_BITS)
maxbits = INIT_BITS;
if (maxbits > BITS)
maxbits = BITS;
maxmaxcode = 1 << maxbits;
if (*filelist != NULL) {
for (fileptr = filelist; *fileptr; fileptr++) {
exit_stat = 0;
if (do_decomp) { /* DECOMPRESSION */
#ifndef ZCAT
/* Check for .Z suffix */
if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
/* No .Z: tack one on */
strcpy(tempname, *fileptr);
strcat(tempname, ".Z");
*fileptr = tempname;
}
#endif
/* Open input file */
if ((freopen(*fileptr, "r", stdin)) == NULL) {
perror(*fileptr);
perm_stat = 1;
continue;
}
/* Check the magic number */
if (nomagic == 0) {
if ((getc(stdin) != (magic_header[0] & 0xFF))
|| (getc(stdin) != (magic_header[1] & 0xFF))) {
fprintf(stderr, "%s: not in compressed format\n",
*fileptr);
continue;
}
maxbits = getc(stdin); /* set -b from file */
block_compress = maxbits & BLOCK_MASK;
maxbits &= BIT_MASK;
maxmaxcode = 1 << maxbits;
if (maxbits > BITS) {
fprintf(stderr,
"%s: compressed with %d bits, can only handle %d bits\n",
*fileptr, maxbits, BITS);
continue;
}
}
#ifndef ZCAT
/* Generate output filename */
strcpy(ofname, *fileptr);
ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
#endif
}
#ifndef ZCAT
else { /* COMPRESSION */
if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
fprintf(stderr, "%s: already has .Z suffix -- no change\n",
*fileptr);
continue;
}
/* Open input file */
if ((freopen(*fileptr, "r", stdin)) == NULL) {
perror(*fileptr);
perm_stat = 1;
continue;
}
stat(*fileptr, &statbuf);
fsize = (long) statbuf.st_size;
/*
* tune hash table size for small files -- ad hoc, but the
* sizes match earlier #defines, which serve as upper bounds
* on the number of output codes.
*/
hsize = HSIZE;
if (fsize < (1 << 12))
hsize = min(5003, HSIZE);
else if (fsize < (1 << 13))
hsize = min(9001, HSIZE);
else if (fsize < (1 << 14))
hsize = min(18013, HSIZE);
else if (fsize < (1 << 15))
hsize = min(35023, HSIZE);
else if (fsize < 47000)
hsize = min(50021, HSIZE);
/* Generate output filename */
strcpy(ofname, *fileptr);
strcat(ofname, ".Z");
}
#endif
#ifndef ZCAT
/* Check for overwrite of existing file */
if (overwrite == 0 && zcat_flg == 0) {
if (stat(ofname, &statbuf) == 0) {
char response[2];
response[0] = 'n';
fprintf(stderr, "%s already exists;", ofname);
if (isatty(2)) {
fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
ofname);
fflush(stderr);
read(2, response, 2);
while (response[1] != '\n') {
if (read(2, response + 1, 1) < 0) { /* Ack! */
perror("stderr");
break;
}
}
}
if (response[0] != 'y') {
fprintf(stderr, "\tnot overwritten\n");
continue;
}
}
}
if (zcat_flg == 0) {/* Open output file */
if (freopen(ofname, "w", stdout) == NULL) {
perror(ofname);
perm_stat = 1;
continue;
}
precious = 0;
if (!quiet)
fprintf(stderr, "%s: ", *fileptr);
}
#endif
/* Actually do the compression/decompression */
#ifndef ZCAT
if (do_decomp == 0)
compress();
else
#endif
decompress();
#ifndef ZCAT
if (zcat_flg == 0) {
copystat(*fileptr, ofname); /* Copy stats */
precious = 1;
if ((exit_stat == 1) || (!quiet))
putc('\n', stderr);
}
#endif
}
}
#ifndef ZCAT
else { /* Standard input */
if (do_decomp == 0) {
compress();
if (!quiet)
putc('\n', stderr);
} else {
/* Check the magic number */
if (nomagic == 0) {
if ((getc(stdin) != (magic_header[0] & 0xFF))
|| (getc(stdin) != (magic_header[1] & 0xFF))) {
fprintf(stderr, "stdin: not in compressed format\n");
exit(1);
}
maxbits = getc(stdin); /* set -b from file */
block_compress = maxbits & BLOCK_MASK;
maxbits &= BIT_MASK;
maxmaxcode = 1 << maxbits;
fsize = 100000; /* assume stdin large for USERMEM */
if (maxbits > BITS) {
fprintf(stderr,
"stdin: compressed with %d bits, can only handle %d bits\n",
maxbits, BITS);
exit(1);
}
}
decompress();
}
}
#endif
exit(perm_stat ? perm_stat : exit_stat);
}
static int offset;
long int in_count = 1; /* length of input */
long int bytes_out; /* length of compressed output */
long int out_count = 0; /* # of codes output (for debugging) */
#ifndef ZCAT
/*
* compress stdin to stdout
*
* Algorithm: use open addressing double hashing (no chaining) on the prefix
* code / next character combination. We do a variant of Knuth's algorithm D
* (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
* Here, the modular division first probe is gives way to a faster
* exclusive-or manipulation. Also do block compression with an adaptive
* reset, whereby the code table is cleared when the compression ratio
* decreases, but after the table fills. The variable-length output codes
* are re-sized at this point, and a special CLEAR code is generated for the
* decompressor. Late addition: construct the table according to file size
* for noticeable speed improvement on small files. Please direct questions
* about this implementation to ames!jaw.
*/
compress()
{
register long fcode;
register code_int i = 0;
register int c;
register code_int ent;
register int disp;
register code_int hsize_reg;
register int hshift;
if (nomagic == 0) {
putc(magic_header[0], stdout);
putc(magic_header[1], stdout);
putc((char) (maxbits | block_compress), stdout);
if (ferror(stdout))
writeerr();
}
offset = 0;
bytes_out = 3; /* includes 3-byte header mojo */
out_count = 0;
clear_flg = 0;
ratio = 0;
in_count = 1;
checkpoint = CHECK_GAP;
maxcode = MAXCODE(n_bits = INIT_BITS);
free_ent = ((block_compress) ? FIRST : 256);
ent = getc(stdin);
hshift = 0;
for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
hshift++;
hshift = 8 - hshift; /* set hash code range bound */
hsize_reg = hsize;
cl_hash((count_int) hsize_reg); /* clear hash table */
while ((c = getc(stdin)) != EOF) {
in_count++;
fcode = (long) (((long) c << maxbits) + ent);
i = ((c << hshift) ^ ent); /* xor hashing */
if (htabof(i) == fcode) {
ent = codetabof(i);
continue;
} else if ((long) htabof(i) < 0) /* empty slot */
goto nomatch;
disp = hsize_reg - i; /* secondary hash (after G. Knott) */
if (i == 0)
disp = 1;
probe:
if ((i -= disp) < 0)
i += hsize_reg;
if (htabof(i) == fcode) {
ent = codetabof(i);
continue;
}
if ((long) htabof(i) > 0)
goto probe;
nomatch:
output((code_int) ent);
out_count++;
ent = c;
if (free_ent < maxmaxcode) {
codetabof(i) = free_ent++; /* code -> hashtable */
htabof(i) = fcode;
} else if ((count_int) in_count >= checkpoint && block_compress)
cl_block();
}
/*
* Put out the final code.
*/
output((code_int) ent);
out_count++;
output((code_int) - 1);
/*
* Print out stats on stderr
*/
if (zcat_flg == 0 && !quiet) {
fprintf(stderr, "Compression: ");
prratio(stderr, in_count - bytes_out, in_count);
}
if (bytes_out > in_count) /* exit(2) if no savings */
exit_stat = 2;
return;
}
#endif
/*****************************************************************
* TAG(output)
*
* Output the given code.
* Inputs:
* code: A n_bits-bit integer. If == -1, then EOF. This assumes
* that n_bits =< (long)wordsize - 1.
* Outputs:
* Outputs code to the file.
* Assumptions:
* Chars are 8 bits long.
* Algorithm:
* Maintain a BITS character long buffer (so that 8 codes will
* fit in it exactly). Use the VAX insv instruction to insert each
* code in turn. When the buffer fills up empty it and start over.
*/
static char buf[BITS];
char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
#ifndef ZCAT
output(code)
code_int code;
{
/*
* On the VAX, it is important to have the register declarations in
* exactly the order given, or the asm will break.
*/
register int r_off = offset, bits = n_bits;
register char *bp = buf;
if (code >= 0) {
/*
* byte/bit numbering on the VAX is simulated by the following code
*/
/*
* Get to the first byte.
*/
bp += (r_off >> 3);
r_off &= 7;
/*
* Since code is always >= 8 bits, only need to mask the first hunk
* on the left.
*/
*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
bp++;
bits -= (8 - r_off);
code >>= 8 - r_off;
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if (bits >= 8) {
*bp++ = code;
code >>= 8;
bits -= 8;
}
/* Last bits. */
if (bits)
*bp = code;
offset += n_bits;
if (offset == (n_bits << 3)) {
bp = buf;
bits = n_bits;
bytes_out += bits;
do
putc(*bp++, stdout);
while (--bits);
offset = 0;
}
/*
* If the next entry is going to be too big for the code size, then
* increase it, if possible.
*/
if (free_ent > maxcode || (clear_flg > 0)) {
/*
* Write the whole buffer, because the input side won't discover
* the size increase until after it has read it.
*/
if (offset > 0) {
if (fwrite(buf, 1, n_bits, stdout) != n_bits)
writeerr();
bytes_out += n_bits;
}
offset = 0;
if (clear_flg) {
maxcode = MAXCODE(n_bits = INIT_BITS);
clear_flg = 0;
} else {
n_bits++;
if (n_bits == maxbits)
maxcode = maxmaxcode;
else
maxcode = MAXCODE(n_bits);
}
}
} else {
/*
* At EOF, write the rest of the buffer.
*/
if (offset > 0)
fwrite(buf, 1, (offset + 7) / 8, stdout);
bytes_out += (offset + 7) / 8;
offset = 0;
fflush(stdout);
if (ferror(stdout))
writeerr();
}
}
#endif
/*
* Decompress stdin to stdout. This routine adapts to the codes in the file
* building the "string" table on-the-fly; requiring no table to be stored in
* the compressed file. The tables used herein are shared with those of the
* compress() routine. See the definitions above.
*/
decompress()
{
register char_type *stackp;
register int finchar;
register code_int code, oldcode, incode;
/*
* As above, initialize the first 256 entries in the table.
*/
maxcode = MAXCODE(n_bits = INIT_BITS);
for (code = 255; code >= 0; code--) {
tab_prefixof(code) = 0;
tab_suffixof(code) = (char_type) code;
}
free_ent = ((block_compress) ? FIRST : 256);
finchar = oldcode = getcode();
if (oldcode == -1) /* EOF already? */
return; /* Get out of here */
putc((char) finchar, stdout); /* first code must be 8 bits = char */
if (ferror(stdout)) /* Crash if can't write */
writeerr();
stackp = de_stack;
while ((code = getcode()) > -1) {
if ((code == CLEAR) && block_compress) {
for (code = 255; code >= 0; code--)
tab_prefixof(code) = 0;
clear_flg = 1;
free_ent = FIRST - 1;
if ((code = getcode()) == -1) /* O, untimely death! */
break;
}
incode = code;
/*
* Special case for KwKwK string.
*/
if (code >= free_ent) {
*stackp++ = finchar;
code = oldcode;
}
/*
* Generate output characters in reverse order
*/
while (code >= 256) {
*stackp++ = tab_suffixof(code);
code = tab_prefixof(code);
}
*stackp++ = finchar = tab_suffixof(code);
/*
* And put them out in forward order
*/
do
putc(*--stackp, stdout);
while (stackp > de_stack);
/*
* Generate the new entry.
*/
if ((code = free_ent) < maxmaxcode) {
tab_prefixof(code) = (unsigned short) oldcode;
tab_suffixof(code) = finchar;
free_ent = code + 1;
}
/*
* Remember previous code.
*/
oldcode = incode;
}
fflush(stdout);
if (ferror(stdout))
writeerr();
}
/*****************************************************************
* TAG( getcode )
*
* Read one code from the standard input. If EOF, return -1.
* Inputs:
* stdin
* Outputs:
* code or -1 is returned.
*/
code_int
getcode()
{
/*
* On the VAX, it is important to have the register declarations in
* exactly the order given, or the asm will break.
*/
register code_int code;
static int offset = 0, size = 0;
static char_type buf[BITS];
register int r_off, bits;
register char_type *bp = buf;
if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
/*
* If the next entry will be too big for the current code size, then
* we must increase the size. This implies reading a new buffer
* full, too.
*/
if (free_ent > maxcode) {
n_bits++;
if (n_bits == maxbits)
maxcode = maxmaxcode; /* won't get any bigger now */
else
maxcode = MAXCODE(n_bits);
}
if (clear_flg > 0) {
maxcode = MAXCODE(n_bits = INIT_BITS);
clear_flg = 0;
}
size = fread(buf, 1, n_bits, stdin);
if (size <= 0)
return -1; /* end of file */
offset = 0;
/* Round size down to integral number of codes */
size = (size << 3) - (n_bits - 1);
}
r_off = offset;
bits = n_bits;
/*
* Get to the first byte.
*/
bp += (r_off >> 3);
r_off &= 7;
/* Get first part (low order bits) */
code = (*bp++ >> r_off);
bits -= (8 - r_off);
r_off = 8 - r_off; /* now, offset into code word */
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if (bits >= 8) {
code |= *bp++ << r_off;
r_off += 8;
bits -= 8;
}
/* high order bits. */
code |= (*bp & rmask[bits]) << r_off;
offset += n_bits;
return code;
}
writeerr()
{
perror(ofname);
unlink(ofname);
exit(1);
}
#ifndef ZCAT
copystat(ifname, ofname)
char *ifname, *ofname;
{
BOOL CopyFileDate();
fclose(stdout);
fclose(stdin);
if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
if (!quiet)
fprintf(stderr, " -- file unchanged"), fflush(stderr);
} else { /* ***** Successful Compression ***** */
exit_stat = 0;
if (CopyFileAttr(ifname, ofname) || CopyFileDate(ifname, ofname))
fprintf(stderr, " -- couldn't copy file attributes"), fflush(stderr);
if (unlink(ifname)) /* Remove input file */
perror(ifname), fflush(stderr);
else if (!quiet)
fprintf(stderr, " -- replaced with %s", ofname), fflush(stderr);
return; /* Successful return */
}
/* Unsuccessful return -- one of the tests failed */
if (unlink(ofname))
perror(ofname), fflush(stderr);
}
#endif
onintr()
{
#ifndef ZCAT
if (!precious)
unlink(ofname);
#endif
exit(1);
}
oops()
{ /* wild pointer -- assume bad input */
if (do_decomp)
fprintf(stderr, "uncompress: corrupt input\n");
#ifndef ZCAT
unlink(ofname);
#endif
exit(1);
}
#ifndef ZCAT
cl_block()
{ /* table clear for block compress */
register long int rat;
checkpoint = in_count + CHECK_GAP;
if (in_count > 0x007fffff) {/* shift will overflow */
rat = bytes_out >> 8;
if (rat == 0) { /* Don't divide by zero */
rat = 0x7fffffff;
} else {
rat = in_count / rat;
}
} else {
rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
}
if (rat > ratio) {
ratio = rat;
} else {
ratio = 0;
cl_hash((count_int) hsize);
free_ent = FIRST;
clear_flg = 1;
output((code_int) CLEAR);
}
}
#endif
#ifndef ZCAT
cl_hash(hsize) /* reset code table */
register count_int hsize;
{
register count_int *htab_p = &htab[hsize];
register long i;
register long m1 = -1;
i = hsize - 16;
do { /* might use Sys V memset(3) here */
*(htab_p - 16) = m1;
*(htab_p - 15) = m1;
*(htab_p - 14) = m1;
*(htab_p - 13) = m1;
*(htab_p - 12) = m1;
*(htab_p - 11) = m1;
*(htab_p - 10) = m1;
*(htab_p - 9) = m1;
*(htab_p - 8) = m1;
*(htab_p - 7) = m1;
*(htab_p - 6) = m1;
*(htab_p - 5) = m1;
*(htab_p - 4) = m1;
*(htab_p - 3) = m1;
*(htab_p - 2) = m1;
*(htab_p - 1) = m1;
htab_p -= 16;
} while ((i -= 16) >= 0);
for (i += 16; i > 0; i--)
*--htab_p = m1;
}
#endif
#ifndef ZCAT
prratio(stream, num, den)
FILE *stream;
long int num, den;
{
register int q; /* Doesn't need to be long */
if (num > 214748L) { /* 2147483647/10000 */
q = num / (den / 10000L);
} else {
q = 10000L * num / den; /* Long calculations, though */
}
if (q < 0) {
putc('-', stream);
q = -q;
}
fprintf(stream, "%d.%02d%%", q / 100, q % 100);
}
#endif
version()
{
fprintf(stderr, "%s, Berkeley 5.9 5/11/86\n", rcs_ident);
fprintf(stderr, "Options: ");
fprintf(stderr, "AMIGA, ");
fprintf(stderr, "BITS = %d\n", BITS);
}
#ifndef ZCAT
/*
* Function: GetFileDate
*
* Called with: name: file name date: pointer to DateStamp structure
*
* Returns: result: 1 => got a date, 0 => didn't
*
* Description: GetFileDate attempts to get the creation/modification date of a
* file (unfortunately, they're one and the same) and stores it into the
* location pointed to by <date>. If the file doesn't exist or for some
* reason the date can't be obtained, <date> is set to zeros and a zero is
* returned. Otherwise, <date> is set to the file date and a 1 is returned.
*/
BOOL
GetFileDate(name, date)
char *name;
struct DateStamp *date;
{
struct FileInfoBlock *Fib;
ULONG FLock;
int result = FALSE;
register struct DateStamp *d;
if ((FLock = (ULONG) Lock(name, (long) (ACCESS_READ))) == NULL)
goto exit1;
Fib = (struct FileInfoBlock *)
AllocMem((long) sizeof(struct FileInfoBlock),
(long) (MEMF_CHIP | MEMF_PUBLIC));
if (Fib == NULL)
result = FALSE;
else {
if (!Examine(FLock, Fib)) {
result = FALSE;
} else if (Fib->fib_DirEntryType > 0)
result = FALSE; /* It's a directory */
else {
d = &Fib->fib_Date;
date->ds_Days = d->ds_Days;
date->ds_Minute = d->ds_Minute;
date->ds_Tick = d->ds_Tick;
result = TRUE;
}
FreeMem((void *) Fib, (long) sizeof(struct FileInfoBlock));
}
UnLock(FLock);
exit1:
if (!result) {
date->ds_Days = 0;
date->ds_Minute = 0;
date->ds_Tick = 0;
}
return result;
}
#endif
#ifndef ZCAT
/*---------------------------------------------------------------------*/
/* SetFileDate: datestamp the given file with the given date. */
/*---------------------------------------------------------------------*/
#define ACTION_SETDATE_MODE 34L /* Set creation date on file */
BOOL
SetFileDate(name, date)
char *name;
struct DateStamp *date;
{
struct MsgPort *task; /* for process id handler */
ULONG arg[4]; /* array of arguments */
int nameleng;
char *bstr, *strcpy(); /* of file to be set */
long rc;
char *strchr();
int strlen();
rc = 0;
nameleng = strlen(name);
if (!(bstr = (char *) AllocMem((long) (nameleng + 2), MEMF_PUBLIC)))
goto exit2;
if (!(task = (struct MsgPort *) DeviceProc(name)))
goto exit1;
/* Dos Packet needs the filename in Bstring format */
(void) strcpy(bstr + 1, name);
*bstr = nameleng;
arg[0] = (ULONG) NULL;
arg[1] = (ULONG) IoErr(); /* lock on parent director set by
* DeviceProc() */
arg[2] = (ULONG) bstr >> 2;
arg[3] = (ULONG) date;
rc = sendpkt(task, ACTION_SETDATE_MODE, arg, 4L);
exit1:if (bstr)
FreeMem((void *) bstr, (long) (nameleng + 2));
exit2:if (rc == DOSTRUE)
return TRUE;
else
return FALSE;
}
#endif
#ifndef ZCAT
/*
* Copy the last modified date from one file to another. Called with: from:
* me of source file to: name of destination file Returns: 0 => success, 1
* => failure Note: Dynamic memory allocation of the DateStamp struction is
* necessary to insure longword alignment.
*/
BOOL
CopyFileDate(from, to)
char *from, *to;
{
struct DateStamp *date;
int status = 1; /* default is fail code */
if (date = (struct DateStamp *)
AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC)) {
if (GetFileDate(from, date))
if (SetFileDate(to, date))
status = 0;
FreeMem(date, (long) sizeof(struct DateStamp));
}
return status;
}
#endif
#ifndef ZCAT
/****************************************************************************/
/*
* Function: CopyFileAttr - Copy File Attributes
*
* Called with: srcName: source file name dstName: destination file name
*
* Returns: status where 0 => success
*
* Description: CopyFileAttr is used by file copying functions to assign the
* attributes of the source file to the destination file.
*/
int
CopyFileAttr(srcName, dstName)
char *srcName, *dstName;
{
struct Lock *srcLock = NULL;
struct FileInfoBlock *srcFIB = NULL;
int status = 0;
if (!(srcFIB = AllocMem((long) sizeof(*srcFIB), MEMF_FAST))) {
nomem:
status = ERROR_NO_FREE_STORE;
goto done;
}
if (!(srcLock = (struct Lock *) Lock(srcName, ACCESS_READ))) {
err:
status = IoErr();
goto done;
}
if (!Examine(srcLock, srcFIB))
goto err;
SetFileDate(dstName, &srcFIB->fib_Date);
if (srcFIB->fib_Comment[0])
SetComment(dstName, srcFIB->fib_Comment);
SetProtection(dstName, srcFIB->fib_Protection);
done:
if (srcLock)
UnLock(srcLock);
if (srcFIB)
FreeMem(srcFIB, (long) sizeof(*srcFIB));
return status;
}
#endif
#ifndef ZCAT
LONG
sendpkt(id, type, args, nargs)
struct MsgPort *id; /* process indentifier ... (handler's message
* port ) */
LONG type, /* packet type ... (what you want handler to
* do ) */
args[], /* a pointer to argument list */
nargs; /* number of arguments in list */
{
struct MsgPort *replyport;
struct StandardPacket *packet;
LONG count, *pargs, res1 = NULL;
if (!(replyport = (struct MsgPort *) CreatePort(NULL, NULL)))
return (NULL);
packet = (struct StandardPacket *)
AllocMem((LONG) sizeof(*packet), MEMF_PUBLIC | MEMF_CLEAR);
if (packet) {
packet->sp_Msg.mn_Node.ln_Name = &(packet->sp_Pkt); /* link packet */
packet->sp_Pkt.dp_Link = &(packet->sp_Msg); /* to message */
packet->sp_Pkt.dp_Port = replyport; /* set-up reply port */
packet->sp_Pkt.dp_Type = type; /* what to do... */
/* move all the arguments to the packet */
pargs = &(packet->sp_Pkt.dp_Arg1); /* address of first argument */
for (count = 0; (count < nargs) && (count < 7); count++)
pargs[count] = args[count];
PutMsg(id, packet); /* send packet */
WaitPort(replyport); /* wait for packet to come back */
GetMsg(replyport); /* pull message */
res1 = packet->sp_Pkt.dp_Res1; /* get result */
FreeMem(packet, (LONG) sizeof(*packet));
}
DeletePort(replyport);
return (res1);
}
#endif