From:	CSBVAX::MRGATE!ijah400%ivax.decnet@gold.bacs.indiana.edu@SMTP 16-AUG-1988 22:17
To:	ARISIA::EVERHART
Subj:	lzcomp/lzdcmp part 3 of 6.


Date: 16 Aug 88 15:21:00 EST
From: "IVAX::IJAH400" <ijah400%ivax.decnet@gold.bacs.indiana.edu>
Subject: lzcomp/lzdcmp part 3 of 6.
To: "everhart%arisia.decnet" <everhart%arisia.decnet@ge-crd.arpa>

$Part3:
$ File_is="VAXCRTL.OPT"
$ Check_Sum_is=1929406956
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
XSYS$SHARE:VAXCRTL.EXE/SHARE
$ GoSub Convert_File
$ File_is="LZDCM1.C"
$ Check_Sum_is=992496249
$ Copy SYS$Input VMS_SHAR_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
XEdit history
X
X`009JAH is James A. Harvey, IUPUI Academic Computing Services
X
X`009IU-1`009JAH`00928-Jun-1988
X`009Fix "unknown option" error message to type out the unknown
X`009option rather than the one after it.
X
X`009IU-2`009JAH`00928-Jun-1988
X`009Add a "Usage:" line to the helptext.
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 <descrip.h>
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    "<input file unknown>" : infilename,
X`009`009(outfilename == NULL) ?
X`009`009    "<no output file>" : 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"Usage: lzdcmp [-options] [infile [outfile]]",`009`009/*[IU-2]*/
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`009ap--;`009`009`009`009`009/*[IU-1]*/
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 = "<stdin>";
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 = "<stdout>";
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 Convert_File
$ File_is="LZDCM2.C"
$ Check_Sum_is=1161190559
$ Copy SYS$Input VMS_SHAR_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 Convert_File
$ File_is="LZDCM3.C"
$ Check_Sum_is=1679715766
$ Copy SYS$Input VMS_SHAR_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 Convert_File
$ Goto Part4

