ar.c revision 38889
133965Sjdp/* ar.c - Archive modify and extract.
238889Sjdp   Copyright 1991, 92, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
333965Sjdp
433965SjdpThis file is part of GNU Binutils.
533965Sjdp
633965SjdpThis program is free software; you can redistribute it and/or modify
733965Sjdpit under the terms of the GNU General Public License as published by
833965Sjdpthe Free Software Foundation; either version 2 of the License, or
933965Sjdp(at your option) any later version.
1033965Sjdp
1133965SjdpThis program is distributed in the hope that it will be useful,
1233965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1333965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1433965SjdpGNU General Public License for more details.
1533965Sjdp
1633965SjdpYou should have received a copy of the GNU General Public License
1733965Sjdpalong with this program; if not, write to the Free Software
1833965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1933965Sjdp
2033965Sjdp/*
2133965Sjdp   Bugs: should use getopt the way tar does (complete w/optional -) and
2233965Sjdp   should have long options too. GNU ar used to check file against filesystem
2333965Sjdp   in quick_update and replace operations (would check mtime). Doesn't warn
2433965Sjdp   when name truncated. No way to specify pos_end. Error messages should be
2533965Sjdp   more consistant.
2633965Sjdp*/
2733965Sjdp#include "bfd.h"
2833965Sjdp#include "libiberty.h"
2933965Sjdp#include "progress.h"
3033965Sjdp#include "bucomm.h"
3133965Sjdp#include "aout/ar.h"
3233965Sjdp#include "libbfd.h"
3333965Sjdp#include "arsup.h"
3433965Sjdp#include <sys/stat.h>
3533965Sjdp
3633965Sjdp#ifdef HAVE_GOOD_UTIME_H
3733965Sjdp#include <utime.h>
3833965Sjdp#else /* ! HAVE_GOOD_UTIME_H */
3933965Sjdp#ifdef HAVE_UTIMES
4033965Sjdp#include <sys/time.h>
4133965Sjdp#endif /* HAVE_UTIMES */
4233965Sjdp#endif /* ! HAVE_GOOD_UTIME_H */
4333965Sjdp
4433965Sjdp#ifdef __GO32___
4533965Sjdp#define EXT_NAME_LEN 3		/* bufflen of addition to name if it's MS-DOS */
4633965Sjdp#else
4733965Sjdp#define EXT_NAME_LEN 6		/* ditto for *NIX */
4833965Sjdp#endif
4933965Sjdp
5033965Sjdp#define BUFSIZE 8192
5133965Sjdp
5233965Sjdp/* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
5333965Sjdp
5433965Sjdpstruct ar_hdr *
5538889Sjdp  bfd_special_undocumented_glue PARAMS ((bfd * abfd, const char *filename));
5633965Sjdp
5733965Sjdp/* Static declarations */
5833965Sjdp
5933965Sjdpstatic void
6033965Sjdpmri_emul PARAMS ((void));
6133965Sjdp
6233965Sjdpstatic const char *
6333965Sjdpnormalize PARAMS ((const char *, bfd *));
6433965Sjdp
6533965Sjdpstatic void
6633965Sjdpremove_output PARAMS ((void));
6733965Sjdp
6833965Sjdpstatic void
6933965Sjdpmap_over_members PARAMS ((bfd *, void (*)(bfd *), char **, int));
7033965Sjdp
7133965Sjdpstatic void
7233965Sjdpprint_contents PARAMS ((bfd * member));
7333965Sjdp
7433965Sjdpstatic void
7533965Sjdpdelete_members PARAMS ((bfd *, char **files_to_delete));
7633965Sjdp
7733965Sjdp#if 0
7833965Sjdpstatic void
7933965Sjdpdo_quick_append PARAMS ((const char *archive_filename,
8033965Sjdp			 char **files_to_append));
8133965Sjdp#endif
8233965Sjdp
8333965Sjdpstatic void
8433965Sjdpmove_members PARAMS ((bfd *, char **files_to_move));
8533965Sjdp
8633965Sjdpstatic void
8733965Sjdpreplace_members PARAMS ((bfd *, char **files_to_replace, boolean quick));
8833965Sjdp
8933965Sjdpstatic void
9033965Sjdpprint_descr PARAMS ((bfd * abfd));
9133965Sjdp
9233965Sjdpstatic void
9333965Sjdpwrite_archive PARAMS ((bfd *));
9433965Sjdp
9533965Sjdpstatic void
9633965Sjdpranlib_only PARAMS ((const char *archname));
9733965Sjdp
9833965Sjdpstatic void
9933965Sjdpranlib_touch PARAMS ((const char *archname));
10033965Sjdp
10133965Sjdpstatic void
10233965Sjdpusage PARAMS ((int));
10333965Sjdp
10433965Sjdp/** Globals and flags */
10533965Sjdp
10633965Sjdpint mri_mode;
10733965Sjdp
10833965Sjdp/* This flag distinguishes between ar and ranlib:
10933965Sjdp   1 means this is 'ranlib'; 0 means this is 'ar'.
11033965Sjdp   -1 means if we should use argv[0] to decide.  */
11133965Sjdpextern int is_ranlib;
11233965Sjdp
11333965Sjdp/* Nonzero means don't warn about creating the archive file if necessary.  */
11433965Sjdpint silent_create = 0;
11533965Sjdp
11633965Sjdp/* Nonzero means describe each action performed.  */
11733965Sjdpint verbose = 0;
11833965Sjdp
11933965Sjdp/* Nonzero means preserve dates of members when extracting them.  */
12033965Sjdpint preserve_dates = 0;
12133965Sjdp
12233965Sjdp/* Nonzero means don't replace existing members whose dates are more recent
12333965Sjdp   than the corresponding files.  */
12433965Sjdpint newer_only = 0;
12533965Sjdp
12633965Sjdp/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
12733965Sjdp   member).  -1 means we've been explicitly asked to not write a symbol table;
12833965Sjdp   +1 means we've been explictly asked to write it;
12933965Sjdp   0 is the default.
13033965Sjdp   Traditionally, the default in BSD has been to not write the table.
13133965Sjdp   However, for POSIX.2 compliance the default is now to write a symbol table
13233965Sjdp   if any of the members are object files.  */
13333965Sjdpint write_armap = 0;
13433965Sjdp
13533965Sjdp/* Nonzero means it's the name of an existing member; position new or moved
13633965Sjdp   files with respect to this one.  */
13733965Sjdpchar *posname = NULL;
13833965Sjdp
13933965Sjdp/* Sez how to use `posname': pos_before means position before that member.
14033965Sjdp   pos_after means position after that member. pos_end means always at end.
14133965Sjdp   pos_default means default appropriately. For the latter two, `posname'
14233965Sjdp   should also be zero.  */
14333965Sjdpenum pos
14433965Sjdp  {
14533965Sjdp    pos_default, pos_before, pos_after, pos_end
14633965Sjdp  } postype = pos_default;
14733965Sjdp
14833965Sjdpstatic bfd **
14938889Sjdpget_pos_bfd PARAMS ((bfd **, enum pos, const char *));
15033965Sjdp
15133965Sjdp/* Whether to truncate names of files stored in the archive.  */
15233965Sjdpstatic boolean ar_truncate = false;
15333965Sjdp
15433965Sjdpint interactive = 0;
15533965Sjdp
15633965Sjdpstatic void
15733965Sjdpmri_emul ()
15833965Sjdp{
15933965Sjdp  interactive = isatty (fileno (stdin));
16033965Sjdp  yyparse ();
16133965Sjdp}
16233965Sjdp
16333965Sjdp/* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
16433965Sjdp   COUNT is the length of the FILES chain; FUNCTION is called on each entry
16533965Sjdp   whose name matches one in FILES.  */
16633965Sjdp
16733965Sjdpstatic void
16833965Sjdpmap_over_members (arch, function, files, count)
16933965Sjdp     bfd *arch;
17033965Sjdp     void (*function) PARAMS ((bfd *));
17133965Sjdp     char **files;
17233965Sjdp     int count;
17333965Sjdp{
17433965Sjdp  bfd *head;
17533965Sjdp
17633965Sjdp  if (count == 0)
17733965Sjdp    {
17833965Sjdp      for (head = arch->next; head; head = head->next)
17933965Sjdp	{
18033965Sjdp	  PROGRESS (1);
18133965Sjdp	  function (head);
18233965Sjdp	}
18333965Sjdp      return;
18433965Sjdp    }
18533965Sjdp  /* This may appear to be a baroque way of accomplishing what we want.
18633965Sjdp     However we have to iterate over the filenames in order to notice where
18733965Sjdp     a filename is requested but does not exist in the archive.  Ditto
18833965Sjdp     mapping over each file each time -- we want to hack multiple
18933965Sjdp     references.  */
19033965Sjdp
19133965Sjdp  for (; count > 0; files++, count--)
19233965Sjdp    {
19333965Sjdp      boolean found = false;
19433965Sjdp
19533965Sjdp      for (head = arch->next; head; head = head->next)
19633965Sjdp	{
19733965Sjdp	  PROGRESS (1);
19833965Sjdp	  if (head->filename == NULL)
19933965Sjdp	    {
20033965Sjdp	      /* Some archive formats don't get the filenames filled in
20133965Sjdp		 until the elements are opened.  */
20233965Sjdp	      struct stat buf;
20333965Sjdp	      bfd_stat_arch_elt (head, &buf);
20433965Sjdp	    }
20533965Sjdp	  if ((head->filename != NULL) &&
20633965Sjdp	      (!strcmp (*files, head->filename)))
20733965Sjdp	    {
20833965Sjdp	      found = true;
20933965Sjdp	      function (head);
21033965Sjdp	    }
21133965Sjdp	}
21233965Sjdp      if (!found)
21333965Sjdp	fprintf (stderr, "no entry %s in archive\n", *files);
21433965Sjdp    }
21533965Sjdp}
21633965Sjdp
21733965Sjdpboolean operation_alters_arch = false;
21833965Sjdp
21933965Sjdpstatic void
22033965Sjdpusage (help)
22133965Sjdp     int help;
22233965Sjdp{
22333965Sjdp  FILE *s;
22433965Sjdp
22533965Sjdp  s = help ? stdout : stderr;
22633965Sjdp  if (! is_ranlib)
22733965Sjdp    fprintf (s, "\
22838889SjdpUsage: %s [-]{dmpqrtx}[abcilosSuvV] [member-name] archive-file file...\n\
22933965Sjdp       %s -M [<mri-script]\n",
23033965Sjdp	     program_name, program_name);
23133965Sjdp  else
23233965Sjdp    fprintf (s, "\
23333965SjdpUsage: %s [-vV] archive\n", program_name);
23433965Sjdp
23533965Sjdp  list_supported_targets (program_name, stderr);
23633965Sjdp
23733965Sjdp  if (help)
23838889Sjdp    fprintf (s, "Report bugs to bug-gnu-utils@gnu.org\n");
23933965Sjdp
24033965Sjdp  xexit (help ? 0 : 1);
24133965Sjdp}
24233965Sjdp
24333965Sjdp/* Normalize a file name specified on the command line into a file
24433965Sjdp   name which we will use in an archive.  */
24533965Sjdp
24633965Sjdpstatic const char *
24733965Sjdpnormalize (file, abfd)
24833965Sjdp     const char *file;
24933965Sjdp     bfd *abfd;
25033965Sjdp{
25133965Sjdp  const char *filename;
25233965Sjdp
25333965Sjdp  filename = strrchr (file, '/');
25433965Sjdp  if (filename != (char *) NULL)
25533965Sjdp    filename++;
25633965Sjdp  else
25733965Sjdp    filename = file;
25833965Sjdp
25933965Sjdp  if (ar_truncate
26033965Sjdp      && abfd != NULL
26133965Sjdp      && strlen (filename) > abfd->xvec->ar_max_namelen)
26233965Sjdp    {
26333965Sjdp      char *s;
26433965Sjdp
26533965Sjdp      /* Space leak.  */
26633965Sjdp      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
26733965Sjdp      memcpy (s, filename, abfd->xvec->ar_max_namelen);
26833965Sjdp      s[abfd->xvec->ar_max_namelen] = '\0';
26933965Sjdp      filename = s;
27033965Sjdp    }
27133965Sjdp
27233965Sjdp  return filename;
27333965Sjdp}
27433965Sjdp
27533965Sjdp/* Remove any output file.  This is only called via xatexit.  */
27633965Sjdp
27733965Sjdpstatic char *output_filename = NULL;
27833965Sjdpstatic FILE *output_file = NULL;
27933965Sjdpstatic bfd *output_bfd = NULL;
28033965Sjdp
28133965Sjdpstatic void
28233965Sjdpremove_output ()
28333965Sjdp{
28433965Sjdp  if (output_filename != NULL)
28533965Sjdp    {
28633965Sjdp      if (output_bfd != NULL && output_bfd->iostream != NULL)
28733965Sjdp	fclose ((FILE *) (output_bfd->iostream));
28833965Sjdp      if (output_file != NULL)
28933965Sjdp	fclose (output_file);
29033965Sjdp      unlink (output_filename);
29133965Sjdp    }
29233965Sjdp}
29333965Sjdp
29433965Sjdp/* The option parsing should be in its own function.
29533965Sjdp   It will be when I have getopt working.  */
29633965Sjdp
29733965Sjdpint
29833965Sjdpmain (argc, argv)
29933965Sjdp     int argc;
30033965Sjdp     char **argv;
30133965Sjdp{
30233965Sjdp  char *arg_ptr;
30333965Sjdp  char c;
30433965Sjdp  enum
30533965Sjdp    {
30633965Sjdp      none = 0, delete, replace, print_table,
30733965Sjdp      print_files, extract, move, quick_append
30833965Sjdp    } operation = none;
30933965Sjdp  int arg_index;
31033965Sjdp  char **files;
31133965Sjdp  char *inarch_filename;
31233965Sjdp  int show_version;
31333965Sjdp
31433965Sjdp  program_name = argv[0];
31533965Sjdp  xmalloc_set_program_name (program_name);
31633965Sjdp
31733965Sjdp  if (is_ranlib < 0)
31833965Sjdp    {
31933965Sjdp      char *temp;
32033965Sjdp
32133965Sjdp      temp = strrchr (program_name, '/');
32233965Sjdp      if (temp == NULL)
32333965Sjdp	temp = program_name;
32433965Sjdp      else
32533965Sjdp	++temp;
32633965Sjdp      if (strlen (temp) >= 6
32733965Sjdp	  && strcmp (temp + strlen (temp) - 6, "ranlib") == 0)
32833965Sjdp	is_ranlib = 1;
32933965Sjdp      else
33033965Sjdp	is_ranlib = 0;
33133965Sjdp    }
33233965Sjdp
33333965Sjdp  if (argc > 1 && argv[1][0] == '-')
33433965Sjdp    {
33533965Sjdp      if (strcmp (argv[1], "--help") == 0)
33633965Sjdp	usage (1);
33733965Sjdp      else if (strcmp (argv[1], "--version") == 0)
33833965Sjdp	{
33933965Sjdp	  if (is_ranlib)
34033965Sjdp	    print_version ("ranlib");
34133965Sjdp	  else
34233965Sjdp	    print_version ("ar");
34333965Sjdp	}
34433965Sjdp    }
34533965Sjdp
34633965Sjdp  START_PROGRESS (program_name, 0);
34733965Sjdp
34833965Sjdp  bfd_init ();
34933965Sjdp  set_default_bfd_target ();
35033965Sjdp
35133965Sjdp  show_version = 0;
35233965Sjdp
35333965Sjdp  xatexit (remove_output);
35433965Sjdp
35533965Sjdp  if (is_ranlib)
35633965Sjdp    {
35733965Sjdp      boolean touch = false;
35833965Sjdp
35933965Sjdp      if (argc < 2 || strcmp (argv[1], "--help") == 0)
36033965Sjdp	usage (0);
36133965Sjdp      if (strcmp (argv[1], "-V") == 0
36233965Sjdp	  || strcmp (argv[1], "-v") == 0
36333965Sjdp	  || strncmp (argv[1], "--v", 3) == 0)
36433965Sjdp	print_version ("ranlib");
36533965Sjdp      arg_index = 1;
36633965Sjdp      if (strcmp (argv[1], "-t") == 0)
36733965Sjdp	{
36833965Sjdp	  ++arg_index;
36933965Sjdp	  touch = true;
37033965Sjdp	}
37133965Sjdp      while (arg_index < argc)
37233965Sjdp	{
37333965Sjdp	  if (! touch)
37433965Sjdp	    ranlib_only (argv[arg_index]);
37533965Sjdp	  else
37633965Sjdp	    ranlib_touch (argv[arg_index]);
37733965Sjdp	  ++arg_index;
37833965Sjdp	}
37933965Sjdp      xexit (0);
38033965Sjdp    }
38133965Sjdp
38233965Sjdp  if (argc == 2 && strcmp (argv[1], "-M") == 0)
38333965Sjdp    {
38433965Sjdp      mri_emul ();
38533965Sjdp      xexit (0);
38633965Sjdp    }
38733965Sjdp
38833965Sjdp  if (argc < 2)
38933965Sjdp    usage (0);
39033965Sjdp
39133965Sjdp  arg_ptr = argv[1];
39233965Sjdp
39333965Sjdp  if (*arg_ptr == '-')
39433965Sjdp    ++arg_ptr;			/* compatibility */
39533965Sjdp
39633965Sjdp  while ((c = *arg_ptr++) != '\0')
39733965Sjdp    {
39833965Sjdp      switch (c)
39933965Sjdp	{
40033965Sjdp	case 'd':
40133965Sjdp	case 'm':
40233965Sjdp	case 'p':
40333965Sjdp	case 'q':
40433965Sjdp	case 'r':
40533965Sjdp	case 't':
40633965Sjdp	case 'x':
40733965Sjdp	  if (operation != none)
40833965Sjdp	    fatal ("two different operation options specified");
40933965Sjdp	  switch (c)
41033965Sjdp	    {
41133965Sjdp	    case 'd':
41233965Sjdp	      operation = delete;
41333965Sjdp	      operation_alters_arch = true;
41433965Sjdp	      break;
41533965Sjdp	    case 'm':
41633965Sjdp	      operation = move;
41733965Sjdp	      operation_alters_arch = true;
41833965Sjdp	      break;
41933965Sjdp	    case 'p':
42033965Sjdp	      operation = print_files;
42133965Sjdp	      break;
42233965Sjdp	    case 'q':
42333965Sjdp	      operation = quick_append;
42433965Sjdp	      operation_alters_arch = true;
42533965Sjdp	      break;
42633965Sjdp	    case 'r':
42733965Sjdp	      operation = replace;
42833965Sjdp	      operation_alters_arch = true;
42933965Sjdp	      break;
43033965Sjdp	    case 't':
43133965Sjdp	      operation = print_table;
43233965Sjdp	      break;
43333965Sjdp	    case 'x':
43433965Sjdp	      operation = extract;
43533965Sjdp	      break;
43633965Sjdp	    }
43733965Sjdp	case 'l':
43833965Sjdp	  break;
43933965Sjdp	case 'c':
44033965Sjdp	  silent_create = 1;
44133965Sjdp	  break;
44233965Sjdp	case 'o':
44333965Sjdp	  preserve_dates = 1;
44433965Sjdp	  break;
44533965Sjdp	case 'V':
44633965Sjdp	  show_version = true;
44733965Sjdp	  break;
44833965Sjdp	case 's':
44933965Sjdp	  write_armap = 1;
45033965Sjdp	  break;
45138889Sjdp	case 'S':
45238889Sjdp	  write_armap = -1;
45338889Sjdp	  break;
45433965Sjdp	case 'u':
45533965Sjdp	  newer_only = 1;
45633965Sjdp	  break;
45733965Sjdp	case 'v':
45833965Sjdp	  verbose = 1;
45933965Sjdp	  break;
46033965Sjdp	case 'a':
46133965Sjdp	  postype = pos_after;
46233965Sjdp	  break;
46333965Sjdp	case 'b':
46433965Sjdp	  postype = pos_before;
46533965Sjdp	  break;
46633965Sjdp	case 'i':
46733965Sjdp	  postype = pos_before;
46833965Sjdp	  break;
46933965Sjdp	case 'M':
47033965Sjdp	  mri_mode = 1;
47133965Sjdp	  break;
47233965Sjdp	case 'f':
47333965Sjdp	  ar_truncate = true;
47433965Sjdp	  break;
47533965Sjdp	default:
47633965Sjdp	  fprintf (stderr, "%s: illegal option -- %c\n", program_name, c);
47733965Sjdp	  usage (0);
47833965Sjdp	}
47933965Sjdp    }
48033965Sjdp
48133965Sjdp  if (show_version)
48233965Sjdp    print_version ("ar");
48333965Sjdp
48433965Sjdp  if (argc < 3)
48533965Sjdp    usage (0);
48633965Sjdp
48733965Sjdp  if (mri_mode)
48833965Sjdp    {
48933965Sjdp      mri_emul ();
49033965Sjdp    }
49133965Sjdp  else
49233965Sjdp    {
49333965Sjdp      bfd *arch;
49433965Sjdp
49533965Sjdp      /* We can't write an armap when using ar q, so just do ar r
49633965Sjdp         instead.  */
49733965Sjdp      if (operation == quick_append && write_armap)
49833965Sjdp	operation = replace;
49933965Sjdp
50033965Sjdp      if ((operation == none || operation == print_table)
50133965Sjdp	  && write_armap == 1)
50233965Sjdp	{
50333965Sjdp	  ranlib_only (argv[2]);
50433965Sjdp	  xexit (0);
50533965Sjdp	}
50633965Sjdp
50733965Sjdp      if (operation == none)
50833965Sjdp	fatal ("no operation specified");
50933965Sjdp
51033965Sjdp      if (newer_only && operation != replace)
51133965Sjdp	fatal ("`u' is only meaningful with the `r' option.");
51233965Sjdp
51333965Sjdp      arg_index = 2;
51433965Sjdp
51533965Sjdp      if (postype != pos_default)
51633965Sjdp	posname = argv[arg_index++];
51733965Sjdp
51833965Sjdp      inarch_filename = argv[arg_index++];
51933965Sjdp
52033965Sjdp      files = arg_index < argc ? argv + arg_index : NULL;
52133965Sjdp
52233965Sjdp#if 0
52333965Sjdp      /* We don't use do_quick_append any more.  Too many systems
52433965Sjdp         expect ar to always rebuild the symbol table even when q is
52533965Sjdp         used.  */
52633965Sjdp
52733965Sjdp      /* We can't do a quick append if we need to construct an
52833965Sjdp	 extended name table, because do_quick_append won't be able to
52933965Sjdp	 rebuild the name table.  Unfortunately, at this point we
53033965Sjdp	 don't actually know the maximum name length permitted by this
53133965Sjdp	 object file format.  So, we guess.  FIXME.  */
53233965Sjdp      if (operation == quick_append && ! ar_truncate)
53333965Sjdp	{
53433965Sjdp	  char **chk;
53533965Sjdp
53633965Sjdp	  for (chk = files; chk != NULL && *chk != '\0'; chk++)
53733965Sjdp	    {
53833965Sjdp	      if (strlen (normalize (*chk, (bfd *) NULL)) > 14)
53933965Sjdp		{
54033965Sjdp		  operation = replace;
54133965Sjdp		  break;
54233965Sjdp		}
54333965Sjdp	    }
54433965Sjdp	}
54533965Sjdp
54633965Sjdp      if (operation == quick_append)
54733965Sjdp	{
54833965Sjdp	  /* Note that quick appending to a non-existent archive creates it,
54933965Sjdp	     even if there are no files to append. */
55033965Sjdp	  do_quick_append (inarch_filename, files);
55133965Sjdp	  xexit (0);
55233965Sjdp	}
55333965Sjdp#endif
55433965Sjdp
55533965Sjdp      arch = open_inarch (inarch_filename,
55633965Sjdp			  files == NULL ? (char *) NULL : files[0]);
55733965Sjdp
55833965Sjdp      switch (operation)
55933965Sjdp	{
56033965Sjdp	case print_table:
56133965Sjdp	  map_over_members (arch, print_descr, files, argc - 3);
56233965Sjdp	  break;
56333965Sjdp
56433965Sjdp	case print_files:
56533965Sjdp	  map_over_members (arch, print_contents, files, argc - 3);
56633965Sjdp	  break;
56733965Sjdp
56833965Sjdp	case extract:
56933965Sjdp	  map_over_members (arch, extract_file, files, argc - 3);
57033965Sjdp	  break;
57133965Sjdp
57233965Sjdp	case delete:
57333965Sjdp	  if (files != NULL)
57433965Sjdp	    delete_members (arch, files);
57533965Sjdp	  break;
57633965Sjdp
57733965Sjdp	case move:
57833965Sjdp	  if (files != NULL)
57933965Sjdp	    move_members (arch, files);
58033965Sjdp	  break;
58133965Sjdp
58233965Sjdp	case replace:
58333965Sjdp	case quick_append:
58433965Sjdp	  if (files != NULL || write_armap > 0)
58533965Sjdp	    replace_members (arch, files, operation == quick_append);
58633965Sjdp	  break;
58733965Sjdp
58833965Sjdp	  /* Shouldn't happen! */
58933965Sjdp	default:
59033965Sjdp	  fprintf (stderr, "%s: internal error -- this option not implemented\n",
59133965Sjdp		   program_name);
59233965Sjdp	  xexit (1);
59333965Sjdp	}
59433965Sjdp    }
59533965Sjdp
59633965Sjdp  END_PROGRESS (program_name);
59733965Sjdp
59833965Sjdp  xexit (0);
59933965Sjdp  return 0;
60033965Sjdp}
60133965Sjdp
60233965Sjdpbfd *
60333965Sjdpopen_inarch (archive_filename, file)
60433965Sjdp     const char *archive_filename;
60533965Sjdp     const char *file;
60633965Sjdp{
60733965Sjdp  const char *target;
60833965Sjdp  bfd **last_one;
60933965Sjdp  bfd *next_one;
61033965Sjdp  struct stat sbuf;
61133965Sjdp  bfd *arch;
61233965Sjdp  char **matching;
61333965Sjdp
61433965Sjdp  bfd_set_error (bfd_error_no_error);
61533965Sjdp
61633965Sjdp  target = NULL;
61733965Sjdp
61833965Sjdp  if (stat (archive_filename, &sbuf) != 0)
61933965Sjdp    {
62033965Sjdp#ifndef __GO32__
62133965Sjdp
62233965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why
62333965Sjdp * stat() is wrong ... think it's buried in GO32's IDT
62433965Sjdp * - Jax
62533965Sjdp */
62633965Sjdp      if (errno != ENOENT)
62733965Sjdp	bfd_fatal (archive_filename);
62833965Sjdp#endif
62933965Sjdp
63033965Sjdp      if (!operation_alters_arch)
63133965Sjdp	{
63233965Sjdp	  fprintf (stderr, "%s: ", program_name);
63333965Sjdp	  perror (archive_filename);
63433965Sjdp	  maybequit ();
63533965Sjdp	  return NULL;
63633965Sjdp	}
63733965Sjdp
63833965Sjdp      /* Try to figure out the target to use for the archive from the
63933965Sjdp         first object on the list.  */
64033965Sjdp      if (file != NULL)
64133965Sjdp	{
64233965Sjdp	  bfd *obj;
64333965Sjdp
64433965Sjdp	  obj = bfd_openr (file, NULL);
64533965Sjdp	  if (obj != NULL)
64633965Sjdp	    {
64733965Sjdp	      if (bfd_check_format (obj, bfd_object))
64833965Sjdp		target = bfd_get_target (obj);
64933965Sjdp	      (void) bfd_close (obj);
65033965Sjdp	    }
65133965Sjdp	}
65233965Sjdp
65333965Sjdp      /* Create an empty archive.  */
65433965Sjdp      arch = bfd_openw (archive_filename, target);
65533965Sjdp      if (arch == NULL
65633965Sjdp	  || ! bfd_set_format (arch, bfd_archive)
65733965Sjdp	  || ! bfd_close (arch))
65833965Sjdp	bfd_fatal (archive_filename);
65933965Sjdp    }
66033965Sjdp
66133965Sjdp  arch = bfd_openr (archive_filename, target);
66233965Sjdp  if (arch == NULL)
66333965Sjdp    {
66433965Sjdp    bloser:
66533965Sjdp      bfd_fatal (archive_filename);
66633965Sjdp    }
66733965Sjdp
66833965Sjdp  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
66933965Sjdp    {
67033965Sjdp      bfd_nonfatal (archive_filename);
67133965Sjdp      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
67233965Sjdp	{
67333965Sjdp	  list_matching_formats (matching);
67433965Sjdp	  free (matching);
67533965Sjdp	}
67633965Sjdp      xexit (1);
67733965Sjdp    }
67833965Sjdp
67933965Sjdp  last_one = &(arch->next);
68033965Sjdp  /* Read all the contents right away, regardless.  */
68133965Sjdp  for (next_one = bfd_openr_next_archived_file (arch, NULL);
68233965Sjdp       next_one;
68333965Sjdp       next_one = bfd_openr_next_archived_file (arch, next_one))
68433965Sjdp    {
68533965Sjdp      PROGRESS (1);
68633965Sjdp      *last_one = next_one;
68733965Sjdp      last_one = &next_one->next;
68833965Sjdp    }
68933965Sjdp  *last_one = (bfd *) NULL;
69033965Sjdp  if (bfd_get_error () != bfd_error_no_more_archived_files)
69133965Sjdp    goto bloser;
69233965Sjdp  return arch;
69333965Sjdp}
69433965Sjdp
69533965Sjdpstatic void
69633965Sjdpprint_contents (abfd)
69733965Sjdp     bfd *abfd;
69833965Sjdp{
69933965Sjdp  int ncopied = 0;
70033965Sjdp  char *cbuf = xmalloc (BUFSIZE);
70133965Sjdp  struct stat buf;
70233965Sjdp  long size;
70333965Sjdp  if (bfd_stat_arch_elt (abfd, &buf) != 0)
70433965Sjdp    fatal ("internal stat error on %s", bfd_get_filename (abfd));
70533965Sjdp
70633965Sjdp  if (verbose)
70733965Sjdp    printf ("\n<member %s>\n\n", bfd_get_filename (abfd));
70833965Sjdp
70933965Sjdp  bfd_seek (abfd, 0, SEEK_SET);
71033965Sjdp
71133965Sjdp  size = buf.st_size;
71233965Sjdp  while (ncopied < size)
71333965Sjdp    {
71433965Sjdp
71533965Sjdp      int nread;
71633965Sjdp      int tocopy = size - ncopied;
71733965Sjdp      if (tocopy > BUFSIZE)
71833965Sjdp	tocopy = BUFSIZE;
71933965Sjdp
72033965Sjdp      nread = bfd_read (cbuf, 1, tocopy, abfd);	/* oops -- broke
72133965Sjdp							   abstraction!  */
72233965Sjdp      if (nread != tocopy)
72333965Sjdp	fatal ("%s is not a valid archive",
72433965Sjdp	       bfd_get_filename (bfd_my_archive (abfd)));
72533965Sjdp      fwrite (cbuf, 1, nread, stdout);
72633965Sjdp      ncopied += tocopy;
72733965Sjdp    }
72833965Sjdp  free (cbuf);
72933965Sjdp}
73033965Sjdp
73133965Sjdp/* Extract a member of the archive into its own file.
73233965Sjdp
73333965Sjdp   We defer opening the new file until after we have read a BUFSIZ chunk of the
73433965Sjdp   old one, since we know we have just read the archive header for the old
73533965Sjdp   one.  Since most members are shorter than BUFSIZ, this means we will read
73633965Sjdp   the old header, read the old data, write a new inode for the new file, and
73733965Sjdp   write the new data, and be done. This 'optimization' is what comes from
73833965Sjdp   sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
73933965Sjdp   Gilmore  */
74033965Sjdp
74133965Sjdpvoid
74233965Sjdpextract_file (abfd)
74333965Sjdp     bfd *abfd;
74433965Sjdp{
74533965Sjdp  FILE *ostream;
74633965Sjdp  char *cbuf = xmalloc (BUFSIZE);
74733965Sjdp  int nread, tocopy;
74833965Sjdp  int ncopied = 0;
74933965Sjdp  long size;
75033965Sjdp  struct stat buf;
75133965Sjdp  if (bfd_stat_arch_elt (abfd, &buf) != 0)
75233965Sjdp    fatal ("internal stat error on %s", bfd_get_filename (abfd));
75333965Sjdp  size = buf.st_size;
75433965Sjdp
75533965Sjdp  if (verbose)
75633965Sjdp    printf ("x - %s\n", bfd_get_filename (abfd));
75733965Sjdp
75833965Sjdp  bfd_seek (abfd, 0, SEEK_SET);
75933965Sjdp
76033965Sjdp  ostream = 0;
76133965Sjdp  if (size == 0)
76233965Sjdp    {
76333965Sjdp      /* Seems like an abstraction violation, eh?  Well it's OK! */
76433965Sjdp      output_filename = bfd_get_filename (abfd);
76533965Sjdp
76633965Sjdp      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
76733965Sjdp      if (!ostream)
76833965Sjdp	{
76933965Sjdp	  perror (bfd_get_filename (abfd));
77033965Sjdp	  xexit (1);
77133965Sjdp	}
77233965Sjdp
77333965Sjdp      output_file = ostream;
77433965Sjdp    }
77533965Sjdp  else
77633965Sjdp    while (ncopied < size)
77733965Sjdp      {
77833965Sjdp	tocopy = size - ncopied;
77933965Sjdp	if (tocopy > BUFSIZE)
78033965Sjdp	  tocopy = BUFSIZE;
78133965Sjdp
78233965Sjdp	nread = bfd_read (cbuf, 1, tocopy, abfd);
78333965Sjdp	if (nread != tocopy)
78433965Sjdp	  fatal ("%s is not a valid archive",
78533965Sjdp		 bfd_get_filename (bfd_my_archive (abfd)));
78633965Sjdp
78733965Sjdp	/* See comment above; this saves disk arm motion */
78833965Sjdp	if (!ostream)
78933965Sjdp	  {
79033965Sjdp	    /* Seems like an abstraction violation, eh?  Well it's OK! */
79133965Sjdp	    output_filename = bfd_get_filename (abfd);
79233965Sjdp
79333965Sjdp	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
79433965Sjdp	    if (!ostream)
79533965Sjdp	      {
79633965Sjdp		perror (bfd_get_filename (abfd));
79733965Sjdp		xexit (1);
79833965Sjdp	      }
79933965Sjdp
80033965Sjdp	    output_file = ostream;
80133965Sjdp	  }
80233965Sjdp	fwrite (cbuf, 1, nread, ostream);
80333965Sjdp	ncopied += tocopy;
80433965Sjdp      }
80533965Sjdp
80633965Sjdp  fclose (ostream);
80733965Sjdp
80833965Sjdp  output_file = NULL;
80933965Sjdp  output_filename = NULL;
81033965Sjdp
81133965Sjdp  chmod (bfd_get_filename (abfd), buf.st_mode);
81233965Sjdp
81333965Sjdp  if (preserve_dates)
81433965Sjdp    {
81533965Sjdp#ifdef HAVE_GOOD_UTIME_H
81633965Sjdp      struct utimbuf tb;
81733965Sjdp      tb.actime = buf.st_mtime;
81833965Sjdp      tb.modtime = buf.st_mtime;
81933965Sjdp      utime (bfd_get_filename (abfd), &tb);	/* FIXME check result */
82033965Sjdp#else /* ! HAVE_GOOD_UTIME_H */
82133965Sjdp#ifndef HAVE_UTIMES
82233965Sjdp      long tb[2];
82333965Sjdp      tb[0] = buf.st_mtime;
82433965Sjdp      tb[1] = buf.st_mtime;
82533965Sjdp      utime (bfd_get_filename (abfd), tb);	/* FIXME check result */
82633965Sjdp#else /* HAVE_UTIMES */
82733965Sjdp      struct timeval tv[2];
82833965Sjdp      tv[0].tv_sec = buf.st_mtime;
82933965Sjdp      tv[0].tv_usec = 0;
83033965Sjdp      tv[1].tv_sec = buf.st_mtime;
83133965Sjdp      tv[1].tv_usec = 0;
83233965Sjdp      utimes (bfd_get_filename (abfd), tv);	/* FIXME check result */
83333965Sjdp#endif /* HAVE_UTIMES */
83433965Sjdp#endif /* ! HAVE_GOOD_UTIME_H */
83533965Sjdp    }
83633965Sjdpfree (cbuf);
83733965Sjdp}
83833965Sjdp
83933965Sjdp#if 0
84033965Sjdp
84133965Sjdp/* We don't use this anymore.  Too many systems expect ar to rebuild
84233965Sjdp   the symbol table even when q is used.  */
84333965Sjdp
84433965Sjdp/* Just do it quickly; don't worry about dups, armap, or anything like that */
84533965Sjdp
84633965Sjdpstatic void
84733965Sjdpdo_quick_append (archive_filename, files_to_append)
84833965Sjdp     const char *archive_filename;
84933965Sjdp     char **files_to_append;
85033965Sjdp{
85133965Sjdp  FILE *ofile, *ifile;
85233965Sjdp  char *buf = xmalloc (BUFSIZE);
85333965Sjdp  long tocopy, thistime;
85433965Sjdp  bfd *temp;
85533965Sjdp  struct stat sbuf;
85633965Sjdp  boolean newfile = false;
85733965Sjdp  bfd_set_error (bfd_error_no_error);
85833965Sjdp
85933965Sjdp  if (stat (archive_filename, &sbuf) != 0)
86033965Sjdp    {
86133965Sjdp
86233965Sjdp#ifndef __GO32__
86333965Sjdp
86433965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why
86533965Sjdp * stat() is wrong ... think it's buried in GO32's IDT
86633965Sjdp * - Jax
86733965Sjdp */
86833965Sjdp
86933965Sjdp      if (errno != ENOENT)
87033965Sjdp	bfd_fatal (archive_filename);
87133965Sjdp#endif
87233965Sjdp
87333965Sjdp      newfile = true;
87433965Sjdp    }
87533965Sjdp
87633965Sjdp  ofile = fopen (archive_filename, FOPEN_AUB);
87733965Sjdp  if (ofile == NULL)
87833965Sjdp    {
87933965Sjdp      perror (program_name);
88033965Sjdp      xexit (1);
88133965Sjdp    }
88233965Sjdp
88333965Sjdp  temp = bfd_openr (archive_filename, NULL);
88433965Sjdp  if (temp == NULL)
88533965Sjdp    {
88633965Sjdp      bfd_fatal (archive_filename);
88733965Sjdp    }
88833965Sjdp  if (newfile == false)
88933965Sjdp    {
89033965Sjdp      if (bfd_check_format (temp, bfd_archive) != true)
89133965Sjdp	fatal ("%s is not an archive", archive_filename);
89233965Sjdp    }
89333965Sjdp  else
89433965Sjdp    {
89533965Sjdp      fwrite (ARMAG, 1, SARMAG, ofile);
89633965Sjdp      if (!silent_create)
89733965Sjdp	fprintf (stderr, "%s: creating %s\n",
89833965Sjdp		 program_name, archive_filename);
89933965Sjdp    }
90033965Sjdp
90133965Sjdp  if (ar_truncate)
90233965Sjdp    temp->flags |= BFD_TRADITIONAL_FORMAT;
90333965Sjdp
90433965Sjdp  /* assume it's an achive, go straight to the end, sans $200 */
90533965Sjdp  fseek (ofile, 0, 2);
90633965Sjdp
90733965Sjdp  for (; files_to_append && *files_to_append; ++files_to_append)
90833965Sjdp    {
90933965Sjdp      struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append);
91033965Sjdp      if (hdr == NULL)
91133965Sjdp	{
91233965Sjdp	  bfd_fatal (*files_to_append);
91333965Sjdp	}
91433965Sjdp
91533965Sjdp      BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
91633965Sjdp
91733965Sjdp      ifile = fopen (*files_to_append, FOPEN_RB);
91833965Sjdp      if (ifile == NULL)
91933965Sjdp	{
92033965Sjdp	  bfd_nonfatal (*files_to_append);
92133965Sjdp	}
92233965Sjdp
92333965Sjdp      if (stat (*files_to_append, &sbuf) != 0)
92433965Sjdp	{
92533965Sjdp	  bfd_nonfatal (*files_to_append);
92633965Sjdp	}
92733965Sjdp
92833965Sjdp      tocopy = sbuf.st_size;
92933965Sjdp
93033965Sjdp      /* XXX should do error-checking! */
93133965Sjdp      fwrite (hdr, 1, sizeof (struct ar_hdr), ofile);
93233965Sjdp
93333965Sjdp      while (tocopy > 0)
93433965Sjdp	{
93533965Sjdp	  thistime = tocopy;
93633965Sjdp	  if (thistime > BUFSIZE)
93733965Sjdp	    thistime = BUFSIZE;
93833965Sjdp	  fread (buf, 1, thistime, ifile);
93933965Sjdp	  fwrite (buf, 1, thistime, ofile);
94033965Sjdp	  tocopy -= thistime;
94133965Sjdp	}
94233965Sjdp      fclose (ifile);
94333965Sjdp      if ((sbuf.st_size % 2) == 1)
94433965Sjdp	putc ('\012', ofile);
94533965Sjdp    }
94633965Sjdp  fclose (ofile);
94733965Sjdp  bfd_close (temp);
94833965Sjdp  free (buf);
94933965Sjdp}
95033965Sjdp
95133965Sjdp#endif /* 0 */
95233965Sjdp
95333965Sjdpstatic void
95433965Sjdpwrite_archive (iarch)
95533965Sjdp     bfd *iarch;
95633965Sjdp{
95733965Sjdp  bfd *obfd;
95833965Sjdp  char *old_name, *new_name;
95933965Sjdp  bfd *contents_head = iarch->next;
96033965Sjdp
96133965Sjdp  old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
96233965Sjdp  strcpy (old_name, bfd_get_filename (iarch));
96333965Sjdp  new_name = make_tempname (old_name);
96433965Sjdp
96533965Sjdp  output_filename = new_name;
96633965Sjdp
96733965Sjdp  obfd = bfd_openw (new_name, bfd_get_target (iarch));
96833965Sjdp
96933965Sjdp  if (obfd == NULL)
97033965Sjdp    bfd_fatal (old_name);
97133965Sjdp
97233965Sjdp  output_bfd = obfd;
97333965Sjdp
97433965Sjdp  bfd_set_format (obfd, bfd_archive);
97533965Sjdp
97633965Sjdp  /* Request writing the archive symbol table unless we've
97733965Sjdp     been explicitly requested not to.  */
97833965Sjdp  obfd->has_armap = write_armap >= 0;
97933965Sjdp
98033965Sjdp  if (ar_truncate)
98133965Sjdp    {
98233965Sjdp      /* This should really use bfd_set_file_flags, but that rejects
98333965Sjdp         archives.  */
98433965Sjdp      obfd->flags |= BFD_TRADITIONAL_FORMAT;
98533965Sjdp    }
98633965Sjdp
98733965Sjdp  if (bfd_set_archive_head (obfd, contents_head) != true)
98833965Sjdp    bfd_fatal (old_name);
98933965Sjdp
99033965Sjdp  if (!bfd_close (obfd))
99133965Sjdp    bfd_fatal (old_name);
99233965Sjdp
99333965Sjdp  output_bfd = NULL;
99433965Sjdp  output_filename = NULL;
99533965Sjdp
99633965Sjdp  /* We don't care if this fails; we might be creating the archive.  */
99733965Sjdp  bfd_close (iarch);
99833965Sjdp  unlink (old_name);
99933965Sjdp
100033965Sjdp  if (rename (new_name, old_name) != 0)
100133965Sjdp    bfd_fatal (old_name);
100233965Sjdp}
100333965Sjdp
100433965Sjdp/* Return a pointer to the pointer to the entry which should be rplacd'd
100533965Sjdp   into when altering.  DEFAULT_POS should be how to interpret pos_default,
100633965Sjdp   and should be a pos value.  */
100733965Sjdp
100833965Sjdpstatic bfd **
100938889Sjdpget_pos_bfd (contents, default_pos, default_posname)
101033965Sjdp     bfd **contents;
101133965Sjdp     enum pos default_pos;
101238889Sjdp     const char *default_posname;
101333965Sjdp{
101433965Sjdp  bfd **after_bfd = contents;
101538889Sjdp  enum pos realpos;
101638889Sjdp  const char *realposname;
101733965Sjdp
101838889Sjdp  if (postype == pos_default)
101938889Sjdp    {
102038889Sjdp      realpos = default_pos;
102138889Sjdp      realposname = default_posname;
102238889Sjdp    }
102338889Sjdp  else
102438889Sjdp    {
102538889Sjdp      realpos = postype;
102638889Sjdp      realposname = posname;
102738889Sjdp    }
102838889Sjdp
102933965Sjdp  if (realpos == pos_end)
103033965Sjdp    {
103133965Sjdp      while (*after_bfd)
103233965Sjdp	after_bfd = &((*after_bfd)->next);
103333965Sjdp    }
103433965Sjdp  else
103533965Sjdp    {
103633965Sjdp      for (; *after_bfd; after_bfd = &(*after_bfd)->next)
103738889Sjdp	if (strcmp ((*after_bfd)->filename, realposname) == 0)
103833965Sjdp	  {
103933965Sjdp	    if (realpos == pos_after)
104033965Sjdp	      after_bfd = &(*after_bfd)->next;
104133965Sjdp	    break;
104233965Sjdp	  }
104333965Sjdp    }
104433965Sjdp  return after_bfd;
104533965Sjdp}
104633965Sjdp
104733965Sjdpstatic void
104833965Sjdpdelete_members (arch, files_to_delete)
104933965Sjdp     bfd *arch;
105033965Sjdp     char **files_to_delete;
105133965Sjdp{
105233965Sjdp  bfd **current_ptr_ptr;
105333965Sjdp  boolean found;
105433965Sjdp  boolean something_changed = false;
105533965Sjdp  for (; *files_to_delete != NULL; ++files_to_delete)
105633965Sjdp    {
105733965Sjdp      /* In a.out systems, the armap is optional.  It's also called
105833965Sjdp	 __.SYMDEF.  So if the user asked to delete it, we should remember
105933965Sjdp	 that fact. This isn't quite right for COFF systems (where
106033965Sjdp	 __.SYMDEF might be regular member), but it's very unlikely
106133965Sjdp	 to be a problem.  FIXME */
106233965Sjdp
106333965Sjdp      if (!strcmp (*files_to_delete, "__.SYMDEF"))
106433965Sjdp	{
106533965Sjdp	  arch->has_armap = false;
106633965Sjdp	  write_armap = -1;
106733965Sjdp	  continue;
106833965Sjdp	}
106933965Sjdp
107033965Sjdp      found = false;
107133965Sjdp      current_ptr_ptr = &(arch->next);
107233965Sjdp      while (*current_ptr_ptr)
107333965Sjdp	{
107433965Sjdp	  if (strcmp (*files_to_delete, (*current_ptr_ptr)->filename) == 0)
107533965Sjdp	    {
107633965Sjdp	      found = true;
107733965Sjdp	      something_changed = true;
107833965Sjdp	      if (verbose)
107933965Sjdp		printf ("d - %s\n",
108033965Sjdp			*files_to_delete);
108133965Sjdp	      *current_ptr_ptr = ((*current_ptr_ptr)->next);
108233965Sjdp	      goto next_file;
108333965Sjdp	    }
108433965Sjdp	  else
108533965Sjdp	    {
108633965Sjdp	      current_ptr_ptr = &((*current_ptr_ptr)->next);
108733965Sjdp	    }
108833965Sjdp	}
108933965Sjdp
109033965Sjdp      if (verbose && found == false)
109133965Sjdp	{
109233965Sjdp	  printf ("No member named `%s'\n", *files_to_delete);
109333965Sjdp	}
109433965Sjdp    next_file:
109533965Sjdp      ;
109633965Sjdp    }
109733965Sjdp
109833965Sjdp  if (something_changed == true)
109933965Sjdp    {
110033965Sjdp      write_archive (arch);
110133965Sjdp    }
110233965Sjdp}
110333965Sjdp
110433965Sjdp
110533965Sjdp/* Reposition existing members within an archive */
110633965Sjdp
110733965Sjdpstatic void
110833965Sjdpmove_members (arch, files_to_move)
110933965Sjdp     bfd *arch;
111033965Sjdp     char **files_to_move;
111133965Sjdp{
111233965Sjdp  bfd **after_bfd;		/* New entries go after this one */
111333965Sjdp  bfd **current_ptr_ptr;	/* cdr pointer into contents */
111433965Sjdp
111533965Sjdp  for (; *files_to_move; ++files_to_move)
111633965Sjdp    {
111733965Sjdp      current_ptr_ptr = &(arch->next);
111833965Sjdp      while (*current_ptr_ptr)
111933965Sjdp	{
112033965Sjdp	  bfd *current_ptr = *current_ptr_ptr;
112133965Sjdp	  if (strcmp (normalize (*files_to_move, arch),
112233965Sjdp		      current_ptr->filename) == 0)
112333965Sjdp	    {
112433965Sjdp	      /* Move this file to the end of the list - first cut from
112533965Sjdp		 where it is.  */
112633965Sjdp	      bfd *link;
112733965Sjdp	      *current_ptr_ptr = current_ptr->next;
112833965Sjdp
112933965Sjdp	      /* Now glue to end */
113038889Sjdp	      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
113133965Sjdp	      link = *after_bfd;
113233965Sjdp	      *after_bfd = current_ptr;
113333965Sjdp	      current_ptr->next = link;
113433965Sjdp
113533965Sjdp	      if (verbose)
113633965Sjdp		printf ("m - %s\n", *files_to_move);
113733965Sjdp
113833965Sjdp	      goto next_file;
113933965Sjdp	    }
114033965Sjdp
114133965Sjdp	  current_ptr_ptr = &((*current_ptr_ptr)->next);
114233965Sjdp	}
114333965Sjdp      fprintf (stderr, "%s: no entry %s in archive %s!\n",
114433965Sjdp	       program_name, *files_to_move, arch->filename);
114533965Sjdp      xexit (1);
114633965Sjdp    next_file:;
114733965Sjdp    }
114833965Sjdp
114933965Sjdp  write_archive (arch);
115033965Sjdp}
115133965Sjdp
115233965Sjdp/* Ought to default to replacing in place, but this is existing practice!  */
115333965Sjdp
115433965Sjdpstatic void
115533965Sjdpreplace_members (arch, files_to_move, quick)
115633965Sjdp     bfd *arch;
115733965Sjdp     char **files_to_move;
115833965Sjdp     boolean quick;
115933965Sjdp{
116033965Sjdp  boolean changed = false;
116133965Sjdp  bfd **after_bfd;		/* New entries go after this one */
116233965Sjdp  bfd *current;
116333965Sjdp  bfd **current_ptr;
116433965Sjdp  bfd *temp;
116533965Sjdp
116633965Sjdp  while (files_to_move && *files_to_move)
116733965Sjdp    {
116833965Sjdp      if (! quick)
116933965Sjdp	{
117033965Sjdp	  current_ptr = &arch->next;
117133965Sjdp	  while (*current_ptr)
117233965Sjdp	    {
117333965Sjdp	      current = *current_ptr;
117433965Sjdp
117533965Sjdp	      /* For compatibility with existing ar programs, we
117633965Sjdp		 permit the same file to be added multiple times.  */
117733965Sjdp	      if (strcmp (normalize (*files_to_move, arch),
117833965Sjdp			  normalize (current->filename, arch)) == 0
117933965Sjdp		  && current->arelt_data != NULL)
118033965Sjdp		{
118133965Sjdp		  if (newer_only)
118233965Sjdp		    {
118333965Sjdp		      struct stat fsbuf, asbuf;
118433965Sjdp
118533965Sjdp		      if (stat (*files_to_move, &fsbuf) != 0)
118633965Sjdp			{
118733965Sjdp			  if (errno != ENOENT)
118833965Sjdp			    bfd_fatal (*files_to_move);
118933965Sjdp			  goto next_file;
119033965Sjdp			}
119133965Sjdp		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
119233965Sjdp			fatal ("internal stat error on %s", current->filename);
119333965Sjdp
119433965Sjdp		      if (fsbuf.st_mtime <= asbuf.st_mtime)
119533965Sjdp			goto next_file;
119633965Sjdp		    }
119733965Sjdp
119838889Sjdp		  after_bfd = get_pos_bfd (&arch->next, pos_after,
119938889Sjdp					   current->filename);
120038889Sjdp		  temp = *after_bfd;
120133965Sjdp
120233965Sjdp		  *after_bfd = bfd_openr (*files_to_move, NULL);
120333965Sjdp		  if (*after_bfd == (bfd *) NULL)
120433965Sjdp		    {
120533965Sjdp		      bfd_fatal (*files_to_move);
120633965Sjdp		    }
120733965Sjdp		  (*after_bfd)->next = temp;
120833965Sjdp
120938889Sjdp		  /* snip out this entry from the chain */
121038889Sjdp		  *current_ptr = (*current_ptr)->next;
121138889Sjdp
121233965Sjdp		  if (verbose)
121333965Sjdp		    {
121433965Sjdp		      printf ("r - %s\n", *files_to_move);
121533965Sjdp		    }
121633965Sjdp
121733965Sjdp		  changed = true;
121833965Sjdp
121933965Sjdp		  goto next_file;
122033965Sjdp		}
122133965Sjdp	      current_ptr = &(current->next);
122233965Sjdp	    }
122333965Sjdp	}
122433965Sjdp
122533965Sjdp      /* Add to the end of the archive.  */
122633965Sjdp
122738889Sjdp      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
122833965Sjdp      temp = *after_bfd;
122933965Sjdp      *after_bfd = bfd_openr (*files_to_move, NULL);
123033965Sjdp      if (*after_bfd == (bfd *) NULL)
123133965Sjdp	{
123233965Sjdp	  bfd_fatal (*files_to_move);
123333965Sjdp	}
123433965Sjdp      if (verbose)
123533965Sjdp	{
123633965Sjdp	  printf ("a - %s\n", *files_to_move);
123733965Sjdp	}
123833965Sjdp
123933965Sjdp      (*after_bfd)->next = temp;
124033965Sjdp
124133965Sjdp      changed = true;
124233965Sjdp
124333965Sjdp    next_file:;
124433965Sjdp
124533965Sjdp      files_to_move++;
124633965Sjdp    }
124733965Sjdp
124833965Sjdp  if (changed)
124933965Sjdp    write_archive (arch);
125033965Sjdp}
125133965Sjdp
125233965Sjdpstatic void
125333965Sjdpranlib_only (archname)
125433965Sjdp     const char *archname;
125533965Sjdp{
125633965Sjdp  bfd *arch;
125733965Sjdp
125833965Sjdp  write_armap = 1;
125933965Sjdp  arch = open_inarch (archname, (char *) NULL);
126033965Sjdp  if (arch == NULL)
126133965Sjdp    xexit (1);
126233965Sjdp  write_archive (arch);
126333965Sjdp}
126433965Sjdp
126533965Sjdp/* Update the timestamp of the symbol map of an archive.  */
126633965Sjdp
126733965Sjdpstatic void
126833965Sjdpranlib_touch (archname)
126933965Sjdp     const char *archname;
127033965Sjdp{
127133965Sjdp#ifdef __GO32__
127233965Sjdp  /* I don't think updating works on go32.  */
127333965Sjdp  ranlib_only (archname);
127433965Sjdp#else
127533965Sjdp  int f;
127633965Sjdp  bfd *arch;
127733965Sjdp  char **matching;
127833965Sjdp
127933965Sjdp  f = open (archname, O_RDWR, 0);
128033965Sjdp  if (f < 0)
128133965Sjdp    {
128233965Sjdp      bfd_set_error (bfd_error_system_call);
128333965Sjdp      bfd_fatal (archname);
128433965Sjdp    }
128533965Sjdp
128633965Sjdp  arch = bfd_fdopenr (archname, (const char *) NULL, f);
128733965Sjdp  if (arch == NULL)
128833965Sjdp    bfd_fatal (archname);
128933965Sjdp  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
129033965Sjdp    {
129133965Sjdp      bfd_nonfatal (archname);
129233965Sjdp      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
129333965Sjdp	{
129433965Sjdp	  list_matching_formats (matching);
129533965Sjdp	  free (matching);
129633965Sjdp	}
129733965Sjdp      xexit (1);
129833965Sjdp    }
129933965Sjdp
130033965Sjdp  if (! bfd_has_map (arch))
130133965Sjdp    fatal ("%s: no archive map to update", archname);
130233965Sjdp
130333965Sjdp  bfd_update_armap_timestamp (arch);
130433965Sjdp
130533965Sjdp  if (! bfd_close (arch))
130633965Sjdp    bfd_fatal (archname);
130733965Sjdp#endif
130833965Sjdp}
130933965Sjdp
131033965Sjdp/* Things which are interesting to map over all or some of the files: */
131133965Sjdp
131233965Sjdpstatic void
131333965Sjdpprint_descr (abfd)
131433965Sjdp     bfd *abfd;
131533965Sjdp{
131633965Sjdp  print_arelt_descr (stdout, abfd, verbose);
131733965Sjdp}
1318