VMS_COMPRESS.BCK\rVMS_COMPRESS.BCKSBACK *.* CMKRNL::[ANONYMOUS.SAVE_SETS]VMS_COMPRESS.BCK/NOCRC/GROUP:0/BLOCK=8192/SAV AWPSYS `7AlV5.1 _VAXB::  V5.0 ,*[DCOLIB.TSLIB_PROGS.COMPRESS]AAAREADME.TXT;1+,=. / 4K -V%0123KPWO 56 7`*189f1G HJ2 CMPR (a VMS File compress and decompress utility)1 DIRECTIONS FOR INSTALLING CMPR?Use BUILD_CMPR.COM to compile and link the CMPR sources, and to=produce the HELP library entry CMPR.HLP. The LINK command in@BUILD_CMPR.COM uses an options file, C_OPTS.OPT, which specifies'the name of the VAXC Run-Time Library. C If you do not have the C compiler then the supplied .EXE shouldB work on a V4.4 system or later. You may also relink the image$ using the supplied object files.A 1) Modify the "image" line in CMPR.CLD to point to where you' have placed the CMPR.EXE image.A 2) Add the CMPR.CLD definition to the system wide dcltables.= If you do not wish to modify the tables, then tell your CMPR< users to place the following line in their login.com files." $ SET COMMAND disk:[spot]CMPR.CLDC If you decide to install the CLD system wide then do the following (From a privileged account)4 $ set command/tables=sys$common:[syslib]dcltables -> /output=sys$common:[syslib]dcltables cmpr $ install == "$install/command"( $ install replace sys$library:dcltables0 Logout and back in to get the new definitions.@ 3) Install the CMPR Help file in the system help directory.0 $ LIBRARY/HELP SYS$HELP:HELPLIB CMPR.HLPDCMPR should now be ready for use. Look in HELP CMPR for all the neat qualifiers.+ DISCUSSION OF SOURCE CODEThe sources for CMPR are:2BUILD_CMPR.COM CMPR.CLD CMPR.H CMPR.RNH3CMPR.C CMPREXT.C CMPRMAIN.C CMPRSHR.C1CMPRUTIL.C DECMPR.C RMSIO.C RMSIO.HACompilation instructions are in BUILD_CMPR.COM. A comment at theBtop of each source file describes the main purpose of the routines in that file.+The C code follows a number of conventions:E o All defined constants, macros, and typedef'd names are uppercase9 o Local variables and function names are all lowercaseA o Global variables start with a single capital letter, so they@ don't look like either defined constants or local variables( o Indentation is by eight column tabs@ o When a statement is broken across multiple lines, all lines/ after the first are indented by half a tab9 o A blank line precedes and follows each comment blockA o Comments do not use pretty formatting, just the minimum open; and close comment pairs, in line with the comment text> o Curly braces are always used, even when they enclose only one statementGTo answer possible complaints, especially about the last two items, letEme point out that the major goals of choosing a style are readabilityHand ease of modification. It would be difficult to find a more flexibleHcomment style than the one used here. Certainly none of the more common1types of comments allow changes nearly so easily:/* * This is a * comment. *//* This is a * * comment. *//*\ * This is a * comment.\*/KAs for using curly braces when they aren't required, the tiny inconvenienceIof typing them in is more than made up for by the guaranteed avoidance ofD"dangling else" errors, and the ease of adding new statements later.KThe remaining conventions are mainly for readability. It seems six of one,Jhalf a dozen of the other whether a space should separate a keyword from aGparenthesized expression, or whether a space should separate a functionIname from its parenthesized argument list. I like the first, but not the1second, however, there isn't any real difference.DUsing all-caps for constants is fairly standard. Using all-caps forDmacro names is not; macro names (following the lead of, for example,Hputchar()/getchar() ) are usually all lowercase. I find it very helpfulJto be able to tell immediately whether something is a function or a macro,Hso that I don't waste time searching all the C files for a function nameIwhich doesn't exist, only to find (eventually) that it is a macro definedIin a .H file. Similarly, capitalizing the first letter of every externalGvariable is a great aid in spotting where non-local data is being used.CMany people prefer four column tabs, rather than eight. I have twoHreasons for favoring eight space tabs. First, a single tab is easier toFtype than four spaces. If you're using a terminal with adjustable tabHstops, this doesn't matter, but many terminals support only eight columnCtabs. Second, to answer the idea that four space tabs allow deeperGnesting without going beyond eighty columns: my own experience is thatHwhen the nesting is deep enough with eight space tabs to push lines pastIeighty columns, it's also getting a bit too deep to be easily understood.GThe innermost few levels should probably be replaced by a new function.CI hope you find CMPR as useful for your purposes as it is for mine.EIf you find time hanging heavy on your hands and want something to doBto fill it, you might have a go at teaching CMPR to handle indexedand/or relative files.BNaturally, if you fix bugs or add useful enhancements, I'd love toAhear about it. I can be reached via BITNET at RITVAXD::JAP5769 . Regards, -Jesse Perry-*[DCOLIB.TSLIB_PROGS.COMPRESS]BUILD_CMPR.COM;1+,I./ 4KB-V%0123KPWO5 6,,7ݪ*189f1G HJ$!$! CMPR version 1.0, April 1987$!K$! Adapted from the public domain program, compress version 3.0, on USENET,C$! which was written by Spencer W. Thomas, Jim McKie, Steve Davies,0$! Ken Turkowski, James A. Woods, and Joe Orost.$!5$! VAX/VMS version copyright (C) 1987 by Jesse Perry.H$! CMPR is in the public domain and may be freely distributed, used, and1$! modified, provided this notice is not removed.$!$! build_cmpr.comA$! This command file creates the CMPR program for the first time.$! $ set verify:$ define/user vaxc$include 'f$env("DEFAULT")', sys$library>$ cc cmprmain, cmpr, decmpr, cmprshr, cmprext, cmprutil, rmsioH$ link /notrace /nodebug /exe=cmpr cmprmain.obj, cmpr.obj, decmpr.obj, -= cmprshr.obj, cmprext.obj, cmprutil.obj, rmsio.obj, c_opts/o$ runoff cmpr.rnh$ set noverify%*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.C;1+,M ./ 4Lf-V%0123KPWO5 6s7 *189f1G HJ VMS_COMPRESS.BCKM V%%[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.C;1L/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed.cmpr.cJThis file contains the routines needed to read and compress a single file.*/#include "cmpr.h"#ifdef SHOWCODE int Def = -1;J#define PRT(ch,asc,hex) printf(((ch >= ' ' && ch < 0x80) ? asc : hex), ch)##define DEFER(chr) if (Def >= 0) {\/ PRT(Def, "CHAR(%c) ", "CHAR(%03X) ") ; \ }\ Def = (chr)#endif3/* The "hog" is the most common input character. */K#define HOG_CHECK ((COUNT_INT)2000) /* amount to read before picking hog */A#define DEF_HOG ' ' /* assume space is most common input char */static COUNT_INT Htab[HSIZE];?static CODE_INT Hsize = HSIZE; /* for dynamic table sizing */&/* Compress input file to output file.JAlgorithm: on large machines, for maxbits <= FBITS, use fast direct tableIlookup on the prefix code / next character combination. For smaller codeLsize, use open addressing modular division double hashing (no chaining), alaJKnuth vol. 3, sec. 6.4 Algorithm D, along with G. Knott's relatively-primeJsecondary probe. Do block compression with an adaptive reset, whereby theIcode table is cleared when the compression ratio decreases, but after theJtable fills. The variable-length output codes are re-sized at this point,Dand a special CLEAR code is generated for the decompressor. For theDmegamemory version, the sparse array is cleared indirectly through aD"shadow" output code history. Late additions: for the hashing code,Kconstruct the table according to file size for noticeable speed improvementEon small files. Also detect and cache codes associated with the mostLcommon character to bypass hash calculation on these codes (a characteristicJof highly-compressable raster images). Please direct questions about thisimplementation to ames!jaw. */$compress(infile, outfile) RMSFILE *infile, *outfile;{ register long fcode; register CODE_INT i = 0; register int c;  register CODE_INT ent; register int disp; register CODE_INT hsize_reg; int found_hog, hog_char; COUNT_INT cfreq[NUMCHAR];6 /* Tune hash table size for small files -- ad hoc. */#if HSIZE > 5003 if (Fsize < (1 << 12)) Hsize = 5003;#if HSIZE > 9001 else if (Fsize < (1 << 13)) Hsize = 9001;#if HSIZE > 18013 else if (Fsize < (1 << 14)) Hsize = 18013;#if HSIZE > 35023 else if (Fsize < (1 << 15)) Hsize = 35023; else if (Fsize < 47000) Hsize = 50021;#endif HSIZE > 35023#endif HSIZE > 18013#endif HSIZE > 9001 else#endif HSIZE > 5003 Hsize = HSIZE; Numchar = NUMCHAR; Bytes_out = 0; Out_count = 0; Clear_flg = 0; Ratio = 0.0; In_count = 1; Chkpnt = CHECK_GAP;' Maxcode = MAXCODE(N_bits = INIT_BITS);( Free_ent = (Blk_cmp ? FIRST : NUMCHAR); ent = rgetc(infile);#ifdef SHOWCODE if (Show_code) { putchar('\n'); DEFER(ent); }#endif#ifdef USERMEM" /* Use hashing on small files. */* if (Maxbits <= FBITS && Fsize >= 30000) {. while ((c = rgetc(infile)) != R_EOF) {#ifdef SHOWCODE if (Show_code) { DEFER(c); }#endif In_count++;. fcode = (long)(((long)c << Maxbits) + ent);) /* Test for code in "string" table. */ if (Ftable[fcode] != 0) { ent = Ftable[fcode]; } else {$ putcode((CODE_INT)ent, outfile); Out_count++; ent = c;" if (Free_ent >= Maxmaxcode) { % if ((COUNT_INT)In_count < Chkpnt || !Blk_cmp) { continue;  } clear(outfile); i = 0; } else { /* Put code in table. */' Ftable[fcode] = (short)Free_ent++;* /* Memorize for block compression. */ Fcodemem[i++] = fcode; } } } goto fin; }#endif USERMEM9 hog_char = DEF_HOG; /* assumed character for the hog */ for (c = 0; c < NUMCHAR; c++) { cfreq[c] = 0; } found_hog = 0; hsize_reg = Hsize;, cl_hash(hsize_reg); /* clear hash tables */' while ((c = rgetc(infile)) != R_EOF) {#ifdef SHOWCODE if (Show_code) { DEFER(c); }#endif In_count++; if (!found_hog) {. /* Gather frequencies at start of input. */ cfreq[c]++;* if ((COUNT_INT)In_count > HOG_CHECK) { found_hog = 1; /* Compute char hog. */ hog_char = hogtally(cfreq);% /* Fixup for wrong assumption. */ if (hog_char != DEF_HOG) {! creset((COUNT_INT)Free_ent); } } } /* Cache -> code */. if (c == hog_char && (i = Hashcache[ent])) { ent = i; continue; }- fcode = (long)(((long)c << Maxbits) + ent);#ifdef SHORT_INTE i = (((c + 12347) * ent) & 077777) % HSIZE; /* avoid 'lrem' call */#else !SHORT_INT1 i = fcode % hsize_reg; /* division hashing */#endif SHORT_INT if (Htab[i] == fcode) { ent = Codetab[i]; continue; } /* Empty slot. */ if ((long)Htab[i] < 0) { goto nomatch; }" /* Secondary hash (G. Knott). */ disp = hsize_reg - i; if (i == 0) { disp = 1; }probe: if ((i -= disp) < 0) { i += hsize_reg; } if (Htab[i] == fcode) { ent = Codetab[i]; continue; }  if ((long)Htab[i] > 0) { goto probe; }nomatch:" putcode((CODE_INT)ent, outfile); Out_count++; if (Free_ent < Maxmaxcode) {+ if (c == hog_char) { /* code -> cache */ Hashcache[ent] = Free_ent; } /* code -> hashtable */ Codetab[i] = Free_ent++; Htab[i] = fcode;< } else if ((COUNT_INT)In_count >= Chkpnt && Blk_cmp) { clear(outfile); } ent = c; }fin: /* Put out the final code. */! putcode((CODE_INT)ent, outfile); Out_count++; putcode((CODE_INT)-1, outfile); /* Print stats on stderr. */ if (!Quiet) { #ifdef DEBUG fprintf(stderr,I "%ld chars in, %ld codes (%ld bytes) out, compression factor %g\n",% In_count, Out_count, Bytes_out,, (double)In_count / (double)Bytes_out);6 fprintf(stderr, "\tLargest code was %d (%d bits)\n", Free_ent - 1, N_bits); #endif DEBUG9 fprintf(stderr, "%s: %5.2f%% compression\r\n", Infname,9 100.0 * (In_count - Bytes_out) / (double)In_count); }8 if (Bytes_out > In_count) { /* exit(2) if no savings */ Exit_stat = 1; }}F/* Output the given code. This routine assumes that a char is 8 bits.DIt maintains a buffer which is BITS chars long, so that 8 codes will7exactly fill it. EOF is indicated by code value -1. */staticputcode(code, outfile)CODE_INT code;RMSFILE *outfile;{ #ifdef DEBUG static int col = 0; #endif DEBUG static int offset; static char buf[BITS];#ifndef USE_VMS_RTL register#endif USE_VMS_RTL( int r_off = offset, bits = N_bits; register char *bp = buf;#ifdef SHOWCODEif (Show_code) {printf("CODE(%04X)\n", code); DEFER(-1);}#endif /* Flush buffer at EOF. */ if (code < 0) { bits = (offset + 7) / 8; if (offset > 0) {" rwrite(buf, 1, bits, outfile); } Bytes_out += bits; offset = 0; #ifdef DEBUG if (Verbose) { fprintf(stderr, "\n"); } #endif DEBUG return; }/ /* Not at EOF -- add latest code to buffer. */ #ifdef DEBUG) /* Print value of code being written. */ if (Verbose) { fprintf(stderr, "%5d%c", code,0  VMS_COMPRESS.BCKM V%%[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.C;1L (col += 6) >= 74 ? (col = 0, '\n') : ' '); }#endif DEBUG #ifdef USE_VMS_RTL$ lib$insv(&code, &r_off, &bits, bp);#else  /* Get to the first byte. */ bp += (r_off >> 3); r_off &= 7;5 /* Since code is always >= 8 bits, only need to mask the first hunk on the left. */= *bp = (*bp & Rmask[r_off]) | (code << r_off) & Lmask[r_off]; bp++; bits -= (8 - r_off); code >>= 8 - r_off;A /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ if (bits >= 8) { *bp++ = code; code >>= 8; bits -= 8; } /* Last bits. */ if (bits) { *bp = code; }#endif USE_VMS_RTL/ /* If buffer is full, write it to the file. */+ if ((offset += N_bits) >= (N_bits << 3)) {" rwrite(buf, 1, N_bits, outfile); Bytes_out += N_bits; offset = 0; }? /* If the next entry is going to be too big for the code size," then increase it, if possible. */' if (Free_ent > Maxcode || Clear_flg) {3 /* Write the whole buffer, because the input side1 won't discover the size increase until after it has read it. */  if (offset > 0) {' rwrite(buf, 1, N_bits, outfile); Bytes_out += N_bits; offset = 0; } if (Clear_flg) {) Maxcode = MAXCODE(N_bits = INIT_BITS); Clear_flg = 0; } else { N_bits++; if (N_bits == Maxbits) { Maxcode = Maxmaxcode; } else { Maxcode = MAXCODE(N_bits); } } #ifdef DEBUG if (Debug) {4 fprintf(stderr, "\nChange to %d bits\n", N_bits); col = 0; } #endif DEBUG }}%/* Table clear for block compress. */staticclear(outfile)RMSFILE *outfile;{ register CODE_INT i; register COUNT_INT *p, *endp; register unsigned short *q; double new_ratio;2 new_ratio = (double)In_count / (double)Bytes_out; #ifdef DEBUG if (Debug) {4 fprintf(stderr, "count: %ld -- ratio: %f\n", In_count, new_ratio); } #endif DEBUG Chkpnt = In_count + CHECK_GAP; if (new_ratio > Ratio) { Ratio = new_ratio; } else { Ratio = 0.0;#ifdef USERMEM3 if (Maxbits <= FBITS) { /* sparse array clear */. for (i = (1 << Maxbits) - 1; i >= 0; i--) { /* indirect thru "shadow" */ Ftable[Fcodemem[i]] = 0; } } else )#endif USERMEM /* hash table clear */ { endp = &Htab[Hsize];3 for (p = &Htab[0], q = &Codetab[0]; p < endp;) { *p++ = -1; *q++ = 0; } creset(MAX_CACHE); } Free_ent = FIRST; Clear_flg = 1;$ putcode((CODE_INT)CLEAR, outfile); #ifdef DEBUG if (Debug) { fprintf(stderr, "clear\n"); } #endif DEBUG }}static creset(n) /* clear hash cache */<register COUNT_INT n; /* clear at least this many entries */{ register COUNT_INT i;! register unsigned short *hash_p;" register unsigned short zero = 0; static int nfiles = 0;9 if (nfiles++ == 0) { /* No clear needed if first time */ return;  } n = (n + 15) & (-16); hash_p = Hashcache + n;% for (i = n; i > 0; i -= 16) { *(hash_p-16) = zero; *(hash_p-15) = zero; *(hash_p-14) = zero; *(hash_p-13) = zero; *(hash_p-12) = zero; *(hash_p-11) = zero; *(hash_p-10) = zero; *(hash_p-9) = zero; *(hash_p-8) = zero; *(hash_p-7) = zero; *(hash_p-6) = zero; *(hash_p-5) = zero; *(hash_p-4) = zero; *(hash_p-3) = zero; *(hash_p-2) = zero; *(hash_p-1) = zero; hash_p -= 16; }}staticcl_hash(hsize)register int hsize;{+ register COUNT_INT *htab_p = Htab + hsize; register int i; register long m1 = -1; /* clear hashcache */* creset(MIN((COUNT_INT)hsize, MAX_CACHE)); i = hsize - 16; do { *(htab_p-16) = m1; *(htab_p-15) = m1; *(htab_p-14) = m1; *(htab_p-13) = m1; *(htab_p-12) = m1; *(htab_p-11) = m1; *(htab_p-10) = m1; *(htab_p-9) = m1; *(htab_p-8) = m1; *(htab_p-7) = m1; *(htab_p-6) = m1; *(htab_p-5) = m1; *(htab_p-4) = m1; *(htab_p-3) = m1; *(htab_p-2) = m1; *(htab_p-1) = m1; htab_p -= 16; } while ((i -= 16) >= 0); for (i += 16; i > 0; i--) { *--htab_p = m1; }}!/* Compute character code hog. */statichogtally(freqptr)register COUNT_INT *freqptr;{ register int i, most;' for (i = most = 0; i < NUMCHAR; i++) {+ if (freqptr[i] >= freqptr[most]) { most = i;  } } return (most);}'*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.CLD;2+,R./ 4Jj-V%0123KPWO56RO7*189f1G HJ!! CMPR version 1.0, April 1987!J! Adapted from the public domain program, compress version 3.0, on USENET,B! which was written by Spencer W. Thomas, Jim McKie, Steve Davies,/! Ken Turkowski, James A. Woods, and Joe Orost.!4! VAX/VMS version copyright (C) 1987 by Jesse Perry.G! CMPR is in the public domain and may be freely distributed, used, and0! modified, provided this notice is not removed.! ! cmpr.cldG! This file defines the parameters and qualifiers for the CMPR command.define verb cmpr7 image cmpr ! <-- Change this line to the full pathname) ! of the installed executable CMPR.EXE< parameter p1, label=File, value(required, list, type=$file) qualifier compress, default qualifier delete< qualifier output, nonnegatable, value(required, type=$file)-! qualifier showcode ! for debugging use only qualifier uncompress'*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.EXE;1+,./ 4-V%0123 KPWO56g<'Al7q'Al89G HJ0DX0205(q&Al| X CMPRV1.0vq&Al05-02  * ++ ,,>  ? ! VAXCRTL_001B!d FORRTL_001! LIBRTL_001! MTHRTL_001!f SMGSHR_001DELETEOUTPUTUNCOMPRESSFILECannot open %s Bad output file spec "%s" DIR%s: directory file, not compressed %s: %s file, not compressed indexedrelativeCannot create %s Bad file name "%s" Cannot open %s Bad output file spec "%s" %s: unknown compression format, cannot decompress %s: uses %d bits, current maximum is %d bits Cannot create %s CMPR.OUT%s%s%s: %5.2f%% compression _Z ' VMS_COMPRESS.BCKV%'[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.EXE;1?~<^;$R"UoSb\P\\<~ߢP|TߢPTe  eeexe<~ߢP%Pd<~ߢPT#Pά^UV#XW߭x|~ݬPTݬߥhG#ЬRbԮd)PRPdRߥ.h#""Y#ZV#l6[hpޮpRItޮtSЮpP``;ЮpP`]PPP```;ЮtRtcb``;딾tߥIIiP@Ic"PIߥMhj1)R&R ŘSPŐSSIߥrhj1P|ݭiP|~߭߭,ѭ1 ѭ1I!!ЭˏLRR@9JMTNФPBTKV)W+X*Y#Z5M8800((ހXYTEݮlI[P8800((ހzЏ@ _Фk[E;PSEšhj1PSf~kS~kSN~kSMˏdRST~SlS TlRݭiP߭ TP1jT%T< ծd ݮd- ^ﻥUVZ[/YݬPRݬųR ͐͐RЬRRPSiPSiCbPiixPS޼RCbo|~ݬPTݬVЬRbԮT-PRPTR"W XXTgPTgPTgPfRQbQ3Qj\ޮ\R͐`ޮ`SЮ\P` P`;Ю\P`]PPP```;Ю`R`cb``;딾`j$vRb͐h1bPˏfʏffSxS SS͐%h1$<kP͈͈̈́̈́̀̀6jkyJPT4Ⱝɏ ڐ㐭АФ͌ݮ\͐͌PR͌ShPˏdSRT T\R\R"SݭP߭MTXP1TTծT ݮTP ^ЬPЬRPQaa;PQPa]QPQaaa; aa;,^Z[ݬPXXլsPXPeլkݬnݬ ЬSSPRkPRkЭP@cPЭP@cSݬ ЬS'RcPPRЬ RR߭ЭP@bSSRBxSPPެ о TYITYPP|RhWdVY TBUfPRP CUgPSPݬ U߭} SRYЬSkPլSkݬ  RBJЭP@Ь SSSRS b Ь P֬ `׬ kí ~P­ PXP XwP<^͡P8800((͡P͢ЬݬPAA`8800((XA`B IMK|~͡0PQQPPQPLRBRRSRUce; URUb~e.] URUb}PPURR~[PTPPPUPPPUUCdzPͅPPͅPPd{P͉PP͉PP|P͍PP͍PP}P͑PP͑PP~P͕PP͕PPdRSQPP SP@bQS嚤RdPPRdRBԭ|~߭߭88PRR PˏRSR@SSTP^ݬ^[Y5XRR <$6\R  <)#$6GR@ <]F$63R <ψ$6R RRV1x>TWVWSzSP{UPQPPRBhS €~^ЬP"PʏPЬPѠPb ^ЬRŬ PPQPSQPݬ~SPSP P^ЬSTլ CXXWXV*UVRW ݬePTPPRPRPTT TP^ЬQ С ԭ|~߭߭߭FPQQPP Q8ˏPQP@QQP<`^,n䐏Pݬ^|VX^,n䐏Qݬf^PRݬll$լ ݬf  RP|;VD^,nȐSȞ+؞ܕlլݬfЬ̑lլ  lլ,n䞭l լ Ь l լЬlլ ݬf^<`^,n䐏Tul լЬ^<`^,n䐏U@4ݬ^@@`d|D$"  `HP, z  @VAXCRTLFORRTLLIBRTLMTHRTLSMGSHRz %*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.H;1+,u. / 4N -V%0123KPWO 5 6`x7#*189f1G HJ/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed.cmpr.hDThis file defines constants, macros, and typedef'd names, as well asall external variables.*/#include #include "rmsio.h"#include #include #include E/* Header information stored at beginning of each compressed file. */typedef struct {< char ch_bks; /* bucket size (relative or indexed files) */) short ch_gbc; /* global buffer count */, long ch_fop; /* file processing options */4 short ch_mrs; /* maximum record size, fab$w_mrs */3 char ch_fsz; /* fixed control information size */& char ch_org; /* file organization */. char ch_rfm; /* record format, fab$b_rfm */1 char ch_rat; /* record attributes, fab$b_rat */2 char ch_shr; /* allowed shareable access mask */ } CMP_HEAD;typedef int (*PFI)();/*BUSERMEM is used to determine the maximum BITS that can be used forGcompression. If USERMEM is big enough, use fast compression algorithm.DDefine FBITS for machines with several MB of physical memory, to useGtable lookup for (b <= FBITS). If FBITS is made too large, performanceHwill decrease due to increased swapping/paging. Since the program minusFthe fast lookup table is about a half Meg, we can allocate the rest of3available physical memory to the fast lookup table.BIf FBITS is set to 12, a 2 MB array is allocated, but only 1 MB is,addressed for parity-free input (i.e. text).5FBITS=10 yields 1/2 meg lookup table + 4K code memory3FBITS=11 yields 1 meg lookup table + 8K code memory4FBITS=12 yields 2 meg lookup table + 16K code memory4FBITS=13 yields 4 meg lookup table + 32K code memory*/#ifdef PIG_MEM#define USERMEM 4244480#define FBITS 14#endif#define BITS 16)#define HSIZE 69001 /* 95% occupancy */N/* A CODE_INT must be able to hold 2**BITS values of type int, and also -1. */ #if BITS > 15typedef long int CODE_INT;#elsetypedef int CODE_INT;#endiftypedef long COUNT_INT;typedef short CHAR_TYPE;F/* Defines for third byte of header. Masks 0x40 and 0x20 are free. IMthink 0x20 should mean that there is a fourth header byte (for expansion). */#define BIT_MASK 0x1F#define BLOCK_MASK 0x806#define INIT_BITS 9 /* initial number of bits/code */-#define MAXCODE(N_bits) ((1 << (N_bits)) - 1)A/* One code could conceivably represent (1<to get a code of length N requires an input string of at least=N*(N-1)/2 characters. With 5000 chars in the stack, an input?file would have to contain a 25Mb string of a single character.This seems unlikely. */#ifdef SHORT_INT1#define MAXSTACK 5000 /* size of output stack */#else1#define MAXSTACK 8000 /* size of output stack */#endif##define MAXDUMPSTACK (4 * MAXSTACK)<#define Tab_prefix Codetab /* prefix code for this entry */CODE_INT getcode();?/* Block compression parameters -- after all codes are used up,(compression rate changes, start over. */2#define CHECK_GAP 10000 /* ratio check interval */E/* The next two codes should not be changed lightly, as they must not1lie within the contiguous general code space. */ 4#define NUMCHAR 257 /* number of distinct VMS_COMPRESS.BCKuV%%[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.H;1N p values in" character set being encoded */4#define CLEAR Numchar /* table clear output code */:#define FIRST (CLEAR + 1) /* number of first free entry */M#define MAX_CACHE ((COUNT_INT)1 << BITS) /* Next line is this constant too */*#define MIN(a,b) (((a) > (b)) ? (b) : (a))##define ERRSTAT(stat) (~(stat) & 1)extern int Numchar;extern PFI Decrdf;#ifdef SHOWCODEextern int Show_code;#endifextern char Stamp[];extern char Oldstamp[];extern char Oldfmt;extern char Infname[256];extern int N_bits;extern int Maxbits;extern CODE_INT Maxcode;extern CODE_INT Maxmaxcode;%extern unsigned short Codetab[HSIZE];extern COUNT_INT Fsize;'extern CHAR_TYPE Tab_suffix[1 << BITS];#ifdef USERMEM,extern short Ftable[(1 << FBITS) * NUMCHAR];&extern COUNT_INT Fcodemem[1 << FBITS];#endif USERMEMextern CODE_INT Free_ent;extern int Exit_stat; #ifdef DEBUGextern int Debug; #endif DEBUGextern int Quiet;extern int Verbose;extern int Force;extern int Blk_cmp;extern int Clear_flg;extern double Ratio;extern COUNT_INT Chkpnt;extern long int In_count;extern long int Bytes_out;extern long int Out_count;+extern unsigned short Hashcache[1 << BITS];extern unsigned char Lmask[9];extern unsigned char Rmask[9];'*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.HLP;2+,. / 4G -V%0123KPWO56'Al75(Al89G HJ1 CMPR / Compresses or uncompresses sequential files.  Format:   CMPR file-spec[,...]  G Compressed files are binary data. This means that the contents are 1 not readable. DO NOT PRINT A COMPRESSED FILE.  G When you need the contents of a compressed file, use the /UNCOMPRESS , qualifier to re-create the original file. 2 Parameter G The name of the file to be compressed. Several file names can be G given, separated by commas. For each named file, CMPR will create a G compressed file with the same name, but with "_Z" appended to the G file type. For example, if you have two files called REPORT.RNO and  REFERENCES.TXT, the command  ( $ CMPR REPORT.RNO, REFERENCES.TXT  C will create two files called REPORT.RNO_Z and REFERENCES.TXT_Z . 2 /DELETE G This qualifier causes CMPR to automatically delete each input file G after creating the corresponding compressed or uncompressed output  file. 2 /UNCOMPRESS G This qualifier tells CMPR to decompress the named file(s) and % re-create the original version(s). 2 /OUTPUT=FILESPEC G By default, CMPR creates an output file with a name based on the G name of the input file. This qualifier forces CMPR to use some G other name. If the FILESPEC is a directory path, all output files G will have default names, but they will be placed in the specified directory.  G Use /OUTPUT=TT: to have the output sent to the terminal. NOTE: G This should only be used in conjunction with the /UNCOMPRESS G qualifier -- compressed files contain binary information which will G not print nicely on a terminal screen (just like .EXE or .OBJ files).  Examples:  G This command compress all FORTRAN files in the current directory G and stores the compressed files in a subdirectory called  ARCHIVE.DIR .  ' $ CMPR/OUTPUT=[.ARCHIVE] *.FOR  G This command decompresses a file called PHONELIST.TXTZ and prints # the contents on the terminal:  5 $ CMPR/UNCOMPRESS/OUTPUT=TT: PHONELIST.TXTZ 2 Usage_notes G CMPR is based on the COMPRESS program from USENET. It creates a G compressed file for each file named in the parameter list. The G compressed files require less disk space than the original files. G The original files can then be deleted. When the data in the G original files is needed, the original files can be re-created using G the /UNCOMPRESS qualifier. CMPR preserves RMS file format G information, so that when a file is decompressed it will have the $ same format as the original file.  G To view the contents of a compressed file without creating the G decompressed file, use the qualifiers /UNCOMPRESS/OUTPUT=TT: . G This will make CMPR send the information to the screen, just as TYPE  does for ordinary files.  G CMPR only compresses sequential files; it cannot compress indexed or < relative files (such as NOTES$NOTEBOOK.NOTE or MAIL.MAI).  G Compressing a file which is already compressed usually WASTES space. : This is indicated by a negative compression percentage. '*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPR.OBJ;1+,}. / 4  -V%0123KPWO56 OAl7`UAl89G HJ1CMPRV1.024-JUN-1989 19:42VAX C V3.0-031$6P #P%s: %5.2f%% compression P^[YXRR <$6\R  <)#$6GR@ <]F$63R <ψ$6R To view the contents of a compressed file without creating theDdecompressed file, use the qualifiers /UNCOMPRESS/OUTPUT=TT: . ThisDwill make CMPR send the information to the screen, just as TYPE doesfor ordinary files..b 1ACMPR only compresses sequential files; it cannot compress indexed<or relative files (such as NOTES$NOTEBOOK.NOTE or MAIL.MAI)..b 1DCompressing a file which is already compressed usually WASTES space.7This is indicated by a negative compression percentage.(*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPREXT.C;1+,)./ 4J\-V%0123KPWO5 6t7[\*189f1G HJ/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed. cmprext.c>This file contains the declarations of all external variables.*/#include "cmpr.h" int Numchar; PFI Decrdf;C/* Show_code is a flag to turn on a very verbose description of theCinput and output characters/codes. To obtain this description, youCmust (1) edit the cld file CMPR.CLD and make sure that the SHOWCODEBqualifier is not commented out, and (2) edit CMPR.H and add a lineat the top as follows:#define SHOWCODEFThen $ MAKE CMPR to create an executable which recognizes the SHOWCODECqualifier. Be careful not to install such a version on the system,Fsince this qualifier would only confuse the user if given accidentally#(as in /S, a common typo of /A). */#ifdef SHOWCODEint Show_code;#endifHchar Stamp[] = { 0x1A, 0x7E }; /* stamp for ordinary compressed file */>char Oldstamp[] = { 0x1F, 0x9D }; /* stamp used by COMPRESS */6char Oldfmt; /* TRUE if decompressing old format */<char Infname[256]; /* name of file now being compressed */(int N_bits; /* number of bits/code */9int Maxbits = BITS; /* user settable max # bits/code */4CODE_INT Maxcode; /* maximum code, given N_bits */FCODE_INT Maxmaxcode = 1 << BITS; /* should NEVER generate this code */unsigned short Codetab[HSIZE];COUNT_INT Fsize;>CHAR_TYPE Tab_suffix[1 << BITS]; /* last char in this entry */#ifdef USERMEM%short Ftable[(1 << FBITS) * NUMCHAR];COUNT_INT Fcodemem[1 << FBITS];#endif USERMEM1CODE_INT Free_ent = 0; /* first unused entry */int Exit_stat = 1; #ifdef DEBUGint Debug = 0; #endif DEBUG5int Quiet = 0; /* don't tell me about compression */ in VMS_COMPRESS.BCK)V%([DCOLIB.TSLIB_PROGS.COMPRESS]CMPREXT.C;1J}t Verbose;int Force = 0;int Blk_cmp = BLOCK_MASK;int Clear_flg = 0;:double Ratio = 0.0; /* compression ratio for last block */COUNT_INT Chkpnt = CHECK_GAP;.long int In_count = 1; /* length of input */7long int Bytes_out; /* length of compressed output */Along int Out_count = 0; /* # of codes output (for debugging) */Junsigned short Hashcache[1 << BITS]; /* common hash short circuit cache */2unsigned char Lmask[9] = { 0xFF, 0xFE, 0xFC, 0xF8,$ 0xF0, 0xE0, 0xC0, 0x80, 0x00 };2unsigned char Rmask[9] = { 0x00, 0x01, 0x03, 0x07,$ 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };**[DCOLIB.TSLIB_PROGS.COMPRESS]CMPREXT.OBJ;1+,!./ 4 -V%0123KPWO56 OAl7ZAl89G HJ4CMPREXTV1.024-JUN-1989 19:42VAX C V3.0-031RCMPREXT CC$RMS_NAM CC$RMS_FAB CC$RMS_RAB CC$RMS_XABALL CC$RMS_XABDAT CC$RMS_XABFHC CC$RMS_XABKEY CC$RMS_XABPRO CC$RMS_XABRDT CC$RMS_XABSUM CC$RMS_XABTRM C$V_CTYPEDEFS$CODE$DATAERRNOSTDINSTDOUTSTDERR_CTYPE_NUMCHARDECRDFSTAMPOLDSTAMPOLDFMTINFNAMEN_BITSMAXBITSMAXCODE MAXMAXCODECODETABFSIZE TAB_SUFFIXFREE_ENT EXIT_STATQUIETVERBOSEFORCEBLK_CMP CLEAR_FLGRATIOCHKPNTIN_COUNT BYTES_OUT OUT_COUNT HASHCACHE LMASK RMASKc P~ PPPPPP'P!P"P?P)*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRMAIN.C;1+,.$/ 4K$"-V%0123KPWO#5 6 u7`n*189f1G HJ/*CMPR version 1.0, April 1987;Adapted from compress v3.0 (for Un*x) which was written by:7Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)Jim McKie (decvax!mcvax!jim)-Steve Davies (decvax!vax135!petsd!peora!srd),Ken Turkowski (decvax!decwrl!turtlevax!ken)'James A. Woods (decvax!ihnp4!ames!jaw)$Joe Orost (decvax!vax135!petsd!joe)2VAX/VMS version copyright (C) 1987 by Jesse Perry.;CMPR is in the public domain and may be freely distributed,8used, and modified, provided this notice is not removed. cmprmain.cEThis file contains the main program, which reads the DCL command lineGqualifiers and parameters. It also contains the routines which control'compression and decompression of files.*/#include #include #include "cmpr.h"E/* This structure is allocated to include enough space for the entireEfile name (the array fnm_str[] is actually variable-size). The otherCelements are indices into the array where various parts of the fileCname begin. Finally, fnm_fod is set TRUE by fnmparse() if the fileDname specifies a file oriented device, otherwise (for example if theEfile name specifies a terminal or mailbox) fnm_fod is set FALSE. TheDorder of these elements cannot be changed independent of fnmparse(),4which counts on their being in the current order. */typedef struct {A unsigned char fnm_dev; /* index of device name in name string */? unsigned char fnm_dir; /* index of directory in name string */? unsigned char fnm_nam; /* index of file name in name string */? unsigned char fnm_typ; /* index of file type in name string */D unsigned char fnm_ver; /* index of version number in name string */= unsigned char fnm_fod; /* TRUE if device is file oriented */< char fnm_str[1]; /* space allocated for file name string */ } FNMCOMP;FNMCOMP *fnmparse();F/* Algorithm from "A Technique for High Performance Data Compression",@Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.DModified Lempel-Ziv method (LZW). Basically finds common substringsDand replaces them with a variable size code. This is deterministic,Dand can be done on the fly. Thus, the decompression procedure needsCno input table, but tracks the way the original table was built. */Estatic char Cmpfend[] = "_Z"; /* appended to compressed file types */Istatic char Delete; /* TRUE to delete input file after (un)compression */main(){ int cmpr(), decmpr(); PFI actionf;" char infname[260], outfname[260];9 /* Determine what command line qualifiers were given. */$ Delete = cli_present("DELETE") > 0;? if (cli_get_value("OUTPUT", outfname, sizeof(outfname)) < 0) { outfname[0] = '\0'; }#ifdef SHOWCODE) Show_code = cli_present("SHOWCODE") > 0;#endif actionf = cmpr;% if (cli_present("UNCOMPRESS") > 0) { actionf = decmpr; } /* Set maximum code length. */ if (Maxbits < INIT_BITS) { Maxbits = INIT_BITS; } if (Maxbits > BITS) { Maxbits = BITS; } Maxmaxcode = 1 << Maxbits;; /* Loop to process each file named on the command line. */? while (cli_get_value("FILE", infname, sizeof(infname)) >= 0) {7 /* Do compression or decompression of file, depending* on whether /UNCOMPRESS was requested. */ (*actionf)(infname, outfname); } comp_exit(Exit_stat);}'/* Compress the named input file(s). */cmpr(inname, outdef)char *inname, *outdef;{ int ver_ok, in_is_fod; RMSFILE *infile, *outfile; FNMCOMP *innm, *outnm; int innmdsc[2]; struct stat statbuf; struct FAB outfab; CMP_HEAD cmpfhead;" unsigned int deadline[2], cdt[2]; int dtnmdsc[2];" char innmbuf[260], outnmbuf[260];  /* Open input file. */ sys$gettim(deadline);7 if ((infile = ropen(inname, R_READ, NULL)) == NULL) {. fprintf(stderr, "Cannot open %s\n", inname); return; }( /* Parse output file spec, if given. */) if (outdef == NULL || *outdef == '\0') { outnm = NULL;1 } else if ((outnm = fnmparse(outdef)) == NULL) {; fprintf(stderr, "Bad output file spec \"%s\"\n", outdef); exit(1); }3 /* Compress each file matched by inname, which may contain wild-cards. */ do {" /* Skip over directory files. */( simplename(infile->rf_rsbuf, innmbuf);: if (strcmp(&innmbuf[strlen(innmbuf) - 3], "DIR") == 0) {; fprintf(stderr, "%s: directory file, not compressed\n", innmbuf); continue; }1 /* Also skip files which are not sequential. */. if (infile->rf_fab.fab$b_org != FAB$C_SEQ) {4 fprintf(stderr, "%s: %s file, not compressed\n",9 innmbuf, (infile->rf_fab.fab$b_org == FAB$C_REL ? "relative" : "indexed")); continue; }? /* Skip file just opened if it was created after deadline. */ cdt[0] = cdt[1] = 0;: dtnmdsc[0] = strlen(dtnmdsc[1] = (int)infile->rf_rsbuf);+ getfdate(dtnmdsc, cdt, NULL, NULL, NULL); if (cdt[1] > deadline[1]; || (cdt[1] == deadline[1] && cdt[0] > deadline[0])) { continue; } strcpy(Infname, innmbuf);,  VMS_COMPRESS.BCKV%)[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRMAIN.C;1K$f /* Get input file size, used by cmpr(). */# stat(infile->rf_rsbuf, &statbuf); Fsize = (long)statbuf.st_size;0 /* Initialize compressed file header block. */C if ((infile->rf_fab.fab$l_dev & DEV$M_FOD) == DEV$M_FOD) {1 /* If input is from file-oriented device, copy its file characteristics. */. cmpfhead.ch_bks = infile->rf_fab.fab$b_bks;. cmpfhead.ch_gbc = infile->rf_fab.fab$w_gbc;. cmpfhead.ch_fop = infile->rf_fab.fab$l_fop;. cmpfhead.ch_mrs = infile->rf_fab.fab$w_mrs;. cmpfhead.ch_fsz = infile->rf_fab.fab$b_fsz;. cmpfhead.ch_org = infile->rf_fab.fab$b_org;/ cmpfhead.ch_rfm = infile->rf_fab.fab$b_rfm;. cmpfhead.ch_rat = infile->rf_fab.fab$b_rat;. cmpfhead.ch_shr = infile->rf_fab.fab$b_shr; } else {7 /* Otherwise, assume normal text characteristics. */9 lib$movc5(&0, 0, &'\0', &sizeof(cmpfhead), &cmpfhead); cmpfhead.ch_rfm = FAB$C_VAR; cmpfhead.ch_rat = FAB$M_CR; cmpfhead.ch_mrs = 255; } /* Create output file. */* mkfname(innmbuf, outnm, outnmbuf, TRUE);7 lib$movc5(&0, NULL, &'\0', &sizeof(outfab), &outfab); outfab.fab$b_rfm = FAB$C_UDF;7 outfab.fab$l_fop = FAB$M_TEF | FAB$M_SQO | FAB$M_CBT;. outfab.fab$l_alq = infile->rf_fab.fab$l_alq; if (outfab.fab$l_alq < 0) { outfab.fab$l_alq = 0; }> if ((outfile = ropen(outnmbuf, R_WRITE, &outfab)) == NULL) {3 fprintf(stderr, "Cannot create %s\n", outnmbuf); continue; } rputc(Stamp[0], outfile); rputc(Stamp[1], outfile);$ rputc(Maxbits | Blk_cmp, outfile);2 rwrite(&cmpfhead, 1, sizeof(cmpfhead), outfile);2 /* Compress input file to create output file. */' in_is_fod = infile->rf_flag & RF_FOD; compress(infile, outfile); rclose(outfile); rfinish(infile);2 /* Remove input file if /DELETE option given. */ if (Delete && in_is_fod) {; innmdsc[0] = strlen(innmdsc[1] = (int)infile->rf_rsbuf); lib$delete_file(innmdsc); } } while (rnxtopen(infile)); rclose(infile); if (outnm != NULL) { free(outnm); }}#/* Decompress the named file(s). */decmpr(inname, outdef)char *inname, *outdef;{ int rread(), compatrd(); int length, in_is_fod; char **innm, **outnm; RMSFILE *infile, *outfile; int innmdsc[2]; struct FAB outfab; CMP_HEAD cmpfhead; char stamp[2];" char innmbuf[260], outnmbuf[260];F /* Parse input name before checking it for compressed file suffix. */) if ((innm = fnmparse(inname)) == NULL) {4 fprintf(stderr, "Bad file name \"%s\"\n", inname); return; } strcpy(innmbuf, innm->fnm_str); inname = innmbuf; free(innm); /* Open input file. */+ length = strlen(inname) - strlen(Cmpfend);; if (length < 0 || strcmp(&inname[length], Cmpfend) != 0) {5 strcpy(&inname[length + strlen(Cmpfend)], Cmpfend); }6 if ((infile = ropen(inname, R_READ, NULL)) == NULL) {. fprintf(stderr, "Cannot open %s\n", inname); return;  }( /* Parse output file spec, if given. */) if (outdef == NULL || *outdef == '\0') { outnm = NULL;1 } else if ((outnm = fnmparse(outdef)) == NULL) {; fprintf(stderr, "Bad output file spec \"%s\"\n", outdef); exit(1); }+ /* Decompress each file matched by inname,! which may contain wild-cards. */ do {7 /* Determine what kind of compressed file this is. */ stamp[0] = rgetc(infile); stamp[1] = rgetc(infile); Maxbits = rgetc(infile);3 Oldfmt = (*(short *)stamp == *(short *)Oldstamp);% /* Make sure file is compressed. */* simplename(infile->rf_rsbuf, innmbuf);7 if (!Oldfmt && *(short *)stamp != *(short *)Stamp) {: fprintf(stderr, "%s: unknown compression format, \cannot decompress\n", innmbuf); continue; }* /* Set maximum code length from file. */! Blk_cmp = Maxbits & BLOCK_MASK; Maxbits &= BIT_MASK; Maxmaxcode = 1 << Maxbits; if (Maxbits > BITS) { fprintf(stderr,8 "%s: uses %d bits, current maximum is %d bits\n", innmbuf, Maxbits, BITS); continue; }0 /* Create FAB to define output file format. */ Numchar = NUMCHAR; Decrdf = rread;7 lib$movc5(&0, NULL, &'\0', &sizeof(outfab), &outfab);( if (Oldfmt) { /* compatibility code */ Numchar--; Decrdf = compatrd;" outfab.fab$b_rfm = FAB$C_STMLF; } else {1 rread(&cmpfhead, 1, sizeof(cmpfhead), infile);& outfab.fab$b_bks = cmpfhead.ch_bks;& outfab.fab$w_gbc = cmpfhead.ch_gbc;2 outfab.fab$l_fop = cmpfhead.ch_fop | FAB$M_CBT;& outfab.fab$w_mrs = cmpfhead.ch_mrs;& outfab.fab$b_fsz = cmpfhead.ch_fsz;& outfab.fab$b_org = cmpfhead.ch_org;' outfab.fab$b_rfm = cmpfhead.ch_rfm;& outfab.fab$b_rat = cmpfhead.ch_rat;& outfab.fab$b_shr = cmpfhead.ch_shr;/ outfab.fab$l_alq = infile->rf_fab.fab$l_alq; if (outfab.fab$l_alq < 0) { outfab.fab$l_alq = 0; } } /* Create output file. */+ mkfname(innmbuf, outnm, outnmbuf, FALSE);> if ((outfile = ropen(outnmbuf, R_WRITE, &outfab)) == NULL) {3 fprintf(stderr, "Cannot create %s\n", outnmbuf); continue; }4 /* Decompress input file to create output file. */' in_is_fod = infile->rf_flag & RF_FOD; decompress(infile, outfile); rfinish(infile); rclose(outfile);7 /* If /DELETE qualifier given, and input file is on a% file-oriented device, delete it. */ if (Delete && in_is_fod) {; innmdsc[0] = strlen(innmdsc[1] = (int)infile->rf_rsbuf); lib$delete_file(innmdsc); } } while (rnxtopen(infile)); rclose(infile); if (outnm != NULL) { free(outnm); }}4/* Copy file name and type from inname to outbuf. */simplename(inname, outbuf)register char *inname, *outbuf;{ register char *scanptr;. for (scanptr = inname; *scanptr; scanptr++) { if (*scanptr == ';') { scanptr = inname; break; } else if (*scanptr == ']') { scanptr++; break; } }& while (*scanptr && *scanptr != ';') { *outbuf++ = *scanptr++; } *outbuf = '\0';}./* Determine name of output file to create. */ )mkfname(innmstr, outnm, newnmbuf, mk_cmp)8char *innmstr; /* name of input file to be compressed */=FNMCOMP *outnm; /* NULL if /OUTPUT=xxx qualifier not given */=char *newnmbuf; /* buffer in which output name is returned */Hint mk_cmp; /* TRUE for compressed output name, FALSE if uncompressed */{+ int i, length, currin, currout, oldoutfod; char *from;! unsigned char *nextin, *nextout; FNMCOMP *innm; static FNMCOMP blankin = {! 0, 0, 0, 0, 0, FALSE, "" };1 /* Parse input file name into its components. */* if ((innm = fnmparse(innmstr)) == NULL) { innm = &blankin; }= /* If no output file name specified, use input file name. */ if (outnm == NULL) {1 /* If no input name given, or input name is not0 a file-oriented device, use a default name. */+ if (innm == &blankin || !innm->fnm_fod) { innmstr = "CMPR.OUT"; } if (mk_cmp) {5 /* For compressed file names, append Cmpfend[]. */4 sprintf(newnmbuf, "%s%s", innmstr, Cmpfend); } else {/ /* For uncompressed file name, make sure the, name used does _not_ end in Cmpfend[]. */. length = strlen(innmstr) - strlen(Cmpfend);0 if (strcmp(&innmstr[length], Cmpfend) == 0) { innmstr[length] = '\0'; } strcpy(newnmbuf, innmstr); } return; }A /* If the output file specified is not on a file-oriented device@ (so probably it is either a terminal or a mailbox) don't change its name, just copy it over. */ if (!outnm->fnm_fod) {+ length = outnm  VMS_COMPRESS.BCKV%)[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRMAIN.C;1K$->fnm_dir - outnm->fnm_dev;/ lib$movc3(&length, outnm->fnm_str, newnmbuf); newnmbuf[length] = '\0'; return; }4 /* Merge components of the two strings, letting the3 /OUTPUT=xxx name have precedence. This is similar0 to using the default name fields of the FAB. */G innm->fnm_fod = innm->fnm_ver + strlen(&innm->fnm_str[innm->fnm_ver]); oldoutfod = outnm->fnm_fod; i = outnm->fnm_ver;1 outnm->fnm_fod = i + strlen(&outnm->fnm_str[i]); currin = currout = 0; nextin = &innm->fnm_dev; nextout = &outnm->fnm_dev; for (i = 0; i < 5; i++) {" from = &outnm->fnm_str[currout];+ if ((length = *nextout - currout) <= 0) {! from = &innm->fnm_str[currin]; length = *nextin - currin; }% lib$movc3(&length, from, newnmbuf); newnmbuf += length; currin = *nextin++; currout = *nextout++; } outnm->fnm_fod = oldoutfod;9 /* If creating a compressed file, append compressed file indicator to file type. */ length = strlen(Cmpfend); if (mk_cmp) { strcpy(newnmbuf, Cmpfend); newnmbuf += length;+ /* If a version number was specified with' the /OUTPUT=xxx qualifier, use it. */  length = outnm->fnm_ver;+ if (outnm->fnm_str[length + 1] != '\0') {- strcpy(newnmbuf, &outnm->fnm_str[length]); while (*newnmbuf++) ; newnmbuf--; }6 } else if (strcmp(newnmbuf - length, Cmpfend) == 0) { newnmbuf -= length; } *newnmbuf = '\0';? /* Free space used for expanded version of input file name. */ if (innm != &blankin) { free(innm); }}K/* This routine parses a file name string into its RMS pathname components.GLogical names are translated, and defaults are applied. Wild-cards areJaccepted, but they are _not_ expanded. See the description of sys$parse()Jin the System Services Manual for more information. If the version numberKis indicated only by a ';', or if file name is indicated only by a '.', theGindicator characters are deleted. A pointer to an FNMCOMP is returned.IThe FNMCOMP is allocated and filled in with a complete description of theGvarious components of the file name. The calling program should free()8the pointer when the information is no longer needed. */#define MISSING 255 FNMCOMP * fnmparse(str) char *str;{  int i, status, devchar; char *trim; unsigned char *fix; FNMCOMP *ret; int devdesc[2]; char nam_ess[255]; struct FAB fab; struct NAM nam; 0 lib$movc5(&0, NULL, &'\0', &sizeof(fab), &fab); fab.fab$b_bid = FAB$C_BID; fab.fab$b_bln = FAB$C_BLN; fab.fab$l_fna = str; fab.fab$b_fns = strlen(str); fab.fab$l_nam = &nam; 0 lib$movc5(&0, NULL, &'\0', &sizeof(nam), &nam); nam.nam$b_bid = NAM$C_BID; nam.nam$b_bln = NAM$C_BLN;* nam.nam$b_nop = NAM$M_SYNCHK | NAM$M_PWD; nam.nam$l_esa = nam_ess;% nam.nam$b_ess = sizeof(nam_ess) - 1; status = sys$parse(&fab, 0, 0); if (~status & 1) { return (status); } trim = &nam_ess[nam.nam$b_esl]; *trim-- = '\0'; if (*trim == ';') { *trim-- = '\0'; nam.nam$b_ver = 0; }' if (*trim == '.' && trim[-1] == ']') { *trim-- = '\0'; nam.nam$b_type = 0; }A ret = (FNMCOMP *)malloc(sizeof(FNMCOMP) + (trim - nam_ess) + 1); if (ret == NULL) { return (NULL); }% ret->fnm_ver = (trim - nam_ess) + 1; trim = ret->fnm_str; strcpy(trim, nam_ess);E ret->fnm_dev = ret->fnm_dir = ret->fnm_nam = ret->fnm_typ = MISSING;4 if (nam.nam$b_dev > 0 && nam.nam$l_dev != NULL) {) ret->fnm_dev = nam.nam$l_dev - nam_ess;M }4 if (nam.nam$b_dir > 0 && nam.nam$l_dir != NULL) {) ret->fnm_dir = nam.nam$l_dir - nam_ess;. }4 if (nam.nam$b_name > 0 && nam.nam$l_name != NULL) {* ret->fnm_nam = nam.nam$l_name - nam_ess; }4 if (nam.nam$b_type > 0 && nam.nam$l_type != NULL) {* ret->fnm_typ = nam.nam$l_type - nam_ess; }4 if (nam.nam$b_ver > 0 && nam.nam$l_ver != NULL) {) ret->fnm_ver = nam.nam$l_ver - nam_ess;. } fix = &ret->fnm_dev;n for (i = 4; i >= 0; i--) {d if (fix[i] == MISSING) { fix[i] = fix[i + 1];e }. }, /* Determine if device is file-oriented. */* devdesc[0] = ret->fnm_dir - ret->fnm_dev;/ devdesc[1] = (int)&ret->fnm_str[ret->fnm_dev];h devchar = 0;oF status = lib$getdvi(&DVI$_DEVCHAR, ___, devdesc, &devchar, ___, ___); if (~status & 1) {c lib$signal(status);i }5 ret->fnm_fod = ((devchar & DEV$M_FOD) == DEV$M_FOD);t return (ret);}a/* Exit routine. */lcomp_exit(code) int code;{m exit(code);}i+*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRMAIN.OBJ;1+,]D./ 4  -V%0123KPWO56 OAl7@ MAl89G HJ 5CMPRMAINV1.024-JUN-1989 19:42VAX C V3.0-031 CC$RMS_NAM CC$RMS_FAB CC$RMS_RAB CC$RMS_XABALL CC$RMS_XABDAT CC$RMS_XABFHC CC$RMS_XABKEY CC$RMS_XABPRO CC$RMS_XABRDT CC$RMS_XABSUM CC$RMS_XABTRM C$V_CTYPEDEFSFNMPARSESPRINTFFPRINTF COMP_EXIT CLI_GET_VALUE CLI_PRESENTDECMPRCMPRRNXTOPENLIB$DELETE_FILEFREERFINISHCOMPRESSRWRITERPUTCMKFNAME LIB$MOVC5STATSTRCPYGETFDATESTRCMPP_Z#PDELETE#POUTPUT#PUNCOMPRESS#PFILE#PCannot open %s #.PBad output file spec "%s" #IPDIR#MP%s: directory file, not compressed #rP%s: %s file, not compressed #Pindexed#Prelative#PCannot create %s #PBad file name "%s" #PCannot open %s #PBad output file spec "%s" #P%s: unknown compression format, cannot decompress #%P%s: uses %d bits, current maximum is %d bits #SPCannot create %s #ePCMPR.OUT#nP%s%sP<^C$MAIN#RUSb CLI_PRESENT\P\\<~ߢ CLI_GET_VALUEPCMPRTߢ CLI_PRESENTPDECMPRTe  eeexe<~ߢ CLI_GET_VALUEP%Pd<~ߢ CLI_GET_VALUEPEXITPά^#U VXW߭ SYS$GETTIM|~ݬROPENPTݬߥhFPRINTFЬRbԮd)PRFNMPARSEPdRߥ.hFPRINTFEXITSTRLENYFPRINTFZ LIB$MOVC5lRPUTC[RFINISHhpޮpRItޮtSЮpP``;ЮpP`]PPP```;ЮtRtcb``;딾tߥIIiP@ISTRCMPPIߥMhj1)R&R ŘSPŐSSIߥrhj1P|ݭiP|~߭߭GETFDATEѭ1 ѭ1I STRCPYSTATЭˏLRR@9JMTNФPBTKV)W+X*Y#Z5M8800((ހXYTEݮlIMKFNAME[P8800((ހzЏ@ _Фk[EROPENPSEšhj1PSf~kS~kS~kSMRWRITEˏdRSTCOMPRESSSlSFREETlRݭiP߭LIB$DELETE_FILETRNXTOPENP1jTRFINISHTFREEծd ݮdFREE^#UV Z[YݬFNMPARSEPRݬųFPRINTF͐STRCPY͐RFREEЬRRSTRLENPSiSTRLENPSiCbSTRCMPPiiSTRLENPS޼RCbSTRCPY|~  VMS_COMPRESS.BCK]DV%+[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRMAIN.OBJ;1ROPENPTݬFPRINTFЬRbԮT-PRFNMPARSEPTRFPRINTFEXITRGETCWFPRINTFXRFINISHXTgPTgPTgPf RQbQ3Qj\ޮ\R͐`ޮ`SЮ\P` P`;Ю\P`]PPP```;Ю`R`cb``;딾`j$ Rb͐h1bPˏfʏffSxSSS͐%h1$<kRREADߟP͈͈̈́̈́̀̀ LIB$MOVC5jkCOMPATRDJPTRREADⰭɏ STRLEN SIMPLENAMEEXITROPEN SYS$GETTIMRNXTOPENLIB$DELETE_FILERFINISH DECOMPRESSMKFNAME LIB$MOVC5 SIMPLENAMERGETCEXITROPENSTRCMPSTRLENFREESTRCPYCOMPATRDRREADFREE LIB$MOVC3STRCPYSTRCMPSTRLEN LIB$SIGNAL LIB$GETDVISTRCPYMALLOC SYS$PARSESTRLEN LIB$MOVC5EXIT <MAIN CMPR 8DECMPR  SIMPLENAMḘڐ㐭АФ͌ݮ\͐MKFNAME͌ROPENPR͌ShPˏdSRT DECOMPRESST\R\RFREE앩"SݭSTRLENP߭LIB$DELETE_FILETRNXTOPENP1TRFINISHTFREEծT ݮTFREEP ^ЬPЬRPQaa;PQPa]QPQaaa; aa;,^#Z[ݬFNMPARSEPXXլsPXPeլkݬnݬ SPRINTFЬSSSTRLENPRkSTRLENPRkP@cSTRCMPPЭP@cSݬ STRCPYЬS'RcPPRЬ RR߭ LIB$MOVC3ЭP@bSSRBSTRLENSPPެ о TYISTRLENYPP|RhWdVY TBUfPRP CUgPSPݬ U߭ LIB$MOVC3 SRYЬSkSTRLENPլSkݬ STRCPY RBJЭP@Ь SSSTRCPYSRS b Ь P֬ `׬ kí ~STRCMPP­ PXP XFREEP<^͡P8800(( LIB$MOVC5͡P͢ЬSTRLENPAA`8800(( LIB$MOVC5ܐA`B IMK|~͡ SYS$PARSEPQQPPQPLRBRRSRUce; URUb~e.] URUb}PPURR~MALLOCPTPPPUPPPUUSTRCPYdzPͅPPͅPPd{P͉PP͉PP|P͍PP͍PP}P͑PP͑PP~P͕PP͕PPdRSQPP SP@bQS嚤RdPPRdRBԭ|~߭߭88RCMPRMAIN main cmprd 8decmpru simplenameLmkfname fnmparseK<  comp_exit ڤ ѹ  MKFNAME <FNMPARSE < COMP_EXITC$MAINL $CODE $DATAERRNOSTDINSTDOUTSTDERR_CTYPE_NUMCHARDECRDFSTAMPOLDSTAMPOLDFMTINFNAMEN_BITSMAXBITSMAXCODE MAXMAXCODECODETABFSIZE TAB_SUFFIXFREE_ENT EXIT_STATQUIETVERBOSEFORCEBLK_CMP CLEAR_FLGRATIOCHKPNTIN_COUNT BYTES_OUT OUT_COUNT HASHCACHE LMASK RMASKs$CHAR_STRING_CONSTANTSZ LIB$GETDVIPRR P LIB$SIGNALˏRSR@SSTP^ݬEXIT(*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRSHR.C;1+,./ 4H-V%0123KPWO5 6Wu7*189f1G HJ /*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed. cmprdbg.c&This file contains debugging routines.*/#include "cmpr.h" #ifdef DEBUG"/* Print codes from input file. */ printcodes(){ CODE_INT code;% int col = 0, bits;  bits = N_bits = INIT_BITS; Maxcode = MAXCODE(N_bits);( Free_ent = (Blk_cmp ? FIRST : Numchar);" while ((code = getcode()) >= 0) {! if (code == CLEAR && Blk_cmp) { Free_ent = FIRST - 1; Clear_flg = 1;% } else if (Free_ent < Maxmaxcode) { Free_ent++; } if (bits != N_bits) {4 fprintf(stderr, "\nChange to %d bits\n", N_bits); bits = N_bits; col = 0; } fprintf(stderr, "%5d%c", code,1 (col += 6) >= 74 ? (col = 0, '\n') : ' ' ); } putc('\n', stderr); comp_exit(1);}/* Dump string table. */ dump_tab(){ " register int i, ent, suff;  register char *stackp;E char stackbuf[MAXDUMPSTACK]; /* \nnn makes it 4 times bigger */" stackp = &stackbuf[MAXDUMPSTACK];! for (i = 0; i < Free_ent; i++) { ent = i; suff = Tab_suffix[ent];' if (isascii(suff) && isprint(suff)) {' fprintf(stderr, "%5d: %5d/'%c' \"",# ent, Tab_prefix[ent], suff); } else {( fprintf(stderr, "%5d: %5d/\\%03o \"",# ent, Tab_prefix[ent], suff); } *--stackp = '\n'; *--stackp = '"'; for ( ; ent != NULL;6 ent = (ent >= FIRST ? Tab_prefix[ent] : NULL)) { suff = Tab_suffix[ent];( if (isascii(suff) && isprint(suff)) { *--stackp = suff; } else { switch (suff) {& case '\n': *--stackp = 'n'; break;& case '\t': *--stackp = 't'; break;& case '\b': *--stackp = 'b'; break;& case '\f': *--stackp = 'f'; break;& case '\r': *--stackp = 'r'; break; default: *--stackp = '0' + suff % 8;& *--stackp = '0' + (suff / 8) % 8;! *--stackp = '0' + suff / 64; break; } *--stackp = '\\'; } }> fwrite(stackp, 1, &stackbuf[MAXDUMPSTACK] - stackp, stderr);# stackp = &stackbuf[MAXDUMPSTACK]; }} #endif DEBUG**[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRSHR.OBJ;1+, ./ 4n -V%0123KPWO56 OAl75Al89G HJ4CMPRSHRV1.024-JUN-1989 19:42VAX C V3.0-031RCMPRSHR CC$RMS_NAM CC$RMS_FAB CC$RMS_RAB CC$RMS_XABALL CC$RMS_XABDAT CC$RMS_XABFHC CC$RMS_XABKEY CC$RMS_XABPRO CC$RMS_XABRDT CC$RMS_XABSUM CC$RMS_XABTRM C$V_CTYPEDEFS$CODE$DATAERRNOSTDINSTDOUTSTDERR_CTYPE_NUMCHARDECRDFSTAMPOLDSTAMPOLDFMTINFNAME  VMS_COMPRESS.BCK V%*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRSHR.OBJ;1N_BITSMAXBITSMAXCODE MAXMAXCODECODETABFSIZE TAB_SUFFIXFREE_ENT EXIT_STATQUIETVERBOSEFORCEBLK_CMP CLEAR_FLGRATIOCHKPNTIN_COUNT BYTES_OUT OUT_COUNT HASHCACHE LMASK RMASKP)*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRUTIL.C;1+,. / 4I -V%0123KPWO 5 6fev7є*189f1G HJ/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed. cmprutil.c$This file contains utility routines.*/#include #include #include #include #include #include #include #include #include #define NULL 0 #define ___ 0&/* Get the creation date of a file. */getfdate(fdscptr, cretm);int *fdscptr; /* address of file name string descriptor */=int *cretm; /* address of two-longword binary time buffer */{ register int *fidptr; short chan; int status; int fibd[2]; int atr[3]; struct FAB fab; struct NAM nam; struct fibdef fib;) char es[NAM$C_MAXRSS], rs[NAM$C_MAXRSS];: if (~(status = date_init(fdscptr, cretm, &fab, &nam, atr,' es, rs, &fib, fibd, &chan)) & 1) { return (status); }2 if (~(status = sys$search(&fab, ___, ___)) & 1) { sys$dassgn(chan); return (status); }$ /* Copy file ID from NAM to FIB. */+ fidptr = &fib.fib$r_fid_overlay.fib$w_fid;# *fidptr++ = *(int *)nam.nam$w_fid;% *(short *)fidptr = nam.nam$w_fid[2]; /* Get date(s). */ status = sys$qiow($ ___, /* default event flag */# chan, /* channel to device */% IO$_ACCESS, /* function code */$ ___, /* no I/O status block */' ___, ___, /* no completion AST */$ fibd, /* P1, FIB descriptor */' ___, ___, ___, /* P2-P4, unused */# atr, /* P5, attribute list */ ___); /* P6, unused */ sys$dassgn(chan); return (status);}4/* Perform initialization required by getfdate(). */staticGdate_init(fdscptr, cretm, fabp, namp, atrp, es, rs, fibp, fibdp, chanp);int *fdscptr; /* pointer to file name string descriptor */=int *cretm; /* pointer to two-longword binary time buffer */2register struct FAB *fabp; /* FAB to initialize */3register struct NAM *namp; /* NAM for FAB to use */8register int *atrp; /* address of file attribute list */+char *es, *rs; /* buffers for NAM block */+struct fibdef *fibp; /* FIB to get dates */!int *fibdp; /* FIB descriptor */Eint *chanp; /* address of word to hold channel assigned to device */{ int status; int devnmdsc[2];" /* Create file attribute list. */1 *atrp++ = ATR$S_CREDATE | (ATR$C_CREDATE << 16); *atrp++ = cretm; *atrp = 0; /* Initialize FAB. */4 lib$movc5(&0, 0, &'\0', &sizeof(struct FAB), fabp); fabp->fab$b_bln = FAB$C_BLN; fabp->fab$b_bid = FAB$C_BID; fabp->fab$l_nam = namp;# fabp->fab$b_fns = *fdscptr & 0xFF; fabp->fab$l_fna = fdscptr[1]; /* Initialize NAM. */4 lib$movc5(&0, 0, &'\0', &sizeof(struct NAM), namp); namp->nam$b_bln = NAM$C_BLN; namp->nam$b_bid = NAM$C_BID; namp->nam$b_ess = NAM$C_MAXRSS; namp->nam$b_rss = NAM$C_MAXRSS; namp->nam$l_esa = es; namp->nam$l_rsa = rs; /* Initialize FIB. */ 7 lib$movc5(&0, 0, &'\0', &sizeof(struct fibdef), fibp); *fibdp = sizeof(struct fibdef); fibdp[1] = (int)fibp;1 if (~(status = sys$parse(fabp, ___, ___)) & 1) { return (status); }) devnmdsc[0] = namp->nam$t_dvi[0] & 0xFF;( devnmdsc[1] = (int)&namp->nam$t_dvi[1];0 return (sys$assign(devnmdsc, chanp, ___, ___));}:/* Return 1 if the parameter or qualifier whose name (as a<null-terminated string) is pointed to by nmptr was specified<on the command line which invoked this program. Return 0 if;it was not specified, and -1 if it was negated (/NOxxx). */cli_present(nmptr) char *nmptr;{ int clistat; int nmdesc[2];, nmdesc[0] = strlen(nmdesc[1] = (int)nmptr); clistat = cli$present(nmdesc); if (clistat == CLI$_NEGATED) { return (-1); } return (clistat & 1);}I/* Attempt to read the value of the command line parameter whose name (asFgiven in the .CLD file) is in the null-terminated string pointed to byDnmptr. If the parameter was specified, its value is returned in theCbuffer of length valsize which is pointed to by valptr. Return theBlength of the parameter value string, or -1 if the named parameter)was not specified on the command line. */%cli_get_value(nmptr, valptr, valsize)char *nmptr, *valptr; int valsize;{ int val_len; int nmdesc[2], valdesc[2]; val_len = 0;@ valdesc[0] = valsize - 1; /* leave room for terminating null */ valdesc[1] = (int)valptr;, nmdesc[0] = strlen(nmdesc[1] = (int)nmptr);7 if (!(cli$get_value(nmdesc, valdesc, &val_len) & 1)) { *valptr = '\0'; return (-1); } valptr[val_len] = '\0'; return (val_len);}+*[DCOLIB.TSLIB_PROGS.COMPRESS]CMPRUTIL.OBJ;1+, ./ 4 -V%0123KPWO56 OAl7[ Al89G HJ5CMPRUTILV1.024-JUN-1989 19:42VAX C V3.0-031P ^?߭߭6ݬݬ sPQQPPQP|~ SYS$SEARCHPRRPP2~ SYS$DASSGNRPQZ^a߭|~߭|~22~ SYS$QIOWPS2~ SYS$DASSGNSP<$^Ь RЬTЬSЏЬcRP߭ԭ߭ԭ߭ LIB$MOVC5UePbT(ЬQˏaPP4С,T`߭ԭ߭ԭ߭e`d Ь Ьݬ @߭ԭ߭ԭ߭eЬ$P@`Ь |~R SYS$PARSEPQQPPQPRR2R|~ݬ( SYS$ASSIGN ^ЬݭSTRLENP߭RCMPRUTILgetfdate date_init cli_present7 cli_get_valueR _     CC$RMS_FAB CC$RMS_NAMSYS$QIOW SYS$DASSGN SYS$SEARCH SYS$ASSIGN SYS$PARSE LIB$MOVC5 CLI$PRESENTSTRLEN CLI$GET_VALUESTRLEN GETFDATE  CLI_PRESENT  CLI_GET_VALUE&$CODE$DATA CLI$PRESENTPPʏP^ԭ ЬRRЬݭSTRLENP߭߭߭ CLI$GET_VALUEPbPЭR޼PB`ЭP  VMS_COMPRESS.BCKV%)[DCOLIB.TSLIB_PROGS.COMPRESS]C_OPTS.OPT;1L)*[DCOLIB.TSLIB_PROGS.COMPRESS]C_OPTS.OPT;1+,./ 4Ll-V%0123KPWO5 6 = g7 *189f1G HJL! Default system options file to link against the sharable C runtime library!sys$share:vaxcrtl/share'*[DCOLIB.TSLIB_PROGS.COMPRESS]DECMPR.C;1+, . / 4J -V%0123KPWO 5 6kv7 *189f1G HJ/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed.decmpr.cCThis file contains the routines needed to decompress a single file.*/#include "cmpr.h"#ifdef SHOWCODEH#define PRT(ch) printf(((ch>=' '&&ch<0x80)?"POP(%c) ":"POP(%03X) "),ch)#endifdecompress(infile, outfile)RMSFILE *infile, *outfile;{ register CHAR_TYPE *stackp; ) register CODE_INT code, oldcode, incode; register int finchar; CHAR_TYPE stackbuf[MAXSTACK]; stackp = &stackbuf[MAXSTACK];5 /* Initialize the first Numchar entries in the table1 to be just the corresponding character value. */' Maxcode = MAXCODE(N_bits = INIT_BITS); code = Numchar; while (--code >= 0) { Tab_prefix[code] = 0;% Tab_suffix[code] = (CHAR_TYPE)code; }( Free_ent = (Blk_cmp ? FIRST : Numchar);% finchar = oldcode = getcode(infile);#ifdef SHOWCODE if (Show_code) { printf("\n%04X: ", finchar); PRT(finchar); }#endif? rputc(finchar, outfile); /* first code must be simple char. */) while ((code = getcode(infile)) != -1) {#ifdef SHOWCODE if (Show_code) { printf("\n%04X: ", code); }#endif! if (code == CLEAR && Blk_cmp) { code = Numchar; while (--code >= 0) { Tab_prefix[code] = 0; } Clear_flg = 1; Free_ent = FIRST - 1; continue; } incode = code;& /* Special case for KwKwK string. */ if (code >= Free_ent) { *--stackp = finchar; code = oldcode; }4 /* Generate output characters in reverse order. */ while (code >= Numchar) { *--stackp = Tab_suffix[code]; code = Tab_prefix[code]; }) *--stackp = finchar = Tab_suffix[code];* /* And put them out in forward order. */( while (stackp < &stackbuf[MAXSTACK]) {#ifdef SHOWCODE if (Show_code) { PRT(*stackp); }#endif rputc(*stackp++, outfile); } /* Generate the new entry. */' if ((code = Free_ent) < Maxmaxcode) {. Tab_prefix[code] = (unsigned short)oldcode; Tab_suffix[code] = finchar; Free_ent = code + 1; }  /* Remember previous code. */ oldcode = incode; }} C/* Return the next code from standard input. If EOF, return -1. */CODE_INTgetcode(infile)RMSFILE *infile;{ register CODE_INT code;! static int offset = 0, size = 0; static unsigned char buf[BITS];#ifndef USE_VMS_RTL register#endif USE_VMS_RTL int r_off, bits;" register unsigned char *bp = buf;9 if (Clear_flg || offset >= size || Free_ent > Maxcode) {; /* If the next entry will be too big for the current code5 size, then we must increase the size. This implies$ reading a new buffer full, too. */ if (Free_ent > Maxcode) { N_bits++; if (N_bits == Maxbits) {0 Maxcode = Maxmaxcode; /* can't get bigger */ } else { Maxcode = MAXCODE(N_bits); }  } if (Clear_flg) {) Maxcode = MAXCODE(N_bits = INIT_BITS); Clear_flg = 0; }+ size = (*Decrdf)(buf, 1, N_bits, infile); /* Check for EOF. */ if (size <= 0) { return (-1); } offset = 0;3 /* Round size down to integral number of codes */$ size = (size << 3) - (N_bits - 1); } r_off = offset; bits = N_bits;#ifdef USE_VMS_RTL% code = lib$extzv(&r_off, &bits, bp);#else /* Get to the first byte. */ bp += (r_off >> 3); r_off &= 7;' /* Get first part (low order bits). */ code = *bp++ >> r_off;#ifdef NO_UCHAR code &= Rmask[8 - r_off]);#endif NO_UCHAR bits -= (8 - r_off);: r_off = 8 - r_off; /* now, offset into code word */A /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ if (bits >= 8) { code |= *bp++ << r_off; r_off += 8; bits -= 8; } /* Copy high order bits. */& code |= (*bp & Rmask[bits]) << r_off;#endif USE_VMS_RTL offset += N_bits; return (code);}G/* Just like rread(), except it converts R_EOR into '\n'. This routineJis used to read from files compressed by COMPRESS, which creates stream-LFformat compressed files. */"compatrd(buffer, size, count, rfp)register char *buffer; int size; int count;register RMSFILE *rfp;{ register int c, nbyte, nobj;' for (nobj = 0; nobj < count; nobj++) { nbyte = size; while (nbyte-- > 0) {# if ((c = rgetc(rfp)) == R_EOF) { return (nobj); } if (c == R_EOR) { c = '\n'; } *buffer++ = c; } } return (nobj);})*[DCOLIB.TSLIB_PROGS.COMPRESS]DECMPR.OBJ;1+,./ 4 -V%0123KPWO56 OAl7܎Al89G HJ3DECMPRV1.024-JUN-1989 19:42VAX C V3.0-031Pp^[WXV  x RRhPP@gP@kPhSSYSYYެݾGETCODEPUUTެZjTRPUTCݾGETCODEPSS1RPUTCYPSh'hP@gPhmSRSTvUSShCkv CC$RMS_NAM CC$RMS_FAB CC$RMS_RAB CC$RMS_XABALL CC$RMS_XABDAT CC$RMS_XABFHC CC$RMS_XABKEY CC$RMS_XABPRO CC$RMS_XABRDT CC$ VMS_COMPRESS.BCKV%)[DCOLIB.TSLIB_PROGS.COMPRESS]DECMPR.OBJ;1;1&RMS_XABSUM CC$RMS_XABTRM C$V_CTYPEDEFSGETCODERPUTCRGETC  DECOMPRESS `GETCODE \COMPATRD$CODE$DATAERRNOSTDINSTDOUTSTDERR_CTYPE_NUMCHARDECRDFSTAMPOLDSTAMPOLDFMTINFNAMEN_BITSVMAXBITSMAXCODE MAXMAXCODECODETABFSIZE TAB_SUFFIXFREE_ENT EXIT_STATQUIETVERBOSEFORCEBLK_CMP CLEAR_FLGRATIOCHKPNTIN_COUNT BYTES_OUT OUT_COUNT HASHCACHE LMASK RMASKRbPPgxTjRRTgVjXxVTTSʏVVUTxUTQVTTXPTRPTxRTTTQRPcTT@"TTTxRTTTQjQP^ЬSTլ OYYXYWRGETCVWRX,ݬfPTPP PPRQRQTT TP+*[DCOLIB.TSLIB_PROGS.COMPRESS]MAKEFILE.MAK;1+,[./ 49-V%0123KPWO5 67m֫*189f1G HJLINK_QUAL = /notrace /nodebug.CMPRMOD = cmprmain cmpr decmpr cmprshr cmprext#CMPROBJ = $(CMPRMOD) cmprutil rmsio# How to make the executable.cmpr.exe: $(CMPROBJ).obj' link $(LINK_QUAL) /exe=$* $?, c_opts/o$(CMPRMOD).obj : cmpr.hcmpr.h rmsio.obj: rmsio.hcmpr.hlb: $*.hlp lib/cre/help $* $*9# How to create a help library module from a runoff file. .rnh.hlp: runo $?-*[DCOLIB.TSLIB_PROGS.COMPRESS]OTHER_COPY.DIR;1+,#./ 4-V%0123 KPWO56I7^*189@ ojG HJI AAAREADME.TXT#BUILD_CMPR.COM#CMPR.C# CMPR.CLD#CMPR.H# CMPR.HLP$ CMPR.RNH/$ CMPREXT.C8$ CMPRMAIN.C9$ CMPRSHR.CN$ CMPRUTIL.Cd$ C_OPTS.OPTk$DECMPR.Cv$MAC.DIR~$  MAKEFILE.MAKC)OLDINSTALLED.EXED)RFC.821F)RFC.822G)RMSIO.CI)RMSIO.H`)TODO.a) WORKING.DIRb) &*[DCOLIB.TSLIB_PROGS.COMPRESS]RMSIO.C;1+,\.!/ 4N! -V%0123KPWO!5 6`_w7`\ *189f1G HJ/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed.rmsio.c?These routines allow C programs to use RMS in much the same way=that they use stdio, but with full control over file formats.=In addition, the "overdraft quota" is automatically used when<a write fails due to lack of space. When even the overdraft<quota is exhausted, exit is forced. (The overdraft quota is<only used during file extend operations; it is not used if a2file create operation fails due to lack of space.)=A special code, R_EOR (defined in rmsio.h) is returned at end?of record. Newline would have been used, but some file formats>allow newline as a character within a record. The most common>example is object files, which have variable length records of=binary data. R_EOR can be written using rputc() to terminate;a record. This value should be used whenever newline wouldordinarily be appropriate.*/#include "rmsio.h"#include #define DEF_BUF_SIZE 2048,/* Evaluate non-zero if file is writable. */#define OPEN_FOR_WRITE(rfp) \4 ((rfp)->rf_fab.fab$b_fac & (FAB$M_PUT | FAB$M_UPD)),/* Evaluate non-zero if file is readable. */#define OPEN_FOR_READ(rfp) \4 ((rfp)->rf_fab.fab$b_fac & (FAB$M_GET | FAB$M_UPD))H/* Evaluate non-zero if file is binary format -- no record delimiter. */A#define BINARY_FORMAT(rfp) ((rfp)->rf_fab.fab$b_rfm == FAB$C_UDF)B/* Evaluate non-zero if file is in any delimited stream format. */#define STREAM_FORMAT(rfp) \( ((rfp)->rf_fab.fab$b_rfm == FAB$C_STM \0 || (rfp)->rf_fab.fab$b_rfm == FAB$C_STMCR \/ || (rfp)->rf_fab.fab$b_rfm == FAB$C_STMLF)G/* Evaluate non-zero if no maximum size is known for file's records. */E#define USE_BLOCK_IO(rfp) (STREAM_FORMAT(rfp) || BINARY_FORMAT(rfp) \1 || ((rfp)->rf_fab.fab$b_fac & FAB$M_BIO))#define BLOCK_SIZE 512$#define ERRSTAT(stat) (~(stat) & 1)B#define EXQUOTA(s) ((s) == SS$_EXQUOTA || (s) == SS$_EXDISKQUOTA)2int sys$get(), sys$put(), sys$read(), sys$write();K/* Open the named file for the indicated access. Allocate, initialize, andHreturn a pointer to an RMSFILE through which to access the file. ReturnINULL on error. For write access, if fabp is NULL, create a standard textIfile (variable length records with carriage-return carriage-control). IfHfabp is not NULL, use the information in the given FAB to open the file.GWhen a user-initialized FAB is passed in this way, some of its contentsGmay be ignored. In particular, the file access mode (fab$b_fac) is setCexplicitly to FAB$V_PUT or FAB$V_GET, and the file name (fab$l_fna,Ifab$b_fns) is set from the string passed as fname (unless fname is NULL).HIf fabp is not NULL, it is assumed that the user FAB is full-length, nota shortened version. */ RMSFILE * ropen(fname, access, fabp) char *fname;%int access; /* 0 = read, 1 = write */struct FAB *fabp;{ register RMSFILE *rfp; register struct NAM *namp; int status;8 /* Validate access mode; allocate and clear RMSFILE. */, if ((access != R_READ && access != R_WRITE)= || (rfp = (RMSFILE *)malloc(sizeof(RMSFILE))) == NULL) { return (NULL); }> lib$movc5(&0, ___, &'\0', &sizeof(struct FAB), &rfp->rf_fab);> lib$movc5(&0, ___, &'\0', &sizeof(struct NAM), &rfp->rf_nam); rfp->rf_flag = 0; rfp->rf_bufp = NULL; rfp->rf_datafunc = NULL;, rfp->rf_rsbuf[0] = rfp->rf_esbuf[0] = '\0'; * /* If a user FAB is given, copy it in. */ if (fabp != NULL) {; lib$movc3(&sizeof(struct FAB), fabp, &rfp->rf_fab); }5 /* Set block identifier and block length for FAB. */# rfp->rf_fab.fab$b_bid = FAB$C_BID;# rfp->rf_fab.fab$b_bln = FAB$C_BLN; /* Sep VMS_COMPRESS.BCK\V%&[DCOLIB.TSLIB_PROGS.COMPRESS]RMSIO.C;1BJ;1N!? t file name in FAB. */ if (fname != NULL) { rfp->rf_fab.fab$l_fna = fname;( rfp->rf_fab.fab$b_fns = strlen(fname); }1 /* Set up NAM block for wild-card operations. */% if (rfp->rf_fab.fab$l_nam == NULL) {' rfp->rf_fab.fab$l_nam = &rfp->rf_nam; } namp = rfp->rf_fab.fab$l_nam; namp->nam$b_bid = NAM$C_BID; namp->nam$b_bln = NAM$C_BLN; if (namp->nam$l_rsa == NULL) {" namp->nam$l_rsa = rfp->rf_rsbuf;. namp->nam$b_rss = sizeof(rfp->rf_rsbuf) - 1; } if (namp->nam$l_esa == NULL) {" namp->nam$l_esa = rfp->rf_esbuf;. namp->nam$b_ess = sizeof(rfp->rf_esbuf) - 1; }6 /* Validate input file name syntax and initialize NAM block for wild-card search. */; if (ERRSTAT(status = sys$parse(&rfp->rf_fab, ___, ___))) {#ifdef RMS_DEBUG printf("[ropen] Parse error\n");#endif lib$signal(status); free(rfp); return (NULL); }$ rfp->rf_fab.fab$l_fop |= FAB$M_NAM;% if (is_fod(rfp->rf_fab.fab$l_nam)) { rfp->rf_flag |= RF_FOD; }( /* Set appropriate file access mode. */ if (access == R_READ) {5 /* Restrict user supplied file access mask to M_GET5 (for read access) and M_BIO (to allow user to force block I/O). */% rfp->rf_fab.fab$b_fac &= FAB$M_BIO;% rfp->rf_fab.fab$b_fac |= FAB$M_GET;> /* If user hasn't specified block I/O, make it an option6 now, in case file format turns out to require it. */- if (!(rfp->rf_fab.fab$b_fac & FAB$M_BIO) && (rfp->rf_flag & RF_FOD)) {& rfp->rf_fab.fab$b_fac |= FAB$M_BRO; } } else {8 /* If no user FAB given, create standard text file. */ if (fabp == NULL) {% rfp->rf_fab.fab$b_rfm = FAB$C_VAR;$ rfp->rf_fab.fab$b_rat = FAB$M_CR; rfp->rf_fab.fab$w_mrs = 255; }) /* Validate access mode of user FAB. */3 rfp->rf_fab.fab$b_fac &= (FAB$M_UPD | FAB$M_BIO);- if (!(rfp->rf_fab.fab$b_fac & FAB$M_UPD)) {& rfp->rf_fab.fab$b_fac |= FAB$M_PUT; } if (USE_BLOCK_IO(rfp)) {& rfp->rf_fab.fab$b_fac |= FAB$M_BRO; }1 /* Set supersede flag to create file even if it6 already exists. Also request contiguous extents. */1 rfp->rf_fab.fab$l_fop |= FAB$M_SUP | FAB$M_CBT; } if ((rfp->rf_flag & RF_FOD) &&< ERRSTAT(status = sys$search(&rfp->rf_fab, ___, ___))) { if (access == R_READ) {#ifdef RMS_DEBUGFprintf("[ropen] First sys$search(%s) fails\n", rfp->rf_fab.fab$l_fna);#endif lib$signal(status); free(rfp); return (NULL); } } if (ERRSTAT(openconn(rfp))) { free(rfp); return (NULL); } return (rfp);}I/* Close the file currently opened on rfp. Open the next file matched byFthe file name (assumed to be a wild-card string). Return 1 if another2file is matched and opened, otherwise return 0. */ rnxtopen(rfp)register RMSFILE *rfp;{ int status;6 /* Close previously open file and free its buffer. */ rfinish(rfp);5 /* If device isn't file-oriented, return failure. */ if (!(rfp->rf_flag & RF_FOD)) { return (0); }+ /* Open next file matched by wild-card. */< if (ERRSTAT(status = sys$search(&rfp->rf_fab, ___, ___))) {/ /* If no more files match, return failure. */ if (status == RMS$_NMF) { return (0); }#ifdef RMS_DEBUGCprintf("[rnxtopen] sys$search(%s) fails\n", rfp->rf_fab.fab$l_fna);#endif lib$signal(status); free(rfp); return (0); } /* Open next matching file. */ if (ERRSTAT(openconn(rfp))) { free(rfp); return (0); } return (1);}N/* Open a file, connect a RAB to the FAB, and allocate record/block buffer. */static openconn(rfp)register RMSFILE *rfp;{ int status; char *nametrim; /* Open file. */) if (rfp->rf_fab.fab$b_fac & FAB$M_PUT) { rfp->rf_datafunc = sys$put;. status = sys$create(&rfp->rf_fab, ___, ___); } else { rfp->rf_datafunc = sys$get;, status = sys$open(&rfp->rf_fab, ___, ___); } if (ERRSTAT(status)) {#ifdef RMS_DEBUG*printf("[openconn] Error from sys$%s()\n",9(rfp->rf_fab.fab$b_fac & FAB$M_PUT ? "create" : "open"));#endif lib$signal(status); return (status); }  /* Initialize RAB. */B ? lib$movc5(&0, NULL, &'\0', &sizeof(struct RAB), &rfp->rf_rab);# rfp->rf_rab.rab$b_bid = RAB$C_BID;# rfp->rf_rab.rab$b_bln = RAB$C_BLN;& rfp->rf_rab.rab$l_fab = &rfp->rf_fab; if (USE_BLOCK_IO(rfp)) {= /* Set up for block I/O with an appropriate buffer size. */% rfp->rf_rab.rab$w_usz = BLOCK_SIZE;% rfp->rf_rab.rab$l_rop |= RAB$M_BIO;* if (rfp->rf_fab.fab$b_fac & FAB$M_PUT) {! rfp->rf_datafunc = sys$write; } else { rfp->rf_datafunc = sys$read; }) } else if (rfp->rf_fab.fab$w_mrs == 0) {' rfp->rf_rab.rab$w_usz = DEF_BUF_SIZE; } else {0 rfp->rf_rab.rab$w_usz = rfp->rf_fab.fab$w_mrs; }7 rfp->rf_rab.rab$l_ubf = malloc(rfp->rf_rab.rab$w_usz);% if (rfp->rf_rab.rab$l_ubf == NULL) {#ifdef RMS_DEBUGKprintf("[openconn] Can't allocate %d for buffer\n", rfp->rf_rab.rab$w_usz);#endif$ sys$close(&rfp->rf_fab, ___, ___); return (0); }& rfp->rf_bufp = rfp->rf_rab.rab$l_ubf;, if (!(rfp->rf_fab.fab$b_fac & FAB$M_PUT)) { rfp->rf_bufp++; } /* Connect RAB to its FAB. */. status = sys$connect(&rfp->rf_rab, ___, ___); if (ERRSTAT(status)) {#ifdef RMS_DEBUG0printf("[openconn] Error from sys$connect()\n");#endif lib$signal(status);$ sys$close(&rfp->rf_fab, ___, ___);& if (rfp->rf_rab.rab$l_ubf != NULL) { free(rfp->rf_rab.rab$l_ubf); } return (status); }4 /* Clean up expanded and resultant name strings. */: nametrim = &rfp->rf_nam.nam$l_rsa[rfp->rf_nam.nam$b_rsl];? while (*--nametrim != ';' && nametrim > rfp->rf_nam.nam$l_rsa) ; if (*nametrim == ';') { *++nametrim = '0'; nametrim++; } *nametrim = '\0';: rfp->rf_nam.nam$b_rsl = nametrim - rfp->rf_nam.nam$l_rsa;5 rfp->rf_nam.nam$l_esa[rfp->rf_nam.nam$b_esl] = '\0'; /* Return success. */ return (1);}F/* Close a file and free its buffer. Don't free the RMSFILE -- it mayAstill be needed to continue wild-card processing, or whatever. */ rfinish(rfp)register RMSFILE *rfp;{* if (rfp->rf_rab.rab$b_bid != RAB$C_BID) { return; } rflush(rfp);% if (rfp->rf_rab.rab$l_ubf != NULL) { free(rfp->rf_rab.rab$l_ubf); rfp->rf_rab.rab$l_ubf = NULL; }4 rfp->rf_rab.rab$w_usz = rfp->rf_rab.rab$w_rsz = 0;( sys$disconnect(&rfp->rf_rab, ___, ___); rfp->rf_rab.rab$b_bid = 0;# sys$close(&rfp->rf_fab, ___, ___);}4/* Write character c to the file accessed by rfp. */ rputc(c, rfp)int c;register RMSFILE *rfp;{ if (!OPEN_FOR_WRITE(rfp)) { return; } /* Check for end of record. */ if (c == R_EOR) { if (USE_BLOCK_IO(rfp)) {. if (rfp->rf_fab.fab$b_rfm == FAB$C_STMCR) { c = '\r';0 } else if (rfp->rf_fab.fab$b_rfm == FAB$C_STM1 || rfp->rf_fab.fab$b_rfm == FAB$C_STMLF) { c = '\n'; } } else { rflsbuf(rfp); return; } }2 /* If output buffer is full, write it to file. */E if (rfp->rf_bufp - rfp->rf_rab.rab$l_ubf >= rfp->rf_rab.rab$w_usz) { rflsbuf(rfp); }) /* Append character to output buffer. */ *rfp->rf_bufp++ = c;}5/* Read next character from the file accessed by rfp./Return that character, or R_EOF on end of file.!Return R_EOR at end of record. */ rgetc(rfp)register RMSFILE *rfp;{ register int c;6 register char *ebup; /* end of buffer used pointer */ int eofr; if (!OPEN_FOR_READ(rfp)) { return (R_EOF); } /* Check for end of buffer. */6 ebup  VMS_COMPRESS.BCK\V%&[DCOLIB.TSLIB_PROGS.COMPRESS]RMSIO.C;1T;1N!= rfp->rf_rab.rab$l_ubf + rfp->rf_rab.rab$w_rsz; if (rfp->rf_bufp == ebup) { rfp->rf_bufp++; if (!USE_BLOCK_IO(rfp)) { return (R_EOR); } }2 /* If buffer is empty, read next record/block. */ if (rfp->rf_bufp > ebup) { if (rfilbuf(rfp) == R_EOF) { return (R_EOF); }# if (rfp->rf_rab.rab$w_rsz == 0) { rfp->rf_bufp++; return (R_EOR); }7 ebup = rfp->rf_rab.rab$l_ubf + rfp->rf_rab.rab$w_rsz; }) /* Return next character from buffer. */ c = *rfp->rf_bufp++ & 0xFF; if (USE_BLOCK_IO(rfp)) {" switch (rfp->rf_fab.fab$b_rfm) {, /* Simple stream format files use a single! record terminator character. */ case FAB$C_STMCR: if (c == '\r') { c = R_EOR; } break; case FAB$C_STMLF: if (c == '\n') { c = R_EOR; } break;6 /* Generic stream format files use several different- record terminators -- LF, FF, VT, CR-LF. */ case FAB$C_STM:/ if (c == '\n' || c == '\f' || c == '\013') { c = R_EOR;- } else if (c == '\r') { /* check CR-LF */ if (rfp->rf_bufp >= ebup) {! if (rfilbuf(rfp) == R_EOF) { break; } } if (*rfp->rf_bufp == '\n') { rfp->rf_bufp++; c = R_EOR; } } break; } } return (c);},/* Read next record (or block) from file. */static rfilbuf(rfp) RMSFILE *rfp;{ int status;& rfp->rf_bufp = rfp->rf_rab.rab$l_ubf;6 status = (*rfp->rf_datafunc)(&rfp->rf_rab, ___, ___); if (status == RMS$_EOF) { return (R_EOF); } if (ERRSTAT(status)) {#ifdef RMS_DEBUGBprintf("[rfilbuf] Read error, %s (0x%08X)\n", rfp->rf_rsbuf, rfp);#endif lib$signal(status); return (R_EOF); } return (0);}H/* Write the latest record (or block) to the file -- if buffer is empty,write an empty record. */static rflsbuf(rfp)register RMSFILE *rfp;{ int status;: /* Set output record pointer and size (record length). *// rfp->rf_rab.rab$l_rbf = rfp->rf_rab.rab$l_ubf;> rfp->rf_rab.rab$w_rsz = rfp->rf_bufp - rfp->rf_rab.rab$l_ubf;# /* Write the record (or block). */6 status = (*rfp->rf_datafunc)(&rfp->rf_rab, ___, ___);< if (status == RMS$_EXT && EXQUOTA(rfp->rf_rab.rab$l_stv)) {7 status = (*rfp->rf_datafunc)(&rfp->rf_rab, ___, ___); if (ERRSTAT(status)) { lib$stop(status); } } if (ERRSTAT(status)) { lib$signal(status); }6 /* Reset buffer pointer, now that buffer is empty. */& rfp->rf_bufp = rfp->rf_rab.rab$l_ubf; rfp->rf_rab.rab$w_rsz = 0;}</* If a partial record is buffered, write it to the file. */ rflush(rfp) RMSFILE *rfp;{( /* Make sure file is open for write. */ if (!OPEN_FOR_WRITE(rfp)) { return; }3 /* If there's anything in the buffer, flush it. */- if (rfp->rf_bufp != rfp->rf_rab.rab$l_ubf) { rflsbuf(rfp); }}E/* Write count objects, each occupying size bytes, from the indicatedIbuffer to the file accessed by rfp. Return number of objects written. */ rwrite(buffer, size, count, rfp)register char *buffer; int size; int count;register RMSFILE *rfp;{ register int nbyte; nbyte = size * count; while (nbyte-- > 0) { rputc(*buffer++, rfp); } return (count);}H/* Read count objects, each occupying size bytes, from the file accessedHby rfp into the indicated buffer. Return the number of objects read. */rread(buffer, size, count, rfp)register char *buffer; int size; int count;register RMSFILE *rfp;{ register int c, nbyte, nobj;' for (nobj = 0; nobj < count; nobj++) { nbyte = size; while (nbyte-- > 0) {# if ((c = rgetc(rfp)) == R_EOF) { return (nobj); } *buffer++ = c; } } return (nobj);}J/* Return TRUE if the file name in the given FAB specifies a file-oriented device. */#include #include static is_fod(namp)struct NAM *namp;{ int status, devchar; int strdsc[2]; strdsc[0] = namp->nam$b_esl;" strdsc[1] = (int)namp->nam$l_esa; devchar = 0;E status = lib$getdvi(&DVI$_DEVCHAR, ___, strdsc, &devchar, ___, ___); if (~status & 1) { lib$signal(status); }1 return ((devchar & DEV$M_FOD) == DEV$M_FOD);}&*[DCOLIB.TSLIB_PROGS.COMPRESS]RMSIO.H;1+,]./ 4H-V%0123KPWO5 6@72!*189f1G HJ/*CMPR version 1.0, April 1987HAdapted from the public domain program, compress version 3.0, on USENET,@which was written by Spencer W. Thomas, Jim McKie, Steve Davies,-Ken Turkowski, James A. Woods, and Joe Orost.2VAX/VMS version copyright (C) 1987 by Jesse Perry.ECMPR is in the public domain and may be freely distributed, used, and.modified, provided this notice is not removed.rmsio.hCThis is the include file for rmsio.c. It defines various constantsand types used by rmsio.c.*/#include #ifndef ___:#define ___ 0 /* placeholder for unspecified arguments */#endif #ifndef NULL#define NULL 0#endif#define R_READ 0#define R_WRITE 1#define R_EOF (-1)#define R_EOR 256 /* Flag bits used in rf_flag. */#define RF_FOD 0x01,#define rclose(rfp) rfinish(rfp); free(rfp)typedef struct {* int rf_flag; /* flags describing file */4 char *rf_bufp; /* current position in rab$l_ubf */8 int (*rf_datafunc)(); /* function to read/write file *// struct FAB rf_fab; /* RMS file access block */1 struct RAB rf_rab; /* RMS record access block */= struct NAM rf_nam; /* RMS file name block, for wild-cards */5 char rf_rsbuf[256]; /* resultant file name buffer */4 char rf_esbuf[256]; /* expanded file name buffer */ } RMSFILE;(*[DCOLIB.TSLIB_PROGS.COMPRESS]RMSIO.OBJ;1+,1. / 4 * -V%0123KPWO 56 OAl7@l!$Al89G HJ2RMSIOV1.024-JUN-1989 19:42VAX C V3.0-031 CC$RMS_NAM CC$RMS_FAB CC$RMS_RAB CC$RMS_XABALL CC$RMS_XABDAT CC$RMS_XABFHC CC$RMS_XABKEY CC$RMS_XABPRO CC$RMS_XABRDT CC$RMS_XABSUM CC$RMS_XABTRMRFLUSHRGETCRPUTCRFINISH SYS$WRITESYS$READSYS$PUTSYS$GET SYS$SEARCHFREE LIB$SIGNAL SYS$PARSESTRLEN LIB$MOVC3 LIB$MOVC5MALLOCFREE LIB$SIGNAL SYS$SEARCHRFINISHFREE SYS$CONNECT SYS$CLOSEP^լѬ<~MALLOCPRP P߭ԭ߭ԭ߭ LIB$MOVC5 `߭ԭ߭ԭ߭ LIB$MOVC5b|լ  ݬ P߭ LIB$MOVC3 P ЬPP8PSTRLENP@բ4 4Т4P``ՠ ՠ    |~  SYS$PARSEPQQPPQ LIB$SIGNALRFREEPȏТ4Q С ԭ|~߭߭߭ LIB$GETDVIPQQPP Q LIB$SIGNALˏPQP@QQbլߢ"""PP]bY@ VMS_COMPRESS.BCK1V%([DCOLIB.TSLIB_PROGS.COMPRESS]RMSIO.OBJ;11;1 "RPլ  +*Bע""PP"+PPPP P"PP@"ȏ b/|~  SYS$SEARCHPQQPPլQ LIB$SIGNALRFREEPRPPP RFREEPRP ^ЬRRS\PPRSQ"PʏPѡQÀÀFREEÀԣ||~\SYS$DISCONNECT\|~  SYS$CLOSEbP|~  SYS$SEARCHPSSPP!SʂPS LIB$SIGNALRFREEPRPPP RFREEPP (^ЬR"PPSYS$PUT|~  SYS$CREATEPSPSYS$GET|~ SYS$OPENPSSPP S LIB$SIGNALSP\D߭ԭ߭ԭ߭ LIB$MOVC5\D] ˜+PPPP P"PP,|ȏ`"PP SYS$WRITE"SYS$READߢPhrflsbuft rflush+ rwrite8 @rreadW is_fodZ  EnMALLOC LIB$MOVC5 LIB$SIGNALSYS$OPEN SYS$CREATE SYS$CLOSESYS$DISCONNECTFREERFLUSH LIB$SIGNAL LIB$SIGNALLIB$STOP LIB$SIGNAL LIB$GETDVI ROPEN 0 RNXTOPEN RFINISH RPUTC <RGETC RFLUSH  RWRITE @RREAD$CODE$DATAv^ЬQ С ԭ|~߭߭߭ LIB$GETDVIPQQPP Q LIB$SIGNALˏPQP@QQP|P0$