Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / binutils-2.15 / binutils / arsup.c
1 /* arsup.c - Archive support for MRI compatibility
2    Copyright 1992, 1994, 1995, 1996, 1997, 2000, 2002, 2003, 2004
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
21
22 /* Contributed by Steve Chamberlain
23    sac@cygnus.com
24
25    This file looks after requests from arparse.y, to provide the MRI
26    style librarian command syntax + 1 word LIST.  */
27
28 #include "bfd.h"
29 #include "arsup.h"
30 #include "libiberty.h"
31 #include "bucomm.h"
32 #include "filenames.h"
33
34 static void map_over_list
35   (bfd *, void (*function) (bfd *, bfd *), struct list *);
36 static void ar_directory_doer (bfd *, bfd *);
37 static void ar_addlib_doer (bfd *, bfd *);
38
39 extern int verbose;
40
41 static void
42 map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
43 {
44   bfd *head;
45
46   if (list == NULL)
47     {
48       bfd *next;
49
50       head = arch->next;
51       while (head != NULL)
52         {
53           next = head->next;
54           function (head, (bfd *) NULL);
55           head = next;
56         }
57     }
58   else
59     {
60       struct list *ptr;
61
62       /* This may appear to be a baroque way of accomplishing what we
63          want.  however we have to iterate over the filenames in order
64          to notice where a filename is requested but does not exist in
65          the archive.  Ditto mapping over each file each time -- we
66          want to hack multiple references.  */
67       for (ptr = list; ptr; ptr = ptr->next)
68         {
69           bfd_boolean found = FALSE;
70           bfd *prev = arch;
71
72           for (head = arch->next; head; head = head->next)
73             {
74               if (head->filename != NULL
75                   && FILENAME_CMP (ptr->name, head->filename) == 0)
76                 {
77                   found = TRUE;
78                   function (head, prev);
79                 }
80               prev = head;
81             }
82           if (! found)
83             fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
84         }
85     }
86 }
87
88
89 FILE *outfile;
90
91 static void
92 ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
93 {
94   print_arelt_descr(outfile, abfd, verbose);
95 }
96
97 void
98 ar_directory (char *ar_name, struct list *list, char *output)
99 {
100   bfd *arch;
101
102   arch = open_inarch (ar_name, (char *) NULL);
103   if (output)
104     {
105       outfile = fopen(output,"w");
106       if (outfile == 0)
107         {
108           outfile = stdout;
109           fprintf (stderr,_("Can't open file %s\n"), output);
110           output = 0;
111         }
112     }
113   else
114     outfile = stdout;
115
116   map_over_list (arch, ar_directory_doer, list);
117
118   bfd_close (arch);
119
120   if (output)
121    fclose (outfile);
122 }
123
124 void
125 prompt (void)
126 {
127   extern int interactive;
128
129   if (interactive)
130     {
131       printf ("AR >");
132       fflush (stdout);
133     }
134 }
135
136 void
137 maybequit (void)
138 {
139   if (! interactive)
140     xexit (9);
141 }
142
143
144 bfd *obfd;
145 char *real_name;
146
147 void
148 ar_open (char *name, int t)
149 {
150   char *tname = (char *) xmalloc (strlen (name) + 10);
151   const char *bname = lbasename (name);
152   real_name = name;
153
154   /* Prepend tmp- to the beginning, to avoid file-name clashes after
155      truncation on filesystems with limited namespaces (DOS).  */
156   sprintf (tname, "%.*stmp-%s", (int) (bname - name), name, bname);
157   obfd = bfd_openw (tname, NULL);
158
159   if (!obfd)
160     {
161       fprintf (stderr,
162                _("%s: Can't open output archive %s\n"),
163                program_name,  tname);
164
165       maybequit ();
166     }
167   else
168     {
169       if (!t)
170         {
171           bfd **ptr;
172           bfd *element;
173           bfd *ibfd;
174
175           ibfd = bfd_openr (name, NULL);
176
177           if (!ibfd)
178             {
179               fprintf (stderr,_("%s: Can't open input archive %s\n"),
180                        program_name, name);
181               maybequit ();
182               return;
183             }
184
185           if (!bfd_check_format(ibfd, bfd_archive))
186             {
187               fprintf (stderr,
188                        _("%s: file %s is not an archive\n"),
189                        program_name, name);
190               maybequit ();
191               return;
192             }
193
194           ptr = &(obfd->archive_head);
195           element = bfd_openr_next_archived_file (ibfd, NULL);
196
197           while (element)
198             {
199               *ptr = element;
200               ptr = &element->next;
201               element = bfd_openr_next_archived_file (ibfd, element);
202             }
203         }
204
205       bfd_set_format (obfd, bfd_archive);
206
207       obfd->has_armap = 1;
208     }
209 }
210
211 static void
212 ar_addlib_doer (bfd *abfd, bfd *prev)
213 {
214   /* Add this module to the output bfd.  */
215   if (prev != NULL)
216     prev->next = abfd->next;
217
218   abfd->next = obfd->archive_head;
219   obfd->archive_head = abfd;
220 }
221
222 void
223 ar_addlib (char *name, struct list *list)
224 {
225   if (obfd == NULL)
226     {
227       fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
228       maybequit ();
229     }
230   else
231     {
232       bfd *arch;
233
234       arch = open_inarch (name, (char *) NULL);
235       if (arch != NULL)
236         map_over_list (arch, ar_addlib_doer, list);
237
238       /* Don't close the bfd, since it will make the elements disappear.  */
239     }
240 }
241
242 void
243 ar_addmod (struct list *list)
244 {
245   if (!obfd)
246     {
247       fprintf (stderr, _("%s: no open output archive\n"), program_name);
248       maybequit ();
249     }
250   else
251     {
252       while (list)
253         {
254           bfd *abfd = bfd_openr (list->name, NULL);
255
256           if (!abfd)
257             {
258               fprintf (stderr, _("%s: can't open file %s\n"),
259                        program_name, list->name);
260               maybequit ();
261             }
262           else
263             {
264               abfd->next = obfd->archive_head;
265               obfd->archive_head = abfd;
266             }
267           list = list->next;
268         }
269     }
270 }
271
272
273 void
274 ar_clear (void)
275 {
276   if (obfd)
277     obfd->archive_head = 0;
278 }
279
280 void
281 ar_delete (struct list *list)
282 {
283   if (!obfd)
284     {
285       fprintf (stderr, _("%s: no open output archive\n"), program_name);
286       maybequit ();
287     }
288   else
289     {
290       while (list)
291         {
292           /* Find this name in the archive.  */
293           bfd *member = obfd->archive_head;
294           bfd **prev = &(obfd->archive_head);
295           int found = 0;
296
297           while (member)
298             {
299               if (FILENAME_CMP(member->filename, list->name) == 0)
300                 {
301                   *prev = member->next;
302                   found = 1;
303                 }
304               else
305                 prev = &(member->next);
306
307               member = member->next;
308             }
309
310           if (!found)
311             {
312               fprintf (stderr, _("%s: can't find module file %s\n"),
313                        program_name, list->name);
314               maybequit ();
315             }
316
317           list = list->next;
318         }
319     }
320 }
321
322 void
323 ar_save (void)
324 {
325   if (!obfd)
326     {
327       fprintf (stderr, _("%s: no open output archive\n"), program_name);
328       maybequit ();
329     }
330   else
331     {
332       char *ofilename = xstrdup (bfd_get_filename (obfd));
333
334       bfd_close (obfd);
335
336       smart_rename (ofilename, real_name, 0);
337       obfd = 0;
338       free (ofilename);
339     }
340 }
341
342 void
343 ar_replace (struct list *list)
344 {
345   if (!obfd)
346     {
347       fprintf (stderr, _("%s: no open output archive\n"), program_name);
348       maybequit ();
349     }
350   else
351     {
352       while (list)
353         {
354           /* Find this name in the archive.  */
355           bfd *member = obfd->archive_head;
356           bfd **prev = &(obfd->archive_head);
357           int found = 0;
358
359           while (member)
360             {
361               if (FILENAME_CMP (member->filename, list->name) == 0)
362                 {
363                   /* Found the one to replace.  */
364                   bfd *abfd = bfd_openr (list->name, 0);
365
366                   if (!abfd)
367                     {
368                       fprintf (stderr, _("%s: can't open file %s\n"),
369                                program_name, list->name);
370                       maybequit ();
371                     }
372                   else
373                     {
374                       *prev = abfd;
375                       abfd->next = member->next;
376                       found = 1;
377                     }
378                 }
379               else
380                 {
381                   prev = &(member->next);
382                 }
383               member = member->next;
384             }
385
386           if (!found)
387             {
388               bfd *abfd = bfd_openr (list->name, 0);
389
390               fprintf (stderr,_("%s: can't find module file %s\n"),
391                        program_name, list->name);
392               if (!abfd)
393                 {
394                   fprintf (stderr, _("%s: can't open file %s\n"),
395                            program_name, list->name);
396                   maybequit ();
397                 }
398               else
399                 *prev = abfd;
400             }
401
402           list = list->next;
403         }
404     }
405 }
406
407 /* And I added this one.  */
408 void
409 ar_list (void)
410 {
411   if (!obfd)
412     {
413       fprintf (stderr, _("%s: no open output archive\n"), program_name);
414       maybequit ();
415     }
416   else
417     {
418       bfd *abfd;
419
420       outfile = stdout;
421       verbose =1 ;
422       printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
423
424       for (abfd = obfd->archive_head;
425            abfd != (bfd *)NULL;
426            abfd = abfd->next)
427         ar_directory_doer (abfd, (bfd *) NULL);
428     }
429 }
430
431 void
432 ar_end (void)
433 {
434   if (obfd)
435     {
436       bfd_cache_close (obfd);
437       unlink (bfd_get_filename (obfd));
438     }
439 }
440
441 void
442 ar_extract (struct list *list)
443 {
444   if (!obfd)
445     {
446       fprintf (stderr, _("%s: no open archive\n"), program_name);
447       maybequit ();
448     }
449   else
450     {
451       while (list)
452         {
453           /* Find this name in the archive.  */
454           bfd *member = obfd->archive_head;
455           int found = 0;
456
457           while (member && !found)
458             {
459               if (FILENAME_CMP (member->filename, list->name) == 0)
460                 {
461                   extract_file (member);
462                   found = 1;
463                 }
464
465               member = member->next;
466             }
467
468           if (!found)
469             {
470               bfd_openr (list->name, 0);
471               fprintf (stderr, _("%s: can't find module file %s\n"),
472                        program_name, list->name);
473             }
474
475           list = list->next;
476         }
477     }
478 }