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