This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / binutils / ar.c
1 /* ar.c - Archive modify and extract.
2    Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 1999
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Binutils.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20 \f
21 /*
22    Bugs: should use getopt the way tar does (complete w/optional -) and
23    should have long options too. GNU ar used to check file against filesystem
24    in quick_update and replace operations (would check mtime). Doesn't warn
25    when name truncated. No way to specify pos_end. Error messages should be
26    more consistant.
27 */
28 #include "bfd.h"
29 #include "libiberty.h"
30 #include "progress.h"
31 #include "bucomm.h"
32 #include "aout/ar.h"
33 #include "libbfd.h"
34 #include "arsup.h"
35 #include <sys/stat.h>
36
37 #ifdef __GO32___
38 #define EXT_NAME_LEN 3          /* bufflen of addition to name if it's MS-DOS */
39 #else
40 #define EXT_NAME_LEN 6          /* ditto for *NIX */
41 #endif
42
43 /* We need to open files in binary modes on system where that makes a
44    difference.  */
45 #ifndef O_BINARY
46 #define O_BINARY 0
47 #endif
48
49 #define BUFSIZE 8192
50
51 /* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
52
53 struct ar_hdr *
54   bfd_special_undocumented_glue PARAMS ((bfd * abfd, const char *filename));
55
56 /* Static declarations */
57
58 static void
59 mri_emul PARAMS ((void));
60
61 static const char *
62 normalize PARAMS ((const char *, bfd *));
63
64 static void
65 remove_output PARAMS ((void));
66
67 static void
68 map_over_members PARAMS ((bfd *, void (*)(bfd *), char **, int));
69
70 static void
71 print_contents PARAMS ((bfd * member));
72
73 static void
74 delete_members PARAMS ((bfd *, char **files_to_delete));
75
76 #if 0
77 static void
78 do_quick_append PARAMS ((const char *archive_filename,
79                          char **files_to_append));
80 #endif
81
82 static void
83 move_members PARAMS ((bfd *, char **files_to_move));
84
85 static void
86 replace_members PARAMS ((bfd *, char **files_to_replace, boolean quick));
87
88 static void
89 print_descr PARAMS ((bfd * abfd));
90
91 static void
92 write_archive PARAMS ((bfd *));
93
94 static void
95 ranlib_only PARAMS ((const char *archname));
96
97 static void
98 ranlib_touch PARAMS ((const char *archname));
99
100 static void
101 usage PARAMS ((int));
102 \f
103 /** Globals and flags */
104
105 int mri_mode;
106
107 /* This flag distinguishes between ar and ranlib:
108    1 means this is 'ranlib'; 0 means this is 'ar'.
109    -1 means if we should use argv[0] to decide.  */
110 extern int is_ranlib;
111
112 /* Nonzero means don't warn about creating the archive file if necessary.  */
113 int silent_create = 0;
114
115 /* Nonzero means describe each action performed.  */
116 int verbose = 0;
117
118 /* Nonzero means preserve dates of members when extracting them.  */
119 int preserve_dates = 0;
120
121 /* Nonzero means don't replace existing members whose dates are more recent
122    than the corresponding files.  */
123 int newer_only = 0;
124
125 /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
126    member).  -1 means we've been explicitly asked to not write a symbol table;
127    +1 means we've been explictly asked to write it;
128    0 is the default.
129    Traditionally, the default in BSD has been to not write the table.
130    However, for POSIX.2 compliance the default is now to write a symbol table
131    if any of the members are object files.  */
132 int write_armap = 0;
133
134 /* Nonzero means it's the name of an existing member; position new or moved
135    files with respect to this one.  */
136 char *posname = NULL;
137
138 /* Sez how to use `posname': pos_before means position before that member.
139    pos_after means position after that member. pos_end means always at end.
140    pos_default means default appropriately. For the latter two, `posname'
141    should also be zero.  */
142 enum pos
143   {
144     pos_default, pos_before, pos_after, pos_end
145   } postype = pos_default;
146
147 static bfd **
148 get_pos_bfd PARAMS ((bfd **, enum pos, const char *));
149
150 /* Whether to truncate names of files stored in the archive.  */
151 static boolean ar_truncate = false;
152
153 int interactive = 0;
154
155 static void
156 mri_emul ()
157 {
158   interactive = isatty (fileno (stdin));
159   yyparse ();
160 }
161
162 /* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
163    COUNT is the length of the FILES chain; FUNCTION is called on each entry
164    whose name matches one in FILES.  */
165
166 static void
167 map_over_members (arch, function, files, count)
168      bfd *arch;
169      void (*function) PARAMS ((bfd *));
170      char **files;
171      int count;
172 {
173   bfd *head;
174
175   if (count == 0)
176     {
177       for (head = arch->next; head; head = head->next)
178         {
179           PROGRESS (1);
180           function (head);
181         }
182       return;
183     }
184   /* This may appear to be a baroque way of accomplishing what we want.
185      However we have to iterate over the filenames in order to notice where
186      a filename is requested but does not exist in the archive.  Ditto
187      mapping over each file each time -- we want to hack multiple
188      references.  */
189
190   for (; count > 0; files++, count--)
191     {
192       boolean found = false;
193
194       for (head = arch->next; head; head = head->next)
195         {
196           PROGRESS (1);
197           if (head->filename == NULL)
198             {
199               /* Some archive formats don't get the filenames filled in
200                  until the elements are opened.  */
201               struct stat buf;
202               bfd_stat_arch_elt (head, &buf);
203             }
204           if ((head->filename != NULL) &&
205               (!strcmp (*files, head->filename)))
206             {
207               found = true;
208               function (head);
209             }
210         }
211       if (!found)
212         /* xgettext:c-format */
213         fprintf (stderr, _("no entry %s in archive\n"), *files);
214     }
215 }
216 \f
217 boolean operation_alters_arch = false;
218
219 static void
220 usage (help)
221      int help;
222 {
223   FILE *s;
224
225   s = help ? stdout : stderr;
226   
227   if (! is_ranlib)
228     {
229       /* xgettext:c-format */
230       fprintf (s, _("Usage: %s [-]{dmpqrstx}[abcilosSuvV] [member-name] archive-file file...\n"), program_name);
231       /* xgettext:c-format */
232       fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
233       fprintf (s, _(" commands:\n"));
234       fprintf (s, _("  d            - delete file(s) from the archive\n"));
235       fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
236       fprintf (s, _("  p            - print file(s) found in the archive\n"));
237       fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
238       fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
239       fprintf (s, _("  t            - display contents of archive\n"));
240       fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
241       fprintf (s, _(" command specific modifiers:\n"));
242       fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
243       fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
244       fprintf (s, _("  [f]          - truncate inserted file names\n"));
245       fprintf (s, _("  [o]          - preserve original dates\n"));
246       fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
247       fprintf (s, _(" generic modifiers:\n"));
248       fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
249       fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
250       fprintf (s, _("  [S]          - do not build a symbol table\n"));
251       fprintf (s, _("  [v]          - be verbose\n"));
252       fprintf (s, _("  [V]          - display the version number\n"));
253     }
254   else
255     /* xgettext:c-format */
256     fprintf (s, _("Usage: %s [-vV] archive\n"), program_name);
257
258   list_supported_targets (program_name, stderr);
259
260   if (help)
261     fprintf (s, _("Report bugs to bug-gnu-utils@gnu.org\n"));
262
263   xexit (help ? 0 : 1);
264 }
265
266 /* Normalize a file name specified on the command line into a file
267    name which we will use in an archive.  */
268
269 static const char *
270 normalize (file, abfd)
271      const char *file;
272      bfd *abfd;
273 {
274   const char *filename;
275
276   filename = strrchr (file, '/');
277   if (filename != (char *) NULL)
278     filename++;
279   else
280     filename = file;
281
282   if (ar_truncate
283       && abfd != NULL
284       && strlen (filename) > abfd->xvec->ar_max_namelen)
285     {
286       char *s;
287
288       /* Space leak.  */
289       s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
290       memcpy (s, filename, abfd->xvec->ar_max_namelen);
291       s[abfd->xvec->ar_max_namelen] = '\0';
292       filename = s;
293     }
294
295   return filename;
296 }
297
298 /* Remove any output file.  This is only called via xatexit.  */
299
300 static char *output_filename = NULL;
301 static FILE *output_file = NULL;
302 static bfd *output_bfd = NULL;
303
304 static void
305 remove_output ()
306 {
307   if (output_filename != NULL)
308     {
309       if (output_bfd != NULL && output_bfd->iostream != NULL)
310         fclose ((FILE *) (output_bfd->iostream));
311       if (output_file != NULL)
312         fclose (output_file);
313       unlink (output_filename);
314     }
315 }
316
317 /* The option parsing should be in its own function.
318    It will be when I have getopt working.  */
319
320 int
321 main (argc, argv)
322      int argc;
323      char **argv;
324 {
325   char *arg_ptr;
326   char c;
327   enum
328     {
329       none = 0, delete, replace, print_table,
330       print_files, extract, move, quick_append
331     } operation = none;
332   int arg_index;
333   char **files;
334   char *inarch_filename;
335   int show_version;
336
337 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
338   setlocale (LC_MESSAGES, "");
339 #endif
340   bindtextdomain (PACKAGE, LOCALEDIR);
341   textdomain (PACKAGE);
342
343   program_name = argv[0];
344   xmalloc_set_program_name (program_name);
345
346   if (is_ranlib < 0)
347     {
348       char *temp;
349
350       temp = strrchr (program_name, '/');
351       if (temp == NULL)
352         temp = program_name;
353       else
354         ++temp;
355       if (strlen (temp) >= 6
356           && strcmp (temp + strlen (temp) - 6, "ranlib") == 0)
357         is_ranlib = 1;
358       else
359         is_ranlib = 0;
360     }
361
362   if (argc > 1 && argv[1][0] == '-')
363     {
364       if (strcmp (argv[1], "--help") == 0)
365         usage (1);
366       else if (strcmp (argv[1], "--version") == 0)
367         {
368           if (is_ranlib)
369             print_version ("ranlib");
370           else
371             print_version ("ar");
372         }
373     }
374
375   START_PROGRESS (program_name, 0);
376
377   bfd_init ();
378   set_default_bfd_target ();
379
380   show_version = 0;
381
382   xatexit (remove_output);
383
384   if (is_ranlib)
385     {
386       boolean touch = false;
387
388       if (argc < 2 || strcmp (argv[1], "--help") == 0)
389         usage (0);
390       if (strcmp (argv[1], "-V") == 0
391           || strcmp (argv[1], "-v") == 0
392           || strncmp (argv[1], "--v", 3) == 0)
393         print_version ("ranlib");
394       arg_index = 1;
395       if (strcmp (argv[1], "-t") == 0)
396         {
397           ++arg_index;
398           touch = true;
399         }
400       while (arg_index < argc)
401         {
402           if (! touch)
403             ranlib_only (argv[arg_index]);
404           else
405             ranlib_touch (argv[arg_index]);
406           ++arg_index;
407         }
408       xexit (0);
409     }
410
411   if (argc == 2 && strcmp (argv[1], "-M") == 0)
412     {
413       mri_emul ();
414       xexit (0);
415     }
416
417   if (argc < 2)
418     usage (0);
419
420   arg_ptr = argv[1];
421
422   if (*arg_ptr == '-')
423     ++arg_ptr;                  /* compatibility */
424
425   while ((c = *arg_ptr++) != '\0')
426     {
427       switch (c)
428         {
429         case 'd':
430         case 'm':
431         case 'p':
432         case 'q':
433         case 'r':
434         case 't':
435         case 'x':
436           if (operation != none)
437             fatal (_("two different operation options specified"));
438           switch (c)
439             {
440             case 'd':
441               operation = delete;
442               operation_alters_arch = true;
443               break;
444             case 'm':
445               operation = move;
446               operation_alters_arch = true;
447               break;
448             case 'p':
449               operation = print_files;
450               break;
451             case 'q':
452               operation = quick_append;
453               operation_alters_arch = true;
454               break;
455             case 'r':
456               operation = replace;
457               operation_alters_arch = true;
458               break;
459             case 't':
460               operation = print_table;
461               break;
462             case 'x':
463               operation = extract;
464               break;
465             }
466         case 'l':
467           break;
468         case 'c':
469           silent_create = 1;
470           break;
471         case 'o':
472           preserve_dates = 1;
473           break;
474         case 'V':
475           show_version = true;
476           break;
477         case 's':
478           write_armap = 1;
479           break;
480         case 'S':
481           write_armap = -1;
482           break;
483         case 'u':
484           newer_only = 1;
485           break;
486         case 'v':
487           verbose = 1;
488           break;
489         case 'a':
490           postype = pos_after;
491           break;
492         case 'b':
493           postype = pos_before;
494           break;
495         case 'i':
496           postype = pos_before;
497           break;
498         case 'M':
499           mri_mode = 1;
500           break;
501         case 'f':
502           ar_truncate = true;
503           break;
504         default:
505           /* xgettext:c-format */
506           fprintf (stderr, _("%s: illegal option -- %c\n"), program_name, c);
507           usage (0);
508         }
509     }
510
511   if (show_version)
512     print_version ("ar");
513
514   if (argc < 3)
515     usage (0);
516
517   if (mri_mode)
518     {
519       mri_emul ();
520     }
521   else
522     {
523       bfd *arch;
524
525       /* We can't write an armap when using ar q, so just do ar r
526          instead.  */
527       if (operation == quick_append && write_armap)
528         operation = replace;
529
530       if ((operation == none || operation == print_table)
531           && write_armap == 1)
532         {
533           ranlib_only (argv[2]);
534           xexit (0);
535         }
536
537       if (operation == none)
538         fatal (_("no operation specified"));
539
540       if (newer_only && operation != replace)
541         fatal (_("`u' is only meaningful with the `r' option."));
542
543       arg_index = 2;
544
545       if (postype != pos_default)
546         posname = argv[arg_index++];
547
548       inarch_filename = argv[arg_index++];
549
550       files = arg_index < argc ? argv + arg_index : NULL;
551
552 #if 0
553       /* We don't use do_quick_append any more.  Too many systems
554          expect ar to always rebuild the symbol table even when q is
555          used.  */
556
557       /* We can't do a quick append if we need to construct an
558          extended name table, because do_quick_append won't be able to
559          rebuild the name table.  Unfortunately, at this point we
560          don't actually know the maximum name length permitted by this
561          object file format.  So, we guess.  FIXME.  */
562       if (operation == quick_append && ! ar_truncate)
563         {
564           char **chk;
565
566           for (chk = files; chk != NULL && *chk != '\0'; chk++)
567             {
568               if (strlen (normalize (*chk, (bfd *) NULL)) > 14)
569                 {
570                   operation = replace;
571                   break;
572                 }
573             }
574         }
575
576       if (operation == quick_append)
577         {
578           /* Note that quick appending to a non-existent archive creates it,
579              even if there are no files to append. */
580           do_quick_append (inarch_filename, files);
581           xexit (0);
582         }
583 #endif
584
585       arch = open_inarch (inarch_filename,
586                           files == NULL ? (char *) NULL : files[0]);
587
588       switch (operation)
589         {
590         case print_table:
591           map_over_members (arch, print_descr, files, argc - 3);
592           break;
593
594         case print_files:
595           map_over_members (arch, print_contents, files, argc - 3);
596           break;
597
598         case extract:
599           map_over_members (arch, extract_file, files, argc - 3);
600           break;
601
602         case delete:
603           if (files != NULL)
604             delete_members (arch, files);
605           break;
606
607         case move:
608           if (files != NULL)
609             move_members (arch, files);
610           break;
611
612         case replace:
613         case quick_append:
614           if (files != NULL || write_armap > 0)
615             replace_members (arch, files, operation == quick_append);
616           break;
617
618           /* Shouldn't happen! */
619         default:
620           /* xgettext:c-format */
621           fprintf (stderr, _("%s: internal error -- this option not implemented\n"),
622                    program_name);
623           xexit (1);
624         }
625     }
626
627   END_PROGRESS (program_name);
628
629   xexit (0);
630   return 0;
631 }
632
633 bfd *
634 open_inarch (archive_filename, file)
635      const char *archive_filename;
636      const char *file;
637 {
638   const char *target;
639   bfd **last_one;
640   bfd *next_one;
641   struct stat sbuf;
642   bfd *arch;
643   char **matching;
644
645   bfd_set_error (bfd_error_no_error);
646
647   target = NULL;
648
649   if (stat (archive_filename, &sbuf) != 0)
650     {
651 #ifndef __GO32__
652
653 /* KLUDGE ALERT! Temporary fix until I figger why
654  * stat() is wrong ... think it's buried in GO32's IDT
655  * - Jax
656  */
657       if (errno != ENOENT)
658         bfd_fatal (archive_filename);
659 #endif
660
661       if (!operation_alters_arch)
662         {
663           fprintf (stderr, "%s: ", program_name);
664           perror (archive_filename);
665           maybequit ();
666           return NULL;
667         }
668
669       /* Try to figure out the target to use for the archive from the
670          first object on the list.  */
671       if (file != NULL)
672         {
673           bfd *obj;
674
675           obj = bfd_openr (file, NULL);
676           if (obj != NULL)
677             {
678               if (bfd_check_format (obj, bfd_object))
679                 target = bfd_get_target (obj);
680               (void) bfd_close (obj);
681             }
682         }
683
684       /* Create an empty archive.  */
685       arch = bfd_openw (archive_filename, target);
686       if (arch == NULL
687           || ! bfd_set_format (arch, bfd_archive)
688           || ! bfd_close (arch))
689         bfd_fatal (archive_filename);
690     }
691
692   arch = bfd_openr (archive_filename, target);
693   if (arch == NULL)
694     {
695     bloser:
696       bfd_fatal (archive_filename);
697     }
698
699   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
700     {
701       bfd_nonfatal (archive_filename);
702       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
703         {
704           list_matching_formats (matching);
705           free (matching);
706         }
707       xexit (1);
708     }
709
710   last_one = &(arch->next);
711   /* Read all the contents right away, regardless.  */
712   for (next_one = bfd_openr_next_archived_file (arch, NULL);
713        next_one;
714        next_one = bfd_openr_next_archived_file (arch, next_one))
715     {
716       PROGRESS (1);
717       *last_one = next_one;
718       last_one = &next_one->next;
719     }
720   *last_one = (bfd *) NULL;
721   if (bfd_get_error () != bfd_error_no_more_archived_files)
722     goto bloser;
723   return arch;
724 }
725
726 static void
727 print_contents (abfd)
728      bfd *abfd;
729 {
730   int ncopied = 0;
731   char *cbuf = xmalloc (BUFSIZE);
732   struct stat buf;
733   long size;
734   if (bfd_stat_arch_elt (abfd, &buf) != 0)
735     /* xgettext:c-format */
736     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
737
738   if (verbose)
739     /* xgettext:c-format */
740     printf (_("\n<member %s>\n\n"), bfd_get_filename (abfd));
741
742   bfd_seek (abfd, 0, SEEK_SET);
743
744   size = buf.st_size;
745   while (ncopied < size)
746     {
747
748       int nread;
749       int tocopy = size - ncopied;
750       if (tocopy > BUFSIZE)
751         tocopy = BUFSIZE;
752
753       nread = bfd_read (cbuf, 1, tocopy, abfd); /* oops -- broke
754                                                            abstraction!  */
755       if (nread != tocopy)
756         /* xgettext:c-format */
757         fatal (_("%s is not a valid archive"),
758                bfd_get_filename (bfd_my_archive (abfd)));
759       fwrite (cbuf, 1, nread, stdout);
760       ncopied += tocopy;
761     }
762   free (cbuf);
763 }
764
765 /* Extract a member of the archive into its own file.
766
767    We defer opening the new file until after we have read a BUFSIZ chunk of the
768    old one, since we know we have just read the archive header for the old
769    one.  Since most members are shorter than BUFSIZ, this means we will read
770    the old header, read the old data, write a new inode for the new file, and
771    write the new data, and be done. This 'optimization' is what comes from
772    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
773    Gilmore  */
774
775 void
776 extract_file (abfd)
777      bfd *abfd;
778 {
779   FILE *ostream;
780   char *cbuf = xmalloc (BUFSIZE);
781   int nread, tocopy;
782   long ncopied = 0;
783   long size;
784   struct stat buf;
785   
786   if (bfd_stat_arch_elt (abfd, &buf) != 0)
787     /* xgettext:c-format */
788     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
789   size = buf.st_size;
790
791   if (size < 0)
792     /* xgettext:c-format */
793     fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
794   
795   if (verbose)
796     printf ("x - %s\n", bfd_get_filename (abfd));
797
798   bfd_seek (abfd, 0, SEEK_SET);
799
800   ostream = NULL;
801   if (size == 0)
802     {
803       /* Seems like an abstraction violation, eh?  Well it's OK! */
804       output_filename = bfd_get_filename (abfd);
805
806       ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
807       if (ostream == NULL)
808         {
809           perror (bfd_get_filename (abfd));
810           xexit (1);
811         }
812
813       output_file = ostream;
814     }
815   else
816     while (ncopied < size)
817       {
818         tocopy = size - ncopied;
819         if (tocopy > BUFSIZE)
820           tocopy = BUFSIZE;
821
822         nread = bfd_read (cbuf, 1, tocopy, abfd);
823         if (nread != tocopy)
824           /* xgettext:c-format */
825           fatal (_("%s is not a valid archive"),
826                  bfd_get_filename (bfd_my_archive (abfd)));
827
828         /* See comment above; this saves disk arm motion */
829         if (ostream == NULL)
830           {
831             /* Seems like an abstraction violation, eh?  Well it's OK! */
832             output_filename = bfd_get_filename (abfd);
833
834             ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
835             if (ostream == NULL)
836               {
837                 perror (bfd_get_filename (abfd));
838                 xexit (1);
839               }
840
841             output_file = ostream;
842           }
843         fwrite (cbuf, 1, nread, ostream);
844         ncopied += tocopy;
845       }
846
847   if (ostream != NULL)
848     fclose (ostream);
849
850   output_file = NULL;
851   output_filename = NULL;
852
853   chmod (bfd_get_filename (abfd), buf.st_mode);
854
855   if (preserve_dates)
856     set_times (bfd_get_filename (abfd), &buf);
857
858   free (cbuf);
859 }
860
861 #if 0
862
863 /* We don't use this anymore.  Too many systems expect ar to rebuild
864    the symbol table even when q is used.  */
865
866 /* Just do it quickly; don't worry about dups, armap, or anything like that */
867
868 static void
869 do_quick_append (archive_filename, files_to_append)
870      const char *archive_filename;
871      char **files_to_append;
872 {
873   FILE *ofile, *ifile;
874   char *buf = xmalloc (BUFSIZE);
875   long tocopy, thistime;
876   bfd *temp;
877   struct stat sbuf;
878   boolean newfile = false;
879   bfd_set_error (bfd_error_no_error);
880
881   if (stat (archive_filename, &sbuf) != 0)
882     {
883
884 #ifndef __GO32__
885
886 /* KLUDGE ALERT! Temporary fix until I figger why
887  * stat() is wrong ... think it's buried in GO32's IDT
888  * - Jax
889  */
890
891       if (errno != ENOENT)
892         bfd_fatal (archive_filename);
893 #endif
894
895       newfile = true;
896     }
897
898   ofile = fopen (archive_filename, FOPEN_AUB);
899   if (ofile == NULL)
900     {
901       perror (program_name);
902       xexit (1);
903     }
904
905   temp = bfd_openr (archive_filename, NULL);
906   if (temp == NULL)
907     {
908       bfd_fatal (archive_filename);
909     }
910   if (newfile == false)
911     {
912       if (bfd_check_format (temp, bfd_archive) != true)
913         /* xgettext:c-format */
914         fatal (_("%s is not an archive"), archive_filename);
915     }
916   else
917     {
918       fwrite (ARMAG, 1, SARMAG, ofile);
919       if (!silent_create)
920         /* xgettext:c-format */
921         fprintf (stderr, _("%s: creating %s\n"),
922                  program_name, archive_filename);
923     }
924
925   if (ar_truncate)
926     temp->flags |= BFD_TRADITIONAL_FORMAT;
927
928   /* assume it's an achive, go straight to the end, sans $200 */
929   fseek (ofile, 0, 2);
930
931   for (; files_to_append && *files_to_append; ++files_to_append)
932     {
933       struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append);
934       if (hdr == NULL)
935         {
936           bfd_fatal (*files_to_append);
937         }
938
939       BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
940
941       ifile = fopen (*files_to_append, FOPEN_RB);
942       if (ifile == NULL)
943         {
944           bfd_nonfatal (*files_to_append);
945         }
946
947       if (stat (*files_to_append, &sbuf) != 0)
948         {
949           bfd_nonfatal (*files_to_append);
950         }
951
952       tocopy = sbuf.st_size;
953
954       /* XXX should do error-checking! */
955       fwrite (hdr, 1, sizeof (struct ar_hdr), ofile);
956
957       while (tocopy > 0)
958         {
959           thistime = tocopy;
960           if (thistime > BUFSIZE)
961             thistime = BUFSIZE;
962           fread (buf, 1, thistime, ifile);
963           fwrite (buf, 1, thistime, ofile);
964           tocopy -= thistime;
965         }
966       fclose (ifile);
967       if ((sbuf.st_size % 2) == 1)
968         putc ('\012', ofile);
969     }
970   fclose (ofile);
971   bfd_close (temp);
972   free (buf);
973 }
974
975 #endif /* 0 */
976
977 static void
978 write_archive (iarch)
979      bfd *iarch;
980 {
981   bfd *obfd;
982   char *old_name, *new_name;
983   bfd *contents_head = iarch->next;
984
985   old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
986   strcpy (old_name, bfd_get_filename (iarch));
987   new_name = make_tempname (old_name);
988
989   output_filename = new_name;
990
991   obfd = bfd_openw (new_name, bfd_get_target (iarch));
992
993   if (obfd == NULL)
994     bfd_fatal (old_name);
995
996   output_bfd = obfd;
997
998   bfd_set_format (obfd, bfd_archive);
999
1000   /* Request writing the archive symbol table unless we've
1001      been explicitly requested not to.  */
1002   obfd->has_armap = write_armap >= 0;
1003
1004   if (ar_truncate)
1005     {
1006       /* This should really use bfd_set_file_flags, but that rejects
1007          archives.  */
1008       obfd->flags |= BFD_TRADITIONAL_FORMAT;
1009     }
1010
1011   if (bfd_set_archive_head (obfd, contents_head) != true)
1012     bfd_fatal (old_name);
1013
1014   if (!bfd_close (obfd))
1015     bfd_fatal (old_name);
1016
1017   output_bfd = NULL;
1018   output_filename = NULL;
1019
1020   /* We don't care if this fails; we might be creating the archive.  */
1021   bfd_close (iarch);
1022
1023   if (smart_rename (new_name, old_name, 0) != 0)
1024     xexit (1);
1025 }
1026
1027 /* Return a pointer to the pointer to the entry which should be rplacd'd
1028    into when altering.  DEFAULT_POS should be how to interpret pos_default,
1029    and should be a pos value.  */
1030
1031 static bfd **
1032 get_pos_bfd (contents, default_pos, default_posname)
1033      bfd **contents;
1034      enum pos default_pos;
1035      const char *default_posname;
1036 {
1037   bfd **after_bfd = contents;
1038   enum pos realpos;
1039   const char *realposname;
1040
1041   if (postype == pos_default)
1042     {
1043       realpos = default_pos;
1044       realposname = default_posname;
1045     }
1046   else
1047     {
1048       realpos = postype;
1049       realposname = posname;
1050     }
1051
1052   if (realpos == pos_end)
1053     {
1054       while (*after_bfd)
1055         after_bfd = &((*after_bfd)->next);
1056     }
1057   else
1058     {
1059       for (; *after_bfd; after_bfd = &(*after_bfd)->next)
1060         if (strcmp ((*after_bfd)->filename, realposname) == 0)
1061           {
1062             if (realpos == pos_after)
1063               after_bfd = &(*after_bfd)->next;
1064             break;
1065           }
1066     }
1067   return after_bfd;
1068 }
1069
1070 static void
1071 delete_members (arch, files_to_delete)
1072      bfd *arch;
1073      char **files_to_delete;
1074 {
1075   bfd **current_ptr_ptr;
1076   boolean found;
1077   boolean something_changed = false;
1078   for (; *files_to_delete != NULL; ++files_to_delete)
1079     {
1080       /* In a.out systems, the armap is optional.  It's also called
1081          __.SYMDEF.  So if the user asked to delete it, we should remember
1082          that fact. This isn't quite right for COFF systems (where
1083          __.SYMDEF might be regular member), but it's very unlikely
1084          to be a problem.  FIXME */
1085
1086       if (!strcmp (*files_to_delete, "__.SYMDEF"))
1087         {
1088           arch->has_armap = false;
1089           write_armap = -1;
1090           continue;
1091         }
1092
1093       found = false;
1094       current_ptr_ptr = &(arch->next);
1095       while (*current_ptr_ptr)
1096         {
1097           if (strcmp (*files_to_delete, (*current_ptr_ptr)->filename) == 0)
1098             {
1099               found = true;
1100               something_changed = true;
1101               if (verbose)
1102                 printf ("d - %s\n",
1103                         *files_to_delete);
1104               *current_ptr_ptr = ((*current_ptr_ptr)->next);
1105               goto next_file;
1106             }
1107           else
1108             {
1109               current_ptr_ptr = &((*current_ptr_ptr)->next);
1110             }
1111         }
1112
1113       if (verbose && found == false)
1114         {
1115           /* xgettext:c-format */
1116           printf (_("No member named `%s'\n"), *files_to_delete);
1117         }
1118     next_file:
1119       ;
1120     }
1121
1122   if (something_changed == true)
1123     {
1124       write_archive (arch);
1125     }
1126 }
1127
1128
1129 /* Reposition existing members within an archive */
1130
1131 static void
1132 move_members (arch, files_to_move)
1133      bfd *arch;
1134      char **files_to_move;
1135 {
1136   bfd **after_bfd;              /* New entries go after this one */
1137   bfd **current_ptr_ptr;        /* cdr pointer into contents */
1138
1139   for (; *files_to_move; ++files_to_move)
1140     {
1141       current_ptr_ptr = &(arch->next);
1142       while (*current_ptr_ptr)
1143         {
1144           bfd *current_ptr = *current_ptr_ptr;
1145           if (strcmp (normalize (*files_to_move, arch),
1146                       current_ptr->filename) == 0)
1147             {
1148               /* Move this file to the end of the list - first cut from
1149                  where it is.  */
1150               bfd *link;
1151               *current_ptr_ptr = current_ptr->next;
1152
1153               /* Now glue to end */
1154               after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1155               link = *after_bfd;
1156               *after_bfd = current_ptr;
1157               current_ptr->next = link;
1158
1159               if (verbose)
1160                 printf ("m - %s\n", *files_to_move);
1161
1162               goto next_file;
1163             }
1164
1165           current_ptr_ptr = &((*current_ptr_ptr)->next);
1166         }
1167       /* xgettext:c-format */
1168       fprintf (stderr, _("%s: no entry %s in archive %s!\n"),
1169                program_name, *files_to_move, arch->filename);
1170       xexit (1);
1171     next_file:;
1172     }
1173
1174   write_archive (arch);
1175 }
1176
1177 /* Ought to default to replacing in place, but this is existing practice!  */
1178
1179 static void
1180 replace_members (arch, files_to_move, quick)
1181      bfd *arch;
1182      char **files_to_move;
1183      boolean quick;
1184 {
1185   boolean changed = false;
1186   bfd **after_bfd;              /* New entries go after this one */
1187   bfd *current;
1188   bfd **current_ptr;
1189   bfd *temp;
1190
1191   while (files_to_move && *files_to_move)
1192     {
1193       if (! quick)
1194         {
1195           current_ptr = &arch->next;
1196           while (*current_ptr)
1197             {
1198               current = *current_ptr;
1199
1200               /* For compatibility with existing ar programs, we
1201                  permit the same file to be added multiple times.  */
1202               if (strcmp (normalize (*files_to_move, arch),
1203                           normalize (current->filename, arch)) == 0
1204                   && current->arelt_data != NULL)
1205                 {
1206                   if (newer_only)
1207                     {
1208                       struct stat fsbuf, asbuf;
1209
1210                       if (stat (*files_to_move, &fsbuf) != 0)
1211                         {
1212                           if (errno != ENOENT)
1213                             bfd_fatal (*files_to_move);
1214                           goto next_file;
1215                         }
1216                       if (bfd_stat_arch_elt (current, &asbuf) != 0)
1217                         /* xgettext:c-format */
1218                         fatal (_("internal stat error on %s"), current->filename);
1219
1220                       if (fsbuf.st_mtime <= asbuf.st_mtime)
1221                         goto next_file;
1222                     }
1223
1224                   after_bfd = get_pos_bfd (&arch->next, pos_after,
1225                                            current->filename);
1226                   temp = *after_bfd;
1227
1228                   *after_bfd = bfd_openr (*files_to_move, NULL);
1229                   if (*after_bfd == (bfd *) NULL)
1230                     {
1231                       bfd_fatal (*files_to_move);
1232                     }
1233                   (*after_bfd)->next = temp;
1234
1235                   /* snip out this entry from the chain */
1236                   *current_ptr = (*current_ptr)->next;
1237
1238                   if (verbose)
1239                     {
1240                       printf ("r - %s\n", *files_to_move);
1241                     }
1242
1243                   changed = true;
1244
1245                   goto next_file;
1246                 }
1247               current_ptr = &(current->next);
1248             }
1249         }
1250
1251       /* Add to the end of the archive.  */
1252
1253       after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1254       temp = *after_bfd;
1255       *after_bfd = bfd_openr (*files_to_move, NULL);
1256       if (*after_bfd == (bfd *) NULL)
1257         {
1258           bfd_fatal (*files_to_move);
1259         }
1260       if (verbose)
1261         {
1262           printf ("a - %s\n", *files_to_move);
1263         }
1264
1265       (*after_bfd)->next = temp;
1266
1267       changed = true;
1268
1269     next_file:;
1270
1271       files_to_move++;
1272     }
1273
1274   if (changed)
1275     write_archive (arch);
1276 }
1277
1278 static void
1279 ranlib_only (archname)
1280      const char *archname;
1281 {
1282   bfd *arch;
1283
1284   write_armap = 1;
1285   arch = open_inarch (archname, (char *) NULL);
1286   if (arch == NULL)
1287     xexit (1);
1288   write_archive (arch);
1289 }
1290
1291 /* Update the timestamp of the symbol map of an archive.  */
1292
1293 static void
1294 ranlib_touch (archname)
1295      const char *archname;
1296 {
1297 #ifdef __GO32__
1298   /* I don't think updating works on go32.  */
1299   ranlib_only (archname);
1300 #else
1301   int f;
1302   bfd *arch;
1303   char **matching;
1304
1305   f = open (archname, O_RDWR | O_BINARY, 0);
1306   if (f < 0)
1307     {
1308       bfd_set_error (bfd_error_system_call);
1309       bfd_fatal (archname);
1310     }
1311
1312   arch = bfd_fdopenr (archname, (const char *) NULL, f);
1313   if (arch == NULL)
1314     bfd_fatal (archname);
1315   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
1316     {
1317       bfd_nonfatal (archname);
1318       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
1319         {
1320           list_matching_formats (matching);
1321           free (matching);
1322         }
1323       xexit (1);
1324     }
1325
1326   if (! bfd_has_map (arch))
1327     /* xgettext:c-format */
1328     fatal (_("%s: no archive map to update"), archname);
1329
1330   bfd_update_armap_timestamp (arch);
1331
1332   if (! bfd_close (arch))
1333     bfd_fatal (archname);
1334 #endif
1335 }
1336
1337 /* Things which are interesting to map over all or some of the files: */
1338
1339 static void
1340 print_descr (abfd)
1341      bfd *abfd;
1342 {
1343   print_arelt_descr (stdout, abfd, verbose);
1344 }