home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / b / vmslz3.arc < prev    next >
Text File  |  2020-01-01  |  52KB  |  1,850 lines

  1. -h- lz.h    Wed Jul 24 11:49:39 1985    USER$A:[MINOW.LZ]LZ.H;72
  2. /*
  3.  * Header file for all lz compression/decompression routines.
  4.  *
  5.  * Machine/Operating system/compiler selection: (#ifdef'ed)
  6.  * vax                Vax/Unix or Vax/VMS
  7.  * pdp11            makes a small compressor
  8.  * M_XENIX            "large-model" Z8000
  9.  * interdata            Signed long compare is slow
  10.  * unix                Defined on true Unix systems
  11.  * decus            Decus C (no signal)
  12.  * vms                Vax/VMS (VMS_V4 may be set automatically)
  13.  * #define readonly        If the compiler doesn't support it correctly.
  14.  * 
  15.  * Compiler configuration (#if'ed):
  16.  * #define vax_asm   TRUE/FALSE    TRUE on Vax (4bsd) if the compiler supports
  17.  *                the asm() operator.  Check the generated code!
  18.  * #define UCHAR     TRUE/FALSE    TRUE if compiler supports unsigned char
  19.  * #define DEBUG     TRUE/FALSE    TRUE to compile in debug printouts
  20.  *
  21.  * Algorithm Tuning parameters:
  22.  * #define USERMEM   <n>    Memory available to compress.
  23.  *                If large enough, a faster algorithm is used.
  24.  * #define SACREDMEM <n>    Don't use this part of USERMEM.
  25.  * #define BITS      <n>    Maximum number of code bits.
  26.  * #define MAXIO     <n>    Output buffer size (squeeze memory if needed)
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <setjmp.h>
  32. #ifndef decus
  33. # include <signal.h>
  34. /*
  35.  * Arguments to signal():
  36.  */
  37. extern int    abort();        /* Debugging interrupt trap    */
  38. extern int    interrupt();        /* Non-debugging interrupt trap    */
  39. extern int    address_error();    /* "Segment" violation        */
  40. #endif
  41.  
  42. #ifndef    TRUE
  43. # define FALSE        0
  44. # define TRUE        1
  45. #endif
  46. #ifndef    EOS
  47. # define EOS        '\0'
  48. #endif
  49. #define    streq(a, b)    (strcmp((a), (b)) == 0)
  50. #define min(a,b)    ((a) > (b)) ? (b) : (a))
  51.  
  52. /*
  53.  * Set USERMEM to the maximum amount of physical user memory available
  54.  * in bytes.  USERMEM is used to determine the maximum BITS that can be used
  55.  * for compression.
  56.  *
  57.  * SACREDMEM is the amount of physical memory saved for others; compress
  58.  * will hog the rest.
  59.  */
  60.  
  61. #ifndef SACREDMEM
  62. # define SACREDMEM    0
  63. #endif
  64.  
  65. /*
  66.  * Set machine-specific parameters
  67.  */
  68.  
  69. #ifdef vax
  70. # ifdef unix
  71. #  define vax_asm    TRUE        /* If asm() supported on vax    */
  72. # endif
  73. #endif
  74. #ifndef    vax_asm
  75. # define vax_asm    FALSE
  76. #endif
  77.  
  78. #ifdef pdp11
  79. # define BITS    12    /* max bits/code for 16-bit machine        */
  80. # define USERMEM 0    /* Force no user memory                */
  81. # define UCHAR    FALSE    /* TRUE if compiler supports unsigned char    */
  82. # define MAXIO 512    /* Buffer size for PDP-11 I/O buffers        */
  83. #endif
  84.  
  85. /*
  86.  * Set default values for some parameters.
  87.  */
  88.  
  89. #ifndef DEBUG
  90. # define DEBUG    FALSE
  91. #endif
  92.  
  93. #ifdef interdata
  94. # define SIGNED_COMPARE_SLOW TRUE
  95. #endif
  96. #ifndef SIGNED_COMPARE_SLOW
  97. # define SIGNED_COMPARE_SLOW FALSE
  98. #endif
  99.  
  100. #ifndef USERMEM
  101. # define USERMEM 750000    /* default user memory                */
  102. #endif
  103.  
  104. #ifndef    UCHAR
  105. # define UCHAR    TRUE    /* Compiler supports unsigned char        */
  106. #endif
  107.  
  108. #ifndef MAXIO
  109. # define MAXIO    2048    /* I/O buffer size                */
  110. #endif
  111.  
  112. /*
  113.  * Set derived tuning parameters.
  114.  */
  115.  
  116. #ifndef USERMEM
  117. # define USERMEM     0
  118. #endif
  119. #if USERMEM >=            (433484 + SACREDMEM)
  120. # define PBITS        16
  121. #else
  122. # if USERMEM >=            (229600 + SACREDMEM)
  123. #  define PBITS        15
  124. # else
  125. #  if USERMEM >=        (127536 + SACREDMEM)
  126. #   define PBITS    14
  127. #   else
  128. #    if USERMEM >=        ( 73464 + SACREDMEM)
  129. #     define PBITS    13
  130. #    else            /* Smaller systems            */
  131. #     define PBITS    12
  132. #    endif
  133. #   endif
  134. # endif
  135. #endif
  136.  
  137. #ifndef BITS
  138. # define BITS PBITS
  139. #endif
  140.  
  141. #ifdef M_XENIX
  142. # if BITS >= 16
  143. #  define XENIX_16        /* Enable special vector access macros    */
  144. # else
  145. #  if BITS > 13
  146. #   undef BITS
  147. #   define BITS 13        /* Code only handles BITS = 12, 13, 16    */
  148. #  endif
  149. # endif
  150. #endif
  151.  
  152. /*
  153.  * HSIZE is the size of the hash lookup table.  It is set to
  154.  * 1 << BITS + fudge factor, rounded up to a prime number.
  155.  * If it is too big, the "clear the hash" routine will take
  156.  * too long.  The same numbers are replicated in the getsize()
  157.  * routine's data table.
  158.  */
  159.  
  160. #if BITS == 16
  161. # define HSIZE    69001        /* 95% occupancy            */
  162. #endif
  163. #if BITS == 15
  164. # define HSIZE    35023        /* 94% occupancy            */
  165. #endif
  166. #if BITS == 14
  167. # define HSIZE    18013        /* 91% occupancy            */
  168. #endif
  169. #if BITS == 13
  170. # define HSIZE     9001        /* 91% occupancy            */
  171. #endif
  172. #if BITS <= 12
  173. # define HSIZE     5003        /* 80% occupancy            */
  174. #endif
  175.  
  176. /*
  177.  * typedef's -- somewhat machine specific.
  178.  */
  179.  
  180. /*
  181.  * a code_int must be able to hold 2**BITS values of type int, and also -1
  182.  */
  183. #if BITS > 15
  184. typedef long int    code_int;
  185. #else
  186. typedef int        code_int;
  187. #endif
  188.  
  189. /*
  190.  * A count_int must hold ((2**BITS)-1) + (255<<BITS)) and -1.
  191.  *
  192.  * count_int's also hold counters.
  193.  *
  194.  * count_short's hold small counters (for the interdata)
  195.  *
  196.  * Some implementations don't support unsigned char (Decus C, for example)
  197.  * Decus C is also brain damaged with regards to unsigned shorts.
  198.  */
  199. #if SIGNED_COMPARE_SLOW
  200. typedef unsigned long int count_int;
  201. typedef unsigned short int count_short;
  202. #else
  203. typedef long int    count_int;
  204. #endif
  205.  
  206. #if UCHAR
  207. typedef    unsigned char    char_type;
  208. #else
  209. typedef char        char_type;
  210. #endif
  211.  
  212. #ifdef decus
  213. typedef unsigned    U_short;
  214. #define    readonly            /* Dummy out readonly modifier    */
  215. #else
  216. typedef unsigned short    U_short;
  217. #endif
  218.  
  219. #ifdef unix
  220. #define    readonly
  221. #endif
  222.  
  223. typedef short        flag;        /* Boolean flag or parameter    */
  224.  
  225. /*
  226.  * The following define the "magic cookie" header
  227.  */
  228. #define    HEAD1_MAGIC    0x1F
  229. #define HEAD2_MAGIC    0x9D
  230. #define    VMS_HEAD2_MAGIC    0x9E        /* vms-private output format    */
  231.  
  232. /*
  233.  * Defines for third byte of header
  234.  */
  235. #define BIT_MASK    0x1F        /* Gets NBITS in the code    */
  236. #define BLOCK_MASK    0x80        /* Gets block_compress flag    */
  237. /*
  238.  * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
  239.  * a fourth header byte (for expansion).
  240.  */
  241.  
  242. /*
  243.  * This is for backwards compatibilty with an old version of Unix compress.
  244.  */
  245. #ifdef COMPATIBLE            /* Compatible, but wrong!    */
  246. # define MAXCODE(n_bits)    (1 << (n_bits) - 1)
  247. #else
  248. # define MAXCODE(n_bits)    ((1 << (n_bits)) - 1)
  249. #endif
  250.  
  251. #define INIT_BITS 9            /* initial number of bits/code */
  252.  
  253. /*
  254.  * One code could conceivably represent (1<<BITS) characters, but
  255.  * to get a code of length N requires an input string of at least
  256.  * N*(N-1)/2 characters.  With 5000 chars in the stack, an input
  257.  * file would have to contain a 25Mb string of a single character.
  258.  * This seems unlikely.
  259.  */
  260. #define MAXSTACK    8000        /* size of lzdcmp output stack    */
  261.  
  262. #ifndef CHECK_GAP
  263. # define CHECK_GAP     10000        /* ratio check interval        */
  264. #endif
  265.  
  266. #ifndef __LINE__
  267. # define NO__LINE__
  268. #endif
  269. #ifndef __FILE__
  270. # define NO__LINE__
  271. #endif
  272. #if DEBUG
  273. # define VERBOSE_DEFAULT    1
  274. # ifndef NO__LINE__
  275. #  define FAIL(why)                    \
  276.     fprintf(stderr, "\nfatal: %s (%s at %d)\n",    \
  277.         why, __FILE__, __LINE__);             \
  278.     longjmp(failure, 1);
  279. # else
  280. #  define FAIL(why)                    \
  281.     fprintf(stderr, "\nfatal: %s\n", why);         \
  282.     longjmp(failure, 1);
  283. # endif
  284. #else
  285. # define VERBOSE_DEFAULT    0
  286. # define FAIL(why)    longjmp(failure, 1);
  287. #endif
  288.  
  289. /*
  290.  * Note -- for compatibility with Unix compress,
  291.  * NBR_CHAR and LZ_CLEAR must equal 256.
  292.  * Also, (1 << (MIN_BITS - 1) should equal or exceed NBR_CHR
  293.  */
  294. #define    NBR_CHAR      256        /* Number of input codes    */
  295. #define MIN_BITS    9        /* Smallest code is 9 bits    */
  296. #if ((1 << BITS) < NBR_CHAR) || (BITS < MIN_BITS)
  297.     << Can't compile: not enough bits for the input character set size >>
  298. #endif
  299. #define    LZ_CLEAR    (NBR_CHAR)    /* Clear code            */
  300. #define    LZ_SOH        (LZ_CLEAR + 1)    /* Start of header block    */
  301. #define    LZ_STX        (LZ_SOH   + 1)    /* Start of text block        */
  302. #define    LZ_EOR        (LZ_STX   + 1)    /* End of text record        */
  303. #define    LZ_ETX        (LZ_EOR   + 1)    /* End of header/text block    */
  304. #define    LZ_FIRST    (LZ_ETX   + 1)    /* First user (data) code    */
  305.  
  306. #ifdef    vms
  307. #include        errno
  308. #include        ssdef
  309. #include        stsdef
  310. #define    IO_SUCCESS    (SS$_NORMAL | STS$M_INHIB_MSG)
  311. #define    IO_ERROR    (SS$_ABORT)
  312. #define VMS_V4        L_cuserid >= 16        /* Enable new stuff    */
  313. #else
  314. #define VMS_V4        0            /* Disable new stuff    */
  315. extern int        errno;
  316. #ifdef decus
  317. #define    errno        $$ferr
  318. #endif
  319. #endif
  320.  
  321. /*
  322.  * Define exit() codes.
  323.  */
  324.  
  325. #ifndef    IO_SUCCESS
  326. #define    IO_SUCCESS    0            /* Normal exit        */
  327. #define    IO_ERROR    1            /* Error exit        */
  328. #endif
  329.  
  330. /*
  331.  * All I/O is done by way of "streams".  To establish a stream,
  332.  * set the parameters appropriately and off you go.  The following
  333.  * functions are provided:
  334.  *    lz_fill(stream)        fills the buffer from stdin
  335.  *    lz_flush(stream)    writes the buffer to stdout
  336.  *    lz_eof(stream)        returns EOF (for fill from memory)
  337.  *    lz_fail(stream)        abort (for writing to memory).
  338.  *    lz_dummy(stream)    throw an output stream away.
  339.  * Note: if VMS_V4 is enabled and the private (non-export) format
  340.  * chosen, lz_fill and lz_flush access the files appropriately.
  341.  * Stream elements are initialized as follows:
  342.  *    Input:    bp = NULL;    bend = NULL;
  343.  *    Output:    bp = bstart;    bend = bstart + bsize;
  344.  */
  345.  
  346. typedef struct STREAM {
  347.     char_type    *bp;        /* Next character to get/put        */
  348.     char_type    *bend;        /* -> end of stream buffer        */
  349.     char_type    *bstart;    /* Start of stream buffer        */
  350.     short    bsize;        /* Stream buffer size            */
  351.     int        (*func)();    /* Read/write a buffer function        */
  352. } STREAM;
  353.  
  354. /*
  355.  * Note also that the compress routine uses putbuf(buf, count, outstream)
  356.  * and the decompress routine uses getbuf(buf, count, instream) to (quickly)
  357.  * transfer multiple bytes.
  358.  */
  359. #if UCHAR
  360. #define    GET(s)        \
  361.     (((s)->bp < (s)->bend) ? *(s)->bp++        : (*(s)->func)(s))
  362. #else
  363. #define    GET(s)        \
  364.     (((s)->bp < (s)->bend) ? *(s)->bp++ & 0xFF : (*(s)->func)(s))
  365. #endif
  366. #define    PUT(c, s)    \
  367.     ((((s)->bp >= (s)->bend) ? (*(s)->func)(s) : 0), *(s)->bp++ = (c))
  368.  
  369. extern int lz_fill();
  370. extern int lz_flush();
  371. extern int lz_eof();
  372. extern int lz_fail();
  373. extern int lz_dummy();
  374.  
  375. #if DEBUG
  376. extern readonly char *lz_names[];        /* "LZ_CLEAR" etc.    */
  377. #endif
  378.  
  379. /*
  380.  * Options and globals.
  381.  */
  382. #if VMS_V4
  383. #define    ATT_NAME    "vms$attributes "
  384. #define    ATT_SIZE    15            /* strlen(ATT_NAME)    */
  385. extern int    fdl_status;    /* Error code from fdl library        */
  386. #endif
  387.  
  388. extern flag    binary;        /* -b Readable text file if FALSE    */
  389. extern flag    noheader;    /* -x3 No magic header if TRUE        */
  390. extern flag    export;        /* -x  (non-zero) Supress vms private    */
  391. extern flag    block_compress;    /* -x2                    */
  392. extern flag    verbose;    /* -v  (non-zero) Verbose logging    */
  393. extern readonly flag is_compress; /* TRUE if compress, FALSE if decomp.    */
  394. extern char    *infilename;    /* For error printouts            */
  395. extern char    *outfilename;    /* For more error printouts        */
  396. extern short    n_bits;        /* Current # of bits in compressed file    */
  397. extern int    firstcode;    /* First value past signals        */
  398. extern jmp_buf    failure;    /* For longjmp() return            */
  399.  
  400. -h- lzio.c    Wed Jul 24 11:49:39 1985    USER$A:[MINOW.LZ]LZIO.C;15
  401. /*
  402.  *            l z i o . c
  403.  *
  404.  * I/O buffer management.  All input/output I/O is done through these
  405.  * routines (and the macros in lz.h).  The rules of the game are:
  406.  *
  407.  * input via GET() and getbuf().
  408.  *    GET returns an 8-bit byte, or -1 on eof/error.
  409.  *    getbuf() returns the number of things gotten, or -1 on eof/error.
  410.  *    No return on error: longjmp's to the main-line.
  411.  *
  412.  * output via PUT() and lz_putbuf().
  413.  *    No return on error: longjmp's to the main-line.
  414.  * flush output by lz_flush() before closing files -- or you'll lose data.
  415.  */
  416.  
  417. #include    "lz.h"
  418. #if VMS_V4
  419. #include    <rmsdef.h>
  420. #ifndef FDLSTUFF
  421. #define FDLSTUFF char
  422. #endif
  423. extern FDLSTUFF *fdl_input;
  424. extern FDLSTUFF *fdl_output;
  425. extern int    fdl_status;
  426. #endif
  427.  
  428. int
  429. lz_fill(s)
  430. register STREAM        *s;
  431. {
  432.     register int    i;
  433.     extern char    *infilename;
  434.  
  435. #if VMS_V4
  436.     if (export && is_compress) {
  437.         i = fread((char *) s->bstart, 1, s->bsize, stdin);
  438.         if (ferror(stdin)) {
  439.         perror(infilename);
  440.         FAIL("export && is_compress fread error");
  441.         }
  442.     }
  443.     else {            /* Decompress and export/private    */
  444.         i = fdl_read(s->bstart, s->bsize, fdl_input);
  445.         if (i < 0 && fdl_status != RMS$_EOF)
  446.         fdl_message(fdl_input, "Read error");
  447.     }
  448. #else
  449. #ifdef unix
  450.     i = read(fileno(stdin), (char *) s->bstart, s->bsize);
  451.     if (i < 0) {
  452.         perror(infilename);
  453.         FAIL("unix read error");
  454.     }
  455. #else
  456.     i = fread((char *) s->bstart, 1, s->bsize, stdin);
  457.     if (ferror(stdin)) {
  458.         perror(infilename);
  459.         exit(IO_ERROR);
  460.     }
  461. #endif
  462. #endif
  463.     if (i <= 0)
  464.         return (EOF);
  465.     else {
  466.         s->bp = s->bstart;
  467.         s->bend = &s->bstart[i];
  468. #if UCHAR
  469.         return (*s->bp++);
  470. #else
  471.         return (*s->bp++ & 0xFF);
  472. #endif
  473.     }
  474. }
  475.  
  476. lz_flush(s)
  477. register STREAM    *s;
  478. {
  479.     register int    count;
  480.     extern char    *outfilename;
  481.  
  482.     count = s->bp - s->bstart;
  483. #if DEBUG
  484.     if (!is_compress && verbose > 4) {
  485.         fprintf(stderr, "lz_flush %d:  ", count);
  486.         dumptext(s->bstart, count, stderr);
  487.     }
  488. #endif
  489. #if VMS_V4
  490.     if (export) {
  491.         if (is_compress)
  492.         fwrite((char *) s->bstart, count, 1, stdout);
  493.         else {
  494.         register char *bp, *bend;
  495.  
  496.         for (bp = s->bstart, bend = bp + count; bp < bend; bp++)
  497.             putchar(*bp);
  498.         }
  499.         if (ferror(stdout)) {
  500.         perror(outfilename);
  501.         FAIL("VMS V4 fwrite/putchar error");
  502.         }
  503.     }
  504.     else {
  505.         if (fdl_write((char *) s->bstart, count, fdl_output) == -1) {
  506.         fdl_message(fdl_output, "Write error");
  507.         FAIL("VMS V4 fdl_write error");
  508.         }
  509.     }
  510. #else
  511. #ifdef unix
  512.     if (write(fileno(stdout), (char *) s->bstart, count) != count) {
  513.         perror(outfilename);
  514.         fprintf(stderr, "Can't write to \"%s\"\n", outfilename);
  515.         FAIL("Unix write error");
  516.     }
  517. #else
  518.     fwrite((char *) s->bstart, 1, count, stdout);
  519.     if (ferror(stdout)) {
  520.         perror(outfilename);
  521.         FAIL("Other (decus) fwrite error");
  522.     }
  523. #endif
  524. #endif
  525.     s->bp = s->bstart;
  526. }
  527.  
  528. int
  529. lz_getbuf(buffer, count, s)
  530. char_type        *buffer;
  531. int            count;
  532. register STREAM        *s;
  533. /*
  534.  * Read a block of data -- be clever.  Return number gotten, or -1
  535.  * on eof.
  536.  */
  537. {
  538.     register char_type    *bp;        /* -> buffer        */
  539.     register char_type    *ip;        /* -> I/O buffer    */
  540.     register char_type    *ep;        /* End of segment    */
  541.     register int        remaining;    /* Size of segment    */
  542.     int            datum;
  543.  
  544.     if (count == 0)                /* Shouldn't happen    */
  545.         return (0);
  546.     bp = buffer;
  547.     while (--count >= 0) {
  548.         if ((datum = GET(s)) == EOF)    /* Maybe fill LZ buff    */
  549.         break;
  550.         *bp++ = datum;
  551.         remaining = s->bend - (ip = s->bp);
  552.         if (remaining > count)
  553.         remaining = count;
  554.         ep = &ip[remaining];
  555.         while (ip < ep)
  556.         *bp++ = *ip++;
  557.         count -= remaining;
  558.         s->bp = ip;                /* Refresh buffer    */
  559.     }
  560.     return ((bp == buffer) ? -1 : bp - buffer);
  561. }
  562.  
  563. int
  564. lz_putbuf(bp, count, s)
  565. register char_type    *bp;
  566. int            count;
  567. register STREAM        *s;
  568. /*
  569.  * Write a block of data -- be clever.
  570.  */
  571. {
  572.     register char_type    *op;        /* -> I/O buffer    */
  573.     register char_type    *ep;        /* End of segment    */
  574.     register int        remaining;    /* Size of segment    */
  575.  
  576.     while (--count >= 0) {
  577.         PUT(*bp++, s);            /* Forces a buffer    */
  578.         remaining = s->bend - (op = s->bp);
  579.         if (remaining > count)
  580.         remaining = count;
  581.         ep = &op[remaining];
  582.         while (op < ep)
  583.         *op++ = *bp++;
  584.         count -= remaining;
  585.         s->bp = op;                /* Refresh buffer    */
  586.     }
  587. }
  588.  
  589. int
  590. lz_eof(s)
  591. STREAM        *s;
  592. /*
  593.  * Dummy routine for read from memory -- returns EOF.
  594.  */
  595. {
  596.     return (s, EOF);
  597. }
  598.  
  599. int
  600. lz_fail(s)
  601. STREAM        *s;
  602. /*
  603.  * Dummy routine for write to memory -- called if buffer fills.
  604.  */
  605. {
  606.     fprintf(stderr, "Memory buffer [%d bytes] filled -- fatal.\n",
  607.         s->bsize);
  608.     FAIL("lz_fail crash");
  609. }
  610.  
  611. int
  612. lz_dummy(s)
  613. STREAM        *s;
  614. /*
  615.  * Dummy routine for write to memory -- writes to the bit-bucket.
  616.  */
  617. {
  618.     s->bp = s->bstart;
  619. }
  620.  
  621. #ifndef decus
  622. /*
  623.  * Signal error handlers.
  624.  */
  625. #ifdef vms
  626. #define unlink    delete
  627. #endif
  628.  
  629. interrupt()
  630. {
  631.     if (outfilename != NULL && !streq(outfilename, "<stdout>"))
  632.         unlink(outfilename);
  633.     exit(IO_ERROR);
  634. }
  635.  
  636. address_error()
  637. {
  638.     if (!is_compress)
  639.         fprintf(stderr, "Decompress: corrupt input file\n");
  640.     interrupt();
  641. }
  642. #endif
  643.  
  644. /*
  645.  * getredirection() is intended to aid in porting C programs
  646.  * to VMS (Vax-11 C) which does not support '>' and '<'
  647.  * I/O redirection.  With suitable modification, it may
  648.  * useful for other portability problems as well.
  649.  */
  650.  
  651. #ifdef    vms
  652.  
  653. int
  654. getredirection(argc, argv)
  655. int        argc;
  656. char        **argv;
  657. /*
  658.  * Process vms redirection arg's.  Exit if any error is seen.
  659.  * If getredirection() processes an argument, it is erased
  660.  * from the vector.  getredirection() returns a new argc value.
  661.  *
  662.  * Warning: do not try to simplify the code for vms.  The code
  663.  * presupposes that getredirection() is called before any data is
  664.  * read from stdin or written to stdout.
  665.  *
  666.  * Normal usage is as follows:
  667.  *
  668.  *    main(argc, argv)
  669.  *    int        argc;
  670.  *    char        *argv[];
  671.  *    {
  672.  *        argc = getredirection(argc, argv);
  673.  *    }
  674.  */
  675. {
  676.     register char        *ap;    /* Argument pointer    */
  677.     int            i;    /* argv[] index        */
  678.     int            j;    /* Output index        */
  679.     int            file;    /* File_descriptor     */
  680.  
  681.     for (j = i = 1; i < argc; i++) {   /* Do all arguments    */
  682.         switch (*(ap = argv[i])) {
  683.         case '<':            /* <file        */
  684.         if (freopen(++ap, "r", stdin) == NULL) {
  685.             perror(ap);        /* Can't find file    */
  686.             exit(IO_ERROR);    /* Is a fatal error    */
  687.         }
  688.         break;
  689.  
  690.         case '>':            /* >file or >>file    */
  691.         if (*++ap == '>') {    /* >>file        */
  692.             /*
  693.              * If the file exists, and is writable by us,
  694.              * call freopen to append to the file (using the
  695.              * file's current attributes).  Otherwise, create
  696.              * a new file with "vanilla" attributes as if
  697.              * the argument was given as ">filename".
  698.              * access(name, 2) is TRUE if we can write on
  699.              * the specified file.
  700.              */
  701.             if (access(++ap, 2) == 0) {
  702.             if (freopen(ap, "a", stdout) != NULL)
  703.                 break;    /* Exit case statement    */
  704.             perror(ap);    /* Error, can't append    */
  705.             exit(IO_ERROR);    /* After access test    */
  706.             }            /* If file accessable    */
  707.         }
  708.         /*
  709.          * On vms, we want to create the file using "standard"
  710.          * record attributes.  create(...) creates the file
  711.          * using the caller's default protection mask and
  712.          * "variable length, implied carriage return"
  713.          * attributes. dup2() associates the file with stdout.
  714.          */
  715.         if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
  716.          || dup2(file, fileno(stdout)) == -1) {
  717.             perror(ap);        /* Can't create file    */
  718.             exit(IO_ERROR);    /* is a fatal error    */
  719.         }            /* If '>' creation    */
  720.         break;            /* Exit case test    */
  721.  
  722.         default:
  723.         argv[j++] = ap;        /* Not a redirector    */
  724.         break;            /* Exit case test    */
  725.         }
  726.     }                /* For all arguments    */
  727.     argv[j] = NULL;            /* Terminate argv[]    */
  728.     return (j);            /* Return new argc    */
  729. }
  730. #endif
  731.  
  732. #if 1 || DEBUG
  733.  
  734. int        col;
  735.  
  736. readonly char *lz_names[] = {
  737.     "LZ_CLEAR", "LZ_SOH", "LZ_STX", "LZ_EOR", "LZ_ETX", "???"
  738. };
  739.  
  740. dumphex(buffer, count, fd)
  741. register char_type    *buffer;
  742. register int        count;
  743. FILE            *fd;
  744. {
  745.     if (col > 0) {
  746.         putc('\n', fd);
  747.         col = 0;
  748.     }
  749.     fprintf(fd, "%2d:", count);
  750.     while (--count >= 0) {
  751.         fprintf(fd, " %02x", *buffer++ & 0xFF);
  752.     }
  753.     fprintf(fd, "\n");
  754. }
  755.  
  756. dumptext(buffer, count, fd)
  757. register char_type    *buffer;
  758. int            count;
  759. FILE            *fd;
  760. {
  761.     extern char    *dumpchar();
  762.  
  763.     putc('"', fd);
  764.     while (--count >= 0)
  765.         fputs(dumpchar((int) *buffer++), fd);
  766.     fputs("\"\n", fd);
  767. }
  768.  
  769. char *
  770. dumpchar(c)
  771. register int    c;
  772. /*
  773.  * Make a character printable.  Returns a static pointer.
  774.  */
  775. {
  776.     static char    dump_buffer[8];
  777.  
  778.     c &= 0xFF;
  779.     if (isascii(c) && isprint(c)) {
  780.         dump_buffer[0] = c;
  781.         dump_buffer[1] = EOS;
  782.     }
  783.     else {
  784.         switch (c) {
  785.         case '\n':    return ("\\n");
  786.         case '\t':    return ("\\t");
  787.         case '\b':    return ("\\b");
  788.         case '\f':    return ("\\f");
  789.         case '\r':    return ("\\r");
  790.         }
  791.         sprintf(dump_buffer, "<x%02X>", c);
  792.     }
  793.     return (dump_buffer);
  794. }
  795. #endif
  796.  
  797. /*
  798.  * Cputime returns the elapsed process time (where available) in msec.
  799.  * Note: Unix doesn't seem to have a good way to determine ticks/sec.
  800.  */
  801.  
  802. #ifdef    decus
  803. #include    <timeb.h>
  804.  
  805. long
  806. cputime()
  807. {
  808.     struct timeb        buf;
  809.     static struct timeb    origin;
  810.     long            result;
  811.     int            msec;
  812.  
  813.     if (origin.time == 0)
  814.         ftime(&origin);
  815.     ftime(&buf);
  816.     result = (buf.time - origin.time) * 1000;
  817.     msec = ((int) buf.msec) - ((int) origin.msec);
  818.     return (result + ((long) msec));
  819. }
  820. #else
  821. #ifdef vms
  822. #include    <types.h>
  823. struct tms {
  824.     time_t    tms_utime;
  825.     time_t    tms_stime;
  826.     time_t    tms_uchild;    /* forgot the */
  827.     time_t    tms_uchildsys;    /* real names */
  828. };
  829. #define HERTZ    100.0                /* 10 msec units    */
  830. #else
  831. #include    <sys/types.h>
  832. #include    <sys/times.h>
  833. #ifndef HERTZ
  834. #define HERTZ    60.0                /* Change for Europe    */
  835. #endif
  836. #endif
  837.  
  838. long
  839. cputime()
  840. {
  841.     struct tms    tms;
  842.     double        temp;
  843.     long        result;
  844.  
  845.     times(&tms);
  846.     result = tms.tms_utime + tms.tms_stime;
  847.     temp = result * 1000.0 / HERTZ;        /* Time in msec.    */
  848.     result = temp;
  849.     return (result);
  850. }
  851. #endif
  852.  
  853. -h- lzvio.c    Wed Jul 24 11:49:39 1985    USER$A:[MINOW.LZ]LZVIO.C;3
  854. /*
  855.  *            l z v i o . c
  856.  * For VMS V4 only.
  857.  */
  858.  
  859. /*
  860.  * Problems:
  861.  *    If you open a second input file (getting rms attributes)
  862.  *    it aborts with an internal "fatal" error (15820C LIB-F-FATERRLIB)
  863.  */
  864.  
  865. /*
  866.  * Make TESTING_FDLIO non-zero to enable test code.
  867.  *
  868.  * Edit History
  869.  */
  870. #ifndef    TESTING_FDLIO
  871. #define    TESTING_FDLIO    0
  872. #endif
  873.  
  874. /*
  875.  * RMS/FDL record level i/o routines for Vax-11 C V4 or greater only.
  876.  * Rather crude.
  877.  *
  878.  * The following are provided:
  879.  *
  880.  *    #define    FDLSTUFF    char
  881.  *    #include descrip
  882.  *
  883.  *    FDLSTUFF *
  884.  *    fdl_open(filename, fdl_descriptor)
  885.  *    char            *filename;
  886.  *    struct    dsc$descriptor    *fdl_descriptor;
  887.  *        Initializes internal buffers and opens this existing
  888.  *        file for input.  The filename may not contain wildcards.
  889.  *        On (successful) return, fdl_descriptor will point to
  890.  *        an initialized fdl specification.  The description
  891.  *        string will be in malloc'ed memory.  The caller does not
  892.  *        initialize the fdl_descriptor.  Returns NULL on error.
  893.  *        (Note an error will be returned if the file is not
  894.  *        block-oriented.)
  895.  *
  896.  *        When you don't need the fdl_descriptor information
  897.  *        any more, free it by calling
  898.  *            fdl_free(fdl_descriptor);
  899.  *        if fdl_descriptor is NULL on entry, the file is opened
  900.  *        normally (fdl information is not collected).
  901.  *
  902.  *    FDLSTUFF *
  903.  *    fdl_create(fdl_descriptor, override_filename)
  904.  *    struct    dsc$descriptor    *fdl_descriptor;
  905.  *    char            *override_filename;
  906.  *        Creates a file using the fdl specification.
  907.  *        If override_filename is not NULL and not equal to "",
  908.  *        it will override the filename specified in the fdl.
  909.  *        fdl_write() is used to write data to the file.
  910.  *        Returns NULL on error.
  911.  *
  912.  *        if fdl_descriptor is NULL, the file is created using
  913.  *        the name in override_filename (which must be present).
  914.  *        The file is created in "undefined" record format.
  915.  *
  916.  *    fdl_free(fdl_descriptor)
  917.  *    struct    dsc$descriptor    *fdl_descriptor;
  918.  *        Releases the fdl descriptor block.
  919.  *
  920.  *    int
  921.  *    fdl_read(buffer, buffer_length, r)
  922.  *    char        *buffer;
  923.  *    int        buffer_length;
  924.  *    FDLSTUFF    *r;
  925.  *        Read buffer_length bytes from the file (using SYS$READ).
  926.  *        No expansion or interpretation.  buffer_length had
  927.  *        better be even or you're asking for trouble.  Returns
  928.  *        the actual number of bytes read.  The file has been
  929.  *        opened by fdl_open.
  930.  *
  931.  *    int
  932.  *    fdl_write(buffer, buffer_length, r)
  933.  *    char        *buffer;
  934.  *    int        buffer_length;
  935.  *    FDLSTUFF    *r;
  936.  *        Write buffer_length bytes to the file (using SYS$WRITE).
  937.  *        No expansion or interpretation.  buffer_length had
  938.  *        better be even or you're asking for trouble.  Returns
  939.  *        the actual number of bytes written.  The file was opened
  940.  *        by fdl_create();
  941.  *
  942.  *    fdl_getname(r, buffer)
  943.  *    FDLSTUFF    *r;
  944.  *    char        *buffer;
  945.  *        Copies the currently open file's name to the caller's
  946.  *        data buffer buffer.
  947.  *
  948.  *    long
  949.  *    fdl_fsize(r)
  950.  *        Returns the size in bytes of the opened file.
  951.  *
  952.  *    fdl_dump(fdl_descriptor, fd)
  953.  *    struct    dsc$descriptor    *fdl_descriptor;
  954.  *    FILE            *fd;
  955.  *        Writes the fdl info to the indicated file with
  956.  *        line breaks in appropriate places.
  957.  *
  958.  *    fdl_message(r, why)
  959.  *    FDLSTUFF    *r;
  960.  *    char        *why;
  961.  *        All system-level routines set a global value, fdl_status.
  962.  *        fdl_message() prints the error message text corresponding
  963.  *        to the current value of fdl_status.  The message printed
  964.  *        has the format:
  965.  *            why current_filename: error_message.
  966.  *        If why is NULL, only the error_message is printed.
  967.  */
  968.  
  969. #include "lz.h"
  970. #if VMS_V4
  971. #include rms
  972. #include ssdef
  973. #include descrip
  974. #include devdef
  975. #ifndef    FDL$M_FDL_SIGNAL
  976. #define FDL$M_FDL_SIGNAL    1    /* Signal errors if set        */
  977. #endif
  978. #ifndef    FDL$M_FDL_STRING
  979. #define FDL$M_FDL_STRING    2    /* Use string for fdl text    */
  980. #endif
  981. #if TESTING_FDLIO
  982. #define    SIGNAL_ON_ERROR    FDL$M_FDL_SIGNAL
  983. #else
  984. #define    SIGNAL_ON_ERROR    0
  985. #endif
  986.  
  987. #define    TRUE    1
  988. #define    FALSE    0
  989. #define    EOS    0
  990.  
  991. typedef struct FDLSTUFF {
  992.     struct    RAB    rab;        /* Record access buffer        */
  993.     struct    FAB    fab;        /* File access buffer        */
  994.     struct    NAM    nam;        /* File name buffer        */
  995.     struct    XABFHC    xab;        /* Extended attributes block    */
  996.     char        starname[NAM$C_MAXRSS + 1]; /* Wild file name    */
  997.     char        filename[NAM$C_MAXRSS + 1]; /* Open file name    */
  998. } FDLSTUFF;
  999.  
  1000. int        fdl_status;        /* Set to last rms call status    */
  1001.  
  1002. static FDLSTUFF *
  1003. fail(r, why, name)
  1004. FDLSTUFF    *r;            /* Buffer            */
  1005. char        *why;            /* A little commentary        */
  1006. char        *name;            /* Argument to perror        */
  1007. /*
  1008.  * Problem exit routine
  1009.  */
  1010. {
  1011. #if TESTING_FDLIO
  1012.     if (name == NULL && r != NULL)
  1013.         name = r->fab.fab$l_fna;
  1014.     message(r, why, name);
  1015. #endif
  1016.     if (r != NULL)
  1017.         free(r);
  1018.     return (NULL);
  1019. }
  1020.  
  1021. FDLSTUFF *
  1022. fdl_open(filename,  fdl_descriptor)
  1023. char            *filename;        /* What to open        */
  1024. struct    dsc$descriptor    *fdl_descriptor;    /* Result descriptor    */
  1025. /*
  1026.  * Open the file.  Returns NULL on failure, else a pointer to RMS stuff.
  1027.  * Which is equivalently a pointer to the RAB. (Note that the RAB points
  1028.  * in turn to the FAB.)
  1029.  *
  1030.  * Return the file's fdl descriptor in the user-supplied (uninitialized)
  1031.  * descriptor.
  1032.  */
  1033. {
  1034.     register FDLSTUFF    *r;
  1035.     int            retlen;
  1036.     int            badblk;
  1037.     struct FAB        *fab_add;
  1038.     struct RAB        *rab_add;
  1039.     static int        flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
  1040.     extern FDLSTUFF        *fdl_setup();
  1041.  
  1042.     if ((r = fdl_setup(filename)) == NULL)
  1043.         return (NULL);
  1044.     /*
  1045.      * Now open the file.
  1046.      */
  1047.     r->fab.fab$b_fac = FAB$M_GET | FAB$M_BIO; /* Block I/O only    */
  1048.     if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
  1049.         return (fail(r, "opening file", NULL));
  1050.     }
  1051.     if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
  1052.         fail(r, "Record only device");
  1053.         fdl_close(r);
  1054.         return (NULL);
  1055.     }
  1056.     r->rab.rab$l_rop = RAB$M_BIO;        /* Block I/O only    */
  1057.     if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
  1058.         return (fail(r, "connecting after open", NULL));
  1059.     if (fdl_descriptor != NULL) {
  1060.         /*
  1061.          * Now, get the file attributes
  1062.          */
  1063.         fdl_descriptor->dsc$w_length = 4096;
  1064.         fdl_descriptor->dsc$b_dtype = DSC$K_DTYPE_VT;
  1065.         fdl_descriptor->dsc$b_class = DSC$K_CLASS_D;
  1066.         fdl_descriptor->dsc$a_pointer = malloc(4096);
  1067.         fab_add = &r->fab;
  1068.         rab_add = &r->rab;
  1069.         if ((fdl_status = fdl$generate(
  1070.             &flags,
  1071.             &fab_add,
  1072.             &rab_add,
  1073.             0, 0,
  1074.             fdl_descriptor,
  1075.             &badblk,
  1076.             &retlen)) != SS$_NORMAL) {
  1077.         fdl_free(fdl_descriptor);
  1078.         sys$close(&r->fab);
  1079.         return(fail(r, "getting fdl info", NULL));
  1080.         }
  1081.         /*
  1082.          * Success, null-terminate fdl info and squeeze the block.
  1083.          */
  1084.         fdl_descriptor->dsc$a_pointer[retlen] = EOS;
  1085.         fdl_descriptor->dsc$a_pointer
  1086.         = realloc(fdl_descriptor->dsc$a_pointer, retlen + 1);
  1087.         fdl_descriptor->dsc$w_length = retlen;
  1088.     }
  1089.     return (r);
  1090. }
  1091.  
  1092. FDLSTUFF *
  1093. fdl_create(fdl_descriptor, override_filename)
  1094. struct    dsc$descriptor    *fdl_descriptor;    /* Result descriptor    */
  1095. char            *override_filename;    /* What to open        */
  1096. /*
  1097.  * Create the file, Returns NULL on failure, else a pointer to RMS stuff.
  1098.  * Which is equivalently a pointer to the RAB. (Note that the RAB points
  1099.  * in turn to the FAB.)  The file is open for writing using fdl_write.
  1100.  *
  1101.  * Uses the filename in the descriptor block, or the override filename
  1102.  * if supplied (non-NULL and not == "");
  1103.  *
  1104.  * If fdl_descriptor is NULL, the override_filename is opened normally.
  1105.  */
  1106. {
  1107.     register FDLSTUFF    *r;
  1108.     int            retlen;
  1109.     int            badblk;
  1110.     static int        flags = (FDL$M_FDL_STRING | SIGNAL_ON_ERROR);
  1111.     struct    dsc$descriptor    newname;
  1112.     struct    dsc$descriptor    *newname_ptr;
  1113.     int            fid_block[3];
  1114.     char            created_name[NAM$C_MAXRSS + 1];
  1115.     struct    dsc$descriptor    created_name_des = {
  1116.                     NAM$C_MAXRSS,
  1117.                     DSC$K_DTYPE_T, 
  1118.                     DSC$K_CLASS_S,
  1119.                     &created_name[0]
  1120.                 };
  1121.     extern FDLSTUFF        *fdl_setup();
  1122.  
  1123.     if (fdl_descriptor == NULL) {
  1124.         if ((r = fdl_setup(override_filename)) == NULL)
  1125.         return (NULL);
  1126.         r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only    */
  1127.         r->fab.fab$l_fop |= (FAB$M_NAM | FAB$M_SQO | FAB$M_BIO);
  1128.         r->fab.fab$b_org = FAB$C_SEQ;    /* Sequential only    */
  1129.         r->fab.fab$b_rfm = FAB$C_UDF;    /* Undefined format    */
  1130.         if ((fdl_status = sys$create(&r->fab)) & 01 == 0)
  1131.         return (fail(r, "creating (sys$create)"));
  1132.         goto exit;
  1133.     }
  1134.     if (override_filename == NULL || override_filename[0] == '\0')
  1135.         newname_ptr = NULL;
  1136.     else {
  1137.         newname_ptr = &newname;
  1138.         newname.dsc$w_length = strlen(override_filename);
  1139.         newname.dsc$b_dtype = DSC$K_DTYPE_T;
  1140.         newname.dsc$b_class = DSC$K_CLASS_S;
  1141.         newname.dsc$a_pointer = override_filename;
  1142.     }
  1143.     if ((fdl_status = fdl$create(fdl_descriptor,
  1144.         newname_ptr,        /* New file name if any        */
  1145.         0,            /* Default filename        */
  1146.         &created_name_des,    /* Resultant filename        */
  1147.         &fid_block[0],        /* File ID block        */
  1148.         &flags,            /* FDL flag bits        */
  1149.         0,            /* Statement number        */
  1150.         &retlen,        /* Created name length        */
  1151.         0, 0)            /* Create status, stv        */
  1152.         ) & 01 == 0) {
  1153.         return(fail(NULL, "creating (fdl$create)", NULL));
  1154.     }
  1155.     created_name[retlen] = '\0';
  1156.     if ((r = fdl_setup(created_name)) == NULL)
  1157.         return (NULL);
  1158.     /*
  1159.      * Now, open the file for output.
  1160.      */
  1161.     r->fab.fab$b_fac = FAB$M_PUT | FAB$M_BIO; /* Block I/O only    */
  1162.     if ((fdl_status = sys$open(&r->fab)) != RMS$_NORMAL) {
  1163.         return (fail(r, "opening created file", NULL));
  1164.     }
  1165. exit:    if ((r->fab.fab$l_dev & DEV$M_REC) != 0) {
  1166.         fail(r, "Record only device");
  1167.         fdl_close(r);
  1168.         return (NULL);
  1169.     }
  1170.     r->rab.rab$l_rop = RAB$M_BIO;        /* Block I/O only    */
  1171.     if ((fdl_status = sys$connect(&r->rab)) != RMS$_NORMAL)
  1172.         return (fail(r, "connecting after create", NULL));
  1173.     return (r);
  1174. }
  1175.  
  1176. static FDLSTUFF *
  1177. fdl_setup(filename)
  1178. char        *filename;
  1179. /*
  1180.  * Initializes rms blocks and parses file name.  Returns the
  1181.  * FDL data block on success, NULL on error.
  1182.  */
  1183. {
  1184.     register FDLSTUFF    *r;
  1185.  
  1186.     if ((r = (char *)malloc(sizeof (FDLSTUFF))) == NULL)
  1187.         return (NULL);
  1188.     r->fab = cc$rms_fab;            /* Preset fab,        */
  1189.     r->nam = cc$rms_nam;            /*   name block        */
  1190.     r->rab = cc$rms_rab;            /*   and record block    */
  1191.     r->xab = cc$rms_xabfhc;            /*   file header block    */
  1192.     r->fab.fab$l_nam = &r->nam;        /* fab -> name block    */
  1193.     r->fab.fab$l_xab = &r->xab;        /* fab -> file header    */
  1194.     r->fab.fab$l_fna = filename;        /* Argument filename    */
  1195.     r->fab.fab$b_fns = strlen(filename);    /* ... size        */
  1196.     r->rab.rab$l_fab = &r->fab;        /* rab -> fab        */
  1197.                         /* Stuff the name block    */
  1198.     r->nam.nam$l_esa = r->starname;        /* Expanded filename    */
  1199.     r->nam.nam$b_ess = NAM$C_MAXRSS + 1;    /* ... size        */
  1200.     r->nam.nam$b_rss = NAM$C_MAXRSS + 1;    /* ... max size        */
  1201.     if ((fdl_status = sys$parse(&r->fab)) != RMS$_NORMAL) {
  1202.         return (fail(r, "parsing", filename));
  1203.     }
  1204.     ((char *)r->nam.nam$l_esa)[r->nam.nam$b_esl] = EOS;
  1205.     r->fab.fab$l_fna = r->nam.nam$l_esa;    /* File name        */
  1206.     r->fab.fab$b_fns = r->nam.nam$b_esl;    /* Length        */
  1207.     r->fab.fab$l_fop |= FAB$M_NAM;        /* Use name block    */
  1208.     return (r);
  1209. }
  1210.  
  1211. fdl_free(fdl_descriptor)
  1212. struct    dsc$descriptor    *fdl_descriptor;
  1213. /*
  1214.  * Release the descriptor
  1215.  */
  1216. {
  1217.     if (fdl_descriptor->dsc$a_pointer != NULL) {
  1218.         free(fdl_descriptor->dsc$a_pointer);
  1219.         fdl_descriptor->dsc$a_pointer = NULL;
  1220.     }
  1221. }
  1222.  
  1223. fdl_close(r)
  1224. register FDLSTUFF    *r;
  1225. {
  1226.     if ((fdl_status = sys$close(&r->fab)) != RMS$_NORMAL)
  1227.         return(fail(r, "close", NULL));
  1228.     free(r);
  1229. }
  1230.  
  1231. int
  1232. fdl_read(buffer, buffer_length, r)
  1233. char        *buffer;        /* Record            */
  1234. int        buffer_length;        /* Record length        */
  1235. register FDLSTUFF *r;            /* Record info.            */
  1236. /*
  1237.  * Read the next record from the file.  Returns number of bytes read or
  1238.  * -1 on any error. fdl_status has the status.
  1239.  */
  1240. {
  1241.     r->rab.rab$l_ubf = buffer;
  1242.     r->rab.rab$w_usz = buffer_length;
  1243.     r->rab.rab$l_bkt = 0;
  1244.     if ((fdl_status = sys$read(&r->rab)) != RMS$_NORMAL) {
  1245. #if TESTING_FDLIO
  1246.         if (fdl_status != RMS$_EOF) {
  1247.         fdl_message(r, "error return from sys$read");
  1248.         sleep(1);
  1249.         }
  1250. #endif
  1251.         return (-1);
  1252.     }
  1253.     return (r->rab.rab$w_rsz);
  1254. }
  1255.  
  1256. int
  1257. fdl_write(buffer, buffer_length, r)
  1258. char        *buffer;        /* Record            */
  1259. int        buffer_length;        /* Record length        */
  1260. register FDLSTUFF *r;            /* Record info.            */
  1261. /*
  1262.  * Write the next record to the file.  Returns number of bytes written or
  1263.  * -1 on any error. fdl_status has the status.
  1264.  */
  1265. {
  1266.     r->rab.rab$l_rbf = buffer;
  1267.     r->rab.rab$w_rsz = buffer_length;
  1268.     r->rab.rab$l_bkt = 0;
  1269.     if ((fdl_status = sys$write(&r->rab)) != RMS$_NORMAL) {
  1270. #if TESTING_FDLIO
  1271.         fdl_message(r, "error return from sys$write");
  1272.         sleep(1);
  1273. #endif
  1274.         return (-1);
  1275.     }
  1276.     return (r->rab.rab$w_rsz);
  1277. }
  1278.  
  1279. fdl_getname(r, buffer)
  1280. FDLSTUFF    *r;            /* File pointer            */
  1281. char        *buffer;        /* Where to put it        */
  1282. /*
  1283.  * Return current file name
  1284.  */
  1285. {
  1286.     strcpy(buffer, r->fab.fab$l_fna);
  1287.     return (buffer);
  1288. }
  1289.  
  1290. long
  1291. fdl_fsize(r)
  1292. FDLSTUFF    *r;            /* File pointer            */
  1293. /*
  1294.  * Return current file size
  1295.  */
  1296. {
  1297.     return (((long) r->xab.xab$l_ebk * 512) + r->xab.xab$w_ffb);
  1298. }
  1299.  
  1300. fdl_message(r, why)
  1301. FDLSTUFF    *r;
  1302. char        *why;
  1303. /*
  1304.  * Print error message
  1305.  */
  1306. {
  1307.     extern char    *vms_etext();
  1308.  
  1309.     if (why == NULL) {
  1310.         fprintf(stderr, "\n%s\n\n", vms_etext(fdl_status));
  1311.     }
  1312.     else {
  1313.         fprintf(stderr, "\n%s%s%s: %s\n\n",
  1314.         why,
  1315.         (why[0] == EOS) ? "" : " ",
  1316.         (r == NULL) ? "" : r->fab.fab$l_fna,
  1317.         vms_etext(fdl_status));
  1318.     }
  1319. }
  1320.  
  1321. static char        errname[257];    /* Error text stored here    */
  1322. static $DESCRIPTOR(err, errname);    /* descriptor for error text    */
  1323.  
  1324. static char *
  1325. vms_etext(errorcode)
  1326. int        errorcode;
  1327. {
  1328.     char        *bp;
  1329.     short        errlen;        /* Actual text length        */
  1330.  
  1331.     lib$sys_getmsg(&errorcode, &errlen, &err, &15);
  1332.     /*
  1333.      * Trim trailing junk.
  1334.      */
  1335.     for (bp = &errname[errlen]; --bp >= errname;) {
  1336.         if (isgraph(*bp) && *bp != ' ')
  1337.         break;
  1338.     }
  1339.     bp[1] = EOS;
  1340.     return(errname);
  1341. }
  1342.  
  1343. static
  1344. message(r, why, name)
  1345. FDLSTUFF    *r;            /* Buffer            */
  1346. char        *why;            /* A little commentary        */
  1347. char        *name;            /* File name            */
  1348. /*
  1349.  * Print error message
  1350.  */
  1351. {
  1352.     fprintf(stderr, "\nRMS error %x when %s %s\n",
  1353.         fdl_status, why, (name == NULL) ? "" : name);
  1354.     fprintf(stderr, "\"%s\"\n", vms_etext(fdl_status));
  1355. }
  1356.  
  1357. fdl_dump(fdl_descriptor, fd)
  1358. struct    dsc$descriptor    *fdl_descriptor;
  1359. FILE            *fd;
  1360. /*
  1361.  * Dump the descriptor to fd.
  1362.  */
  1363. {
  1364.     register char    *tp, *end;
  1365.  
  1366.     tp = fdl_descriptor->dsc$a_pointer;
  1367.     end = tp + fdl_descriptor->dsc$w_length;
  1368.     while (tp < end) {
  1369.         if (*tp == '"') {
  1370.         do {
  1371.             putc(*tp++, fd);
  1372.         } while (*tp != '"');
  1373.         }
  1374.         putc(*tp, fd);
  1375.         if (*tp++ == ';')
  1376.         putc('\n', fd);
  1377.     }
  1378. }
  1379.  
  1380.  
  1381. #if    TESTING_FDLIO
  1382. /*
  1383.  * Test program for rms io
  1384.  */
  1385. #include <stdio.h>
  1386.  
  1387. char            line[133];
  1388. char            filename[133];
  1389. char            buffer[2048];
  1390.  
  1391. main(argc, argv)
  1392. int        argc;
  1393. char        *argv[];
  1394. {
  1395.     FDLSTUFF    *old;
  1396.     FDLSTUFF    *new;
  1397.     int        size, total, nrecords;
  1398.     struct    dsc$descriptor    fdl_info;    /* Result descriptor    */
  1399.  
  1400.     for (;;) {
  1401.         fprintf(stderr, "Old file name: ");
  1402.         fflush(stdout);
  1403.         if (gets(line) == NULL)
  1404.         break;
  1405.         if (line[0] == EOS)
  1406.         continue;
  1407.         if ((old = fdl_open(line, &fdl_info)) == NULL) {
  1408.         fprintf(stderr, "open failed\n");
  1409.         continue;
  1410.         }
  1411.         fprintf(stderr, "New file name: ");
  1412.         if (gets(line) == NULL)
  1413.         break;
  1414.         if ((new = fdl_create(&fdl_info, line)) == NULL) {
  1415.         fprintf(stderr, "create failed\n");
  1416.         fdl_free(&fdl_info);
  1417.         continue;
  1418.         }
  1419.         fdl_getname(old, buffer);
  1420.         fprintf(stderr, "Fdl for \"%s\", size %ld\n",
  1421.         buffer, fdl_fsize(old));
  1422.         fdl_dump(&fdl_info, stderr);
  1423.         total = nrecords = 0;
  1424.         while ((size = fdl_read(buffer, sizeof buffer, old)) > 0) {
  1425.         fdl_write(buffer, size, new);
  1426.         nrecords++;
  1427.         total += size;
  1428.         }
  1429.         fdl_close(old);
  1430.         fdl_close(new);
  1431.         fprintf(stderr, "copied %d records, %d bytes total\n",
  1432.         nrecords, total);
  1433.         fdl_free(&fdl_info);
  1434.     }
  1435. }
  1436.  
  1437. #endif
  1438. #endif
  1439.  
  1440. -h- makefile.txt    Wed Jul 24 11:49:39 1985    USER$A:[MINOW.LZ]MAKEFILE.TXT;6
  1441. # Unix makefile for lzcomp, lzdcmp
  1442. #
  1443. # The redefinition of strchr() and strrchr() are needed for
  1444. # Ultrix-32, Unix 4.2 bsd (and maybe some other Unices).
  1445. #
  1446. BSDDEFINE = -Dstrchr=index -Dstrrchr=rindex
  1447. #
  1448. # On certain systems, such as Unix System III, you may need to define
  1449. # $(LINTFLAGS) in the make command line to set system-specific lint flags.
  1450. #
  1451.  
  1452. CFLAGS = -O $(BSDDEFINES)
  1453.  
  1454. all    : lzcomp lzdcmp
  1455.  
  1456. #
  1457. # ** compile lzcomp
  1458. #
  1459. LZCOMP_SRCS = lzcmp1.c lzcmp2.c lzcmp3.c lzio.c
  1460. LZCOMP_OBJS = lzcmp1.o lzcmp2.o lzcmp3.o lzio.o
  1461. lzcomp: $(LZCOMP_OBJS)
  1462.     $(CC) $(CFLAGS) $(LZCOMP_OBJS) -o lzcomp
  1463.  
  1464. #
  1465. # ** compile lzdcmp
  1466. #
  1467. LZDCMP_SRCS = lzdcm1.c lzdcm2.c lzdcm3.c lzio.c
  1468. LZDCMP_OBJS = lzdcm1.o lzdcm2.o lzdcm3.o lzio.o
  1469. lzdcmp: $(LZDCMP_OBJS)
  1470.     $(CC) $(CFLAGS) $(LZDCMP_OBJS) -o lzdcmp
  1471.  
  1472. #
  1473. # ** Lint the code
  1474. #
  1475. lint:    $(LZCOMP_SRCS) $(LZDCMP_SRCS)
  1476.     lint $(LINTFLAGS) $(DEFINES) $(LZCOMP_SRCS)
  1477.     lint $(LINTFLAGS) $(DEFINES) $(LZDCMP_SRCS)
  1478.  
  1479. #
  1480. # ** Remove unneeded files
  1481. #
  1482. clean:
  1483.     rm -f $(OBJS) lzcomp lzdcmp
  1484.  
  1485. #
  1486. # ** Rebuild the archive files
  1487. # ** Uses the Decus C archive utility.
  1488. #
  1489. archive:
  1490.     cp Makefile makefile.txt
  1491.     archc lzcmp1.c lzcmp2.c lzcmp3.c >lz1.arc
  1492.     archc lzdcm1.c lzdcm2.c lzdcm3.c >lz2.arc
  1493.     archc lz.h lzio.c lzvio.c makefile.txt >lz3.arc
  1494.  
  1495. #
  1496. # Object module dependencies
  1497. #
  1498.  
  1499. lzcmp1.o    :    lzcmp1.c lz.h
  1500.  
  1501. lzcmp2.o    :    lzcmp2.c lz.h
  1502.  
  1503. lzcmp3.o    :    lzcmp3.c lz.h
  1504.  
  1505. lzio.o        :    lzio.c lz.h
  1506.  
  1507. lzdcm1.o    :    lzdcm1.c lz.h
  1508.  
  1509. lzdcm2.o    :    lzdcm2.c lz.h
  1510.  
  1511. lzdcm3.o    :    lzdcm3.c lz.h
  1512.  
  1513.  
  1514. -h- lzcomp.mem    Wed Jul 24 11:49:39 1985    USER$A:[MINOW.LZ]LZCOMP.MEM;2
  1515.  
  1516.  
  1517.  
  1518.  
  1519.            ____ ___________        1  File Compression
  1520.  
  1521.  
  1522.  
  1523.                                    **********
  1524.                                    * lzcomp *
  1525.                                    **********
  1526.  
  1527.  
  1528.  
  1529.         NAME:   lzcomp -- File Compression
  1530.  
  1531.         SYNOPSIS:
  1532.  
  1533.                 lzcomp [-options] [infile [outfile]]
  1534.  
  1535.         DESCRIPTION:
  1536.  
  1537.                 lzcomp  implements  the  Lempel-Ziv   file   compression
  1538.                 algorithm.  (Files compressed by lzcomp are uncompressed
  1539.                 by lzdcmp.) It operates by finding common substrings and
  1540.                 replaces  them  with  a  variable-size  code.   This  is
  1541.                 deterministic, and can be done with a single  pass  over
  1542.                 the  file.   Thus,  the decompression procedure needs no
  1543.                 input table, but can track the way the table was built.
  1544.  
  1545.                 Options may be given in either case.
  1546.  
  1547.                 -B      Input file  is  "binary",  not  "human  readable
  1548.                         text".   This  is  necessary  on  Dec  operating
  1549.                         systems, such as VMS  and  RSX-11M,  that  treat
  1550.                         these  files  differently.   (Note  that  binary
  1551.                         support is rudamentary and probably insufficient
  1552.                         as  yet.)  (On  VMS  version  4, this is ignored
  1553.                         unless the -x option is specified or  the  input
  1554.                         file is record-oriented.)
  1555.  
  1556.                 -M bits Write using the specified number of bits in  the
  1557.                         code  -- necessary for big machines making files
  1558.                         for   little   machines.    For   example,    if
  1559.                         compressing a file on VMS which is to be read on
  1560.                         a PDP-11, you should select -M 12.
  1561.  
  1562.                 -V [n]  Verbose if specified.  If a value is  specified,
  1563.                         it will enable debugging code (if compiled in).
  1564.  
  1565.                 -X [n]  "Export" -- write a file format that can be read
  1566.                         by  other  operating systems.  Only the bytes in
  1567.                         the file are copied;  file  attributes  are  not
  1568.                         preserved.   If  specified, the value determines
  1569.                         the level of compatiblity.  If not specified, or
  1570.                         specified  with  an  explicit value of zero, and
  1571.                         lzcomp is running on  Vax/VMS  version  4  under
  1572.                         VaxC  and  the  input  file is a disk or magtape
  1573.                                                                           Page 2
  1574.         lzcomp  File Compression
  1575.  
  1576.  
  1577.                         file  (block-oriented),  a  VMS-private   output
  1578.                         format  is  used  which is incompatible with the
  1579.                         Unix compress utility, but which  preserves  VMS
  1580.                         file  attributes.   -X may take on the following
  1581.                         values:
  1582.  
  1583.                          0  Choose VMS private format.  See restrictions
  1584.                             below.
  1585.                          1  Compatible with Unix compress  version  3.0:
  1586.                             this is the default if -x is given without a
  1587.                             value.
  1588.                          2  As above, but supress "block compression"
  1589.                          3  Supress block compression and do not  output
  1590.                             a   compress  header  block.   This  is  for
  1591.                             compatiblity with a quite early  version  of
  1592.                             Unix       compress       (and      requires
  1593.                             conditional-compilation to use).
  1594.  
  1595.                         Note that the  -B  (binary)  option  is  ignored
  1596.                         unless the input file is "record-oriented", such
  1597.                         as a terminal or mailbox.
  1598.  
  1599.                 The  other  two  arguments  are  the  input  and  output
  1600.                 filenames   respectively.    Redirection  is  supported,
  1601.                 however, the output must be a disk/tape file.
  1602.  
  1603.                 The file format is almost identical to the current  Unix
  1604.                 implementation  of  compress  (V4.0).   Files written by
  1605.                 Unix compress  should  be  readable  by  lzdcmp.   Files
  1606.                 written by lzcomp in export (-x) format will be readable
  1607.                 by Unix compress (except that lzcomp outputs two "clear"
  1608.                 codes  to  mark  EOF.   A  patch  to  Unix  compress  is
  1609.                 available.)
  1610.  
  1611.         VMS RESTRICTIONS:
  1612.  
  1613.                 VMS Private mode stores the true name and attributes  of
  1614.                 the  input  file  into  the  compressed  file and lzdcmp
  1615.                 restores the attributes  (and  filename  if  requested).
  1616.                 The  following  restrictions apply -- they may be lifted
  1617.                 in the future as they are primarily due to the  author's
  1618.                 lack of understanding of the intricacies of of VMS I/O:
  1619.  
  1620.                     All files must be stored on disk.
  1621.                     The lzcomp output file must be specified directly.
  1622.  
  1623.                 Also, for all usage on VMS, the compressed file must  be
  1624.                 written to, and read from disk.
  1625.  
  1626.         LZW COMPRESSION ALGORITHM:
  1627.  
  1628.                 This section is abstracted from  Terry  Welch's  article
  1629.                 referenced   below.    The  algorithm  builds  a  string
  1630.                 translation table that maps substrings in the input into
  1631.                                                                           Page 3
  1632.         lzcomp  File Compression
  1633.  
  1634.  
  1635.                 fixed-length  codes.   The  compress  algorithm  may  be
  1636.                 described as follows:
  1637.  
  1638.                   1. Initialize table to contain single-character
  1639.                      strings.
  1640.                   2. Read the first character.  Set <w> (the prefix
  1641.                      string) to that character.
  1642.                   3. (step): Read next input character, K.
  1643.                   4. If at end of file, output code(<w>); exit.
  1644.                   5. If <w>K is in the string table:
  1645.                         Set <w> to <w>K; goto step 3.
  1646.                   6. Else <w>K is not in the string table.
  1647.                         Output code(<w>);
  1648.                         Put <w>K into the string table;
  1649.                         Set <w> to K; Goto step 3.
  1650.  
  1651.                 "At each execution of the basic step an acceptable input
  1652.                 string <w> has been parsed off.  The next character K is
  1653.                 read and the extended string <w>K is tested to see if it
  1654.                 exists  in  the  string table.  If it is there, then the
  1655.                 extended string becomes the parsed string  <w>  and  the
  1656.                 step  is  repeated.  If <w>K is not in the string table,
  1657.                 then it is entered, the code for the successfully parsed
  1658.                 string <w> is put out as comprssed data, the character K
  1659.                 becomes the beginning of the next string, and  the  step
  1660.                 is repeated."
  1661.  
  1662.                 The decompression  algorithm  translates  each  received
  1663.                 code   into  a  prefix  string  and  extension  [suffix]
  1664.                 character.  The extension  character  is  stored  (in  a
  1665.                 push-down stack), and the prefix translated again, until
  1666.                 the  prefix  is  a  single  character,  which  completes
  1667.                 decompression  of  this  code.   The entire code is then
  1668.                 output by popping the stack.
  1669.  
  1670.                 "An update to the string table is  made  for  each  code
  1671.                 received  (except  the first one).  When a code has been
  1672.                 translated, its final character is used as the extension
  1673.                 character,  combined with the prior string, to add a new
  1674.                 string to the string table.  This new string is assigned
  1675.                 a  unique  code  value,  which is the same code that the
  1676.                 compressor assigned to that string.  In  this  way,  the
  1677.                 decompressor  incrementally reconstructs the same string
  1678.                 table that the decompressor used....  Unfortunately  ...
  1679.                 [the algorithm] does not work for an abnormal case.
  1680.  
  1681.                 The abnormal case occurs  whenever  an  input  character
  1682.                 string  contains  the  sequence  K<w>K<w>K,  where  K<w>
  1683.                 already appears in the compressor string table."
  1684.  
  1685.                 The decompression algorithm,  augmented  to  handle  the
  1686.                 abnormal case, is as follows:
  1687.  
  1688.                   1. Read first input code;
  1689.                                                                           Page 4
  1690.         lzcomp  File Compression
  1691.  
  1692.  
  1693.                      Store in CODE and OLDcode;
  1694.                      With CODE = code(K), output(K);  FINchar = K;
  1695.                   2. Read next code to CODE; INcode = CODE;
  1696.                      If at end of file, exit;
  1697.                   3. If CODE not in string table (special case) then
  1698.                         Output(FINchar);
  1699.                         CODE = OLDcode;
  1700.                         INcode = code(OLDcode, FINchar);
  1701.  
  1702.                   4. If CODE == code(<w>K) then
  1703.                         Push K onto the stack;
  1704.                         CODE == code(<w>);
  1705.                         Goto 4.
  1706.  
  1707.                   5. If CODE == code(K) then
  1708.                         Output K;
  1709.                         FINchar = K;
  1710.  
  1711.                   6. While stack not empty
  1712.                         Output top of stack;
  1713.                         Pop stack;
  1714.  
  1715.                   7. Put OLDcode,K into the string table.
  1716.                      OLDcode = INcode;
  1717.                      Goto 2.
  1718.  
  1719.                 The  algorithm  as  implemented  here   introduces   two
  1720.                 additional complications.
  1721.  
  1722.                 The actual codes are transmitted using a variable-length
  1723.                 encoding.  The lowest-level routines increase the number
  1724.                 of bits in the code when the largest  possible  code  is
  1725.                 transmitted.
  1726.  
  1727.                 Periodically, the algorithm checks that  compression  is
  1728.                 still increasing.  If the ratio of input bytes to output
  1729.                 bytes decreases, the entire process is reset.  This  can
  1730.                 happen if the characteristics of the input file change.
  1731.  
  1732.         VMS PRIVATE FILE STRUCTURE:
  1733.  
  1734.                 In VMS Private mode, the compressed data file contains a
  1735.                 variable-length  (but  compressed)  file header with the
  1736.                 file "attributes" needed  by  the  operating  system  to
  1737.                 construct  the  file.   This  allows  the  decompression
  1738.                 program to recreate the file  in  its  original  format,
  1739.                 which is essential if ISAM databases are compressed.
  1740.  
  1741.                 The overall file format is as follows:
  1742.  
  1743.                 LZ_SOH  "start of  header"  signal  (this  value  cannot
  1744.                         appear in user data).
  1745.  
  1746.                         A  variable-length  data  record  (maximum   256
  1747.                                                                           Page 5
  1748.         lzcomp  File Compression
  1749.  
  1750.  
  1751.                         bytes)  containing  the header name, followed by
  1752.                         whitespace,    followed    by    header-specific
  1753.                         information.  In this case, the name record will
  1754.                         contain the string "vms$attributes" followed  by
  1755.                         the number of bytes in the attribute data block.
  1756.                         (I assume that the name record will consist of a
  1757.                         facility  name,  such  as  "vms",  followed by a
  1758.                         dollar  sign,  followed  by  a   facility-unique
  1759.                         word.)
  1760.  
  1761.                 LZ_EOR  Signals "end of record".
  1762.  
  1763.                         This is followed by a VMS file attributes record
  1764.                         (generated by a VMS system library
  1765.                               routine).
  1766.  
  1767.                 LZ_ETX  Signals "end of segment".
  1768.  
  1769.                 ST_STX  Signals "start of text"  (i.e.,  start  of  data
  1770.                         file).
  1771.  
  1772.                         This is followed by the user data file.
  1773.  
  1774.                 LZ_ETX  Signals "end of segment"
  1775.  
  1776.                 LZ_ETX  Two in a row signals "end of file".
  1777.  
  1778.                 Note that this format can easily be extended to  include
  1779.                 trailer  records (with file counts and checksums) and/or
  1780.                 multiple data files in one compressed file.
  1781.  
  1782.                 Note also that the LZ_CLEAR code may appear  in  headers
  1783.                 or  data  files  to  cause  the decompression program to
  1784.                 "readapt" to the  characteristics  of  the  input  data.
  1785.                 LZ_STX  and  LZ_SOH  reset  the  compression  algorithm.
  1786.                 LZ_EOR does not.
  1787.  
  1788.         AUTHORS:
  1789.  
  1790.                 The algorithm is from "A Technique for High  Performance
  1791.                 Data  Compression."  Terry A.  Welch.  IEEE Computer Vol
  1792.                 17, No.  6 (June 1984), pp 8-19.
  1793.  
  1794.                 This revision is by Martin Minow.
  1795.  
  1796.                 Unix Compress authors are as follows:
  1797.  
  1798.                 Spencer W. Thomas
  1799.                        (decvax!harpo!utah-cs!utah-gr!thomas)
  1800.                 Jim McKie               (decvax!mcvax!jim)
  1801.                 Steve Davies            (decvax!vax135!petsd!peora!srd)
  1802.                 Ken Turkowski           (decvax!decwrl!turtlevax!ken)
  1803.                 James A. Woods          (decvax!ihnp4!ames!jaw)
  1804.                 Joe Orost               (decvax!vax135!petsd!joe)
  1805.  
  1806. -h- lzdcmp.mem    Wed Jul 24 11:49:39 1985    USER$A:[MINOW.LZ]LZDCMP.MEM;2
  1807.  
  1808.  
  1809.  
  1810.  
  1811.            ____ _____________        1  File Decompression
  1812.  
  1813.  
  1814.  
  1815.                                    **********
  1816.                                    * lzdcmp *
  1817.                                    **********
  1818.  
  1819.  
  1820.  
  1821.         NAME:   lzdcmp -- File Decompression
  1822.  
  1823.         SYNOPSIS:
  1824.  
  1825.                 lzdcmp [-options] [infile [outfile]]
  1826.  
  1827.         DESCRIPTION:
  1828.  
  1829.                 lzdcmp decompresses files  compressed  by  lzcomp.   The
  1830.                 documentation   for  lzcomp  describes  the  process  in
  1831.                 greater detail.
  1832.  
  1833.                 Options may be given in either case.
  1834.  
  1835.                 -B      Output file is "binary", not text.  (Ignored  in
  1836.                         VMS private mode.)
  1837.  
  1838.                 -X 3    To read files compressed by an old Unix  version
  1839.                         that doesn't generate header records.
  1840.  
  1841.                 -V val  Verbose (print  status  messages  and  debugging
  1842.                         information).   The  value selects the amount of
  1843.                         verbosity.
  1844.  
  1845.                 AUTHOR:
  1846.  
  1847.                         This version by Martin Minow.   See  lzcomp  for
  1848.                         more details.
  1849.  
  1850.