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


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

$Part6:
$ File_is="LZIO.C"
$ Check_Sum_is=1829574117
$ Copy SYS$Input VMS_SHAR_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<rmsdef.h>
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, "<stdout>"))
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/* <file`009`009*/
X`009`009if (freopen(++ap, "r", stdin) == NULL) {
X`009`009    perror(ap);`009`009/* Can't find file`009*/
X`009`009    exit(IO_ERROR);`009/* Is a fatal error`009*/
X`009`009}
X`009`009break;
X
X`009    case '>':`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 ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
X`009`009 || dup2(file, fileno(stdout)) == -1) {
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, "<x%02X>", 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<timeb.h>
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<types.h>
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<sys/types.h>
X#include`009<sys/times.h>
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 Convert_File
$ File_is="MAKEFILE.TXT"
$ Check_Sum_is=711605164
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X# Unix makefile for lzcomp, lzdcmp
X#
X# The redefinition of strchr() and strrchr() are needed for
X# Ultrix-32, Unix 4.2 bsd (and maybe some other Unices).
X#
XBSDDEFINE = -Dstrchr=index -Dstrrchr=rindex
X#
X# On certain systems, such as Unix System III, you may need to define
X# $(LINTFLAGS) in the make command line to set system-specific lint flags.
X#
X
XCFLAGS = -O $(BSDDEFINES)
X
Xall`009: lzcomp lzdcmp
X
X#
X# ** compile lzcomp
X#
XLZCOMP_SRCS = lzcmp1.c lzcmp2.c lzcmp3.c lzio.c
XLZCOMP_OBJS = lzcmp1.o lzcmp2.o lzcmp3.o lzio.o
Xlzcomp: $(LZCOMP_OBJS)
X`009$(CC) $(CFLAGS) $(LZCOMP_OBJS) -o lzcomp
X
X#
X# ** compile lzdcmp
X#
XLZDCMP_SRCS = lzdcm1.c lzdcm2.c lzdcm3.c lzio.c
XLZDCMP_OBJS = lzdcm1.o lzdcm2.o lzdcm3.o lzio.o
Xlzdcmp: $(LZDCMP_OBJS)
X`009$(CC) $(CFLAGS) $(LZDCMP_OBJS) -o lzdcmp
X
X#
X# ** Lint the code
X#
Xlint:`009$(LZCOMP_SRCS) $(LZDCMP_SRCS)
X`009lint $(LINTFLAGS) $(DEFINES) $(LZCOMP_SRCS)
X`009lint $(LINTFLAGS) $(DEFINES) $(LZDCMP_SRCS)
X
X#
X# ** Remove unneeded files
X#
Xclean:
X`009rm -f $(OBJS) lzcomp lzdcmp
X
X#
X# ** Rebuild the archive files
X# ** Uses the Decus C archive utility.
X#
Xarchive:
X`009cp Makefile makefile.txt
X`009archc lzcmp1.c lzcmp2.c lzcmp3.c >lz1.arc
X`009archc lzdcm1.c lzdcm2.c lzdcm3.c >lz2.arc
X`009archc lz.h lzio.c lzvio.c makefile.txt >lz3.arc
X
X#
X# Object module dependencies
X#
X
Xlzcmp1.o`009:`009lzcmp1.c lz.h
X
Xlzcmp2.o`009:`009lzcmp2.c lz.h
X
Xlzcmp3.o`009:`009lzcmp3.c lz.h
X
Xlzio.o`009`009:`009lzio.c lz.h
X
Xlzdcm1.o`009:`009lzdcm1.c lz.h
X
Xlzdcm2.o`009:`009lzdcm2.c lz.h
X
Xlzdcm3.o`009:`009lzdcm3.c lz.h
X
X
$ GoSub Convert_File
$ File_is="README.TXT"
$ Check_Sum_is=5847959
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
XThis is a rewrite of the Unix compress utility.  It is *not*
Xswitch-compatible with Unix compress, however it is (almost)
Xfile-compatible (when compiled on Unix, or when "export" mode
Xis selected on VMS Version 4).
X
XThe advantages of this version are as follows:
X
X1. Compress and decompress are separate programs, simplifying the
X   problems of the small system implementor.  Both run on an
X   unmapped PDP-11 (with a maximum of 12 bits).
X
X   The command interface is just
X
X`009lzcomp input compressed_output
X`009lzdcmp compressed_input output
X
X   Input files are not deleted.
X
X2. The compression algorithm and I/O design is intended to simplify
X   embedding the programs (as subroutines) in some other task.
X   (for example, in a database package.)
X
X3. On non-Unix systems, the I/O design should be significantly
X   faster.  It should be slightly faster on Unix.
X
XThe only disadvantage is that, as noted, it is not command (option)
Xcompatible with Unix compress.  Also, some periferal functionality
X(such as the deletion of input files and the output file naming
Xconventions) have not been implemented.
X
XOn Unix (i.e., in "export" mode), the compressed data file is
Xidentical to the Unix file, *except* that lzcomp writes two
XCLEAR codes in a row to signal end-of-file (and lzdcmp treats
Xtwo CLEAR codes in a row as signalling end-of-file).
X
Xlzcomp and lzdcmp have been added to the Decus C distribution.
X
XMartin Minow
Xdecvax!minow,
Xminow%rex.dec@decwrl.arpa
X
$ GoSub Convert_File
$ File_is="RULES.MMS"
$ Check_Sum_is=708653584
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X!
X! This MMS file has rules and definitions used in DESCRIP.MMS for LZW
X!
X! Redefined rules...
X!
X.SUFFIXES
X.SUFFIXES .OLB .OPT .LIS .LST .H .OBJ .C .MSG .C~ .H~ .MSG~
X
X.C.LIS
X`009$(CC) $(CLIST) $(MMS$SOURCE)
X.MAR.LIS
X`009$(MACRO) $(MLIST) $(MMS$SOURCE)
X.MSG.LIS
X`009MESSAGE $(MSGLIST) $(MMS$SOURCE)
X.OBJ.OLB
X`009$(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)
X`009DELETE $(MMS$SOURCE);*
X.C.OLB
X`009$(CC) $(CFLAGS) $(MMS$SOURCE)
X`009  mms_object = "$(MMS$SOURCE)" - ".C" + ".OBJ"
X`009$(LIBR) $(LIBRFLAGS) $(MMS$TARGET) 'mms_object'
X`009DELETE 'mms_object';*
X.MSG.OLB
X`009MESSAGE $(MSGFLAGS) $(MMS$SOURCE)
X`009  mms_object = "$(MMS$SOURCE)" - ".MSG" + ".OBJ"
X`009$(LIBR) $(LIBRFLAGS) $(MMS$TARGET) 'mms_object'
X`009DELETE 'mms_object';*
X!
X! Macros
X!
X.IFDEF`009LIST
XCFLAGS = /LIST /SHOW=SYMBOLS /OBJECT=$(MMS$TARGET_NAME)
XMFLAGS = /LIST /CROSS_REFERENCE /OBJECT=$(MMS$TARGET_NAME)
XMSGFLAGS = /LIST /OBJECT=$(MMS$TARGET_NAME)
X.ENDIF
X
X.IFDEF`009DEBUG
XCFLAGS = /DEBUG /NOOPTIMIZE /OBJECT=$(MMS$TARGET_NAME)
XMFLAGS = /DEBUG /OBJECT=$(MMS$TARGET_NAME)
XLINKFLAGS = /DEBUG /EXECUTABLE=$(MMS$TARGET_NAME)
X.ELSE
XLINKFLAGS = /NOTRACEBACK /EXECUTABLE=$(MMS$TARGET_NAME)
X.ENDIF
X
XCODE_WHERE = INTERSPERSED
X
XCLIST = /LIST=$(MMS$TARGET_NAME) /SHOW=SYMBOLS /NOOBJECT
X
XMLIST = /LIST=$(MMS$TARGET_NAME) /CROSS_REFERENCE /NOOBJECT
XMSGLIST = /LIST=$(MMS$TARGET_NAME) /NOOBJECT
$ GoSub Convert_File
$ File_is="DESCRIP.MMS"
$ Check_Sum_is=810774971
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X!
X! This MMS file is used to build the LZ* programs.
X!
X! Rules and definitions...
X!
X.INCLUDE  RULES.MMS
X!
X! Dependencies:
X!`009$ mms`009`009`009`009!Build LZCOMP.EXE and LZDCMP.EXE
X!
Xboth`009: lzcomp.exe, lzdcmp.exe
X`009@ CONTINUE
X
Xlzcomp.exe`009: lzcmp1.obj, lzcmp2.obj, lzcmp3.obj, lzio.obj, lzvio.obj
X`009$(LINK) $(LINKFLAGS) LZCMP1.OBJ, LZCMP2.OBJ, LZCMP3.OBJ, -
XLZIO.OBJ, LZVIO.OBJ, SYS$LIBRARY:VAXCRTL/OPTIONS
X
Xlzcmp1.obj`009: lzcmp1.c, lz.h
X
Xlzcmp2.obj`009: lzcmp2.c, lz.h
X
Xlzcmp3.obj`009: lzcmp3.c, lz.h
X
Xlzdcmp.exe`009: lzdcm1.obj, lzdcm2.obj, lzdcm3.obj, lzio.obj, lzvio.obj
X`009$(LINK) $(LINKFLAGS) LZDCM1.OBJ, LZDCM2.OBJ, LZDCM3.OBJ, -
XLZIO.OBJ, LZVIO.OBJ, SYS$LIBRARY:VAXCRTL/OPTIONS
X
Xlzdcm1.obj`009: lzdcm1.c, lz.h
X
Xlzdcm2.obj`009: lzdcm2.c, lz.h
X
Xlzdcm3.obj`009: lzdcm3.c, lz.h
X
Xlzio.obj`009: lzio.c, lz.h
X
Xlzvio.obj`009: lzvio.c, lz.h
X
X!
X! Cleanup
X!
X.LAST`009:
X`009@  PURGE
$ GoSub Convert_File
$ File_is="LZCMP3.C"
$ Check_Sum_is=1949626030
$ Copy SYS$Input VMS_SHAR_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 Convert_File
$ File_is="LZDEF.COM"
$ Check_Sum_is=209675197
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X$!
X$!`009Defines symbols to run lzcomp and lzdcmp.
X$!`009Assumes both are installed in SYS$SYSTEM.
X$!
X$ LZC*OMP :== $LZCOMP
X$ LZD*CMP :== $LZDCMP
$ GoSub Convert_File
$ File_is="LZBLD.COM"
$ Check_Sum_is=674050152
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X$!
X$!`009Builds LZCOMP.EXE and LZDCMP.EXE from sources and the
X$!`009NON-SHAREABLE VAXC RTL.  Note: See LZBLDSHR.COM to make
X$!`009EXEs that use the shareable VAXC RTL.
X$!
X$ SAVE_VERIFY = F$VERIFY(1)
X$ SET NOON
X$ CC LZCMP1
X$ CC LZCMP2
X$ CC LZCMP3
X$ CC LZVIOISAM
X$ CC LZIO
X$ CC LZDCM1
X$ CC LZDCM2
X$ CC LZDCM3
X$ LINK/EXE=LZCOMP LZCMP1,LZCMP2,LZCMP3,LZVIOISAM,LZIO, -
X`009SYS$LIBRARY:VAXCRTL/LIBRARY
X$ LINK/EXE=LZDCMP LZDCM1,LZDCM2,LZDCM3,LZVIOISAM,LZIO, -
X`009SYS$LIBRARY:VAXCRTL/LIBRARY
X$ IF .NOT. SAVE_VERIFY THEN SET NOVERIFY
$ GoSub Convert_File
$ File_is="LZBLDSHR.COM"
$ Check_Sum_is=673533241
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X$!
X$!`009Builds LZCOMP.EXE and LZDCMP.EXE from sources that use the
X$!`009SHAREABLE VAXC RTL.
X$!
X$ SAVE_VERIFY = F$VERIFY(1)
X$ SET NOON
X$ CC LZCMP1
X$ CC LZCMP2
X$ CC LZCMP3
X$ CC LZVIOISAM
X$ CC LZIO
X$ CC LZDCM1
X$ CC LZDCM2
X$ CC LZDCM3
X$ LINK/EXE=LZCOMP LZCMP1,LZCMP2,LZCMP3,LZVIOISAM,LZIO,VAXCRTL/OPT
X$ LINK/EXE=LZDCMP LZDCM1,LZDCM2,LZDCM3,LZVIOISAM,LZIO,VAXCRTL/OPT
X$ IF .NOT. SAVE_VERIFY THEN SET NOVERIFY
$ GoSub Convert_File
$ File_is="LZCMP.COM"
$ Check_Sum_is=268574293
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X$set verify
X$set noon
X$cc lzcmp1
X$cc lzcmp2
X$cc lzcmp3
X$cc lzvioisam
X$cc lzio
X$cc lzdcm1
X$cc lzdcm2
X$cc lzdcm3
X$set noverify
$ GoSub Convert_File
$ Exit

