home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / yacoder.lha / yacoder / encode.c < prev    next >
C/C++ Source or Header  |  1998-05-07  |  5KB  |  216 lines

  1. /*
  2.  * $Header: /usr/people/tcl/src/uutar/RCS/encode.c,v 1.1.1.5 1993/09/11 22:42:56 tcl Exp $
  3.  * Tom Lawrence
  4.  * tcl@sgi.com
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "codes.h"
  13.  
  14. static FILE *infp, *outfp;
  15. static char *name, *charset;
  16. static mode_t inmode;
  17.  
  18. static void
  19. usage()
  20. {
  21.     printf("options:\n");
  22.     printf("-i <inputfile>\n");
  23.     printf("-o <outputfile>\n");
  24.     printf("-n <name>\n");
  25.     printf("-c <charset>\n");
  26.     exit(1);
  27. }
  28.  
  29. /* parse command line arguments */
  30. static void
  31. parse(argc, argv)
  32.     int argc;
  33.     char **argv;
  34. {
  35.     char *infile, *outfile;
  36.     struct stat statbuf;
  37.  
  38.     infile = outfile = 0;
  39.     name = charset = 0;
  40.  
  41.     while(--argc) {
  42.     argv++;
  43.     if (!strcmp(*argv, "-i")) {
  44.         if (argc < 2)
  45.         usage();
  46.         argc--;
  47.         argv++;
  48.         infile = *argv;
  49.     }
  50.     else if (!strcmp(*argv, "-o")) {
  51.         if (argc < 2)
  52.         usage();
  53.         argc--;
  54.         argv++;
  55.         outfile = *argv;
  56.     }
  57.     else if (!strcmp(*argv, "-n")) {
  58.         if (argc < 2)
  59.         usage();
  60.         argc--;
  61.         argv++;
  62.         name = *argv;
  63.     }
  64.     else if (!strcmp(*argv, "-c")) {
  65.         if (argc < 2)
  66.         usage();
  67.         argc--;
  68.         argv++;
  69.         charset = *argv;
  70.     }
  71.     else
  72.         usage();
  73.     }
  74.  
  75.     /* open the input stream */
  76.     if (infile) {
  77.     if ((infp = fopen(infile, "r")) == 0) {
  78.         perror(infile);
  79.         exit(1);
  80.     }
  81.     if (stat(infile, &statbuf) < 0) {
  82.         perror(infile);
  83.         exit(1);
  84.     }
  85.     inmode = statbuf.st_mode & 0777;
  86.     }
  87.     else {
  88.     infp = stdin;
  89.     inmode = 0666;
  90.     }
  91.  
  92.     /* open the output stream */
  93.     if (outfile) {
  94.     if ((outfp = fopen(outfile, "w")) == 0) {
  95.         perror(outfile);
  96.         exit(1);
  97.     }
  98.     }
  99.     else
  100.     outfp = stdout;
  101.  
  102.     /* get the filename to store in the encoded file */
  103.     if (name == 0) {
  104.     if (infile == 0)
  105.         name = "stdin";
  106.     else
  107.         name = infile;
  108.     }
  109.  
  110.     /* set default character set if none was specified */
  111.     if (charset == 0)
  112.     charset = "32-126";
  113. }
  114.  
  115. main(argc, argv)
  116.     int argc;
  117.     char **argv;
  118. {
  119.     int c;
  120.     unsigned short buf;
  121.     int buf_offset, inlen, cols = 0, pattern;
  122.     unsigned int cksum;
  123.  
  124.     /* parse command line arguments */
  125.     parse(argc, argv);
  126.  
  127.     /* parse the supplied character set specification and initialize
  128.      * tables based on that set
  129.      */
  130.     parse_charval_list(charset);
  131.     init_codes(ENCODE);
  132.  
  133.     fprintf(outfp, "BEGIN %o %s ", inmode, name);
  134.     print_charval_list(outfp);
  135.     putc('\n', outfp);
  136.  
  137.     /* clear the sliding input buffer */
  138.     buf = 0;
  139.     buf_offset = 16;
  140.     
  141.     cksum = 0;
  142.  
  143.     /* read in the input file */
  144.     while((c = getc(infp)) != EOF) {
  145.  
  146.     /* compute a checksum on the input file */
  147.     cksum = ((cksum << 7) | (cksum >> 25)) ^ (unsigned)c;
  148.  
  149.     /* shift the byte just read in into our sliding buffer */
  150.     buf_offset -= 8;
  151.     buf |= ((unsigned short)c << buf_offset);
  152.  
  153.     /* see if there are any complete variable length bitfields
  154.      * in the input buffer. If so, output their corresponding
  155.      * printable output character and advance the input buffer
  156.      * by their length in bits
  157.      */
  158.     while (1) {
  159.  
  160.         /* grab the next 8 bits in the input bitstream */
  161.         pattern = (int)(buf >> 8);
  162.  
  163.         /* determine how many of those bits we will need
  164.          * to extract from the sliding buffer
  165.          */
  166.         inlen = codes[pattern].len;
  167.  
  168.         /* if there are not enough bits in the sliding
  169.          * buffer, stop for now. (interestingly, you don't need
  170.          * to have all of the needed bits in order to determine
  171.          * that you don't have all of the needed bits)
  172.          */
  173.         if (inlen > (16 - buf_offset))
  174.         break;
  175.  
  176.         /* output the printable character associated with
  177.          * the variable length bitfield recognized in the
  178.          * input bitstream
  179.          */
  180.         putc(codes[pattern].code, outfp);
  181.  
  182.         /* limit our width */
  183.         if (++cols == 79) {
  184.         cols = 0;
  185.         putc('\n', outfp);
  186.         }
  187.  
  188.         /* advance the input bitstream by the length of the bitfield
  189.          * just recognized
  190.          */
  191.         buf_offset += inlen;
  192.         buf <<= inlen;
  193.     }
  194.     }
  195.  
  196.     /* flush the buffer. The last byte read in may still have some
  197.      * of its bits in the sliding buffer. If so, print out one more
  198.      * output character. This will necessarily append some garbage
  199.      * bits to the output but what can we do? we can't write files
  200.      * at a finer granularity that the byte. The decoder will ignore
  201.      * them so it's ok
  202.      */
  203.     if (buf_offset < 16) {
  204.     putc(codes[pattern].code, outfp);
  205.     cols++;
  206.     }
  207.  
  208.     /* indicate end of encoded data by 2 consecutive newlines followed
  209.      * by the keyword END. This is necessary since the END line itself
  210.      * is potentially valid encoded data
  211.      */
  212.     if (cols)
  213.     putc('\n', outfp);
  214.     fprintf(outfp, "\nEND %X\n", cksum);
  215. }
  216.