Path: utzoo!attcan!uunet!lll-winken!lll-lcc!ames!pasteur!ucbvax!LBL.GOV!nagy%warner.hepnet
From: nagy%warner.hepnet@LBL.GOV (Frank J. Nagy, VAX Wizard & Guru)
Newsgroups: comp.os.vms
Subject: Lempel-Ziv file (de)compress from VAX SIG tapes (Part 2 of 3)
Message-ID: <880712062710.2760608d@LBL.Gov>
Date: 12 Jul 88 13:27:10 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Organization: The Internet
Lines: 2113
+-+-+-+ Beginning of part 2 +-+-+-+
Xextern long`009tot_outcount;`009`009/* Total output count`009`009*/
Xextern code_int`009hsize;`009`009`009/* Actual hash table size`009*/
X
X#ifdef XENIX_16
Xstatic count_int htab0[8192];
Xstatic count_int htab1[8192];
Xstatic count_int htab2[8192];
Xstatic count_int htab3[8192];
Xstatic count_int htab4[8192];
Xstatic count_int htab5[8192];
Xstatic count_int htab6[8192];
Xstatic count_int htab7[8192];
Xstatic count_int htab8[HSIZE - 65536];
Xstatic count_int *hashtab[9] = {
X htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8
X};
X
Xstatic U_short code0[16384];
Xstatic U_short code1[16384];
Xstatic U_short code2[16384];
Xstatic U_short code3[16384];
Xstatic U_short code4[HSIZE - 65536];
Xstatic U_short *codetab[5] = {
X code0, code1, code3, code3, code4
X}
X
X#define HASH(i)`009`009(hashtab[((unsigned) (i)) >> 13][(i) & 0x1FFF])
X#define CODE(i)`009`009(codetab[((unsigned) (i)) >> 14][(i) & 0x3FFF])
X
X#else
Xcount_int`009hashtab[HSIZE];
XU_short`009`009codetab[HSIZE];
X
X#define HASH(i)`009`009hashtab[i]
X#define CODE(i)`009`009codetab[i]
X#endif
X`012
X/*
X * compress a datastream
X *
X * Algorithm: on large machines, for maxbits <= FBITS, use fast direct table
X * lookup on the prefix code / next character combination. For smaller code
X * size, use open addressing modular division double hashing (no chaining), ala
X * Knuth vol. 3, sec. 6.4 Algorithm D, along with G. Knott's relatively-prime
X * secondary probe. Do block compression with an adaptive reset, whereby the
X * code table is cleared when the compression ratio decreases, but after the
X * table fills. The variable-length output codes are re-sized at this point,
X * and a special LZ_CLEAR code is generated for the decompressor. For the
X * megamemory version, the sparse array is cleared indirectly through a
X * "shadow" output code history. Late additions: for the hashing code,
X * construct the table according to file size for noticeable speed improvement
X * on small files. Also detect and cache codes associated with the most
X * common character to bypass hash calculation on these codes (a characteristic
X * of highly-compressable raster images). Please direct questions about this
X * implementation to ames!jaw.
X */
X
Xcompress(in)
XSTREAM`009`009*in;`009`009/* Input stream structure`009`009*/
X/*
X * Compress driver. Global fsize is the size of the entire datastream
X * (from LZ_STX or LZ_SOH to the terminating LZ_ETX). You must
X * force a reinitialization -- by calling outputcode() with a new header --
X * if size is changed. If the "newer" output format is chosen (with
X * data streams delimited by LZ_SOH/LZ_STX, init_compress will be
X * called automatically. Otherwise, you must call init_compress(TRUE)
X * before calling compress() for the first time.
X */
X{
X`009register long`009`009hash_code;`009/* What we look for`009*/
X`009register code_int`009i;`009`009/* Index into vectors`009*/
X`009register int`009`009c;`009`009/* Current input char`009*/
X`009register code_int`009code;`009`009/* Substring code`009*/
X`009register int`009`009displacement;`009/* For secondary hash`009*/
X`009register code_int`009hsize_reg;`009/* Size of hash table`009*/
X`009register int`009`009hshift;`009`009/* For xor hasher`009*/
X
X`009if ((code = GET(in)) == EOF)
X`009 return;
X`009in_count++;
X`009hsize_reg = hsize;
X`009/*
X`009 * Set hash code range bound
X`009 */
X`009hshift = 0;
X`009for (hash_code = (long) hsize; hash_code < 65536L; hash_code <<= 1)
X`009 hshift++;
X`009hshift = 8 - hshift;
X`009while ((c = GET(in)) != (unsigned) EOF) {
X`009 in_count++;
X`009 hash_code = (long) (((long) c << maxbits) + code);
X`009 i = (c << hshift) ^ code;`009`009/* XOR hashing`009`009*/
X`009 if (HASH(i) == hash_code) {`009`009/* Found at first slot?`009*/
X`009`009code = CODE(i);
X`009`009continue;
X`009 }
X`009 else if ((long) HASH(i) < 0)`009/* empty slot`009`009*/
X`009`009goto nomatch;
X`009 displacement = hsize_reg - i;`009/* secondary hash`009*/
X`009 if (i == 0)
X`009`009displacement = 1;
Xprobe:
X`009 if ((i -= displacement) < 0)`009/* Wrap around?`009`009*/
X`009`009i += hsize_reg;
X`009 if (HASH(i) == hash_code) {`009`009/* Found in hash table?`009*/
X`009`009code = CODE(i);`009`009`009/* Set new prefix code`009*/
X`009`009continue;`009`009`009/* Read next input char`009*/
X`009 }
X`009 else if ((long) HASH(i) > 0)`009/* If slot is occupied`009*/
X`009`009goto probe;`009`009`009/* Look somewhere else`009*/
Xnomatch:
X`009 /*
X`009 * Output the current prefix and designate a new prefix.
X`009 * If the input character was the "hog", save it in the
X`009 * look-ahead cache table. Then, save in the hash table.
X`009 */
X`009 outputcode((code_int) code);`009/* No match, put prefix`009*/
X#if SIGNED_COMPARE_SLOW
X`009 if ((unsigned) next_code < (unsigned) maxmaxcode) {
X#else
X`009 if (next_code < maxmaxcode) {
X#endif
X`009`009CODE(i) = next_code++;`009`009/* code -> hashtable`009*/
X`009`009HASH(i) = hash_code;
X`009 }
X`009 else if (block_compress
X`009`009 && (count_int) in_count >= checkpoint) {
X`009`009clear();
X`009 }
X`009 code = c;`009`009`009`009/* Start new substring`009*/
X`009}
X`009/*
X`009 * At EOF, put out the final code.
X`009 */
X`009outputcode((code_int) code);
X}
X`012
Xclear()
X/*
X * Check the compression ratio to see whether it is going up
X * or staying the same. If it is going down, the internal
X * statistics of the file have changed, so clear out our
X * tables and start over. Inform the decompressor of the
X * change by sending out a LZ_CLEAR code.
X */
X{
X`009register long int`009rat;
X
X`009checkpoint = in_count + CHECK_GAP;
X#if DEBUG
X`009if (verbose > 2) {
X`009 divout("at clear() test", in_count, out_count, "");
X`009 fprintf(stderr, ", ratio at entry: %ld.%02ld, gap %d\n",
X`009`009rat / 256L, ((rat & 255L) * 100L) / 256L, CHECK_GAP);
X`009}
X#endif
X`009if (in_count > 0x007FFFFL) {`009`009/* Shift will overflow`009*/
X`009 rat = out_count >> 8;
X`009 if (rat == 0)
X`009`009rat = 0x7FFFFFFFL;
X`009 else {
X`009`009rat = in_count / rat;
X`009 }
X`009}
X`009else {
X`009 rat = (in_count << 8) / out_count;
X`009}
X`009if (rat > ratio)
X`009 ratio = rat;
X`009else {
X#if DEBUG
X`009 if (verbose > 0) {
X`009`009fprintf(stderr, "Resetting compression, in %ld, out %ld\n",
X`009`009 in_count, out_count);
X`009`009fprintf(stderr, "Old ratio: %ld == (%ld.%02ld)",
X`009`009 ratio, ratio / 256L, ((ratio & 255L) * 100L) / 256L);
X`009`009fprintf(stderr, ", test ratio: %ld = (%ld.%02ld), gap %d\n",
X`009`009 rat, rat / 256L, ((rat & 255L) * 100L) / 256L, CHECK_GAP);
X`009 }
X#endif
X`009 outputcode((code_int) LZ_CLEAR);`009/* Calls init_compress`009*/
X`009}
X}
X`012
Xinit_compress(full_init)
Xflag`009`009full_init;`009/* TRUE for full initialization`009`009*/
X/*
X * Clear the tables. Called by outputcode() on LZ_SOH, LZ_STX
X * (full_init TRUE) or on LZ_CLEAR (full_init FALSE).
X * init_compress() is not called on LZ_EOR.
X */
X{
X#ifdef XENIX_16
X`009register count_int`009*hp;
X`009register int`009`009n;
X`009register int`009`009j;
X`009register code_int`009k;
X
X`009k = hsize;
X`009for (j = 0; k > 0; k -= 8192) {
X`009 i = (k < 8192) ? k : 8192;
X`009 hp = hashtab[j++];
X`009 n = i >> 4;
X`009 switch (i & 15) {
X`009 case 15:`009*hp++ = -1;
X`009 case 14:`009*hp++ = -1;
X`009 case 13:`009*hp++ = -1;
X`009 case 12:`009*hp++ = -1;
X`009 case 11:`009*hp++ = -1;
X`009 case 10:`009*hp++ = -1;
X`009 case 9:`009*hp++ = -1;
X`009 case 8:`009*hp++ = -1;
X`009 case 7:`009*hp++ = -1;
X`009 case 6:`009*hp++ = -1;
X`009 case 5:`009*hp++ = -1;
X`009 case 4:`009*hp++ = -1;
X`009 case 3:`009*hp++ = -1;
X`009 case 2:`009*hp++ = -1;
X`009 case 1:`009*hp++ = -1;
X`009 }
X`009 while (--n >= 0) {
X`009`009*hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009`009*hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009`009*hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009`009*hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009 }
X`009}
X#else
X`009register count_int`009*hp;
X`009register code_int`009n;
X
X`009hp = &hashtab[0];
X`009n = hsize >> 4;`009`009`009/* divide by 16`009`009`009*/
X`009switch (hsize & 15) {
X`009case 15:`009*hp++ = -1;
X`009case 14:`009*hp++ = -1;
X`009case 13:`009*hp++ = -1;
X`009case 12:`009*hp++ = -1;
X`009case 11:`009*hp++ = -1;
X`009case 10:`009*hp++ = -1;
X`009case 9:`009*hp++ = -1;
X`009case 8:`009*hp++ = -1;
X`009case 7:`009*hp++ = -1;
X`009case 6:`009*hp++ = -1;
X`009case 5:`009*hp++ = -1;
X`009case 4:`009*hp++ = -1;
X`009case 3:`009*hp++ = -1;
X`009case 2:`009*hp++ = -1;
X`009case 1:`009*hp++ = -1;
X`009}
X`009while (--n >= 0) {
X`009 *hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009 *hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009 *hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009 *hp++ = -1; *hp++ = -1; *hp++ = -1; *hp++ = -1;
X`009}
X#endif
X`009if (full_init) {
X`009 tot_incount += in_count;
X`009 tot_outcount += out_count;
X`009 in_count = 0;
X`009 out_count = 0;
X`009 ratio = 0;
X`009}
X`009first_clear = FALSE;
X`009next_code = firstcode;
X}
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZCMP3.C"
$ CHECKSUM_IS = 1949626030
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X * `009`009`009l z c m p 3 . c
X * Output a given code.
X */
X#include "lz.h"
X
Xextern STREAM`009outstream;
Xextern code_int`009next_code;
Xextern code_int`009maxmaxcode;`009`009/* Actual maximum output code`009*/
Xextern short`009maxbits;
Xextern count_int out_count;
X
Xstatic char_type buf[BITS];
Xstatic int`009offset;
Xstatic short`009n_bits = INIT_BITS;`009/* # of bits in compressed file`009*/
Xstatic short`009n_bits8 = INIT_BITS << 3;
Xstatic code_int`009maxcode = MAXCODE(INIT_BITS);
X
X#if !vax_asm
Xstatic readonly char_type lmask[9] = {
X 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
X};
Xstatic readonly char_type rmask[9] = {
X 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
X};
X#endif
X
X#if DEBUG
Xextern int`009col;
Xstatic int`009todump;
X#endif
X
Xoutputcode(code)
Xcode_int code;
X/*
X * Output the given code.
X * Inputs:
X * `009code:`009A n_bits-bit integer. If == -1, then EOF. This assumes
X *`009`009that n_bits <= (long)wordsize - 1.
X * Note: if not in "export" mode, the following values are special:
X *`009LZ_CLEAR`009(also in export mode if block_compress TRUE)
X *`009`009`009(soft) clear out compress tables and reset the
X *`009`009`009number of bits per code to the minimum.
X *`009LZ_SOH, LZ_STX`009(hard) clear out compress tables and reset as above.
X *`009LZ_ETX, LZ_EOR`009force out the current output segment, analogous
X *`009`009`009to fflush.
X *`009`009`009
X * Outputs:
X * `009Outputs code to the file. If the codespace has filled
X *`009(next_code >= (1 << n_bits), increase n_bits.
X *`009If LZ_CLEAR, LZ_SOH, or LZ_STX is seen, reset n_bits
X *`009to the initial value and call init_compress to reset
X *`009the lookup and cache tables.
X *
X * Assumptions:
X *`009Output chars are 8 bits long. This is deeply hardwired
X *`009into the algorithm. It is independent, however, of the
X *`009size of the input data.
X *
X * Algorithm:
X * `009Maintain a BITS character long buffer (so that 8 codes will
X *`009fit in it exactly). Use the VAX insv instruction to insert each
X *`009code in turn. When the buffer fills up empty it and start over.
X */
X{
X`009/*
X`009 * On the VAX (Unix), it is important to have the register declarations
X`009 * in exactly the order given, or the asm will break.
X`009 */
X`009register int`009r_off, bits;
X`009register char_type`009*bp;
X#if !vax_asm
X`009register code_int`009r_code;
X#endif
X
X`009r_off = offset;
X`009bits = n_bits;
X`009bp = buf;
X`009if (code >= 0) {
X`009 /*
X`009 * Not at EOF, add the code
X`009 */
X#if DEBUG
X`009 if (verbose > 3) {
X`009`009fprintf(stderr, "%c%5d %5d",
X`009`009 ((col += 12) >= 72) ? (col = 0, '\n') : ' ',
X`009`009 code, next_code);
X`009`009if (code >= LZ_CLEAR && code < firstcode) {
X`009`009 fprintf(stderr, " = %s", lz_names[code - LZ_CLEAR]);
X`009`009 col = 74;
X`009`009}
X`009 }
X#endif
X#if vax_asm
X`009 /*
X`009 * VAX DEPENDENT!! Implementation on other machines may be
X`009 * difficult.
X`009 *
X`009 * Translation: Insert BITS bits from the argument starting at
X`009 * offset bits from the beginning of buf.
X`009 */
X`009 0;`009`009`009`009`009/* C compiler bug ??`009*/
X`009 asm("insv`0094(ap),r11,r10,(r9)");
X#else
X`009 /*
X`009 * WARNING: byte/bit numbering on the vax is simulated
X`009 * by the following code
X`009 */
X`009 bp += (r_off >> 3);`009`009`009/* -> first output slot`009*/
X`009 r_off &= 7;
X`009 /*
X`009 * Since code is always >= 8 bits, only need to mask the first
X`009 * hunk on the left.
X`009 */
X`009 r_code = code;
X`009 *bp = (*bp & rmask[r_off]) | (r_code << r_off) & lmask[r_off];
X`009 bp++;
X`009 bits -= (8 - r_off);
X`009 r_code >>= 8 - r_off;
X`009 /*
X`009 * Get any 8 bit parts in the middle ( <= 1 for up to 16 bits).
X`009 */
X`009 if (bits >= 8) {
X`009`009*bp++ = r_code;
X`009`009r_code >>= 8;
X`009`009bits -= 8;
X`009 }
X`009 if (bits != 0)`009`009`009`009/* Last bits. */
X`009`009*bp = r_code;
X#endif
X`009 offset += n_bits;
X`009 if (offset == n_bits8) {
X`009`009out_count += n_bits;
X`009`009lz_putbuf(buf, n_bits, &outstream);
X#if DEBUG
X`009`009if (todump > 0) {
X`009`009 dumphex(buf, n_bits, stderr);
X`009`009 todump -= n_bits;
X`009`009}
X#endif
X`009`009offset = 0;
X`009 }
X`009 /*
X`009 * If the next entry is going to be too big for the code size,
X`009 * then increase it, if possible. Note:
X`009 * !export`009`009`009firstcode == LZ_FIRST
X`009 *`009 export && block_compress`009firstcode == LZ_CLEAR + 1
X`009 *`009 export && !block_compress`009firstcode == LZ_CLEAR
X`009 */
X`009 if (next_code > maxcode) {
X`009`009if (offset > 0) {
X`009`009 lz_putbuf(buf, n_bits, &outstream);
X`009`009 out_count += n_bits;
X`009`009 offset = 0;
X#if DEBUG
X`009`009 if (todump > 0) {
X`009`009`009dumphex(buf, n_bits, stderr);
X`009`009`009todump -= n_bits;
X`009`009 }
X#endif
X`009`009}
X`009`009n_bits++;`009`009`009/* Need more bits`009*/
X`009`009n_bits8 += (1 << 3);
X`009`009if (n_bits == maxbits)
X`009`009 maxcode = maxmaxcode;
X`009`009else
X`009`009 maxcode = MAXCODE(n_bits);
X#if DEBUG
X`009`009if (verbose > 2) {
X`009`009 fprintf(stderr,
X`009`009`009"%snext_code %d, change to %d bits max %d",
X`009`009`009(col > 0) ? "\n" : "", next_code,
X`009`009`009n_bits, maxcode);
X`009`009 col = 74;
X`009`009}
X#endif
X`009 }
X`009 if (code >= LZ_CLEAR && code < firstcode) {
X`009`009switch (code) {
X`009`009case LZ_SOH:
X`009`009case LZ_STX:
X`009`009case LZ_CLEAR:
X`009`009 if (offset > 0) {
X`009`009`009lz_putbuf(buf, n_bits, &outstream);
X`009`009`009out_count += n_bits;
X`009`009`009offset = 0;
X#if DEBUG
X`009`009`009if (todump > 0) {
X`009`009`009 dumphex(buf, n_bits, stderr);
X`009`009`009 todump -= n_bits;
X`009`009`009}
X#endif
X`009`009 }
X`009`009 n_bits = INIT_BITS;`009`009/* Reset codes`009`009*/
X`009`009 n_bits8 = INIT_BITS << 3;
X`009`009 maxcode = MAXCODE(INIT_BITS);
X`009`009 init_compress(code != LZ_CLEAR);
X#if DEBUG
X`009`009 if (verbose > 2) {
X`009`009`009fprintf(stderr,
X`009`009 "\n(%s) Change to %d bits, maxcode %d, next_code = %d",
X`009`009`009 lz_names[code - LZ_CLEAR],
X`009`009`009 n_bits, maxcode, next_code);
X`009`009`009col = 74;
X`009`009`009todump = 32;
X`009`009 }
X#endif
X`009`009 break;
X
X`009`009case LZ_EOR:
X`009`009case LZ_ETX:`009`009`009/* Just written out`009*/
X`009`009 break;
X
X`009`009default:
X`009`009 abort();`009`009`009/* Can't happen`009`009*/
X`009`009}
X`009 }
X`009}
X`009else {
X`009 /*
X`009 * At EOF, write the rest of the buffer.
X`009 */
X`009 if ((r_off = offset) > 0) {
X`009`009r_off += 7;
X`009`009r_off >>= 3;
X`009`009lz_putbuf(buf, r_off, &outstream);
X`009`009out_count += r_off;
X#if DEBUG
X`009`009if (todump > 0) {
X`009`009 dumphex(buf, r_off, stderr);
X`009`009 todump -= r_off;
X`009`009}
X#endif
X`009 }
X`009 offset = 0;
X`009 lz_flush(&outstream);`009`009/* Flush output buffer`009*/
X#if DEBUG
X`009 if (verbose > 3 || todump > 0) {
X`009`009fprintf(stderr, "\n*EOF*\n");
X`009`009col = 0;
X`009 }
X#endif
X`009}
X}
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZDCM1.C"
$ CHECKSUM_IS = 828175667
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009lzdcmp [-options] [infile [outfile]]
X */
X#ifdef`009DOCUMENTATION
X
Xtitle`009lzdcmp`009File Decompression
Xindex`009`009File decompression
X
Xsynopsis
X`009.s.nf
X`009lzdcmp [-options] [infile [outfile]]
X`009.s.f
Xdescription
X
X`009lzdcmp decompresses files compressed by lzcomp. The
X`009documentation for lzcomp describes the process in
X`009greater detail.
X
X`009Options may be given in either case.
X`009.lm +8
X`009.p -8
X`009-B`009Output file is "binary", not text. (Ignored
X`009in VMS private mode.)
X`009.p -8
X`009-X 3`009To read files compressed by an old Unix version
X`009that doesn't generate header records.
X`009.p -8
X`009-V val`009Verbose (print status messages and debugging
X`009information). The value selects the amount of verbosity.
X
XAuthor
X
X`009This version by Martin Minow. See lzcomp for more
X`009details.
X
X#endif
X
X/*
X * Compatible with compress.c, v3.0 84/11/27
X */
X
X/*)BUILD
X`009`009$(PROGRAM) = lzdcmp
X`009`009$(INCLUDE) = lz.h
X`009`009$(CPP) = 1
X`009`009$(FILES) = { lzdcm1.c lzdcm2.c lzdcm3.c lzio.c lzvio.c }
X*/
X
X#include`009"lz.h"
X
X/*
X * These global parameters are read from the compressed file.
X * The decompressor needs them.
X */
Xshort`009`009maxbits = BITS;`009`009/* settable max # bits/code`009*/
Xcode_int`009maxmaxcode = 1 << BITS;
X
X/*
X * Note, if export is zero or 1, the "true" value will be set from
X * the file header. If it is 2, no header will be read.
X */
X#if VMS_V4
Xflag`009`009export = 0;`009`009/* Assume VMS private`009`009*/
X#else
Xflag`009`009export = 1;`009`009/* Assume Unix compatible`009*/
X#endif
Xflag`009`009binary = FALSE;`009`009/* Read text if false`009`009*/
Xflag`009`009block_compress = TRUE;`009/* TRUE if CLEAR enabled`009*/
Xflag`009`009noheader = FALSE;`009/* No magic header if TRUE`009*/
Xflag`009`009verbose = VERBOSE_DEFAULT; /* Non-zero for status/debug`009*/
Xflag`009`009background = FALSE;`009/* TRUE (Unix) if detached`009*/
Xflag`009`009is_compress = FALSE;`009/* For lzio.c (?)`009`009*/
Xchar`009`009*infilename = NULL;`009/* For error printouts`009`009*/
Xchar`009`009*outfilename = NULL;`009/* For openoutput and errors`009*/
Xint`009`009firstcode;`009`009/* First code after internals`009*/
Xstatic long`009start_time;`009`009/* Time we started (in msec)`009*/
Xextern long`009cputime();`009`009/* Returns process time in msec`009*/
Xjmp_buf`009`009failure;
XSTREAM`009`009instream;
XSTREAM`009`009outstream;
Xchar_type`009inbuffer[MAXIO];
Xchar_type`009outbuffer[MAXIO];
Xstatic STREAM`009mem_stream;
X#if VMS_V4
X#include
X#ifndef FDLSTUFF
X#define FDLSTUFF char
X#endif
XFDLSTUFF`009*fdl_input;
XFDLSTUFF`009*fdl_output;
Xstatic struct dsc$descriptor fdl_descriptor;
X#endif
X`012
Xmain(argc, argv)
Xint`009`009argc;
Xchar`009`009*argv[];
X/*
X * Decompress mainline
X */
X{
X`009int`009`009result;
X
X#ifndef`009decus
X`009/*
X`009 * background is TRUE if running detached from the command terminal.
X`009 */
X`009background = (signal(SIGINT, SIG_IGN) == SIG_IGN) ? TRUE : FALSE;
X`009if (!background)
X`009 background = !isatty(fileno(stderr));
X`009if (!background) {
X`009 if (verbose > 0)
X`009`009signal(SIGINT, abort);
X`009 else {
X`009`009signal(SIGINT, interrupt);
X`009`009signal(SIGSEGV, address_error);
X`009 }
X`009}
X#endif
X`009if (setjmp(failure) == 0) {
X`009 setup(argc, argv);
X`009 openinput();
X`009 get_magic_header();`009`009`009/* Sets export, etc.`009*/
X`009 openoutput();
X`009 if (verbose > 0)
X`009`009start_time = cputime();
X`009 init_decompress();
X`009 result = decompress(&outstream);
X`009 if (!export
X`009 && result != LZ_ETX
X`009 && getcode() != (code_int) LZ_ETX) {
X`009`009fprintf(stderr, "Decompress didn't finish correctly.\n");
X`009`009goto fail;
X`009 }
X`009 lz_flush(&outstream);
X#if DEBUG
X`009 if ((verbose & 04) != 0)
X`009`009dump_tab(stdout);
X#endif
X`009 if (verbose > 0) {
X`009`009start_time = cputime() - start_time;
X`009`009fprintf(stderr,
X`009`009 "%ld.%02ld seconds (process time) for decompression.\n",
X`009`009 start_time / 1000L, (start_time % 1000L) / 10L);
X`009 }
X`009 exit(IO_SUCCESS);
X`009}
X`009else {
Xfail:`009 fprintf(stderr, "Error when decompressing \"%s\" to \"%s\"\n",
X`009`009(infilename == NULL) ?
X`009`009 "" : infilename,
X`009`009(outfilename == NULL) ?
X`009`009 "" : outfilename);
X`009 if (errno != 0)
X`009`009perror("lzdcmp fatal error");
X`009 exit(IO_ERROR);
X`009}
X}
X`012
Xstatic
Xget_magic_header()
X{
X`009int`009`009head1;
X`009int`009`009head2;
X`009int`009`009head3;
X
X`009head2 = 0;
X`009if (export != 2) {
X`009 if ((head1 = GET(&instream)) != HEAD1_MAGIC) {
X`009`009fprintf(stderr, "Incorrect first header byte 0x%X\n",
X`009`009 head1);
X`009`009FAIL("can't get header");
X`009 }
X`009 head2 = GET(&instream);
X`009 head3 = GET(&instream);
X`009 switch (head2) {
X`009 case HEAD2_MAGIC:
X`009`009export = 1;
X`009`009break;
X
X`009 case VMS_HEAD2_MAGIC:
X`009`009export = 0;
X`009`009break;
X
X`009 default:
X`009`009fprintf(stderr, "Incorrect second header byte 0x%X\n",
X`009`009 head2);
X`009`009FAIL("can't get header");
X`009 }
X`009 maxbits = head3 & BIT_MASK;
X`009 block_compress = ((head3 & BLOCK_MASK) != 0) ? TRUE : FALSE;
X#if DEBUG
X`009 if (verbose > 1) {
X`009`009fprintf(stderr, "%s: compressed with %d bits,",
X`009`009 infilename, maxbits);
X`009`009fprintf(stderr, " block compression %s.\n",
X`009`009 (block_compress != 0) ? "enabled" : "disabled");
X`009 }
X#endif
X`009}
X`009if (maxbits > BITS) {
X`009 fprintf(stderr, "%s: compressed with %d bits,",
X`009`009infilename, maxbits);
X`009 fprintf(stderr, " lzdcmp can only handle %d bits\n", BITS);
X`009 FAIL("too many bits");
X`009}
X`009maxmaxcode = 1 << maxbits;
X`009if (export == 0)
X`009 firstcode = GET(&instream) + 0x100;`009/* From compressed file`009*/
X`009else if (block_compress)
X`009 firstcode = LZ_CLEAR + 1;`009`009/* Default`009`009*/
X`009else
X`009 firstcode = 256;`009`009`009/* Backwards compatible`009*/
X#if VMS_V4
X`009if (!export) {
X`009 register code_int`009code;
X`009 char`009`009text[256];
X`009 /*
X`009 * Get the attribute record.
X`009 */
X`009 if ((code = getcode()) != LZ_SOH) {
X`009`009fprintf(stderr, "Expected header, read 0x%X\n", code);
X`009`009FAIL("can't get header (private)");
X`009 }
X`009 init_decompress();
X`009 code = mem_decompress(text, sizeof text);
X`009 text[code] = EOS;
X`009 if (strncmp(text, ATT_NAME, ATT_SIZE) != 0) {
X`009`009fprintf(stderr, "Expected \"%s\", read \"%.*s\"\n",
X`009`009 ATT_NAME, code, text);
X`009`009FAIL("can't get attribute block header");
X`009 }
X`009 code = atoi(text + ATT_SIZE);
X`009 fdl_descriptor.dsc$a_pointer = malloc(code);
X`009 fdl_descriptor.dsc$w_length = code;
X`009 if ((code = mem_decompress(fdl_descriptor.dsc$a_pointer, code))
X`009`009 != fdl_descriptor.dsc$w_length) {
X`009`009fprintf(stderr, "\nError reading fdl attributes block,");
X`009`009fprintf(stderr, " expected %d bytes, read %d bytes\n",
X`009`009 fdl_descriptor.dsc$w_length, code);
X`009`009FAIL("can't get attribute block data");
X`009 }
X`009 if (verbose > 1) {
X`009`009fprintf(stderr, "\nFDL information read from \"%s\"\n",
X`009`009 infilename);
X`009`009fdl_dump(&fdl_descriptor, stderr);
X`009 }
X`009 if ((code = getcode()) != LZ_STX) {
X`009`009fprintf(stderr, "\nExpecting start of text, got 0x%X\n", code);
X`009`009FAIL("no start of text");
X`009 }
X`009}
X#endif
X}
X`012
Xint
Xmem_decompress(buffer, size)
Xchar_type`009*buffer;
Xint`009`009size;
X/*
X * Decompress up to size bytes to buffer. Return actual size.
X */
X{
X`009int`009`009result;
X
X`009mem_stream.bp = mem_stream.bstart = buffer;
X`009mem_stream.bend = buffer + size;
X`009mem_stream.bsize = size;
X`009mem_stream.func = lz_fail;
X`009if ((result = decompress(&mem_stream)) == LZ_EOR
X`009 || result == LZ_ETX)
X`009 return (mem_stream.bp - buffer);
X`009else {
X`009 fprintf(stderr, "Decompress to memory failed.\n");
X`009 FAIL("can't decompress to memory");
X`009}
X`009return (-1);`009`009`009`009/* Can't happen`009`009*/
X}
X`012
Xstatic readonly char *helptext[] = {
X`009"The following options are valid:",
X`009"-B\tBinary file (important on VMS/RSX, ignored on Unix)",
X`009"-M val\tSet the maximum number of code bits (unless header present)",
X`009"-V val\tPrint status information or debugging data.",
X`009"-X val\tSet export (compatibility) mode:",
X`009"-X 0\tVMS private mode",
X`009"-X 1\tCompatibility with Unix compress",
X`009"-X 2\tDo not read a header, disable \"block-compress\" mode",
X`009"\t(If a header is present, lzdcmp will properly configure itself,",
X`009"\toverriding the -X, -B and -M flag values.",
X`009NULL,
X};
X
Xstatic
Xsetup(argc, argv)
Xint`009`009argc;
Xchar`009`009*argv[];
X/*
X * Get parameters and open files. Exit fatally on errors.
X */
X{
X`009register char`009*ap;
X`009register int`009c;
X`009char`009`009**hp;
X`009auto int`009i;
X`009int`009`009j;
X
X#ifdef`009vms
X`009argc = getredirection(argc, argv);
X#endif
X`009for (i = j = 1; i < argc; i++) {
X`009 ap = argv[i];
X`009 if (*ap++ != '-' || *ap == EOS)`009/* Filename?`009`009*/
X`009`009argv[j++] = argv[i];`009`009/* Just copy it`009`009*/
X`009 else {
X`009`009while ((c = *ap++) != EOS) {
X`009`009 if (islower(c))
X`009`009`009c = toupper(c);
X`009`009 switch (c) {
X`009`009 case 'B':
X`009`009`009binary = TRUE;
X`009`009`009break;
X
X`009`009 case 'M':
X`009`009`009maxbits = getvalue(ap, &i, argv);
X`009`009`009if (maxbits < MIN_BITS) {
X`009`009`009 fprintf(stderr, "Illegal -M value\n");
X`009`009`009 goto usage;
X`009`009`009}
X`009`009`009break;
X
X`009`009 case 'V':
X`009`009`009verbose = getvalue(ap, &i, argv);
X`009`009`009break;
X
X`009`009 case 'X':
X`009`009`009export = getvalue(ap, &i, argv);
X`009`009`009if (export < 0 || export > 3) {
X`009`009`009 fprintf(stderr, "Illegal -X value: %d\n", export);
X`009`009`009 goto usage;
X`009`009`009}
X`009`009`009block_compress = (export < 2);
X`009`009`009noheader = (export == 3);
X`009`009`009break;
X
X`009`009 default:
X`009`009`009fprintf(stderr, "Unknown option '%c' in \"%s\"\n",
X`009`009`009`009*ap, argv[i]);
Xusage:`009`009`009for (hp = helptext; *hp != NULL; hp++)
X`009`009`009 fprintf(stderr, "%s\n", *hp);
X`009`009`009FAIL("unknown option");
X`009`009 }`009`009`009`009/* Switch on options`009*/
X`009`009}`009`009`009`009/* Everything for -xxx`009*/
X`009 }`009`009`009`009`009/* If -option`009`009*/
X`009}`009`009`009`009`009/* For all argc's`009*/
X`009/* infilename = NULL; */`009`009/* Set "stdin" signal`009*/
X`009/* outfilename = NULL; */`009`009/* Set "stdout" signal`009*/
X`009switch (j) {`009`009`009`009/* Any file arguments?`009*/
X`009case 3:`009`009`009`009`009/* both files given`009*/
X`009 if (!streq(argv[2], "-"))`009`009/* But - means stdout`009*/
X`009`009outfilename = argv[2];
X`009case 2:`009`009`009`009`009/* Input file given`009*/
X`009 if (!streq(argv[1], "-")) {
X`009`009infilename = argv[1];
X`009 }
X`009 break;
X
X`009case 0:`009`009`009`009`009/* None!`009`009*/
X`009case 1:`009`009`009`009`009/* No file arguments`009*/
X`009 break;
X
X`009default:
X`009 fprintf(stderr, "Too many file arguments\n");
X`009 FAIL("too many files");
X`009}
X}
X`012
Xstatic int
Xgetvalue(ap, ip, argv)
Xregister char`009`009*ap;
Xint`009`009`009*ip;
Xchar`009`009`009*argv[];
X/*
X * Compile a "value". We are currently scanning *ap, part of argv[*ip].
X * The following are possible:
X *`009-x123`009`009return (123) and set *ap to EOS so the caller
X *`009ap^`009`009cycles to the next argument.
X *
X *`009-x 123`009`009*ap == EOS and argv[*ip + 1][0] is a digit.
X *`009`009`009return (123) and increment *i to skip over the
X *`009`009`009next argument.
X *
X *`009-xy or -x y`009return(1), don't touch *ap or *ip.
X *
X * Note that the default for "flag option without value" is 1. This
X * can only cause a problem for the -M option where the value is
X * mandatory. However, the result of 1 is illegal as it is less
X * than INIT_BITS.
X */
X{
X`009register int`009result;
X`009register int`009i;
X
X`009i = *ip + 1;
X`009if (isdigit(*ap)) {
X`009 result = atoi(ap);
X`009 *ap = EOS;
X`009}
X`009else if (*ap == EOS
X`009 && argv[i] != NULL
X`009 && isdigit(argv[i][0])) {
X`009 result = atoi(argv[i]);
X`009 *ip = i;
X`009}
X`009else {
X`009 result = 1;
X`009}
X`009return (result);
X}
X`012
Xopeninput()
X{
X#ifdef`009decus
X`009if (infilename == NULL) {
X`009 infilename = malloc(257);
X`009 fgetname(stdin, infilename);
X`009 infilename = realloc(infilename, strlen(infilename) + 1);
X`009}
X`009if (freopen(infilename, "rn", stdin) == NULL) {
X`009 perror(infilename);
X`009 FAIL("can't open compressed input");
X`009}
X#else
X#ifdef vms
X#if VMS_V4
X`009if (!export) {
X`009 if (infilename == NULL) {
X`009`009infilename = malloc(256 + 1);
X`009`009fgetname(stdin, infilename);
X`009`009infilename = realloc(infilename, strlen(infilename) + 1);
X`009 }
X`009 if ((fdl_input = fdl_open(infilename, NULL)) == NULL) {
X`009`009fdl_message(NULL, infilename);
X`009`009FAIL("can't open compressed input (vms private)");
X`009 }
X`009}
X`009else
X#endif
X`009{
X`009 if (infilename == NULL) {
X`009`009infilename = malloc(256 + 1);
X`009`009fgetname(stdin, infilename);
X`009`009infilename = realloc(infilename, strlen(infilename) + 1);
X`009 }
X`009 else {
X`009`009if (freopen(infilename, "r", stdin) == NULL) {
X`009`009 perror(infilename);
X`009`009 FAIL("can't open compressed input (export)");
X`009`009}
X`009 }
X`009}
X#else
X`009if (infilename == NULL)
X`009 infilename = "";
X`009else {
X`009 if (freopen(infilename, "r", stdin) == NULL) {
X`009`009perror(infilename);
X`009`009FAIL("can't open input");
X`009 }
X`009}
X#endif
X#endif
X`009instream.bp = instream.bend = NULL;
X`009instream.bstart = inbuffer;
X`009instream.bsize = sizeof inbuffer;
X`009instream.func = lz_fill;
X}
X`012
Xopenoutput()
X{
X#ifdef vms
X#if VMS_V4
X`009if (!export) {
X`009 fclose(stdout);
X`009 stdout = NULL;
X`009 if ((fdl_output =
X`009`009 fdl_create(&fdl_descriptor, outfilename)) == NULL) {
X`009`009fprintf(stderr, "Can't create output file\n");
X`009`009if ((fdl_status & 01) == 0)
X`009`009 fdl_message(NULL, outfilename);
X`009`009FAIL("can't create output (vms private)");
X`009 }
X`009 if (outfilename == NULL) {
X`009`009outfilename = malloc(256 + 1);
X`009`009fdl_getname(fdl_output, outfilename);
X`009`009outfilename = realloc(outfilename, strlen(outfilename) + 1);
X`009 }
X`009}
X`009else
X#endif
X`009{
X`009 /*
X`009 * Not VMS Version 4, or export mode.
X`009 */
X`009 if (outfilename == NULL) {
X`009`009outfilename = malloc(256 + 1);
X`009`009fgetname(stdout, outfilename);
X`009`009outfilename = realloc(outfilename, strlen(outfilename) + 1);
X`009`009if (!binary)
X`009`009 goto do_reopen;
X`009 }
X`009 else {
X`009`009if (binary) {
X`009`009 if (freopen(outfilename, "w", stdout) == NULL) {
X`009`009`009perror(outfilename);
X`009`009`009FAIL("can't create output (binary)");
X`009`009 }
X`009`009}
X`009`009else {
X`009`009 int`009`009i;
Xdo_reopen:
X`009`009 if ((i = creat(outfilename, 0, "rat=cr", "rfm=var")) == -1
X`009`009 || dup2(i, fileno(stdout)) == -1) {
X`009`009`009perror(outfilename);
X`009`009`009FAIL("can't create output (text)");
X`009`009 }
X`009`009}
X`009 }
X`009}
X#else
X#ifdef decus
X`009if (outfilename == NULL) {
X`009 outfilename = malloc(256 + 1);
X`009 fgetname(stdout, outfilename);
X`009 outfilename = realloc(outfilename, strlen(outfilename) + 1);
X`009 if (binary) {
X`009`009if (freopen(outfilename, "wn", stdout) == NULL) {
X`009`009 perror(outfilename);
X`009`009 FAIL("can't create (binary)");
X`009`009}
X`009 }
X`009}
X`009else {
X`009 if (freopen(outfilename, (binary) ? "wn" : "w", stdout) == NULL) {
X`009`009perror(outfilename);
X`009`009FAIL("can't create");
X`009 }
X`009}
X#else
X`009if (outfilename == NULL)
X`009 outfilename = "";
X`009else {
X`009 if (freopen(outfilename, "w", stdout) == NULL) {
X`009`009perror(outfilename);
X`009`009FAIL("can't create");
X`009 }
X`009}
X#endif
X#endif
X`009outstream.bp = outstream.bstart = outbuffer;
X`009outstream.bend = outbuffer + sizeof outbuffer;
X`009outstream.bsize = sizeof outbuffer;
X`009outstream.func = lz_flush;
X}
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZDCM2.C"
$ CHECKSUM_IS = 1161199679
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009`009l z d c m 2 . c
X *
X * Actual decompression code
X */
X
X#include "lz.h"
X
X/*
X * These global parameters are read from the compressed file.
X * The decompressor needs them.
X */
Xextern short`009maxbits;`009`009/* settable max # bits/code`009*/
Xextern code_int`009maxmaxcode;`009`009/* 1 << maxbits`009`009`009*/
X
Xstatic flag`009first_clear = TRUE;
X
X/*
X * Big data storage stuff
X */
X
Xstatic char_type`009stack[MAXSTACK];
X#define`009STACK_TOP`009(&stack[MAXSTACK])
Xstatic U_short`009`009tab_prefix[1 << BITS];`009/* prefix code`009`009*/
Xstatic char_type `009tab_suffix[1 << BITS];`009/* last char in string`009*/
Xcode_int`009`009next_code;
X
X#if DEBUG
X#define`009CHECK(what)`009`009`009`009`009`009\
X`009if (stp <= stack) {`009`009`009`009`009\
X`009 fprintf(stderr, "Stack overflow -- %s\n", what);`009\
X`009 abort();`009`009`009`009`009`009\
X`009}
X#else
X#define CHECK(what)
X#endif
X`012
Xint
Xdecompress(out)
XSTREAM`009`009*out;
X/*
X * Decompress instream (global) to out. Returns "end" signal:
X *`009-1`009end of file
X *`009LZ_EOR`009end of record
X *`009LZ_ETX`009end of segment
X */
X{
X`009register char_type`009*stp;`009`009/* Stack pointer`009*/
X`009register code_int code, oldcode, incode;
X`009register int`009`009final;`009/* End of a sequence?`009*/
X`009extern code_int`009`009getcode();
X
X`009stp = STACK_TOP;
X`009final = oldcode = getcode();
X`009PUT((char) final, out);
X`009while ((code = getcode()) >= 0) {
Xtest:`009 if (code >= LZ_CLEAR && code < firstcode) {
X`009`009lz_putbuf(stp, STACK_TOP - stp, out);
X`009`009stp = STACK_TOP;
X`009`009switch (code) {
X`009`009case LZ_ETX:
X`009`009case LZ_EOR:
X`009`009 goto finish;
X
X`009`009case LZ_SOH:`009`009`009/* Unexpected`009`009*/
X`009`009case LZ_STX:`009`009`009/* Unexpected`009`009*/
X`009`009default:
X`009`009 fprintf(stderr, "\nUnexpected control 0x%X\n", code);
X`009`009 FAIL("Unexpected control");
X
X`009`009case LZ_CLEAR:
X`009`009 init_decompress();`009`009/* Before getcode() !! */
X`009`009 if ((code = getcode()) < 0
X`009`009 || (export && code == LZ_CLEAR))
X`009`009`009goto finish;
X`009`009 else {
X`009`009`009/*
X`009`009`009 * init_decompress has set next_code to firstcode,
X`009`009`009 * however, for magical reasons, we want to toss
X`009`009`009 * the next substring, so we set next_code so
X`009`009`009 * that the tab_... entry is effectively ignored.
X`009`009`009 * Note below that tab_prefix[next_code] is set
X`009`009`009 * to the character before the LZ_CLEAR and
X`009`009`009 * tab_suffix to the character after the LZ_CLEAR.
X`009`009`009 * But, these values have no relationship to one
X`009`009`009 * another, so, by decrementing next_code, they
X`009`009`009 * will be ignored. (I think.)
X`009`009`009 */
X`009`009`009next_code--;
X`009`009`009goto test;
X`009`009 }
X`009`009}
X`009 }
X`009 incode = code;
X`009 /*
X`009 * Special case for KwKwK string.
X`009 */
X`009 if (code >= next_code) {
X`009`009CHECK("KwKwK");
X`009`009*--stp = final;
X`009`009code = oldcode;
X`009 }
X`009 /*
X`009 * Generate output characters in reverse order
X`009 */
X#ifdef interdata
X`009 while (((unsigned long) code) >= ((unsigned long) NBR_CHAR)) {
X#else
X`009 while (code >= NBR_CHAR) {
X#endif
X`009`009CHECK("generate output");
X`009`009*--stp = tab_suffix[code];
X`009`009code = tab_prefix[code];
X`009 }
X`009 CHECK("final char");
X`009 *--stp = final = tab_suffix[code];
X`009 /*
X`009 * And put them out in forward order
X`009 */
X`009 lz_putbuf(stp, STACK_TOP - stp, out);
X`009 stp = STACK_TOP;
X`009 /*
X`009 * Generate the new entry.
X`009 */
X`009 if ((code = next_code) < maxmaxcode) {
X`009`009tab_prefix[code] = (U_short) oldcode;
X`009`009tab_suffix[code] = final;
X`009`009next_code++;
X`009 }
X`009 /*
X`009 * Remember previous code.
X`009 */
X`009 oldcode = incode;
X`009}
Xfinish:
X`009return (code);
X}
X`012
Xinit_decompress()
X/*
X * Called on cold start, or on LZ_SOH, LZ_STX, LZ_CLEAR.
X */
X{
X`009register char_type`009*cp;
X`009register U_short`009*up;
X`009register int`009`009code;
X
X`009if (first_clear) {
X`009 for (cp = &tab_suffix[0], code = 0; cp < &tab_suffix[NBR_CHAR];)
X`009`009*cp++ = code++;
X`009 first_clear = FALSE;
X`009}
X`009else {
X#if ((NBR_CHAR % 8) != 0)
X`009 << error, the following won't work >>
X#endif
X`009 for (up = &tab_prefix[0]; up < &tab_prefix[NBR_CHAR];) {
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009`009*up++ = 0;
X`009 }
X`009}
X`009next_code = firstcode;
X}
X`012
X#if DEBUG
Xdump_tab(dumpfd)
XFILE`009`009*dumpfd;
X/*
X * dump string table
X */
X{
X`009register char_type`009*stp;`009/* Stack pointer`009`009*/
X`009register int`009`009i;
X`009register int`009`009ent;
X`009extern char`009`009*dumpchar();
X
X`009stp = STACK_TOP;
X`009fprintf(dumpfd, "%d %s in string table\n",
X`009 next_code, (next_code == 1) ? "entry" : "entries");
X`009for (i = 0; i < next_code; i++) {
X`009 fprintf(dumpfd, "%5d: %5d/'%s' ",
X`009`009i, tab_prefix[i], dumpchar(tab_suffix[i]));
X`009 for (ent = i;;) {
X`009`009*--stp = tab_suffix[ent];
X`009`009if (ent < firstcode)
X`009`009 break;
X`009`009ent = tab_prefix[ent];
X`009 }
X`009 dumptext(stp, STACK_TOP - stp, dumpfd);
X`009 stp = STACK_TOP;
X`009}
X}
X#endif
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZDCM3.C"
$ CHECKSUM_IS = 1679715766
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009`009l z d c m 3 . c
X *
X * Read codes from the input stream.
X */
X
X#include "lz.h"
X
X
X#if !vax_asm
Xstatic readonly char_type rmask[9] = {
X`0090x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
X};
X#endif
X#if DEBUG
Xextern int`009col;
Xstatic int`009todump;
X#endif
X
X/*
X * getcode()
X *
X * Read one code from the standard input. If EOF, return -1.
X * Inputs:
X * `009stdin (via GET)
X * Outputs:
X * `009code or -1 is returned.
X */
X
Xextern code_int`009`009next_code;
Xextern STREAM`009`009instream;
Xextern code_int`009`009maxmaxcode;
Xextern short`009`009maxbits;
Xstatic short`009`009n_bits = INIT_BITS;
Xstatic code_int`009`009maxcode = MAXCODE(INIT_BITS);
X
X/*
X * buf[] contains 8-bit data read from the input stream. getcode()
X * treats buf[] as a vector of bits, repacking it into variable-bit codes.
X */
Xstatic char_type`009buf[BITS];
Xstatic int`009`009offset = 0;`009/* Offset into buf IN BITS `009*/
Xstatic int`009`009size = 0;`009/* Actual size of buf IN BITS `009*/
X
Xcode_int
Xgetcode()
X{
X`009/*
X`009 * On the VAX (4.2 bsd), it is important to have the register
X`009 * declarations in exactly the order given, or the asm will break.
X`009 */
X`009register code_int `009code;
X`009register int`009`009r_off, bits;
X`009register char_type`009*bp;
X
X`009bp = buf;
X`009if (next_code > maxcode) {
X`009 n_bits++;
X`009 if (n_bits == maxbits)
X`009`009maxcode = maxmaxcode;
X`009 else {
X`009`009maxcode = MAXCODE(n_bits);
X`009 }
X`009 size = 0;
X#if DEBUG
X`009 if (verbose > 2) {
X`009`009fprintf(stderr, "\nChange to %d bits", n_bits);
X`009`009col = 74;
X`009 }
X#endif
X`009}
X`009if (offset >= size) {
X`009 size = lz_getbuf(buf, n_bits, &instream);
X#if DEBUG
X`009 if (verbose > 4 || todump > 0) {
X`009`009dumphex(buf, size, stderr);
X`009`009if (todump > 0)
X`009`009 todump -= size;
X`009 }
X#endif
X`009 if (size <= 0)
X`009`009return (-1);`009`009`009/* end of file`009`009*/
X`009 offset = 0;
X`009 /*
X`009 * Round size down to integral number of codes in the buffer.
X`009 * (Expressed as a number of bits).
X`009 */
X`009 size = (size << 3) - (n_bits - 1);
X`009}
X`009r_off = offset;
X`009bits = n_bits;
X#if vax_asm
X`009asm("extzv r10,r9,(r8),r11");
X#else
X`009/*
X`009 * Get to the first byte.
X`009 */
X`009bp += (r_off >> 3);
X`009r_off &= 7;
X`009/*
X`009 * Get first part (low order bits)
X`009 */
X#if UCHAR
X`009code = (*bp++ >> r_off);
X#else
X`009/*
X`009 * Don't touch the 0xFF; it prevents sign extension.
X`009 */
X`009code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xFF;
X#endif
X`009bits -= (8 - r_off);
X`009r_off = 8 - r_off;`009`009/* now, offset into code word`009*/
X`009/*
X`009 * Get any 8 bit parts in the middle (<=1 for up to 16 bits).
X`009 */
X`009if (bits >= 8) {
X#if UCHAR
X`009 code |= *bp++ << r_off;
X#else
X`009 code |= (*bp++ & 0xFF) << r_off;
X#endif
X`009 r_off += 8;
X`009 bits -= 8;
X`009}
X`009/* high order bits. */
X#if UCHAR
X`009code |= (*bp & rmask[bits]) << r_off;
X#else
X`009code |= (*bp & rmask[bits]) << r_off;
X#endif
X`009/*
X`009 * End of non-vax (Unix) specific code.
X`009 */
X#endif
X`009offset += n_bits;
X`009if (code >= LZ_CLEAR && code < firstcode) {
X`009 switch (code) {
X`009 case LZ_SOH:
X`009 case LZ_STX:
X`009 case LZ_CLEAR:
X`009`009size = 0;`009`009`009/* Force read next time`009*/
X`009`009n_bits = INIT_BITS;
X`009`009maxcode = MAXCODE(INIT_BITS);
X#if DEBUG
X`009`009if (verbose > 1) {
X`009`009 fprintf(stderr, "Read %s (%d)\n",
X`009`009`009lz_names[code - LZ_CLEAR], code);
X`009`009 todump = 32;
X`009`009}
X#endif
X`009`009break;
X`009 }
X`009}
X#if DEBUG
X`009if (verbose > 3) {
X`009 fprintf(stderr, "%c%5d %5d",
X`009`009((col += 12) >= 72) ? (col = 0, '\n') : ' ',
X`009`009code, next_code);
X`009 if (code >= LZ_CLEAR && code < firstcode) {
X`009`009fprintf(stderr, " = %s", lz_names[code - LZ_CLEAR]);
X`009 col = 74;
X`009 }
X`009}
X#endif
X`009return (code);
X}
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZIO.C"
$ CHECKSUM_IS = 1214693144
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009`009l z i o . c
X *
X * I/O buffer management. All input/output I/O is done through these
X * routines (and the macros in lz.h). The rules of the game are:
X *
X * input via GET() and getbuf().
X *`009GET returns an 8-bit byte, or -1 on eof/error.
X *`009getbuf() returns the number of things gotten, or -1 on eof/error.
X *`009No return on error: longjmp's to the main-line.
X *
X * output via PUT() and lz_putbuf().
X *`009No return on error: longjmp's to the main-line.
X * flush output by lz_flush() before closing files -- or you'll lose data.
X */
X
X#include`009"lz.h"
X#if VMS_V4
X#include`009
X#ifndef FDLSTUFF
X#define FDLSTUFF char
X#endif
Xextern FDLSTUFF *fdl_input;
Xextern FDLSTUFF *fdl_output;
Xextern int`009fdl_status;
X#endif
X`012
Xint
Xlz_fill(s)
Xregister STREAM`009`009*s;
X{
X`009register int`009i;
X`009extern char`009*infilename;
X
X#if VMS_V4
X`009if (export && is_compress) {
X`009 i = fread((char *) s->bstart, 1, s->bsize, stdin);
X`009 if (ferror(stdin)) {
X`009`009perror(infilename);
X`009`009FAIL("export && is_compress fread error");
X`009 }
X`009}
X`009else {`009`009`009/* Decompress and export/private`009*/
X`009 i = fdl_read(s->bstart, s->bsize, fdl_input);
X`009 if (i < 0 && fdl_status != RMS$_EOF)
X`009`009fdl_message(fdl_input, "Read error");
X`009}
X#else
X#ifdef unix
X`009i = read(fileno(stdin), (char *) s->bstart, s->bsize);
X`009if (i < 0) {
X`009 perror(infilename);
X`009 FAIL("unix read error");
X`009}
X#else
X`009i = fread((char *) s->bstart, 1, s->bsize, stdin);
X`009if (ferror(stdin)) {
X`009 perror(infilename);
X`009 exit(IO_ERROR);
X`009}
X#endif
X#endif
X`009if (i <= 0)
X`009 return (EOF);
X`009else {
X`009 s->bp = s->bstart;
X`009 s->bend = &s->bstart[i];
X#if UCHAR
X`009 return (*s->bp++);
X#else
X`009 return (*s->bp++ & 0xFF);
X#endif
X`009}
X}
X`012
Xlz_flush(s)
Xregister STREAM`009*s;
X{
X`009register int`009count;
X`009extern char`009*outfilename;
X
X`009count = s->bp - s->bstart;
X#if DEBUG
X`009if (!is_compress && verbose > 4) {
X`009 fprintf(stderr, "lz_flush %d: ", count);
X`009 dumptext(s->bstart, count, stderr);
X`009}
X#endif
X#if VMS_V4
X`009if (export) {
X`009 if (is_compress)
X`009`009fwrite((char *) s->bstart, count, 1, stdout);
X`009 else {
X`009`009register char *bp, *bend;
X
X`009`009for (bp = s->bstart, bend = bp + count; bp < bend; bp++)
X`009`009 putchar(*bp);
X`009 }
X`009 if (ferror(stdout)) {
X`009`009perror(outfilename);
X`009`009FAIL("VMS V4 fwrite/putchar error");
X`009 }
X`009}
X`009else {
X`009 if (fdl_write((char *) s->bstart, count, fdl_output) == -1) {
X`009`009fdl_message(fdl_output, "Write error");
X`009`009FAIL("VMS V4 fdl_write error");
X`009 }
X`009}
X#else
X#ifdef unix
X`009if (write(fileno(stdout), (char *) s->bstart, count) != count) {
X`009 perror(outfilename);
X`009 fprintf(stderr, "Can't write to \"%s\"\n", outfilename);
X`009 FAIL("Unix write error");
X`009}
X#else
X`009fwrite((char *) s->bstart, 1, count, stdout);
X`009if (ferror(stdout)) {
X`009 perror(outfilename);
X`009 FAIL("Other (decus) fwrite error");
X`009}
X#endif
X#endif
X`009s->bp = s->bstart;
X}
X`012
Xint
Xlz_getbuf(buffer, count, s)
Xchar_type`009`009*buffer;
Xint`009`009`009count;
Xregister STREAM`009`009*s;
X/*
X * Read a block of data -- be clever. Return number gotten, or -1
X * on eof.
X */
X{
X`009register char_type`009*bp;`009`009/* -> buffer`009`009*/
X`009register char_type`009*ip;`009`009/* -> I/O buffer`009*/
X`009register char_type`009*ep;`009`009/* End of segment`009*/
X`009register int`009`009remaining;`009/* Size of segment`009*/
X`009int`009`009`009datum;
X
X`009if (count == 0)`009`009`009`009/* Shouldn't happen`009*/
X`009 return (0);
X`009bp = buffer;
X`009while (--count >= 0) {
X`009 if ((datum = GET(s)) == EOF)`009/* Maybe fill LZ buff`009*/
X`009`009break;
X`009 *bp++ = datum;
X`009 remaining = s->bend - (ip = s->bp);
X`009 if (remaining > count)
X`009`009remaining = count;
X`009 ep = &ip[remaining];
X`009 while (ip < ep)
X`009`009*bp++ = *ip++;
X`009 count -= remaining;
X`009 s->bp = ip;`009`009`009`009/* Refresh buffer`009*/
X`009}
X`009return ((bp == buffer) ? -1 : bp - buffer);
X}
X`012
Xint
Xlz_putbuf(bp, count, s)
Xregister char_type`009*bp;
Xint`009`009`009count;
Xregister STREAM`009`009*s;
X/*
X * Write a block of data -- be clever.
X */
X{
X`009register char_type`009*op;`009`009/* -> I/O buffer`009*/
X`009register char_type`009*ep;`009`009/* End of segment`009*/
X`009register int`009`009remaining;`009/* Size of segment`009*/
X
X`009while (--count >= 0) {
X`009 PUT(*bp++, s);`009`009`009/* Forces a buffer`009*/
X`009 remaining = s->bend - (op = s->bp);
X`009 if (remaining > count)
X`009`009remaining = count;
X`009 ep = &op[remaining];
X`009 while (op < ep)
X`009`009*op++ = *bp++;
X`009 count -= remaining;
X`009 s->bp = op;`009`009`009`009/* Refresh buffer`009*/
X`009}
X}
X`012
Xint
Xlz_eof(s)
XSTREAM`009`009*s;
X/*
X * Dummy routine for read from memory -- returns EOF.
X */
X{
X`009return (s, EOF);
X}
X
Xint
Xlz_fail(s)
XSTREAM`009`009*s;
X/*
X * Dummy routine for write to memory -- called if buffer fills.
X */
X{
X`009fprintf(stderr, "Memory buffer [%d bytes] filled -- fatal.\n",
X`009`009s->bsize);
X`009FAIL("lz_fail crash");
X}
X
Xint
Xlz_dummy(s)
XSTREAM`009`009*s;
X/*
X * Dummy routine for write to memory -- writes to the bit-bucket.
X */
X{
X`009s->bp = s->bstart;
X}
X`012
X#ifndef decus
X/*
X * Signal error handlers.
X */
X#ifdef vms
X#define unlink`009delete
X#endif
X
Xinterrupt()
X{
X`009if (outfilename != NULL && !streq(outfilename, ""))
X`009 unlink(outfilename);
X`009exit(IO_ERROR);
X}
X
Xaddress_error()
X{
X`009if (!is_compress)
X`009 fprintf(stderr, "Decompress: corrupt input file\n");
X`009interrupt();
X}
X#endif
X`012
X/*
X * getredirection() is intended to aid in porting C programs
X * to VMS (Vax-11 C) which does not support '>' and '<'
X * I/O redirection. With suitable modification, it may
X * useful for other portability problems as well.
X */
X
X#ifdef`009vms
X
Xint
Xgetredirection(argc, argv)
Xint`009`009argc;
Xchar`009`009**argv;
X/*
X * Process vms redirection arg's. Exit if any error is seen.
X * If getredirection() processes an argument, it is erased
X * from the vector. getredirection() returns a new argc value.
X *
X * Warning: do not try to simplify the code for vms. The code
X * presupposes that getredirection() is called before any data is
X * read from stdin or written to stdout.
X *
X * Normal usage is as follows:
X *
X *`009main(argc, argv)
X *`009int`009`009argc;
X *`009char`009`009*argv[];
X *`009{
X *`009`009argc = getredirection(argc, argv);
X *`009}
X */
X{
X`009register char`009`009*ap;`009/* Argument pointer`009*/
X`009int`009`009`009i;`009/* argv[] index`009`009*/
X`009int`009`009`009j;`009/* Output index`009`009*/
X`009int`009`009`009file;`009/* File_descriptor `009*/
X
X`009for (j = i = 1; i < argc; i++) { /* Do all arguments`009*/
X`009 switch (*(ap = argv[i])) {
X`009 case '<':`009`009`009/* ':`009`009`009/* >file or >>file`009*/
X`009`009if (*++ap == '>') {`009/* >>file`009`009*/
X`009`009 /*
X`009`009 * If the file exists, and is writable by us,
X`009`009 * call freopen to append to the file (using the
X`009`009 * file's current attributes). Otherwise, create
X`009`009 * a new file with "vanilla" attributes as if
X`009`009 * the argument was given as ">filename".
X`009`009 * access(name, 2) is TRUE if we can write on
X`009`009 * the specified file.
X`009`009 */
X`009`009 if (access(++ap, 2) == 0) {
X`009`009`009if (freopen(ap, "a", stdout) != NULL)
X`009`009`009 break;`009/* Exit case statement`009*/
X`009`009`009perror(ap);`009/* Error, can't append`009*/
X`009`009`009exit(IO_ERROR);`009/* After access test`009*/
X`009`009 }`009`009`009/* If file accessable`009*/
X`009`009}
X`009`009/*
X`009`009 * On vms, we want to create the file using "standard"
X`009`009 * record attributes. create(...) creates the file
X`009`009 * using the caller's default protection mask and
X`009`009 * "variable length, implied carriage return"
X`009`009 * attributes. dup2() associates the file with stdout.
X`009`009 */
X`009`009if (freopen(ap, "w", stdout, "rat=cr", "rfm=var") == NULL) {
X`009`009 perror(ap);`009`009/* Can't create file`009*/
X`009`009 exit(IO_ERROR);`009/* is a fatal error`009*/
X`009`009}`009`009`009/* If '>' creation`009*/
X`009`009break;`009`009`009/* Exit case test`009*/
X
X`009 default:
X`009`009argv[j++] = ap;`009`009/* Not a redirector`009*/
X`009`009break;`009`009`009/* Exit case test`009*/
X`009 }
X`009}`009`009`009`009/* For all arguments`009*/
X`009argv[j] = NULL;`009`009`009/* Terminate argv[]`009*/
X`009return (j);`009`009`009/* Return new argc`009*/
X}
X#endif
X`012
X#if 1 || DEBUG
X
Xint`009`009col;
X
Xreadonly char *lz_names[] = {
X "LZ_CLEAR", "LZ_SOH", "LZ_STX", "LZ_EOR", "LZ_ETX", "???"
X};
X
Xdumphex(buffer, count, fd)
Xregister char_type`009*buffer;
Xregister int`009`009count;
XFILE`009`009`009*fd;
X{
X`009if (col > 0) {
X`009 putc('\n', fd);
X`009 col = 0;
X`009}
X`009fprintf(fd, "%2d:", count);
X`009while (--count >= 0) {
X`009 fprintf(fd, " %02x", *buffer++ & 0xFF);
X`009}
X`009fprintf(fd, "\n");
X}
X
Xdumptext(buffer, count, fd)
Xregister char_type`009*buffer;
Xint`009`009`009count;
XFILE`009`009`009*fd;
X{
X`009extern char`009*dumpchar();
X
X`009putc('"', fd);
X`009while (--count >= 0)
X`009 fputs(dumpchar((int) *buffer++), fd);
X`009fputs("\"\n", fd);
X}
X
Xchar *
Xdumpchar(c)
Xregister int`009c;
X/*
X * Make a character printable. Returns a static pointer.
X */
X{
X`009static char`009dump_buffer[8];
X
X`009c &= 0xFF;
X`009if (isascii(c) && isprint(c)) {
X`009 dump_buffer[0] = c;
X`009 dump_buffer[1] = EOS;
X`009}
X`009else {
X`009 switch (c) {
X`009 case '\n':`009return ("\\n");
X`009 case '\t':`009return ("\\t");
X`009 case '\b':`009return ("\\b");
X`009 case '\f':`009return ("\\f");
X`009 case '\r':`009return ("\\r");
X`009 }
X`009 sprintf(dump_buffer, "", c);
X`009}
X`009return (dump_buffer);
X}
X#endif
X`012
X/*
X * Cputime returns the elapsed process time (where available) in msec.
X * Note: Unix doesn't seem to have a good way to determine ticks/sec.
X */
X
X#ifdef`009decus
X#include`009
X
Xlong
Xcputime()
X{
X`009struct timeb`009`009buf;
X`009static struct timeb`009origin;
X`009long`009`009`009result;
X`009int`009`009`009msec;
X
X`009if (origin.time == 0)
X`009 ftime(&origin);
X`009ftime(&buf);
X`009result = (buf.time - origin.time) * 1000;
X`009msec = ((int) buf.msec) - ((int) origin.msec);
X`009return (result + ((long) msec));
X}
X#else
X#ifdef vms
X#include`009
Xstruct tms {
X`009time_t`009tms_utime;
X`009time_t`009tms_stime;
X`009time_t`009tms_uchild;`009/* forgot the */
X`009time_t`009tms_uchildsys;`009/* real names */
X};
X#define HERTZ`009100.0`009`009`009`009/* 10 msec units`009*/
X#else
X#include`009
X#include`009
X#ifndef HERTZ
X#define HERTZ`00960.0`009`009`009`009/* Change for Europe`009*/
X#endif
X#endif
X
Xlong
Xcputime()
X{
X`009struct tms`009tms;
X`009double`009`009temp;
X`009long`009`009result;
X
X`009times(&tms);
X`009result = tms.tms_utime + tms.tms_stime;
X`009temp = result * 1000.0 / HERTZ;`009`009/* Time in msec.`009*/
X`009result = temp;
X`009return (result);
X}
X#endif
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZVIO.C"
$ CHECKSUM_IS = 1412617984
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009`009l z v i o . c
X * For VMS V4 only.
X */
X
X/*
X * Problems:
X *`009If you open a second input file (getting rms attributes)
X *`009it aborts with an internal "fatal" error (15820C LIB-F-FATERRLIB)
X */
X
X/*
X * Make TESTING_FDLIO non-zero to enable test code.
X *
X * Edit History
X */
X#ifndef`009TESTING_FDLIO
X#define`009TESTING_FDLIO`0090
X#endif
X
X/*
X * RMS/FDL record level i/o routines for Vax-11 C V4 or greater only.
X * Rather crude.
X *
X * The following are provided:
X *
X *`009#define`009FDLSTUFF`009char
X *`009#include descrip
X *
X *`009FDLSTUFF *
X *`009fdl_open(filename, fdl_descriptor)
X *`009char`009`009`009*filename;
X *`009struct`009dsc$descriptor`009*fdl_descriptor;
X *`009`009Initializes internal buffers and opens this existing
X *`009`009file for input. The filename may not contain wildcards.
X *`009`009On (successful) return, fdl_descriptor will point to
X *`009`009an initialized fdl specification. The description
X *`009`009string will be in malloc'ed memory. The caller does not
X *`009`009initialize the fdl_descriptor. Returns NULL on error.
X *`009`009(Note an error will be returned if the file is not
X *`009`009block-oriented.)
X *
X *`009`009When you don't need the fdl_descriptor information
X *`009`009any more, free it by calling
X *`009`009 fdl_free(fdl_descriptor);
X *`009`009if fdl_descriptor is NULL on entry, the file is opened
X *`009`009normally (fdl information is not collected).
X *
X *`009FDLSTUFF *
X *`009fdl_create(fdl_descriptor, override_filename)
X *`009struct`009dsc$descriptor`009*fdl_descriptor;
X *`009char`009`009`009*override_filename;
X *`009`009Creates a file using the fdl specification.
X *`009`009If override_filename is not NULL and not equal to "",
X *`009`009it will override the filename specified in the fdl.
X *`009`009fdl_write() is used to write data to the file.
X *`009`009Returns NULL on error.
X *
X *`009`009if fdl_descriptor is NULL, the file is created using
X *`009`009the name in override_filename (which must be present).
X *`009`009The file is created in "undefined" record format.
X *
X *`009fdl_free(fdl_descriptor)
X *`009struct`009dsc$descriptor`009*fdl_descriptor;
X *`009`009Releases the fdl descriptor block.
X *
X *`009int
X *`009fdl_read(buffer, buffer_length, r)
X *`009char`009`009*buffer;
X *`009int`009`009buffer_length;
X *`009FDLSTUFF`009*r;
X *`009`009Read buffer_length bytes from the file (using SYS$READ).
X *`009`009No expansion or interpretation. buffer_length had
X *`009`009better be even or you're asking for trouble. Returns
X *`009`009the actual number of bytes read. The file has been
X *`009`009opened by fdl_open.
X *
X *`009int
X *`009fdl_write(buffer, buffer_length, r)
X *`009char`009`009*buffer;
X *`009int`009`009buffer_length;
X *`009FDLSTUFF`009*r;
X *`009`009Write buffer_length bytes to the file (using SYS$WRITE).
X *`009`009No expansion or interpretation. buffer_length had
X *`009`009better be even or you're asking for trouble. Returns
X *`009`009the actual number of bytes written. The file was opened
X *`009`009by fdl_create();
X *
X *`009fdl_getname(r, buffer)
X *`009FDLSTUFF`009*r;
X *`009char`009`009*buffer;
X *`009`009Copies the currently open file's name to the caller's
X *`009`009data buffer buffer.
X *
X *`009long
X *`009fdl_fsize(r)
X *`009`009Returns the size in bytes of the opened file.
X *
X *`009fdl_dump(fdl_descriptor, fd)
X *`009struct`009dsc$descriptor`009*fdl_descriptor;
X *`009FILE`009`009`009*fd;
X *`009`009Writes the fdl info to the indicated file with
X *`009`009line breaks in appropriate places.
X *
X *`009fdl_message(r, why)
X *`009FDLSTUFF`009*r;
X *`009char`009`009*why;
X *`009`009All system-level routines set a global value, fdl_status.
X *`009`009fdl_message() prints the error message text corresponding
X *`009`009to the current value of fdl_status. The message printed
X *`009`009has the format:
X *`009`009`009why current_filename: error_message.
X *`009`009If why is NULL, only the error_message is printed.
X */
X`012
X#include "lz.h"
X#if VMS_V4
X#include rms
X#include ssdef
X#include descrip
X#include devdef
X#ifndef`009FDL$M_FDL_SIGNAL
X#define FDL$M_FDL_SIGNAL`0091`009/* Signal errors if set`009`009*/
X#endif
X#ifndef`009FDL$M_FDL_STRING
X#define FDL$M_FDL_STRING`0092`009/* Use string for fdl text`009*/
X#endif
X#if TESTING_FDLIO
X#define`009SIGNAL_ON_ERROR`009FDL$M_FDL_SIGNAL
X#else
X#define`009SIGNAL_ON_ERROR`0090
X#endif
X
X#define`009TRUE`0091
X#define`009FALSE`0090
X#define`009EOS`0090
X
Xtypedef struct FDLSTUFF {
X`009struct`009RAB`009rab;`009`009/* Record access buffer`009`009*/
X`009struct`009FAB`009fab;`009`009/* File access buffer`009`009*/
X`009struct`009NAM`009nam;`009`009/* File name buffer`009`009*/
X`009struct`009XABFHC`009xab;`009`009/* Extended attributes block`009*/
X`009char`009`009starname[NAM$C_MAXRSS + 1]; /* Wild file name`009*/
X`009char`009`009filename[NAM$C_MAXRSS + 1]; /* Open file name`009*/
X} FDLSTUFF;
X
Xint`009`009fdl_status;`009`009/* Set to last rms call status`009*/
X
Xstatic FDLSTUFF *
Xfail(r, why, name)
XFDLSTUFF`009*r;`009`009`009/* Buffer`009`009`009*/
Xchar`009`009*why;`009`009`009/* A little commentary`009`009*/
Xchar`009`009*name;`009`009`009/* Argument to perror`009`009*/
X/*
X * Problem exit routine
X */
X{
X#if TESTING_FDLIO
X`009if (name == NULL && r != NULL)
X`009 name = r->fab.fab$l_fna;
X`009message(r, why, name);
X#endif
X`009if (r != NULL)
X`009 free(r);
X`009return (NULL);
X}
X`012
XFDLSTUFF *
Xfdl_open(filename, fdl_descriptor)
Xchar`009`009`009*filename;`009`009/* What to open`009`009*/
Xstruct`009dsc$descriptor`009*fdl_descriptor;`009/* Result descriptor`009*/
X/*
X * Open the file. Returns NULL on failure, else a pointer to RMS stuff.
X * Which is equivalently a pointer to the RAB. (Note that the RAB points
X * in turn to the FAB.)
X *
X * Return the file's fdl descriptor in the user-supplied (uninitialized)
X * descriptor.
X */
X{
X`009register FDLSTUFF`009*r;
X`009int`009`009`009retlen;
X`009int`009`009`009badblk;
X`009struct FAB`009`009*fab_add;
X`009struct RAB`009`009*rab_add;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009extern FDLSTUFF`009`009*fdl_setup();
X
X`009if ((r = fdl_setup(filename)) == NULL)
X`009 return (NULL);
X`009/*
X`009 * Now open the file.
X`009 */
X`009r->fab.fab$b_fac = FAB$M_GET | FAB$M_BIO; /* Block I/O only`009*/
X`009if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
X`009 return (fail(r, "opening file", NULL));
X`009}
-+-+-+-+-+ End of part 2 +-+-+-+-+-