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 +-+-+-+-+-