1 /***********************************************************
3 ***********************************************************/
5 static char *version = "0.01";
8 "ar -- compression archiver -- written by Haruhiko Okumura\n"
9 " PC-VAN:SCIENCE CompuServe:74050,1022\n"
10 " NIFTY-Serve:PAF01022 INTERNET:74050.1022@compuserve.com\n"
11 "Usage: ar command archive [file ...]\n"
13 " a: Add files to archive (replace if present)\n"
14 " x: Extract files from archive\n"
15 " r: Replace files in archive\n"
16 " d: Delete files from archive\n"
17 " p: Print files on standard output\n"
18 " l: List contents of archive\n"
19 "If no files are named, all files in archive are processed,\n"
20 " except for commands 'a' and 'd'.\n"
21 "You may copy, distribute, and rewrite this program freely.\n";
23 /***********************************************************
25 Structure of archive block (low order byte first):
28 = 25 + strlen(filename) (= 0 if end of archive)
29 1 basic header algebraic sum (mod 256)
31 5 method ("-lh0-" = stored, "-lh5-" = compressed)
32 4 compressed size (including extended headers)
41 2 first extended header size (0 if none)
42 -----first extended header, etc.
45 ***********************************************************/
57 struct lha_method methods[] = {
58 /* id, dicbit, pbit, maxmatch */
59 /* note: dicbit == 0 means no compress */
60 /* (1U << pbit) > np(dicbit+1) */
61 {"-lh0-", 0, 0, 0}, /* 0: no compress */
62 {"-lh1-", 12, 0, 60}, /* 1: 2^12 = 4KB dynamic huffman (LHarc) */
63 {"-lh2-", 13, 0,256}, /* 2: 2^13 = 8KB dynamic huffman */
64 {"-lh3-", 13, 0,256}, /* 3: 2^13 = 8KB static huffman */
65 {"-lh4-", 12, 4,256}, /* 4: 2^12 = 4KB static huffman (pos and len)*/
66 {"-lh5-", 13, 4,256}, /* 5: 2^13 = 8KB static huffman (pos and len)*/
67 {"-lh6-", 15, 5,256}, /* 6: 2^15 = 32KB static huffman (pos and len)*/
68 {"-lh7-", 16, 5,256}, /* 7: 2^16 = 64KB static huffman (pos and len)*/
69 {"-lzs-", 11, 0, 17}, /* 8: 2^11 = 2KB (LArc) */
70 {"-lz5-", 12, 0, 17}, /* 9: 2^12 = 4KB (LArc) */
71 {"-lz4-", 0, 0, 0}, /*10: no compress (LArc) */
72 {"-lhd-", 0, 0, 0}, /*11: directory */
78 which_method(char *id)
82 for (i = 0; i < sizeof(methods)/sizeof(methods[0]); i++) {
83 if (strncmp(id, methods[i].id, sizeof(methods[0].id)) == 0) {
100 printf("version %s\n", version);
105 ratio(ulong a, ulong b)
106 { /* [(1000a + [b/2]) / b] */
109 for (i = 0; i < 3; i++)
110 if (a <= ULONG_MAX / 10)
114 if ((ulong) (a + (b >> 1)) < a) {
120 return (uint) ((a + (b >> 1)) / b);
124 skip(FILE *fp, struct lzh_header *h)
127 if (opts.archive_to_stdio)
128 for (i = 0; i < h->compsize; i++)
131 fseek(fp, h->compsize, SEEK_CUR);
135 copy(FILE *arcfile, FILE *outfile, struct lzh_header *h)
138 uchar buffer[MAXDICSIZ];
140 write_header(outfile, h);
141 while (h->compsize != 0) {
142 n = (uint) ((h->compsize > sizeof(buffer)) ? sizeof(buffer) : h->compsize);
143 if (fread((char *) buffer, 1, n, arcfile) != n)
145 if (fwrite((char *) buffer, 1, n, outfile) != n)
146 error("Can't write");
152 get_line(char *s, int n)
157 while ((c = getchar()) != EOF && c != '\n')
165 match(char *s1, char *s2)
168 while (*s2 == '*' || *s2 == '?') {
170 while (*s1 && *s1 != *s2)
187 search(int argc, char *argv[], struct lzh_header *h)
193 for (i = 0; i < argc; i++)
194 if (argv[i] && match(h->filename, argv[i]))
199 #include "getopt_long.h"
202 parse_args(int argc, char **argv)
207 /* int this_option_optind = optind ? optind : 1; */
208 int option_index = 0;
215 static struct option long_options[] = {
216 /* name, has_arg, *flag, val */
219 required_argument (1)
220 optional_argument (2)
222 NULL: getopt_long() return val
223 non-NULL: getopt_long() return 0, and *flag set val.
225 {"help", no_argument, NULL, LHA_OPT_HELP},
226 {"version", no_argument, NULL, LHA_OPT_VERSION},
230 c = getopt_long(argc, argv, "012fgo[567]q[012]vw:z",
231 long_options, &option_index);
233 if (c == -1) break; /* end of parsing options */
240 /* set value by long option */
242 case '0': case '1': case '2':
244 opts.header_level = c - '0';
247 opts.force_extract = 1;
251 opts.header_level = 0;
254 /* compress method */
256 int idx = 1; /* -o means -lh1- method */
259 idx = *optarg - '0'; /* -lh[567]- method */
261 opts.method = &methods[idx];
266 opts.quiet = 2; /* -q is equivalent to -q2 */
268 opts.quiet = *optarg - '0';
276 /* extract directory */
278 error("extract directory does not specified for `-w'");
282 opts.outdir = optarg;
284 case 'z': /* no compress */
290 case LHA_OPT_VERSION:
306 error("Can't open temporary file");
312 op_add(int cmd, char *archive_file, int argc, char **argv)
314 int i, count, nfiles, found, done;
317 struct lzh_ostream w, *wp;
318 FILE *arcfile = NULL;
319 FILE *outfile = NULL;
323 count = done = nfiles = 0;
326 outfile = open_tempfile();
330 error("archived files are not specified.");
332 if (!opts.archive_to_stdio && (cmd == 'a' || cmd == 'u')) {
333 if (file_exists(archive_file)) {
334 arcfile = fopen(archive_file, "rb");
336 error("Can't open archive '%s'", archive_file);
341 for (i = 0; i < argc; i++) {
342 add(wp, 0, argv[i], strlen(argv[i]));
345 fputc(0, outfile); /* end of archive */
347 error("Can't write");
349 if (opts.archive_to_stdio) {
350 if (copy_stream(outfile, stdout) == -1)
351 error("fail to copy_stream_to_file(): temp -> %s","stdout");
354 if (copy_stream_to_file(outfile, archive_file) == -1)
355 error("fail to copy_stream_to_file(): temp -> %s",archive_file);
364 while (!done && read_header(arcfile, &h)) {
368 found = search(argc, argv, &h);
378 if (file_mtime(h.filename, &mtime) == -1 || h.mtime > mtime) {
379 copy(arcfile, outfile, &h);
384 if (add(wp, 1, h.filename, h.namelen)) {
389 copy(arcfile, outfile, &h);
392 copy(arcfile, outfile, &h);
397 message("'%s' deleted", h.filename);
401 copy(arcfile, outfile, &h);
406 for (i = 0; i < argc; i++) {
409 add(wp, 0, argv[i], strlen(argv[i]));
415 printf(" %d files\n", count);
419 fputc(0, outfile); /* end of archive */
421 error("Can't write");
422 if (!opts.archive_to_stdio)
423 unlink(archive_file);
427 if (copy_stream_to_file(outfile, archive_file) == -1)
428 error("fail to copy_stream_to_file(): temp -> %s",archive_file);
434 op_update(int cmd, char *archive_file, int argc, char **argv)
436 int i, count, nfiles, found, done;
439 struct lzh_ostream w, *wp;
440 FILE *arcfile = NULL;
441 FILE *outfile = NULL;
445 count = done = nfiles = 0;
448 outfile = open_tempfile();
452 error("archived files are not specified.");
454 if (!opts.archive_to_stdio && (cmd == 'a' || cmd == 'u')) {
455 if (file_exists(archive_file)) {
456 arcfile = fopen(archive_file, "rb");
458 error("Can't open archive '%s'", archive_file);
463 for (i = 0; i < argc; i++) {
464 add(wp, 0, argv[i], strlen(argv[i]));
467 fputc(0, outfile); /* end of archive */
469 error("Can't write");
471 if (opts.archive_to_stdio) {
472 if (copy_stream(outfile, stdout) == -1)
473 error("fail to copy_stream_to_file(): temp -> %s","stdout");
476 if (copy_stream_to_file(outfile, archive_file) == -1)
477 error("fail to copy_stream_to_file(): temp -> %s",archive_file);
486 while (!done && read_header(arcfile, &h)) {
490 found = search(argc, argv, &h);
500 if (file_mtime(h.filename, &mtime) == -1 || h.mtime > mtime) {
501 copy(arcfile, outfile, &h);
506 if (add(wp, 1, h.filename, h.namelen)) {
511 copy(arcfile, outfile, &h);
514 copy(arcfile, outfile, &h);
519 message("'%s' deleted", h.filename);
523 copy(arcfile, outfile, &h);
528 for (i = 0; i < argc; i++) {
531 add(wp, 0, argv[i], strlen(argv[i]));
537 printf(" %d files\n", count);
541 fputc(0, outfile); /* end of archive */
543 error("Can't write");
544 if (!opts.archive_to_stdio)
545 unlink(archive_file);
549 if (copy_stream_to_file(outfile, archive_file) == -1)
550 error("fail to copy_stream_to_file(): temp -> %s",archive_file);
556 op_create(int cmd, char *archive_file, int argc, char **argv)
559 struct lzh_ostream w, *wp;
560 FILE *outfile = NULL;
565 outfile = open_tempfile();
569 error("archived files are not specified.");
571 for (i = 0; i < argc; i++) {
572 add(wp, 0, argv[i], strlen(argv[i]));
575 fputc(0, outfile); /* end of archive */
577 error("Can't write");
579 if (opts.archive_to_stdio) {
580 if (copy_stream(outfile, stdout) == -1)
581 error("fail to copy_stream_to_file(): temp -> %s","stdout");
584 if (copy_stream_to_file(outfile, archive_file) == -1)
585 error("fail to copy_stream_to_file(): temp -> %s",archive_file);
593 op_delete(int cmd, char *archive_file, int argc, char **argv)
595 int count, nfiles, found, done;
598 struct lzh_ostream w, *wp;
599 FILE *arcfile = NULL;
600 FILE *outfile = NULL;
604 count = done = nfiles = 0;
608 message("No files given in argument, do nothing.");
611 outfile = open_tempfile();
614 if (opts.archive_to_stdio) {
618 arcfile = fopen(archive_file, "rb");
621 error("Can't open archive '%s'", archive_file);
626 while (!done && read_header(arcfile, &h)) {
630 found = search(argc, argv, &h);
635 message("'%s' deleted", h.filename);
639 copy(arcfile, outfile, &h);
646 printf(" %d files\n", count);
650 fputc(0, outfile); /* end of archive */
652 error("Can't write");
653 if (!opts.archive_to_stdio)
654 unlink(archive_file);
659 if (arc_count > count) {
660 if (copy_stream_to_file(outfile, archive_file) == -1)
661 error("fail to copy_stream_to_file(): temp -> %s",archive_file);
664 message("The archive file \"%s\" was removed because it would be empty.", archive_file);
672 op_extract(int cmd, char *archive_file, int argc, char **argv)
674 int count, nfiles, found, done;
677 struct lzh_istream r, *rp;
678 FILE *arcfile = NULL;
682 count = done = nfiles = 0;
688 if (opts.archive_to_stdio) {
692 arcfile = fopen(archive_file, "rb");
695 error("Can't open archive '%s'", archive_file);
700 /* change directory to extract dir */
703 if (mkdir(opts.outdir, 0777) == -1) {
705 error("cannot make directory \"%s\"", opts.outdir);
708 if (chdir(opts.outdir) == -1)
709 error("cannot change directory \"%s\"", opts.outdir);
715 while (!done && read_header(arcfile, &h)) {
719 found = search(argc, argv, &h);
725 rp->compsize = h.compsize;
726 extract(rp, cmd == 'x', &h);
727 if (++count == nfiles)
738 printf(" %d files\n", count);
743 op_list(int cmd, char *archive_file, int argc, char **argv)
745 int count, nfiles, found, done;
748 struct lzh_istream r, *rp;
749 FILE *arcfile = NULL;
753 count = done = nfiles = 0;
756 if (opts.archive_to_stdio) {
760 arcfile = fopen(archive_file, "rb");
763 error("Can't open archive '%s'", archive_file);
767 while (!done && read_header(arcfile, &h)) {
771 found = search(argc, argv, &h);
777 if (++count == nfiles)
784 printf(" %d files\n", count);
788 main(int argc, char *argv[])
793 INITIALIZE_OPTS(opts);
798 /*take a command character */
810 /* -<cmd> -<opts> ... */
815 /* -<cmd><opts> => -<opts> */
820 parse_args(argc, argv);
824 archive_file = argv[0];
826 if (strcmp(archive_file, "-") == 0)
827 opts.archive_to_stdio = 1;
828 if (opts.archive_to_stdio)
838 op_add(cmd, archive_file, argc, argv);
842 op_update(cmd, archive_file, argc, argv);
846 op_create(cmd, archive_file, argc, argv);
850 op_delete(cmd, archive_file, argc, argv);
855 op_extract(cmd, archive_file, argc, argv);
860 op_list(cmd, archive_file, argc, argv);