home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / squsq / sq-17.c < prev    next >
C/C++ Source or Header  |  1983-11-12  |  7KB  |  262 lines

  1. /* SQ.C CHANGE HISTORY:
  2.  * 1.7  Add checkurk() memory check, changed credits 8-14-83 -CAF
  3.  *    Check for proper linking and sufficient memory to execute
  4.  *    Made inbuff and outbuff global for speed gain.
  5.  * 1.6  Add wild card expansion (wildexp) 6-12-82 -CAF
  6.  * 1.5  Fix BUG that caused a rare few squeezed files
  7.  *    to be incorrect and fail the USQ crc check.
  8.  *    The problem was that some 17 bit codes were
  9.  *    generated but are not supported by other code.
  10.  *    THIS IS A MAJOR CHANGE affecting TR2.C and SQ.H and
  11.  *    requires recompilation of all files which are part
  12.  *    of SQ. Two basic changes were made: tree depth is now
  13.  *    used as a tie breaker when weights are equal. This
  14.  *    makes the tree shallower. Although that may always be
  15.  *    sufficient, an error trap was added to cause rescaling
  16.  *    of the counts if any code > 16 bits long is generated.
  17.  *     Add debugging displays option '-'.
  18.  * 1.4    Break up long introductory lines.
  19.  *     Send introduction only to console.
  20.  *     Send errors only to console.
  21.  * 1.3    Close files properly in case of error exit.
  22.  *
  23.  * This program compresses a file without losing information.
  24.  * The usq.com program is required to unsqueeze the file
  25.  * before it can be used.
  26.  *
  27.  * Typical compression rates are:
  28.  *    .COM    6%    (Don't bother)
  29.  *    .ASM    33%    (using full ASCII set)
  30.  *    .DIC    46%    (using only uppercase and a few others)
  31.  * Squeezing a really big file takes a few minutes.
  32.  *
  33.  * Useage:
  34.  *    SQ item ...
  35.  * where ... represents more (optional) items and
  36.  * "item" is either:
  37.  *    drive:        to change the output drive
  38.  *    file        input file
  39.  *    drive:file    input file
  40.  *    -        toggle debugging display mode
  41.  *
  42.  * If no such items are given on the command line you will be
  43.  * prompted for commands (one at a time). An empty command
  44.  * terminates the program.
  45.  *
  46.  * SQ uses the dio package, so input and output can be redirected
  47.  * by special items on the command line such as:
  48.  *    <file        reads console input from file
  49.  *    >file        sends console output to file
  50.  *    +file        sends console output to console and file
  51.  * Also console output of another program using dio can be piped
  52.  * to the input of this one or vice-versa. Example:
  53.  *    A>fls parameters |sq
  54.  * where fls might be a program that expands patterns like *.com
  55.  * to a list of ambiguous file names for sq to squeeze.
  56.  *
  57.  * The squeezed file name is formed by changing the second
  58.  * letter of the file type to Q. If there is no file type,
  59.  * the squeezed file type is QQQ. If the name exists it is
  60.  * overwritten!
  61.  * 
  62.  * Examples:
  63.  *    A>SQ GRUMP        makes GRUMP.QQQ on A:
  64.  *    A>SQ D:CRAP.XYZ        makes CRAP.XQZ on A:
  65.  *    A>SQ B: D:CRAP.COM    makes CRAP.CQM on B:
  66.  *    B>SQ X.A C: Y.B        makes X.AQ on B: and Y.BQ on C:
  67.  *
  68.  * The transformations compress strings of identical bytes and
  69.  * then encode each resulting byte value and EOF as bit strings
  70.  * having lengths in inverse proportion to their frequency of
  71.  * occurrance in the intermediate input stream. The latter uses
  72.  * the Huffman algorithm. Decoding information is included in
  73.  * the squeezed file, so squeezing short files or files with
  74.  * uniformly distributed byte values will actually increase size.
  75.  */
  76.  
  77. #define VERSION "1.7   08-14-83"
  78.  
  79. #include <a:bdscio.h>
  80. #include <a:dio.h>
  81. #include "sqcom.h"
  82. #include "sq.h"
  83. #define STDERR 4    /* console only (error) stream */
  84.  
  85. /* Sneak in a few "local externs": N.B. sq.crl must be linked first! */
  86. char outfile[16];    /* output file spec. */
  87. unsigned Sentinel;    /* be sure this doesn't get munged ! */
  88. #define SENTINEL    055555
  89.  
  90. main(argc, argv)
  91. int argc;
  92. char *argv[];
  93. {
  94.     int i,c;
  95.     int getchar();        /* Directed io version */
  96.     char inparg[16];    /* parameter from input */
  97.  
  98.     checkurk();        /* check for armageddon */
  99.     Sentinel = SENTINEL;    /* unlikely value */
  100.     wildexp(&argc, &argv);    /* do the shell's work */
  101.     dioinit(&argc, argv);    /* obey directed to args */
  102.  
  103.     debug = FALSE;
  104.  
  105.     /* Initialize output drive to default drive */
  106.     outdrv[0]  = '\0';
  107.     /* But prepare for a specific drive */
  108.     outdrv[1] = ':';
  109.     outdrv[2] = '\0';    /* string terminator */
  110.  
  111.     /* Process the parameters in order */
  112.     for(i = 1; i < argc; ++i)
  113.         obey(argv[i]);
  114.  
  115.     if(argc < 2) {
  116.         if(! _diflag) {
  117.             fprintf(STDERR,"File squeezer %s\n", VERSION);
  118.             fprintf(STDERR,"Conceived by Richard Greenlaw Modified by Chuck Forsberg et al.\n");
  119.             fprintf(STDERR,"Accepts redirection and pipes.\n");
  120.             fprintf(STDERR, "Parameters (from command line or singly from stdin)\nconsist of output drives and input file names.\n");
  121.         }
  122.         do {
  123.             fprintf(STDERR, "\n*");
  124.             for(i = 0; i < 16; ++i) {
  125.                 if((c = getchar()) == EOF)
  126.                     c = '\n';    /* fake empty (exit) command */
  127.                 if((inparg[i] = c) == '\n') {
  128.                     inparg[i] = '\0';
  129.                     break;
  130.                 }
  131.             }
  132.             if(inparg[0] != '\0')
  133.                 obey(inparg);
  134.         } while(inparg[0] != '\0');
  135.     }
  136.     dioflush();    /* clean up any directed io */
  137.     if (Sentinel != SENTINEL)
  138.         fprintf(STDERR,"out of memory: translation suspect\007\n");
  139. }
  140.  
  141. obey(p)
  142. char *p;
  143. {
  144.     char *q;
  145.  
  146.     if(*p == '-') {
  147.         /* toggle debug option */
  148.         debug = !debug;
  149.         return;
  150.     }
  151.     if(*(p + 1) == ':') {
  152.         /* Got a drive */
  153.         if(isalpha(*p)) {
  154.             if(*(p+2) == '\0') {
  155.                 /* Change output drive */
  156.                 printf("\nOutput drive =%s",p);
  157.                 outdrv[0] = *p;
  158.                 return;
  159.             }
  160.         } else {
  161.             fprintf(STDERR, "\nERROR - Ignoring %s", p);
  162.             return;
  163.         }
  164.     }
  165.  
  166.     /* Check for ambiguous (wild-card) name */
  167.     for(q = p; *q != '\0'; ++q)
  168.         if(*q == '*' || *q == '?') {
  169.             fprintf(STDERR, "\nAmbiguous name %s ignored", p);
  170.             return;
  171.     }
  172.     /* First build output file name */
  173.     outfile[0] = '\0';        /* empty */
  174.     strcat(outfile, outdrv);    /* drive */
  175.     strcat(outfile, (*(p + 1) == ':') ? p + 2 : p);    /* input name */
  176.  
  177.     /* Find and change output file type */
  178.     for(q = outfile; *q != '\0'; ++q)
  179.         if(*q == '.')
  180.             if(*(q + 1) == '\0')
  181.                 *q = '\0';    /* kill trailing dot */
  182.             else
  183.                 switch(*(q+2)) {
  184.                 case 'q':
  185.                 case 'Q':
  186.                     fprintf(STDERR, "\n%s ignored ( already squeezed?)", p);
  187.                     return;
  188.                 case '\0':
  189.                     *(q+3) = '\0';
  190.                     /* fall thru */
  191.                 default:
  192.                     *(q + 2) = 'Q';
  193.                     goto named;
  194.                 }
  195.     /* No file type */
  196.     strcat(outfile, ".QQQ");
  197. named:
  198.     squeeze(p, outfile);
  199. }
  200.  
  201. squeeze(infile, outfile)
  202. char *infile, *outfile;
  203. {
  204.     int i, c;
  205.  
  206.     printf("\n%s -> %s: ", infile, outfile);
  207.  
  208.     if(fopen(infile, &inbuff) == ERROR) {
  209.         fprintf(STDERR, "Can't open %s\n", infile);
  210.         return;
  211.     }
  212.     if(fcreat(outfile, &outbuff) == ERROR) {
  213.         fprintf(STDERR, "Can't create %s\n", outfile);
  214.         fclose(&inbuff);
  215.         return;
  216.     }
  217.  
  218.     /* First pass - get properties of file */
  219.     crc = 0;    /* initialize checksum */
  220.     init_ncr();
  221.     printf("scanning, ");
  222.     init_huff();   
  223.     fclose(&inbuff);
  224.  
  225.     /* Write output file header with decoding info */
  226.     wrt_head(infile);
  227.  
  228.     /* Second pass - encode the file */
  229.     printf("squeezing, ");
  230.     if(fopen(infile, &inbuff) == ERROR) {
  231.         fprintf(STDERR, "Can't open %s\n", infile);
  232.         goto closeout;
  233.     }
  234.     init_ncr();    /* For second pass */
  235.  
  236.     /* Translate the input file into the output file */
  237.     while((c = gethuff()) != EOF)
  238.         if(putc(c, &outbuff) == ERROR) {
  239.             fprintf(STDERR, "ERROR - write error in %s\n", outfile);
  240.             goto closeall;
  241.         }
  242.     printf(" done.");
  243. closeall:
  244.     fclose(&inbuff);
  245. closeout:
  246.     fflush(&outbuff);
  247.     fclose(&outbuff);
  248. }
  249. /*
  250.  * Check for proper linking and sufficient memory to execute
  251.  */
  252. checkurk()
  253. {
  254.     char *endext(), *topofmem(), *codend(), *externs();
  255.  
  256.     if (codend() > externs()     /* check for bad -e value! */
  257.      || (topofmem()-1000) < endext() ) {
  258.         printf("checkurk(): bad memory layout\n");
  259.         exit();
  260.     }
  261. }
  262.