home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / AR002.LZH / AR.C < prev    next >
C/C++ Source or Header  |  1990-08-14  |  10KB  |  393 lines

  1. /***********************************************************
  2.     ar.c -- main file
  3. ***********************************************************/
  4.  
  5. static char *usage =
  6.     "ar -- compression archiver -- written by Haruhiko Okumura\n"
  7.     "  PC-VAN:SCIENCE        CompuServe:74050,1022\n"
  8.     "  NIFTY-Serve:PAF01022  INTERNET:74050.1022@compuserve.com\n"
  9.     "Usage: ar command archive [file ...]\n"
  10.     "Commands:\n"
  11.     "   a: Add files to archive (replace if present)\n"
  12.     "   x: Extract files from archive\n"
  13.     "   r: Replace files in archive\n"
  14.     "   d: Delete files from archive\n"
  15.     "   p: Print files on standard output\n"
  16.     "   l: List contents of archive\n"
  17.     "If no files are named, all files in archive are processed,\n"
  18.     "   except for commands 'a' and 'd'.\n"
  19.     "You may copy, distribute, and rewrite this program freely.\n";
  20.  
  21. /***********************************************************
  22.  
  23. Structure of archive block (low order byte first):
  24. -----preheader
  25.  1    basic header size
  26.         = 25 + strlen(filename) (= 0 if end of archive)
  27.  1    basic header algebraic sum (mod 256)
  28. -----basic header
  29.  5    method ("-lh0-" = stored, "-lh5-" = compressed)
  30.  4    compressed size (including extended headers)
  31.  4    original size
  32.  4    not used
  33.  1    0x20
  34.  1    0x01
  35.  1    filename length (x)
  36.  x    filename
  37.  2    original file's CRC
  38.  1    0x20
  39.  2    first extended header size (0 if none)
  40. -----first extended header, etc.
  41. -----compressed file
  42.  
  43. ***********************************************************/
  44.  
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. #include "ar.h"
  49.  
  50. #define FNAME_MAX (255 - 25) /* max strlen(filename) */
  51. #define namelen  header[19]
  52. #define filename ((char *)&header[20])
  53.  
  54. int unpackable;            /* global, set in io.c */
  55. ulong compsize, origsize;  /* global */
  56.  
  57. static uchar buffer[DICSIZ];
  58. static uchar header[255];
  59. static uchar headersize, headersum;
  60. static uint  file_crc;
  61. static char  *temp_name;
  62.  
  63. static uint ratio(ulong a, ulong b)  /* [(1000a + [b/2]) / b] */
  64. {
  65.     int i;
  66.  
  67.     for (i = 0; i < 3; i++)
  68.         if (a <= ULONG_MAX / 10) a *= 10;  else b /= 10;
  69.     if ((ulong)(a + (b >> 1)) < a) {  a >>= 1;  b >>= 1;  }
  70.     if (b == 0) return 0;
  71.     return (uint)((a + (b >> 1)) / b);
  72. }
  73.  
  74. static void put_to_header(int i, int n, ulong x)
  75. {
  76.     while (--n >= 0) {
  77.         header[i++] = (uchar)((uint)x & 0xFF);  x >>= 8;
  78.     }
  79. }
  80.  
  81. static ulong get_from_header(int i, int n)
  82. {
  83.     ulong s;
  84.  
  85.     s = 0;
  86.     while (--n >= 0) s = (s << 8) + header[i + n];  /* little endian */
  87.     return s;
  88. }
  89.  
  90. static uint calc_headersum(void)
  91. {
  92.     int i;
  93.     uint s;
  94.  
  95.     s = 0;
  96.     for (i = 0; i < headersize; i++) s += header[i];
  97.     return s & 0xFF;
  98. }
  99.  
  100. static int read_header(void)
  101. {
  102.     headersize = (uchar) fgetc(arcfile);
  103.     if (headersize == 0) return 0;  /* end of archive */
  104.     headersum  = (uchar) fgetc(arcfile);
  105.     fread_crc(header, headersize, arcfile);  /* CRC not used */
  106.     if (calc_headersum() != headersum) error("Header sum error");
  107.     compsize = get_from_header(5, 4);
  108.     origsize = get_from_header(9, 4);
  109.     file_crc = (uint)get_from_header(headersize - 5, 2);
  110.     filename[namelen] = '\0';
  111.     return 1;  /* success */
  112. }
  113.  
  114. static void write_header(void)
  115. {
  116.     fputc(headersize, outfile);
  117.     /* We've destroyed file_crc by null-terminating filename. */
  118.     put_to_header(headersize - 5, 2, (ulong)file_crc);
  119.     fputc(calc_headersum(), outfile);
  120.     fwrite_crc(header, headersize, outfile);  /* CRC not used */
  121. }
  122.  
  123. static void skip(void)
  124. {
  125.     fseek(arcfile, compsize, SEEK_CUR);
  126. }
  127.  
  128. static void copy(void)
  129. {
  130.     uint n;
  131.  
  132.     write_header();
  133.     while (compsize != 0) {
  134.         n = (uint)((compsize > DICSIZ) ? DICSIZ : compsize);
  135.         if (fread ((char *)buffer, 1, n, arcfile) != n)
  136.             error("Can't read");
  137.         if (fwrite((char *)buffer, 1, n, outfile) != n)
  138.             error("Can't write");
  139.         compsize -= n;
  140.     }
  141. }
  142.  
  143. static void store(void)
  144. {
  145.     uint n;
  146.  
  147.     origsize = 0;
  148.     crc = INIT_CRC;
  149.     while ((n = fread((char *)buffer, 1, DICSIZ, infile)) != 0) {
  150.         fwrite_crc(buffer, n, outfile);  origsize += n;
  151.     }
  152.     compsize = origsize;
  153. }
  154.  
  155. static int add(int replace_flag)
  156. {
  157.     long headerpos, arcpos;
  158.     uint r;
  159.  
  160.     if ((infile = fopen(filename, "rb")) == NULL) {
  161.         fprintf(stderr, "Can't open %s\n", filename);
  162.         return 0;  /* failure */
  163.     }
  164.     if (replace_flag) {
  165.         printf("Replacing %s ", filename);  skip();
  166.     } else
  167.         printf("Adding %s ", filename);
  168.     headerpos = ftell(outfile);
  169.     namelen = strlen(filename);
  170.     headersize = 25 + namelen;
  171.     memcpy(header, "-lh5-", 5);  /* compress */
  172.     write_header();  /* temporarily */
  173.     arcpos = ftell(outfile);
  174.     origsize = compsize = 0;  unpackable = 0;
  175.     crc = INIT_CRC;  encode();
  176.     if (unpackable) {
  177.         header[3] = '0';  /* store */
  178.         rewind(infile);
  179.         fseek(outfile, arcpos, SEEK_SET);
  180.         store();
  181.     }
  182.     file_crc = crc ^ INIT_CRC;
  183.     fclose(infile);
  184.     put_to_header(5, 4, compsize);
  185.     put_to_header(9, 4, origsize);
  186.     memcpy(header + 13, "\0\0\0\0\x20\x01", 6);
  187.     memcpy(header + headersize - 3, "\x20\0\0", 3);
  188.     fseek(outfile, headerpos, SEEK_SET);
  189.     write_header();  /* true header */
  190.     fseek(outfile, 0L, SEEK_END);
  191.     r = ratio(compsize, origsize);
  192.     printf(" %d.%d%%\n", r / 10, r % 10);
  193.     return 1;  /* success */
  194. }
  195.  
  196. int get_line(char *s, int n)
  197. {
  198.     int i, c;
  199.  
  200.     i = 0;
  201.     while ((c = getchar()) != EOF && c != '\n')
  202.         if (i < n) s[i++] = (char)c;
  203.     s[i] = '\0';
  204.     return i;
  205. }
  206.  
  207. static void extract(int to_file)
  208. {
  209.     int n, method;
  210.     uint ext_headersize;
  211.  
  212.     if (to_file) {
  213.         while ((outfile = fopen(filename, "wb")) == NULL) {
  214.             fprintf(stderr, "Can't open %s\nNew filename: ", filename);
  215.             if (get_line(filename, FNAME_MAX) == 0) {
  216.                 fprintf(stderr, "Not extracted\n");
  217.                 skip();  return;
  218.             }
  219.             namelen = strlen(filename);
  220.         }
  221.         printf("Extracting %s ", filename);
  222.     } else {
  223.         outfile = stdout;
  224.         printf("===== %s =====\n", filename);
  225.     }
  226.     crc = INIT_CRC;
  227.     method = header[3];  header[3] = ' ';
  228.     if (! strchr("045", method) || memcmp("-lh -", header, 5)) {
  229.         fprintf(stderr, "Unknown method: %u\n", method);
  230.         skip();
  231.     } else {
  232.         ext_headersize = (uint)get_from_header(headersize - 2, 2);
  233.         while (ext_headersize != 0) {
  234.             fprintf(stderr, "There's an extended header of size %u.\n",
  235.                 ext_headersize);
  236.             compsize -= ext_headersize;
  237.             if (fseek(arcfile, ext_headersize - 2, SEEK_CUR))
  238.                 error("Can't read");
  239.             ext_headersize = fgetc(arcfile);
  240.             ext_headersize += (uint)fgetc(arcfile) << 8;
  241.         }
  242.         crc = INIT_CRC;
  243.         if (method != '0') decode_start();
  244.         while (origsize != 0) {
  245.             n = (uint)((origsize > DICSIZ) ? DICSIZ : origsize);
  246.             if (method != '0') decode(n, buffer);
  247.             else if (fread((char *)buffer, 1, n, arcfile) != n)
  248.                 error("Can't read");
  249.             fwrite_crc(buffer, n, outfile);
  250.             if (outfile != stdout) putc('.', stderr);
  251.             origsize -= n;
  252.         }
  253.     }
  254.     if (to_file) fclose(outfile);  else outfile = NULL;
  255.     printf("\n");
  256.     if ((crc ^ INIT_CRC) != file_crc)
  257.         fprintf(stderr, "CRC error\n");
  258. }
  259.  
  260. static void list_start(void)
  261. {
  262.     printf("Filename         Original Compressed Ratio CRC Method\n");
  263. }
  264.  
  265. static void list(void)
  266. {
  267.     uint r;
  268.  
  269.     printf("%-14s", filename);
  270.     if (namelen > 14) printf("\n              ");
  271.     r = ratio(compsize, origsize);
  272.     printf(" %10lu %10lu %u.%03u %04X %5.5s\n",
  273.         origsize, compsize, r / 1000, r % 1000, file_crc, header);
  274. }
  275.  
  276. static int match(char *s1, char *s2)
  277. {
  278.     for ( ; ; ) {
  279.         while (*s2 == '*' || *s2 == '?') {
  280.             if (*s2++ == '*')
  281.                 while (*s1 && *s1 != *s2) s1++;
  282.             else if (*s1 == 0)
  283.                 return 0;
  284.             else s1++;
  285.         }
  286.         if (*s1 != *s2) return 0;
  287.         if (*s1 == 0  ) return 1;
  288.         s1++;  s2++;
  289.     }
  290. }
  291.  
  292. static int search(int argc, char *argv[])
  293. {
  294.     int i;
  295.  
  296.     if (argc == 3) return 1;
  297.     for (i = 3; i < argc; i++)
  298.         if (match(filename, argv[i])) return 1;
  299.     return 0;
  300. }
  301.  
  302. static void exitfunc(void)
  303. {
  304.     fclose(outfile);  remove(temp_name);
  305. }
  306.  
  307. int main(int argc, char *argv[])
  308. {
  309.     int i, j, cmd, count, nfiles, found, done;
  310.  
  311.     /* Check command line arguments. */
  312.     if (argc < 3
  313.      || argv[1][1] != '\0'
  314.      || ! strchr("AXRDPL", cmd = toupper(argv[1][0]))
  315.      || (argc == 3 && strchr("AD", cmd)))
  316.         error(usage);
  317.  
  318.     /* Wildcards used? */
  319.     for (i = 3; i < argc; i++)
  320.         if (strpbrk(argv[i], "*?")) break;
  321.     if (cmd == 'A' && i < argc)
  322.         error("Filenames may not contain '*' and '?'");
  323.     if (i < argc) nfiles = -1;  /* contains wildcards */
  324.     else nfiles = argc - 3;     /* number of files to process */
  325.  
  326.     /* Open archive. */
  327.     arcfile = fopen(argv[2], "rb");
  328.     if (arcfile == NULL && cmd != 'A')
  329.         error("Can't open archive '%s'", argv[2]);
  330.  
  331.     /* Open temporary file. */
  332.     if (strchr("ARD", cmd)) {
  333.         temp_name = tmpnam(NULL);
  334.         outfile = fopen(temp_name, "wb");
  335.         if (outfile == NULL)
  336.             error("Can't open temporary file");
  337.         atexit(exitfunc);
  338.     } else temp_name = NULL;
  339.  
  340.     make_crctable();  count = done = 0;
  341.  
  342.     if (cmd == 'A') {
  343.         for (i = 3; i < argc; i++) {
  344.             for (j = 3; j < i; j++)
  345.                 if (strcmp(argv[j], argv[i]) == 0) break;
  346.             if (j == i) {
  347.                 strcpy(filename, argv[i]);
  348.                 if (add(0)) count++;  else argv[i][0] = 0;
  349.             } else nfiles--;
  350.         }
  351.         if (count == 0 || arcfile == NULL) done = 1;
  352.     }
  353.  
  354.     while (! done && read_header()) {
  355.         found = search(argc, argv);
  356.         switch (cmd) {
  357.         case 'R':
  358.             if (found) {
  359.                 if (add(1)) count++;  else copy();
  360.             } else copy();
  361.             break;
  362.         case 'A':  case 'D':
  363.             if (found) {
  364.                 count += (cmd == 'D');  skip();
  365.             } else copy();
  366.             break;
  367.         case 'X':  case 'P':
  368.             if (found) {
  369.                 extract(cmd == 'X');
  370.                 if (++count == nfiles) done = 1;
  371.             } else skip();
  372.             break;
  373.         case 'L':
  374.             if (found) {
  375.                 if (count == 0) list_start();
  376.                 list();
  377.                 if (++count == nfiles) done = 1;
  378.             }
  379.             skip();  break;
  380.         }
  381.     }
  382.  
  383.     if (temp_name != NULL && count != 0) {
  384.         fputc(0, outfile);  /* end of archive */
  385.         if (ferror(outfile) || fclose(outfile) == EOF)
  386.             error("Can't write");
  387.         remove(argv[2]);  rename(temp_name, argv[2]);
  388.     }
  389.  
  390.     printf("  %d files\n", count);
  391.     return EXIT_SUCCESS;
  392. }
  393.