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