home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / UTILS / F / LH-CPM12.ZIP / LHVW120.C < prev    next >
Text File  |  1990-11-24  |  31KB  |  920 lines

  1. /*****************************************************************************
  2.  *      v. 1.20 adds a "#define CPM" which, if defined, recognizes CP/M 
  3.  * drive/user areas (DU:FILENAME.EXT), with both drive and user-area
  4.  * arguments optional. Also adds compile-time selectable "int maxusr" and 
  5.  * "int maxdrv" values to specify maximum drive/user areas for protection.
  6.  * The maximum length of "char arc_name[]" was increased to accommodate
  7.  * drive/user areas and a test added to check validity of lengths of this
  8.  * string and "char filespec[]". V. 1.11 omitted this potential crash-
  9.  * inducing check and would actually accept and execute a user request which
  10.  * included a drive even when such overran the arc_name buffer. Lastly, a
  11.  * check has been added to disallow display of .EXE, .COM, .OBJ and ambiguous
  12.  * filenames if viewonly set to true.
  13.  *     For reasons noted in the update file, these modest changes were a real
  14.  * struggle and (given those reasons) polish which could readily be made to 
  15.  * changes are left to someone in a better position to do so. In the interim,
  16.  * the program is significantly more functional tool, especially for RCP/Ms 
  17.  * offering MS-DOS archives.
  18.  *     Thanks to Bill Mattson for energies far beyond the original request to
  19.  * "just" compile and link the new code, again as noted in the update file.
  20.  *     Like predecessor contributors to this code, the latest changes are 
  21.  * released into the public domain "as is," with a disclaimer of all 
  22.  * warranties, expressed or implied. While I can't guarantee to take any 
  23.  * particular action in response to bug reports, suggestions for improvements,
  24.  * etc., such input is welcome and encouraged.
  25.  *
  26.  *     -- J.W. Olsen, 4/5/90
  27.  *       Sysop, The Advocate RCP/M
  28.  *        312.939.4411 (24 hrs., 300/1200/2400, 8/n/1)
  29.  *       Advocate Enterprises, Ltd.
  30.  *       117 W. Harrison Building
  31.  *         6th Floor Mail Stop #A-408
  32.  *       Chicago, IL 60605
  33.  *
  34.  */
  35.  
  36.  /*
  37.  * LHRD.C from LZHUFDEC.C for listing and extracting members of LHARC
  38.  *  - (.LZH) files, v1.0  S. Greenberg 4/16/89.  v1.11 source released 5/28/89
  39.  * LZHUFDEC.C from LZHUF10.C for CPM, Eugene Nolan 4/13/89
  40.  * LZHUF.C English version 1.0 Based on Japanese version 29-NOV-1988
  41.  * LZSS coded by Haruhiko OKUMURA
  42.  * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
  43.  * Edited and translated to English by Kenji RIKITAKE
  44.  */
  45.  
  46. /* To create a "view only" version (displays to console; will not write
  47.  *  to disk)  un-comment the "#define viewonly" below.
  48.  *
  49.  * To create an MS-DOS version, un-comment "#define MSC" and "#pragma pack(1)"
  50.  *  The resulting file should compile without error with Micrsoft 'C' 5.0.
  51.  *  If MSC is not defined, the program compiles without error with Aztec 'C'
  52.  *  v1.06d, to create a CP/M version. (This is how the .COM file included
  53.  *  was created). ==> Please note the included COM file is CP/M, not MS-DOS !!
  54.  *
  55.  * Any responsible updates invited, I make no claims to or restrictions on the
  56.  *  the sections of code I have written. (I also make no guarantees this code
  57.  *  will perform a specific function and am not responsible for incidental or
  58.  *  consequential damages arising from its use. This code is supplied 'as is')
  59.  *
  60.  *   Certain restrictions may apply to sections of code belonging to other
  61.  *    authors listed above. Please consult them if if any questions arise.
  62.  *
  63.  *                                                - S. Greenberg  28 May 1989
  64.  *****************************************************************************/
  65.  
  66.                                 /* comment out if file extraction desired */
  67. #define viewonly
  68.                                 /* not for user alteration */
  69. #include "stdio.h"
  70. #include "ctype.h"
  71. #define EXIT_OK 0
  72. #define EXIT_FAILED -1
  73.                 /* if CPM is defined, CP/M drive/user areas
  74.                    will be recognized. if so, MSC & its pragma
  75.                      pack should be commented out */
  76. #define CPM
  77.                                        /* this line not for user alteration */
  78. #ifdef CPM
  79.                          /* set these if CPM defined */
  80. int         maxusr    =    8;         /* maximum CP/M user area */
  81. char        maxdrv    =    'C';             /* maximum CP/M drive */
  82. #endif
  83.                          /* if defined, code is to be compiled
  84.                                   with Microsoft 'C' for MS/PC-DOS */
  85. /* #define MSC
  86. * #pragma pack(1)
  87. */
  88.  
  89. /* END OF USER-ALTERABLE EQUATES ********************************************/
  90.  
  91. #ifdef    MSC
  92. #define read_access         "rb"     /* to open input file (binary) with fopen */
  93. #define write_access         "wb"    /* likewise output file */
  94. #define str_chr          strchr  /* find occurrence of substring in a string */
  95. #define mem_move         memmove /* memory to memory move */
  96.  
  97. #else
  98. #define read_access         "r"     /* these all correspond to the above */
  99. #define write_access         "w"
  100. #define str_chr          index
  101. #define mem_move         movmem
  102.                                        /* apparently AZTEC C has no ststr()
  103.                                           --this protytpes my replacement fxn
  104.                                           found at the end of this file */
  105. #endif
  106.  
  107. FILE        *infile,
  108.             *outfile;
  109. long int    codesize,
  110.             printcount;
  111. int            linecount;
  112. /*****************************************************************************/
  113. /* This stuff is used to do file extent comparisons in the view-only mode,   */
  114. /* to prevent attempts to display non-printable files. Such attempts will    */
  115. /* surely drive your trusty computer berserk, and we can't have that. See    */
  116. /* also the appropriate code down around line #860 or so for more........    */
  117. /*                                                                           */
  118. int             filelen;           /* used to get the length of filespec*/
  119. char            extent[4];         /* used to hold  concatenated extent */
  120. char            exe[] = {"EXE"};   /* used to hold "EXE" for comparison */
  121. char            com[] = {"COM"};   /* used to hold "COM" for comparison */
  122. char            obj[] = {"OBJ"};   /* used to hold "OBJ" for comparison */ 
  123. char            amb[] = {"*.*"};   /* used to hold "*.*" for comparison */
  124. char            astrsk[] = {"*"};  /* used to hold "*" for comparison   */
  125. char            questn[] = {"?"};  /* used to hold "?" for comparison   */
  126. int             exetst;            /* used to test for match with "EXE" */
  127. int             comtst;            /* used to test for match with "COM" */ 
  128. int             objtst;            /* used to test for match with "OBJ" */
  129. int             ambtst;            /* used to test for match with "*.*" */
  130. int             letter = 1;        /* flag for presence of "?" or "*"   */ 
  131. /*                                                                           */
  132. /*****************************************************************************/
  133. char        hdrlen;
  134. char        outfname[13];
  135. char        comp_type[6];
  136. int            crc;
  137. long int    orig_tot,
  138.             comp_tot;
  139. int            num_files = 0;
  140.  
  141. struct archdr {
  142.     char        hdr_len;        /* header length in bytes */
  143.     char        checksum;        /* checksum of header only */
  144.     char        stowage[5];        /* compression method- "-lh1-" or "-lh2-" */
  145.     long int    comp_size;        /* size of compressed file in bytes */
  146.     long int    orig_size;        /* size of the original file in bytes */
  147.     int            file_time;        /* file's last mod time, MS-DOS format */
  148.     int            file_date;        /* date, likewise */
  149.     int            attrib;            /* file's attributes, bit mapped */
  150.     char        fn_len;            /* #of characters in filename */
  151. }        archdr;                    /* (filename follows, variable length field) */
  152.  
  153. #define LINEFEED 0x0a            /* ascii linefeed character */
  154.  
  155. /* LZSS Parameters */
  156. #define N 4096                    /* Size of string buffer */
  157. #define F 60                    /* Size of look-ahead buffer */
  158. #define THRESHOLD 2                
  159. #define NIL N                    /* End of tree's node */
  160.  
  161. unsigned char    text_buf[N + F - 1];
  162.  
  163. /* Huffman coding parameters */
  164. #define N_CHAR (256 - THRESHOLD + F)
  165.  
  166. /* character code (= 0..N_CHAR-1) */
  167. #define T (N_CHAR * 2 - 1)            /* Size of table */
  168. #define R (T - 1)                /* root position */
  169. #define MAX_FREQ 0x8000
  170.  
  171. /* update when cumulative frequency reaches to this value */
  172. typedef unsigned char uchar;
  173.  
  174. /*
  175.  * Tables for encoding/decoding upper 6 bits of sliding dictionary pointer
  176.  */
  177.  
  178. /* decoder table */
  179. uchar        d_code[256] = {
  180.                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  181.                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  182.                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  183.                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  184.                  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  185.                  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  186.                  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
  187.                  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
  188.                  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  189.                  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  190.                  0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  191.                  0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  192.                  0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  193.                  0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  194.                  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  195.                  0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
  196.                  0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
  197.                  0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
  198.                  0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
  199.                  0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
  200.                  0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
  201.                  0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
  202.                  0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
  203.                  0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
  204.                  0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
  205.                  0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
  206.                  0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
  207.                  0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
  208.                  0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
  209.                  0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
  210.                  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  211.                  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
  212. };
  213.  
  214. uchar        d_len[256] = {
  215.                   0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  216.                   0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  217.                   0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  218.                   0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
  219.                   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  220.                   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  221.                   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  222.                   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  223.                   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  224.                   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  225.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  226.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  227.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  228.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  229.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  230.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  231.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  232.                   0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
  233.                   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  234.                   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  235.                   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  236.                   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  237.                   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  238.                   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
  239.                   0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  240.                   0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  241.                   0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  242.                   0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  243.                   0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  244.                   0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  245.                   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  246.                   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  247. };
  248.  
  249. unsigned    freq[T + 1];            /* cumulative freq table */
  250.  
  251. /*
  252.  * pointing parent nodes. area [T..(T + N_CHAR - 1)] are pointers for leaves
  253.  */
  254.  
  255. int        prnt[T + N_CHAR];
  256.  
  257. /* pointing children nodes (son[], son[] + 1) */
  258. int        son[T];
  259. unsigned    getbuf = 0;
  260. uchar        getlen = 0;
  261.  
  262. /* Display specified message and abort the program */
  263. void
  264. Error0(message)
  265.     char           *message;
  266. {
  267.     printf(message);
  268.     exit(EXIT_FAILED);
  269. }
  270.  
  271. /* Like above, used when message has an argument */
  272. void
  273. Error1(message, string)
  274.     char           *message;
  275.     char           *string;
  276. {
  277.     printf(message, string);
  278.     exit(EXIT_FAILED);
  279. }
  280.  
  281. /* Output one character to the output file (or console in 'view' version) */
  282. void
  283. Output(ch)
  284.     char        ch;
  285. {
  286. #ifndef viewonly
  287.     putc(ch, outfile);                        /* simple enough */
  288.  
  289. #else
  290.     if (ch != 0x1A) {                        /* Don't type the EOF */
  291.         putc((ch & 0x7F), stdout);            /* strip any hi-bits */
  292.         if (ch == LINEFEED) {                /* count linefeeds */
  293.             if (linecount++ == 22) {        /* 22 lines yet? */
  294.                 linecount = 0;                /* reset line count */
  295.                 printf("[More]");            /* wait for <rtn> */
  296.                 if ((getc(stdin)) == 0x0B)    /* ^K aborts [doesn't work!] */
  297.                     Error0("++ Abort ++");    /* supposed to abort! */
  298.             }
  299.         }
  300.     }
  301. #endif
  302. }
  303.  
  304. /* get one bit */
  305. int
  306. GetBit()
  307. {
  308.     static int    i;
  309.  
  310.     while (getlen <= 8) {
  311.         if ((i = getc(infile)) < 0)
  312.             i = 0;
  313.         getbuf |= i << (8 - getlen);
  314.         getlen += 8;
  315.     }
  316.     i = getbuf;
  317.     getbuf <<= 1;
  318.     getlen--;
  319.     return (i < 0);
  320. }
  321.  
  322. /* get a byte */
  323. int
  324. GetByte()
  325. {
  326.     static unsigned i;
  327.  
  328.     while (getlen <= 8) {
  329.         if ((i = getc(infile)) < 0)
  330.             i = 0;
  331.         getbuf |= i << (8 - getlen);
  332.         getlen += 8;
  333.     }
  334.     i = getbuf;
  335.     getbuf <<= 8;
  336.     getlen -= 8;
  337.     return i >> 8;
  338. }
  339.  
  340. /* initialize freq tree */
  341. void
  342. StartHuff()
  343. {
  344.     static int    i,
  345.             j;
  346.  
  347.     for (i = 0; i < N_CHAR; i++) {
  348.         freq[i] = 1;
  349.         son[i] = i + T;
  350.         prnt[i + T] = i;
  351.     }
  352.     i = 0;
  353.     j = N_CHAR;
  354.     while (j <= R) {
  355.         freq[j] = freq[i] + freq[i + 1];
  356.         son[j] = i;
  357.         prnt[i] = prnt[i + 1] = j;
  358.         i += 2;
  359.         j++;
  360.     }
  361.     freq[T] = 0xffff;
  362.     prnt[R] = 0;
  363. }
  364.  
  365. /* reconstruct freq tree */
  366. void
  367. reconst()
  368. {
  369.     static int    i,
  370.             j,
  371.             k;
  372.     static unsigned f,
  373.             l;
  374.  
  375.     /* halven cumulative freq for leaf nodes */
  376.     j = 0;
  377.     for (i = 0; i < T; i++) {
  378.         if (son[i] >= T) {
  379.             freq[j] = (freq[i] + 1) / 2;
  380.             son[j] = son[i];
  381.             j++;
  382.         }
  383.     }
  384.  
  385.     /* make a tree : first, connect children nodes */
  386.     for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
  387.         k = i + 1;
  388.         f = freq[j] = freq[i] + freq[k];
  389.         for (k = j - 1; f < freq[k]; k--);
  390.         k++;
  391.         l = (j - k) * 2;
  392.  
  393.         mem_move(&freq[k], &freq[k + 1], l);
  394.         freq[k] = f;
  395.         mem_move(&son[k], &son[k + 1], l);
  396.  
  397.         son[k] = i;
  398.     }
  399.  
  400.     /* connect parent nodes */
  401.     for (i = 0; i < T; i++) {
  402.         if ((k = son[i]) >= T) {
  403.             prnt[k] = i;
  404.         } else {
  405.             prnt[k] = prnt[k + 1] = i;
  406.         }
  407.     }
  408. }
  409.  
  410. /* update freq tree */
  411. void
  412.     update(c) int    c;
  413.  
  414. {
  415.     static int    i,
  416.             j,
  417.             k,
  418.             l;
  419.  
  420.     if (freq[R] == MAX_FREQ) {
  421.         reconst();
  422.     }
  423.     c = prnt[c + T];
  424.     do {
  425.         k = ++freq[c];
  426.  
  427.         /* swap nodes to keep the tree freq-ordered */
  428.         if (k > freq[l = c + 1]) {
  429.             while (k > freq[++l]);
  430.             l--;
  431.             freq[c] = freq[l];
  432.             freq[l] = k;
  433.             i = son[c];
  434.             prnt[i] = l;
  435.             if (i < T)
  436.                 prnt[i + 1] = l;
  437.             j = son[l];
  438.             son[l] = i;
  439.             prnt[j] = c;
  440.             if (j < T)
  441.                 prnt[j + 1] = c;
  442.             son[c] = j;
  443.             c = l;
  444.         }
  445.     } while ((c = prnt[c]) != 0);        /* do it until reaching the
  446.                          * root */
  447. }
  448.  
  449. unsigned    code,
  450.         len;
  451. int
  452. DecChar()
  453. {
  454.     static unsigned c;
  455.  
  456.     c = son[R];
  457.  
  458.     /*
  459.      * start searching tree from the root to leaves. choose node #(son[])
  460.      * if input bit == 0 else choose #(son[]+1) (input bit == 1)
  461.      */
  462.     while (c < T) {
  463.         c += GetBit();
  464.         c = son[c];
  465.     }
  466.     c -= T;
  467.     update(c);
  468.     return c;
  469. }
  470.  
  471. int
  472. DecPosition()
  473. {
  474.     static unsigned i,
  475.             j,
  476.             c;
  477.  
  478.     /* decode upper 6 bits from given table */
  479.     i = GetByte();
  480.     c = (unsigned) d_code[i] << 6;
  481.     j = d_len[i];
  482.  
  483.     /* input lower 6 bits directly */
  484.     j -= 2;
  485.     while (j--) {
  486.         i = (i << 1) + GetBit();
  487.     }
  488.     return c | i & 0x3f;
  489. }
  490.  
  491. /* Decoding/Uncompressing */
  492. void
  493. Decode()
  494. {
  495.     static int    i,
  496.             j,
  497.             k,
  498.             r,
  499.             c;
  500.     static long int count;
  501.  
  502.     if (archdr.orig_size == 0)
  503.         return;
  504.     StartHuff();
  505.     for (i = 0; i < N - F; i++)
  506.         text_buf[i] = ' ';
  507.     r = N - F;
  508.     for (count = 0; count < archdr.orig_size;) {
  509.         c = DecChar();
  510.         if (c < 256) {
  511.             Output(c);
  512.             text_buf[r++] = c;
  513.             r &= (N - 1);
  514.             count++;
  515.         } else {
  516.             i = (r - DecPosition() - 1) & (N - 1);
  517.             j = c - 255 + THRESHOLD;
  518.             for (k = 0; k < j; k++) {
  519.                 c = text_buf[(i + k) & (N - 1)];
  520.                 Output(c);
  521.                 text_buf[r++] = c;
  522.                 r &= (N - 1);
  523.                 count++;
  524.             }
  525.         }
  526. #ifndef viewonly
  527.         if (count > printcount) {
  528.             printf("%4dk\r", count / 1024);        /* display progress each 1k  */
  529.             printcount += 1024;
  530.         }
  531. #endif
  532.     }
  533.     printf("      \r");                    /* clear last 'progress display' */
  534.     fseek(infile, -1L, 1);                /* back up one byte */
  535. }
  536.  
  537. /* list a member file */
  538. void
  539. Listent()
  540. {
  541.  
  542.     int        yr,
  543.             mo,
  544.             dy;
  545.     int        hh,
  546.             mm,
  547.             ss;
  548.     int        ratio;
  549.  
  550.     printf("  %-14s%8ld  %8ld  ", outfname, archdr.orig_size, archdr.comp_size);
  551.  
  552.     /*
  553.      *  Compute compression ratio, in tenths of a percent.
  554.      *  Display percent & tenths later using divide and modulus separately.
  555.      *  The roundabout technique avoids calling in the floating point stuff.
  556.      */
  557.     
  558.     ratio = (1000 * archdr.comp_size) / archdr.orig_size;
  559.  
  560.     yr = (archdr.file_date >> 9) & 0x7f;    /* extract date from bit mapped fields */
  561.     mo = (archdr.file_date >> 5) & 0x0f;
  562.     dy = archdr.file_date & 0x1f;
  563.  
  564.     hh = (archdr.file_time >> 11) & 0x1f;    /* likewise the time */
  565.     mm = (archdr.file_time >> 5) & 0x3f;
  566.     ss = (archdr.file_time & 0x1f) * 2;
  567.  
  568.     printf("%3d.%1d%%", ratio / 10, ratio % 10);    /* percent & tenths */
  569.     printf("  %2d-%02d-%02d", (yr + 80) % 100, mo, dy);        /* date */
  570.     printf("  %2d:%02d:%02d  ", hh, mm, ss);                /* time */
  571.     printf("%5s  %04x\n", comp_type, crc);            /* comp. method & CRC */
  572. }
  573.  
  574. /* extract an uncompressed file (flagged "-lh0-") */
  575. void
  576. Copy()
  577. {
  578.     static long int count;
  579.  
  580.     for (count = 0; count < archdr.orig_size; count++) {
  581.         Output(getc(infile));                    /* easy enough */
  582. #ifndef viewonly
  583.         if (count > printcount) {
  584.             printf("%4dk\r", count / 1024);        /* progress reports */
  585.             printcount += 1024;
  586.         }
  587. #endif
  588.     }
  589.     printf("      \r");
  590. }
  591.  
  592. /*
  593.  * match() compares a pattern with a string.  Wildcards accepted in the
  594.  * pattern are:  "*" for zero or more arbitrary characters;  "?" for any one
  595.  * characters.    Unlike the MS-DOS wildcard match, "*" is correctly handled
  596.  * even if it isn't at the end of the pattern. ".' is not special.
  597.  *
  598.  * Originally written by Jeff Damens of Columbia University Center for Computing
  599.  * Activities.    Taken from the source code for C-Kermit version 4C.
  600.  */
  601.  
  602. /* Note: I left this routine intact, but did add a "." character to either
  603.  * a filename or match pattern that originally had a blank extension (done
  604.  * elsewhere, before this routine is called). This provides a minimum
  605.  * expected compatibility with MS-DOS conventions, eg that "*.*" refers to
  606.  * all files, not all files except those with blank extensions. - SGG
  607.  */
  608.  
  609. int
  610. match(string, pattern)
  611.     register char    *string,
  612.                     *pattern;
  613. {
  614.     char            *psave,
  615.                     *ssave;            /* back up pointers for failure */
  616.  
  617.     psave = ssave = ((char *) 0);
  618.     while (1) {
  619.         for (; *pattern == *string; pattern++, string++)    /* skip first */
  620.             if (*string == '\0')
  621.                 return (1);    /* end of strings, succeed */
  622.         if (*string != '\0' && *pattern == '?') {
  623.             pattern++;        /* '?', let it match */
  624.             string++;
  625.         } else if (*pattern == '*') {    /* '*' ... */
  626.             psave = ++pattern;    /* remember where we saw it */
  627.             ssave = string;     /* let it match 0 chars */
  628.         } else if (ssave != ((char *) 0) && *ssave != '\0') {    /* if not at end  */
  629.             /* ...have seen a star */
  630.             string = ++ssave;    /* skip 1 char from string */
  631.             pattern = psave;    /* and back up pattern */
  632.         } else
  633.             return (0);        /* otherwise just fail */
  634.     }
  635. }
  636.  
  637. /* Open an output file with a specified name. If a file with that name
  638.  * already exists, prompt the user before overwriting it.
  639.  */
  640.  
  641. FILE
  642. * Openfile(fn)
  643.     char           *fn;
  644. {
  645.     FILE           *handle;
  646.  
  647. #ifndef viewonly
  648.  
  649. /* there is no doubt a more straightforward way to do this! */
  650. #ifdef    MSC
  651.     if (access(fn, 0) == 0) {                    /* does file exist? */
  652.         printf(" File exists- overwrite?");        /* yes, prompt */
  653.         if (toupper(getc(stdin)) == 'Y') {        /* yes? */
  654.             if ((handle = fopen(fn, write_access)) == NULL)    /* open if poss */
  655.                 Error1("Can't open: %s\n", outfname);        /* else fatal err */
  656.         } else
  657.             handle = 0;                            /* if he said no, rtn null */
  658.     } else {
  659.         if ((handle = fopen(fn, write_access)) == NULL)    /* doesn't exist...*/
  660.             Error1("Can't open: %s\n", outfname);        /* ...open if poss */
  661.     }
  662.  
  663. /* do it without the benifit of the 'access' function... */
  664. #else
  665.     if ((handle = fopen(fn, "x")) == NULL) {  /* open in no-overwrite mode */
  666.         if ((handle = fopen(fn, read_access)) != NULL) { /* fail, try read */
  667.             close(handle);    /* that worked, must have failed due to existance */
  668.             handle = 0;        /* close, didn't really want to read it anyway! */
  669.             printf(" File exists- overwrite?");    /* ask */
  670.             if (toupper(getc(stdin)) == 'Y') {    /* well? */
  671.                 if ((handle = fopen(fn, write_access)) == NULL)    /* write over! */
  672.                     Error1("Can't open: %s\n", outfname);    /* random failure */
  673.             }
  674.         }
  675.     }
  676. #endif
  677.  
  678. #else
  679.     handle = stdout;
  680. #endif
  681.  
  682.     printf("\n");
  683.     return (handle);
  684. }
  685.  
  686. int
  687.     main(argc, argv) int argc;
  688.     char           *argv[];
  689.  
  690. {
  691.     char    arc_name[17];
  692.     char    filespec[13];
  693.     int        ksize;
  694.     int        rat_tot;
  695.         int        i;
  696.  
  697. #ifdef CPM
  698.     char     *p;
  699.     char     *q;
  700.     char    du[5];
  701. #endif
  702.     
  703.     comp_type[5] = 0;
  704.     comp_tot = 0;
  705.     orig_tot = 0;
  706.  
  707. #ifndef viewonly
  708.     printf("\nLHRD  v. 1.20  (3/10/90) JWO\n\n");
  709. #else
  710.     printf("\nLHVW  v. 1.20  (3/10/90) JWO\n\n");
  711. #endif
  712.  
  713.     if ((argc != 3) && (argc != 2)) {
  714. #ifndef viewonly
  715.         printf("Usage: LHRD  <filename>  [<afn>]\n\n");
  716.         printf("where <filename> is an LHARC file (default extension .LZH or .LHC).\n");
  717.         printf("Members matching <afn> are extracted to the current drive.\n");
  718.         printf("If <afn> is absent, member names are displayed.\n");
  719.         return EXIT_FAILED;
  720. #else
  721.         printf("Usage: LHVW  <filename>  [<afn>]\n\n");
  722.         printf("where <filename> is an LHARC file (default extension .LZH or .LHC).\n");
  723.         printf("Contents of member(s) matching <afn> will be displayed to the console.\n");
  724.         printf("If <afn> is absent, member names are displayed.\n");
  725.         return EXIT_FAILED;
  726. #endif
  727.  
  728.          }
  729.  
  730.          i=0;                                    /* kludge a CP/M strupr() */
  731.          while(argv[1][i]) {                     /* need caps for maxdrv check */
  732.                    arc_name[i]=toupper(argv[1][i]);
  733.                    ++i;
  734.                    }
  735.          arc_name[i]='\0';
  736.     if (argc > 2) {
  737.            strcpy(filespec, argv[2]);
  738.                       }
  739. #ifdef    MSC
  740.     strupr(arc_name);
  741.     if (argc > 2)
  742.         strupr(filespec);
  743. #endif
  744.  
  745. #ifdef CPM
  746.       /* Check for drive/user area in arc_name in form DU:FILENAME (both drive
  747.        *  and user area are optional). Strip out any user area and, if valid,
  748.        *  use BDOS call to set it for read/write. Ensure arc_name contains only
  749.        *  filename and optional drive w/out user area when done     */
  750.       p=str_chr(arc_name,':');            /* colon in arc_name? */
  751.     if (p) {            /* if so, parse it, else do nada */
  752.         if ((p-arc_name)>3) {            /* DU: too long? */
  753.             *(p+1)='\0';    /* yep, so report it & bad entry */
  754.             Error1("Invalid DU: %s",arc_name);
  755.             }
  756.         for (i=0;i<=(p-arc_name);i++) du[i]=arc_name[i];    /* no, so parse */
  757.         du[i-1]='\0';
  758.         if (isalpha(arc_name[0]))         /* put arc_name in form [D:]FILENAME */
  759.             q=arc_name+1;
  760.         else {
  761.             q=arc_name;
  762.             p++;
  763.             }
  764.         strcpy(q,p);
  765.         if(isalpha(du[0])) {               /* does DU: contain a drive? */
  766.             if (du[0]>maxdrv) {               /* yep, so check maximum drive */
  767.                 Error0("Invalid drive");
  768.                 }
  769.             q=du+1;                           /* & point to byte after it */
  770.             }
  771.         else q=du;                                 /* nope, so point to beginning */
  772.         if (isdigit(*q)) {               /* got a number? */
  773.             if (atoi(q) > maxusr)           /* yep, so check max. user area */
  774.                 Error1("Invalid user area %s",q);
  775.             bdos(32,atoi(q));                  /* & read/write user area */
  776.             }
  777.         }
  778. #endif
  779.  
  780.     if ((argc > 2) && (str_chr(filespec, '.')) == NULL)
  781.         strcat(filespec, ".");
  782.     if (str_chr(arc_name, '.') == NULL)
  783.         strcat(arc_name, ".LHC");
  784.  
  785. if (strlen(arc_name)>16) Error0("Arcname too long");
  786. if ((argc>2)&&(strlen(filespec))>12) Error0("Arc member filename too long");
  787.  
  788.     if ((infile = fopen(arc_name, read_access)) == NULL) {
  789.         strcpy((arc_name + strlen(arc_name) - 3), "LZH");
  790.         if ((infile = fopen(arc_name, read_access)) == NULL)
  791.             Error1("Not found: %s\n", arc_name);
  792.     }
  793.     printf("File: %-13s\n\n", arc_name);
  794.  
  795.     if (argc == 2) {
  796.         printf("  Name          Original    Packed   Ratio    Date      Time    Type   CRC\n");
  797.         printf("--------------  --------  --------  ------  --------  --------  -----  ----\n");
  798.     }
  799.     while ((hdrlen = getc(infile)) != 0) {
  800.  
  801.         fread(&archdr.checksum, 1, sizeof archdr - 1, infile);
  802.         strncpy(comp_type, archdr.stowage, 5);
  803.         if ((strcmp(comp_type, "-lh1-") != 0) &&
  804.             (strcmp(comp_type, "-lh0-") != 0))
  805.             Error0("Unsupported storage method encountered. \n");
  806.         ksize = (archdr.orig_size + 1023) / 1024;
  807.         comp_tot += archdr.comp_size;
  808.         orig_tot += archdr.orig_size;
  809.         num_files++;
  810.  
  811.         if (archdr.fn_len > 12)
  812.             Error0("Invalid filename encountered.\n");
  813.         fread(outfname, 1, archdr.fn_len, infile);    /* read in the filename */
  814.         outfname[archdr.fn_len] = 0;    /* null terminate */
  815.         if ((hdrlen - archdr.fn_len) == 22)
  816.             fread(&crc, sizeof(crc), 1, infile);    /* read CRC if it exists */
  817.         else
  818.             crc = 0;        /* default display value if
  819.                          * no CRC support */
  820.  
  821.         if (argc == 2) {
  822.             Listent();
  823.             fseek(infile, archdr.comp_size, 1);
  824.         } else {
  825.  
  826.             if (str_chr(outfname, '.') == NULL)
  827.                 strcat(outfname, ".");
  828.  
  829.         if (match(outfname, filespec)) {
  830.  
  831. /*****************************************************************************/
  832. /* Let's parse up the requested filename and strip off the extent so that we */
  833. /* can examine it for nasty stuff like EXE, COM, OBJ, *.*, ?, and *. This is */
  834. /* necessary because printing these files will frequently hang your computer */
  835.  
  836.                       filelen=(strlen(filespec));             /* Get length  */
  837.                       extent[0] = filespec[filelen - 3];      /* of each char*/
  838.                       extent[1] = filespec[filelen - 2];      /* in the input*/
  839.                       extent[2] = filespec[filelen - 1];      /* file extent */
  840.                       exetst = strcmp(extent,exe);       /* Compare with EXE */
  841.                       comtst = strcmp(extent,com);       /* COM, OBJ and *.* */
  842.                       objtst = strcmp(extent,obj);       /* Value becomes 0  */
  843.                       ambtst = strcmp(extent,amb);       /* if match is true */
  844.                       if(extent[0] == astrsk[0]) letter = 0; /* Now check on */
  845.                       if(extent[1] == astrsk[0]) letter = 0; /* each letter  */
  846.                       if(extent[2] == astrsk[0]) letter = 0; /* of the extent*/
  847.                       if(extent[0] == questn[0]) letter = 0; /* for ? and *, */
  848.                       if(extent[1] == questn[0]) letter = 0; /* set letter to*/
  849.                       if(extent[2] == questn[0]) letter = 0; /* 0 if matched */
  850.                       printf("\n");
  851. /*                                                                           */
  852. /*****************************************************************************/
  853.  
  854. #ifndef viewonly
  855.             printf("Extracting: %-13s (%dk)", outfname, ksize);
  856. #else
  857.  
  858. /*****************************************************************************/
  859. /* Back to viewonly mode, and if we found a nasty value, we'll tell you so:  */
  860.  
  861.                            if (exetst == 0) goto enterr; /* Don't bitch about*/
  862.                            if (comtst == 0) goto enterr; /* the goto's!!!    */
  863.                            if (objtst == 0) goto enterr; /* enterr: is at    */
  864.                            if (ambtst == 0) goto enterr; /* line #927        */
  865.                            if (letter == 0) goto enterr; /* 0 means found it!*/
  866.  
  867. /* By going down and getting a special error message, before going to "skip" */
  868. /*****************************************************************************/
  869.  
  870.                printf("Viewing: %-13s (%dk)", outfname, ksize);
  871. #endif
  872.                 codesize = 0;
  873.                 printcount = 0;
  874.                 getbuf = 0;
  875.                  getlen = 0;
  876.  
  877.                 if ((outfile = Openfile(outfname)) != 0) {
  878.  
  879.                     if (comp_type[3] == '0')
  880.                         Copy(); /* if file is
  881.                              * uncompressed */
  882.                     else if (comp_type[3] == '1')
  883.                         Decode();    /* if file is compressed */
  884.                     if (outfile != stdout)    /* don't close stdout ! */
  885.                         fclose(outfile);
  886.                 } else
  887.                     fseek(infile, archdr.comp_size, 1);
  888.             } else {
  889.  
  890. /*****************************************************************************/
  891. /*                                Here is skip                               */
  892. skip:            printf("Skipping:   %-13s (%dk)\n", outfname, ksize);
  893. /*                     We got here from line # 945                           */
  894. /*****************************************************************************/
  895.  
  896.                 fseek(infile, archdr.comp_size, 1);
  897.             }
  898.         }
  899.     }
  900.  
  901.     close(infile);
  902.  
  903.     if (argc == 2) {
  904.         rat_tot = (1000 * comp_tot) / orig_tot;
  905.         printf("--------------  --------  --------  ------\n");
  906.         printf("  %4d files    %8ld  %8ld  %3d.%1d%%\n", num_files, orig_tot, comp_tot, rat_tot / 10, rat_tot % 10);
  907.     } else
  908.         printf("\nEnd of archive.\n");
  909.     return EXIT_OK;
  910.         
  911. /*****************************************************************************/
  912. /*                              Here is enterr                               */
  913. /*                     We got here from lines #891-895                       */
  914. enterr: printf("Error: EXE, COM, OBJ, *.*, ?, and * are illegal file extents when viewing!");
  915.                printf("\n");
  916.                goto skip;                                     
  917. /*                            skip is at line #921                           */
  918. /*****************************************************************************/
  919. }
  920.