171671b9obrien/* arsup.c - Archive support for MRI compatibility
20acbbeedim   Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3d0f678fdim   2004, 2007 Free Software Foundation, Inc.
471671b9obrien
571671b9obrien   This file is part of GNU Binutils.
671671b9obrien
771671b9obrien   This program is free software; you can redistribute it and/or modify
871671b9obrien   it under the terms of the GNU General Public License as published by
971671b9obrien   the Free Software Foundation; either version 2 of the License, or
1071671b9obrien   (at your option) any later version.
1171671b9obrien
1271671b9obrien   This program is distributed in the hope that it will be useful,
1371671b9obrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1471671b9obrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1571671b9obrien   GNU General Public License for more details.
1671671b9obrien
1771671b9obrien   You should have received a copy of the GNU General Public License
1871671b9obrien   along with this program; if not, write to the Free Software
190acbbeedim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2071671b9obrien
2171671b9obrien
2271671b9obrien/* Contributed by Steve Chamberlain
2371671b9obrien   sac@cygnus.com
2471671b9obrien
2571671b9obrien   This file looks after requests from arparse.y, to provide the MRI
2671671b9obrien   style librarian command syntax + 1 word LIST.  */
2771671b9obrien
28d0f678fdim#include "sysdep.h"
2971671b9obrien#include "bfd.h"
3071671b9obrien#include "libiberty.h"
3171671b9obrien#include "filenames.h"
32d0f678fdim#include "bucomm.h"
33d0f678fdim#include "arsup.h"
3471671b9obrien
3571671b9obrienstatic void map_over_list
3671671b9obrien  (bfd *, void (*function) (bfd *, bfd *), struct list *);
3771671b9obrienstatic void ar_directory_doer (bfd *, bfd *);
3871671b9obrienstatic void ar_addlib_doer (bfd *, bfd *);
3971671b9obrien
4071671b9obrienextern int verbose;
4171671b9obrien
420acbbeedimstatic bfd *obfd;
430acbbeedimstatic char *real_name;
440acbbeedimstatic FILE *outfile;
450acbbeedim
4671671b9obrienstatic void
4771671b9obrienmap_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
4871671b9obrien{
4971671b9obrien  bfd *head;
5071671b9obrien
5171671b9obrien  if (list == NULL)
5271671b9obrien    {
5371671b9obrien      bfd *next;
5471671b9obrien
55d0f678fdim      head = arch->archive_next;
5671671b9obrien      while (head != NULL)
5771671b9obrien	{
58d0f678fdim	  next = head->archive_next;
5971671b9obrien	  function (head, (bfd *) NULL);
6071671b9obrien	  head = next;
6171671b9obrien	}
6271671b9obrien    }
6371671b9obrien  else
6471671b9obrien    {
6571671b9obrien      struct list *ptr;
6671671b9obrien
6771671b9obrien      /* This may appear to be a baroque way of accomplishing what we
6871671b9obrien	 want.  however we have to iterate over the filenames in order
6971671b9obrien	 to notice where a filename is requested but does not exist in
7071671b9obrien	 the archive.  Ditto mapping over each file each time -- we
7171671b9obrien	 want to hack multiple references.  */
7271671b9obrien      for (ptr = list; ptr; ptr = ptr->next)
7371671b9obrien	{
7471671b9obrien	  bfd_boolean found = FALSE;
7571671b9obrien	  bfd *prev = arch;
7671671b9obrien
77d0f678fdim	  for (head = arch->archive_next; head; head = head->archive_next)
7871671b9obrien	    {
7971671b9obrien	      if (head->filename != NULL
8071671b9obrien		  && FILENAME_CMP (ptr->name, head->filename) == 0)
8171671b9obrien		{
8271671b9obrien		  found = TRUE;
8371671b9obrien		  function (head, prev);
8471671b9obrien		}
8571671b9obrien	      prev = head;
8671671b9obrien	    }
8771671b9obrien	  if (! found)
8871671b9obrien	    fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
8971671b9obrien	}
9071671b9obrien    }
9171671b9obrien}
9271671b9obrien
9371671b9obrien
9471671b9obrien
9571671b9obrienstatic void
9671671b9obrienar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
9771671b9obrien{
9871671b9obrien  print_arelt_descr(outfile, abfd, verbose);
9971671b9obrien}
10071671b9obrien
10171671b9obrienvoid
10271671b9obrienar_directory (char *ar_name, struct list *list, char *output)
10371671b9obrien{
10471671b9obrien  bfd *arch;
10571671b9obrien
10671671b9obrien  arch = open_inarch (ar_name, (char *) NULL);
10771671b9obrien  if (output)
10871671b9obrien    {
10971671b9obrien      outfile = fopen(output,"w");
11071671b9obrien      if (outfile == 0)
11171671b9obrien	{
11271671b9obrien	  outfile = stdout;
11371671b9obrien	  fprintf (stderr,_("Can't open file %s\n"), output);
11471671b9obrien	  output = 0;
11571671b9obrien	}
11671671b9obrien    }
11771671b9obrien  else
11871671b9obrien    outfile = stdout;
11971671b9obrien
12071671b9obrien  map_over_list (arch, ar_directory_doer, list);
12171671b9obrien
12271671b9obrien  bfd_close (arch);
12371671b9obrien
12471671b9obrien  if (output)
12571671b9obrien   fclose (outfile);
12671671b9obrien}
12771671b9obrien
12871671b9obrienvoid
12971671b9obrienprompt (void)
13071671b9obrien{
13171671b9obrien  extern int interactive;
13271671b9obrien
13371671b9obrien  if (interactive)
13471671b9obrien    {
13571671b9obrien      printf ("AR >");
13671671b9obrien      fflush (stdout);
13771671b9obrien    }
13871671b9obrien}
13971671b9obrien
14071671b9obrienvoid
14171671b9obrienmaybequit (void)
14271671b9obrien{
14371671b9obrien  if (! interactive)
14471671b9obrien    xexit (9);
14571671b9obrien}
14671671b9obrien
14771671b9obrien
14871671b9obrienvoid
14971671b9obrienar_open (char *name, int t)
15071671b9obrien{
15171671b9obrien  char *tname = (char *) xmalloc (strlen (name) + 10);
15271671b9obrien  const char *bname = lbasename (name);
15371671b9obrien  real_name = name;
15471671b9obrien
15571671b9obrien  /* Prepend tmp- to the beginning, to avoid file-name clashes after
15671671b9obrien     truncation on filesystems with limited namespaces (DOS).  */
15771671b9obrien  sprintf (tname, "%.*stmp-%s", (int) (bname - name), name, bname);
15871671b9obrien  obfd = bfd_openw (tname, NULL);
15971671b9obrien
16071671b9obrien  if (!obfd)
16171671b9obrien    {
16271671b9obrien      fprintf (stderr,
16371671b9obrien	       _("%s: Can't open output archive %s\n"),
16471671b9obrien	       program_name,  tname);
16571671b9obrien
16671671b9obrien      maybequit ();
16771671b9obrien    }
16871671b9obrien  else
16971671b9obrien    {
17071671b9obrien      if (!t)
17171671b9obrien	{
17271671b9obrien	  bfd **ptr;
17371671b9obrien	  bfd *element;
17471671b9obrien	  bfd *ibfd;
17571671b9obrien
17671671b9obrien	  ibfd = bfd_openr (name, NULL);
17771671b9obrien
17871671b9obrien	  if (!ibfd)
17971671b9obrien	    {
18071671b9obrien	      fprintf (stderr,_("%s: Can't open input archive %s\n"),
18171671b9obrien		       program_name, name);
18271671b9obrien	      maybequit ();
18371671b9obrien	      return;
18471671b9obrien	    }
18571671b9obrien
18671671b9obrien	  if (!bfd_check_format(ibfd, bfd_archive))
18771671b9obrien	    {
18871671b9obrien	      fprintf (stderr,
18971671b9obrien		       _("%s: file %s is not an archive\n"),
19071671b9obrien		       program_name, name);
19171671b9obrien	      maybequit ();
19271671b9obrien	      return;
19371671b9obrien	    }
19471671b9obrien
19571671b9obrien	  ptr = &(obfd->archive_head);
19671671b9obrien	  element = bfd_openr_next_archived_file (ibfd, NULL);
19771671b9obrien
19871671b9obrien	  while (element)
19971671b9obrien	    {
20071671b9obrien	      *ptr = element;
201d0f678fdim	      ptr = &element->archive_next;
20271671b9obrien	      element = bfd_openr_next_archived_file (ibfd, element);
20371671b9obrien	    }
20471671b9obrien	}
20571671b9obrien
20671671b9obrien      bfd_set_format (obfd, bfd_archive);
20771671b9obrien
20871671b9obrien      obfd->has_armap = 1;
20971671b9obrien    }
21071671b9obrien}
21171671b9obrien
21271671b9obrienstatic void
21371671b9obrienar_addlib_doer (bfd *abfd, bfd *prev)
21471671b9obrien{
21571671b9obrien  /* Add this module to the output bfd.  */
21671671b9obrien  if (prev != NULL)
217d0f678fdim    prev->archive_next = abfd->archive_next;
21871671b9obrien
219d0f678fdim  abfd->archive_next = obfd->archive_head;
22071671b9obrien  obfd->archive_head = abfd;
22171671b9obrien}
22271671b9obrien
22371671b9obrienvoid
22471671b9obrienar_addlib (char *name, struct list *list)
22571671b9obrien{
22671671b9obrien  if (obfd == NULL)
22771671b9obrien    {
22871671b9obrien      fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
22971671b9obrien      maybequit ();
23071671b9obrien    }
23171671b9obrien  else
23271671b9obrien    {
23371671b9obrien      bfd *arch;
23471671b9obrien
23571671b9obrien      arch = open_inarch (name, (char *) NULL);
23671671b9obrien      if (arch != NULL)
23771671b9obrien	map_over_list (arch, ar_addlib_doer, list);
23871671b9obrien
23971671b9obrien      /* Don't close the bfd, since it will make the elements disappear.  */
24071671b9obrien    }
24171671b9obrien}
24271671b9obrien
24371671b9obrienvoid
24471671b9obrienar_addmod (struct list *list)
24571671b9obrien{
24671671b9obrien  if (!obfd)
24771671b9obrien    {
24871671b9obrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
24971671b9obrien      maybequit ();
25071671b9obrien    }
25171671b9obrien  else
25271671b9obrien    {
25371671b9obrien      while (list)
25471671b9obrien	{
25571671b9obrien	  bfd *abfd = bfd_openr (list->name, NULL);
25671671b9obrien
25771671b9obrien	  if (!abfd)
25871671b9obrien	    {
25971671b9obrien	      fprintf (stderr, _("%s: can't open file %s\n"),
26071671b9obrien		       program_name, list->name);
26171671b9obrien	      maybequit ();
26271671b9obrien	    }
26371671b9obrien	  else
26471671b9obrien	    {
265d0f678fdim	      abfd->archive_next = obfd->archive_head;
26671671b9obrien	      obfd->archive_head = abfd;
26771671b9obrien	    }
26871671b9obrien	  list = list->next;
26971671b9obrien	}
27071671b9obrien    }
27171671b9obrien}
27271671b9obrien
27371671b9obrien
27471671b9obrienvoid
27571671b9obrienar_clear (void)
27671671b9obrien{
27771671b9obrien  if (obfd)
27871671b9obrien    obfd->archive_head = 0;
27971671b9obrien}
28071671b9obrien
28171671b9obrienvoid
28271671b9obrienar_delete (struct list *list)
28371671b9obrien{
28471671b9obrien  if (!obfd)
28571671b9obrien    {
28671671b9obrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
28771671b9obrien      maybequit ();
28871671b9obrien    }
28971671b9obrien  else
29071671b9obrien    {
29171671b9obrien      while (list)
29271671b9obrien	{
29371671b9obrien	  /* Find this name in the archive.  */
29471671b9obrien	  bfd *member = obfd->archive_head;
29571671b9obrien	  bfd **prev = &(obfd->archive_head);
29671671b9obrien	  int found = 0;
29771671b9obrien
29871671b9obrien	  while (member)
29971671b9obrien	    {
30071671b9obrien	      if (FILENAME_CMP(member->filename, list->name) == 0)
30171671b9obrien		{
302d0f678fdim		  *prev = member->archive_next;
30371671b9obrien		  found = 1;
30471671b9obrien		}
30571671b9obrien	      else
306d0f678fdim		prev = &(member->archive_next);
30771671b9obrien
308d0f678fdim	      member = member->archive_next;
30971671b9obrien	    }
31071671b9obrien
31171671b9obrien	  if (!found)
31271671b9obrien	    {
31371671b9obrien	      fprintf (stderr, _("%s: can't find module file %s\n"),
31471671b9obrien		       program_name, list->name);
31571671b9obrien	      maybequit ();
31671671b9obrien	    }
31771671b9obrien
31871671b9obrien	  list = list->next;
31971671b9obrien	}
32071671b9obrien    }
32171671b9obrien}
32271671b9obrien
32371671b9obrienvoid
32471671b9obrienar_save (void)
32571671b9obrien{
32671671b9obrien  if (!obfd)
32771671b9obrien    {
32871671b9obrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
32971671b9obrien      maybequit ();
33071671b9obrien    }
33171671b9obrien  else
33271671b9obrien    {
33371671b9obrien      char *ofilename = xstrdup (bfd_get_filename (obfd));
33471671b9obrien
33571671b9obrien      bfd_close (obfd);
33671671b9obrien
33771671b9obrien      smart_rename (ofilename, real_name, 0);
33871671b9obrien      obfd = 0;
33971671b9obrien      free (ofilename);
34071671b9obrien    }
34171671b9obrien}
34271671b9obrien
34371671b9obrienvoid
34471671b9obrienar_replace (struct list *list)
34571671b9obrien{
34671671b9obrien  if (!obfd)
34771671b9obrien    {
34871671b9obrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
34971671b9obrien      maybequit ();
35071671b9obrien    }
35171671b9obrien  else
35271671b9obrien    {
35371671b9obrien      while (list)
35471671b9obrien	{
35571671b9obrien	  /* Find this name in the archive.  */
35671671b9obrien	  bfd *member = obfd->archive_head;
35771671b9obrien	  bfd **prev = &(obfd->archive_head);
35871671b9obrien	  int found = 0;
35971671b9obrien
36071671b9obrien	  while (member)
36171671b9obrien	    {
36271671b9obrien	      if (FILENAME_CMP (member->filename, list->name) == 0)
36371671b9obrien		{
36471671b9obrien		  /* Found the one to replace.  */
36571671b9obrien		  bfd *abfd = bfd_openr (list->name, 0);
36671671b9obrien
36771671b9obrien		  if (!abfd)
36871671b9obrien		    {
36971671b9obrien		      fprintf (stderr, _("%s: can't open file %s\n"),
37071671b9obrien			       program_name, list->name);
37171671b9obrien		      maybequit ();
37271671b9obrien		    }
37371671b9obrien		  else
37471671b9obrien		    {
37571671b9obrien		      *prev = abfd;
376d0f678fdim		      abfd->archive_next = member->archive_next;
37771671b9obrien		      found = 1;
37871671b9obrien		    }
37971671b9obrien		}
38071671b9obrien	      else
38171671b9obrien		{
382d0f678fdim		  prev = &(member->archive_next);
38371671b9obrien		}
384d0f678fdim	      member = member->archive_next;
38571671b9obrien	    }
38671671b9obrien
38771671b9obrien	  if (!found)
38871671b9obrien	    {
38971671b9obrien	      bfd *abfd = bfd_openr (list->name, 0);
39071671b9obrien
39171671b9obrien	      fprintf (stderr,_("%s: can't find module file %s\n"),
39271671b9obrien		       program_name, list->name);
39371671b9obrien	      if (!abfd)
39471671b9obrien		{
39571671b9obrien		  fprintf (stderr, _("%s: can't open file %s\n"),
39671671b9obrien			   program_name, list->name);
39771671b9obrien		  maybequit ();
39871671b9obrien		}
39971671b9obrien	      else
40071671b9obrien		*prev = abfd;
40171671b9obrien	    }
40271671b9obrien
40371671b9obrien	  list = list->next;
40471671b9obrien	}
40571671b9obrien    }
40671671b9obrien}
40771671b9obrien
40871671b9obrien/* And I added this one.  */
40971671b9obrienvoid
41071671b9obrienar_list (void)
41171671b9obrien{
41271671b9obrien  if (!obfd)
41371671b9obrien    {
41471671b9obrien      fprintf (stderr, _("%s: no open output archive\n"), program_name);
41571671b9obrien      maybequit ();
41671671b9obrien    }
41771671b9obrien  else
41871671b9obrien    {
41971671b9obrien      bfd *abfd;
42071671b9obrien
42171671b9obrien      outfile = stdout;
42271671b9obrien      verbose =1 ;
42371671b9obrien      printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
42471671b9obrien
42571671b9obrien      for (abfd = obfd->archive_head;
42671671b9obrien	   abfd != (bfd *)NULL;
427d0f678fdim	   abfd = abfd->archive_next)
42871671b9obrien	ar_directory_doer (abfd, (bfd *) NULL);
42971671b9obrien    }
43071671b9obrien}
43171671b9obrien
43271671b9obrienvoid
43371671b9obrienar_end (void)
43471671b9obrien{
43571671b9obrien  if (obfd)
43671671b9obrien    {
43771671b9obrien      bfd_cache_close (obfd);
43871671b9obrien      unlink (bfd_get_filename (obfd));
43971671b9obrien    }
44071671b9obrien}
44171671b9obrien
44271671b9obrienvoid
44371671b9obrienar_extract (struct list *list)
44471671b9obrien{
44571671b9obrien  if (!obfd)
44671671b9obrien    {
44771671b9obrien      fprintf (stderr, _("%s: no open archive\n"), program_name);
44871671b9obrien      maybequit ();
44971671b9obrien    }
45071671b9obrien  else
45171671b9obrien    {
45271671b9obrien      while (list)
45371671b9obrien	{
45471671b9obrien	  /* Find this name in the archive.  */
45571671b9obrien	  bfd *member = obfd->archive_head;
45671671b9obrien	  int found = 0;
45771671b9obrien
45871671b9obrien	  while (member && !found)
45971671b9obrien	    {
46071671b9obrien	      if (FILENAME_CMP (member->filename, list->name) == 0)
46171671b9obrien		{
46271671b9obrien		  extract_file (member);
46371671b9obrien		  found = 1;
46471671b9obrien		}
46571671b9obrien
466d0f678fdim	      member = member->archive_next;
46771671b9obrien	    }
46871671b9obrien
46971671b9obrien	  if (!found)
47071671b9obrien	    {
47171671b9obrien	      bfd_openr (list->name, 0);
47271671b9obrien	      fprintf (stderr, _("%s: can't find module file %s\n"),
47371671b9obrien		       program_name, list->name);
47471671b9obrien	    }
47571671b9obrien
47671671b9obrien	  list = list->next;
47771671b9obrien	}
47871671b9obrien    }
47971671b9obrien}
480