[comp.os.vms] Lempel-Ziv file

nagy%warner.hepnet@LBL.GOV (Frank J. Nagy, VAX Wizard & Guru) (07/12/88)

...................... Cut between dotted lines and save. .....................
$!.............................................................................
$! VAX/VMS archive file created by VMS_SHARE V06.00 26-May-1988.
$!
$! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from
$! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au).
$!
$! To unpack, simply save, concatinate all parts into one file and
$! execute (@) that file.
$!
$! This archive was created by user NAGY
$! on  6-APR-1866 20:07:23.73.
$!
$! ATTENTION: To keep each article below 127 blocks (65024 bytes), this
$!            program has been transmitted in 3 parts.  You should
$!            concatenate ALL parts to ONE file and execute (@)that file.
$!
$! It contains the following 16 files:
$!        AAAREADME.TXT
$!        DESCRIP.MMS
$!        LZ.H
$!        LZ.HLP
$!        LZCMP1.C
$!        LZCMP2.C
$!        LZCMP3.C
$!        LZDCM1.C
$!        LZDCM2.C
$!        LZDCM3.C
$!        LZIO.C
$!        LZVIO.C
$!        LZVIOISAM.C
$!        MAKEFILE.TXT
$!        README.TXT
$!        RULES.MMS
$!
$!==============================================================================
$ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL )
$ VERSION = F$GETSYI( "VERSION" )
$ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK
$ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", -
    "VMS_SHARE V06.00 26-May-1988 requires VMS V4.4 or higher."
$ EXIT 44 
$VERSION_OK:
$ GOTO START
$
$UNPACK_FILE:
$ WRITE SYS$OUTPUT "Creating ''FILE_IS'"
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION -
    VMS_SHARE_DUMMY.DUMMY
