OSDN Git Service

support level 2 header (limited)
[lha/olha.git] / ar.c
1 /***********************************************************
2         ar.c -- main file
3 ***********************************************************/
4
5 static char *version = "0.01";
6
7 static char *usage =
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"
12     "Commands:\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";
22
23 /***********************************************************
24
25 Structure of archive block (low order byte first):
26 -----preheader
27  1      basic header size
28                 = 25 + strlen(filename) (= 0 if end of archive)
29  1      basic header algebraic sum (mod 256)
30 -----basic header
31  5      method ("-lh0-" = stored, "-lh5-" = compressed)
32  4      compressed size (including extended headers)
33  4      original size
34  4      not used
35  1      0x20
36  1      0x01
37  1      filename length (x)
38  x      filename
39  2      original file's CRC
40  1      0x20
41  2      first extended header size (0 if none)
42 -----first extended header, etc.
43 -----compressed file
44
45 ***********************************************************/
46
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <errno.h>
51 #include "ar.h"
52
53 struct lzh_header {
54     char filename[1024];
55     int  namelen;
56     char method[5];
57     int compsize;
58     int origsize;
59     int ftime;
60     int file_crc;
61     char os_id;
62     int level;
63 };
64
65 struct lha_method methods[] = {
66            /* id, dicbit, pbit, maxmatch */
67            /* note: dicbit == 0 means no compress */
68     /*0*/ {"-lh0-", 0,  0,  0},        /* no compress */
69     /*1*/ {"-lh1-", 12, 0, 60},        /* 2^12 =  4KB dynamic huffman (LHarc) */
70     /*2*/ {"-lh2-", 13, 0,256},        /* 2^13 =  8KB dynamic huffman */
71     /*3*/ {"-lh3-", 13, 0,256},        /* 2^13 =  8KB static huffman */
72     /*4*/ {"-lh4-", 12, 4,256},        /* 2^12 =  4KB static huffman (pos and len)*/
73     /*5*/ {"-lh5-", 13, 4,256},        /* 2^13 =  8KB static huffman (pos and len)*/
74     /*6*/ {"-lh6-", 15, 5,256},        /* 2^15 = 32KB static huffman (pos and len)*/
75     /*7*/ {"-lh7-", 16, 5,256},        /* 2^16 = 64KB static huffman (pos and len)*/
76     /*8*/ {"-lzs-", 11, 0, 17},        /* 2^11 =  2KB (LArc) */
77     /*9*/ {"-lz5-", 12, 0, 17},        /* 2^12 =  4KB (LArc) */
78     /*10*/{"-lz4-", 0,  0,  0},        /* no compress (LArc) */
79     /*11*/{"-lzd-", 0,  0,  0},        /* directory */
80 };
81
82 struct lha_opts opts;
83
84 struct lha_method *
85 which_method(char *id)
86 {
87     int i;
88
89     for (i = 0; i < sizeof(methods)/sizeof(methods[0]); i++) {
90         if (strncmp(id, methods[i].id, sizeof(methods[0].id)) == 0) {
91             return &methods[i];
92         }
93     }
94     return NULL;
95 }
96
97 init_opts()
98 {
99     opts.nocompress = 0;
100     opts.outdir = NULL;
101     opts.quiet = 0;
102     opts.header_level = 2;
103
104     /* default is the -lh5- method */
105     opts.method   = &methods[5];
106 }
107
108 #define FNAME_MAX (255 - 25)    /* max strlen(filename) */
109
110 int unpackable;                 /* global, set in io.c */
111 ulong compsize, origsize;       /* global */
112
113 static char *temp_name;
114
115 static void
116 print_usage()
117 {
118     printf("%s", usage);
119     exit(0);
120 }
121
122 static void
123 print_version()
124 {
125     printf("version %s\n", version);
126     exit(0);
127 }
128
129 static uint
130 ratio(ulong a, ulong b)
131 {                               /* [(1000a + [b/2]) / b] */
132     int i;
133
134     for (i = 0; i < 3; i++)
135         if (a <= ULONG_MAX / 10)
136             a *= 10;
137         else
138             b /= 10;
139     if ((ulong) (a + (b >> 1)) < a) {
140         a >>= 1;
141         b >>= 1;
142     }
143     if (b == 0)
144         return 0;
145     return (uint) ((a + (b >> 1)) / b);
146 }
147
148 static void
149 put_to_header(char *buf, int i, int n, ulong x)
150 {
151     while (--n >= 0) {
152         buf[i++] = (uchar) ((uint) x & 0xFF);
153         x >>= 8;
154     }
155 }
156
157 static ulong
158 get_from_header(char *buf, int i, int n)
159 {
160     ulong s;
161
162     s = 0;
163     while (--n >= 0)
164         s = (s << 8) + buf[i + n];   /* little endian */
165     return s;
166 }
167
168 static uint
169 calc_headersum(char *buf, int size)
170 {
171     int i;
172     uint s;
173
174     s = 0;
175     for (i = 0; i < size; i++)
176         s += buf[i];
177     return s & 0xFF;
178 }
179
180 int
181 get_byte(char *buf)
182 {
183     return *(unsigned char*)buf;
184 }
185
186 uint16_t
187 get_word(char *buf)
188 {
189     return get_byte(buf) | (get_byte(buf+1) << 8);
190 }
191
192 uint32_t
193 get_dword(char *buf)
194 {
195     return get_byte(buf) |
196         (get_byte(buf+1) << 8) |
197         (get_byte(buf+2) << 16) |
198         (get_byte(buf+3) << 24);
199 }
200
201 void
202 get_char(char *buf, char *p, size_t size)
203 {
204     memcpy(p, buf, size);
205 }
206
207 void
208 put_byte(char *buf, int c)
209 {
210     *buf = (unsigned char)(c & 0xff);
211 }
212
213 void
214 put_word(char *buf, uint16_t c)
215 {
216     put_byte(buf,   c);
217     put_byte(buf+1, c>>8);
218 }
219
220 void
221 put_dword(char *buf, uint32_t c)
222 {
223     put_byte(buf, c);
224     put_byte(buf+1, c>>8);
225     put_byte(buf+2, c>>16);
226     put_byte(buf+3, c>>24);
227 }
228
229 void
230 put_char(char *buf, char *p, size_t size)
231 {
232     memcpy(buf, p, size);
233 }
234
235 static int
236 read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
237 {
238     int headersize;
239     int headersum;
240     int ext_headersize;
241
242     headersize = get_byte(&buf[0]);
243     headersum = get_byte(&buf[1]);
244
245     fread_crc(buf + 21, headersize - (21 - 2), fp);     /* CRC not used */
246
247     buf += 2;
248
249     if (calc_headersum(buf, headersize) != headersum)
250         error("Header sum error");
251
252     get_char(&buf[0], h->method, 5);
253     h->compsize = get_dword(&buf[5]);
254     h->origsize = get_dword(&buf[9]);
255     h->ftime    = get_dword(&buf[13]);
256     /* attrib   = get_byte(&buf[17]); */
257     h->level    = get_byte(&buf[18]); /* header level */
258     h->namelen = get_byte(&buf[19]);
259     get_char(&buf[20], h->filename, h->namelen);
260     h->filename[h->namelen] = 0;
261     h->file_crc = get_word(&buf[20+h->namelen]);
262     h->os_id    = get_byte(&buf[20+h->namelen+2]);
263
264     ext_headersize = get_word(&buf[20+h->namelen+3]);
265
266     while (ext_headersize != 0) {
267         fprintf(stderr, "There's an extended header of size %u.\n",
268                 ext_headersize);
269         h->compsize -= ext_headersize;
270
271         /* skip ext header */
272         if (fseek(arcfile, ext_headersize - 2, SEEK_CUR))
273             error("Can't read");
274         ext_headersize = fgetc(arcfile);
275         ext_headersize += (uint) fgetc(arcfile) << 8;
276     }
277
278     return 1;                   /* success */
279 }
280
281 static int
282 read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
283 {
284     int headersize;
285     int headersum;
286     int ext_headersize;
287     char extbuf[1024];
288     uchar ext_type;
289     int remainder;
290
291     headersize = get_word(&buf[0]);
292
293     fread_crc(buf + 21, 26 - 21, fp);     /* CRC not used */
294
295     get_char(&buf[2], h->method, 5);
296     h->compsize = get_dword(&buf[7]);
297     h->origsize = get_dword(&buf[11]);
298     h->ftime    = get_dword(&buf[15]);
299     /* attrib   = get_byte(&buf[19]); */
300     h->level    = get_byte(&buf[20]); /* header level */
301     h->file_crc = get_word(&buf[21]);
302     h->os_id    = get_byte(&buf[23]);
303
304     ext_headersize = get_word(&buf[24]);
305
306     remainder = headersize - 26;
307
308     while (ext_headersize != 0) {
309         char *p = extbuf;
310
311         remainder -= ext_headersize;
312
313         fread_crc(p, ext_headersize, fp);
314         ext_type = get_byte(p++);
315         switch (ext_type) {
316         case 0:
317             /* header crc */
318             break;
319         case 1:
320             /* filename header */
321             h->namelen = ext_headersize - 3;
322             get_char(p, h->filename, h->namelen);
323             h->filename[h->namelen] = 0;
324             break;
325         case 2:
326             /* dirname header */
327             break;
328         }
329         ext_headersize = get_word(&extbuf[ext_headersize - 2]);
330     }
331
332     while (remainder > 0) {
333         fgetc(fp); /* skip padding */
334         remainder--;
335     }
336
337     return 1;                   /* success */
338 }
339
340 static int
341 read_header(FILE *fp, struct lzh_header *h)
342 {
343     int headersize;
344     int headersum;
345     char buf[4096];
346     int ext_headersize;
347     int ret;
348
349     ret = fgetc(fp);
350     buf[0] = (uchar)ret;
351     if (buf[0] == 0 || ret == EOF)
352         return 0;               /* end of archive */
353     fread_crc(buf + 1, 21 - 1, fp);
354     switch (buf[20]) {
355     case 0:
356         break;
357     case 1:
358         return read_header_lv1(fp, buf, h);
359         break;
360     case 2:
361         return read_header_lv2(fp, buf, h);
362         break;
363     default:
364         error("unknown level (%d)\n", buf[20]);
365         break;
366     }
367
368     return 1;                   /* success */
369 }
370
371
372 void
373 write_header_lv0(FILE *fp, struct lzh_header *h)
374 {
375 }
376
377 void
378 write_header_lv1(FILE *fp, struct lzh_header *h)
379 {
380     char buf[4096], *p = buf;
381     int sum;
382     int headersize;
383
384     headersize = 25 + h->namelen;
385
386     put_byte(&buf[0], headersize);
387     put_byte(&buf[1], 0); /* dummy */
388     put_char(&buf[2], h->method, 5);
389     put_dword(&buf[7], h->compsize);   /* packed size */
390     put_dword(&buf[11], h->origsize);   /* original size */
391     put_dword(&buf[15], h->ftime);   /* ftime */
392     put_byte(&buf[19], 0x20);   /* attribute */
393     put_byte(&buf[20], 1);  /* level */
394     put_byte(&buf[21], h->namelen); /* length of pathname */
395     put_char(&buf[22], h->filename, h->namelen);
396     put_word(&buf[22+h->namelen], h->file_crc);
397     put_byte(&buf[22+h->namelen+2], 'M');
398     put_word(&buf[22+h->namelen+3], 0x0000); /* next header size */
399
400     sum = calc_headersum(buf+2, headersize);
401     put_byte(&buf[1], sum);
402
403     fwrite_crc(buf, headersize+2, fp);
404 }
405
406 void
407 write_header_lv2(FILE *fp, struct lzh_header *h)
408 {
409     char buf[4096], *p = buf, *crcptr;
410     int sum;
411     int headersize, next_headersize;
412     extern ushort crctable[];
413
414     put_word(&buf[0], 0);       /* dummy */
415     put_char(&buf[2], h->method, 5);
416     put_dword(&buf[7], h->compsize);    /* packed size */
417     put_dword(&buf[11], h->origsize);   /* original size */
418     put_dword(&buf[15], h->ftime);      /* time_t */
419     put_byte(&buf[19], 0x20);           /* DOS attribute (0x20 fixed) */
420     put_byte(&buf[20], 2);              /* level */
421     put_word(&buf[21], h->file_crc);
422     put_byte(&buf[23], 'M');
423
424     headersize = 24;
425
426     /* ext-header */
427     p = buf + headersize;
428     next_headersize = 3 + 2;
429     put_word(p, next_headersize); /* next header size */
430     put_byte(p+2, 0);             /* 0x00: header crc */
431     crcptr = p+3;
432     put_word(p+3, 0);             /* crc (dummy) */
433     headersize += next_headersize;
434
435     p = buf + headersize;
436     next_headersize = 3 + h->namelen;
437     put_word(p, next_headersize);      /* next header size */
438     put_byte(p+2, 1);                  /* 0x01: filename header */
439     put_char(p+3, h->filename, h->namelen); /* filename */
440     headersize += next_headersize;
441
442 #if 0
443     p = buf + headersize;
444     next_headersize = 3 + h->namelen;
445     put_word(p, next_headersize); /* next header size */
446     put_byte(p+2, 2);             /* 0x02: dirname header */
447     put_char(p+3, x, len);        /* dirname */
448     headersize += next_headersize;
449 #endif
450
451     p = buf + headersize;
452     next_headersize = 0;
453     put_word(p, next_headersize); /* next header size */
454     headersize += next_headersize;
455     headersize += 2;
456
457     /* padding */
458     if (headersize % 256 == 0) {
459         put_byte(&buf[headersize], 0);
460         headersize++;
461     }
462
463     put_word(&buf[0], headersize);
464
465     crc = INIT_CRC;
466     for (p = buf; p - buf < headersize; p++)
467         UPDATE_CRC(*p);
468
469     put_word(crcptr, crc);
470
471     fwrite_crc(buf, headersize, fp);
472 }
473
474 void
475 write_header(FILE *fp, struct lzh_header *h)
476 {
477     switch (h->level) {
478     case 0:
479         write_header_lv0(fp, h);
480         break;
481     case 1:
482         write_header_lv1(fp, h);
483         break;
484     case 2:
485         write_header_lv2(fp, h);
486         break;
487     default:
488         error("unknown level (%d)", h->level);
489         break;
490     }
491 }
492
493 static void
494 skip(FILE *fp, struct lzh_header *h)
495 {
496     fseek(fp, h->compsize, SEEK_CUR);
497 }
498
499 static void
500 copy(FILE *arcfile, FILE *outfile, struct lzh_header *h)
501 {
502     uint n;
503     uchar buffer[MAXDICSIZ];
504
505     write_header(outfile, h);
506     while (h->compsize != 0) {
507         n = (uint) ((h->compsize > sizeof(buffer)) ? sizeof(buffer) : h->compsize);
508         if (fread((char *) buffer, 1, n, arcfile) != n)
509             error("Can't read");
510         if (fwrite((char *) buffer, 1, n, outfile) != n)
511             error("Can't write");
512         h->compsize -= n;
513     }
514 }
515
516 static void
517 store(void)
518 {
519     uint n;
520     uchar buffer[MAXDICSIZ];
521
522     origsize = 0;
523     crc = INIT_CRC;
524     while ((n = fread((char *) buffer, 1, sizeof(buffer), infile)) != 0) {
525         fwrite_crc(buffer, n, outfile);
526         origsize += n;
527     }
528     compsize = origsize;
529 }
530
531 static int
532 add(int replace_flag, char *filename)
533 {
534     long headerpos, arcpos;
535     uint r;
536     struct lzh_header h;
537
538     h.level = opts.header_level;
539
540     if ((infile = fopen(filename, "rb")) == NULL) {
541         fprintf(stderr, "Can't open %s\n", filename);
542         return 0;               /* failure */
543     }
544     if (replace_flag) {
545         if (opts.quiet < 2)
546             printf("Replacing %s ", filename);
547         skip(arcfile, &h);
548     }
549     else {
550         if (opts.quiet < 2)
551             printf("Adding %s ", filename);
552     }
553
554     strcpy(h.filename, filename);
555     h.namelen = strlen(filename);
556
557     memcpy(h.method, opts.method->id, sizeof(h.method));  /* compress */
558
559     headerpos = ftell(outfile);
560     write_header(outfile, &h);
561     arcpos = ftell(outfile);
562
563     origsize = compsize = 0;
564     crc = INIT_CRC;
565     if (opts.nocompress) {
566         unpackable = 1;
567     }
568     else {
569         unpackable = 0;
570         encode();
571     }
572
573     if (unpackable) {
574         h.method[3] = '0';        /* store */
575         rewind(infile);
576         fseek(outfile, arcpos, SEEK_SET);
577         store();
578     }
579     h.file_crc = crc ^ INIT_CRC;
580     fclose(infile);
581
582     h.compsize = compsize;
583     h.origsize = origsize;
584
585     fseek(outfile, headerpos, SEEK_SET);
586     write_header(outfile, &h);
587     fseek(outfile, 0L, SEEK_END);
588     r = ratio(compsize, origsize);
589     if (opts.quiet < 2)
590         printf(" %d.%d%%\n", r / 10, r % 10);
591     return 1;                   /* success */
592 }
593
594 int
595 get_line(char *s, int n)
596 {
597     int i, c;
598
599     i = 0;
600     while ((c = getchar()) != EOF && c != '\n')
601         if (i < n)
602             s[i++] = (char) c;
603     s[i] = '\0';
604     return i;
605 }
606
607 static void
608 extract(int to_file, struct lzh_header *h)
609 {
610     int n;
611     uint ext_headersize;
612     uchar buffer[MAXDICSIZ];
613
614     if (to_file) {
615         while ((outfile = fopen(h->filename, "wb")) == NULL) {
616             fprintf(stderr, "Can't open %s\nNew filename: ", h->filename);
617             if (get_line(h->filename, FNAME_MAX) == 0) {
618                 fprintf(stderr, "Not extracted\n");
619                 skip(arcfile, h);
620                 return;
621             }
622             h->namelen = strlen(h->filename);
623         }
624         if (opts.quiet < 2)
625             printf("Extracting %s ", h->filename);
626     }
627     else {
628         outfile = stdout;
629         if (opts.quiet < 2)
630             printf("===== %s =====\n", h->filename);
631     }
632     crc = INIT_CRC;
633     opts.method = which_method(h->method);
634     if (opts.method == NULL) {
635         fprintf(stderr, "Unknown method: %.5s\n", h->method);
636         skip(arcfile, h);
637     }
638     else {
639         crc = INIT_CRC;
640         if (opts.method->dicbit != 0)
641             decode_start();
642         while (h->origsize != 0) {
643             n = (uint) ((h->origsize > MAXDICSIZ) ? MAXDICSIZ : h->origsize);
644             if (opts.method->dicbit != 0)
645                 decode(n, buffer);
646             else if (fread((char *) buffer, 1, n, arcfile) != n)
647                 error("Can't read");
648             fwrite_crc(buffer, n, outfile);
649             if (outfile != stdout && opts.quiet < 1) {
650                 putc('.', stdout);
651             }
652             h->origsize -= n;
653         }
654     }
655     if (to_file)
656         fclose(outfile);
657     else
658         outfile = NULL;
659     if ((crc ^ INIT_CRC) != h->file_crc)
660         fprintf(stderr, "CRC error\n");
661 }
662
663 static void
664 list_start(void)
665 {
666     if (opts.quiet < 2)
667         printf("Filename         Original Compressed Ratio CRC Method\n");
668 }
669
670 static void
671 list(struct lzh_header *h)
672 {
673     uint r;
674
675     printf("%-14.*s", h->namelen, h->filename);
676     if (h->namelen > 14)
677         printf("\n              ");
678     r = ratio(h->compsize, h->origsize);
679     printf(" %10lu %10lu %u.%03u %04X %5.5s\n",
680            h->origsize, h->compsize, r / 1000, r % 1000, h->file_crc, h->method);
681 }
682
683 static int
684 match(char *s1, char *s2)
685 {
686     for (;;) {
687         while (*s2 == '*' || *s2 == '?') {
688             if (*s2++ == '*')
689                 while (*s1 && *s1 != *s2)
690                     s1++;
691             else if (*s1 == 0)
692                 return 0;
693             else
694                 s1++;
695         }
696         if (*s1 != *s2)
697             return 0;
698         if (*s1 == 0)
699             return 1;
700         s1++;
701         s2++;
702     }
703 }
704
705 static int
706 search(int argc, char *argv[], struct lzh_header *h)
707 {
708     int i;
709
710     if (argc == 0)
711         return 1;
712     for (i = 0; i < argc; i++)
713         if (match(h->filename, argv[i]))
714             return 1;
715     return 0;
716 }
717
718 static void
719 exitfunc(void)
720 {
721     fclose(outfile);
722     remove(temp_name);
723 }
724
725 #include "getopt_long.h"
726
727 int
728 parse_args(int argc, char **argv)
729 {
730     int c;
731
732     for (;;) {
733         int this_option_optind = optind ? optind : 1;
734         int option_index = 0;
735
736         enum {
737             LHA_OPT_HELP = 128,
738             LHA_OPT_VERSION,
739         };
740
741         static struct option long_options[] = {
742             /* name, has_arg, *flag, val */
743             /* has_arg:
744                no_argument (0)
745                required_argument (1)
746                optional_argument (2)
747                flag:
748                NULL: getopt_long() return val
749                non-NULL: getopt_long() return 0, and *flag set val.
750             */
751             {"help", no_argument, NULL, LHA_OPT_HELP},
752             {"version", no_argument, NULL, LHA_OPT_VERSION},
753             {0, 0, 0, 0}
754         };
755
756         c = getopt_long(argc, argv, "h[012]o[567]q[012]w:z",
757                         long_options, &option_index);
758
759         if (c == -1) break;     /* end of parsing options */
760
761         switch (c) {
762         case 0:
763             /* set value by long option */
764             break;
765         case 'h':
766             /* header level */
767             opts.header_level = 2;     /* -h is equivalent to -h2 */
768             if (optarg)
769                 opts.header_level = *optarg - '0';
770             break;
771         case 'o':
772             /* compress method */
773             {
774                 int idx = 1;    /* -o means -lh1- method */
775
776                 if (optarg)
777                     idx = *optarg - '0'; /* -lh[567]- method */
778
779                 opts.method   = &methods[idx];
780             }
781             break;
782         case 'q':
783             /* quiet mode */
784             opts.quiet = 2;     /* -q is equivalent to -q2 */
785             if (optarg)
786                 opts.quiet = *optarg - '0';
787             break;
788         case 'w':
789             /* extract directory */
790             if (!optarg)
791                 error("extract directory does not specified for `-w'");
792             if (*optarg == '=')
793                 optarg++;
794
795             opts.outdir = optarg;
796             break;
797         case 'z':               /* no compress */
798             opts.nocompress = 1;
799             break;
800         case LHA_OPT_HELP:
801             print_usage();
802             break;
803         case LHA_OPT_VERSION:
804             print_version();
805             break;
806         default:
807             break;
808         }
809     }
810 }
811
812 FILE *
813 open_tempfile()
814 {
815     temp_name = tmpnam(NULL);
816     outfile = fopen(temp_name, "wb");
817     if (outfile == NULL)
818         error("Can't open temporary file");
819     atexit(exitfunc);
820
821     return outfile;
822 }
823
824 int
825 main(int argc, char *argv[])
826 {
827     int i, j, cmd, count, nfiles, found, done;
828     char *archive_file;
829     struct lzh_header h;
830
831     init_opts();
832
833     if (argv[1] == 0)
834         print_usage();
835
836     /*take a command character */
837     {
838         char *arg1;
839
840         arg1 = argv[1];
841         if (arg1[0] == '-')
842             arg1++;
843         if (arg1[0] == 0)
844             print_usage();
845
846         cmd = *arg1;
847         if (arg1[1] == 0) {
848             /* -<cmd> -<opts> ... */
849             argv++;
850             argc--;
851         }
852         else {
853             /* -<cmd><opts> => -<opts> */
854             *arg1 = '-';
855         }
856     }
857
858     parse_args(argc, argv);
859     argv += optind;
860     argc -= optind;
861
862     archive_file = argv[0];
863
864     argv++;
865     argc--;
866
867     temp_name = NULL;
868
869     make_crctable();
870     count = done = nfiles = 0;
871
872     switch (cmd) {
873     case 'a':
874     case 'c':
875         outfile = open_tempfile();
876         if (*argv == 0)
877             error("archived files are not specified.");
878         for (i = 0; i < argc; i++) {
879             add(0, argv[i]);
880         }
881
882         fputc(0, outfile);      /* end of archive */
883         if (ferror(outfile))
884             error("Can't write");
885         remove(archive_file);
886         if (rename(temp_name, archive_file) == -1)
887             error("fail to rename()");
888
889         exit(0);
890         break;
891     case 'r':
892     case 'd':
893         outfile = open_tempfile();
894     case 'x':
895     case 'p':
896     case 'l':
897     case 'v':
898         /* Open archive. */
899         arcfile = fopen(archive_file, "rb");
900         if (arcfile == NULL)
901             error("Can't open archive '%s'", argv[2]);
902
903         break;
904     default:
905         print_usage();
906         break;
907     }
908
909     /* change directory to extract dir */
910     if (cmd == 'x') {
911         struct stat *stbuf;
912
913         if (opts.outdir) {
914             if (mkdir(opts.outdir, 0777) == -1) {
915                 if (errno != EEXIST)
916                     error("cannot make directory \"%s\"", opts.outdir);
917             }
918
919             if (chdir(opts.outdir) == -1)
920                 error("cannot change directory \"%s\"", opts.outdir);
921         }
922     }
923
924     while (!done && read_header(arcfile, &h)) {
925
926         compsize = h.compsize;
927         origsize = h.origsize;
928
929         found = search(argc, argv, &h);
930         switch (cmd) {
931         case 'r':
932             if (found) {
933                 if (add(1, *argv))
934                     count++;
935                 else
936                     copy(arcfile, outfile, &h);
937             }
938             else
939                 copy(arcfile, outfile, &h);
940             break;
941         case 'a':
942         case 'd':
943             if (found) {
944                 count += (cmd == 'D');
945                 skip(arcfile, &h);
946             }
947             else
948                 copy(arcfile, outfile, &h);
949             break;
950         case 'x':
951         case 'p':
952             if (found) {
953                 extract(cmd == 'x', &h);
954                 if (++count == nfiles)
955                     done = 1;
956             }
957             else
958                 skip(arcfile, &h);
959             break;
960         case 'l':
961         case 'v':
962             if (found) {
963                 if (count == 0)
964                     list_start();
965                 list(&h);
966                 if (++count == nfiles)
967                     done = 1;
968             }
969             skip(arcfile, &h);
970             break;
971         }
972     }
973
974     if (cmd != 'p') {
975         if (opts.quiet < 2)
976             printf("  %d files\n", count);
977     }
978     return EXIT_SUCCESS;
979 }