Added -V option to print the version number.
[platform/upstream/binutils.git] / binutils / ar.c
1 /* ar.c - Archive modify and extract.
2    Copyright (C) 1991 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /*
21    Bugs: should use getopt the way tar does (complete w/optional -) and
22    should have long options too. GNU ar used to check file against filesystem
23    in quick_update and replace operations (would check mtime). Doesn't warn
24    when name truncated. No way to specify pos_end. Error messages should be
25    more consistant.
26 */
27 #include "bfd.h"
28 #include "sysdep.h"
29 #include "bucomm.h"
30 #include "aout/ar.h"
31 #include "../bfd/libbfd.h"
32 #include "arsup.h"
33 #include <stdio.h>
34 #ifdef  USG
35 #include <time.h>
36 #else
37 #include <sys/time.h>
38 #endif
39 #include <errno.h>
40 #ifndef errno
41 extern int errno;
42 #endif
43 #define BUFSIZE 8192
44
45
46
47
48 PROTO(void, print_contents, (bfd * member));
49 PROTO(void, extract_file, (bfd * abfd));
50 PROTO(void, delete_members, (char **files_to_delete));
51 PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
52 PROTO(void, move_members, (char **files_to_move));
53 PROTO(void, replace_members, (char **files_to_replace));
54 PROTO(void, print_descr, (bfd * abfd));
55 PROTO(void, ranlib_only, (char *archname));
56
57 /** Globals and flags */
58
59 extern         *program_version;
60 char           *program_name = NULL;
61 bfd            *inarch;         /* The input arch we're manipulating */
62
63 int mri_mode;
64 /* This flag distinguishes between ar and ranlib:
65    1 means this is 'ranlib'; 0 means this is 'ar'.
66    -1 means if we should use argv[0] to decide. */
67 extern int is_ranlib;
68 /* Nonzero means don't warn about creating the archive file if necessary.  */
69 int             silent_create = 0;
70 /* Nonzero means describe each action performed.  */
71 int             verbose = 0;
72 /* Nonzero means preserve dates of members when extracting them.  */
73 int             preserve_dates = 0;
74 /*
75    Nonzero means don't replace existing members whose dates are more recent
76    than the corresponding files.
77 */
78 int             newer_only = 0;
79 /* write a __.SYMDEF member into the modified archive.  */
80 boolean         write_armap = false;
81 /*
82    Nonzero means don't update __.SYMDEF unless command line explicitly
83    requested it
84 */
85 int             ignore_symdef = 0;
86 /*
87    Nonzero means it's the name of an existing member; position new or moved
88    files with respect to this one.
89 */
90 char           *posname = NULL;
91 /*
92    Sez how to use `posname': pos_before means position before that member.
93    pos_after means position after that member. pos_end means always at end.
94    pos_default means default appropriately. For the latter two, `posname'
95    should also be zero.
96 */
97 enum pos {
98     pos_default, pos_before, pos_after, pos_end
99 }               postype = pos_default;
100
101 #ifdef GNU960
102         char *default_target;
103
104         void
105         gnu960_verify_target(abfd)
106         bfd *abfd;
107         {
108             if ( abfd->format == bfd_unknown ){
109                 bfd_check_format(abfd, bfd_object);
110                 /* Don't really care if it's an object --
111                  * just want to get the correct xvec.
112                  */
113             }
114             if ( !BFD_COFF_FILE_P(abfd) ){
115                 fatal( "'%s' not a COFF file -- operation aborted",
116                                                         abfd->filename );
117             }
118         }
119 #endif
120
121 int interactive = 0;
122 void
123 DEFUN_VOID(mri_emul)
124 {
125   interactive = isatty(fileno(stdin)) ;
126   yyparse();
127 }
128
129 /*
130    If count is 0, then function is called once on each entry. if nonzero,
131    count is the length of the files chain; function is called on each entry
132    whose name matches one in files
133 */
134 void
135 DEFUN(map_over_members,(function, files, count),
136       void            (*function) () AND
137       char          **files AND
138       int             count)
139 {
140   bfd            *head;
141
142   if (count == 0) {
143     for (head = inarch->next; head; head = head->next)
144      function(head);
145     return;
146   }
147   /*
148     This may appear to be a baroque way of accomplishing what we want.
149     however we have to iterate over the filenames in order to notice where
150     a filename is requested but does not exist in the archive.  Ditto
151     mapping over each file each time -- we want to hack multiple
152     references.
153     */
154
155   for (; count > 0; files++, count--) {
156     boolean         found = false;
157     for (head = inarch->next; head; head = head->next)
158      if ((head->filename != NULL) &&
159          (!strcmp(*files, head->filename))) {
160        found = true;
161        function(head);
162      }
163     if (!found)
164      fprintf(stderr, "No entry %s in archive.\n", *files);
165   }
166 }
167
168
169 boolean operation_alters_arch = false;
170
171 /*
172    The option parsing should be in its own function.  It will be when I have
173    getopt working.
174 */
175 int
176 main(argc, argv)
177     int             argc;
178     char          **argv;
179 {
180   char           *arg_ptr;
181   char            c;
182   enum {
183     none = 0, delete, replace, print_table,
184     print_files, extract, move, quick_append
185   }               operation = none;
186   int             arg_index;
187   char          **files;
188   char           *inarch_filename;
189   char           *temp;
190   int            show_version;
191
192   bfd_init();
193   verbose = 1;
194   show_version = 0;
195 #ifdef GNU960
196   check_v960( argc, argv );
197   default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
198 #endif
199
200   program_name = argv[0];
201
202   temp = strrchr(program_name, '/');
203   if (temp == (char *) NULL)
204    temp = program_name;         /* shouldn't happen, but... */
205   else
206    ++temp;
207   if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
208     if (argc < 2)
209      fatal("Too few command arguments.");
210     ranlib_only(argv[1]);
211   }
212
213   if (argc == 2 && strcmp(argv[1],"-M") == 0) {
214     mri_emul();
215     exit(0);
216   }
217   if (argc < 3)
218    fatal("Too few command arguments.");
219
220   arg_ptr = argv[1];
221
222   if (*arg_ptr == '-')
223    ++arg_ptr;                   /* compatibility */
224
225   while (c = *arg_ptr++) {
226     switch (c) {
227      case 'd':
228      case 'm':
229      case 'p':
230      case 'q':
231      case 'r':
232      case 't':
233      case 'x':
234       if (operation != none)
235        fatal("two different operation switches specified");
236       switch (c) {
237        case 'd':
238         operation = delete;
239         operation_alters_arch = true;
240         break;
241        case 'm':
242         operation = move;
243         operation_alters_arch = true;
244         break;
245        case 'p':
246         operation = print_files;
247         break;
248        case 'q':
249         operation = quick_append;
250         operation_alters_arch = true;
251         break;
252        case 'r':
253         operation = replace;
254         operation_alters_arch = true;
255         break;
256        case 't':
257         operation = print_table;
258         break;
259        case 'x':
260         operation = extract;
261         break;
262       }
263      case 'l':
264       break;
265      case 'c':
266       silent_create = 1;
267       break;
268      case 'o':
269       preserve_dates = 1;
270       break;
271      case 'V':
272       show_version = true;
273       break;
274      case 's':
275       write_armap = true;
276       break;
277      case 'u':
278       newer_only = 1;
279       break;
280      case 'v':
281       verbose = 1;
282       break;
283      case 'a':
284       postype = pos_after;
285       break;
286      case 'b':
287       postype = pos_before;
288       break;
289      case 'i':
290       postype = pos_before;
291       break;
292      case 'M':
293
294       mri_mode = 1;
295       break;
296      default:
297       fatal("invalid option %c", c);
298     }
299   }
300
301   if (show_version)
302      printf ("%s version %s\n", program_name, program_version);
303
304   if (mri_mode) {
305     mri_emul();
306   }
307   else {
308     if ((operation == none || operation == print_table) 
309         && write_armap == true)
310      ranlib_only(argv[2]);
311
312     if (operation == none)
313      fatal("no operation specified");
314
315     if (newer_only && operation != replace)
316      fatal("'u' only meaningful with 'r' option.");
317
318     arg_index = 2;
319
320     if (postype != pos_default)
321      posname = argv[arg_index++];
322
323     inarch_filename = argv[arg_index++];
324
325     if (arg_index < argc) {
326       files = argv + arg_index;
327       while (arg_index < argc)
328        if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
329          ignore_symdef = 1;
330          break;
331        }
332     }
333     else
334      files = NULL;
335
336     if (operation == quick_append) {
337       if (files != NULL)
338        do_quick_append(inarch_filename, files);
339       exit(0);
340     }
341
342
343     open_inarch(inarch_filename);
344
345     switch (operation) {
346
347      case print_table:
348       map_over_members(print_descr, files, argc - 3);
349       break;
350
351      case print_files:
352       map_over_members(print_contents, files, argc - 3);
353       break;
354
355      case extract:
356       map_over_members(extract_file, files, argc - 3);
357       break;
358
359      case delete:
360       if (files != NULL)
361        delete_members(files);
362       break;
363
364      case move:
365       if (files != NULL)
366        move_members(files);
367       break;
368
369      case replace:
370       if (files != NULL || write_armap)
371        replace_members(files);
372       break;
373
374       /* Shouldn't happen! */
375      default:
376       fprintf(stderr, "Sorry; this option not implemented.\n");
377     }
378   }
379   return (0);
380 }                               /* main() */
381
382 static
383 char *normalize(file)
384 char *file;
385 {
386     char *    filename = strrchr(file, '/');
387     if (filename != (char *)NULL) {
388         filename ++;
389     }
390     else {
391         filename = file;
392     }
393     return filename;
394 }
395
396 int 
397 open_inarch(archive_filename)
398     char           *archive_filename;
399 {
400     bfd           **last_one;
401     bfd            *next_one;
402     struct stat     sbuf;
403     bfd_error = no_error;
404     if (stat(archive_filename, &sbuf) != 0) {
405         if (errno != ENOENT)
406             bfd_fatal(archive_filename);
407         if (!operation_alters_arch) {
408           fprintf (stderr, "%s: %s not found.\n", program_name,
409                    archive_filename);
410           maybequit();
411           return 0;
412         }       
413
414         /* This routine is one way to forcibly create the archive. */
415         do_quick_append(archive_filename, 0);
416     }
417
418 #ifdef GNU960
419     inarch = bfd_openr(archive_filename, default_target);
420 #else
421     inarch = bfd_openr(archive_filename, NULL);
422 #endif
423     if (inarch == NULL) {
424       bloser:
425         bfd_perror(archive_filename);
426         exit(1);
427     }
428
429     if (bfd_check_format(inarch, bfd_archive) != true)
430         fatal("File %s is not an archive.", archive_filename);
431 #ifdef GNU960
432     gnu960_verify_target(inarch);       /* Exits on failure */
433 #endif
434     last_one = &(inarch->next);
435     /* Read all the contents right away, regardless. */
436     for (next_one = bfd_openr_next_archived_file(inarch, NULL);
437          next_one;
438          next_one = bfd_openr_next_archived_file(inarch, next_one)) {
439         *last_one = next_one;
440         last_one = &next_one->next;
441     }
442     *last_one = (bfd *) NULL;
443     if (bfd_error != no_more_archived_files)
444         goto bloser;
445     return 1;
446 }
447
448
449
450
451
452 void
453 print_contents(abfd)
454     bfd            *abfd;
455 {
456     int             ncopied = 0;
457     struct stat     buf;
458     long            size;
459     if (bfd_stat_arch_elt(abfd, &buf) != 0)
460         fatal("Internal stat error on %s", abfd->filename);
461
462     if (verbose)
463         printf("\n<member %s>\n\n", abfd->filename);
464
465     bfd_seek(abfd, 0, SEEK_SET);
466
467     size = buf.st_size;
468     while (ncopied < size) {
469         char            cbuf[BUFSIZE];
470         int             nread;
471         int             tocopy = size - ncopied;
472         if (tocopy > BUFSIZE)
473             tocopy = BUFSIZE;
474
475         nread = bfd_read(cbuf, 1, tocopy, abfd);        /* oops -- broke
476                                                            abstraction!  */
477
478         if (nread != tocopy)
479             fatal("file %s not a valid archive", abfd->my_archive->filename);
480         fwrite(cbuf, 1, nread, stdout);
481         ncopied += tocopy;
482     }
483 }
484
485
486 /*
487    Extract a member of the archive into its own file.
488
489 We defer opening the new file until after we have read a BUFSIZ chunk of the
490    old one, since we know we have just read the archive header for the old
491    one.  Since most members are shorter than BUFSIZ, this means we will read
492    the old header, read the old data, write a new inode for the new file, and
493    write the new data, and be done. This 'optimization' is what comes from
494    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
495    Gilmore
496 */
497
498 void
499 extract_file(abfd)
500     bfd            *abfd;
501 {
502     FILE           *ostream;
503     char            cbuf[BUFSIZE];
504     int             nread,
505                     tocopy;
506     int             ncopied = 0;
507     long            size;
508     struct stat     buf;
509     if (bfd_stat_arch_elt(abfd, &buf) != 0)
510         fatal("Internal stat error on %s", abfd->filename);
511     size = buf.st_size;
512
513     if (verbose)
514         printf("x - %s\n", abfd->filename);
515
516     bfd_seek(abfd, 0, SEEK_SET);
517
518     ostream = 0;
519     if (size == 0) {
520       /* Seems like an abstraction violation, eh?  Well it's OK! */
521       ostream = fopen(abfd->filename, FOPEN_WB);
522       if (!ostream) {
523         perror(abfd->filename);
524         exit(1);
525       }
526     } else
527     while (ncopied < size) {
528         tocopy = size - ncopied;
529         if (tocopy > BUFSIZE)
530             tocopy = BUFSIZE;
531
532         nread = bfd_read(cbuf, 1, tocopy, abfd);
533         if (nread != tocopy)
534             fatal("file %s not a valid archive", abfd->my_archive->filename);
535
536         /* See comment above; this saves disk arm motion */
537         if (!ostream) {
538             /* Seems like an abstraction violation, eh?  Well it's OK! */
539             ostream = fopen(abfd->filename, FOPEN_WB);
540             if (!ostream) {
541                 perror(abfd->filename);
542                 exit(1);
543             }
544         }
545         fwrite(cbuf, 1, nread, ostream);
546         ncopied += tocopy;
547     }
548
549     fclose(ostream);
550     chmod(abfd->filename, buf.st_mode);
551
552     if (preserve_dates) {
553 #ifdef USG
554         long            tb[2];
555         tb[0] = buf.st_mtime;
556         tb[1] = buf.st_mtime;
557         utime(abfd->filename, tb);      /* FIXME check result */
558 #else
559         struct timeval  tv[2];
560         tv[0].tv_sec = buf.st_mtime;
561         tv[0].tv_usec = 0;
562         tv[1].tv_sec = buf.st_mtime;
563         tv[1].tv_usec = 0;
564         utimes(abfd->filename, tv);     /* FIXME check result */
565 #endif
566     }
567 }
568
569
570 /* Just do it quickly; don't worry about dups, armap, or anything like that */
571
572 /* This is ugly! XXX */
573
574 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
575
576 void
577 do_quick_append(archive_filename, files_to_append)
578     char           *archive_filename;
579     char          **files_to_append;
580
581 {
582     FILE           *ofile,
583                    *ifile;
584     char            buf[BUFSIZE];
585     long            tocopy,
586                     thistime;
587     bfd            *temp;
588     struct stat     sbuf;
589     boolean         newfile = false;
590     bfd_error = no_error;
591
592     if (stat(archive_filename, &sbuf) != 0) {
593         if (errno != ENOENT)
594             bfd_fatal(archive_filename);
595         newfile = true;
596     }
597
598
599     ofile = fopen(archive_filename, FOPEN_AUB);
600     if (ofile == NULL) {
601         perror(program_name);
602         exit(1);
603     }
604
605     /* bletch */
606 #ifdef GNU960
607     temp = bfd_openr(archive_filename, default_target);
608 #else
609     temp = bfd_openr(archive_filename, NULL);
610 #endif
611     if (temp == NULL) {
612         bfd_perror(archive_filename);
613         exit(1);
614     }
615     if (newfile == false) {
616         if (bfd_check_format(temp, bfd_archive) != true)
617             fatal("File %s is not an archive.", archive_filename);
618 #ifdef GNU960
619         gnu960_verify_target(temp);     /* Exits on failure */
620 #endif
621     }
622     else {
623         fwrite(ARMAG, 1, SARMAG, ofile);
624         if (!silent_create)
625             fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
626     }
627
628     /* assume it's an achive, go straight to the end, sans $200 */
629     fseek(ofile, 0, 2);
630
631     for (; files_to_append && *files_to_append; ++files_to_append) {
632         struct ar_hdr  *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
633         if (hdr == NULL) {
634             bfd_perror(*files_to_append);
635             exit(1);
636         }
637
638         BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
639
640         ifile = fopen(*files_to_append, FOPEN_RB);
641         if (ifile == NULL)
642             bfd_perror(program_name);
643
644         if (stat(*files_to_append, &sbuf) != 0)
645             bfd_perror(*files_to_append);
646
647         tocopy = sbuf.st_size;
648
649         /* XXX should do error-checking! */
650         fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
651
652
653         while (tocopy > 0) {
654             thistime = tocopy;
655             if (thistime > BUFSIZE)
656                 thistime = BUFSIZE;
657             fread(buf, 1, thistime, ifile);
658             fwrite(buf, 1, thistime, ofile);
659             tocopy -= thistime;
660         }
661         fclose(ifile);
662         if ((sbuf.st_size % 2) == 1)
663             putc('\n', ofile);
664     }
665     fclose(ofile);
666     bfd_close(temp);
667 }
668
669
670 void
671 write_archive()
672 {
673     bfd            *obfd;
674     int             namelen = strlen(inarch->filename);
675     char           *new_name = xmalloc(namelen + 6);
676     bfd            *contents_head = inarch->next;
677
678         strcpy(new_name, inarch->filename);
679         strcpy(new_name + namelen, "-art");
680         obfd = bfd_openw(new_name,
681                  /* FIXME: violates abstraction; need a better protocol */
682                          (inarch->xvec ? bfd_get_target(inarch) : NULL));
683
684         if (obfd == NULL)
685             bfd_fatal(inarch->filename);
686
687         bfd_set_format(obfd, bfd_archive);
688         obfd->has_armap = write_armap;
689
690         if (bfd_set_archive_head(obfd, contents_head) != true)
691             bfd_fatal(inarch->filename);
692
693         if (!bfd_close(obfd))
694             bfd_fatal(inarch->filename);
695
696         /* We don't care if this fails, we might be creating the
697            archive */
698         (void) unlink(inarch->filename);
699
700         if (rename(new_name, inarch->filename) != 0)
701             bfd_fatal(inarch->filename);
702 }
703
704
705
706 /*
707    returns a pointer to the pointer to the entry which should be rplacd'd
708    into when altering.  default_pos should be how to interpret pos_default,
709    and should be a pos value.
710 */
711
712 bfd **
713 get_pos_bfd(contents, default_pos)
714     bfd           **contents;
715     enum pos        default_pos;
716 {
717     bfd           **after_bfd = contents;
718     enum pos        realpos = (postype == pos_default ? default_pos : postype);
719
720     if (realpos == pos_end) {
721         while (*after_bfd)
722             after_bfd = &((*after_bfd)->next);
723     }
724     else {
725         for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
726             if (!strcmp((*after_bfd)->filename, posname)) {
727                 if (realpos == pos_after)
728                     after_bfd = &(*after_bfd)->next;
729                 break;
730         }
731     }
732     return after_bfd;
733 }
734
735
736 void
737 delete_members(files_to_delete)
738     char          **files_to_delete;
739 {
740     bfd           **current_ptr_ptr;
741     boolean         found;
742     boolean         something_changed = false;
743     for (; *files_to_delete != NULL; ++files_to_delete) {
744         /*
745            In a.out systems, the armap is optional.  It's also called
746            __.SYMDEF.  So if the user asked to delete it, we should remember
747            that fact. The name is NULL in COFF archives, so using this as a
748            key is as good as anything I suppose
749         */
750         if (!strcmp(*files_to_delete, "__.SYMDEF")) {
751             inarch->has_armap = false;
752             write_armap = false;
753             continue;
754         }
755
756         found = false;
757         current_ptr_ptr = &(inarch->next);
758         while (*current_ptr_ptr) {
759             if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
760                 found = true;
761                 something_changed = true;
762                 if (verbose)
763                     printf("d - %s\n",
764                            *files_to_delete);
765                 *current_ptr_ptr = ((*current_ptr_ptr)->next);
766                 goto next_file;
767
768             }
769             else {
770                 current_ptr_ptr = &((*current_ptr_ptr)->next);
771             }
772         }
773
774         if (verbose && found == false) {
775             printf("No member named `%s'\n", *files_to_delete);
776         }
777 next_file:;
778
779     }
780
781     if (something_changed == true) {
782         write_archive();
783     }
784 }
785
786
787 /* Reposition existing members within an archive */
788
789 void
790 move_members(files_to_move)
791     char          **files_to_move;
792 {
793     bfd           **after_bfd;  /* New entries go after this one */
794     bfd           **current_ptr_ptr;    /* cdr pointer into contents */
795
796
797
798
799     for (; *files_to_move; ++files_to_move) {
800         current_ptr_ptr = &(inarch->next);
801         while (*current_ptr_ptr) {
802             bfd            *current_ptr = *current_ptr_ptr;
803             if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
804                 /*
805                    Move this file to the end of the list - first cut from
806                    where it is.
807                 */
808                 *current_ptr_ptr = current_ptr->next;
809
810                 /* Now glue to end */
811                 after_bfd = get_pos_bfd(&inarch->next, pos_end);
812                 *after_bfd = current_ptr;
813                 current_ptr->next = (bfd *) NULL;
814
815                 if (verbose)
816                     printf("m - %s\n", *files_to_move);
817
818                 goto next_file;
819             }
820             current_ptr_ptr = &((*current_ptr_ptr)->next);
821         }
822         fprintf(stderr, "No entry %s in archive %s!\n",
823                 *files_to_move, inarch->filename);
824         exit(1);
825 next_file:;
826     }
827
828     write_archive();
829 }
830
831
832 /* Ought to default to replacing in place, but this is existing practice! */
833
834 void
835 replace_members(files_to_move)
836     char          **files_to_move;
837 {
838     bfd           **after_bfd;  /* New entries go after this one */
839     bfd            *current;
840     bfd           **current_ptr;
841     bfd            *temp;
842     /*
843        If the first item in the archive is an __.SYMDEF then remove it
844     */
845     if (inarch->next &&
846         strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
847         inarch->next = inarch->next->next;
848     }
849
850
851
852     while (files_to_move && *files_to_move) {
853         current_ptr = &inarch->next;
854         while (*current_ptr) {
855             current = *current_ptr;
856             
857             if (!strcmp(normalize(*files_to_move), current->filename)) {
858                 if (newer_only) {
859                     struct stat     fsbuf,
860                                     asbuf;
861
862                     if (current->arelt_data == NULL) {
863                       /* This can only happen if you specify a file on the
864                          command line more than once. */
865                       fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
866                       goto next_file;
867                     }
868
869                     if (stat(*files_to_move, &fsbuf) != 0) {
870                         if (errno != ENOENT)
871                             bfd_fatal(*files_to_move);
872                         goto next_file;
873                     }
874                     if (bfd_stat_arch_elt(current, &asbuf) != 0)
875                         fatal("Internal stat error on %s", current->filename);
876
877                     if (fsbuf.st_mtime <= asbuf.st_mtime)
878                         goto next_file;
879                 }
880
881                 /* snip out this entry from the chain */
882                 *current_ptr = current->next;
883
884                 after_bfd = get_pos_bfd(&inarch->next, pos_end);
885                 temp = *after_bfd;
886                 *after_bfd = bfd_openr(*files_to_move, NULL);
887                 if (*after_bfd == (bfd *) NULL) {
888                     fprintf(stderr, "Can't open file %s\n", *files_to_move);
889                     exit(1);
890                 }
891 #ifdef GNU960
892                 gnu960_verify_target(*after_bfd);       /* Exits on failure */
893 #endif
894                 (*after_bfd)->next = temp;
895
896                 if (verbose) {
897                     printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
898                            *files_to_move);
899                 }
900                 goto next_file;
901             }
902             current_ptr = &(current->next);
903         }
904
905         /* It isn't in there, so add to end */
906
907         after_bfd = get_pos_bfd(&inarch->next, pos_end);
908         temp = *after_bfd;
909         *after_bfd = bfd_openr(*files_to_move, NULL);
910         if (*after_bfd == (bfd *) NULL) {
911             fprintf(stderr, "Can't open file %s\n", *files_to_move);
912             exit(1);
913         }
914 #ifdef GNU960
915         gnu960_verify_target(*after_bfd);       /* Exits on failure */
916 #endif
917         if (verbose) {
918             printf("c - %s\n", *files_to_move);
919         }
920
921         (*after_bfd)->next = temp;
922
923 next_file:;
924
925         files_to_move++;
926     }
927
928
929     write_archive();
930 }
931
932 void
933 ranlib_only(archname)
934     char           *archname;
935 {
936     write_armap = true;
937     open_inarch(archname);
938     write_archive();
939     exit(0);
940 }
941
942
943
944 /* Things which are interesting to map over all or some of the files: */
945
946 void
947 print_descr(abfd)
948     bfd            *abfd;
949 {
950     print_arelt_descr(stdout,abfd, verbose);
951 }
952
953
954