1/* arsup.c - Archive support for MRI compatibility
2   Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3   2004 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 "bfd.h"
29#include "arsup.h"
30#include "libiberty.h"
31#include "bucomm.h"
32#include "filenames.h"
33
34static void map_over_list
35  (bfd *, void (*function) (bfd *, bfd *), struct list *);
36static void ar_directory_doer (bfd *, bfd *);
37static void ar_addlib_doer (bfd *, bfd *);
38
39extern int verbose;
40
41static bfd *obfd;
42static char *real_name;
43static FILE *outfile;
44
45static void
46map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
47{
48  bfd *head;
49
50  if (list == NULL)
51    {
52      bfd *next;
53
54      head = arch->next;
55      while (head != NULL)
56	{
57	  next = head->next;
58	  function (head, (bfd *) NULL);
59	  head = next;
60	}
61    }
62  else
63    {
64      struct list *ptr;
65
66      /* This may appear to be a baroque way of accomplishing what we
67	 want.  however we have to iterate over the filenames in order
68	 to notice where a filename is requested but does not exist in
69	 the archive.  Ditto mapping over each file each time -- we
70	 want to hack multiple references.  */
71      for (ptr = list; ptr; ptr = ptr->next)
72	{
73	  bfd_boolean found = FALSE;
74	  bfd *prev = arch;
75
76	  for (head = arch->next; head; head = head->next)
77	    {
78	      if (head->filename != NULL
79		  && FILENAME_CMP (ptr->name, head->filename) == 0)
80		{
81		  found = TRUE;
82		  function (head, prev);
83		}
84	      prev = head;
85	    }
86	  if (! found)
87	    fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
88	}
89    }
90}
91
92
93
94static void
95ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
96{
97  print_arelt_descr(outfile, abfd, verbose);
98}
99
100void
101ar_directory (char *ar_name, struct list *list, char *output)
102{
103  bfd *arch;
104
105  arch = open_inarch (ar_name, (char *) NULL);
106  if (output)
107    {
108      outfile = fopen(output,"w");
109      if (outfile == 0)
110	{
111	  outfile = stdout;
112	  fprintf (stderr,_("Can't open file %s\n"), output);
113	  output = 0;
114	}
115    }
116  else
117    outfile = stdout;
118
119  map_over_list (arch, ar_directory_doer, list);
120
121  bfd_close (arch);
122
123  if (output)
124   fclose (outfile);
125}
126
127void
128prompt (void)
129{
130  extern int interactive;
131
132  if (interactive)
133    {
134      printf ("AR >");
135      fflush (stdout);
136    }
137}
138
139void
140maybequit (void)
141{
142  if (! interactive)
143    xexit (9);
144}
145
146
147void
148ar_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
211static void
212ar_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
222void
223ar_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
242void
243ar_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
273void
274ar_clear (void)
275{
276  if (obfd)
277    obfd->archive_head = 0;
278}
279
280void
281ar_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
322void
323ar_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
342void
343ar_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.  */
408void
409ar_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
431void
432ar_end (void)
433{
434  if (obfd)
435    {
436      bfd_cache_close (obfd);
437      unlink (bfd_get_filename (obfd));
438    }
439}
440
441void
442ar_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}
479