OSDN Git Service

* src/header.c (get_header): the variable "noconvertcase" changed
[lha/lha.git] / src / lharc.c
1 /* ------------------------------------------------------------------------ */
2 /* LHa for UNIX                                                             */
3 /*              lharc.c -- append to archive                                */
4 /*                                                                          */
5 /*      Copyright (C) MCMLXXXIX Yooichi.Tagawa                              */
6 /*      Modified                Nobutaka Watazaki                           */
7 /*                          Thanks to H.Yoshizaki. (MS-DOS LHarc)           */
8 /*                                                                          */
9 /*  Ver. 0.00  Original                         1988.05.23  Y.Tagawa        */
10 /*  Ver. 0.01  Alpha Version (for 4.2BSD)       1989.05.28  Y.Tagawa        */
11 /*  Ver. 0.02  Alpha Version Rel.2              1989.05.29  Y.Tagawa        */
12 /*  Ver. 0.03  Release #3  Beta Version         1989.07.02  Y.Tagawa        */
13 /*  Ver. 0.03a Debug                            1989.07.03  Y.Tagawa        */
14 /*  Ver. 0.03b Modified                         1989.07.13  Y.Tagawa        */
15 /*  Ver. 0.03c Debug (Thanks to void@rena.dit.junet)                        */
16 /*                                              1989.08.09  Y.Tagawa        */
17 /*  Ver. 0.03d Modified (quiet and verbose)     1989.09.14  Y.Tagawa        */
18 /*  V1.00  Fixed                                1989.09.22  Y.Tagawa        */
19 /*  V1.01  Bug Fixed                            1989.12.25  Y.Tagawa        */
20 /*                                                                          */
21 /*  DOS-Version Original LHx V C2.01        (C) H.Yohizaki                  */
22 /*                                                                          */
23 /*  V2.00  UNIX Lharc + DOS LHx -> OSK LHx      1990.11.01  Momozou         */
24 /*  V2.01  Minor Modified                       1990.11.24  Momozou         */
25 /*                                                                          */
26 /*  Ver. 0.02  LHx for UNIX                     1991.11.18  M.Oki           */
27 /*  Ver. 0.03  LHa for UNIX                     1991.12.17  M.Oki           */
28 /*  Ver. 0.04  LHa for UNIX beta version        1992.01.20  M.Oki           */
29 /*  Ver. 1.00  LHa for UNIX Fixed               1992.03.19  M.Oki           */
30 /*                                                                          */
31 /*  Ver. 1.10  for Symbolic Link                1993.06.25  N.Watazaki      */
32 /*  Ver. 1.11  for Symbolic Link Bug Fixed      1993.08.18  N.Watazaki      */
33 /*  Ver. 1.12  for File Date Check              1993.10.28  N.Watazaki      */
34 /*  Ver. 1.13  Bug Fixed (Idicator calcurate)   1994.02.21  N.Watazaki      */
35 /*  Ver. 1.13a Bug Fixed (Sym. Link delete)     1994.03.11  N.Watazaki      */
36 /*  Ver. 1.13b Bug Fixed (Sym. Link delete)     1994.07.29  N.Watazaki      */
37 /*  Ver. 1.14  Source All chagned               1995.01.14  N.Watazaki      */
38 /*  Ver. 1.14b,c  Bug Fixed                     1996.03.07  t.okamoto       */
39 /*  Ver. 1.14d Version up                       1997.01.12  t.okamoto       */
40 /*  Ver. 1.14g Bug Fixed                        2000.05.06  t.okamoto       */
41 /*  Ver. 1.14i Modified                         2000.10.06  t.okamoto       */
42 /* ------------------------------------------------------------------------ */
43 #define LHA_MAIN_SRC
44
45 #include "lha.h"
46
47 static int      cmd = CMD_UNKNOWN;
48 static int error_occurred;
49
50 /* static functions */
51 static void     sort_files();
52 static void     print_version();
53
54 extern int optional_archive_kanji_code;
55 extern int optional_system_kanji_code;
56
57 /* ------------------------------------------------------------------------ */
58 static void
59 init_variable()     /* Added N.Watazaki */
60 {
61 /* options */
62     quiet           = FALSE;
63     text_mode       = FALSE;
64     verbose         = 0;
65     noexec          = FALSE;    /* debugging option */
66     force           = FALSE;
67
68     compress_method = DEFAULT_LZHUFF_METHOD; /* defined in config.h */
69
70     header_level    = 2;        /* level 2 */
71     quiet_mode      = 0;
72
73 #ifdef EUC
74     euc_mode        = FALSE;
75 #endif
76
77 /* view command flags */
78     verbose_listing = FALSE;
79
80 /* extract command flags */
81     output_to_stdout = FALSE;
82
83 /* append command flags */
84     new_archive         = FALSE;
85     update_if_newer     = FALSE;
86     delete_after_append = FALSE;
87     generic_format      = FALSE;
88
89     recover_archive_when_interrupt          = FALSE;
90     remove_extracting_file_when_interrupt   = FALSE;
91     get_filename_from_stdin                 = FALSE;
92     ignore_directory                        = FALSE;
93     exclude_files                           = NULL;
94     verify_mode                             = FALSE;
95
96     convertcase                             = FALSE;
97
98     extract_directory = NULL;
99     temporary_fd = -1;
100
101 #if BACKUP_OLD_ARCHIVE
102     backup_old_archive = TRUE;
103 #else
104     backup_old_archive = FALSE;
105 #endif
106
107     extract_broken_archive = FALSE;
108     decode_macbinary_contents = FALSE;
109 }
110
111 /* ------------------------------------------------------------------------ */
112 /* NOTES :          Text File Format                                        */
113 /* GENERATOR        NewLine                                                 */
114 /* [generic]        0D 0A                                                   */
115 /* [MS-DOS]         0D 0A                                                   */
116 /* [OS9][MacOS]     0D                                                      */
117 /* [UNIX]           0A                                                      */
118 /* ------------------------------------------------------------------------ */
119 static void
120 print_tiny_usage()
121 {
122 #if HAVE_LIBAPPLEFILE
123     fprintf(stdout, "\
124 usage: lha [-]<commands>[<options>] [-<options> ...] archive_file [file...]\n\
125   commands:  [axelvudmcpt]\n\
126   options:   [q[012]vnfto[567]dizg012eb[w=<dir>|x=<pattern>]]\n\
127   long options: --system-kanji-code={euc,sjis,utf8,cap}\n\
128                 --archive-kanji-code={euc,sjis,utf8,cap}\n\
129                 --extract-broken-archive\n\
130                 --convert-filename-case\n\
131                 --help\n\
132                 --version\n");
133 #else
134     fprintf(stdout, "\
135 usage: lha [-]<commands>[<options>] [-<options> ...] archive_file [file...]\n\
136   commands:  [axelvudmcpt]\n\
137   options:   [q[012]vnfto[567]dizg012e[w=<dir>|x=<pattern>]]\n\
138   long options: --system-kanji-code={euc,sjis,utf8,cap}\n\
139                 --archive-kanji-code={euc,sjis,utf8,cap}\n\
140                 --extract-broken-archive\n\
141                 --convert-filename-case\n\
142                 --help\n\
143                 --version\n");
144 #endif
145 }
146
147 static void
148 print_usage()
149 {
150     fprintf(stdout, "\
151 LHarc    for UNIX  V 1.02  Copyright(C) 1989  Y.Tagawa\n\
152 LHx      for MSDOS V C2.01 Copyright(C) 1990  H.Yoshizaki\n\
153 LHx(arc) for OSK   V 2.01  Modified     1990  Momozou\n\
154 LHa      for UNIX  V 1.00  Copyright(C) 1992  Masaru Oki\n\
155 LHa      for UNIX  V 1.14  Modified     1995  Nobutaka Watazaki\n\
156 LHa      for UNIX  V 1.14i Modified     2000  Tsugio Okamoto\n\
157                    Autoconfiscated 2001-2007  Koji Arai\n\
158 ");
159
160     print_tiny_usage();
161
162     fprintf(stdout, "\
163 commands:                           options:\n\
164  a   Add(or replace) to archive      q{num} quiet (num:quiet mode)\n\
165  x,e EXtract from archive            v  verbose\n\
166  l,v List / Verbose List             n  not execute\n\
167  u   Update newer files to archive   f  force (over write at extract)\n\
168  d   Delete from archive             t  FILES are TEXT file\n");
169 #ifdef SUPPORT_LH7
170     fprintf(stdout, "\
171  m   Move to archive (means 'ad')    o[567] compression method (a/u/c)\n\
172 ");
173 #endif
174 #ifndef SUPPORT_LH7
175     fprintf(stdout, "\
176  m   Move to archive (means 'ad')    o  use LHarc compatible method (a/u/c)\n\
177 ");
178 #endif
179     fprintf(stdout, "\
180  c   re-Construct new archive        d  delete FILES after (a/u/c)\n\
181  p   Print to STDOUT from archive    i  ignore directory path (x/e)\n\
182  t   Test file CRC in archive        z  files not compress (a/u/c)\n\
183                                      g  Generic format (for compatibility)\n\
184                                      0/1/2 header level (a/u/c)\n\
185 ");
186 #ifdef EUC
187     fprintf(stdout, "\
188                                      e  TEXT code convert from/to EUC\n\
189 ");
190 #endif
191 #if HAVE_LIBAPPLEFILE
192     fprintf(stdout, "\
193                                      b  decode MacBinary (x/e)\n\
194 ");
195 #endif
196     fprintf(stdout, "\
197                                      w=<dir> specify extract directory (x/e)\n\
198                                      x=<pattern>  eXclude files (a/u/c)\n\
199 ");
200 #if IGNORE_DOT_FILES            /* experimental feature */
201     fprintf(stdout, "\
202                                      X ignore dot files (a/u/c)\n\
203 ");
204 #endif
205 }
206
207 #include "getopt_long.h"
208
209 /*
210   Parse LHA options
211 */
212 static int
213 parse_suboption(int argc, char **argv)
214 {
215     enum {
216         HELP_OPTION = 256,
217         VERSION_OPTION,
218         SYSTEM_KANJI_CODE_OPTION,
219         ARCHIVE_KANJI_CODE_OPTION,
220     };
221
222     struct option long_options[] = {
223         /* These options set a flag. */
224         {"help",    no_argument,       0, HELP_OPTION},
225         {"version", no_argument,       0, VERSION_OPTION},
226
227         {"system-kanji-code", required_argument, 0, SYSTEM_KANJI_CODE_OPTION},
228         {"archive-kanji-code", required_argument, 0, ARCHIVE_KANJI_CODE_OPTION},
229         {"extract-broken-archive", no_argument, &extract_broken_archive, 1},
230         {"convert-filename-case", no_argument, &convertcase, TRUE},
231         {0, 0, 0, 0}
232     };
233     int i;
234
235     char short_options[256] = "q[012]vnfto[567]dizg012ew:x:";
236     /* "[...]" means optional 1 byte argument (original extention) */
237
238 #if IGNORE_DOT_FILES
239     strncat(short_options, "X", sizeof(short_options)-strlen(short_options)-1);
240 #endif
241 #if HAVE_LIBAPPLEFILE
242     strncat(short_options, "b", sizeof(short_options)-strlen(short_options)-1);
243 #endif
244
245     /* parse option */
246     while (1) {
247         int option_index = 0;
248         int c = getopt_long(argc, argv,
249                             short_options, long_options,
250                             &option_index);
251
252         if (c == -1) break;     /* end of options */
253
254         switch (c) {
255         case 0:
256             /* Already set a flag variable by the definition of the
257                long_options. */
258             break;
259         case '?':
260             /* Invalid option */
261             print_tiny_usage();
262             exit(2);
263         case HELP_OPTION:
264             print_usage();
265             exit(0);
266         case VERSION_OPTION:
267             print_version();
268             exit(0);
269         case 'q':
270             if (!optarg) {
271                 /* In quiet mode, no confirm to overwrite */
272                 force = TRUE;
273                 quiet = TRUE;
274                 break;
275             }
276
277             switch (*optarg) {
278             case '0':           /* no quiet */
279             case '1':           /* no use the incremental indicator */
280                 quiet_mode = *optarg - '0';
281                 break;
282             case '2':           /* no output */
283                 /* fall through */
284             default:
285                 force = TRUE;
286                 quiet = TRUE;
287                 break;
288             }
289             break;
290         case 'f':
291             force = TRUE;
292             break;
293         case 'v':
294             verbose++;
295             break;
296         case 't':
297             text_mode = TRUE;
298             break;
299 #ifdef EUC
300         case 'e':
301             text_mode = TRUE;
302             euc_mode = TRUE;
303             break;
304 #endif
305 #if HAVE_LIBAPPLEFILE
306         case 'b':
307             decode_macbinary_contents = TRUE;
308             break;
309 #endif
310         case 'n':
311             noexec = TRUE;
312             break;
313         case 'g':
314             generic_format = TRUE;
315             header_level = 0;
316             break;
317         case 'd':
318             delete_after_append = TRUE;
319             break;
320         case 'o':
321             if (!optarg) {
322                 compress_method = LZHUFF1_METHOD_NUM;
323                 header_level = 0;
324                 break;
325             }
326             switch (*optarg) {
327             case '5':
328                 compress_method = LZHUFF5_METHOD_NUM;
329                 break;
330 #ifdef SUPPORT_LH7
331             case '6':
332                 compress_method = LZHUFF6_METHOD_NUM;
333                 break;
334             case '7':
335                 compress_method = LZHUFF7_METHOD_NUM;
336                 break;
337 #endif
338             default:
339                 error("invalid compression method 'o%c'", *optarg);
340                 return -1;
341             }
342             break;
343         case 'z':
344             compress_method = LZHUFF0_METHOD_NUM;   /* Changed N.Watazaki */
345             break;
346         case 'i':
347             ignore_directory = TRUE;
348             break;
349         case 'x':
350             if (!optarg) {
351                 error("exclude files does not specified for `-x'");
352                 exit(2);
353             }
354
355             for (i = 0; exclude_files && exclude_files[i]; i++)
356                 ;
357             exclude_files = (char**)xrealloc(exclude_files,
358                                              sizeof(char*) * (i+2));
359
360             if (*optarg == '=')
361                 optarg++;
362             exclude_files[i] = optarg;
363             exclude_files[i+1] = 0;
364
365             break;
366 #if IGNORE_DOT_FILES            /* experimental feature */
367         case 'X':
368             for (i = 0; exclude_files && exclude_files[i]; i++)
369                 ;
370             exclude_files = (char**)xrealloc(exclude_files,
371                                              sizeof(char*) * (i+2));
372
373             exclude_files[i] = xstrdup(".*");
374             exclude_files[i+1] = 0;
375             break;
376 #endif
377         case 'w':
378             if (!optarg) {
379                 error("working directory does not specified for `-w'");
380                 exit(2);
381             }
382             if (*optarg == '=')
383                 optarg++;
384
385             extract_directory = optarg;
386             break;
387         case '0':
388             header_level = 0;
389             break;
390         case '1':
391             header_level = 1;
392             break;
393         case '2':
394             header_level = 2;
395             break;
396         case SYSTEM_KANJI_CODE_OPTION:
397             if (!optarg) {
398                 error("kanji code not specified for --%s",
399                       long_options[option_index].name);
400                 return -1;
401             }
402             if (strcmp(optarg, "euc") == 0) {
403                 optional_system_kanji_code = CODE_EUC;
404             }
405             else if (strcmp(optarg, "sjis") == 0) {
406                 optional_system_kanji_code = CODE_SJIS;
407             }
408             else if (strcmp(optarg, "utf8") == 0) {
409                 optional_system_kanji_code = CODE_UTF8;
410             }
411             else if (strcmp(optarg, "cap") == 0) {
412                 optional_system_kanji_code = CODE_CAP;
413             }
414             else {
415                 error("unknown kanji code \"%s\"", optarg);
416                 return -1;
417             }
418             break;
419
420         case ARCHIVE_KANJI_CODE_OPTION:
421             if (!optarg) {
422                 error("kanji code not specified for --%s",
423                       long_options[option_index].name);
424                 return -1;
425             }
426             if (strcmp(optarg, "euc") == 0) {
427                 optional_archive_kanji_code = CODE_EUC;
428             }
429             else if (strcmp(optarg, "sjis") == 0) {
430                 optional_archive_kanji_code = CODE_SJIS;
431             }
432             else if (strcmp(optarg, "utf8") == 0) {
433                 optional_archive_kanji_code = CODE_UTF8;
434             }
435             else if (strcmp(optarg, "cap") == 0) {
436                 optional_archive_kanji_code = CODE_CAP;
437             }
438             else {
439                 error("unknown kanji code \"%s\"", optarg);
440                 return -1;
441             }
442             break;
443
444         default:
445             error("unknown option `-%c'.", c);
446             return -1;
447         }
448     }
449
450     argc -= optind;
451     argv += optind;
452
453     if (!archive_name) {
454         archive_name = *argv++;
455         argc--;
456     }
457
458     cmd_filec = argc;
459     cmd_filev = argv;
460
461     return 0;
462 }
463
464 /*
465   Parse LHA command and options.
466 */
467 static int
468 parse_option(int argc, char **argv)
469 {
470     char *cmd_char;
471
472     if (argv[1] == NULL || strcmp(argv[1], "--help") == 0) {
473         print_usage();
474         exit(0);
475     }
476
477     if (strcmp(argv[1], "--version") == 0) {
478         print_version();
479         exit(0);
480     }
481
482     if (argc == 2 && *argv[1] != '-') {
483         archive_name = argv[1];
484         cmd = CMD_LIST;
485         cmd_filec = 0;
486         cmd_filev = 0;
487         return 0;
488     }
489
490     cmd_char = argv[1];
491
492     if (cmd_char[0] == '-')
493         cmd_char++;
494
495     /* parse commands */
496     switch (*cmd_char) {
497     case 'x':
498     case 'e':
499         cmd = CMD_EXTRACT;
500         break;
501
502     case 'p':
503         output_to_stdout = TRUE;
504         cmd = CMD_EXTRACT;
505         break;
506
507     case 'c':
508         new_archive = TRUE;
509         cmd = CMD_ADD;
510         break;
511
512     case 'a':
513         cmd = CMD_ADD;
514         break;
515
516     case 'd':
517         cmd = CMD_DELETE;
518         break;
519
520     case 'u':
521         update_if_newer = TRUE;
522         cmd = CMD_ADD;
523         break;
524
525     case 'm':
526         delete_after_append = TRUE;
527         cmd = CMD_ADD;
528         break;
529
530     case 'v':
531         verbose_listing = TRUE;
532         cmd = CMD_LIST;
533         break;
534
535     case 'l':
536         cmd = CMD_LIST;
537         break;
538
539     case 't':
540         cmd = CMD_EXTRACT;
541         verify_mode = TRUE;
542         break;
543
544     default:
545         error("unknown command `-%c'", *cmd_char);
546         return -1;
547     }
548
549     if (cmd_char[1] == '\0') {
550         /* argv[1] is command name */
551         argv[1] = argv[0];
552         argv++;
553         argc--;
554     }
555     else {
556         /* Eliminate command character
557            e.g.) lha  cv foo.lzh -> lha -v foo.lzh
558                  lha -cv foo.lzh -> lha -v foo.lzh
559         */
560         cmd_char[0] = '-';
561         argv[1] = cmd_char;
562     }
563
564     return parse_suboption(argc, argv);
565 }
566
567 /* ------------------------------------------------------------------------ */
568 int
569 main(argc, argv)
570     int             argc;
571     char           *argv[];
572 {
573     char           *p;
574
575     int i;
576
577     init_variable();        /* Added N.Watazaki */
578
579     if (parse_option(argc, argv) == -1) {
580         fputs("\n", stderr);
581         print_tiny_usage();
582         exit(2);
583     }
584
585     if (!archive_name) {
586         error("archive file does not specified");
587         fputs("\n", stderr);
588         print_tiny_usage();
589         exit(2);
590     }
591
592     if (!strcmp(archive_name, "-")) {
593         if (!isatty(1) && cmd == CMD_ADD)
594             quiet = TRUE;
595     }
596 #if 0 /* Comment out; IMHO, this feature is useless. by Koji Arai */
597     else {
598         if (argc == 3 && !isatty(0)) { /* 1999.7.18 */
599             /* Bug(?) on MinGW, isatty() return 0 on Cygwin console.
600                mingw-runtime-1.3-2 and Cygwin 1.3.10(0.51/3/2) on Win2000 */
601             get_filename_from_stdin = TRUE;
602         }
603     }
604 #endif
605
606     /* target file name */
607     if (get_filename_from_stdin) {
608         char inpbuf[4096];
609         char **xfilev;
610         int xfilec = 257;
611
612         cmd_filec = 0;
613         xfilev = (char **)xmalloc(sizeof(char *) * xfilec);
614         while (fgets(inpbuf, sizeof(inpbuf), stdin)) {
615             /* delete \n if it exist */
616             i=0; p=inpbuf;
617             while (i < sizeof(inpbuf) && p != 0) {
618                 if (*p == '\n') {
619                     *p = 0;
620                     break;
621                 }
622                 p++; i++;
623             }
624
625             if (cmd_filec >= xfilec) {
626                 xfilec += 256;
627                 xfilev = (char **) xrealloc(xfilev,
628                            sizeof(char *) * xfilec);
629             }
630             if (strlen(inpbuf) < 1)
631                 continue;
632             xfilev[cmd_filec++] = xstrdup(inpbuf);
633         }
634         xfilev[cmd_filec] = NULL;
635         cmd_filev = xfilev;
636     }
637
638     sort_files();
639
640     /* make crc table */
641     make_crctable();
642
643     switch (cmd) {
644     case CMD_EXTRACT:
645         cmd_extract();
646         break;
647     case CMD_ADD:
648         cmd_add();
649         break;
650     case CMD_LIST:
651         cmd_list();
652         break;
653     case CMD_DELETE:
654         cmd_delete();
655         break;
656     }
657
658     if (error_occurred)
659         return 1;
660     return 0;
661 }
662
663
664 /* ------------------------------------------------------------------------ */
665 static void
666 print_version()
667 {
668     /* macro PACKAGE_NAME, PACKAGE_VERSION and PLATFORM are
669        defined in config.h by configure script */
670     fprintf(stderr, "%s version %s (%s)\n",
671             PACKAGE_NAME, PACKAGE_VERSION, PLATFORM);
672 }
673
674 void
675 #if STDC_HEADERS
676 message(char *fmt, ...)
677 #else
678 message(fmt, va_alist)
679     char *fmt;
680     va_dcl
681 #endif
682 {
683     int errno_sv = errno;
684     va_list v;
685
686     fprintf(stderr, "LHa: ");
687
688     va_init(v, fmt);
689     vfprintf(stderr, fmt, v);
690     va_end(v);
691
692     fputs("\n", stderr);
693
694     errno =  errno_sv;
695 }
696
697 /* ------------------------------------------------------------------------ */
698 void
699 #if STDC_HEADERS
700 warning(char *fmt, ...)
701 #else
702 warning(fmt, va_alist)
703     char *fmt;
704     va_dcl
705 #endif
706 {
707     int errno_sv = errno;
708     va_list v;
709
710     fprintf(stderr, "LHa: Warning: ");
711
712     va_init(v, fmt);
713     vfprintf(stderr, fmt, v);
714     va_end(v);
715
716     fputs("\n", stderr);
717
718     errno =  errno_sv;
719 }
720
721 /* ------------------------------------------------------------------------ */
722 void
723 #if STDC_HEADERS
724 error(char *fmt, ...)
725 #else
726 error(fmt, va_alist)
727     char *fmt;
728     va_dcl
729 #endif
730 {
731     int errno_sv = errno;
732     va_list v;
733
734     fprintf(stderr, "LHa: Error: ");
735
736     va_init(v, fmt);
737     vfprintf(stderr, fmt, v);
738     va_end(v);
739
740     fputs("\n", stderr);
741
742     error_occurred = 1;
743
744     errno =  errno_sv;
745 }
746
747 void
748 #if STDC_HEADERS
749 fatal_error(char *fmt, ...)
750 #else
751 fatal_error(fmt, va_alist)
752     char *fmt;
753     va_dcl
754 #endif
755 {
756     int errno_sv = errno;
757     va_list v;
758
759     fprintf(stderr, "LHa: Fatal error: ");
760
761     va_init(v, fmt);
762     vfprintf(stderr, fmt, v);
763     va_end(v);
764
765     if (errno)
766         fprintf(stderr, ": %s\n", strerror(errno_sv));
767     else
768         fputs("\n", stderr);
769
770     exit(1);
771 }
772
773 void
774 cleanup()
775 {
776     if (temporary_fd != -1) {
777         close(temporary_fd);
778         temporary_fd = -1;
779         unlink(temporary_name);
780     }
781
782     if (recover_archive_when_interrupt) {
783         rename(backup_archive_name, archive_name);
784         recover_archive_when_interrupt = FALSE;
785     }
786     if (remove_extracting_file_when_interrupt) {
787         message("Removing: %s", writing_filename);
788         unlink(writing_filename);
789         remove_extracting_file_when_interrupt = FALSE;
790     }
791 }
792
793 RETSIGTYPE
794 interrupt(signo)
795     int signo;
796 {
797     message("Interrupted");
798
799     cleanup();
800
801     signal(SIGINT, SIG_DFL);
802 #ifdef SIGHUP
803     signal(SIGHUP, SIG_DFL);
804 #endif
805     kill(getpid(), signo);
806 }
807
808 /* ------------------------------------------------------------------------ */
809 /*                                                                          */
810 /* ------------------------------------------------------------------------ */
811 static int
812 sort_by_ascii(a, b)
813     char          **a, **b;
814 {
815     register char  *p, *q;
816     register int    c1, c2;
817
818     p = *a, q = *b;
819     if (generic_format) {
820         do {
821             c1 = *(unsigned char *) p++;
822             c2 = *(unsigned char *) q++;
823             if (!c1 || !c2)
824                 break;
825             if (islower(c1))
826                 c1 = toupper(c1);
827             if (islower(c2))
828                 c2 = toupper(c2);
829         }
830         while (c1 == c2);
831         return c1 - c2;
832     }
833     else {
834         while (*p == *q && *p != '\0')
835             p++, q++;
836         return *(unsigned char *) p - *(unsigned char *) q;
837     }
838 }
839
840 /* ------------------------------------------------------------------------ */
841 static void
842 sort_files()
843 {
844     if (cmd_filec > 1)
845         qsort(cmd_filev, cmd_filec, sizeof(char *), sort_by_ascii);
846 }
847
848 /* ------------------------------------------------------------------------ */
849 void *
850 xmalloc(size)
851     size_t size;
852 {
853     void *p = malloc(size);
854     if (!p)
855         fatal_error("Not enough memory");
856     return p;
857 }
858
859 /* ------------------------------------------------------------------------ */
860 void *
861 xrealloc(old, size)
862     void *old;
863     size_t size;
864 {
865     void *p = (char *) realloc(old, size);
866     if (!p)
867         fatal_error("Not enough memory");
868     return p;
869 }
870
871 char *
872 xstrdup(str)
873     char *str;
874 {
875     int len = strlen(str);
876     char *p = (char *)xmalloc(len + 1);
877     strcpy(p, str);             /* ok */
878     return p;
879 }
880
881 /* ------------------------------------------------------------------------ */
882 /*                              STRING POOL                                 */
883 /* ------------------------------------------------------------------------ */
884 /*
885   string pool :
886     +-------------+-------------+------+-------------+----------+
887     | N A M E 1 \0| N A M E 2 \0| .... | N A M E n \0|          |
888     +-------------+-------------+------+-------------+----------+
889       ^ ^        ^ buffer+0 buffer+used buffer+size
890
891   vector :
892     +---------------+---------------+------------- -----------------+
893     | pointer to    | pointer to    | pointer to   ...  pointer to  |
894     |  stringpool   |  N A M E 1    |  N A M E 2   ...   N A M E n  |
895     +---------------+---------------+-------------     -------------+
896     ^ malloc base      returned
897 */
898
899 /* ------------------------------------------------------------------------ */
900 void
901 init_sp(sp)
902     struct string_pool *sp;
903 {
904     sp->size = 1024 - 8;    /* any ( >=0 ) */
905     sp->used = 0;
906     sp->n = 0;
907     sp->buffer = (char *) xmalloc(sp->size * sizeof(char));
908 }
909
910 /* ------------------------------------------------------------------------ */
911 void
912 add_sp(sp, name, len)
913     struct string_pool *sp;
914     char           *name;   /* stored '\0' at tail */
915     int             len;    /* include '\0' */
916 {
917     while (sp->used + len > sp->size) {
918         sp->size *= 2;
919         sp->buffer = (char *) xrealloc(sp->buffer, sp->size * sizeof(char));
920     }
921     memmove(sp->buffer + sp->used, name, len);
922     sp->used += len;
923     sp->n++;
924 }
925
926 /* ------------------------------------------------------------------------ */
927 void
928 finish_sp(sp, v_count, v_vector)
929     register struct string_pool *sp;
930     int            *v_count;
931     char         ***v_vector;
932 {
933     int             i;
934     register char  *p;
935     char          **v;
936
937     v = (char **) xmalloc((sp->n + 1) * sizeof(char *));
938     *v++ = sp->buffer;
939     *v_vector = v;
940     *v_count = sp->n;
941     p = sp->buffer;
942     for (i = sp->n; i; i--) {
943         *v++ = p;
944         if (i - 1)
945             p += strlen(p) + 1;
946     }
947 }
948
949 /* ------------------------------------------------------------------------ */
950 void
951 free_sp(vector)
952     char          **vector;
953 {
954     vector--;
955     free(*vector);      /* free string pool */
956     free(vector);
957 }
958
959
960 /* ------------------------------------------------------------------------ */
961 /*                          READ DIRECTORY FILES                            */
962 /* ------------------------------------------------------------------------ */
963 static          boolean
964 include_path_p(path, name)
965     char           *path, *name;
966 {
967     char           *n = name;
968     while (*path)
969         if (*path++ != *n++)
970             return (path[-1] == '/' && *n == '\0');
971     return (*n == '/' || (n != name && path[-1] == '/' && n[-1] == '/'));
972 }
973
974 /* ------------------------------------------------------------------------ */
975 void
976 cleaning_files(v_filec, v_filev)
977     int            *v_filec;
978     char         ***v_filev;
979 {
980     char           *flags;
981     struct stat     stbuf;
982
983     register char **filev = *v_filev;
984     register int    filec = *v_filec;
985     register char  *p;
986     register int    i, j;
987
988     if (filec == 0)
989         return;
990
991     flags = xmalloc(filec * sizeof(char));
992
993     /* flags & 0x01 :   1: ignore */
994     /* flags & 0x02 :   1: directory, 0 : regular file */
995     /* flags & 0x04 :   1: need delete */
996
997     for (i = 0; i < filec; i++)
998         if (GETSTAT(filev[i], &stbuf) < 0) {
999             flags[i] = 0x04;
1000             warning("Cannot access \"%s\" : %s; ignored.", filev[i],
1001                     strerror(errno));
1002         }
1003         else {
1004             if (is_regularfile(&stbuf))
1005                 flags[i] = 0x00;
1006             else if (is_directory(&stbuf))
1007                 flags[i] = 0x02;
1008 #ifdef S_IFLNK
1009             else if (is_symlink(&stbuf)) /* t.okamoto */
1010                 flags[i] = 0x00;
1011 #endif
1012             else {
1013                 flags[i] = 0x04;
1014                 warning("Cannot archive \"%s\", ignored.", filev[i]);
1015             }
1016         }
1017
1018     for (i = 0; i < filec; i++) {
1019         p = filev[i];
1020         if ((flags[i] & 0x07) == 0x00) {    /* regular file, not
1021                              * deleted/ignored */
1022             for (j = i + 1; j < filec; j++) {
1023                 if ((flags[j] & 0x07) == 0x00) {    /* regular file, not
1024                                      * deleted/ignored */
1025                     if (STREQU(p, filev[j]))
1026                         flags[j] = 0x04;    /* delete */
1027                 }
1028             }
1029         }
1030         else if ((flags[i] & 0x07) == 0x02) {   /* directory, not
1031                              * deleted/ignored */
1032             for (j = i + 1; j < filec; j++) {
1033                 if ((flags[j] & 0x07) == 0x00) {    /* regular file, not
1034                                      * deleted/ignored */
1035                     if (include_path_p(p, filev[j]))
1036                         flags[j] = 0x04;    /* delete */
1037                 }
1038                 else if ((flags[j] & 0x07) == 0x02) {   /* directory, not
1039                                      * deleted/ignored */
1040                     if (include_path_p(p, filev[j]))
1041                         flags[j] = 0x04;    /* delete */
1042                 }
1043             }
1044         }
1045     }
1046
1047     for (i = j = 0; i < filec; i++) {
1048         if ((flags[i] & 0x04) == 0) {
1049             if (i != j)
1050                 filev[j] = filev[i];
1051             j++;
1052         }
1053     }
1054     *v_filec = j;
1055
1056     free(flags);
1057 }
1058
1059 /* ------------------------------------------------------------------------ */
1060 boolean
1061 find_files(name, v_filec, v_filev)
1062     char           *name;
1063     int            *v_filec;
1064     char         ***v_filev;
1065 {
1066     struct string_pool sp;
1067     char            newname[FILENAME_LENGTH];
1068     int             len, n, i;
1069     DIR            *dirp;
1070     struct dirent  *dp;
1071     struct stat     tmp_stbuf, arc_stbuf, fil_stbuf;
1072     int exist_tmp = 1, exist_arc = 1;
1073
1074     len = str_safe_copy(newname, name, sizeof(newname));
1075     if (len > 0 && newname[len - 1] != '/') {
1076         if (len < sizeof(newname)-1)
1077             strcpy(&newname[len++], "/"); /* ok */
1078         else
1079             warning("the length of pathname \"%s\" is too long.", name);
1080     }
1081
1082     dirp = opendir(name);
1083     if (!dirp)
1084         return FALSE;
1085
1086     init_sp(&sp);
1087
1088     if (GETSTAT(temporary_name, &tmp_stbuf) == -1)
1089         exist_tmp = 0;
1090     if (GETSTAT(archive_name, &arc_stbuf) == -1)
1091         exist_arc = 0;
1092
1093     while ((dp = readdir(dirp)) != NULL) {
1094         n = NAMLEN(dp);
1095
1096         /* exclude '.' and '..' */
1097         if (strncmp(dp->d_name, ".", n) == 0
1098             || strncmp(dp->d_name, "..", n) == 0)
1099             continue;
1100
1101         /* exclude exclude_files supplied by user */
1102         for (i = 0; exclude_files && exclude_files[i]; i++) {
1103             if (fnmatch(exclude_files[i], dp->d_name,
1104                         FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) == 0)
1105                 goto next;
1106         }
1107
1108         if (len + n >= sizeof(newname)) {
1109             warning("filename is too long");
1110             continue;
1111         }
1112
1113         strncpy(newname + len, dp->d_name, n);
1114         newname[len + n] = '\0';
1115         if (GETSTAT(newname, &fil_stbuf) < 0)
1116             continue;
1117
1118 #if defined(HAVE_STRUCT_STAT_ST_INO) && !__MINGW32__
1119         /* MinGW has meaningless st_ino */
1120
1121         /* exclude temporary file, archive file and these links */
1122         if (exist_tmp &&
1123             tmp_stbuf.st_dev == fil_stbuf.st_dev &&
1124             tmp_stbuf.st_ino == fil_stbuf.st_ino)
1125             continue;
1126
1127         if (exist_arc &&
1128             arc_stbuf.st_dev == fil_stbuf.st_dev &&
1129             arc_stbuf.st_ino == fil_stbuf.st_ino)
1130             continue;
1131 #endif
1132         add_sp(&sp, newname, len+n+1);
1133     next:
1134         ;
1135     }
1136     closedir(dirp);
1137     finish_sp(&sp, v_filec, v_filev);
1138     if (*v_filec > 1)
1139         qsort(*v_filev, *v_filec, sizeof(char *), sort_by_ascii);
1140     cleaning_files(v_filec, v_filev);
1141
1142     return TRUE;
1143 }
1144
1145 /* ------------------------------------------------------------------------ */
1146 void
1147 free_files(filec, filev)
1148     int             filec;
1149     char          **filev;
1150 {
1151     free_sp(filev);
1152 }
1153
1154 /* ------------------------------------------------------------------------ */
1155 /*                                                                          */
1156 /* ------------------------------------------------------------------------ */
1157 /* Build temporary file name and store to TEMPORARY_NAME */
1158 int
1159 build_temporary_name()
1160 {
1161 #ifdef TMP_FILENAME_TEMPLATE
1162     /* "/tmp/lhXXXXXX" etc. */
1163     if (extract_directory == NULL) {
1164         str_safe_copy(temporary_name, TMP_FILENAME_TEMPLATE,
1165                       sizeof(temporary_name));
1166     }
1167     else {
1168         xsnprintf(temporary_name, sizeof(temporary_name),
1169                   "%s/lhXXXXXX", extract_directory);
1170     }
1171 #else
1172     char *s;
1173
1174     str_safe_copy(temporary_name, archive_name, sizeof(temporary_name));
1175     s = strrchr(temporary_name, '/');
1176     if (s) {
1177         int len;
1178         len = s - temporary_name;
1179         if (len + strlen("lhXXXXXX") < sizeof(temporary_name))
1180             /* use directory at archive file */
1181             strcpy(s, "lhXXXXXX"); /* ok */
1182         else
1183             /* use current directory */
1184             str_safe_copy(temporary_name, "lhXXXXXX", sizeof(temporary_name));
1185     }
1186     else
1187         /* use current directory */
1188         str_safe_copy(temporary_name, "lhXXXXXX", sizeof(temporary_name));
1189 #endif
1190 #ifdef HAVE_MKSTEMP
1191     {
1192         int old_umask, fd;
1193
1194         old_umask = umask(077);
1195         fd = mkstemp(temporary_name);
1196         umask(old_umask);
1197         return fd;
1198     }
1199 #else
1200     {
1201         int flags;
1202
1203         mktemp(temporary_name);
1204         flags = O_CREAT|O_EXCL|O_RDWR;
1205 #ifdef O_BINARY
1206         flags |= O_BINARY;
1207 #endif
1208         return open(temporary_name, flags, 0600);
1209     }
1210 #endif
1211 }
1212
1213 /* ------------------------------------------------------------------------ */
1214 static void
1215 modify_filename_extention(buffer, ext, size)
1216     char           *buffer;
1217     char           *ext;
1218     size_t size;
1219 {
1220     register char  *p, *dot;
1221
1222     for (p = buffer, dot = (char *) 0; *p; p++) {
1223         if (*p == '.')
1224             dot = p;
1225         else if (*p == '/')
1226             dot = (char *) 0;
1227     }
1228
1229     if (dot)
1230         p = dot;
1231
1232     str_safe_copy(p, ext, size - (p - buffer));
1233 }
1234
1235 /* ------------------------------------------------------------------------ */
1236 /* build backup file name */
1237 void
1238 build_backup_name(buffer, original, size)
1239     char           *buffer;
1240     char           *original;
1241     size_t size;
1242 {
1243     str_safe_copy(buffer, original, size);
1244     modify_filename_extention(buffer, BACKUPNAME_EXTENTION, size);    /* ".bak" */
1245 }
1246
1247 /* ------------------------------------------------------------------------ */
1248 void
1249 build_standard_archive_name(buffer, original, size)
1250     char           *buffer;
1251     char           *original;
1252     size_t size;
1253 {
1254     str_safe_copy(buffer, original, size);
1255     modify_filename_extention(buffer, ARCHIVENAME_EXTENTION, size);   /* ".lzh" */
1256 }
1257
1258 /* ------------------------------------------------------------------------ */
1259 /*                                                                          */
1260 /* ------------------------------------------------------------------------ */
1261 boolean
1262 need_file(name)
1263     char           *name;
1264 {
1265     int             i;
1266
1267     if (cmd_filec == 0)
1268         return TRUE;
1269
1270     for (i = 0; i < cmd_filec; i++) {
1271         if (patmatch(cmd_filev[i], name, 0))
1272             return TRUE;
1273     }
1274
1275     return FALSE;
1276 }
1277
1278 FILE           *
1279 xfopen(name, mode)
1280     char           *name, *mode;
1281 {
1282     FILE           *fp;
1283
1284     if ((fp = fopen(name, mode)) == NULL)
1285         fatal_error("Cannot open file \"%s\"", name);
1286
1287     return fp;
1288 }
1289
1290 /* ------------------------------------------------------------------------ */
1291 /*                                                                          */
1292 /* ------------------------------------------------------------------------ */
1293 static          boolean
1294 open_old_archive_1(name, v_fp)
1295     char           *name;
1296     FILE          **v_fp;
1297 {
1298     FILE           *fp;
1299     struct stat     stbuf;
1300
1301     if (stat(name, &stbuf) >= 0 &&
1302         is_regularfile(&stbuf) &&
1303         (fp = fopen(name, READ_BINARY)) != NULL) {
1304         *v_fp = fp;
1305         archive_file_gid = stbuf.st_gid;
1306         archive_file_mode = stbuf.st_mode;
1307         return TRUE;
1308     }
1309
1310     *v_fp = NULL;
1311     archive_file_gid = -1;
1312     return FALSE;
1313 }
1314
1315 /* ------------------------------------------------------------------------ */
1316 FILE           *
1317 open_old_archive()
1318 {
1319     FILE           *fp;
1320     char           *p;
1321     static char expanded_archive_name[FILENAME_LENGTH];
1322
1323     if (!strcmp(archive_name, "-")) {
1324         if (cmd == CMD_EXTRACT || cmd == CMD_LIST) {
1325 #if defined(__MINGW32__) || defined(__DJGPP__)
1326             setmode(fileno(stdin), O_BINARY);
1327 #endif
1328             return stdin;
1329         }
1330         else
1331             return NULL;
1332     }
1333     p = strrchr(archive_name, '.');
1334     if (p) {
1335         if (strcasecmp(".LZH", p) == 0
1336             || strcasecmp(".LZS", p) == 0
1337             || strcasecmp(".COM", p) == 0  /* DOS SFX */
1338             || strcasecmp(".EXE", p) == 0
1339             || strcasecmp(".X", p) == 0    /* HUMAN SFX */
1340             || strcasecmp(".BAK", p) == 0) {   /* for BackUp */
1341             open_old_archive_1(archive_name, &fp);
1342             return fp;
1343         }
1344     }
1345
1346     if (open_old_archive_1(archive_name, &fp))
1347         return fp;
1348     xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1349               "%s.lzh", archive_name);
1350     if (open_old_archive_1(expanded_archive_name, &fp)) {
1351         archive_name = expanded_archive_name;
1352         return fp;
1353     }
1354     /*
1355      * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1356      * expanded_archive_name; return NULL; }
1357      */
1358     xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1359               "%s.lzs", archive_name);
1360     if (open_old_archive_1(expanded_archive_name, &fp)) {
1361         archive_name = expanded_archive_name;
1362         return fp;
1363     }
1364     /*
1365      * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1366      * expanded_archive_name; return NULL; }
1367      */
1368     /*
1369      * sprintf( expanded_archive_name , "%s.lzh",archive_name);
1370      * archive_name = expanded_archive_name;
1371      */
1372     return NULL;
1373 }
1374
1375 /* ------------------------------------------------------------------------ */
1376 int
1377 inquire(msg, name, selective)
1378     char           *msg, *name, *selective;
1379 {
1380     char            buffer[1024];
1381     char           *p;
1382
1383     for (;;) {
1384         fprintf(stderr, "%s %s ", name, msg);
1385         fflush(stderr);
1386
1387         fgets(buffer, 1024, stdin);
1388
1389         for (p = selective; *p; p++)
1390             if (buffer[0] == *p)
1391                 return p - selective;
1392     }
1393     /* NOTREACHED */
1394 }
1395
1396 /* ------------------------------------------------------------------------ */
1397 void
1398 write_archive_tail(nafp)
1399     FILE           *nafp;
1400 {
1401     putc(0x00, nafp);
1402 }
1403
1404 /* ------------------------------------------------------------------------ */
1405 void
1406 copy_old_one(oafp, nafp, hdr)
1407     FILE           *oafp, *nafp;
1408     LzHeader       *hdr;
1409 {
1410     if (noexec) {
1411         fseeko(oafp, hdr->header_size + hdr->packed_size, SEEK_CUR);
1412     }
1413     else {
1414         reading_filename = archive_name;
1415         writing_filename = temporary_name;
1416         copyfile(oafp, nafp, hdr->header_size + hdr->packed_size, 0, 0);
1417     }
1418 }
1419
1420 #undef exit
1421
1422 void
1423 lha_exit(status)
1424     int status;
1425 {
1426     cleanup();
1427     exit(status);
1428 }