OSDN Git Service

* 00readme.autoconf: describe about new feature `-x'.
[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 /*             Modified for Mac OS X            2002.06.03  H.Sakai         */
43 /* ------------------------------------------------------------------------ */
44 #define LHA_MAIN_SRC
45
46 #include "lha.h"
47
48 static int      cmd = CMD_UNKNOWN;
49 static int error_occurred;
50
51 /* static functions */
52 static void     sort_files();
53 static void     print_version();
54
55 /* ------------------------------------------------------------------------ */
56 static void
57 init_variable()     /* Added N.Watazaki */
58 {
59 /* options */
60     quiet           = FALSE;
61     text_mode       = FALSE;
62     verbose         = 0;
63     noexec          = FALSE;    /* debugging option */
64     force           = FALSE;
65     prof            = FALSE;
66
67     compress_method = DEFAULT_LZHUFF_METHOD; /* defined in config.h */
68
69     header_level    = HEADER_LEVEL2;
70     quiet_mode      = 0;
71
72 #ifdef EUC
73     euc_mode        = FALSE;
74 #endif
75
76 /* view command flags */
77     verbose_listing = FALSE;
78
79 /* extract command flags */
80     output_to_stdout = FALSE;
81
82 /* append command flags */
83     new_archive         = FALSE;
84     update_if_newer     = FALSE;
85     delete_after_append = FALSE;
86     generic_format      = FALSE;
87
88     remove_temporary_at_error               = FALSE;
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     noconvertcase                           = 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
108 /* ------------------------------------------------------------------------ */
109 /* NOTES :          Text File Format                                        */
110 /* GENERATOR        NewLine                                                 */
111 /* [generic]        0D 0A                                                   */
112 /* [MS-DOS]         0D 0A                                                   */
113 /* [OS9][MacOS]     0D                                                      */
114 /* [UNIX]           0A                                                      */
115 /* ------------------------------------------------------------------------ */
116 static void
117 print_tiny_usage()
118 {
119     fprintf(stderr, "\
120 LHarc    for UNIX  V 1.02  Copyright(C) 1989  Y.Tagawa\n\
121 LHx      for MSDOS V C2.01 Copyright(C) 1990  H.Yoshizaki\n\
122 LHx(arc) for OSK   V 2.01  Modified     1990  Momozou\n\
123 LHa      for UNIX  V 1.00  Copyright(C) 1992  Masaru Oki\n\
124 LHa      for UNIX  V 1.14  Modified     1995  Nobutaka Watazaki\n\
125 LHa      for UNIX  V 1.14i Modified     2000  Tsugio Okamoto\n\
126                            Modified     2002  Hiroto Sakai\n\
127                     Autoconfiscated 2001,2002 Koji Arai\n\
128 ");
129     fprintf(stderr, "\
130 usage: lha [-]<commands><options> [-<options> ...] archive_file [file...]\n\
131   commands:  [axelvudmcpt]\n\
132   options:   [q[num]vnfto[num]dizge012[w=<dir>][x=<pattern>]]\n\
133 commands:                           options:\n\
134  a   Add(or replace) to archive      q{num} quiet (num:quiet mode)\n\
135  x,e EXtract from archive            v  verbose\n\
136  l,v List / Verbose List             n  not execute\n\
137  u   Update newer files to archive   f  force (over write at extract)\n\
138  d   Delete from archive             t  FILES are TEXT file\n");
139 #ifdef SUPPORT_LH7
140     fprintf(stderr, "\
141  m   Move to archive (means 'ad')    o[567] compression method (a/u)\n\
142 ");
143 #endif
144 #ifndef SUPPORT_LH7
145     fprintf(stderr, "\
146  m   Move to archive (means 'ad')    o  use LHarc compatible method (a/u)\n\
147 ");
148 #endif
149     fprintf(stderr, "\
150  c   re-Construct new archive        w=<dir> specify extract directory (a/u/m/x/e)\n\
151  p   Print to STDOUT from archive    d  delete FILES after (a/u/c)\n\
152  t   Test file CRC in archive        i  ignore directory path (x/e)\n\
153                                      x=<pattern>  eXclude files (a/u)\n\
154                                      z  files not compress (a/u)\n\
155                                      g  Generic format (for compatibility)\n\
156                                         or not convert case when extracting\n\
157                                      0/1/2 header level (a/u)\n\
158 ");
159 #ifdef EUC
160     fprintf(stderr, "\
161                                      e  TEXT code convert from/to EUC\n\
162 ");
163 #endif
164 }
165
166 void
167 parse_option(int argc, char **argv)
168 {
169     char *opt;
170     int i;
171
172     argv++; argc--;             /* exclude command name */
173
174     if (argc < 1) {
175         print_tiny_usage();
176         exit(0);
177     }
178
179     if (strcmp(*argv, "--help") == 0) {
180         print_tiny_usage();
181         exit(0);
182     }
183     if (strcmp(*argv, "--version") == 0) {
184         print_version();
185         exit(0);
186     }
187
188     if (argc == 1) {
189         archive_name = *argv++; argc--;
190         cmd = CMD_LIST;
191         cmd_filec = argc;
192         cmd_filev = argv;
193         return;
194     }
195
196     opt = *argv++; argc--;
197
198     if (opt[0] == '-')
199         opt++;
200
201     /* commands */
202     switch (*opt) {
203     case 'x':
204     case 'e':
205         cmd = CMD_EXTRACT;
206         break;
207
208     case 'p':
209         output_to_stdout = TRUE;
210         cmd = CMD_EXTRACT;
211         break;
212
213     case 'c':
214         new_archive = TRUE;
215         cmd = CMD_ADD;
216         break;
217
218     case 'a':
219         cmd = CMD_ADD;
220         break;
221
222     case 'd':
223         cmd = CMD_DELETE;
224         break;
225
226     case 'u':
227         update_if_newer = TRUE;
228         cmd = CMD_ADD;
229         break;
230
231     case 'm':
232         delete_after_append = TRUE;
233         cmd = CMD_ADD;
234         break;
235
236     case 'v':
237         verbose_listing = TRUE;
238         cmd = CMD_LIST;
239         break;
240
241     case 'l':
242         cmd = CMD_LIST;
243         break;
244
245     case 't':
246         cmd = CMD_EXTRACT;
247         verify_mode = TRUE;
248         break;
249
250     default:
251         print_tiny_usage();
252         exit(2);
253     }
254
255     /* options */
256     for (;;) {
257         char *p = opt+1;
258
259         while ( *p != 0 ) {
260             switch ((*p++)) {
261             case 'q':
262                 switch (*p) {
263                 case '0':           /* no quiet */
264                 case '1':           /* no use the incremental indicator */
265                     quiet_mode = *p - '0';
266                     ++p;
267                     break;
268                 case '2':           /* no output */
269                     ++p;
270                     /* fall through */
271                 default:
272                     /* In quiet mode, no confirm to overwrite */
273                     force = TRUE;
274                     quiet = TRUE;
275                     break;
276                 }
277                 break;
278             case 'f':
279                 force = TRUE;
280                 break;
281             case 'p':
282                 prof = TRUE;
283                 break;
284             case 'v':
285                 verbose++;
286                 break;
287             case 't':
288                 text_mode = TRUE;
289                 break;
290 #ifdef EUC
291             case 'e':
292                 text_mode = TRUE;
293                 euc_mode = TRUE;
294                 break;
295 #endif
296             case 'n':
297                 noexec = TRUE;
298                 break;
299             case 'g':
300                 generic_format = TRUE;
301                 noconvertcase = TRUE;
302                 header_level = 0;
303                 break;
304             case 'd':
305                 delete_after_append = TRUE;
306                 break;
307             case 'o':
308                 switch (*p) {
309                 case 0:
310                     compress_method = LZHUFF1_METHOD_NUM;
311                     header_level = 0;
312                     break;
313                 case '5':
314                     compress_method = LZHUFF5_METHOD_NUM;
315                     p++;
316                     break;
317 #ifdef SUPPORT_LH7
318                 case '6':
319                     compress_method = LZHUFF6_METHOD_NUM;
320                     p++;
321                     break;
322                 case '7':
323                     compress_method = LZHUFF7_METHOD_NUM;
324                     p++;
325                     break;
326 #endif
327                 default:
328                     error("invalid compression method 'o%c'", *p);
329                     exit(2);
330                 }
331                 break;
332             case 'z':
333                 compress_method = LZHUFF0_METHOD_NUM;   /* Changed N.Watazaki */
334                 break;
335             case 'i':
336                 ignore_directory = TRUE;
337                 break;
338             case 'x':
339                 if (*p == '=')
340                     p++;
341
342                 for (i = 0; exclude_files && exclude_files[i]; i++)
343                     ;
344                 exclude_files = (char**)xrealloc(exclude_files,
345                                                  sizeof(char*) * (i+2));
346
347                 if (*p == 0) {
348                     exclude_files[i] = *argv++; argc--;
349                     exclude_files[i+1] = 0;
350                     goto next;
351                 }
352                 else {
353                     exclude_files[i] = p;
354                     exclude_files[i+1] = 0;
355                     p += strlen(p);
356                 }
357                 break;
358             case 'w':
359                 if (*p == '=')
360                     p++;
361                 if (*p == 0) {
362                     extract_directory = *argv++; argc--;
363                     goto next;
364                 }
365                 else {
366                     extract_directory = p;
367                     p += strlen(p);
368                 }
369                 break;
370             case '0':
371                 header_level = HEADER_LEVEL0;
372                 break;
373             case '1':
374                 header_level = HEADER_LEVEL1;
375                 break;
376             case '2':
377                 header_level = HEADER_LEVEL2;
378                 break;
379             default:
380                 error("Unknown option '%c'.", p[-1]);
381                 exit(2);
382             }
383         }
384
385     next:
386         opt = *argv;
387         if (!opt || opt[0] != '-')
388             break;
389
390         /* special archive name */
391         if (strcmp(opt, "-") == 0)
392             break;
393
394         argv++; argc--;
395     }
396
397     archive_name = *argv++; argc--;
398
399     cmd_filec = argc;
400     cmd_filev = argv;
401 }
402
403 /* ------------------------------------------------------------------------ */
404 int
405 main(argc, argv)
406     int             argc;
407     char           *argv[];
408 {
409     char           *p;
410
411     int i;
412
413     init_variable();        /* Added N.Watazaki */
414
415     parse_option(argc, argv);
416
417     if (!archive_name) {
418         print_tiny_usage();
419         exit(0);
420     }
421
422     if (!strcmp(archive_name, "-")) {
423         if (!isatty(1) && cmd == CMD_ADD)
424             quiet = TRUE;
425     }
426 #if 0 /* Comment out; IMHO, this feature is useless. by Koji Arai */
427     else {
428         if (argc == 3 && !isatty(0)) { /* 1999.7.18 */
429             /* Bug(?) on MinGW, isatty() return 0 on Cygwin console.
430                mingw-runtime-1.3-2 and Cygwin 1.3.10(0.51/3/2) on
431                Win2000 */
432             get_filename_from_stdin = TRUE;
433         }
434     }
435 #endif
436
437     /* target file name */
438     if (get_filename_from_stdin) {
439         char inpbuf[4096];
440         char **xfilev;
441         int xfilec = 257;
442
443         cmd_filec = 0;
444         xfilev = (char **)xmalloc(sizeof(char *) * xfilec);
445         while (fgets(inpbuf, sizeof(inpbuf), stdin)) {
446             /* delete \n if it exist */
447             i=0; p=inpbuf;
448             while (i < sizeof(inpbuf) && p != 0) {
449                 if (*p == '\n') {
450                     *p = 0;
451                     break;
452                 }
453                 p++; i++;
454             }
455
456             if (cmd_filec >= xfilec) {
457                 xfilec += 256;
458                 xfilev = (char **) xrealloc(xfilev,
459                            sizeof(char *) * xfilec);
460             }
461             if (strlen(inpbuf) < 1)
462                 continue;
463             xfilev[cmd_filec++] = xstrdup(inpbuf);
464         }
465         xfilev[cmd_filec] = NULL;
466         cmd_filev = xfilev;
467     }
468
469     sort_files();
470
471     /* make crc table */
472     make_crctable();
473
474     switch (cmd) {
475     case CMD_EXTRACT:
476         cmd_extract();
477         break;
478     case CMD_ADD:
479         cmd_add();
480         break;
481     case CMD_LIST:
482         cmd_list();
483         break;
484     case CMD_DELETE:
485         cmd_delete();
486         break;
487     }
488
489 #ifdef USE_PROF
490     if (!prof)
491         exit(0);
492 #endif
493
494     if (error_occurred)
495         return 1;
496     return 0;
497 }
498
499
500 /* ------------------------------------------------------------------------ */
501 /* */
502 /* ------------------------------------------------------------------------ */
503
504 /* ------------------------------------------------------------------------ */
505 static void
506 print_version()
507 {
508     /* macro PACKAGE_NAME, PACKAGE_VERSION and PLATFORM are
509        defined in config.h by configure script */
510     fprintf(stderr, "%s version %s (%s)\n",
511             PACKAGE_NAME, PACKAGE_VERSION, PLATFORM);
512 }
513
514 void
515 #if STDC_HEADERS
516 message(char *fmt, ...)
517 #else
518 message(fmt, va_alist)
519     char *fmt;
520     va_dcl
521 #endif
522 {
523     int errno_sv = errno;
524     va_list v;
525
526     fprintf(stderr, "LHa: ");
527
528     va_init(v, fmt);
529     vfprintf(stderr, fmt, v);
530     va_end(v);
531
532     fputs("\n", stderr);
533
534     errno =  errno_sv;
535 }
536
537 /* ------------------------------------------------------------------------ */
538 void
539 #if STDC_HEADERS
540 warning(char *fmt, ...)
541 #else
542 warning(fmt, va_alist)
543     char *fmt;
544     va_dcl
545 #endif
546 {
547     int errno_sv = errno;
548     va_list v;
549
550     fprintf(stderr, "LHa: Warning: ");
551
552     va_init(v, fmt);
553     vfprintf(stderr, fmt, v);
554     va_end(v);
555
556     fputs("\n", stderr);
557
558     errno =  errno_sv;
559 }
560
561 /* ------------------------------------------------------------------------ */
562 void
563 #if STDC_HEADERS
564 error(char *fmt, ...)
565 #else
566 error(fmt, va_alist)
567     char *fmt;
568     va_dcl
569 #endif
570 {
571     int errno_sv = errno;
572     va_list v;
573
574     fprintf(stderr, "LHa: Error: ");
575
576     va_init(v, fmt);
577     vfprintf(stderr, fmt, v);
578     va_end(v);
579
580     fputs("\n", stderr);
581
582     error_occurred = 1;
583
584     errno =  errno_sv;
585 }
586
587 void
588 #if STDC_HEADERS
589 fatal_error(char *fmt, ...)
590 #else
591 fatal_error(fmt, va_alist)
592     char *fmt;
593     va_dcl
594 #endif
595 {
596     int errno_sv = errno;
597     va_list v;
598
599     fprintf(stderr, "LHa: Fatal error: ");
600
601     va_init(v, fmt);
602     vfprintf(stderr, fmt, v);
603     va_end(v);
604
605     if (errno)
606         fprintf(stderr, ": %s\n", strerror(errno_sv));
607     else
608         fputs("\n", stderr);
609
610     if (remove_temporary_at_error) {
611         if (temporary_fd != -1)
612             close(temporary_fd);
613         unlink(temporary_name);
614     }
615
616     exit(1);
617 }
618
619 /* ------------------------------------------------------------------------ */
620 RETSIGTYPE
621 interrupt(signo)
622     int             signo;
623 {
624     message("Interrupted");
625
626     if (temporary_fd != -1)
627         close(temporary_fd);
628     unlink(temporary_name);
629     if (recover_archive_when_interrupt)
630         rename(backup_archive_name, archive_name);
631     if (remove_extracting_file_when_interrupt) {
632         message("Removing: %s", writing_filename);
633         unlink(writing_filename);
634     }
635     signal(SIGINT, SIG_DFL);
636 #ifdef SIGHUP
637     signal(SIGHUP, SIG_DFL);
638 #endif
639     kill(getpid(), signo);
640 }
641
642 /* ------------------------------------------------------------------------ */
643 /*                                                                          */
644 /* ------------------------------------------------------------------------ */
645 static int
646 sort_by_ascii(a, b)
647     char          **a, **b;
648 {
649     register char  *p, *q;
650     register int    c1, c2;
651
652     p = *a, q = *b;
653     if (generic_format) {
654         do {
655             c1 = *(unsigned char *) p++;
656             c2 = *(unsigned char *) q++;
657             if (!c1 || !c2)
658                 break;
659             if (islower(c1))
660                 c1 = toupper(c1);
661             if (islower(c2))
662                 c2 = toupper(c2);
663         }
664         while (c1 == c2);
665         return c1 - c2;
666     }
667     else {
668         while (*p == *q && *p != '\0')
669             p++, q++;
670         return *(unsigned char *) p - *(unsigned char *) q;
671     }
672 }
673
674 /* ------------------------------------------------------------------------ */
675 static void
676 sort_files()
677 {
678     if (cmd_filec > 1)
679         qsort(cmd_filev, cmd_filec, sizeof(char *), sort_by_ascii);
680 }
681
682 /* ------------------------------------------------------------------------ */
683 void *
684 xmalloc(size)
685     size_t size;
686 {
687     void *p = malloc(size);
688     if (!p)
689         fatal_error("Not enough memory");
690     return p;
691 }
692
693 /* ------------------------------------------------------------------------ */
694 void *
695 xrealloc(old, size)
696     void *old;
697     size_t size;
698 {
699     void *p = (char *) realloc(old, size);
700     if (!p)
701         fatal_error("Not enough memory");
702     return p;
703 }
704
705 char *
706 xstrdup(str)
707     char *str;
708 {
709     int len = strlen(str);
710     char *p = (char *)xmalloc(len + 1);
711     strcpy(p, str);
712     return p;
713 }
714
715 /* ------------------------------------------------------------------------ */
716 /*                              STRING POOL                                 */
717 /* ------------------------------------------------------------------------ */
718 /*
719   string pool :
720     +-------------+-------------+------+-------------+----------+
721     | N A M E 1 \0| N A M E 2 \0| .... | N A M E n \0|          |
722     +-------------+-------------+------+-------------+----------+
723       ^ ^        ^ buffer+0 buffer+used buffer+size
724
725   vector :
726     +---------------+---------------+------------- -----------------+
727     | pointer to    | pointer to    | pointer to   ...  pointer to  |
728     |  stringpool   |  N A M E 1    |  N A M E 2   ...   N A M E n  |
729     +---------------+---------------+-------------     -------------+
730     ^ malloc base      returned
731 */
732
733 /* ------------------------------------------------------------------------ */
734 void
735 init_sp(sp)
736     struct string_pool *sp;
737 {
738     sp->size = 1024 - 8;    /* any ( >=0 ) */
739     sp->used = 0;
740     sp->n = 0;
741     sp->buffer = (char *) xmalloc(sp->size * sizeof(char));
742 }
743
744 /* ------------------------------------------------------------------------ */
745 void
746 add_sp(sp, name, len)
747     struct string_pool *sp;
748     char           *name;   /* stored '\0' at tail */
749     int             len;    /* include '\0' */
750 {
751     while (sp->used + len > sp->size) {
752         sp->size *= 2;
753         sp->buffer = (char *) xrealloc(sp->buffer, sp->size * sizeof(char));
754     }
755     memmove(sp->buffer + sp->used, name, len);
756     sp->used += len;
757     sp->n++;
758 }
759
760 /* ------------------------------------------------------------------------ */
761 void
762 finish_sp(sp, v_count, v_vector)
763     register struct string_pool *sp;
764     int            *v_count;
765     char         ***v_vector;
766 {
767     int             i;
768     register char  *p;
769     char          **v;
770
771     v = (char **) xmalloc((sp->n + 1) * sizeof(char *));
772     *v++ = sp->buffer;
773     *v_vector = v;
774     *v_count = sp->n;
775     p = sp->buffer;
776     for (i = sp->n; i; i--) {
777         *v++ = p;
778         if (i - 1)
779             p += strlen(p) + 1;
780     }
781 }
782
783 /* ------------------------------------------------------------------------ */
784 void
785 free_sp(vector)
786     char          **vector;
787 {
788     vector--;
789     free(*vector);      /* free string pool */
790     free(vector);
791 }
792
793
794 /* ------------------------------------------------------------------------ */
795 /*                          READ DIRECTORY FILES                            */
796 /* ------------------------------------------------------------------------ */
797 static          boolean
798 include_path_p(path, name)
799     char           *path, *name;
800 {
801     char           *n = name;
802     while (*path)
803         if (*path++ != *n++)
804             return (path[-1] == '/' && *n == '\0');
805     return (*n == '/' || (n != name && path[-1] == '/' && n[-1] == '/'));
806 }
807
808 /* ------------------------------------------------------------------------ */
809 void
810 cleaning_files(v_filec, v_filev)
811     int            *v_filec;
812     char         ***v_filev;
813 {
814     char           *flags;
815     struct stat     stbuf;
816
817     register char **filev = *v_filev;
818     register int    filec = *v_filec;
819     register char  *p;
820     register int    i, j;
821
822     if (filec == 0)
823         return;
824
825     flags = xmalloc(filec * sizeof(char));
826
827     /* flags & 0x01 :   1: ignore */
828     /* flags & 0x02 :   1: directory, 0 : regular file */
829     /* flags & 0x04 :   1: need delete */
830
831     
832     for (i = 0; i < filec; i++)
833         if (GETSTAT(filev[i], &stbuf) < 0) {
834             flags[i] = 0x04;
835             warning("Cannot access \"%s\", ignored.", filev[i]);
836         }
837         else {
838             if (is_regularfile(&stbuf))
839                 flags[i] = 0x00;
840             else if (is_directory(&stbuf))
841                 flags[i] = 0x02;
842 #ifdef S_IFLNK
843             else if (is_symlink(&stbuf)) /* t.okamoto */
844                 flags[i] = 0x00;
845 #endif          
846             else {
847                 flags[i] = 0x04;
848                 warning("Cannot archive \"%s\", ignored.", filev[i]);
849             }
850         }
851
852     for (i = 0; i < filec; i++) {
853         p = filev[i];
854         if ((flags[i] & 0x07) == 0x00) {    /* regular file, not
855                              * deleted/ignored */
856             for (j = i + 1; j < filec; j++) {
857                 if ((flags[j] & 0x07) == 0x00) {    /* regular file, not
858                                      * deleted/ignored */
859                     if (STREQU(p, filev[j]))
860                         flags[j] = 0x04;    /* delete */
861                 }
862             }
863         }
864         else if ((flags[i] & 0x07) == 0x02) {   /* directory, not
865                              * deleted/ignored */
866             for (j = i + 1; j < filec; j++) {
867                 if ((flags[j] & 0x07) == 0x00) {    /* regular file, not
868                                      * deleted/ignored */
869                     if (include_path_p(p, filev[j]))
870                         flags[j] = 0x04;    /* delete */
871                 }
872                 else if ((flags[j] & 0x07) == 0x02) {   /* directory, not
873                                      * deleted/ignored */
874                     if (include_path_p(p, filev[j]))
875                         flags[j] = 0x04;    /* delete */
876                 }
877             }
878         }
879     }
880
881     for (i = j = 0; i < filec; i++) {
882         if ((flags[i] & 0x04) == 0) {
883             if (i != j)
884                 filev[j] = filev[i];
885             j++;
886         }
887     }
888     *v_filec = j;
889
890     free(flags);
891 }
892
893 /* ------------------------------------------------------------------------ */
894 boolean
895 find_files(name, v_filec, v_filev)
896     char           *name;
897     int            *v_filec;
898     char         ***v_filev;
899 {
900     struct string_pool sp;
901     char            newname[FILENAME_LENGTH];
902     int             len, n, i;
903     DIR            *dirp;
904     struct dirent  *dp;
905     struct stat     tmp_stbuf, arc_stbuf, fil_stbuf;
906
907     strcpy(newname, name);
908     len = strlen(name);
909     if (len > 0 && newname[len - 1] != '/')
910         newname[len++] = '/';
911
912     dirp = opendir(name);
913     if (!dirp)
914         return FALSE;
915
916     init_sp(&sp);
917
918     GETSTAT(temporary_name, &tmp_stbuf);
919     GETSTAT(archive_name, &arc_stbuf);
920
921     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
922         for (i = 0; exclude_files && exclude_files[i]; i++) {
923             if (fnmatch(exclude_files[i], dp->d_name,
924                         FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) == 0)
925                 goto next;
926         }
927
928         n = NAMLEN(dp);
929         strncpy(newname + len, dp->d_name, n);
930         newname[len + n] = '\0';
931         if (GETSTAT(newname, &fil_stbuf) < 0)
932             continue;
933 #if !defined(HAVE_STRUCT_STAT_ST_INO) || __MINGW32__
934         if ( dp->d_name[0] != '.' ||
935             (n != 1 &&
936              (dp->d_name[1] != '.' ||
937               n != 2))  ) {
938             add_sp(&sp, newname, len+n+1);
939         }
940 #else       
941         if ((dp->d_ino != 0) &&
942         /* exclude '.' and '..' */
943             ((dp->d_name[0] != '.') ||
944              ((n != 1) &&
945               ((dp->d_name[1] != '.') ||
946                (n != 2)))) &&
947             ((tmp_stbuf.st_dev != fil_stbuf.st_dev ||
948               tmp_stbuf.st_ino != fil_stbuf.st_ino) &&
949              (arc_stbuf.st_dev != fil_stbuf.st_dev ||
950               arc_stbuf.st_ino != fil_stbuf.st_ino))) {
951             add_sp(&sp, newname, len + n + 1);
952         }
953 #endif
954     next:
955     }
956     closedir(dirp);
957     finish_sp(&sp, v_filec, v_filev);
958     if (*v_filec > 1)
959         qsort(*v_filev, *v_filec, sizeof(char *), sort_by_ascii);
960     cleaning_files(v_filec, v_filev);
961
962     return TRUE;
963 }
964
965 /* ------------------------------------------------------------------------ */
966 void
967 free_files(filec, filev)
968     int             filec;
969     char          **filev;
970 {
971     free_sp(filev);
972 }
973
974 /* ------------------------------------------------------------------------ */
975 /*                                                                          */
976 /* ------------------------------------------------------------------------ */
977 /* Build temporary file name and store to TEMPORARY_NAME */
978 int
979 build_temporary_name()
980 {
981 #ifdef TMP_FILENAME_TEMPLATE
982     /* "/tmp/lhXXXXXX" etc. */
983     if (extract_directory == NULL) {
984         strcpy(temporary_name, TMP_FILENAME_TEMPLATE);
985     }
986     else {
987         xsnprintf(temporary_name, sizeof(temporary_name),
988                   "%s/lhXXXXXX", extract_directory);
989     }
990 #else
991     char           *p, *s;
992
993     strcpy(temporary_name, archive_name);
994     for (p = temporary_name, s = (char *) 0; *p; p++)
995         if (*p == '/')
996             s = p;
997     strcpy((s ? s + 1 : temporary_name), "lhXXXXXX");
998 #endif
999 #ifdef HAVE_MKSTEMP
1000     {
1001         int old_umask, fd;
1002
1003         old_umask = umask(077);
1004         fd = mkstemp(temporary_name);
1005         umask(old_umask);
1006         return fd;
1007     }
1008 #else
1009     {
1010         int flags;
1011
1012         mktemp(temporary_name);
1013         flags = O_CREAT|O_EXCL|O_RDWR;
1014 #ifdef O_BINARY
1015         flags |= O_BINARY;
1016 #endif
1017         return open(temporary_name, flags, 0600);
1018     }
1019 #endif
1020 }
1021
1022 /* ------------------------------------------------------------------------ */
1023 static void
1024 modify_filename_extention(buffer, ext)
1025     char           *buffer;
1026     char           *ext;
1027 {
1028     register char  *p, *dot;
1029
1030     for (p = buffer, dot = (char *) 0; *p; p++) {
1031         if (*p == '.')
1032             dot = p;
1033         else if (*p == '/')
1034             dot = (char *) 0;
1035     }
1036
1037     if (dot)
1038         p = dot;
1039
1040     strcpy(p, ext);
1041 }
1042
1043 /* ------------------------------------------------------------------------ */
1044 /* build backup file name */
1045 void
1046 build_backup_name(buffer, original)
1047     char           *buffer;
1048     char           *original;
1049 {
1050     strcpy(buffer, original);
1051     modify_filename_extention(buffer, BACKUPNAME_EXTENTION);    /* ".bak" */
1052 }
1053
1054 /* ------------------------------------------------------------------------ */
1055 void
1056 build_standard_archive_name(buffer, orginal)
1057     char           *buffer;
1058     char           *orginal;
1059 {
1060     strcpy(buffer, orginal);
1061     modify_filename_extention(buffer, ARCHIVENAME_EXTENTION);   /* ".lzh" */
1062 }
1063
1064 /* ------------------------------------------------------------------------ */
1065 /*                                                                          */
1066 /* ------------------------------------------------------------------------ */
1067 boolean
1068 need_file(name)
1069     char           *name;
1070 {
1071     int             i;
1072
1073     if (cmd_filec == 0)
1074         return TRUE;
1075
1076     for (i = 0; i < cmd_filec; i++) {
1077         if (patmatch(cmd_filev[i], name, 0))
1078             return TRUE;
1079     }
1080
1081     return FALSE;
1082 }
1083
1084 FILE           *
1085 xfopen(name, mode)
1086     char           *name, *mode;
1087 {
1088     FILE           *fp;
1089
1090     if ((fp = fopen(name, mode)) == NULL)
1091         fatal_error("Cannot open file \"%s\"", name);
1092
1093     return fp;
1094 }
1095
1096 /* ------------------------------------------------------------------------ */
1097 /*                                                                          */
1098 /* ------------------------------------------------------------------------ */
1099 static          boolean
1100 open_old_archive_1(name, v_fp)
1101     char           *name;
1102     FILE          **v_fp;
1103 {
1104     FILE           *fp;
1105     struct stat     stbuf;
1106
1107     if (stat(name, &stbuf) >= 0 &&
1108         is_regularfile(&stbuf) &&
1109         (fp = fopen(name, READ_BINARY)) != NULL) {
1110         *v_fp = fp;
1111         archive_file_gid = stbuf.st_gid;
1112         archive_file_mode = stbuf.st_mode;
1113         return TRUE;
1114     }
1115
1116     *v_fp = NULL;
1117     archive_file_gid = -1;
1118     return FALSE;
1119 }
1120
1121 /* ------------------------------------------------------------------------ */
1122 FILE           *
1123 open_old_archive()
1124 {
1125     FILE           *fp;
1126     char           *p;
1127     static char expanded_archive_name[FILENAME_LENGTH];
1128
1129     if (!strcmp(archive_name, "-")) {
1130         if (cmd == CMD_EXTRACT || cmd == CMD_LIST) {
1131 #if __MINGW32__
1132             setmode(fileno(stdin), O_BINARY);
1133 #endif
1134             return stdin;
1135         }
1136         else
1137             return NULL;
1138     }
1139     p = strrchr(archive_name, '.');
1140     if (p) {
1141         if (strucmp(".LZH", p) == 0
1142             || strucmp(".LZS", p) == 0
1143             || strucmp(".COM", p) == 0  /* DOS SFX */
1144             || strucmp(".EXE", p) == 0
1145             || strucmp(".X", p) == 0    /* HUMAN SFX */
1146             || strucmp(".BAK", p) == 0) {   /* for BackUp */
1147             open_old_archive_1(archive_name, &fp);
1148             return fp;
1149         }
1150     }
1151
1152     if (open_old_archive_1(archive_name, &fp))
1153         return fp;
1154     xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1155               "%s.lzh", archive_name);
1156     if (open_old_archive_1(expanded_archive_name, &fp)) {
1157         archive_name = expanded_archive_name;
1158         return fp;
1159     }
1160     /*
1161      * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1162      * expanded_archive_name; return NULL; }
1163      */
1164     xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1165               "%s.lzs", archive_name);
1166     if (open_old_archive_1(expanded_archive_name, &fp)) {
1167         archive_name = expanded_archive_name;
1168         return fp;
1169     }
1170     /*
1171      * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1172      * expanded_archive_name; return NULL; }
1173      */
1174     /*
1175      * sprintf( expanded_archive_name , "%s.lzh",archive_name);
1176      * archive_name = expanded_archive_name;
1177      */
1178     return NULL;
1179 }
1180
1181 /* ------------------------------------------------------------------------ */
1182 int
1183 inquire(msg, name, selective)
1184     char           *msg, *name, *selective;
1185 {
1186     char            buffer[1024];
1187     char           *p;
1188
1189     for (;;) {
1190         fprintf(stderr, "%s %s ", name, msg);
1191         fflush(stderr);
1192
1193         fgets(buffer, 1024, stdin);
1194
1195         for (p = selective; *p; p++)
1196             if (buffer[0] == *p)
1197                 return p - selective;
1198     }
1199     /* NOTREACHED */
1200 }
1201
1202 /* ------------------------------------------------------------------------ */
1203 void
1204 write_archive_tail(nafp)
1205     FILE           *nafp;
1206 {
1207     putc(0x00, nafp);
1208 }
1209
1210 /* ------------------------------------------------------------------------ */
1211 void
1212 copy_old_one(oafp, nafp, hdr)
1213     FILE           *oafp, *nafp;
1214     LzHeader       *hdr;
1215 {
1216     if (noexec) {
1217         fseek(oafp, hdr->header_size + hdr->packed_size, SEEK_CUR);
1218     }
1219     else {
1220         reading_filename = archive_name;
1221         writing_filename = temporary_name;
1222         copyfile(oafp, nafp, hdr->header_size + hdr->packed_size, 0, 0);
1223     }
1224 }