133965Sjdp/* arsup.c - Archive support for MRI compatibility
2218822Sdim   Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3218822Sdim   2004, 2007 Free Software Foundation, Inc.
433965Sjdp
5104834Sobrien   This file is part of GNU Binutils.
633965Sjdp
7104834Sobrien   This program is free software; you can redistribute it and/or modify
8104834Sobrien   it under the terms of the GNU General Public License as published by
9104834Sobrien   the Free Software Foundation; either version 2 of the License, or
10104834Sobrien   (at your option) any later version.
1133965Sjdp
12104834Sobrien   This program is distributed in the hope that it will be useful,
13104834Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
14104834Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15104834Sobrien   GNU General Public License for more details.
1633965Sjdp
17104834Sobrien   You should have received a copy of the GNU General Public License
18104834Sobrien   along with this program; if not, write to the Free Software
19218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2033965Sjdp
2133965Sjdp
2233965Sjdp/* Contributed by Steve Chamberlain
23104834Sobrien   sac@cygnus.com
2433965Sjdp
25104834Sobrien   This file looks after requests from arparse.y, to provide the MRI
26104834Sobrien   style librarian command syntax + 1 word LIST.  */
2733965Sjdp
28218822Sdim#include "sysdep.h"
2933965Sjdp#include "bfd.h"
3033965Sjdp#include "libiberty.h"
31218822Sdim#include "filenames.h"
3233965Sjdp#include "bucomm.h"
33218822Sdim#include "arsup.h"
3433965Sjdp
3533965Sjdpstatic void map_over_list
36130561Sobrien  (bfd *, void (*function) (bfd *, bfd *), struct list *);
37130561Sobrienstatic void ar_directory_doer (bfd *, bfd *);
38130561Sobrienstatic void ar_addlib_doer (bfd *, bfd *);
3933965Sjdp
4033965Sjdpextern int verbose;
4133965Sjdp
42218822Sdimstatic bfd *obfd;
43218822Sdimstatic char *real_name;
44218822Sdimstatic FILE *outfile;
45218822Sdim
4633965Sjdpstatic void
47130561Sobrienmap_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
4833965Sjdp{
4933965Sjdp  bfd *head;
5033965Sjdp
5133965Sjdp  if (list == NULL)
5233965Sjdp    {
5333965Sjdp      bfd *next;
5433965Sjdp
55218822Sdim      head = arch->archive_next;
5633965Sjdp      while (head != NULL)
5733965Sjdp	{
58218822Sdim	  next = head->archive_next;
5933965Sjdp	  function (head, (bfd *) NULL);
6033965Sjdp	  head = next;
6133965Sjdp	}
6233965Sjdp    }
6333965Sjdp  else
6433965Sjdp    {
6533965Sjdp      struct list *ptr;
6633965Sjdp
6733965Sjdp      /* This may appear to be a baroque way of accomplishing what we
6833965Sjdp	 want.  however we have to iterate over the filenames in order
6933965Sjdp	 to notice where a filename is requested but does not exist in
7033965Sjdp	 the archive.  Ditto mapping over each file each time -- we
7133965Sjdp	 want to hack multiple references.  */
7233965Sjdp      for (ptr = list; ptr; ptr = ptr->next)
7333965Sjdp	{
74130561Sobrien	  bfd_boolean found = FALSE;
7533965Sjdp	  bfd *prev = arch;
7633965Sjdp
77218822Sdim	  for (head = arch->archive_next; head; head = head->archive_next)
7833965Sjdp	    {
7933965Sjdp	      if (head->filename != NULL
8061843Sobrien		  && FILENAME_CMP (ptr->name, head->filename) == 0)
8133965Sjdp		{
82130561Sobrien		  found = TRUE;
8333965Sjdp		  function (head, prev);
8433965Sjdp		}
8533965Sjdp	      prev = head;
8633965Sjdp	    }
8733965Sjdp	  if (! found)
8860484Sobrien	    fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
8933965Sjdp	}
9033965Sjdp    }
9133965Sjdp}
9233965Sjdp
9333965Sjdp
9433965Sjdp
9533965Sjdpstatic void
96130561Sobrienar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
9733965Sjdp{
98104834Sobrien  print_arelt_descr(outfile, abfd, verbose);
9933965Sjdp}
10033965Sjdp
10133965Sjdpvoid
102130561Sobrienar_directory (char *ar_name, struct list *list, char *output)
10333965Sjdp{
10433965Sjdp  bfd *arch;
10533965Sjdp
10633965Sjdp  arch = open_inarch (ar_name, (char *) NULL);
10733965Sjdp  if (output)
10833965Sjdp    {
10933965Sjdp      outfile = fopen(output,"w");
11033965Sjdp      if (outfile == 0)
11133965Sjdp	{
11233965Sjdp	  outfile = stdout;
11360484Sobrien	  fprintf (stderr,_("Can't open file %s\n"), output);
11433965Sjdp	  output = 0;
11533965Sjdp	}
11633965Sjdp    }
117104834Sobrien  else
11833965Sjdp    outfile = stdout;
11933965Sjdp
12033965Sjdp  map_over_list (arch, ar_directory_doer, list);
12133965Sjdp
12233965Sjdp  bfd_close (arch);
12333965Sjdp
12433965Sjdp  if (output)
12533965Sjdp   fclose (outfile);
12633965Sjdp}
12733965Sjdp
12833965Sjdpvoid
129130561Sobrienprompt (void)
13033965Sjdp{
13133965Sjdp  extern int interactive;
132104834Sobrien
133104834Sobrien  if (interactive)
134104834Sobrien    {
135104834Sobrien      printf ("AR >");
136104834Sobrien      fflush (stdout);
137104834Sobrien    }
13833965Sjdp}
13933965Sjdp
14033965Sjdpvoid
141130561Sobrienmaybequit (void)
14233965Sjdp{
143104834Sobrien  if (! interactive)
14433965Sjdp    xexit (9);
14533965Sjdp}
14633965Sjdp
14733965Sjdp
14833965Sjdpvoid
149130561Sobrienar_open (char *name, int t)
15033965Sjdp{
15133965Sjdp  char *tname = (char *) xmalloc (strlen (name) + 10);
15289857Sobrien  const char *bname = lbasename (name);
15333965Sjdp  real_name = name;
154104834Sobrien
15561843Sobrien  /* Prepend tmp- to the beginning, to avoid file-name clashes after
15661843Sobrien     truncation on filesystems with limited namespaces (DOS).  */
157104834Sobrien  sprintf (tname, "%.*stmp-%s", (int) (bname - name), name, bname);
158104834Sobrien  obfd = bfd_openw (tname, NULL);
15933965Sjdp
160104834Sobrien  if (!obfd)
161104834Sobrien    {
162104834Sobrien      fprintf (stderr,
163104834Sobrien	       _("%s: Can't open output archive %s\n"),
164104834Sobrien	       program_name,  tname);
16533965Sjdp
166104834Sobrien      maybequit ();
16733965Sjdp    }
168104834Sobrien  else
169104834Sobrien    {
170104834Sobrien      if (!t)
171104834Sobrien	{
172104834Sobrien	  bfd **ptr;
173104834Sobrien	  bfd *element;
174104834Sobrien	  bfd *ibfd;
17533965Sjdp
176104834Sobrien	  ibfd = bfd_openr (name, NULL);
17733965Sjdp
178104834Sobrien	  if (!ibfd)
179104834Sobrien	    {
180104834Sobrien	      fprintf (stderr,_("%s: Can't open input archive %s\n"),
181104834Sobrien		       program_name, name);
182104834Sobrien	      maybequit ();
183104834Sobrien	      return;
184104834Sobrien	    }
185104834Sobrien
186130561Sobrien	  if (!bfd_check_format(ibfd, bfd_archive))
187104834Sobrien	    {
188104834Sobrien	      fprintf (stderr,
189104834Sobrien		       _("%s: file %s is not an archive\n"),
190104834Sobrien		       program_name, name);
191104834Sobrien	      maybequit ();
192104834Sobrien	      return;
193104834Sobrien	    }
194104834Sobrien
195104834Sobrien	  ptr = &(obfd->archive_head);
196104834Sobrien	  element = bfd_openr_next_archived_file (ibfd, NULL);
197104834Sobrien
198104834Sobrien	  while (element)
199104834Sobrien	    {
200104834Sobrien	      *ptr = element;
201218822Sdim	      ptr = &element->archive_next;
202104834Sobrien	      element = bfd_openr_next_archived_file (ibfd, element);
203104834Sobrien	    }
204104834Sobrien	}
205104834Sobrien
206104834Sobrien      bfd_set_format (obfd, bfd_archive);
207104834Sobrien
208104834Sobrien      obfd->has_armap = 1;
209104834Sobrien    }
21033965Sjdp}
21133965Sjdp
21233965Sjdpstatic void
213130561Sobrienar_addlib_doer (bfd *abfd, bfd *prev)
21433965Sjdp{
215104834Sobrien  /* Add this module to the output bfd.  */
21633965Sjdp  if (prev != NULL)
217218822Sdim    prev->archive_next = abfd->archive_next;
218104834Sobrien
219218822Sdim  abfd->archive_next = obfd->archive_head;
22033965Sjdp  obfd->archive_head = abfd;
22133965Sjdp}
22233965Sjdp
22333965Sjdpvoid
224130561Sobrienar_addlib (char *name, struct list *list)
22533965Sjdp{
22633965Sjdp  if (obfd == NULL)
22733965Sjdp    {
22860484Sobrien      fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
22933965Sjdp      maybequit ();
23033965Sjdp    }
23133965Sjdp  else
23233965Sjdp    {
23333965Sjdp      bfd *arch;
23433965Sjdp
23533965Sjdp      arch = open_inarch (name, (char *) NULL);
23633965Sjdp      if (arch != NULL)
23733965Sjdp	map_over_list (arch, ar_addlib_doer, list);
23833965Sjdp
239130561Sobrien      /* Don't close the bfd, since it will make the elements disappear.  */
24033965Sjdp    }
24133965Sjdp}
24233965Sjdp
24333965Sjdpvoid
244130561Sobrienar_addmod (struct list *list)
24533965Sjdp{
246104834Sobrien  if (!obfd)
247104834Sobrien    {
248104834Sobrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
249104834Sobrien      maybequit ();
25033965Sjdp    }
251104834Sobrien  else
252104834Sobrien    {
253104834Sobrien      while (list)
254104834Sobrien	{
255104834Sobrien	  bfd *abfd = bfd_openr (list->name, NULL);
256104834Sobrien
257104834Sobrien	  if (!abfd)
258104834Sobrien	    {
259104834Sobrien	      fprintf (stderr, _("%s: can't open file %s\n"),
260104834Sobrien		       program_name, list->name);
261104834Sobrien	      maybequit ();
262104834Sobrien	    }
263104834Sobrien	  else
264104834Sobrien	    {
265218822Sdim	      abfd->archive_next = obfd->archive_head;
266104834Sobrien	      obfd->archive_head = abfd;
267104834Sobrien	    }
268104834Sobrien	  list = list->next;
269104834Sobrien	}
270104834Sobrien    }
27133965Sjdp}
27233965Sjdp
27333965Sjdp
27433965Sjdpvoid
275130561Sobrienar_clear (void)
27633965Sjdp{
277104834Sobrien  if (obfd)
278104834Sobrien    obfd->archive_head = 0;
27933965Sjdp}
28033965Sjdp
28133965Sjdpvoid
282130561Sobrienar_delete (struct list *list)
28333965Sjdp{
284104834Sobrien  if (!obfd)
285104834Sobrien    {
286104834Sobrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
287104834Sobrien      maybequit ();
288104834Sobrien    }
289104834Sobrien  else
290104834Sobrien    {
291104834Sobrien      while (list)
292104834Sobrien	{
293104834Sobrien	  /* Find this name in the archive.  */
294104834Sobrien	  bfd *member = obfd->archive_head;
295104834Sobrien	  bfd **prev = &(obfd->archive_head);
296104834Sobrien	  int found = 0;
297104834Sobrien
298104834Sobrien	  while (member)
299104834Sobrien	    {
300104834Sobrien	      if (FILENAME_CMP(member->filename, list->name) == 0)
301104834Sobrien		{
302218822Sdim		  *prev = member->archive_next;
303104834Sobrien		  found = 1;
304104834Sobrien		}
305104834Sobrien	      else
306218822Sdim		prev = &(member->archive_next);
307104834Sobrien
308218822Sdim	      member = member->archive_next;
309104834Sobrien	    }
310104834Sobrien
311104834Sobrien	  if (!found)
312104834Sobrien	    {
313104834Sobrien	      fprintf (stderr, _("%s: can't find module file %s\n"),
314104834Sobrien		       program_name, list->name);
315104834Sobrien	      maybequit ();
316104834Sobrien	    }
317104834Sobrien
318104834Sobrien	  list = list->next;
31933965Sjdp	}
32033965Sjdp    }
32133965Sjdp}
32233965Sjdp
32333965Sjdpvoid
324130561Sobrienar_save (void)
32533965Sjdp{
326104834Sobrien  if (!obfd)
327104834Sobrien    {
328104834Sobrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
329104834Sobrien      maybequit ();
330104834Sobrien    }
331104834Sobrien  else
332104834Sobrien    {
333104834Sobrien      char *ofilename = xstrdup (bfd_get_filename (obfd));
33433965Sjdp
335104834Sobrien      bfd_close (obfd);
336104834Sobrien
337130561Sobrien      smart_rename (ofilename, real_name, 0);
338104834Sobrien      obfd = 0;
339104834Sobrien      free (ofilename);
340104834Sobrien    }
34133965Sjdp}
34233965Sjdp
34333965Sjdpvoid
344130561Sobrienar_replace (struct list *list)
34533965Sjdp{
346104834Sobrien  if (!obfd)
347104834Sobrien    {
348104834Sobrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
349104834Sobrien      maybequit ();
350104834Sobrien    }
351104834Sobrien  else
352104834Sobrien    {
353104834Sobrien      while (list)
35433965Sjdp	{
355104834Sobrien	  /* Find this name in the archive.  */
356104834Sobrien	  bfd *member = obfd->archive_head;
357104834Sobrien	  bfd **prev = &(obfd->archive_head);
358104834Sobrien	  int found = 0;
359104834Sobrien
360104834Sobrien	  while (member)
361104834Sobrien	    {
362104834Sobrien	      if (FILENAME_CMP (member->filename, list->name) == 0)
363104834Sobrien		{
364104834Sobrien		  /* Found the one to replace.  */
365104834Sobrien		  bfd *abfd = bfd_openr (list->name, 0);
366104834Sobrien
367104834Sobrien		  if (!abfd)
368104834Sobrien		    {
369104834Sobrien		      fprintf (stderr, _("%s: can't open file %s\n"),
370104834Sobrien			       program_name, list->name);
371104834Sobrien		      maybequit ();
372104834Sobrien		    }
373104834Sobrien		  else
374104834Sobrien		    {
375104834Sobrien		      *prev = abfd;
376218822Sdim		      abfd->archive_next = member->archive_next;
377104834Sobrien		      found = 1;
378104834Sobrien		    }
379104834Sobrien		}
380104834Sobrien	      else
381104834Sobrien		{
382218822Sdim		  prev = &(member->archive_next);
383104834Sobrien		}
384218822Sdim	      member = member->archive_next;
385104834Sobrien	    }
386104834Sobrien
387104834Sobrien	  if (!found)
388104834Sobrien	    {
389104834Sobrien	      bfd *abfd = bfd_openr (list->name, 0);
390104834Sobrien
391104834Sobrien	      fprintf (stderr,_("%s: can't find module file %s\n"),
392104834Sobrien		       program_name, list->name);
393104834Sobrien	      if (!abfd)
394104834Sobrien		{
395104834Sobrien		  fprintf (stderr, _("%s: can't open file %s\n"),
396104834Sobrien			   program_name, list->name);
397104834Sobrien		  maybequit ();
398104834Sobrien		}
399104834Sobrien	      else
400104834Sobrien		*prev = abfd;
401104834Sobrien	    }
402104834Sobrien
403104834Sobrien	  list = list->next;
40433965Sjdp	}
40533965Sjdp    }
40633965Sjdp}
40733965Sjdp
408104834Sobrien/* And I added this one.  */
40933965Sjdpvoid
410130561Sobrienar_list (void)
41133965Sjdp{
412104834Sobrien  if (!obfd)
41333965Sjdp    {
414104834Sobrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
415104834Sobrien      maybequit ();
41633965Sjdp    }
417104834Sobrien  else
418104834Sobrien    {
419104834Sobrien      bfd *abfd;
420104834Sobrien
421104834Sobrien      outfile = stdout;
422104834Sobrien      verbose =1 ;
423104834Sobrien      printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
424104834Sobrien
425104834Sobrien      for (abfd = obfd->archive_head;
426104834Sobrien	   abfd != (bfd *)NULL;
427218822Sdim	   abfd = abfd->archive_next)
428104834Sobrien	ar_directory_doer (abfd, (bfd *) NULL);
429104834Sobrien    }
43033965Sjdp}
43133965Sjdp
432104834Sobrienvoid
433130561Sobrienar_end (void)
43433965Sjdp{
43533965Sjdp  if (obfd)
436104834Sobrien    {
437130561Sobrien      bfd_cache_close (obfd);
438104834Sobrien      unlink (bfd_get_filename (obfd));
439104834Sobrien    }
44033965Sjdp}
441104834Sobrien
44233965Sjdpvoid
443130561Sobrienar_extract (struct list *list)
44433965Sjdp{
445104834Sobrien  if (!obfd)
446104834Sobrien    {
447104834Sobrien      fprintf (stderr, _("%s: no open archive\n"), program_name);
448104834Sobrien      maybequit ();
449104834Sobrien    }
450104834Sobrien  else
451104834Sobrien    {
452104834Sobrien      while (list)
45333965Sjdp	{
454104834Sobrien	  /* Find this name in the archive.  */
455104834Sobrien	  bfd *member = obfd->archive_head;
456104834Sobrien	  int found = 0;
45733965Sjdp
458104834Sobrien	  while (member && !found)
459104834Sobrien	    {
460104834Sobrien	      if (FILENAME_CMP (member->filename, list->name) == 0)
461104834Sobrien		{
462104834Sobrien		  extract_file (member);
463104834Sobrien		  found = 1;
464104834Sobrien		}
46533965Sjdp
466218822Sdim	      member = member->archive_next;
467104834Sobrien	    }
468104834Sobrien
469104834Sobrien	  if (!found)
470104834Sobrien	    {
471104834Sobrien	      bfd_openr (list->name, 0);
472104834Sobrien	      fprintf (stderr, _("%s: can't find module file %s\n"),
473104834Sobrien		       program_name, list->name);
474104834Sobrien	    }
475104834Sobrien
476104834Sobrien	  list = list->next;
477104834Sobrien	}
47833965Sjdp    }
47933965Sjdp}
480