b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) )
; s_file_spec := GET_INFO( COMMAND_LINE, "output_file" ); SET( OUTPUT_FILE
, b_part, s_file_spec ); b_errors := CREATE_BUFFER( "{Errors}" ); i_errors 
:= 0; pat_beg_1 := ANCHOR & "-+-+-+ Beginning"; pat_beg_2 := LINE_BEGIN 
& "+-+-+-+ Beginning"; pat_end := ANCHOR & "+-+-+-+-+ End"; POSITION
( BEGINNING_OF( b_part ) ); i_append_line := 0; LOOP EXITIF MARK( NONE 
) = END_OF( b_part ); s_x := ERASE_CHARACTER( 1 ); IF s_x = "+" THEN r_skip 
:= SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip <> 0 THEN s_x := ""
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF; ENDIF
; IF s_x = "-" THEN r_skip := SEARCH( pat_end, FORWARD, EXACT ); IF r_skip <
> 0 THEN s_x := ""; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip := MARK( NONE )
; r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip <> 0 THEN POSITION
( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET ); MOVE_VERTICAL( 1 )
; MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part ) ); ENDIF; ERASE
( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF
; IF s_x = "V" THEN s_x := ""; IF i_append_line <> 0 THEN APPEND_LINE
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line := 1; MOVE_VERTICAL
( 1 ); ENDIF; IF s_x = "X" THEN s_x := ""; IF i_append_line <
> 0 THEN APPEND_LINE; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF
; i_append_line := 0; MOVE_VERTICAL( 1 ); ENDIF; IF s_x <> "" THEN i_errors 
:= i_errors + 1; s_text := CURRENT_LINE; POSITION( b_errors ); COPY_TEXT
( "The following line could not be unpacked properly:" ); SPLIT_LINE
; COPY_TEXT( s_x ); COPY_TEXT( s_text ); POSITION( b_part ); MOVE_VERTICAL( 1 
); ENDIF; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP r_x := SEARCH( "`"
, FORWARD, EXACT ); EXITIF r_x = 0; POSITION( r_x ); ERASE_CHARACTER( 1 )
; IF CURRENT_CHARACTER = "`" THEN MOVE_HORIZONTAL( 1 ); ELSE COPY_TEXT( ASCII
( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDIF; ENDLOOP; IF i_errors = 0 THEN SET
( NO_WRITE, b_errors, ON ); ELSE POSITION( BEGINNING_OF( b_errors ) )
; COPY_TEXT( FAO( "The following !UL errors were detectedwhile unpacking !AS"
, i_errors, s_file_spec ) ); SPLIT_LINE; SET( OUTPUT_FILE, b_errors
, "SYS$COMMAND" ); ENDIF; EXIT; 
$ DELETE VMS_SHARE_DUMMY.DUMMY;*
$ CHECKSUM 'FILE_IS
$ WRITE SYS$OUTPUT " CHECKSUM ", -
  F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!,passed." )
$ RETURN
$
$START:
$ FILE_IS = "AAAREADME.TXT"
$ CHECKSUM_IS = 874896225
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
XThis area contains source and executable for the LZCMP and LZDCM
Xutilities used in several places on the tape to compress large
Xfiles to gain room. The sources contain documentation in comments
Xat the start of the code for those curious about the programs'
Xoperation.
X`009To use LZCMP and LZDCM, define them as DCL foreign
Xsymbols. For instance, you might use commands like
X
X$LZCMP:==$DECUS$DISK:[VAX86D.LZW]LZCMP
X$LZDCM:==$DECUS$DISK:[VAX86D.LZW]LZDCM
X
XThen to compress a file use a command like
X
X$ LZCMP -v inputfile.typ squeezedfile.typ
X
Xor to decompress the file use a command like
X
X$ LZDCM squeezedfile.typ unsqueezedfile.typ
X
XIf you use those commands, "inputfile.typ" and "unsqueezedfile.typ"
Xwill be copies of each other.
X
X`009Note that you'd have to define "DECUS$DISK" before giving the
X$ lzcmp:==...
Xetc. definitions above... the idea is to run the programs as foreign
Xcommands. The -v switch for LZCMP is the "verbose" switch so that
Xwhen LZCMP is done it'll report to you what it did. The default
Xoperation on VMS preserves file attributes in the squeezed file.
XSeveral "compatibility" options (not used on the tapes) treat the
Xfiles in one of two stream modes (text and binary) and can be used
Xfor transporting files to/from non-VMS systems.
X`009It is presumed that if you're able to read the tape in VMS
XBACKUP, you must have a VMS system handy to do the decompress on, and
Xthat in that case, preserving all the file attributes is desirable.
X
X`009USAGE NOTE FOR THE VAX SIG TAPES
X
X`009Wherever any file has a type of form  .*_LZW,  where * is any
Xextension, it is compressed by LZCMP here and should be decompressed
Xwith LZDCM before use. In all cases, where this has been done, there 
Xwill be a directory (often named THIS_DIR.LIS) of the file directory
Xtree prior to backing up and compressing. Areas have been compressed
Xby creating a VMS Backup saveset and compressing the saveset, so
Xthat only one squeezed file per directory tree need be dealt with.
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "DESCRIP.MMS"
$ CHECKSUM_IS = 946674144
$ COPY SYS$INPUT VMS_SHARE_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 LZCMP.EXE and LZDCM.EXE
X!
Xboth`009: lzcmp.exe, lzdcm.exe
X`009@ CONTINUE
X
Xlzcmp.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
Xlzdcm.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 UNPACK_FILE
$ FILE_IS = "LZ.H"
$ CHECKSUM_IS = 1433596817
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X * Header file for all lz compression/decompression routines.
X *
X * Machine/Operating system/compiler selection: (#ifdef'ed)
X * vax`009`009`009`009Vax/Unix or Vax/VMS
X * pdp11`009`009`009makes a small compressor
X * M_XENIX`009`009`009"large-model" Z8000
X * interdata`009`009`009Signed long compare is slow
X * unix`009`009`009`009Defined on true Unix systems
X * decus`009`009`009Decus C (no signal)
X * vms`009`009`009`009Vax/VMS (VMS_V4 may be set automatically)
X * #define readonly`009`009If the compiler doesn't support it correctly.
X * 
X * Compiler configuration (#if'ed):
X * #define vax_asm   TRUE/FALSE`009TRUE on Vax (4bsd) if the compiler supports
X *`009`009`009`009the asm() operator.  Check the generated code!
X * #define UCHAR     TRUE/FALSE`009TRUE if compiler supports unsigned char
X * #define DEBUG     TRUE/FALSE`009TRUE to compile in debug printouts
X *
X * Algorithm Tuning parameters:
X * #define USERMEM   <n>`009Memory available to compress.
X *`009`009`009`009If large enough, a faster algorithm is used.
X * #define SACREDMEM <n>`009Don't use this part of USERMEM.
X * #define BITS      <n>`009Maximum number of code bits.
X * #define MAXIO     <n>`009Output buffer size (squeeze memory if needed)
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <setjmp.h>
X#ifndef decus
X# include <signal.h>
X/*
X * Arguments to signal():
X */
Xextern int`009abort();`009`009/* Debugging interrupt trap`009*/
Xextern int`009interrupt();`009`009/* Non-debugging interrupt trap`009*/
Xextern int`009address_error();`009/* "Segment" violation`009`009*/
X#endif
X
X#ifndef`009TRUE
X# define FALSE`009`0090
X# define TRUE`009`0091
X#endif
X#ifndef`009EOS
X# define EOS`009`009'\0'
X#endif
X#define`009streq(a, b)`009(strcmp((a), (b)) == 0)
X#define min(a,b)`009((a) > (b)) ? (b) : (a))
X
X/*
X * Set USERMEM to the maximum amount of physical user memory available
X * in bytes.  USERMEM is used to determine the maximum BITS that can be used
X * for compression.
X *
X * SACREDMEM is the amount of physical memory saved for others; compress
X * will hog the rest.
X */
X
X#ifndef SACREDMEM
X# define SACREDMEM`0090
X#endif
X
X/*
X * Set machine-specific parameters
X */
X
X#ifdef vax
X# ifdef unix
X#  define vax_asm`009TRUE`009`009/* If asm() supported on vax`009*/
X# endif
X#endif
X#ifndef`009vax_asm
X# define vax_asm`009FALSE
X#endif
X
X#ifdef pdp11
X# define BITS`00912`009/* max bits/code for 16-bit machine`009`009*/
X# define USERMEM 0`009/* Force no user memory`009`009`009`009*/
X# define UCHAR`009FALSE`009/* TRUE if compiler supports unsigned char`009*/
X# define MAXIO 512`009/* Buffer size for PDP-11 I/O buffers`009`009*/
X#endif
X
X/*
X * Set default values for some parameters.
X */
X
X#ifndef DEBUG
X# define DEBUG`009FALSE
X#endif
X
X#ifdef interdata
X# define SIGNED_COMPARE_SLOW TRUE
X#endif
X#ifndef SIGNED_COMPARE_SLOW
X# define SIGNED_COMPARE_SLOW FALSE
X#endif
X
X#ifndef USERMEM
X# define USERMEM 750000`009/* default user memory`009`009`009`009*/
X#endif
X
X#ifndef`009UCHAR
X# define UCHAR`009TRUE`009/* Compiler supports unsigned char`009`009*/
X#endif
X
X#ifndef MAXIO
X# define MAXIO`0092048`009/* I/O buffer size`009`009`009`009*/
X#endif
X
X/*
X * Set derived tuning parameters.
X */
X
X#ifndef USERMEM
X# define USERMEM`009 0
X#endif
X#if USERMEM >=`009`009`009(433484 + SACREDMEM)
X# define PBITS`009`00916
X#else
X# if USERMEM >=`009`009`009(229600 + SACREDMEM)
X#  define PBITS`009`00915
X# else
X#  if USERMEM >=`009`009(127536 + SACREDMEM)
X#   define PBITS`00914
X#   else
X#    if USERMEM >=`009`009( 73464 + SACREDMEM)
X#     define PBITS`00913
X#    else`009`009`009/* Smaller systems`009`009`009*/
X#     define PBITS`00912
X#    endif
X#   endif
X# endif
X#endif
X
X#ifndef BITS
X# define BITS PBITS
X#endif
X
X#ifdef M_XENIX
X# if BITS >= 16
X#  define XENIX_16`009`009/* Enable special vector access macros`009*/
X# else
X#  if BITS > 13
X#   undef BITS
X#   define BITS 13`009`009/* Code only handles BITS = 12, 13, 16`009*/
X#  endif
X# endif
X#endif
X
X/*
X * HSIZE is the size of the hash lookup table.  It is set to
X * 1 << BITS + fudge factor, rounded up to a prime number.
X * If it is too big, the "clear the hash" routine will take
X * too long.  The same numbers are replicated in the getsize()
X * routine's data table.
X */
X
X#if BITS == 16
X# define HSIZE`00969001`009`009/* 95% occupancy`009`009`009*/
X#endif
X#if BITS == 15
X# define HSIZE`00935023`009`009/* 94% occupancy`009`009`009*/
X#endif
X#if BITS == 14
X# define HSIZE`00918013`009`009/* 91% occupancy`009`009`009*/
X#endif
X#if BITS == 13
X# define HSIZE`009 9001`009`009/* 91% occupancy`009`009`009*/
X#endif
X#if BITS <= 12
X# define HSIZE`009 5003`009`009/* 80% occupancy`009`009`009*/
X#endif
X`012
X/*
X * typedef's -- somewhat machine specific.
X */
X
X/*
X * a code_int must be able to hold 2**BITS values of type int, and also -1
X */
X#if BITS > 15
Xtypedef long int`009code_int;
X#else
Xtypedef int`009`009code_int;
X#endif
X
X/*
X * A count_int must hold ((2**BITS)-1) + (255<<BITS)) and -1.
X *
X * count_int's also hold counters.
X *
X * count_short's hold small counters (for the interdata)
X *
X * Some implementations don't support unsigned char (Decus C, for example)
X * Decus C is also brain damaged with regards to unsigned shorts.
X */
X#if SIGNED_COMPARE_SLOW
Xtypedef unsigned long int count_int;
Xtypedef unsigned short int count_short;
X#else
Xtypedef long int`009count_int;
X#endif
X
X#if UCHAR
Xtypedef`009unsigned char`009char_type;
X#else
Xtypedef char`009`009char_type;
X#endif
X
X#ifdef decus
Xtypedef unsigned`009U_short;
X#define`009readonly`009`009`009/* Dummy out readonly modifier`009*/
X#else
Xtypedef unsigned short`009U_short;
X#endif
X
X#ifdef unix
X#define`009readonly
X#endif
X
Xtypedef short`009`009flag;`009`009/* Boolean flag or parameter`009*/
X`012
X/*
X * The following define the "magic cookie" header
X */
X#define`009HEAD1_MAGIC`0090x1F
X#define HEAD2_MAGIC`0090x9D
X#define`009VMS_HEAD2_MAGIC`0090x9E`009`009/* vms-private output format`009*/
X
X/*
X * Defines for third byte of header
X */
X#define BIT_MASK`0090x1F`009`009/* Gets NBITS in the code`009*/
X#define BLOCK_MASK`0090x80`009`009/* Gets block_compress flag`009*/
X/*
X * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
X * a fourth header byte (for expansion).
X */
X
X/*
X * This is for backwards compatibilty with an old version of Unix compress.
X */
X#ifdef COMPATIBLE`009`009`009/* Compatible, but wrong!`009*/
X# define MAXCODE(n_bits)`009(1 << (n_bits) - 1)
X#else
X# define MAXCODE(n_bits)`009((1 << (n_bits)) - 1)
X#endif
X
X#define INIT_BITS 9`009`009`009/* initial number of bits/code */
X
X/*
X * One code could conceivably represent (1<<BITS) characters, but
X * to get a code of length N requires an input string of at least
X * N*(N-1)/2 characters.  With 5000 chars in the stack, an input
X * file would have to contain a 25Mb string of a single character.
X * This seems unlikely.
X */
X#define MAXSTACK    8000`009`009/* size of lzdcmp output stack`009*/
X
X#ifndef CHECK_GAP
X# define CHECK_GAP `00910000`009`009/* ratio check interval`009`009*/
X#endif
X
X#ifndef __LINE__
X# define NO__LINE__
X#endif
X#ifndef __FILE__
X# define NO__LINE__
X#endif
X#if DEBUG
X# define VERBOSE_DEFAULT    1
X# ifndef NO__LINE__
X#  define FAIL(why)`009`009`009`009`009\
X`009fprintf(stderr, "\nfatal: %s (%s at %d)\n",`009\
X`009    why, __FILE__, __LINE__); `009`009`009\
X`009longjmp(failure, 1);
X# else
X#  define FAIL(why)`009`009`009`009`009\
X`009fprintf(stderr, "\nfatal: %s\n", why); `009`009\
X`009longjmp(failure, 1);
X# endif
X#else
X# define VERBOSE_DEFAULT    0
X# define FAIL(why)`009longjmp(failure, 1);
X#endif
X
X/*
X * Note -- for compatibility with Unix compress,
X * NBR_CHAR and LZ_CLEAR must equal 256.
X * Also, (1 << (MIN_BITS - 1) should equal or exceed NBR_CHR
X */
X#define`009NBR_CHAR      256`009`009/* Number of input codes`009*/
X#define MIN_BITS`0099`009`009/* Smallest code is 9 bits`009*/
X#if ((1 << BITS) < NBR_CHAR) || (BITS < MIN_BITS)
X    << Can't compile: not enough bits for the input character set size >>
X#endif
X#define`009LZ_CLEAR`009(NBR_CHAR)`009/* Clear code`009`009`009*/
X#define`009LZ_SOH`009`009(LZ_CLEAR + 1)`009/* Start of header block`009*/
X#define`009LZ_STX`009`009(LZ_SOH   + 1)`009/* Start of text block`009`009*/
X#define`009LZ_EOR`009`009(LZ_STX   + 1)`009/* End of text record`009`009*/
X#define`009LZ_ETX`009`009(LZ_EOR   + 1)`009/* End of header/text block`009*/
X#define`009LZ_FIRST`009(LZ_ETX   + 1)`009/* First user (data) code`009*/
X
X#ifdef`009vms
X#include`009`009errno
X#include`009`009ssdef
X#include`009`009stsdef
X#define`009IO_SUCCESS`009(SS$_NORMAL | STS$M_INHIB_MSG)
X#define`009IO_ERROR`009(SS$_ABORT)
X#define VMS_V4`009`009L_cuserid >= 16`009`009/* Enable new stuff`009*/
X#else
X#define VMS_V4`009`0090`009`009`009/* Disable new stuff`009*/
Xextern int`009`009errno;
X#ifdef decus
X#define`009errno`009`009$$ferr
X#endif
X#endif
X
X/*
X * Define exit() codes.
X */
X
X#ifndef`009IO_SUCCESS
X#define`009IO_SUCCESS`0090`009`009`009/* Normal exit`009`009*/
X#define`009IO_ERROR`0091`009`009`009/* Error exit`009`009*/
X#endif
X`012
X/*
X * All I/O is done by way of "streams".  To establish a stream,
X * set the parameters appropriately and off you go.  The following
X * functions are provided:
X *`009lz_fill(stream)`009`009fills the buffer from stdin
X *`009lz_flush(stream)`009writes the buffer to stdout
X *`009lz_eof(stream)`009`009returns EOF (for fill from memory)
X *`009lz_fail(stream)`009`009abort (for writing to memory).
X *`009lz_dummy(stream)`009throw an output stream away.
X * Note: if VMS_V4 is enabled and the private (non-export) format
X * chosen, lz_fill and lz_flush access the files appropriately.
X * Stream elements are initialized as follows:
X *`009Input:`009bp = NULL;`009bend = NULL;
X *`009Output:`009bp = bstart;`009bend = bstart + bsize;
X */
X
Xtypedef struct STREAM {
X    char_type`009*bp;`009`009/* Next character to get/put`009`009*/
X    char_type`009*bend;`009`009/* -> end of stream buffer`009`009*/
X    char_type`009*bstart;`009/* Start of stream buffer`009`009*/
X    short`009bsize;`009`009/* Stream buffer size`009`009`009*/
X    int`009`009(*func)();`009/* Read/write a buffer function`009`009*/
X} STREAM;
X
X/*
X * Note also that the compress routine uses putbuf(buf, count, outstream)
X * and the decompress routine uses getbuf(buf, count, instream) to (quickly)
X * transfer multiple bytes.
X */
X#if UCHAR
X#define`009GET(s)`009`009\
X`009(((s)->bp < (s)->bend) ? *(s)->bp++        : (*(s)->func)(s))
X#else
X#define`009GET(s)`009`009\
X`009(((s)->bp < (s)->bend) ? *(s)->bp++ & 0xFF : (*(s)->func)(s))
X#endif
X#define`009PUT(c, s)`009\
X`009((((s)->bp >= (s)->bend) ? (*(s)->func)(s) : 0), *(s)->bp++ = (c))
X
Xextern int lz_fill();
Xextern int lz_flush();
Xextern int lz_eof();
Xextern int lz_fail();
Xextern int lz_dummy();
X
X#if DEBUG
Xextern readonly char *lz_names[];`009`009/* "LZ_CLEAR" etc.`009*/
X#endif
X
X/*
X * Options and globals.
X */
X#if VMS_V4
X#define`009ATT_NAME`009"vms$attributes "
X#define`009ATT_SIZE`00915`009`009`009/* strlen(ATT_NAME)`009*/
Xextern int`009fdl_status;`009/* Error code from fdl library`009`009*/
X#endif
X
Xextern flag`009binary;`009`009/* -b Readable text file if FALSE`009*/
Xextern flag`009noheader;`009/* -x3 No magic header if TRUE`009`009*/
Xextern flag`009export;`009`009/* -x  (non-zero) Supress vms private`009*/
Xextern flag`009block_compress;`009/* -x2`009`009`009`009`009*/
Xextern flag`009verbose;`009/* -v  (non-zero) Verbose logging`009*/
Xextern readonly flag is_compress; /* TRUE if compress, FALSE if decomp.`009*/
Xextern char`009*infilename;`009/* For error printouts`009`009`009*/
Xextern char`009*outfilename;`009/* For more error printouts`009`009*/
Xextern short`009n_bits;`009`009/* Current # of bits in compressed file`009*/
Xextern int`009firstcode;`009/* First value past signals`009`009*/
Xextern jmp_buf`009failure;`009/* For longjmp() return`009`009`009*/
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZ.HLP"
$ CHECKSUM_IS = 978341288
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X1 LZCMP
X File Compression Utility
X Usage:
X
X`009$ LZCMP  [-options]  infile  outfile
X
X LZCMP implements the Lempel-Ziv file compression algorithm.
X (Files compressed by LZCMP are uncompressed by LZDCM.)
X It operates by finding common substrings and replaces them
X with a variable-size code.  This is deterministic, and
X can be done with a single pass over the file.  Thus,
X the decompression procedure needs no input table, but
X can track the way the table was built.
X
X2 Options
X Options may be given in either case.
X2 -BInput
X Input file is "binary", not "human readable text".
X This is necessary on Dec operating systems, such as VMS and
X RSX-11M, that treat these files differently.  (Note that binary
X support is rudamentary and probably insufficient as yet.)
X (On VMS version 4, this is ignored unless the -x option is
X specified or the input file is record-oriented.)
X2 -M bits
X Write using the specified number of bits in the code -- necessary
X for big machines making files for little machines.  For example,
X if compressing a file on VMS which is to be read on a PDP-11,
X you should select -M 12.
X2 -V [n]
X Verbose if specified.  If a value is specified,
X it will enable debugging code (if compiled in).
X2 -X [n]
X "Export" -- write a file format that can be read by
X other operating systems.  Only the bytes in the file are copied;
X file attributes are not preserved.  If specified, the value
X determines the level of compatiblity.  If not specified,
X or specified with an explicit value of zero, and LZCMP is
X running on Vax/VMS version 4 under VaxC and the input file
X is a disk or magtape file (block-oriented), a VMS-private output
X format is used which is incompatible with the Unix compress
X utility, but which preserves VMS file attributes.  -X may
X take on the following values:
X
X    0  Choose VMS private format.  See restrictions below.
X    1  Compatible with Unix compress version 3.0:
X       this is the default if -x is given without a value.
X    2  As above, but supress "block compression"
X    3  Supress block compression and do not output
X       a compress header block.  This is for compatiblity
X       with a quite early version of Unix compress (and requires
X       conditional-compilation to use).
X
X Note that the -B (binary) option is ignored unless
X the input file is "record-oriented", such as a terminal
X or mailbox.
X2 Arguments
X The other two arguments are the input and output
X filenames respectively.  Redirection is supported,
X however, the output must be a disk/tape file.
X
X The file format is almost identical to the current
X Unix implementation of compress (V4.0).  Files written
X by Unix compress should be readable by LZDCM.  Files
X written by LZCMP in export (-x) format will be
X readable by Unix compress (except that LZCMP outputs
X two "clear" codes to mark EOF.  A patch to Unix
X compress is available.)
X
X2 VMS_Restrictions
X
X VMS Private mode stores the true name and attributes
X of the input file into the compressed file and LZDCM
X restores the attributes (and filename if requested).
X The following restrictions apply -- they may be lifted
X in the future as they are primarily due to the author's
X lack of understanding of the intricacies of of VMS I/O:
X
X    All files must be stored on disk.
X    The LZCMP output file must be specified directly.
X
X Also, for all usage on VMS, the compressed file must
X be written to, and read from disk.
X
X2 Compression_Algorithm
X
X This section is abstracted from Terry Welch's article
X referenced below.  The algorithm builds a string
X translation table that maps substrings in the input
X into fixed-length codes.  The compress algorithm may
X be described as follows:
X
X  1. Initialize table to contain single-character
X     strings.
X  2. Read the first character.  Set <w> (the prefix
X     string) to that character.
X  3. (step): Read next input character, K.
X  4. If at end of file, output code(<w>); exit.
X  5. If <w>K is in the string table:
X     Set <w> to <w>K; goto step 3.
X  6. Else <w>K is not in the string table.
X     Output code(<w>);
X     Put <w>K into the string table;
X     Set <w> to K; Goto step 3.
X
X "At each execution of the basic step an acceptable input
X string <w> has been parsed off.  The next character K is
X read and the extended string <w>K is tested to see if it
X exists in the string table.  If it is there, then the
X extended string becomes the parsed string <w> and the
X step is repeated.  If <w>K is not in the string table,
X then it is entered, the code for the successfully
X parsed string <w> is put out as comprssed data, the
X character K becomes the beginning of the next string,
X and the step is repeated."
X
X The decompression algorithm translates each received
X code into a prefix string and extension [suffix] character.
X The extension character is stored (in a push-down stack),
X and the prefix translated again, until the prefix is a
X single character, which completes decompression of this
X code.  The entire code is then output by popping the
X stack.
X
X "An update to the string table is made for each code received
X (except the first one).  When a code has been translated,
X its final character is used as the extension character,
X combined with the prior string, to add a new string to
X the string table.  This new string is assigned a unique
X code value, which is the same code that the compressor
X assigned to that string.  In this way, the decompressor
X incrementally reconstructs the same string table that
X the decompressor used.... Unfortunately ... [the algorithm]
X does not work for an abnormal case.
X 
X The abnormal case occurs whenever an input character string
X contains the sequence K<w>K<w>K, where K<w> already
X appears in the compressor string table."
X
X The decompression algorithm, augmented to handle
X the abnormal case, is as follows:
X
X  1. Read first input code;
X     Store in CODE and OLDcode;
X     With CODE = code(K), output(K);  FINchar = K;
X  2. Read next code to CODE; INcode = CODE;
X     If at end of file, exit;
X  3. If CODE not in string table (special case) then
X     Output(FINchar);
X     CODE = OLDcode;
X     INcode = code(OLDcode, FINchar);
X
X  4. If CODE == code(<w>K) then
X     Push K onto the stack;
X     CODE == code(<w>);
X     Goto 4.
X
X  5. If CODE == code(K) then
X     Output K;
X     FINchar = K;
X
X  6. While stack not empty
X     Output top of stack;
X     Pop stack;
X
X  7. Put OLDcode,K into the string table.
X     OLDcode = INcode;
X     Goto 2.
X
X The algorithm as implemented here introduces two additional
X complications.
X
X The actual codes are transmitted using a variable-length
X encoding.  The lowest-level routines increase the number
X of bits in the code when the largest possible code is
X transmitted.
X
X Periodically, the algorithm checks that compression is
X still increasing.  If the ratio of input bytes to output
X bytes decreases, the entire process is reset.  This can
X happen if the characteristics of the input file change.
X
X2 VMS_Private_File_Structure
X
X In VMS Private mode, the compressed data file contains
X a variable-length (but compressed) file header with the
X file "attributes" needed by the operating system to
X  construct the file.  This allows the decompression
X program to recreate the file in its original format,
X which is essential if ISAM databases are compressed.
X 
X The overall file format is as follows:
X
X    LZ_SOH  "start of header" signal (this value cannot appear
X            in user data).
X
X            A variable-length data record (maximum 256 bytes)
X            containing the header name, followed by whitespace, followed
X            by header-specific information.  In this case, the name
X            record will contain the string "vms$attributes" followed
X            by the number of bytes in the attribute data block.
X            (I assume that the name record will consist of a facility
X            name, such as "vms", followed by a dollar sign, followed
X            by a facility-unique word.)
X
X    LZ_EOR  Signals "end of record".
X
X            This is followed by a VMS file attributes record (generated
X            by a VMS system libraryroutine).
X
X    LZ_ETX  Signals "end of segment".
X
X    ST_STX  Signals "start of text" (i.e., start of data file).
X
X            This is followed by the user data file.
X
X    LZ_ETX  Signals "end of segment"
X
X    LZ_ETX  Two in a row signals "end of file".
X
X Note that this format can easily be extended to include
X trailer records (with file counts and checksums) and/or
X multiple data files in one compressed file.
X
X Note also that the LZ_CLEAR code may appear in headers
X or data files to cause the decompression program to
X "readapt" to the characteristics of the input data.
X LZ_STX and LZ_SOH reset the compression algorithm.
X LZ_EOR does not.
X
X2 Authors
X The algorithm is from "A Technique for High Performance
X Data Compression."  Terry A. Welch. IEEE Computer Vol 17,
X No. 6 (June 1984), pp 8-19.
X
X This revision is by Martin Minow.
X
X Unix Compress authors are as follows:
X
X Spencer W. Thomas  (decvax!harpo!utah-cs!utah-gr!thomas)
X Jim McKie          (decvax!mcvax!jim)
X Steve Davies       (decvax!vax135!petsd!peora!srd)
X Ken Turkowski      (decvax!decwrl!turtlevax!ken)
X James A. Woods     (decvax!ihnp4!ames!jaw)
X Joe Orost          (decvax!vax135!petsd!joe)
X
X Compatible with compress.c, v3.0 84/11/27
X
X1 LZDCM
X File Decompression Utility
X Usage:
X
X`009$ LZDCM  [-options]  infile  outfile
X
X LZDCM decompresses files compressed by LZCMP.  The
X help information for LZCMP describes the process in
X greater detail.
X
X2 Options
X Options may be given in either case.
X2 -BOutput
X Output file is "binary", not text.  (Ignored
X in VMS private mode.)
X2 -X 3
X To read files compressed by an old Unix version
X that doesn't generate header records.
X2 -V val
X Verbose (print status messages and debugging
X information).  The value selects the amount of verbosity.
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZCMP1.C"
$ CHECKSUM_IS = 371966649
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009lzcomp [-options] infile outfile
X */
X#ifdef`009DOCUMENTATION
X
Xtitle`009lzcomp`009File Compression
Xindex`009`009File compression
X
Xsynopsis
X`009.s.nf
X`009lzcomp [-options] [infile [outfile]]
X`009.s.f
Xdescription
X
X`009lzcomp implements the Lempel-Ziv file compression algorithm.
X`009(Files compressed by lzcomp are uncompressed by lzdcmp.)
X`009It operates by finding common substrings and replaces them
X`009with a variable-size code.  This is deterministic, and
X`009can be done with a single pass over the file.  Thus,
X`009the decompression procedure needs no input table, but
X`009can track the way the table was built.
X
X`009Options may be given in either case.
X`009.lm +8
X`009.p -8
X`009-B`009Input file is "binary", not "human readable text".
X`009This is necessary on Dec operating systems, such as VMS and
X`009RSX-11M, that treat these files differently.  (Note that binary
X`009support is rudamentary and probably insufficient as yet.)
X`009(On VMS version 4, this is ignored unless the -x option is
X`009specified or the input file is record-oriented.)
X`009.p -8
X`009-M bits`009Write using the specified number of bits in the
X`009code -- necessary for big machines making files for little
X`009machines.  For example, if compressing a file on VMS
X`009which is to be read on a PDP-11, you should select -M 12.
X`009.p -8
X`009-V [n]`009Verbose if specified.  If a value is specified,
X`009it will enable debugging code (if compiled in).
X`009.p -8
X`009-X [n]`009"Export" -- write a file format that can be read by
X`009other operating systems.  Only the bytes in the file are copied;
X`009file attributes are not preserved.  If specified, the value
X`009determines the level of compatiblity.  If not specified,
X`009or specified with an explicit value of zero, and lzcomp is
X`009running on Vax/VMS version 4 under VaxC and the input file
X`009is a disk or magtape file (block-oriented), a VMS-private output
X`009format is used which is incompatible with the Unix compress
X`009utility, but which preserves VMS file attributes.  -X may
X`009take on the following values:
X`009.lm +4.s
X`009.i -4;#0##Choose VMS private format.  See restrictions below.
X`009.i -4;#1##Compatible with Unix compress version 3.0:
X`009this is the default if -x is given without a value.
X`009.i -4;#2##As above, but supress "block compression"
X`009.i -4;#3##Supress block compression and do not output
X`009a compress header block.  This is for compatiblity
X`009with a quite early version of Unix compress (and requires
X`009conditional-compilation to use).
X`009.lm -4.s
X`009Note that the -B (binary) option is ignored unless
X`009the input file is "record-oriented", such as a terminal
X`009or mailbox.
X`009.lm -8.s
X`009The other two arguments are the input and output
X`009filenames respectively.  Redirection is supported,
X`009however, the output must be a disk/tape file.
X
X`009The file format is almost identical to the current
X`009Unix implementation of compress (V4.0).  Files written
X`009by Unix compress should be readable by lzdcmp.  Files
X`009written by lzcomp in export (-x) format will be
X`009readable by Unix compress (except that lzcomp outputs
X`009two "clear" codes to mark EOF.  A patch to Unix
X`009compress is available.)
X
XVMS Restrictions
X
X`009VMS Private mode stores the true name and attributes
X`009of the input file into the compressed file and lzdcmp
X`009restores the attributes (and filename if requested).
X`009The following restrictions apply -- they may be lifted
X`009in the future as they are primarily due to the author's
X`009lack of understanding of the intricacies of of VMS I/O:
X
X`009    All files must be stored on disk.
X`009    The lzcomp output file must be specified directly.
X
X`009Also, for all usage on VMS, the compressed file must
X`009be written to, and read from disk.
X
XLZW compression algorithm
X
X`009This section is abstracted from Terry Welch's article
X`009referenced below.  The algorithm builds a string
X`009translation table that maps substrings in the input
X`009into fixed-length codes.  The compress algorithm may
X`009be described as follows:
X
X`009  1. Initialize table to contain single-character
X`009     strings.
X`009  2. Read the first character.  Set <w> (the prefix
X`009     string) to that character.
X`009  3. (step): Read next input character, K.
X `009  4. If at end of file, output code(<w>); exit.
X`009  5. If <w>K is in the string table:
X`009`009Set <w> to <w>K; goto step 3.
X`009  6. Else <w>K is not in the string table.
X`009`009Output code(<w>);
X`009`009Put <w>K into the string table;
X`009`009Set <w> to K; Goto step 3.
X
X`009"At each execution of the basic step an acceptable input
X`009string <w> has been parsed off.  The next character K is
X`009read and the extended string <w>K is tested to see if it
X`009exists in the string table.  If it is there, then the
X`009extended string becomes the parsed string <w> and the
X`009step is repeated.  If <w>K is not in the string table,
X`009then it is entered, the code for the successfully
X`009parsed string <w> is put out as comprssed data, the
X`009character K becomes the beginning of the next string,
X`009and the step is repeated."
X
X`009The decompression algorithm translates each received
X`009code into a prefix string and extension [suffix] character.
X`009The extension character is stored (in a push-down stack),
X`009and the prefix translated again, until the prefix is a
X`009single character, which completes decompression of this
X`009code.  The entire code is then output by popping the
X`009stack.
X
X`009"An update to the string table is made for each code received
X`009(except the first one).  When a code has been translated,
X`009its final character is used as the extension character,
X`009combined with the prior string, to add a new string to
X`009the string table.  This new string is assigned a unique
X`009code value, which is the same code that the compressor
X`009assigned to that string.  In this way, the decompressor
X`009incrementally reconstructs the same string table that
X`009the decompressor used.... Unfortunately ... [the algorithm]
X`009does not work for an abnormal case.
X
X`009The abnormal case occurs whenever an input character string
X`009contains the sequence K<w>K<w>K, where K<w> already
X`009appears in the compressor string table."
X
X`009The decompression algorithm, augmented to handle
X`009the abnormal case, is as follows:
X
X`009  1. Read first input code;
X`009     Store in CODE and OLDcode;
X`009     With CODE = code(K), output(K);  FINchar = K;
X`009  2. Read next code to CODE; INcode = CODE;
X`009     If at end of file, exit;
X`009  3. If CODE not in string table (special case) then
X`009`009Output(FINchar);
X`009`009CODE = OLDcode;
X`009`009INcode = code(OLDcode, FINchar);
X`009
X`009  4. If CODE == code(<w>K) then
X`009`009Push K onto the stack;
X`009`009CODE == code(<w>);
X`009`009Goto 4.
X
X`009  5. If CODE == code(K) then
X`009`009Output K;
X`009`009FINchar = K;
X
X`009  6. While stack not empty
X`009`009Output top of stack;
X`009`009Pop stack;
X
X`009  7. Put OLDcode,K into the string table.
X`009     OLDcode = INcode;
X`009     Goto 2.
X
X`009The algorithm as implemented here introduces two additional
X`009complications.
X
X`009The actual codes are transmitted using a variable-length
X`009encoding.  The lowest-level routines increase the number
X`009of bits in the code when the largest possible code is
X`009transmitted.
X
X`009Periodically, the algorithm checks that compression is
X`009still increasing.  If the ratio of input bytes to output
X`009bytes decreases, the entire process is reset.  This can
X`009happen if the characteristics of the input file change.
X
XVMS Private File Structure
X
X`009In VMS Private mode, the compressed data file contains
X`009a variable-length (but compressed) file header with the
X`009file "attributes" needed by the operating system to
X `009construct the file.  This allows the decompression
X`009program to recreate the file in its original format,
X`009which is essential if ISAM databases are compressed.
X
X`009The overall file format is as follows:
X`009.lm +8
X`009.p -8
X`009LZ_SOH`009"start of header" signal (this value cannot appear
X`009in user data).
X
X`009A variable-length data record (maximum 256 bytes)
X`009containing the header name, followed by whitespace, followed
X`009by header-specific information.  In this case, the name
X`009record will contain the string "vms$attributes" followed
X`009by the number of bytes in the attribute data block.
X`009(I assume that the name record will consist of a facility
X`009name, such as "vms", followed by a dollar sign, followed
X`009by a facility-unique word.)
X`009.p -8
X`009LZ_EOR`009Signals "end of record".
X
X`009This is followed by a VMS file attributes record (generated
X`009by a VMS system library`009routine).
X`009.p -8
X`009LZ_ETX`009Signals "end of segment".
X`009.p -8
X`009ST_STX`009Signals "start of text" (i.e., start of data file).
X
X`009This is followed by the user data file.
X`009.p -8
X`009LZ_ETX`009Signals "end of segment"
X`009.p -8
X`009LZ_ETX`009Two in a row signals "end of file".
X`009.s.lm -8
X`009Note that this format can easily be extended to include
X`009trailer records (with file counts and checksums) and/or
X`009multiple data files in one compressed file.
X
X`009Note also that the LZ_CLEAR code may appear in headers
X`009or data files to cause the decompression program to
X`009"readapt" to the characteristics of the input data.
X`009LZ_STX and LZ_SOH reset the compression algorithm.
X`009LZ_EOR does not.
X
XAuthors
X
X`009The algorithm is from "A Technique for High Performance
X`009Data Compression."  Terry A. Welch. IEEE Computer Vol 17,
X`009No. 6 (June 1984), pp 8-19.
X
X`009This revision is by Martin Minow.
X
X`009Unix Compress authors are as follows:
X`009.s.nf
X`009Spencer W. Thomas`009(decvax!harpo!utah-cs!utah-gr!thomas)
X`009Jim McKie`009`009(decvax!mcvax!jim)
X`009Steve Davies`009`009(decvax!vax135!petsd!peora!srd)
X`009Ken Turkowski`009`009(decvax!decwrl!turtlevax!ken)
X`009James A. Woods`009`009(decvax!ihnp4!ames!jaw)
X`009Joe Orost`009`009(decvax!vax135!petsd!joe)
X`009.s.f
X
X#endif
X
X/*
X * Compatible with compress.c, v3.0 84/11/27
X */
X
X/*)BUILD
X`009`009$(PROGRAM) = lzcomp
X`009`009$(INCLUDE) = lz.h
X`009`009$(CPP) = 1
X`009`009$(FILES) = { lzcmp1.c lzcmp2.c lzcmp3.c lzio.c lzvio.c }
X*/
X`012
X#include`009"lz.h"
X
X
X#ifdef unix
X#include <sys/types.h>
X#include <sys/stat.h>
X#endif
X
X/*
X * These global parameters are written to the compressed file.
X * The decompressor needs them.  The initialized values are defaults
X * and are modified by command line arguments.
X */
Xshort`009`009maxbits = BITS;`009`009/* settable max # bits/code`009*/
Xcode_int maxmaxcode = 1 << BITS; `009/* Totally largest code`009*/
Xcode_int`009hsize = HSIZE;`009`009/* Actual hash table size`009*/
X
X/*
X * Flags (command line arguments) to control compression.
X */
X#if VMS_V4
Xflag`009`009export = 0;`009`009/* Assume vms "private" mode`009*/
X#else
Xflag`009`009export = 1;`009`009/* Assume Unix compatible mode`009*/
X#endif
Xflag`009`009block_compress = TRUE;`009/* Assume block compression`009*/
Xflag`009`009binary = FALSE;`009`009/* Reading text file if FALSE`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*/
Xreadonly flag`009is_compress = TRUE;`009/* for lzio.c (needed?)`009`009*/
Xlong`009`009fsize;`009`009`009/* Input file size in bytes`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*/
Xcount_int`009tot_incount = 0;`009/* Total number of input bytes`009*/
Xcount_int`009tot_outcount = 0;`009/* Total number of output codes`009*/
Xextern count_int in_count;
Xextern count_int out_count;
Xstatic long`009start_time;`009`009/* Time we started (in msec)`009*/
Xextern long`009cputime();`009`009/* Returns process time in msec`009*/
XSTREAM`009`009instream;
XSTREAM`009`009outstream;
Xchar_type`009inbuffer[MAXIO];
Xchar_type`009outbuffer[MAXIO];
Xstatic STREAM`009mem_stream;
Xjmp_buf`009`009failure;
X#if VMS_V4
X#include types
X#include stat
X#include descrip
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 * Compress mainline
X */
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);`009`009/* Command line parameters`009*/
X`009    openinput();`009`009/* Open input, set instream`009*/
X`009    getfilesize();`009`009/* Get input file size`009`009*/
X`009    gethashsize();`009`009/* Get actual hash table size`009*/
X`009    initialize();`009`009/* Set maxbits and the like`009*/
X`009    openoutput();`009`009/* Open output file`009`009*/
X`009    if (verbose > 0)
X`009`009start_time = cputime();
X`009    put_magic_header();
X`009    init_compress(TRUE);
X`009    compress(&instream);
X#if VMS_V4
X`009    if (export == 0) {
X`009`009outputcode((code_int) LZ_ETX);
X`009`009outputcode((code_int) LZ_ETX);
X`009`009fdl_close(fdl_input);
X`009    }
X`009    else
X#endif
X`009    if (block_compress) {
X`009`009outputcode((code_int) LZ_CLEAR);
X`009`009outputcode((code_int) LZ_CLEAR);
X`009    }
X`009    outputcode((code_int) -1);`009`009/* Flush output buffers`009*/
X#if VMS_V4
X`009    if (export == 0)
X`009`009fdl_close(fdl_output);
X`009    else {
X`009`009fclose(stdout);
X`009    }
X#else
X`009    fclose(stdout);
X#endif
X`009    if (verbose > 0) {
X`009`009start_time = cputime() - start_time;
X`009`009tot_incount += in_count;
X`009`009tot_outcount += out_count;
X`009`009fprintf(stderr, "%ld chars in, %ld bytes out, ",
X`009`009    tot_incount, tot_outcount);
X`009`009if (tot_outcount > 0) {
X`009`009    divout("compression ratio: ",
X`009`009`009(long) tot_incount, (long) tot_outcount, "");
X`009`009    divout(" (",
X`009`009`009((long) tot_incount - (long) tot_outcount) * 100,
X`009`009`009(long) tot_incount, "%)\n");
X`009`009}
X`009`009fprintf(stderr,
X`009`009    "%ld.%02ld seconds (process time) for compression.\n",
X`009`009    start_time / 1000L, (start_time % 1000L) / 10L);
X`009`009if (start_time > 0) {
X`009`009    divout("  ", (long) tot_incount * 10L,
X`009`009`009(start_time + 50L) / 100L,
X`009`009`009" input bytes per second.\n");
X`009`009}
X`009    }
X`009    exit(IO_SUCCESS);
X`009}
X`009else {
X`009    fprintf(stderr, "Error when compressing \"%s\" to \"%s\"\n",
X`009`009(infilename  == NULL) ? 
X`009`009    "<input file unknown>" : infilename,
X`009`009(outfilename == NULL) ?
X`009`009    "<output file unknown>" : outfilename);
X`009    if (errno != 0)
X`009`009perror("lzcomp fatal error");
X`009    exit(IO_ERROR);
X`009}
X}
X`012
Xdivout(leader, numer, denom, trailer)
Xchar`009`009*leader;
Xlong`009`009numer;
Xlong`009`009denom;
Xchar`009`009*trailer;
X/*
X * Print numer/denom without floating point on small machines.
X */
X{
X`009fprintf(stderr, "%s%ld.%02ld%s",
X`009    leader, numer / denom, ((numer % denom) * 100L) / denom, trailer);
X}
X
Xstatic
Xinitialize()
X/*
X * Mung some global values.
X */
X{
X`009if (maxbits < INIT_BITS)`009/* maxbits is set by the -M `009*/
X`009    maxbits = INIT_BITS;`009/* option.  Make sure it's`009*/
X`009if (maxbits > BITS)`009`009/* within a reasonable range`009*/
X`009    maxbits = BITS;
X`009maxmaxcode = 1 << maxbits;`009/* Truly biggest code`009`009*/
X`009if (export == 0)
X`009    firstcode = LZ_FIRST;`009/* VMS private`009`009`009*/
X`009else if (block_compress)
X`009    firstcode = LZ_CLEAR + 1;`009/* Default`009`009`009*/
X`009else
X`009    firstcode = 256;`009`009/* Backwards compatible`009`009*/
X}
X`012
Xput_magic_header()
X/*
X * Write the magic header bits.
X */
X{
X#ifndef COMPATIBLE
X`009if (export && !noheader) {
X`009    PUT(HEAD1_MAGIC, &outstream);
X`009    PUT(HEAD2_MAGIC, &outstream);
X`009    PUT(maxbits | ((block_compress) ? BLOCK_MASK : 0),
X`009`009&outstream);
X`009}
X#if VMS_V4
X`009else if (export == 0) {
X`009    char`009`009text[256];
X`009    /*
X`009     * VMS private mode (with attribute block)
X`009     */
X`009    PUT(HEAD1_MAGIC, &outstream);
X`009    PUT(VMS_HEAD2_MAGIC, &outstream);
X`009    PUT((char) (maxbits | BLOCK_MASK), &outstream);
X`009    PUT(firstcode - 0x100, &outstream);
X`009    init_compress();
X`009    outputcode(LZ_SOH);
X#if DEBUG
X`009    if (strlen(ATT_NAME) != ATT_SIZE) {
X`009`009fprintf("\"%s\", expected %d, got %d\n",
X`009`009    ATT_NAME, ATT_SIZE, strlen(ATT_NAME));
X`009    }
X#endif
X`009    sprintf(text, "%s%d;", ATT_NAME, fdl_descriptor.dsc$w_length);
X`009    mem_compress(text, strlen(text));
X`009    outputcode(LZ_EOR);
X`009    mem_compress(fdl_descriptor.dsc$a_pointer,
X`009`009`009 fdl_descriptor.dsc$w_length);
X`009    fdl_free(&fdl_descriptor);
X`009    outputcode(LZ_ETX);
X`009    outputcode(LZ_STX);
X`009}
X#endif
X#endif
X}
X
Xmem_compress(datum, length)
Xchar_type`009*datum;
Xint`009`009length;
X/*
X * Compress from memory
X */
X{
X`009mem_stream.bp = mem_stream.bstart = datum;
X`009mem_stream.bsize = length;
X`009mem_stream.bend = datum + length;
X`009mem_stream.func = lz_eof;
X`009compress(&mem_stream);
X}
X`012
X/*
X * This routine is used to tune the hash table size according to
X * the file size.  If the filesize is unknown, fsize should be
X * set to zero.
X */
X
Xtypedef struct TUNETAB {
X    long`009fsize;
X    code_int`009hsize;
X} TUNETAB;
X
Xstatic readonly TUNETAB tunetab[] = {
X#if HSIZE > 5003
X    {`0091 << 12,`009 5003`009},
X#endif
X#if HSIZE > 9001
X    {`0091 << 13,`009 9001`009},
X#endif
X#if HSIZE > 18013
X    {`0091 << 14,`00918013`009},
X#endif
X#if HSIZE > 35023
X    {`0091 << 15,`00935023`009},
X    {`009  47000,`00950021`009},
X#endif
X    {`009      0,`009    0`009},
X};
X
Xstatic
Xgethashsize()
X/*
X * Tune the hash table parameters for small files.
X * We don't have a good way to find the file size on vms V3.
X * fsize is set to zero if we can't find it.
X */
X{
X`009register TUNETAB`009*tunep;
X
X`009hsize = HSIZE;
X`009if (fsize > 0) {
X`009    for (tunep = tunetab; tunep->fsize != 0; tunep++) {
X`009`009if (fsize < tunep->fsize) {
X`009`009    hsize = tunep->hsize;
X`009`009    break;
X`009`009}
X`009    }
X`009}
X}
X`012
Xstatic
Xgetfilesize()
X/*
X * Set fsize to the input filesize (in bytes) if possible.
X * Magic for all operating systems.
X */
X{
X#ifdef`009rsx
X`009extern char`009f_efbk;`009/* F.EFBK -- highest block in file`009*/
X#define`009fdb(p,offset)`009(stdin->io_fdb[((int) &p + offset)] & 0xFF)
X#define efbk(offset)`009fdb(f_efbk, offset)
X`009extern char`009f_rtyp;`009/* F.RTYP -- Record type`009`009*/
X`009extern char`009f_ratt;`009/* F.RATT -- Record attributes`009`009*/
X`009/*
X`009 * Note: Block number is stored high-order word first.
X`009 */
X`009fsize = efbk(2)
X`009    + (efbk(3) << 8)
X`009    + (efbk(0) << 16)
X`009    + (efbk(1) << 24);
X`009fsize *= 512;
X#endif
X#ifdef`009rt11
X`009fsize = stdin->io_size;`009`009/* Set by Decus C`009`009*/
X`009fsize *= 512;
X#endif
X#ifdef`009vms
X#if VMS_V4
X`009struct stat`009statbuf;
X
X`009fsize = 0;
X`009if (export != 0) {
X`009    if (fstat(fileno(stdin), &statbuf) == 0)
X`009`009fsize = (long) statbuf.st_size;
X`009}
X`009else {
X`009    fsize = (long) fdl_fsize(fdl_input);
X`009}
X#else
X`009fsize = 0;`009`009`009`009/* Can't find filesize`009*/
X#endif
X#endif
X#ifdef`009unix
X`009struct stat`009statbuf;
X
X`009fsize = 0;
X`009if (fstat(fileno(stdin), &statbuf) == 0)
X`009    fsize = (long) statbuf.st_size;
X#endif
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\tExplicitly set the maximum number of code bits",
X`009"-V val\tPrint status information (or debugging) to stderr",
X`009"-X val\tSet export (compatiblity) mode:",
X#if VMS_V4
X`009"  -X 0\tExplicitly choose VMS Private mode",
X#endif
X`009"  -X 1\t(default if -X specified, output format is compatible",
X`009      "\twith Unix compress V3.0",
X`009"  -X 2\tCompatible with Unix compress 3.0, block compression",
X`009      "\tsupressed.",
X#ifdef COMPATIBLE
X`009"  -X 3No header (file is readable by old compress)",
X#endif
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 = "\1\1\0\0"[export];
X`009`009`009noheader       = "\0\0\0\1"[export];
X`009`009`009export         = "\0\1\1\1"[export];
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("usage");
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 decus
X`009if (infilename == NULL) {
X`009    infilename = malloc(256 + 1);
X`009    fgetname(stdin, infilename);
X`009    infilename = realloc(infilename, strlen(infilename) + 1);
X`009}
X`009else {
X`009    if (freopen(infilename, (binary) ? "rn" : "r", stdin) == NULL) {
X`009`009perror(infilename);
X`009`009FAIL("can't reopen input");
X`009    }
X`009}
X#else
X#ifdef vms
X#if VMS_V4
X`009if (export == 0) {
X`009    char`009`009*fname;
X`009    char`009`009filename[256];
X
X`009    if ((fname = infilename) == NULL) {
X`009`009fgetname(stdin, filename);
X`009`009fname = filename;
X`009    }
X`009    if ((fdl_input = fdl_open(fname, &fdl_descriptor)) == NULL) {
X`009`009if ((fdl_status & 01) == 0) {
X`009`009    fdl_message(NULL, fname);
X`009`009    FAIL("can't fdl_open");
X`009`009}
X`009`009fprintf(stderr,
X`009`009    "Cannot open \"%s\" in vms private format,", fname);
X`009`009fprintf(stderr, " trying export format.\n");
X`009`009export = TRUE;
X`009`009goto try_export;
X`009    }
X`009    fclose(stdin);
X`009    stdin = NULL;
X`009    infilename = malloc(256 + 1);
X`009    infilename = realloc(fname, strlen(fname) + 1);
X`009    if (verbose > 1) {
X`009`009fprintf(stderr, "FDL information for \"%s\"\n", filename);
X`009`009fdl_dump(&fdl_descriptor, stderr);
X`009    }
X`009    goto opened;
X`009}
Xtry_export:
X#endif
X`009if (infilename == NULL) {
X`009    infilename = malloc(256 + 1);
X`009    fgetname(stdin, infilename);
X`009    infilename = realloc(infilename, strlen(infilename) + 1);
X`009}
X`009else {
X#if VMS_V4
X`009    if ((stdin = freopen(infilename, "r", stdin)) == NULL) {
X#else
X`009    if (freopen(infilename, "r", stdin) == NULL) {
X#endif
X`009`009perror(infilename);
X`009`009exit(IO_ERROR);
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`009exit(IO_ERROR);
X`009    }`009`009    
X`009}
X#endif
X#endif
Xopened:`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 * Open the output file (after the input file has been opened).
X * if outfilename == NULL, it's already open on stdout.
X */
X{
X`009if (outfilename == NULL) {
X#if VMS_V4
X#if 0`009`009`009`009`009/* The following doesn't work`009*/
X`009    outfilename = malloc(256 + 1);
X`009    fgetname(stdout, outfilename);
X`009    outfilename = realloc(outfilename, strlen(outfilename) + 1);
X`009    if (export == 0) {
X`009`009fclose(stdout);
X`009`009stdout = NULL;`009`009/* Can't do terminal test below`009*/
X`009`009if ((fdl_output = fdl_create(NULL, outfilename)) == NULL) {
X`009`009    if ((fdl_status & 01) == 0)
X`009`009`009fdl_message(NULL, outfilename);
X`009`009    fprintf(stderr, "Can't create \"%s\"\n", outfilename);
X`009`009    FAIL("can't fdl_create");
X`009`009}
X`009    }
X#else
X`009    fprintf(stderr,
X`009`009"Restriction: The output file must be specified.\n");
X`009    FAIL("can't redirect on VMS V4");
X#endif
X#else
X#ifdef`009vms
X`009    outfilename = malloc(256 + 1);
X`009    fgetname(stdout, outfilename);
X`009    outfilename = realloc(outfilename, strlen(outfilename) + 1);
X#else
X#ifdef decus
X`009    outfilename = malloc(256 + 1);
X`009    fgetname(stdout, outfilename);
X`009    outfilename = realloc(outfilename, strlen(outfilename) + 1);
X#else
X`009    outfilename = "<stdout>";
X#endif
X#endif
X#endif
X`009}
X`009else {
X#if VMS_V4
X`009    if (export == 0) {
X`009`009fclose(stdout);
X`009`009stdout = NULL;`009`009/* Can't do terminal test below`009*/
X`009`009if ((fdl_output = fdl_create(NULL, outfilename)) == NULL) {
X`009`009    if ((fdl_status & 01) == 0)
X`009`009`009fdl_message(NULL, outfilename);
X`009`009    fprintf(stderr,
X`009`009`009"Can't create \"%s\" (VMS private)\n", outfilename);
X`009`009    FAIL("can't fdl_create");
X`009`009}
X`009    }
X`009    else {
X`009`009if (freopen(outfilename, "w", stdout) == NULL) {
X`009`009    perror(outfilename);
X`009`009    FAIL("can't create");
X`009`009}
X`009    }
X#else
X#ifdef decus
X`009    if (freopen(outfilename, "wn", stdout) == NULL) {
X`009`009perror(outfilename);
X`009`009FAIL("can't create");
X`009    }
X#else
X`009    if (freopen(outfilename, "w", stdout) == NULL) {
X`009`009perror(outfilename);
X`009`009FAIL("can't create");
X`009    }
X#endif
X#endif
X`009}
X`009if (stdout != NULL && isatty(fileno(stdout))) {
X`009    fprintf(stderr, "%s: is a terminal.  We object.\n",
X`009`009outfilename);
X`009    FAIL("can't create");
X`009}
X`009outstream.bp = outstream.bstart = outbuffer;
X`009outstream.bend = outbuffer + sizeof outbuffer;
X`009outstream.bsize = sizeof outbuffer;
X`009outstream.func = lz_flush;
X}
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZCMP2.C"
$ CHECKSUM_IS = 1634966692
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009`009l z c m p 2 . c
X *
X * Actually do compression.  Terminology (and algorithm):
X *
X * Assume the input string is "abcd", we have just processed "ab" and
X * read 'c'.  At this point, a "prefix code" will be assigned to "ab".
X * Search in the prefix:character memory (either the "fast memory" or
X * the hash-code table) for the code followed by this character.  If
X * found, assign the code found to the "prefix code" and read the
X * next character.  If not found, output the current prefix code,
X * generate a new prefix code and store "old_prefix:char" in the
X * table with "new_prefix" as its definition.
X *
X * Naming conventions:
X *   code`009a variable containing a prefix code
X *   c or char`009a variable containing a character
X *
X * There are three tables that are searched (dependent on compile-time
X * and execution time considerations):
X *   fast`009Direct table-lookup -- requires a huge amount of physical
X *`009`009(non-paged) memory, but is very fast.
X *   hash`009Hash-coded table-lookup.
X *   cache`009A "look-ahead" cache for the hash table that optimizes
X *`009`009searching for the most frequent character.  This considerably
X *`009`009speeds up processing for raster-images (for example) at
X *`009`009a modest amount of memory.
X * Structures are used to hold the actual tables to simplify organization
X * of the program.
X *
X * Subroutines:
X *    compress()`009performs data compression on an input datastream.
X *    init_compress()`009called by the output routine to clear tables.
X */
X
X#include`009"lz.h"
X
X/*
X * General variables
X * Cleared by init_compress on a "hard initialization"
X * outputcode() in lzcmp3.c refers to next_code.
X */
X
Xlong int`009in_count;`009`009/* Length of input`009`009*/
Xlong int`009out_count;`009`009/* Bytes written to output file`009*/
Xstatic flag`009first_clear = TRUE;`009/* Don't zero first time`009*/
Xcode_int`009next_code;`009`009/* Next output code`009`009*/
Xstatic count_int checkpoint = CHECK_GAP; /* When to test ratio again`009*/
Xstatic long`009ratio = 0;`009`009/* Ratio for last segment`009*/
X
X/*
X * These global parameters are set by mainline code.  Unchanged here.
X */
Xextern short`009maxbits;`009`009/* Settable max # bits/code`009*/
Xextern short`009block_compress;`009`009/* For old-style compatibility`009*/
Xextern code_int`009maxmaxcode;`009`009/* Actual maximum output code`009*/
Xextern long`009tot_incount;`009`009/* Total input count`009`009*/
-+-+-+-+-+ End of part 1 +-+-+-+-+-

nagy%warner.hepnet@LBL.GOV (Frank J. Nagy, VAX Wizard & Guru) (07/12/88)

+-+-+-+ 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 <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"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 = "<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 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<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 (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, "<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 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 +-+-+-+-+-

nagy%warner.hepnet@LBL.GOV (Frank J. Nagy, VAX Wizard & Guru) (07/12/88)

+-+-+-+ Beginning of part 3 +-+-+-+
X`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after open", NULL));
X`009if (fdl_descriptor != NULL) {
X`009    /*
X`009     * Now, get the file attributes
X`009     */
X`009    fdl_descriptor->dsc$w_length = 4096;
X`009    fdl_descriptor->dsc$b_dtype = DSC$K_DTYPE_VT;
X`009    fdl_descriptor->dsc$b_class = DSC$K_CLASS_D;
X`009    fdl_descriptor->dsc$a_pointer = malloc(4096);
X`009    fab_add = &r->fab;
X`009    rab_add = &r->rab;
X`009    if ((fdl_status = fdl$generate(
X`009`009    &flags,
X`009`009    &fab_add,
X`009`009    &rab_add,
X`009`009    0, 0,
X`009`009    fdl_descriptor,
X`009`009    &badblk,
X`009`009    &retlen)) != SS$_NORMAL) {
X`009`009fdl_free(fdl_descriptor);
X`009`009sys$close(&r->fab);
X`009`009return(fail(r, "getting fdl info", NULL));
X`009    }
X`009    /*
X`009     * Success, null-terminate fdl info and squeeze the block.
X`009     */
X`009    fdl_descriptor->dsc$a_pointer[retlen] = EOS;
X`009    fdl_descriptor->dsc$a_pointer
X`009`009= realloc(fdl_descriptor->dsc$a_pointer, retlen + 1);
X`009    fdl_descriptor->dsc$w_length = retlen;
X`009}
X`009return (r);
X}
X`012
XFDLSTUFF *
Xfdl_create(fdl_descriptor, override_filename)
Xstruct`009dsc$descriptor`009*fdl_descriptor;`009/* Result descriptor`009*/
Xchar`009`009`009*override_filename;`009/* What to open`009`009*/
X/*
X * Create 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.)  The file is open for writing using fdl_write.
X *
X * Uses the filename in the descriptor block, or the override filename
X * if supplied (non-NULL and not == "");
X *
X * If fdl_descriptor is NULL, the override_filename is opened normally.
X */
X{
X`009register FDLSTUFF`009*r;
X`009int`009`009`009retlen;
X`009int`009`009`009badblk;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009struct`009dsc$descriptor`009newname;
X`009struct`009dsc$descriptor`009*newname_ptr;
X`009int`009`009`009fid_block[3];
X`009char`009`009`009created_name[NAM$C_MAXRSS + 1];
X`009struct`009dsc$descriptor`009created_name_des = {
X`009`009`009`009    NAM$C_MAXRSS,
X`009`009`009`009    DSC$K_DTYPE_T, 
X`009`009`009`009    DSC$K_CLASS_S,
X`009`009`009`009    &created_name[0]
X`009`009`009`009};
X`009extern FDLSTUFF`009`009*fdl_setup();
X
X`009if (fdl_descriptor == NULL) {
X`009    if ((r = fdl_setup(override_filename)) == NULL)
X`009`009return (NULL);
X`009    r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009    r->fab.fab$l_fop |= (FAB$M_NAM | FAB$M_SQO | FAB$M_BIO);
X`009    r->fab.fab$b_org = FAB$C_SEQ;`009/* Sequential only`009*/
X`009    r->fab.fab$b_rfm = FAB$C_UDF;`009/* Undefined format`009*/
X`009    if ((fdl_status = sys$create(&r->fab)) & 01 == 0)
X`009`009return (fail(r, "creating (sys$create)"));
X`009    goto exit;
X`009}
X`009if (override_filename == NULL || override_filename[0] == '\0')
X`009    newname_ptr = NULL;
X`009else {
X`009    newname_ptr = &newname;
X`009    newname.dsc$w_length = strlen(override_filename);
X`009    newname.dsc$b_dtype = DSC$K_DTYPE_T;
X`009    newname.dsc$b_class = DSC$K_CLASS_S;
X`009    newname.dsc$a_pointer = override_filename;
X`009}
X`009if ((fdl_status = fdl$create(fdl_descriptor,
X`009`009newname_ptr,`009`009/* New file name if any`009`009*/
X`009`0090,`009`009`009/* Default filename`009`009*/
X`009`009&created_name_des,`009/* Resultant filename`009`009*/
X`009`009&fid_block[0],`009`009/* File ID block`009`009*/
X`009`009&flags,`009`009`009/* FDL flag bits`009`009*/
X`009`0090,`009`009`009/* Statement number`009`009*/
X`009`009&retlen,`009`009/* Created name length`009`009*/
X`009`0090, 0)`009`009`009/* Create status, stv`009`009*/
X`009`009) & 01 == 0) {
X`009    return(fail(NULL, "creating (fdl$create)", NULL));
X`009}
X`009created_name[retlen] = '\0';
X`009if ((r = fdl_setup(created_name)) == NULL)
X`009    return (NULL);
X`009/*
X`009 * Now, open the file for output.
X`009 */
X`009r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "opening created file", NULL));
X`009}
Xexit:`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after create", NULL));
X`009return (r);
X}
X`012
Xstatic FDLSTUFF *
Xfdl_setup(filename)
Xchar`009`009*filename;
X/*
X * Initializes rms blocks and parses file name.  Returns the
X * FDL data block on success, NULL on error.
X */
X{
X`009register FDLSTUFF`009*r;
X
X`009if ((r = (char *)malloc(sizeof (FDLSTUFF))) == NULL)
X`009    return (NULL);
X`009r->fab = cc$rms_fab;`009`009`009/* Preset fab,`009`009*/
X`009r->nam = cc$rms_nam;`009`009`009/*   name block`009`009*/
X`009r->rab = cc$rms_rab;`009`009`009/*   and record block`009*/
X`009r->xab = cc$rms_xabfhc;`009`009`009/*   file header block`009*/
X`009r->fab.fab$l_nam = &r->nam;`009`009/* fab -> name block`009*/
X`009r->fab.fab$l_xab = &r->xab;`009`009/* fab -> file header`009*/
X`009r->fab.fab$l_fna = filename;`009`009/* Argument filename`009*/
X`009r->fab.fab$b_fns = strlen(filename);`009/* ... size`009`009*/
X`009r->rab.rab$l_fab = &r->fab;`009`009/* rab -> fab`009`009*/
X`009`009`009`009`009`009/* Stuff the name block`009*/
X`009r->nam.nam$l_esa = r->starname;`009`009/* Expanded filename`009*/
X`009r->nam.nam$b_ess = NAM$C_MAXRSS + 1;`009/* ... size`009`009*/
X`009r->nam.nam$b_rss = NAM$C_MAXRSS + 1;`009/* ... max size`009`009*/
X`009if ((fdl_status = sys$parse(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "parsing", filename));
X`009}
X`009((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS;
X`009r->fab.fab$l_fna = r->nam.nam$l_esa;`009/* File name`009`009*/
X`009r->fab.fab$b_fns = r->nam.nam$b_esl;`009/* Length`009`009*/
X`009r->fab.fab$l_fop |= FAB$M_NAM;`009`009/* Use name block`009*/
X`009return (r);
X}
X`012
Xfdl_free(fdl_descriptor)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
X/*
X * Release the descriptor
X */
X{
X`009if (fdl_descriptor->dsc$a_pointer != NULL) {
X`009    free(fdl_descriptor->dsc$a_pointer);
X`009    fdl_descriptor->dsc$a_pointer = NULL;
X`009}
X}
X
Xfdl_close(r)
Xregister FDLSTUFF`009*r;
X{
X`009if ((fdl_status = sys$close(&r->fab)) != RMS$_NORMAL)
X`009    return(fail(r, "close", NULL));
X`009free(r);
X}
X`012
Xint
Xfdl_read(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Read the next record from the file.  Returns number of bytes read or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_ubf = buffer;
X`009r->rab.rab$w_usz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$read(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    if (fdl_status != RMS$_EOF) {
X`009`009fdl_message(r, "error return from sys$read");
X`009`009sleep(1);
X`009    }
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xint
Xfdl_write(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Write the next record to the file.  Returns number of bytes written or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_rbf = buffer;
X`009r->rab.rab$w_rsz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$write(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    fdl_message(r, "error return from sys$write");
X`009    sleep(1);
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xfdl_getname(r, buffer)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
Xchar`009`009*buffer;`009`009/* Where to put it`009`009*/
X/*
X * Return current file name
X */
X{
X`009strcpy(buffer, r->fab.fab$l_fna);
X`009return (buffer);
X}
X
Xlong
Xfdl_fsize(r)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
X/*
X * Return current file size
X */
X{
X`009return (((long) r->xab.xab$l_ebk * 512) + r->xab.xab$w_ffb);
X}
X
Xfdl_message(r, why)
XFDLSTUFF`009*r;
Xchar`009`009*why;
X/*
X * Print error message
X */
X{
X`009extern char`009*vms_etext();
X
X`009if (why == NULL) {
X`009    fprintf(stderr, "\n%s\n\n", vms_etext(fdl_status));
X`009}
X`009else {
X`009    fprintf(stderr, "\n%s%s%s: %s\n\n",
X`009`009why,
X`009`009(why[0] == EOS) ? "" : " ",
X`009`009(r == NULL) ? "" : r->fab.fab$l_fna,
X`009`009vms_etext(fdl_status));
X`009}
X}
X
Xstatic char`009`009errname[257];`009/* Error text stored here`009*/
Xstatic $DESCRIPTOR(err, errname);`009/* descriptor for error text`009*/
X
Xstatic char *
Xvms_etext(errorcode)
Xint`009`009errorcode;
X{
X`009char`009`009*bp;
X`009short`009`009errlen;`009`009/* Actual text length`009`009*/
X
X`009lib$sys_getmsg(&errorcode, &errlen, &err, &15);
X`009/*
X`009 * Trim trailing junk.
X`009 */
X`009for (bp = &errname[errlen]; --bp >= errname;) {
X`009    if (isgraph(*bp) && *bp != ' ')
X`009`009break;
X`009}
X`009bp[1] = EOS;
X`009return(errname);
X}
X
Xstatic
Xmessage(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/* File name`009`009`009*/
X/*
X * Print error message
X */
X{
X`009fprintf(stderr, "\nRMS error %x when %s %s\n",
X`009    fdl_status, why, (name == NULL) ? "" : name);
X`009fprintf(stderr, "\"%s\"\n", vms_etext(fdl_status));
X}
X`012
Xfdl_dump(fdl_descriptor, fd)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
XFILE`009`009`009*fd;
X/*
X * Dump the descriptor to fd.
X */
X{
X`009register char`009*tp, *end;
X
X`009tp = fdl_descriptor->dsc$a_pointer;
X`009end = tp + fdl_descriptor->dsc$w_length;
X`009while (tp < end) {
X`009    if (*tp == '"') {
X`009`009do {
X`009`009    putc(*tp++, fd);
X`009`009} while (*tp != '"');
X`009    }
X`009    putc(*tp, fd);
X`009    if (*tp++ == ';')
X`009`009putc('\n', fd);
X`009}
X}
X
X`012
X#if`009TESTING_FDLIO
X/*
X * Test program for rms io
X */
X#include <stdio.h>
X
Xchar`009`009`009line[133];
Xchar`009`009`009filename[133];
Xchar`009`009`009buffer[2048];
X
Xmain(argc, argv)
Xint`009`009argc;
Xchar`009`009*argv[];
X{
X`009FDLSTUFF`009*old;
X`009FDLSTUFF`009*new;
X`009int`009`009size, total, nrecords;
X`009struct`009dsc$descriptor`009fdl_info;`009/* Result descriptor`009*/
X
X`009for (;;) {
X`009    fprintf(stderr, "Old file name: ");
X`009    fflush(stdout);
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if (line[0] == EOS)
X`009`009continue;
X`009    if ((old = fdl_open(line, &fdl_info)) == NULL) {
X`009`009fprintf(stderr, "open failed\n");
X`009`009continue;
X`009    }
X`009    fprintf(stderr, "New file name: ");
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if ((new = fdl_create(&fdl_info, line)) == NULL) {
X`009`009fprintf(stderr, "create failed\n");
X`009`009fdl_free(&fdl_info);
X`009`009continue;
X`009    }
X`009    fdl_getname(old, buffer);
X`009    fprintf(stderr, "Fdl for \"%s\", size %ld\n",
X`009`009buffer, fdl_fsize(old));
X`009    fdl_dump(&fdl_info, stderr);
X`009    total = nrecords = 0;
X`009    while ((size = fdl_read(buffer, sizeof buffer, old)) > 0) {
X`009`009fdl_write(buffer, size, new);
X`009`009nrecords++;
X`009`009total += size;
X`009    }
X`009    fdl_close(old);
X`009    fdl_close(new);
X`009    fprintf(stderr, "copied %d records, %d bytes total\n",
X`009`009nrecords, total);
X`009    fdl_free(&fdl_info);
X`009}
X}
X
X#endif
X#endif
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZVIOISAM.C"
$ CHECKSUM_IS = 660140431
$ 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`009struct`009XABSUM`009xabsum;`009`009/* Summary 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`009struct XABALL`009`009*xaball;
X`009struct XABKEY`009`009*xabkey,*this_xab;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009extern FDLSTUFF`009`009*fdl_setup();
X`009int`009`009`009i;
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_BRO; /* 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}
X`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X
X`009/* now, we know how many keys (if any) there are in the file, lets
X`009   add that many xabkeys */
X`009this_xab = &r->xabsum;
X`009for (i=0; i < r->xabsum.xab$b_nok; i++)
X`009    {
X `009    if ((xabkey = (char *)malloc(sizeof (struct XABKEY) + 32)) == NULL)
X`009`009return (NULL);
X`009    this_xab->xab$l_nxt = xabkey;
X`009    *xabkey = cc$rms_xabkey;
X`009    xabkey->xab$b_ref = i;
X`009    xabkey->xab$l_knm = xabkey + sizeof(struct XABKEY);
X`009    this_xab = xabkey;
X`009    xabkey = 0;
X`009    }
X
X`009/* we know how many allocation areas (if any) there are in the
X`009   file, lets add that many xaballs and then do a $display */
X`009for (i=0; i < r->xabsum.xab$b_noa; i++)
X`009    {
X`009    if ((xaball = (char *)malloc(sizeof (struct XABALL))) == NULL)
X`009`009return (NULL);
X`009    this_xab->xab$l_nxt = xaball;
X`009    *xaball = cc$rms_xaball;
X`009    xaball->xab$b_aid = i;
X`009    this_xab = xaball;
X`009    xaball = 0;
X`009    }
X
X`009if ((fdl_status = sys$display(&r->fab)) != RMS$_NORMAL)
X`009    return (fail(r, "displaying after adding xabkeys", NULL));
X
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after open", NULL));
X
X`009if (fdl_descriptor != NULL) {
X`009    /*
X`009     * Now, get the file attributes
X`009     */
X`009    fdl_descriptor->dsc$w_length = 4096;
X`009    fdl_descriptor->dsc$b_dtype = DSC$K_DTYPE_VT;
X`009    fdl_descriptor->dsc$b_class = DSC$K_CLASS_D;
X`009    fdl_descriptor->dsc$a_pointer = malloc(4096);
X`009    fab_add = &r->fab;
X`009    rab_add = &r->rab;
X`009    if ((fdl_status = fdl$generate(
X`009`009    &flags,
X`009`009    &fab_add,
X`009`009    &rab_add,
X`009`009    0, 0,
X`009`009    fdl_descriptor,
X`009`009    &badblk,
X`009`009    &retlen)) != SS$_NORMAL) {
X`009`009fdl_free(fdl_descriptor);
X`009`009sys$close(&r->fab);
X`009`009return(fail(r, "getting fdl info", NULL));
X`009    }
X`009    /*
X`009     * Success, null-terminate fdl info and squeeze the block.
X`009     */
X`009    fdl_descriptor->dsc$a_pointer[retlen] = EOS;
X`009    fdl_descriptor->dsc$a_pointer
X`009`009= realloc(fdl_descriptor->dsc$a_pointer, retlen + 1);
X`009    fdl_descriptor->dsc$w_length = retlen;
X`009}
X`009return (r);
X}
X`012
XFDLSTUFF *
Xfdl_create(fdl_descriptor, override_filename)
Xstruct`009dsc$descriptor`009*fdl_descriptor;`009/* Result descriptor`009*/
Xchar`009`009`009*override_filename;`009/* What to open`009`009*/
X/*
X * Create 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.)  The file is open for writing using fdl_write.
X *
X * Uses the filename in the descriptor block, or the override filename
X * if supplied (non-NULL and not == "");
X *
X * If fdl_descriptor is NULL, the override_filename is opened normally.
X */
X{
X`009register FDLSTUFF`009*r;
X`009int`009`009`009retlen;
X`009int`009`009`009badblk;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009struct`009dsc$descriptor`009newname;
X`009struct`009dsc$descriptor`009*newname_ptr;
X`009int`009`009`009fid_block[3];
X`009char`009`009`009created_name[NAM$C_MAXRSS + 1];
X`009struct`009dsc$descriptor`009created_name_des = {
X`009`009`009`009    NAM$C_MAXRSS,
X`009`009`009`009    DSC$K_DTYPE_T, 
X`009`009`009`009    DSC$K_CLASS_S,
X`009`009`009`009    &created_name[0]
X`009`009`009`009};
X`009extern FDLSTUFF`009`009*fdl_setup();
X
X`009if (fdl_descriptor == NULL) {
X`009    if ((r = fdl_setup(override_filename)) == NULL)
X`009`009return (NULL);
X`009    r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009    r->fab.fab$l_fop |= (FAB$M_NAM | FAB$M_SQO | FAB$M_BIO);
X`009    r->fab.fab$b_org = FAB$C_SEQ;`009/* Sequential only`009*/
X`009    r->fab.fab$b_rfm = FAB$C_UDF;`009/* Undefined format`009*/
X`009    if ((fdl_status = sys$create(&r->fab)) & 01 == 0)
X`009`009return (fail(r, "creating (sys$create)"));
X`009    goto exit;
X`009}
X`009if (override_filename == NULL || override_filename[0] == '\0')
X`009    newname_ptr = NULL;
X`009else {
X`009    newname_ptr = &newname;
X`009    newname.dsc$w_length = strlen(override_filename);
X`009    newname.dsc$b_dtype = DSC$K_DTYPE_T;
X`009    newname.dsc$b_class = DSC$K_CLASS_S;
X`009    newname.dsc$a_pointer = override_filename;
X`009}
X`009if ((fdl_status = fdl$create(fdl_descriptor,
X`009`009newname_ptr,`009`009/* New file name if any`009`009*/
X`009`0090,`009`009`009/* Default filename`009`009*/
X`009`009&created_name_des,`009/* Resultant filename`009`009*/
X`009`009&fid_block[0],`009`009/* File ID block`009`009*/
X`009`009&flags,`009`009`009/* FDL flag bits`009`009*/
X`009`0090,`009`009`009/* Statement number`009`009*/
X`009`009&retlen,`009`009/* Created name length`009`009*/
X`009`0090, 0)`009`009`009/* Create status, stv`009`009*/
X`009`009) & 01 == 0) {
X`009    return(fail(NULL, "creating (fdl$create)", NULL));
X`009}
X`009created_name[retlen] = '\0';
X`009if ((r = fdl_setup(created_name)) == NULL)
X`009    return (NULL);
X`009/*
X`009 * Now, open the file for output.
X`009 */
X`009r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "opening created file", NULL));
X`009}
Xexit:`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after create", NULL));
X`009return (r);
X}
X`012
Xstatic FDLSTUFF *
Xfdl_setup(filename)
Xchar`009`009*filename;
X/*
X * Initializes rms blocks and parses file name.  Returns the
X * FDL data block on success, NULL on error.
X */
X{
X`009register FDLSTUFF`009*r;
X
X`009if ((r = (char *)malloc(sizeof (FDLSTUFF))) == NULL)
X`009    return (NULL);
X`009r->fab = cc$rms_fab;`009`009`009/* Preset fab,`009`009*/
X`009r->nam = cc$rms_nam;`009`009`009/*   name block`009`009*/
X`009r->rab = cc$rms_rab;`009`009`009/*   and record block`009*/
X`009r->xab = cc$rms_xabfhc;`009`009`009/*   file header block`009*/
X`009r->xabsum = cc$rms_xabsum;`009`009/*   summary block`009*/
X`009r->fab.fab$l_nam = &r->nam;`009`009/* fab -> name block`009*/
X`009r->fab.fab$l_xab = &r->xab;`009`009/* fab -> file header`009*/
X`009r->xab.xab$l_nxt = &r->xabsum;`009`009/* xabfhc -> xabsum`009*/
X`009r->fab.fab$l_fna = filename;`009`009/* Argument filename`009*/
X`009r->fab.fab$b_fns = strlen(filename);`009/* ... size`009`009*/
X`009r->rab.rab$l_fab = &r->fab;`009`009/* rab -> fab`009`009*/
X`009`009`009`009`009`009/* Stuff the name block`009*/
X`009r->nam.nam$l_esa = r->starname;`009`009/* Expanded filename`009*/
X`009r->nam.nam$b_ess = NAM$C_MAXRSS ;`009/* ... size`009`009*/
X`009r->nam.nam$l_rsa = r->filename;`009`009/* Resultant filename`009*/
X`009r->nam.nam$b_rss = NAM$C_MAXRSS ;`009/* ... max size`009`009*/
X`009if ((fdl_status = sys$parse(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "parsing", filename));
X`009}
X`009((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS;
X`009r->fab.fab$l_fna = r->nam.nam$l_esa;`009/* File name`009`009*/
X`009r->fab.fab$b_fns = r->nam.nam$b_esl;`009/* Length`009`009*/
X`009r->fab.fab$l_fop |= FAB$M_NAM;`009`009/* Use name block`009*/
X`009return (r);
X}
X`012
Xfdl_free(fdl_descriptor)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
X/*
X * Release the descriptor
X */
X{
X`009if (fdl_descriptor->dsc$a_pointer != NULL) {
X`009    free(fdl_descriptor->dsc$a_pointer);
X`009    fdl_descriptor->dsc$a_pointer = NULL;
X`009}
X}
X
Xfdl_close(r)
Xregister FDLSTUFF`009*r;
X{
X`009if ((fdl_status = sys$close(&r->fab)) != RMS$_NORMAL)
X`009    return(fail(r, "close", NULL));
X`009free(r);
X}
X`012
Xint
Xfdl_read(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Read the next record from the file.  Returns number of bytes read or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_ubf = buffer;
X`009r->rab.rab$w_usz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$read(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    if (fdl_status != RMS$_EOF) {
X`009`009fdl_message(r, "error return from sys$read");
X`009`009sleep(1);
X`009    }
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xint
Xfdl_write(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Write the next record to the file.  Returns number of bytes written or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_rbf = buffer;
X`009r->rab.rab$w_rsz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$write(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    fdl_message(r, "error return from sys$write");
X`009    sleep(1);
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xfdl_getname(r, buffer)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
Xchar`009`009*buffer;`009`009/* Where to put it`009`009*/
X/*
X * Return current file name
X */
X{
X`009strcpy(buffer, r->fab.fab$l_fna);
X`009return (buffer);
X}
X
Xlong
Xfdl_fsize(r)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
X/*
X * Return current file size
X */
X{
X`009return (((long) r->xab.xab$l_ebk * 512) + r->xab.xab$w_ffb);
X}
X
Xfdl_message(r, why)
XFDLSTUFF`009*r;
Xchar`009`009*why;
X/*
X * Print error message
X */
X{
X`009extern char`009*vms_etext();
X
X`009if (why == NULL) {
X`009    fprintf(stderr, "\n%s\n\n", vms_etext(fdl_status));
X`009}
X`009else {
X`009    fprintf(stderr, "\n%s%s%s: %s\n\n",
X`009`009why,
X`009`009(why[0] == EOS) ? "" : " ",
X`009`009(r == NULL) ? "" : r->fab.fab$l_fna,
X`009`009vms_etext(fdl_status));
X`009}
X}
X
Xstatic char`009`009errname[257];`009/* Error text stored here`009*/
Xstatic $DESCRIPTOR(err, errname);`009/* descriptor for error text`009*/
X
Xstatic char *
Xvms_etext(errorcode)
Xint`009`009errorcode;
X{
X`009char`009`009*bp;
X`009short`009`009errlen;`009`009/* Actual text length`009`009*/
X
X`009lib$sys_getmsg(&errorcode, &errlen, &err, &15);
X`009/*
X`009 * Trim trailing junk.
X`009 */
X`009for (bp = &errname[errlen]; --bp >= errname;) {
X`009    if (isgraph(*bp) && *bp != ' ')
X`009`009break;
X`009}
X`009bp[1] = EOS;
X`009return(errname);
X}
X
Xstatic
Xmessage(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/* File name`009`009`009*/
X/*
X * Print error message
X */
X{
X`009fprintf(stderr, "\nRMS error %x when %s %s\n",
X`009    fdl_status, why, (name == NULL) ? "" : name);
X`009fprintf(stderr, "\"%s\"\n", vms_etext(fdl_status));
X}
X`012
Xfdl_dump(fdl_descriptor, fd)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
XFILE`009`009`009*fd;
X/*
X * Dump the descriptor to fd.
X */
X{
X`009register char`009*tp, *end;
X
X`009tp = fdl_descriptor->dsc$a_pointer;
X`009end = tp + fdl_descriptor->dsc$w_length;
X`009while (tp < end) {
X`009    if (*tp == '"') {
X`009`009do {
X`009`009    putc(*tp++, fd);
X`009`009} while (*tp != '"');
X`009    }
X`009    putc(*tp, fd);
X`009    if (*tp++ == ';')
X`009`009putc('\n', fd);
X`009}
X}
X
X`012
X#if`009TESTING_FDLIO
X/*
X * Test program for rms io
X */
X#include <stdio.h>
X
Xchar`009`009`009line[133];
Xchar`009`009`009filename[133];
Xchar`009`009`009buffer[2048];
X
Xmain(argc, argv)
Xint`009`009argc;
Xchar`009`009*argv[];
X{
X`009FDLSTUFF`009*old;
X`009FDLSTUFF`009*new;
X`009int`009`009size, total, nrecords;
X`009struct`009dsc$descriptor`009fdl_info;`009/* Result descriptor`009*/
X
X`009for (;;) {
X`009    fprintf(stderr, "Old file name: ");
X`009    fflush(stdout);
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if (line[0] == EOS)
X`009`009continue;
X`009    if ((old = fdl_open(line, &fdl_info)) == NULL) {
X`009`009fprintf(stderr, "open failed\n");
X`009`009continue;
X`009    }
X`009    fprintf(stderr, "New file name: ");
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if ((new = fdl_create(&fdl_info, line)) == NULL) {
X`009`009fprintf(stderr, "create failed\n");
X`009`009fdl_free(&fdl_info);
X`009`009continue;
X`009    }
X`009    fdl_getname(old, buffer);
X`009    fprintf(stderr, "Fdl for \"%s\", size %ld\n",
X`009`009buffer, fdl_fsize(old));
X`009    fdl_dump(&fdl_info, stderr);
X`009    total = nrecords = 0;
X`009    while ((size = fdl_read(buffer, sizeof buffer, old)) > 0) {
X`009`009fdl_write(buffer, size, new);
X`009`009nrecords++;
X`009`009total += size;
X`009    }
X`009    fdl_close(old);
X`009    fdl_close(new);
X`009    fprintf(stderr, "copied %d records, %d bytes total\n",
X`009`009nrecords, total);
X`009    fdl_free(&fdl_info);
X`009}
X}
X
X#endif
X#endif
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "MAKEFILE.TXT"
$ CHECKSUM_IS = 711590732
$ COPY SYS$INPUT VMS_SHARE_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 UNPACK_FILE
$ FILE_IS = "README.TXT"
$ CHECKSUM_IS = 5852823
$ COPY SYS$INPUT VMS_SHARE_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 UNPACK_FILE
$ FILE_IS = "RULES.MMS"
$ CHECKSUM_IS = 174682289
$ COPY SYS$INPUT VMS_SHARE_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 UNPACK_FILE
$ EXIT
-+-+-+-+-+ End of part 3 +-+-+-+-+-

nagy%warner.hepnet@LBL.GOV (07/19/88)

GVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGV
From: nagy%warner.hepnet@LBL.Gov (Frank J. Nagy, VAX Wizard & Guru)
Subject: Lempel-Ziv file (de)compress from VAX SIG tapes (Part 3 of 3)
To: Info-VAX@kl.sri.com
Return-Path: <@KL.SRI.COM:Info-VAX-RELAY@KL.SRI.COM>
Redistributed: XeroxVAXInterest^.x
Received: from KL.SRI.COM ([10.1.0.2]) by Xerox.COM ; 16 JUL 88 05:22:17 PDT
Received: from LBL.Gov by KL.SRI.COM with TCP; Tue, 12 Jul 88 07:02:11 PDT
Received: from warner.hepnet by LBL.Gov with VMSmail ;	Tue, 12 Jul 88 06:32:13 PDT
Original-Date: Tue, 12 Jul 88 06:32:13 PDT
Message-Id: <880712063213.2760600f@LBL.Gov>
X-ST-Vmsmail-To: INFO_VAX
GVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGVGV

+-+-+-+ Beginning of part 3 +-+-+-+
X`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after open", NULL));
X`009if (fdl_descriptor != NULL) {
X`009    /*
X`009     * Now, get the file attributes
X`009     */
X`009    fdl_descriptor->dsc$w_length = 4096;
X`009    fdl_descriptor->dsc$b_dtype = DSC$K_DTYPE_VT;
X`009    fdl_descriptor->dsc$b_class = DSC$K_CLASS_D;
X`009    fdl_descriptor->dsc$a_pointer = malloc(4096);
X`009    fab_add = &r->fab;
X`009    rab_add = &r->rab;
X`009    if ((fdl_status = fdl$generate(
X`009`009    &flags,
X`009`009    &fab_add,
X`009`009    &rab_add,
X`009`009    0, 0,
X`009`009    fdl_descriptor,
X`009`009    &badblk,
X`009`009    &retlen)) != SS$_NORMAL) {
X`009`009fdl_free(fdl_descriptor);
X`009`009sys$close(&r->fab);
X`009`009return(fail(r, "getting fdl info", NULL));
X`009    }
X`009    /*
X`009     * Success, null-terminate fdl info and squeeze the block.
X`009     */
X`009    fdl_descriptor->dsc$a_pointer[retlen] = EOS;
X`009    fdl_descriptor->dsc$a_pointer
X`009`009= realloc(fdl_descriptor->dsc$a_pointer, retlen + 1);
X`009    fdl_descriptor->dsc$w_length = retlen;
X`009}
X`009return (r);
X}
X`012
XFDLSTUFF *
Xfdl_create(fdl_descriptor, override_filename)
Xstruct`009dsc$descriptor`009*fdl_descriptor;`009/* Result descriptor`009*/
Xchar`009`009`009*override_filename;`009/* What to open`009`009*/
X/*
X * Create 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.)  The file is open for writing using fdl_write.
X *
X * Uses the filename in the descriptor block, or the override filename
X * if supplied (non-NULL and not == "");
X *
X * If fdl_descriptor is NULL, the override_filename is opened normally.
X */
X{
X`009register FDLSTUFF`009*r;
X`009int`009`009`009retlen;
X`009int`009`009`009badblk;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009struct`009dsc$descriptor`009newname;
X`009struct`009dsc$descriptor`009*newname_ptr;
X`009int`009`009`009fid_block[3];
X`009char`009`009`009created_name[NAM$C_MAXRSS + 1];
X`009struct`009dsc$descriptor`009created_name_des = {
X`009`009`009`009    NAM$C_MAXRSS,
X`009`009`009`009    DSC$K_DTYPE_T, 
X`009`009`009`009    DSC$K_CLASS_S,
X`009`009`009`009    &created_name[0]
X`009`009`009`009};
X`009extern FDLSTUFF`009`009*fdl_setup();
X
X`009if (fdl_descriptor == NULL) {
X`009    if ((r = fdl_setup(override_filename)) == NULL)
X`009`009return (NULL);
X`009    r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009    r->fab.fab$l_fop |= (FAB$M_NAM | FAB$M_SQO | FAB$M_BIO);
X`009    r->fab.fab$b_org = FAB$C_SEQ;`009/* Sequential only`009*/
X`009    r->fab.fab$b_rfm = FAB$C_UDF;`009/* Undefined format`009*/
X`009    if ((fdl_status = sys$create(&r->fab)) & 01 == 0)
X`009`009return (fail(r, "creating (sys$create)"));
X`009    goto exit;
X`009}
X`009if (override_filename == NULL || override_filename[0] == '\0')
X`009    newname_ptr = NULL;
X`009else {
X`009    newname_ptr = &newname;
X`009    newname.dsc$w_length = strlen(override_filename);
X`009    newname.dsc$b_dtype = DSC$K_DTYPE_T;
X`009    newname.dsc$b_class = DSC$K_CLASS_S;
X`009    newname.dsc$a_pointer = override_filename;
X`009}
X`009if ((fdl_status = fdl$create(fdl_descriptor,
X`009`009newname_ptr,`009`009/* New file name if any`009`009*/
X`009`0090,`009`009`009/* Default filename`009`009*/
X`009`009&created_name_des,`009/* Resultant filename`009`009*/
X`009`009&fid_block[0],`009`009/* File ID block`009`009*/
X`009`009&flags,`009`009`009/* FDL flag bits`009`009*/
X`009`0090,`009`009`009/* Statement number`009`009*/
X`009`009&retlen,`009`009/* Created name length`009`009*/
X`009`0090, 0)`009`009`009/* Create status, stv`009`009*/
X`009`009) & 01 == 0) {
X`009    return(fail(NULL, "creating (fdl$create)", NULL));
X`009}
X`009created_name[retlen] = '\0';
X`009if ((r = fdl_setup(created_name)) == NULL)
X`009    return (NULL);
X`009/*
X`009 * Now, open the file for output.
X`009 */
X`009r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "opening created file", NULL));
X`009}
Xexit:`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after create", NULL));
X`009return (r);
X}
X`012
Xstatic FDLSTUFF *
Xfdl_setup(filename)
Xchar`009`009*filename;
X/*
X * Initializes rms blocks and parses file name.  Returns the
X * FDL data block on success, NULL on error.
X */
X{
X`009register FDLSTUFF`009*r;
X
X`009if ((r = (char *)malloc(sizeof (FDLSTUFF))) == NULL)
X`009    return (NULL);
X`009r->fab = cc$rms_fab;`009`009`009/* Preset fab,`009`009*/
X`009r->nam = cc$rms_nam;`009`009`009/*   name block`009`009*/
X`009r->rab = cc$rms_rab;`009`009`009/*   and record block`009*/
X`009r->xab = cc$rms_xabfhc;`009`009`009/*   file header block`009*/
X`009r->fab.fab$l_nam = &r->nam;`009`009/* fab -> name block`009*/
X`009r->fab.fab$l_xab = &r->xab;`009`009/* fab -> file header`009*/
X`009r->fab.fab$l_fna = filename;`009`009/* Argument filename`009*/
X`009r->fab.fab$b_fns = strlen(filename);`009/* ... size`009`009*/
X`009r->rab.rab$l_fab = &r->fab;`009`009/* rab -> fab`009`009*/
X`009`009`009`009`009`009/* Stuff the name block`009*/
X`009r->nam.nam$l_esa = r->starname;`009`009/* Expanded filename`009*/
X`009r->nam.nam$b_ess = NAM$C_MAXRSS + 1;`009/* ... size`009`009*/
X`009r->nam.nam$b_rss = NAM$C_MAXRSS + 1;`009/* ... max size`009`009*/
X`009if ((fdl_status = sys$parse(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "parsing", filename));
X`009}
X`009((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS;
X`009r->fab.fab$l_fna = r->nam.nam$l_esa;`009/* File name`009`009*/
X`009r->fab.fab$b_fns = r->nam.nam$b_esl;`009/* Length`009`009*/
X`009r->fab.fab$l_fop |= FAB$M_NAM;`009`009/* Use name block`009*/
X`009return (r);
X}
X`012
Xfdl_free(fdl_descriptor)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
X/*
X * Release the descriptor
X */
X{
X`009if (fdl_descriptor->dsc$a_pointer != NULL) {
X`009    free(fdl_descriptor->dsc$a_pointer);
X`009    fdl_descriptor->dsc$a_pointer = NULL;
X`009}
X}
X
Xfdl_close(r)
Xregister FDLSTUFF`009*r;
X{
X`009if ((fdl_status = sys$close(&r->fab)) != RMS$_NORMAL)
X`009    return(fail(r, "close", NULL));
X`009free(r);
X}
X`012
Xint
Xfdl_read(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Read the next record from the file.  Returns number of bytes read or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_ubf = buffer;
X`009r->rab.rab$w_usz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$read(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    if (fdl_status != RMS$_EOF) {
X`009`009fdl_message(r, "error return from sys$read");
X`009`009sleep(1);
X`009    }
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xint
Xfdl_write(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Write the next record to the file.  Returns number of bytes written or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_rbf = buffer;
X`009r->rab.rab$w_rsz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$write(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    fdl_message(r, "error return from sys$write");
X`009    sleep(1);
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xfdl_getname(r, buffer)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
Xchar`009`009*buffer;`009`009/* Where to put it`009`009*/
X/*
X * Return current file name
X */
X{
X`009strcpy(buffer, r->fab.fab$l_fna);
X`009return (buffer);
X}
X
Xlong
Xfdl_fsize(r)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
X/*
X * Return current file size
X */
X{
X`009return (((long) r->xab.xab$l_ebk * 512) + r->xab.xab$w_ffb);
X}
X
Xfdl_message(r, why)
XFDLSTUFF`009*r;
Xchar`009`009*why;
X/*
X * Print error message
X */
X{
X`009extern char`009*vms_etext();
X
X`009if (why == NULL) {
X`009    fprintf(stderr, "\n%s\n\n", vms_etext(fdl_status));
X`009}
X`009else {
X`009    fprintf(stderr, "\n%s%s%s: %s\n\n",
X`009`009why,
X`009`009(why[0] == EOS) ? "" : " ",
X`009`009(r == NULL) ? "" : r->fab.fab$l_fna,
X`009`009vms_etext(fdl_status));
X`009}
X}
X
Xstatic char`009`009errname[257];`009/* Error text stored here`009*/
Xstatic $DESCRIPTOR(err, errname);`009/* descriptor for error text`009*/
X
Xstatic char *
Xvms_etext(errorcode)
Xint`009`009errorcode;
X{
X`009char`009`009*bp;
X`009short`009`009errlen;`009`009/* Actual text length`009`009*/
X
X`009lib$sys_getmsg(&errorcode, &errlen, &err, &15);
X`009/*
X`009 * Trim trailing junk.
X`009 */
X`009for (bp = &errname[errlen]; --bp >= errname;) {
X`009    if (isgraph(*bp) && *bp != ' ')
X`009`009break;
X`009}
X`009bp[1] = EOS;
X`009return(errname);
X}
X
Xstatic
Xmessage(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/* File name`009`009`009*/
X/*
X * Print error message
X */
X{
X`009fprintf(stderr, "\nRMS error %x when %s %s\n",
X`009    fdl_status, why, (name == NULL) ? "" : name);
X`009fprintf(stderr, "\"%s\"\n", vms_etext(fdl_status));
X}
X`012
Xfdl_dump(fdl_descriptor, fd)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
XFILE`009`009`009*fd;
X/*
X * Dump the descriptor to fd.
X */
X{
X`009register char`009*tp, *end;
X
X`009tp = fdl_descriptor->dsc$a_pointer;
X`009end = tp + fdl_descriptor->dsc$w_length;
X`009while (tp < end) {
X`009    if (*tp == '"') {
X`009`009do {
X`009`009    putc(*tp++, fd);
X`009`009} while (*tp != '"');
X`009    }
X`009    putc(*tp, fd);
X`009    if (*tp++ == ';')
X`009`009putc('\n', fd);
X`009}
X}
X
X`012
X#if`009TESTING_FDLIO
X/*
X * Test program for rms io
X */
X#include <stdio.h>
X
Xchar`009`009`009line[133];
Xchar`009`009`009filename[133];
Xchar`009`009`009buffer[2048];
X
Xmain(argc, argv)
Xint`009`009argc;
Xchar`009`009*argv[];
X{
X`009FDLSTUFF`009*old;
X`009FDLSTUFF`009*new;
X`009int`009`009size, total, nrecords;
X`009struct`009dsc$descriptor`009fdl_info;`009/* Result descriptor`009*/
X
X`009for (;;) {
X`009    fprintf(stderr, "Old file name: ");
X`009    fflush(stdout);
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if (line[0] == EOS)
X`009`009continue;
X`009    if ((old = fdl_open(line, &fdl_info)) == NULL) {
X`009`009fprintf(stderr, "open failed\n");
X`009`009continue;
X`009    }
X`009    fprintf(stderr, "New file name: ");
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if ((new = fdl_create(&fdl_info, line)) == NULL) {
X`009`009fprintf(stderr, "create failed\n");
X`009`009fdl_free(&fdl_info);
X`009`009continue;
X`009    }
X`009    fdl_getname(old, buffer);
X`009    fprintf(stderr, "Fdl for \"%s\", size %ld\n",
X`009`009buffer, fdl_fsize(old));
X`009    fdl_dump(&fdl_info, stderr);
X`009    total = nrecords = 0;
X`009    while ((size = fdl_read(buffer, sizeof buffer, old)) > 0) {
X`009`009fdl_write(buffer, size, new);
X`009`009nrecords++;
X`009`009total += size;
X`009    }
X`009    fdl_close(old);
X`009    fdl_close(new);
X`009    fprintf(stderr, "copied %d records, %d bytes total\n",
X`009`009nrecords, total);
X`009    fdl_free(&fdl_info);
X`009}
X}
X
X#endif
X#endif
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "LZVIOISAM.C"
$ CHECKSUM_IS = 660140431
$ 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`009struct`009XABSUM`009xabsum;`009`009/* Summary 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`009struct XABALL`009`009*xaball;
X`009struct XABKEY`009`009*xabkey,*this_xab;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009extern FDLSTUFF`009`009*fdl_setup();
X`009int`009`009`009i;
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_BRO; /* 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}
X`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X
X`009/* now, we know how many keys (if any) there are in the file, lets
X`009   add that many xabkeys */
X`009this_xab = &r->xabsum;
X`009for (i=0; i < r->xabsum.xab$b_nok; i++)
X`009    {
X `009    if ((xabkey = (char *)malloc(sizeof (struct XABKEY) + 32)) == NULL)
X`009`009return (NULL);
X`009    this_xab->xab$l_nxt = xabkey;
X`009    *xabkey = cc$rms_xabkey;
X`009    xabkey->xab$b_ref = i;
X`009    xabkey->xab$l_knm = xabkey + sizeof(struct XABKEY);
X`009    this_xab = xabkey;
X`009    xabkey = 0;
X`009    }
X
X`009/* we know how many allocation areas (if any) there are in the
X`009   file, lets add that many xaballs and then do a $display */
X`009for (i=0; i < r->xabsum.xab$b_noa; i++)
X`009    {
X`009    if ((xaball = (char *)malloc(sizeof (struct XABALL))) == NULL)
X`009`009return (NULL);
X`009    this_xab->xab$l_nxt = xaball;
X`009    *xaball = cc$rms_xaball;
X`009    xaball->xab$b_aid = i;
X`009    this_xab = xaball;
X`009    xaball = 0;
X`009    }
X
X`009if ((fdl_status = sys$display(&r->fab)) != RMS$_NORMAL)
X`009    return (fail(r, "displaying after adding xabkeys", NULL));
X
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after open", NULL));
X
X`009if (fdl_descriptor != NULL) {
X`009    /*
X`009     * Now, get the file attributes
X`009     */
X`009    fdl_descriptor->dsc$w_length = 4096;
X`009    fdl_descriptor->dsc$b_dtype = DSC$K_DTYPE_VT;
X`009    fdl_descriptor->dsc$b_class = DSC$K_CLASS_D;
X`009    fdl_descriptor->dsc$a_pointer = malloc(4096);
X`009    fab_add = &r->fab;
X`009    rab_add = &r->rab;
X`009    if ((fdl_status = fdl$generate(
X`009`009    &flags,
X`009`009    &fab_add,
X`009`009    &rab_add,
X`009`009    0, 0,
X`009`009    fdl_descriptor,
X`009`009    &badblk,
X`009`009    &retlen)) != SS$_NORMAL) {
X`009`009fdl_free(fdl_descriptor);
X`009`009sys$close(&r->fab);
X`009`009return(fail(r, "getting fdl info", NULL));
X`009    }
X`009    /*
X`009     * Success, null-terminate fdl info and squeeze the block.
X`009     */
X`009    fdl_descriptor->dsc$a_pointer[retlen] = EOS;
X`009    fdl_descriptor->dsc$a_pointer
X`009`009= realloc(fdl_descriptor->dsc$a_pointer, retlen + 1);
X`009    fdl_descriptor->dsc$w_length = retlen;
X`009}
X`009return (r);
X}
X`012
XFDLSTUFF *
Xfdl_create(fdl_descriptor, override_filename)
Xstruct`009dsc$descriptor`009*fdl_descriptor;`009/* Result descriptor`009*/
Xchar`009`009`009*override_filename;`009/* What to open`009`009*/
X/*
X * Create 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.)  The file is open for writing using fdl_write.
X *
X * Uses the filename in the descriptor block, or the override filename
X * if supplied (non-NULL and not == "");
X *
X * If fdl_descriptor is NULL, the override_filename is opened normally.
X */
X{
X`009register FDLSTUFF`009*r;
X`009int`009`009`009retlen;
X`009int`009`009`009badblk;
X`009static int`009`009flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
X`009struct`009dsc$descriptor`009newname;
X`009struct`009dsc$descriptor`009*newname_ptr;
X`009int`009`009`009fid_block[3];
X`009char`009`009`009created_name[NAM$C_MAXRSS + 1];
X`009struct`009dsc$descriptor`009created_name_des = {
X`009`009`009`009    NAM$C_MAXRSS,
X`009`009`009`009    DSC$K_DTYPE_T, 
X`009`009`009`009    DSC$K_CLASS_S,
X`009`009`009`009    &created_name[0]
X`009`009`009`009};
X`009extern FDLSTUFF`009`009*fdl_setup();
X
X`009if (fdl_descriptor == NULL) {
X`009    if ((r = fdl_setup(override_filename)) == NULL)
X`009`009return (NULL);
X`009    r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009    r->fab.fab$l_fop |= (FAB$M_NAM | FAB$M_SQO | FAB$M_BIO);
X`009    r->fab.fab$b_org = FAB$C_SEQ;`009/* Sequential only`009*/
X`009    r->fab.fab$b_rfm = FAB$C_UDF;`009/* Undefined format`009*/
X`009    if ((fdl_status = sys$create(&r->fab)) & 01 == 0)
X`009`009return (fail(r, "creating (sys$create)"));
X`009    goto exit;
X`009}
X`009if (override_filename == NULL || override_filename[0] == '\0')
X`009    newname_ptr = NULL;
X`009else {
X`009    newname_ptr = &newname;
X`009    newname.dsc$w_length = strlen(override_filename);
X`009    newname.dsc$b_dtype = DSC$K_DTYPE_T;
X`009    newname.dsc$b_class = DSC$K_CLASS_S;
X`009    newname.dsc$a_pointer = override_filename;
X`009}
X`009if ((fdl_status = fdl$create(fdl_descriptor,
X`009`009newname_ptr,`009`009/* New file name if any`009`009*/
X`009`0090,`009`009`009/* Default filename`009`009*/
X`009`009&created_name_des,`009/* Resultant filename`009`009*/
X`009`009&fid_block[0],`009`009/* File ID block`009`009*/
X`009`009&flags,`009`009`009/* FDL flag bits`009`009*/
X`009`0090,`009`009`009/* Statement number`009`009*/
X`009`009&retlen,`009`009/* Created name length`009`009*/
X`009`0090, 0)`009`009`009/* Create status, stv`009`009*/
X`009`009) & 01 == 0) {
X`009    return(fail(NULL, "creating (fdl$create)", NULL));
X`009}
X`009created_name[retlen] = '\0';
X`009if ((r = fdl_setup(created_name)) == NULL)
X`009    return (NULL);
X`009/*
X`009 * Now, open the file for output.
X`009 */
X`009r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only`009*/
X`009if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "opening created file", NULL));
X`009}
Xexit:`009if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
X`009    fail(r, "Record only device");
X`009    fdl_close(r);
X`009    return (NULL);
X`009}
X`009r->rab.rab$l_rop = RAB$M_BIO;`009`009/* Block I/O only`009*/
X`009if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
X`009    return (fail(r, "connecting after create", NULL));
X`009return (r);
X}
X`012
Xstatic FDLSTUFF *
Xfdl_setup(filename)
Xchar`009`009*filename;
X/*
X * Initializes rms blocks and parses file name.  Returns the
X * FDL data block on success, NULL on error.
X */
X{
X`009register FDLSTUFF`009*r;
X
X`009if ((r = (char *)malloc(sizeof (FDLSTUFF))) == NULL)
X`009    return (NULL);
X`009r->fab = cc$rms_fab;`009`009`009/* Preset fab,`009`009*/
X`009r->nam = cc$rms_nam;`009`009`009/*   name block`009`009*/
X`009r->rab = cc$rms_rab;`009`009`009/*   and record block`009*/
X`009r->xab = cc$rms_xabfhc;`009`009`009/*   file header block`009*/
X`009r->xabsum = cc$rms_xabsum;`009`009/*   summary block`009*/
X`009r->fab.fab$l_nam = &r->nam;`009`009/* fab -> name block`009*/
X`009r->fab.fab$l_xab = &r->xab;`009`009/* fab -> file header`009*/
X`009r->xab.xab$l_nxt = &r->xabsum;`009`009/* xabfhc -> xabsum`009*/
X`009r->fab.fab$l_fna = filename;`009`009/* Argument filename`009*/
X`009r->fab.fab$b_fns = strlen(filename);`009/* ... size`009`009*/
X`009r->rab.rab$l_fab = &r->fab;`009`009/* rab -> fab`009`009*/
X`009`009`009`009`009`009/* Stuff the name block`009*/
X`009r->nam.nam$l_esa = r->starname;`009`009/* Expanded filename`009*/
X`009r->nam.nam$b_ess = NAM$C_MAXRSS ;`009/* ... size`009`009*/
X`009r->nam.nam$l_rsa = r->filename;`009`009/* Resultant filename`009*/
X`009r->nam.nam$b_rss = NAM$C_MAXRSS ;`009/* ... max size`009`009*/
X`009if ((fdl_status = sys$parse(&r->fab)) != RMS$_NORMAL) {
X`009    return (fail(r, "parsing", filename));
X`009}
X`009((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS;
X`009r->fab.fab$l_fna = r->nam.nam$l_esa;`009/* File name`009`009*/
X`009r->fab.fab$b_fns = r->nam.nam$b_esl;`009/* Length`009`009*/
X`009r->fab.fab$l_fop |= FAB$M_NAM;`009`009/* Use name block`009*/
X`009return (r);
X}
X`012
Xfdl_free(fdl_descriptor)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
X/*
X * Release the descriptor
X */
X{
X`009if (fdl_descriptor->dsc$a_pointer != NULL) {
X`009    free(fdl_descriptor->dsc$a_pointer);
X`009    fdl_descriptor->dsc$a_pointer = NULL;
X`009}
X}
X
Xfdl_close(r)
Xregister FDLSTUFF`009*r;
X{
X`009if ((fdl_status = sys$close(&r->fab)) != RMS$_NORMAL)
X`009    return(fail(r, "close", NULL));
X`009free(r);
X}
X`012
Xint
Xfdl_read(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Read the next record from the file.  Returns number of bytes read or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_ubf = buffer;
X`009r->rab.rab$w_usz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$read(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    if (fdl_status != RMS$_EOF) {
X`009`009fdl_message(r, "error return from sys$read");
X`009`009sleep(1);
X`009    }
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xint
Xfdl_write(buffer, buffer_length, r)
Xchar`009`009*buffer;`009`009/* Record`009`009`009*/
Xint`009`009buffer_length;`009`009/* Record length`009`009*/
Xregister FDLSTUFF *r;`009`009`009/* Record info.`009`009`009*/
X/*
X * Write the next record to the file.  Returns number of bytes written or
X * -1 on any error. fdl_status has the status.
X */
X{
X`009r->rab.rab$l_rbf = buffer;
X`009r->rab.rab$w_rsz = buffer_length;
X`009r->rab.rab$l_bkt = 0;
X`009if ((fdl_status = sys$write(&r->rab)) != RMS$_NORMAL) {
X#if TESTING_FDLIO
X`009    fdl_message(r, "error return from sys$write");
X`009    sleep(1);
X#endif
X`009    return (-1);
X`009}
X`009return (r->rab.rab$w_rsz);
X}
X`012
Xfdl_getname(r, buffer)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
Xchar`009`009*buffer;`009`009/* Where to put it`009`009*/
X/*
X * Return current file name
X */
X{
X`009strcpy(buffer, r->fab.fab$l_fna);
X`009return (buffer);
X}
X
Xlong
Xfdl_fsize(r)
XFDLSTUFF`009*r;`009`009`009/* File pointer`009`009`009*/
X/*
X * Return current file size
X */
X{
X`009return (((long) r->xab.xab$l_ebk * 512) + r->xab.xab$w_ffb);
X}
X
Xfdl_message(r, why)
XFDLSTUFF`009*r;
Xchar`009`009*why;
X/*
X * Print error message
X */
X{
X`009extern char`009*vms_etext();
X
X`009if (why == NULL) {
X`009    fprintf(stderr, "\n%s\n\n", vms_etext(fdl_status));
X`009}
X`009else {
X`009    fprintf(stderr, "\n%s%s%s: %s\n\n",
X`009`009why,
X`009`009(why[0] == EOS) ? "" : " ",
X`009`009(r == NULL) ? "" : r->fab.fab$l_fna,
X`009`009vms_etext(fdl_status));
X`009}
X}
X
Xstatic char`009`009errname[257];`009/* Error text stored here`009*/
Xstatic $DESCRIPTOR(err, errname);`009/* descriptor for error text`009*/
X
Xstatic char *
Xvms_etext(errorcode)
Xint`009`009errorcode;
X{
X`009char`009`009*bp;
X`009short`009`009errlen;`009`009/* Actual text length`009`009*/
X
X`009lib$sys_getmsg(&errorcode, &errlen, &err, &15);
X`009/*
X`009 * Trim trailing junk.
X`009 */
X`009for (bp = &errname[errlen]; --bp >= errname;) {
X`009    if (isgraph(*bp) && *bp != ' ')
X`009`009break;
X`009}
X`009bp[1] = EOS;
X`009return(errname);
X}
X
Xstatic
Xmessage(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/* File name`009`009`009*/
X/*
X * Print error message
X */
X{
X`009fprintf(stderr, "\nRMS error %x when %s %s\n",
X`009    fdl_status, why, (name == NULL) ? "" : name);
X`009fprintf(stderr, "\"%s\"\n", vms_etext(fdl_status));
X}
X`012
Xfdl_dump(fdl_descriptor, fd)
Xstruct`009dsc$descriptor`009*fdl_descriptor;
XFILE`009`009`009*fd;
X/*
X * Dump the descriptor to fd.
X */
X{
X`009register char`009*tp, *end;
X
X`009tp = fdl_descriptor->dsc$a_pointer;
X`009end = tp + fdl_descriptor->dsc$w_length;
X`009while (tp < end) {
X`009    if (*tp == '"') {
X`009`009do {
X`009`009    putc(*tp++, fd);
X`009`009} while (*tp != '"');
X`009    }
X`009    putc(*tp, fd);
X`009    if (*tp++ == ';')
X`009`009putc('\n', fd);
X`009}
X}
X
X`012
X#if`009TESTING_FDLIO
X/*
X * Test program for rms io
X */
X#include <stdio.h>
X
Xchar`009`009`009line[133];
Xchar`009`009`009filename[133];
Xchar`009`009`009buffer[2048];
X
Xmain(argc, argv)
Xint`009`009argc;
Xchar`009`009*argv[];
X{
X`009FDLSTUFF`009*old;
X`009FDLSTUFF`009*new;
X`009int`009`009size, total, nrecords;
X`009struct`009dsc$descriptor`009fdl_info;`009/* Result descriptor`009*/
X
X`009for (;;) {
X`009    fprintf(stderr, "Old file name: ");
X`009    fflush(stdout);
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if (line[0] == EOS)
X`009`009continue;
X`009    if ((old = fdl_open(line, &fdl_info)) == NULL) {
X`009`009fprintf(stderr, "open failed\n");
X`009`009continue;
X`009    }
X`009    fprintf(stderr, "New file name: ");
X`009    if (gets(line) == NULL)
X`009`009break;
X`009    if ((new = fdl_create(&fdl_info, line)) == NULL) {
X`009`009fprintf(stderr, "create failed\n");
X`009`009fdl_free(&fdl_info);
X`009`009continue;
X`009    }
X`009    fdl_getname(old, buffer);
X`009    fprintf(stderr, "Fdl for \"%s\", size %ld\n",
X`009`009buffer, fdl_fsize(old));
X`009    fdl_dump(&fdl_info, stderr);
X`009    total = nrecords = 0;
X`009    while ((size = fdl_read(buffer, sizeof buffer, old)) > 0) {
X`009`009fdl_write(buffer, size, new);
X`009`009nrecords++;
X`009`009total += size;
X`009    }
X`009    fdl_close(old);
X`009    fdl_close(new);
X`009    fprintf(stderr, "copied %d records, %d bytes total\n",
X`009`009nrecords, total);
X`009    fdl_free(&fdl_info);
X`009}
X}
X
X#endif
X#endif
X
$ GOSUB UNPACK_FILE
$ FILE_IS = "MAKEFILE.TXT"
$ CHECKSUM_IS = 711590732
$ COPY SYS$INPUT VMS_SHARE_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 UNPACK_FILE
$ FILE_IS = "README.TXT"
$ CHECKSUM_IS = 5852823
$ COPY SYS$INPUT VMS_SHARE_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 UNPACK_FILE
$ FILE_IS = "RULES.MMS"
$ CHECKSUM_IS = 174682289
$ COPY SYS$INPUT VMS_SHARE_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 UNPACK_FILE
$ EXIT
-+-+-+-+-+ End of part 3 +-+-+-+-+-