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