home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / squsq / usq-20.c < prev    next >
C/C++ Source or Header  |  1984-07-08  |  9KB  |  321 lines

  1. /* USQ.C CHANGE HISTORY:
  2.  * 2.0    Added checkurk(), changed credits -CAF 8-14-83
  3.  * 1.9  Added wildexp -CAF 6-12-82
  4.  * 1.8  Output CPMEOF's while last output sector is partially filled.
  5.  *    Needed if file was squeezed on a non-CP/M system. -CAF 3-10-82
  6.  * 1.7  Added -n to change NL to CRLF when unsqueezing files.  Added CPMEOF
  7.  *    at end of file in case of checksum error detected.
  8.  * 1.6  Lengthened permissible length of unsqueezed filename so long **nix
  9.  *    pathnames won't choke unsqueeze(). -CAF 12-5-81
  10.  * 1.5  Break up long lines of introductory text
  11.  *      -count no longer appends formfeed to preview of each file.
  12.  *    -fcount (-f10, -F10) does append formfeed.
  13.  * 1.4    Add -count option to allow quick inspection of files.
  14.  * 1.3    Close inbuff to avoid exceeding maximum number of
  15.  *    open files. Includes rearranging error exits.
  16.  *
  17.  * Program to unsqueeze files formed by sq.com
  18.  *
  19.  * Usage:
  20.  *    USQ item ...
  21.  * where ... represents more (optional) items and
  22.  * "item" is either:
  23.  *    drive:        to change the output drive
  24.  *    file        input file
  25.  *    drive:file    input file
  26.  *    -count        Previewing feature: redirects output
  27.  *             files to standard output with parity stripped
  28.  *            and unprintables except CR, LF, TAB and  FF
  29.  *            converted to periods. Limits each file
  30.  *            to first count lines.
  31.  *            Defaults to console, but see below how
  32.  *            to capture all in one file for further
  33.  *            processing, such as by PIP.
  34.  *            Count defaults to a very high value.
  35.  *            No CRC check is performed when previewing.
  36.  *            Use drive: to cancel this.
  37.  *
  38.  *    -fcount        Same as -count except formfeed
  39.  *            appended to preview of each file.
  40.  *            Example: -f10.
  41.  *
  42.  *    -n        Change NL to CRLF
  43.  *
  44.  * If no such items are given on the command line you will be
  45.  * prompted for commands (one at a time). An empty command
  46.  * terminates the program.
  47.  *
  48.  * USQ uses the dio package, so input and output can be redirected
  49.  * by special items on the command line such as:
  50.  *    <file        reads console input from file
  51.  *    >file        sends console output to file
  52.  *    +file        sends console output to console and file
  53.  * Also console output of another program using dio can be piped
  54.  * to the input of USQ or vice-versa. Example:
  55.  *    A>fls parameters |usq
  56.  * where fls might be a program that expands patterns like *.asm
  57.  * to a list of specific file names for usq to unsqueeze.
  58.  *
  59.  * The unsqueezed file name is recorded in the squeezed file.
  60.  * 
  61.  * Examples:
  62.  *    A>USQ GRUMP.QQQ        writes on a:
  63.  *    A>USQ D:CRAP.XQZ    writes on A:
  64.  *    A>USQ B: D:CRAP.CQM    writes on B:
  65.  *    B>USQ X.AQ C: Y.BQ    writes X.?? on B: and Y.?? on C:
  66.  */
  67.  
  68. #include <a:bdscio.h>
  69. #include <a:dio.h>
  70. #include "sqcom.h"
  71. #include "usq.h"
  72. #define VERSION "2.0   8-14-83"
  73. #define STDERR 4    /*Error output stream (always console) */
  74.  
  75. /* This must follow all include files.  USQ.CRL must be linked first! */
  76. unsigned dispcnt;    /* How much of each file to preview */
  77. char    ffflag;        /* Formfeed separates preview from different files */
  78. char    nlmode;        /* <>0 if adding/deleting cr's for host system */
  79. unsigned Sentinel;    /* be sure this doesn't get munged ! */
  80. #define SENTINEL    055555
  81.  
  82. main(argc, argv)
  83. int argc;
  84. char *argv[];
  85. {
  86.     int i,c;
  87.     int getchar();        /* Directed io version */
  88.     char inparg[16];    /* parameter from input */
  89.  
  90.     checkurk();        /* check for memory overflow */
  91.     Sentinel = SENTINEL;    /* unlikely value */
  92.     wildexp(&argc, &argv);    /* do the Shell's bloody work */
  93.     dioinit(&argc, argv);    /* obey directed to args */
  94.  
  95.     nlmode = dispcnt = 0;    /* Not in preview or nlmode */
  96.  
  97.  
  98.     /* Initialize output drive to default drive */
  99.     outdrv[0]  = '\0';
  100.     /* But prepare for a specific drive */
  101.     outdrv[1] = ':';
  102.     outdrv[2] = '\0';    /* string terminator */
  103.  
  104.     /* Process the parameters in order */
  105.     for(i = 1; i < argc; ++i)
  106.         obey(argv[i]);
  107.  
  108.     if(argc < 2) {
  109.         if(! _diflag) {
  110.             fprintf(STDERR, "File unsqueezer version %s\n", VERSION);
  111.             fprintf(STDERR,"Conceived by Richard Greenlaw Modified by Chuck Forsberg et al.\n");
  112.             fprintf(STDERR, "Accepts redirection and pipes.\n");
  113.             fprintf(STDERR, "Usage: usq [-count][-Fcount][-N] [file ...]\n");
  114.             fprintf(STDERR, "Parameters are from command line or one-at-a-time from standard\ninput and are output drives and input file names. Empty to quit.\n");
  115.         }
  116.         do {
  117.             fprintf(STDERR, "\n*");
  118.             for(i = 0; i < 16; ++i) {
  119.                 if((c = getchar()) == EOF)
  120.                     c = '\n';    /* force empty (exit) command */
  121.                 if((inparg[i] = c) == '\n') {
  122.                     inparg[i] = '\0';
  123.                     break;
  124.                 }
  125.             }
  126.             if(inparg[0] != '\0')
  127.                 obey(inparg);
  128.         } while(inparg[0] != '\0');
  129.     }
  130.     dioflush();    /* clean up any directed io */
  131.     if (Sentinel != SENTINEL)
  132.         fprintf(STDERR,"out of memory: translation suspect\007\n");
  133. }
  134.  
  135. obey(p)
  136. char *p;
  137. {
  138.     char *q;
  139.  
  140.     if(*p == '-') {
  141.         if('n' ==tolower(p[1])) {
  142.             ++nlmode; return;
  143.         }
  144.         if(ffflag = (toupper(*(p+1)) == 'F'))
  145.             ++p;
  146.         /* Set number of lines of each file to view */
  147.         dispcnt = 65535;    /* default */
  148.         if(*(p+1))
  149.             if((dispcnt = atoi(p + 1)) == 0)
  150.                 fprintf(STDERR, "\nBAD COUNT %s", p + 1);
  151.         return;
  152.     }    
  153.  
  154.     if(*(p + 1) == ':') {
  155.         /* Got a drive */
  156.         if(isalpha(*p)) {
  157.             if(*(p+2) == '\0') {
  158.                 /* Change output drive */
  159.                 dispcnt = 0;    /* cancel previewing */
  160.                 printf("\nOutput drive =%s",p);
  161.                 outdrv[0] = *p;
  162.                 return;
  163.             }
  164.         } else {
  165.             fprintf(STDERR, "\nERROR - Ignoring %s", p);
  166.             return;
  167.         }
  168.     }
  169.  
  170.     /* Check for ambiguous (wild-card) name */
  171.     for(q = p; *q != '\0'; ++q)
  172.         if(*q == '*' || *q == '?') {
  173.             fprintf(STDERR, "\nCan't accept ambiguous name %s", p);
  174.             return;
  175.         }
  176.  
  177.     unsqueeze(p);
  178. }
  179.  
  180.  
  181. unsqueeze(infile)
  182. char *infile;
  183. {
  184.     struct _buf inbuff, outbuff;    /* file buffers */
  185.     int i, c;
  186.     char cc;
  187.  
  188.     char *p;
  189.     unsigned filecrc;    /* checksum */
  190.     int numnodes;        /* size of decoding tree */
  191.     char outfile[257];    /* output file name */
  192.     unsigned linect;    /* count of number of lines previewed */
  193.  
  194.     if(fopen(infile, &inbuff) == ERROR) {
  195.         fprintf(STDERR, "Can't open %s\n", infile);
  196.         return;
  197.     }
  198.     /* Initialization */
  199.     linect = 0;
  200.     crc = 0;
  201.     init_cr();
  202.     init_huff();
  203.  
  204.     /* Process header */
  205.     if(getw(&inbuff) != RECOGNIZE) {
  206.         fprintf(STDERR, "%s is not a squeezed file\n", infile);
  207.         goto closein;
  208.     }
  209.  
  210.     filecrc = getw(&inbuff);
  211.  
  212.     /* Get original file name */
  213.     p = origname;    /* send it to array */
  214.     do {
  215.         *p = getc(&inbuff);
  216.     } while(*p++ != '\0');
  217.  
  218.     /* Combine with output drive */
  219.     outfile[0] = '\0';        /* empty */
  220.     strcat(outfile, outdrv);    /* drive */
  221.     strcat(outfile, origname);    /* name */
  222.  
  223.     printf("\n%s -> %s: ", infile, outfile);
  224.  
  225.  
  226.     numnodes = getw(&inbuff);
  227.  
  228.     if(numnodes < 0 || numnodes >= NUMVALS) {
  229.         fprintf(STDERR, "%s has invalid decode tree size\n", infile);
  230.         goto closein;
  231.     }
  232.  
  233.     /* Initialize for possible empty tree (SPEOF only) */
  234.     dnode[0].children[0] = -(SPEOF + 1);
  235.     dnode[0].children[1] = -(SPEOF + 1);
  236.  
  237.     /* Get decoding tree from file */
  238.     for(i = 0; i < numnodes; ++i) {
  239.         dnode[i].children[0] = getw(&inbuff);
  240.         dnode[i].children[1] = getw(&inbuff);
  241.     }
  242.  
  243.     if(dispcnt) {
  244.         /* Use standard output for previewing */
  245.         putchar('\n');
  246.         while(((c = getcr(&inbuff)) != EOF) && (linect < dispcnt)) {
  247.             cc = 0x7f & c;    /* strip parity */
  248.             if((cc < ' ') || (cc > '~'))
  249.                 /* Unprintable */
  250.                 switch(cc) {
  251.                 case '\r':    /* return */
  252.                     /* newline will generate CR-LF */
  253.                     goto next;
  254.                 case '\n':    /* newline */
  255.                     ++linect;
  256.                 case '\f':    /* formfeed */
  257.                 case '\t':    /* tab */
  258.                     break;
  259.                 default:
  260.                     cc = '.';
  261.                 }
  262.             putchar(cc);
  263.         next: ;
  264.         }
  265.         if(ffflag)
  266.             putchar('\f');    /* formfeed */
  267.     } else {
  268.         /* Create output file */
  269.         if(fcreat(outfile, &outbuff) == ERROR) {
  270.             fprintf(STDERR, "Can't create %s\n", outfile);
  271.             goto closeall;
  272.         }
  273.         /* Get translated output bytes and write file */
  274.         while((c = getcr(&inbuff)) != EOF) {
  275.             crc += c;
  276.             if(nlmode && c=='\n')
  277.                 putc('\r', &outbuff);
  278.             if((putc(c, &outbuff)) == ERROR) {
  279.                 fprintf(STDERR, "Write error in %s\n", outfile);
  280.                 goto closeall;
  281.             }
  282.         }
  283.  
  284.         if(filecrc != crc) {
  285.             putc(CPMEOF, &outbuff);
  286.             fprintf(STDERR, "ERROR - checksum error in %s\n", outfile);
  287.         }
  288.  
  289.  
  290.     closeall:
  291.         /*
  292.          * If the last sector is partially filled (this would happen
  293.          * iff the file was squeezed on MARC, Unix(TM), MS-DOS or
  294.          * similar system which avoids the CP/M EOF crock),
  295.          * pad it out with ^Z characters so editors,
  296.          * etc. won't choke on it. -CAF 3-10-82
  297.          */
  298.         while(outbuff._nleft % SECSIZ)    /* for BDS C 1.4x only */
  299.             putc(CPMEOF, &outbuff);
  300.         fflush(&outbuff);
  301.         fclose(&outbuff);
  302.     }
  303.  
  304. closein:
  305.     fclose(&inbuff);
  306. }
  307.  
  308. /*
  309.  * Check for proper linking and sufficient memory to execute
  310.  */
  311. checkurk()
  312. {
  313.     char *endext(), *topofmem(), *codend(), *externs();
  314.  
  315.     if (codend() > externs()     /* check for bad -e value! */
  316.      || (topofmem()-3000) < endext() ) {
  317.         printf("checkurk(): bad memory layout\n");
  318.         exit();
  319.     }
  320. }
  321.