133965Sjdp/* ar.c - Archive modify and extract.
289857Sobrien   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3218822Sdim   2001, 2002, 2003, 2004, 2005, 2006, 2007
460484Sobrien   Free Software Foundation, Inc.
533965Sjdp
6104834Sobrien   This file is part of GNU Binutils.
733965Sjdp
8104834Sobrien   This program is free software; you can redistribute it and/or modify
9104834Sobrien   it under the terms of the GNU General Public License as published by
10104834Sobrien   the Free Software Foundation; either version 2 of the License, or
11104834Sobrien   (at your option) any later version.
1233965Sjdp
13104834Sobrien   This program is distributed in the hope that it will be useful,
14104834Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
15104834Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16104834Sobrien   GNU General Public License for more details.
1733965Sjdp
18104834Sobrien   You should have received a copy of the GNU General Public License
19104834Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2133965Sjdp
2233965Sjdp/*
2333965Sjdp   Bugs: should use getopt the way tar does (complete w/optional -) and
2433965Sjdp   should have long options too. GNU ar used to check file against filesystem
2533965Sjdp   in quick_update and replace operations (would check mtime). Doesn't warn
2633965Sjdp   when name truncated. No way to specify pos_end. Error messages should be
27130561Sobrien   more consistent.  */
28104834Sobrien
29218822Sdim#include "sysdep.h"
3033965Sjdp#include "bfd.h"
3133965Sjdp#include "libiberty.h"
3233965Sjdp#include "progress.h"
3333965Sjdp#include "aout/ar.h"
3433965Sjdp#include "libbfd.h"
35218822Sdim#include "bucomm.h"
3633965Sjdp#include "arsup.h"
3761843Sobrien#include "filenames.h"
38104834Sobrien#include "binemul.h"
3933965Sjdp#include <sys/stat.h>
4033965Sjdp
4133965Sjdp#ifdef __GO32___
4233965Sjdp#define EXT_NAME_LEN 3		/* bufflen of addition to name if it's MS-DOS */
4333965Sjdp#else
4433965Sjdp#define EXT_NAME_LEN 6		/* ditto for *NIX */
4533965Sjdp#endif
4633965Sjdp
4760484Sobrien/* We need to open files in binary modes on system where that makes a
4860484Sobrien   difference.  */
4960484Sobrien#ifndef O_BINARY
5060484Sobrien#define O_BINARY 0
5160484Sobrien#endif
5260484Sobrien
5333965Sjdp/* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
5433965Sjdp
5533965Sjdpstruct ar_hdr *
56130561Sobrien  bfd_special_undocumented_glue (bfd * abfd, const char *filename);
5733965Sjdp
5833965Sjdp/* Static declarations */
5933965Sjdp
60130561Sobrienstatic void mri_emul (void);
61130561Sobrienstatic const char *normalize (const char *, bfd *);
62130561Sobrienstatic void remove_output (void);
63130561Sobrienstatic void map_over_members (bfd *, void (*)(bfd *), char **, int);
64130561Sobrienstatic void print_contents (bfd * member);
65130561Sobrienstatic void delete_members (bfd *, char **files_to_delete);
6633965Sjdp
67130561Sobrienstatic void move_members (bfd *, char **files_to_move);
68130561Sobrienstatic void replace_members
69130561Sobrien  (bfd *, char **files_to_replace, bfd_boolean quick);
70130561Sobrienstatic void print_descr (bfd * abfd);
71130561Sobrienstatic void write_archive (bfd *);
72218822Sdimstatic int  ranlib_only (const char *archname);
73218822Sdimstatic int  ranlib_touch (const char *archname);
74130561Sobrienstatic void usage (int);
7533965Sjdp
7633965Sjdp/** Globals and flags */
7733965Sjdp
78218822Sdimstatic int mri_mode;
7933965Sjdp
8033965Sjdp/* This flag distinguishes between ar and ranlib:
8133965Sjdp   1 means this is 'ranlib'; 0 means this is 'ar'.
8233965Sjdp   -1 means if we should use argv[0] to decide.  */
8333965Sjdpextern int is_ranlib;
8433965Sjdp
8533965Sjdp/* Nonzero means don't warn about creating the archive file if necessary.  */
8633965Sjdpint silent_create = 0;
8733965Sjdp
8833965Sjdp/* Nonzero means describe each action performed.  */
8933965Sjdpint verbose = 0;
9033965Sjdp
9133965Sjdp/* Nonzero means preserve dates of members when extracting them.  */
9233965Sjdpint preserve_dates = 0;
9333965Sjdp
9433965Sjdp/* Nonzero means don't replace existing members whose dates are more recent
9533965Sjdp   than the corresponding files.  */
9633965Sjdpint newer_only = 0;
9733965Sjdp
9833965Sjdp/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
9933965Sjdp   member).  -1 means we've been explicitly asked to not write a symbol table;
100130561Sobrien   +1 means we've been explicitly asked to write it;
10133965Sjdp   0 is the default.
10233965Sjdp   Traditionally, the default in BSD has been to not write the table.
10333965Sjdp   However, for POSIX.2 compliance the default is now to write a symbol table
10433965Sjdp   if any of the members are object files.  */
10533965Sjdpint write_armap = 0;
10633965Sjdp
10733965Sjdp/* Nonzero means it's the name of an existing member; position new or moved
10833965Sjdp   files with respect to this one.  */
10933965Sjdpchar *posname = NULL;
11033965Sjdp
11133965Sjdp/* Sez how to use `posname': pos_before means position before that member.
11233965Sjdp   pos_after means position after that member. pos_end means always at end.
11333965Sjdp   pos_default means default appropriately. For the latter two, `posname'
11433965Sjdp   should also be zero.  */
11533965Sjdpenum pos
11633965Sjdp  {
11733965Sjdp    pos_default, pos_before, pos_after, pos_end
11833965Sjdp  } postype = pos_default;
11933965Sjdp
12033965Sjdpstatic bfd **
121130561Sobrienget_pos_bfd (bfd **, enum pos, const char *);
12233965Sjdp
123130561Sobrien/* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
12460484Sobrien   extract the COUNTED_NAME_COUNTER instance of that name.  */
125130561Sobrienstatic bfd_boolean counted_name_mode = 0;
12660484Sobrienstatic int counted_name_counter = 0;
12760484Sobrien
12833965Sjdp/* Whether to truncate names of files stored in the archive.  */
129130561Sobrienstatic bfd_boolean ar_truncate = FALSE;
13033965Sjdp
13160484Sobrien/* Whether to use a full file name match when searching an archive.
13260484Sobrien   This is convenient for archives created by the Microsoft lib
13360484Sobrien   program.  */
134130561Sobrienstatic bfd_boolean full_pathname = FALSE;
13560484Sobrien
13633965Sjdpint interactive = 0;
13733965Sjdp
13833965Sjdpstatic void
139130561Sobrienmri_emul (void)
14033965Sjdp{
14133965Sjdp  interactive = isatty (fileno (stdin));
14233965Sjdp  yyparse ();
14333965Sjdp}
14433965Sjdp
14533965Sjdp/* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
14633965Sjdp   COUNT is the length of the FILES chain; FUNCTION is called on each entry
14733965Sjdp   whose name matches one in FILES.  */
14833965Sjdp
14933965Sjdpstatic void
150130561Sobrienmap_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
15133965Sjdp{
15233965Sjdp  bfd *head;
15360484Sobrien  int match_count;
15433965Sjdp
15533965Sjdp  if (count == 0)
15633965Sjdp    {
157218822Sdim      for (head = arch->archive_next; head; head = head->archive_next)
15833965Sjdp	{
15933965Sjdp	  PROGRESS (1);
16033965Sjdp	  function (head);
16133965Sjdp	}
16233965Sjdp      return;
16333965Sjdp    }
16460484Sobrien
16533965Sjdp  /* This may appear to be a baroque way of accomplishing what we want.
16633965Sjdp     However we have to iterate over the filenames in order to notice where
16733965Sjdp     a filename is requested but does not exist in the archive.  Ditto
16833965Sjdp     mapping over each file each time -- we want to hack multiple
16933965Sjdp     references.  */
17033965Sjdp
17133965Sjdp  for (; count > 0; files++, count--)
17233965Sjdp    {
173130561Sobrien      bfd_boolean found = FALSE;
17433965Sjdp
17560484Sobrien      match_count = 0;
176218822Sdim      for (head = arch->archive_next; head; head = head->archive_next)
17733965Sjdp	{
17833965Sjdp	  PROGRESS (1);
17933965Sjdp	  if (head->filename == NULL)
18033965Sjdp	    {
18133965Sjdp	      /* Some archive formats don't get the filenames filled in
18233965Sjdp		 until the elements are opened.  */
18333965Sjdp	      struct stat buf;
18433965Sjdp	      bfd_stat_arch_elt (head, &buf);
18533965Sjdp	    }
18633965Sjdp	  if ((head->filename != NULL) &&
18761843Sobrien	      (!FILENAME_CMP (normalize (*files, arch), head->filename)))
18833965Sjdp	    {
18960484Sobrien	      ++match_count;
19060484Sobrien	      if (counted_name_mode
191104834Sobrien		  && match_count != counted_name_counter)
19260484Sobrien		{
19360484Sobrien		  /* Counting, and didn't match on count; go on to the
19460484Sobrien                     next one.  */
19560484Sobrien		  continue;
19660484Sobrien		}
19760484Sobrien
198130561Sobrien	      found = TRUE;
19933965Sjdp	      function (head);
20033965Sjdp	    }
20133965Sjdp	}
20233965Sjdp      if (!found)
20360484Sobrien	/* xgettext:c-format */
20460484Sobrien	fprintf (stderr, _("no entry %s in archive\n"), *files);
20533965Sjdp    }
20633965Sjdp}
20733965Sjdp
208130561Sobrienbfd_boolean operation_alters_arch = FALSE;
20933965Sjdp
21033965Sjdpstatic void
211130561Sobrienusage (int help)
21233965Sjdp{
21333965Sjdp  FILE *s;
21433965Sjdp
21533965Sjdp  s = help ? stdout : stderr;
216104834Sobrien
21733965Sjdp  if (! is_ranlib)
21860484Sobrien    {
21960484Sobrien      /* xgettext:c-format */
220104834Sobrien      fprintf (s, _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"),
22160484Sobrien	       program_name);
22260484Sobrien      /* xgettext:c-format */
22360484Sobrien      fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
22460484Sobrien      fprintf (s, _(" commands:\n"));
22560484Sobrien      fprintf (s, _("  d            - delete file(s) from the archive\n"));
22660484Sobrien      fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
22760484Sobrien      fprintf (s, _("  p            - print file(s) found in the archive\n"));
22860484Sobrien      fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
22960484Sobrien      fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
23060484Sobrien      fprintf (s, _("  t            - display contents of archive\n"));
23160484Sobrien      fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
23260484Sobrien      fprintf (s, _(" command specific modifiers:\n"));
23360484Sobrien      fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
23460484Sobrien      fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
23560484Sobrien      fprintf (s, _("  [N]          - use instance [count] of name\n"));
23660484Sobrien      fprintf (s, _("  [f]          - truncate inserted file names\n"));
23760484Sobrien      fprintf (s, _("  [P]          - use full path names when matching\n"));
23860484Sobrien      fprintf (s, _("  [o]          - preserve original dates\n"));
23960484Sobrien      fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
24060484Sobrien      fprintf (s, _(" generic modifiers:\n"));
24160484Sobrien      fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
24260484Sobrien      fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
24360484Sobrien      fprintf (s, _("  [S]          - do not build a symbol table\n"));
24460484Sobrien      fprintf (s, _("  [v]          - be verbose\n"));
24560484Sobrien      fprintf (s, _("  [V]          - display the version number\n"));
246218822Sdim      fprintf (s, _("  @<file>      - read options from <file>\n"));
247218822Sdim
248104834Sobrien      ar_emul_usage (s);
24960484Sobrien    }
25033965Sjdp  else
25189857Sobrien    {
252104834Sobrien      /* xgettext:c-format */
25389857Sobrien      fprintf (s, _("Usage: %s [options] archive\n"), program_name);
25489857Sobrien      fprintf (s, _(" Generate an index to speed access to archives\n"));
25589857Sobrien      fprintf (s, _(" The options are:\n\
256218822Sdim  @<file>                      Read options from <file>\n\
25789857Sobrien  -h --help                    Print this help message\n\
25889857Sobrien  -V --version                 Print version information\n"));
25989857Sobrien    }
26033965Sjdp
261218822Sdim  list_supported_targets (program_name, s);
26233965Sjdp
263218822Sdim  if (REPORT_BUGS_TO[0] && help)
26460484Sobrien    fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
26533965Sjdp
26633965Sjdp  xexit (help ? 0 : 1);
26733965Sjdp}
26833965Sjdp
26933965Sjdp/* Normalize a file name specified on the command line into a file
27033965Sjdp   name which we will use in an archive.  */
27133965Sjdp
27233965Sjdpstatic const char *
273130561Sobriennormalize (const char *file, bfd *abfd)
27433965Sjdp{
27533965Sjdp  const char *filename;
27633965Sjdp
27760484Sobrien  if (full_pathname)
27860484Sobrien    return file;
27960484Sobrien
28033965Sjdp  filename = strrchr (file, '/');
28161843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
28261843Sobrien  {
28361843Sobrien    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
28461843Sobrien    char *bslash = strrchr (file, '\\');
28577298Sobrien    if (filename == NULL || (bslash != NULL && bslash > filename))
28661843Sobrien      filename = bslash;
28761843Sobrien    if (filename == NULL && file[0] != '\0' && file[1] == ':')
28877298Sobrien      filename = file + 1;
28961843Sobrien  }
29061843Sobrien#endif
29133965Sjdp  if (filename != (char *) NULL)
29233965Sjdp    filename++;
29333965Sjdp  else
29433965Sjdp    filename = file;
29533965Sjdp
29633965Sjdp  if (ar_truncate
29733965Sjdp      && abfd != NULL
29833965Sjdp      && strlen (filename) > abfd->xvec->ar_max_namelen)
29933965Sjdp    {
30033965Sjdp      char *s;
30133965Sjdp
30233965Sjdp      /* Space leak.  */
30333965Sjdp      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
30433965Sjdp      memcpy (s, filename, abfd->xvec->ar_max_namelen);
30533965Sjdp      s[abfd->xvec->ar_max_namelen] = '\0';
30633965Sjdp      filename = s;
30733965Sjdp    }
30833965Sjdp
30933965Sjdp  return filename;
31033965Sjdp}
31133965Sjdp
31233965Sjdp/* Remove any output file.  This is only called via xatexit.  */
31333965Sjdp
31460484Sobrienstatic const char *output_filename = NULL;
31533965Sjdpstatic FILE *output_file = NULL;
31633965Sjdpstatic bfd *output_bfd = NULL;
31733965Sjdp
31833965Sjdpstatic void
319130561Sobrienremove_output (void)
32033965Sjdp{
32133965Sjdp  if (output_filename != NULL)
32233965Sjdp    {
323130561Sobrien      if (output_bfd != NULL)
324130561Sobrien	bfd_cache_close (output_bfd);
32533965Sjdp      if (output_file != NULL)
32633965Sjdp	fclose (output_file);
327218822Sdim      unlink_if_ordinary (output_filename);
32833965Sjdp    }
32933965Sjdp}
33033965Sjdp
33133965Sjdp/* The option parsing should be in its own function.
33233965Sjdp   It will be when I have getopt working.  */
33333965Sjdp
334130561Sobrienint main (int, char **);
33589857Sobrien
33633965Sjdpint
337130561Sobrienmain (int argc, char **argv)
33833965Sjdp{
33933965Sjdp  char *arg_ptr;
34033965Sjdp  char c;
34133965Sjdp  enum
34233965Sjdp    {
34333965Sjdp      none = 0, delete, replace, print_table,
34433965Sjdp      print_files, extract, move, quick_append
34533965Sjdp    } operation = none;
34633965Sjdp  int arg_index;
34733965Sjdp  char **files;
34860484Sobrien  int file_count;
34933965Sjdp  char *inarch_filename;
35033965Sjdp  int show_version;
351104834Sobrien  int i;
352130561Sobrien  int do_posix = 0;
35333965Sjdp
35460484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
35560484Sobrien  setlocale (LC_MESSAGES, "");
35660484Sobrien#endif
35789857Sobrien#if defined (HAVE_SETLOCALE)
35889857Sobrien  setlocale (LC_CTYPE, "");
35989857Sobrien#endif
36060484Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
36160484Sobrien  textdomain (PACKAGE);
36260484Sobrien
36333965Sjdp  program_name = argv[0];
36433965Sjdp  xmalloc_set_program_name (program_name);
36533965Sjdp
366218822Sdim  expandargv (&argc, &argv);
367218822Sdim
36833965Sjdp  if (is_ranlib < 0)
36933965Sjdp    {
37033965Sjdp      char *temp;
37133965Sjdp
37233965Sjdp      temp = strrchr (program_name, '/');
37361843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
374104834Sobrien      {
375104834Sobrien	/* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
376104834Sobrien	char *bslash = strrchr (program_name, '\\');
377104834Sobrien	if (temp == NULL || (bslash != NULL && bslash > temp))
378104834Sobrien	  temp = bslash;
379104834Sobrien	if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':')
380104834Sobrien	  temp = program_name + 1;
381104834Sobrien      }
38261843Sobrien#endif
38333965Sjdp      if (temp == NULL)
38433965Sjdp	temp = program_name;
38533965Sjdp      else
38633965Sjdp	++temp;
38733965Sjdp      if (strlen (temp) >= 6
38861843Sobrien	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
38933965Sjdp	is_ranlib = 1;
39033965Sjdp      else
39133965Sjdp	is_ranlib = 0;
39233965Sjdp    }
39333965Sjdp
39433965Sjdp  if (argc > 1 && argv[1][0] == '-')
39533965Sjdp    {
39633965Sjdp      if (strcmp (argv[1], "--help") == 0)
39733965Sjdp	usage (1);
39833965Sjdp      else if (strcmp (argv[1], "--version") == 0)
39933965Sjdp	{
40033965Sjdp	  if (is_ranlib)
40133965Sjdp	    print_version ("ranlib");
40233965Sjdp	  else
40333965Sjdp	    print_version ("ar");
40433965Sjdp	}
40533965Sjdp    }
40633965Sjdp
40733965Sjdp  START_PROGRESS (program_name, 0);
40833965Sjdp
40933965Sjdp  bfd_init ();
41033965Sjdp  set_default_bfd_target ();
41133965Sjdp
41233965Sjdp  show_version = 0;
41333965Sjdp
41433965Sjdp  xatexit (remove_output);
41533965Sjdp
416104834Sobrien  for (i = 1; i < argc; i++)
417104834Sobrien    if (! ar_emul_parse_arg (argv[i]))
418104834Sobrien      break;
419104834Sobrien  argv += (i - 1);
420104834Sobrien  argc -= (i - 1);
42177298Sobrien
42233965Sjdp  if (is_ranlib)
42333965Sjdp    {
424218822Sdim      int status = 0;
425130561Sobrien      bfd_boolean touch = FALSE;
42633965Sjdp
42789857Sobrien      if (argc < 2
42889857Sobrien	  || strcmp (argv[1], "--help") == 0
42989857Sobrien	  || strcmp (argv[1], "-h") == 0
43089857Sobrien	  || strcmp (argv[1], "-H") == 0)
43133965Sjdp	usage (0);
43233965Sjdp      if (strcmp (argv[1], "-V") == 0
43333965Sjdp	  || strcmp (argv[1], "-v") == 0
434218822Sdim	  || CONST_STRNEQ (argv[1], "--v"))
43533965Sjdp	print_version ("ranlib");
43633965Sjdp      arg_index = 1;
43733965Sjdp      if (strcmp (argv[1], "-t") == 0)
43833965Sjdp	{
43933965Sjdp	  ++arg_index;
440130561Sobrien	  touch = TRUE;
44133965Sjdp	}
44233965Sjdp      while (arg_index < argc)
44333965Sjdp	{
44433965Sjdp	  if (! touch)
445218822Sdim	    status |= ranlib_only (argv[arg_index]);
44633965Sjdp	  else
447218822Sdim	    status |= ranlib_touch (argv[arg_index]);
44833965Sjdp	  ++arg_index;
44933965Sjdp	}
450218822Sdim      xexit (status);
45133965Sjdp    }
45233965Sjdp
45333965Sjdp  if (argc == 2 && strcmp (argv[1], "-M") == 0)
45433965Sjdp    {
45533965Sjdp      mri_emul ();
45633965Sjdp      xexit (0);
45733965Sjdp    }
45833965Sjdp
45933965Sjdp  if (argc < 2)
46033965Sjdp    usage (0);
46133965Sjdp
462130561Sobrien  arg_index = 1;
463130561Sobrien  arg_ptr = argv[arg_index];
46433965Sjdp
46533965Sjdp  if (*arg_ptr == '-')
466130561Sobrien    {
467130561Sobrien      /* When the first option starts with '-' we support POSIX-compatible
468130561Sobrien	 option parsing.  */
469130561Sobrien      do_posix = 1;
470130561Sobrien      ++arg_ptr;			/* compatibility */
471130561Sobrien    }
47233965Sjdp
473130561Sobrien  do
47433965Sjdp    {
475130561Sobrien      while ((c = *arg_ptr++) != '\0')
47633965Sjdp	{
47733965Sjdp	  switch (c)
47833965Sjdp	    {
47933965Sjdp	    case 'd':
48033965Sjdp	    case 'm':
48133965Sjdp	    case 'p':
48233965Sjdp	    case 'q':
48333965Sjdp	    case 'r':
48433965Sjdp	    case 't':
48533965Sjdp	    case 'x':
486130561Sobrien	      if (operation != none)
487130561Sobrien		fatal (_("two different operation options specified"));
488130561Sobrien	      switch (c)
489130561Sobrien		{
490130561Sobrien		case 'd':
491130561Sobrien		  operation = delete;
492130561Sobrien		  operation_alters_arch = TRUE;
493130561Sobrien		  break;
494130561Sobrien		case 'm':
495130561Sobrien		  operation = move;
496130561Sobrien		  operation_alters_arch = TRUE;
497130561Sobrien		  break;
498130561Sobrien		case 'p':
499130561Sobrien		  operation = print_files;
500130561Sobrien		  break;
501130561Sobrien		case 'q':
502130561Sobrien		  operation = quick_append;
503130561Sobrien		  operation_alters_arch = TRUE;
504130561Sobrien		  break;
505130561Sobrien		case 'r':
506130561Sobrien		  operation = replace;
507130561Sobrien		  operation_alters_arch = TRUE;
508130561Sobrien		  break;
509130561Sobrien		case 't':
510130561Sobrien		  operation = print_table;
511130561Sobrien		  break;
512130561Sobrien		case 'x':
513130561Sobrien		  operation = extract;
514130561Sobrien		  break;
515130561Sobrien		}
516130561Sobrien	    case 'l':
51733965Sjdp	      break;
518130561Sobrien	    case 'c':
519130561Sobrien	      silent_create = 1;
520130561Sobrien	      break;
521130561Sobrien	    case 'o':
522130561Sobrien	      preserve_dates = 1;
523130561Sobrien	      break;
524130561Sobrien	    case 'V':
525130561Sobrien	      show_version = TRUE;
526130561Sobrien	      break;
527130561Sobrien	    case 's':
528130561Sobrien	      write_armap = 1;
529130561Sobrien	      break;
530130561Sobrien	    case 'S':
531130561Sobrien	      write_armap = -1;
532130561Sobrien	      break;
533130561Sobrien	    case 'u':
534130561Sobrien	      newer_only = 1;
535130561Sobrien	      break;
536130561Sobrien	    case 'v':
537130561Sobrien	      verbose = 1;
538130561Sobrien	      break;
539130561Sobrien	    case 'a':
540130561Sobrien	      postype = pos_after;
541130561Sobrien	      break;
542130561Sobrien	    case 'b':
543130561Sobrien	      postype = pos_before;
544130561Sobrien	      break;
545130561Sobrien	    case 'i':
546130561Sobrien	      postype = pos_before;
547130561Sobrien	      break;
548130561Sobrien	    case 'M':
549130561Sobrien	      mri_mode = 1;
550130561Sobrien	      break;
551130561Sobrien	    case 'N':
552130561Sobrien	      counted_name_mode = TRUE;
553130561Sobrien	      break;
554130561Sobrien	    case 'f':
555130561Sobrien	      ar_truncate = TRUE;
556130561Sobrien	      break;
557130561Sobrien	    case 'P':
558130561Sobrien	      full_pathname = TRUE;
559130561Sobrien	      break;
560130561Sobrien	    default:
561130561Sobrien	      /* xgettext:c-format */
562130561Sobrien	      non_fatal (_("illegal option -- %c"), c);
563130561Sobrien	      usage (0);
56433965Sjdp	    }
56533965Sjdp	}
566130561Sobrien
567130561Sobrien      /* With POSIX-compatible option parsing continue with the next
568130561Sobrien	 argument if it starts with '-'.  */
569130561Sobrien      if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-')
570130561Sobrien	arg_ptr = argv[++arg_index] + 1;
571130561Sobrien      else
572130561Sobrien	do_posix = 0;
57333965Sjdp    }
574130561Sobrien  while (do_posix);
57533965Sjdp
57633965Sjdp  if (show_version)
57733965Sjdp    print_version ("ar");
57833965Sjdp
579130561Sobrien  ++arg_index;
580130561Sobrien  if (arg_index >= argc)
58133965Sjdp    usage (0);
58233965Sjdp
58333965Sjdp  if (mri_mode)
58433965Sjdp    {
58533965Sjdp      mri_emul ();
58633965Sjdp    }
58733965Sjdp  else
58833965Sjdp    {
58933965Sjdp      bfd *arch;
59033965Sjdp
591218822Sdim      /* We don't use do_quick_append any more.  Too many systems
592218822Sdim	 expect ar to always rebuild the symbol table even when q is
593218822Sdim	 used.  */
594218822Sdim
59533965Sjdp      /* We can't write an armap when using ar q, so just do ar r
59633965Sjdp         instead.  */
59733965Sjdp      if (operation == quick_append && write_armap)
59833965Sjdp	operation = replace;
59933965Sjdp
60033965Sjdp      if ((operation == none || operation == print_table)
60133965Sjdp	  && write_armap == 1)
602218822Sdim	xexit (ranlib_only (argv[arg_index]));
60333965Sjdp
60433965Sjdp      if (operation == none)
60560484Sobrien	fatal (_("no operation specified"));
60633965Sjdp
60733965Sjdp      if (newer_only && operation != replace)
60860484Sobrien	fatal (_("`u' is only meaningful with the `r' option."));
60933965Sjdp
61033965Sjdp      if (postype != pos_default)
61133965Sjdp	posname = argv[arg_index++];
61233965Sjdp
613104834Sobrien      if (counted_name_mode)
61460484Sobrien	{
615104834Sobrien	  if (operation != extract && operation != delete)
61660484Sobrien	     fatal (_("`N' is only meaningful with the `x' and `d' options."));
61760484Sobrien	  counted_name_counter = atoi (argv[arg_index++]);
618104834Sobrien	  if (counted_name_counter <= 0)
61960484Sobrien	    fatal (_("Value for `N' must be positive."));
62060484Sobrien	}
62160484Sobrien
62233965Sjdp      inarch_filename = argv[arg_index++];
62333965Sjdp
62433965Sjdp      files = arg_index < argc ? argv + arg_index : NULL;
62560484Sobrien      file_count = argc - arg_index;
62633965Sjdp
62733965Sjdp      arch = open_inarch (inarch_filename,
62833965Sjdp			  files == NULL ? (char *) NULL : files[0]);
62933965Sjdp
63033965Sjdp      switch (operation)
63133965Sjdp	{
63233965Sjdp	case print_table:
63360484Sobrien	  map_over_members (arch, print_descr, files, file_count);
63433965Sjdp	  break;
63533965Sjdp
63633965Sjdp	case print_files:
63760484Sobrien	  map_over_members (arch, print_contents, files, file_count);
63833965Sjdp	  break;
63933965Sjdp
64033965Sjdp	case extract:
64160484Sobrien	  map_over_members (arch, extract_file, files, file_count);
64233965Sjdp	  break;
64333965Sjdp
64433965Sjdp	case delete:
64533965Sjdp	  if (files != NULL)
64633965Sjdp	    delete_members (arch, files);
64760484Sobrien	  else
64860484Sobrien	    output_filename = NULL;
64933965Sjdp	  break;
65033965Sjdp
65133965Sjdp	case move:
65233965Sjdp	  if (files != NULL)
65333965Sjdp	    move_members (arch, files);
65460484Sobrien	  else
65560484Sobrien	    output_filename = NULL;
65633965Sjdp	  break;
65733965Sjdp
65833965Sjdp	case replace:
65933965Sjdp	case quick_append:
66033965Sjdp	  if (files != NULL || write_armap > 0)
66133965Sjdp	    replace_members (arch, files, operation == quick_append);
66260484Sobrien	  else
66360484Sobrien	    output_filename = NULL;
66433965Sjdp	  break;
66533965Sjdp
66633965Sjdp	  /* Shouldn't happen! */
66733965Sjdp	default:
66860484Sobrien	  /* xgettext:c-format */
66960484Sobrien	  fatal (_("internal error -- this option not implemented"));
67033965Sjdp	}
67133965Sjdp    }
67233965Sjdp
67333965Sjdp  END_PROGRESS (program_name);
67433965Sjdp
67533965Sjdp  xexit (0);
67633965Sjdp  return 0;
67733965Sjdp}
67833965Sjdp
67933965Sjdpbfd *
680130561Sobrienopen_inarch (const char *archive_filename, const char *file)
68133965Sjdp{
68233965Sjdp  const char *target;
68333965Sjdp  bfd **last_one;
68433965Sjdp  bfd *next_one;
68533965Sjdp  struct stat sbuf;
68633965Sjdp  bfd *arch;
68733965Sjdp  char **matching;
68833965Sjdp
68933965Sjdp  bfd_set_error (bfd_error_no_error);
69033965Sjdp
69133965Sjdp  target = NULL;
69233965Sjdp
69333965Sjdp  if (stat (archive_filename, &sbuf) != 0)
69433965Sjdp    {
69561843Sobrien#if !defined(__GO32__) || defined(__DJGPP__)
69633965Sjdp
69761843Sobrien      /* FIXME: I don't understand why this fragment was ifndef'ed
69861843Sobrien	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
69961843Sobrien	 stat() works just fine in v2.x, so I think this should be
70061843Sobrien	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
70161843Sobrien
70233965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why
70361843Sobrien   stat() is wrong ... think it's buried in GO32's IDT - Jax */
70433965Sjdp      if (errno != ENOENT)
70533965Sjdp	bfd_fatal (archive_filename);
70633965Sjdp#endif
70733965Sjdp
70833965Sjdp      if (!operation_alters_arch)
70933965Sjdp	{
71033965Sjdp	  fprintf (stderr, "%s: ", program_name);
71133965Sjdp	  perror (archive_filename);
71233965Sjdp	  maybequit ();
71333965Sjdp	  return NULL;
71433965Sjdp	}
71533965Sjdp
71633965Sjdp      /* Try to figure out the target to use for the archive from the
71733965Sjdp         first object on the list.  */
71833965Sjdp      if (file != NULL)
71933965Sjdp	{
72033965Sjdp	  bfd *obj;
72133965Sjdp
72233965Sjdp	  obj = bfd_openr (file, NULL);
72333965Sjdp	  if (obj != NULL)
72433965Sjdp	    {
72533965Sjdp	      if (bfd_check_format (obj, bfd_object))
72633965Sjdp		target = bfd_get_target (obj);
72733965Sjdp	      (void) bfd_close (obj);
72833965Sjdp	    }
72933965Sjdp	}
73033965Sjdp
73133965Sjdp      /* Create an empty archive.  */
73233965Sjdp      arch = bfd_openw (archive_filename, target);
73333965Sjdp      if (arch == NULL
73433965Sjdp	  || ! bfd_set_format (arch, bfd_archive)
73533965Sjdp	  || ! bfd_close (arch))
73633965Sjdp	bfd_fatal (archive_filename);
737130561Sobrien      else if (!silent_create)
738130561Sobrien        non_fatal (_("creating %s"), archive_filename);
73960484Sobrien
74060484Sobrien      /* If we die creating a new archive, don't leave it around.  */
74160484Sobrien      output_filename = archive_filename;
74233965Sjdp    }
74333965Sjdp
74433965Sjdp  arch = bfd_openr (archive_filename, target);
74533965Sjdp  if (arch == NULL)
74633965Sjdp    {
74733965Sjdp    bloser:
74833965Sjdp      bfd_fatal (archive_filename);
74933965Sjdp    }
75033965Sjdp
75133965Sjdp  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
75233965Sjdp    {
75333965Sjdp      bfd_nonfatal (archive_filename);
75433965Sjdp      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
75533965Sjdp	{
75633965Sjdp	  list_matching_formats (matching);
75733965Sjdp	  free (matching);
75833965Sjdp	}
75933965Sjdp      xexit (1);
76033965Sjdp    }
76133965Sjdp
762218822Sdim  last_one = &(arch->archive_next);
76333965Sjdp  /* Read all the contents right away, regardless.  */
76433965Sjdp  for (next_one = bfd_openr_next_archived_file (arch, NULL);
76533965Sjdp       next_one;
76633965Sjdp       next_one = bfd_openr_next_archived_file (arch, next_one))
76733965Sjdp    {
76833965Sjdp      PROGRESS (1);
76933965Sjdp      *last_one = next_one;
770218822Sdim      last_one = &next_one->archive_next;
77133965Sjdp    }
77233965Sjdp  *last_one = (bfd *) NULL;
77333965Sjdp  if (bfd_get_error () != bfd_error_no_more_archived_files)
77433965Sjdp    goto bloser;
77533965Sjdp  return arch;
77633965Sjdp}
77733965Sjdp
77833965Sjdpstatic void
779130561Sobrienprint_contents (bfd *abfd)
78033965Sjdp{
781218822Sdim  size_t ncopied = 0;
78233965Sjdp  char *cbuf = xmalloc (BUFSIZE);
78333965Sjdp  struct stat buf;
784218822Sdim  size_t size;
78533965Sjdp  if (bfd_stat_arch_elt (abfd, &buf) != 0)
78660484Sobrien    /* xgettext:c-format */
78760484Sobrien    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
78833965Sjdp
78933965Sjdp  if (verbose)
79077298Sobrien    /* xgettext:c-format */
791130561Sobrien    printf (_("\n<%s>\n\n"), bfd_get_filename (abfd));
79233965Sjdp
79389857Sobrien  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
79433965Sjdp
79533965Sjdp  size = buf.st_size;
79633965Sjdp  while (ncopied < size)
79733965Sjdp    {
79833965Sjdp
799218822Sdim      size_t nread;
800218822Sdim      size_t tocopy = size - ncopied;
80133965Sjdp      if (tocopy > BUFSIZE)
80233965Sjdp	tocopy = BUFSIZE;
80333965Sjdp
80489857Sobrien      nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
80533965Sjdp      if (nread != tocopy)
80660484Sobrien	/* xgettext:c-format */
80760484Sobrien	fatal (_("%s is not a valid archive"),
80833965Sjdp	       bfd_get_filename (bfd_my_archive (abfd)));
809218822Sdim
810218822Sdim      /* fwrite in mingw32 may return int instead of size_t. Cast the
811218822Sdim	 return value to size_t to avoid comparison between signed and
812218822Sdim	 unsigned values.  */
813218822Sdim      if ((size_t) fwrite (cbuf, 1, nread, stdout) != nread)
814218822Sdim	fatal ("stdout: %s", strerror (errno));
81533965Sjdp      ncopied += tocopy;
81633965Sjdp    }
81733965Sjdp  free (cbuf);
81833965Sjdp}
81933965Sjdp
82033965Sjdp/* Extract a member of the archive into its own file.
82133965Sjdp
82233965Sjdp   We defer opening the new file until after we have read a BUFSIZ chunk of the
82333965Sjdp   old one, since we know we have just read the archive header for the old
82433965Sjdp   one.  Since most members are shorter than BUFSIZ, this means we will read
82533965Sjdp   the old header, read the old data, write a new inode for the new file, and
82633965Sjdp   write the new data, and be done. This 'optimization' is what comes from
82733965Sjdp   sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
82833965Sjdp   Gilmore  */
82933965Sjdp
83033965Sjdpvoid
831130561Sobrienextract_file (bfd *abfd)
83233965Sjdp{
83333965Sjdp  FILE *ostream;
83433965Sjdp  char *cbuf = xmalloc (BUFSIZE);
835218822Sdim  size_t nread, tocopy;
836218822Sdim  size_t ncopied = 0;
837218822Sdim  size_t size;
83833965Sjdp  struct stat buf;
839104834Sobrien
84033965Sjdp  if (bfd_stat_arch_elt (abfd, &buf) != 0)
84160484Sobrien    /* xgettext:c-format */
84260484Sobrien    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
84333965Sjdp  size = buf.st_size;
84433965Sjdp
84533965Sjdp  if (verbose)
84633965Sjdp    printf ("x - %s\n", bfd_get_filename (abfd));
84733965Sjdp
84889857Sobrien  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
84933965Sjdp
85060484Sobrien  ostream = NULL;
85133965Sjdp  if (size == 0)
85233965Sjdp    {
85333965Sjdp      /* Seems like an abstraction violation, eh?  Well it's OK! */
85433965Sjdp      output_filename = bfd_get_filename (abfd);
85533965Sjdp
85633965Sjdp      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
85760484Sobrien      if (ostream == NULL)
85833965Sjdp	{
85933965Sjdp	  perror (bfd_get_filename (abfd));
86033965Sjdp	  xexit (1);
86133965Sjdp	}
86233965Sjdp
86333965Sjdp      output_file = ostream;
86433965Sjdp    }
86533965Sjdp  else
86633965Sjdp    while (ncopied < size)
86733965Sjdp      {
86833965Sjdp	tocopy = size - ncopied;
86933965Sjdp	if (tocopy > BUFSIZE)
87033965Sjdp	  tocopy = BUFSIZE;
87133965Sjdp
87289857Sobrien	nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
87333965Sjdp	if (nread != tocopy)
87460484Sobrien	  /* xgettext:c-format */
87560484Sobrien	  fatal (_("%s is not a valid archive"),
87633965Sjdp		 bfd_get_filename (bfd_my_archive (abfd)));
87733965Sjdp
87833965Sjdp	/* See comment above; this saves disk arm motion */
87960484Sobrien	if (ostream == NULL)
88033965Sjdp	  {
88133965Sjdp	    /* Seems like an abstraction violation, eh?  Well it's OK! */
88233965Sjdp	    output_filename = bfd_get_filename (abfd);
88333965Sjdp
88433965Sjdp	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
88560484Sobrien	    if (ostream == NULL)
88633965Sjdp	      {
88733965Sjdp		perror (bfd_get_filename (abfd));
88833965Sjdp		xexit (1);
88933965Sjdp	      }
89033965Sjdp
89133965Sjdp	    output_file = ostream;
89233965Sjdp	  }
893218822Sdim
894218822Sdim	/* fwrite in mingw32 may return int instead of size_t. Cast
895218822Sdim	   the return value to size_t to avoid comparison between
896218822Sdim	   signed and unsigned values.  */
897218822Sdim	if ((size_t) fwrite (cbuf, 1, nread, ostream) != nread)
898218822Sdim	  fatal ("%s: %s", output_filename, strerror (errno));
89933965Sjdp	ncopied += tocopy;
90033965Sjdp      }
90133965Sjdp
90260484Sobrien  if (ostream != NULL)
90360484Sobrien    fclose (ostream);
90433965Sjdp
90533965Sjdp  output_file = NULL;
90633965Sjdp  output_filename = NULL;
90733965Sjdp
90833965Sjdp  chmod (bfd_get_filename (abfd), buf.st_mode);
90933965Sjdp
91033965Sjdp  if (preserve_dates)
91133965Sjdp    {
912218822Sdim      /* Set access time to modification time.  Only st_mtime is
913218822Sdim	 initialized by bfd_stat_arch_elt.  */
914218822Sdim      buf.st_atime = buf.st_mtime;
915218822Sdim      set_times (bfd_get_filename (abfd), &buf);
91633965Sjdp    }
91733965Sjdp
918218822Sdim  free (cbuf);
91933965Sjdp}
92033965Sjdp
92133965Sjdpstatic void
922130561Sobrienwrite_archive (bfd *iarch)
92333965Sjdp{
92433965Sjdp  bfd *obfd;
92533965Sjdp  char *old_name, *new_name;
926218822Sdim  bfd *contents_head = iarch->archive_next;
92733965Sjdp
92833965Sjdp  old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
92933965Sjdp  strcpy (old_name, bfd_get_filename (iarch));
93033965Sjdp  new_name = make_tempname (old_name);
93133965Sjdp
932218822Sdim  if (new_name == NULL)
933218822Sdim    bfd_fatal ("could not create temporary file whilst writing archive");
934218822Sdim
93533965Sjdp  output_filename = new_name;
93633965Sjdp
93733965Sjdp  obfd = bfd_openw (new_name, bfd_get_target (iarch));
93833965Sjdp
93933965Sjdp  if (obfd == NULL)
94033965Sjdp    bfd_fatal (old_name);
94133965Sjdp
94233965Sjdp  output_bfd = obfd;
94333965Sjdp
94433965Sjdp  bfd_set_format (obfd, bfd_archive);
94533965Sjdp
94633965Sjdp  /* Request writing the archive symbol table unless we've
94733965Sjdp     been explicitly requested not to.  */
94833965Sjdp  obfd->has_armap = write_armap >= 0;
94933965Sjdp
95033965Sjdp  if (ar_truncate)
95133965Sjdp    {
95233965Sjdp      /* This should really use bfd_set_file_flags, but that rejects
95333965Sjdp         archives.  */
95433965Sjdp      obfd->flags |= BFD_TRADITIONAL_FORMAT;
95533965Sjdp    }
95633965Sjdp
957130561Sobrien  if (!bfd_set_archive_head (obfd, contents_head))
95833965Sjdp    bfd_fatal (old_name);
95933965Sjdp
96033965Sjdp  if (!bfd_close (obfd))
96133965Sjdp    bfd_fatal (old_name);
96233965Sjdp
96333965Sjdp  output_bfd = NULL;
96433965Sjdp  output_filename = NULL;
96533965Sjdp
96633965Sjdp  /* We don't care if this fails; we might be creating the archive.  */
96733965Sjdp  bfd_close (iarch);
96833965Sjdp
96960484Sobrien  if (smart_rename (new_name, old_name, 0) != 0)
97060484Sobrien    xexit (1);
97133965Sjdp}
97233965Sjdp
97333965Sjdp/* Return a pointer to the pointer to the entry which should be rplacd'd
97433965Sjdp   into when altering.  DEFAULT_POS should be how to interpret pos_default,
97533965Sjdp   and should be a pos value.  */
97633965Sjdp
97733965Sjdpstatic bfd **
978130561Sobrienget_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
97933965Sjdp{
98033965Sjdp  bfd **after_bfd = contents;
98138889Sjdp  enum pos realpos;
98238889Sjdp  const char *realposname;
98333965Sjdp
98438889Sjdp  if (postype == pos_default)
98538889Sjdp    {
98638889Sjdp      realpos = default_pos;
98738889Sjdp      realposname = default_posname;
98838889Sjdp    }
98938889Sjdp  else
99038889Sjdp    {
99138889Sjdp      realpos = postype;
99238889Sjdp      realposname = posname;
99338889Sjdp    }
99438889Sjdp
99533965Sjdp  if (realpos == pos_end)
99633965Sjdp    {
99733965Sjdp      while (*after_bfd)
998218822Sdim	after_bfd = &((*after_bfd)->archive_next);
99933965Sjdp    }
100033965Sjdp  else
100133965Sjdp    {
1002218822Sdim      for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next)
100361843Sobrien	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
100433965Sjdp	  {
100533965Sjdp	    if (realpos == pos_after)
1006218822Sdim	      after_bfd = &(*after_bfd)->archive_next;
100733965Sjdp	    break;
100833965Sjdp	  }
100933965Sjdp    }
101033965Sjdp  return after_bfd;
101133965Sjdp}
101233965Sjdp
101333965Sjdpstatic void
1014130561Sobriendelete_members (bfd *arch, char **files_to_delete)
101533965Sjdp{
101633965Sjdp  bfd **current_ptr_ptr;
1017130561Sobrien  bfd_boolean found;
1018130561Sobrien  bfd_boolean something_changed = FALSE;
101960484Sobrien  int match_count;
102060484Sobrien
102133965Sjdp  for (; *files_to_delete != NULL; ++files_to_delete)
102233965Sjdp    {
102333965Sjdp      /* In a.out systems, the armap is optional.  It's also called
102433965Sjdp	 __.SYMDEF.  So if the user asked to delete it, we should remember
102533965Sjdp	 that fact. This isn't quite right for COFF systems (where
102633965Sjdp	 __.SYMDEF might be regular member), but it's very unlikely
102733965Sjdp	 to be a problem.  FIXME */
102833965Sjdp
102933965Sjdp      if (!strcmp (*files_to_delete, "__.SYMDEF"))
103033965Sjdp	{
1031130561Sobrien	  arch->has_armap = FALSE;
103233965Sjdp	  write_armap = -1;
103333965Sjdp	  continue;
103433965Sjdp	}
103533965Sjdp
1036130561Sobrien      found = FALSE;
103760484Sobrien      match_count = 0;
1038218822Sdim      current_ptr_ptr = &(arch->archive_next);
103933965Sjdp      while (*current_ptr_ptr)
104033965Sjdp	{
104161843Sobrien	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
1042104834Sobrien			    (*current_ptr_ptr)->filename) == 0)
104333965Sjdp	    {
104460484Sobrien	      ++match_count;
104560484Sobrien	      if (counted_name_mode
1046104834Sobrien		  && match_count != counted_name_counter)
104760484Sobrien		{
104860484Sobrien		  /* Counting, and didn't match on count; go on to the
104960484Sobrien                     next one.  */
105060484Sobrien		}
105160484Sobrien	      else
105260484Sobrien		{
1053130561Sobrien		  found = TRUE;
1054130561Sobrien		  something_changed = TRUE;
105560484Sobrien		  if (verbose)
105660484Sobrien		    printf ("d - %s\n",
105760484Sobrien			    *files_to_delete);
1058218822Sdim		  *current_ptr_ptr = ((*current_ptr_ptr)->archive_next);
105960484Sobrien		  goto next_file;
106060484Sobrien		}
106133965Sjdp	    }
106260484Sobrien
1063218822Sdim	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
106433965Sjdp	}
106533965Sjdp
1066130561Sobrien      if (verbose && !found)
106733965Sjdp	{
106860484Sobrien	  /* xgettext:c-format */
106960484Sobrien	  printf (_("No member named `%s'\n"), *files_to_delete);
107033965Sjdp	}
107133965Sjdp    next_file:
107233965Sjdp      ;
107333965Sjdp    }
107433965Sjdp
1075130561Sobrien  if (something_changed)
107660484Sobrien    write_archive (arch);
107760484Sobrien  else
107860484Sobrien    output_filename = NULL;
107933965Sjdp}
108033965Sjdp
108133965Sjdp
108233965Sjdp/* Reposition existing members within an archive */
108333965Sjdp
108433965Sjdpstatic void
1085130561Sobrienmove_members (bfd *arch, char **files_to_move)
108633965Sjdp{
108733965Sjdp  bfd **after_bfd;		/* New entries go after this one */
108833965Sjdp  bfd **current_ptr_ptr;	/* cdr pointer into contents */
108933965Sjdp
109033965Sjdp  for (; *files_to_move; ++files_to_move)
109133965Sjdp    {
1092218822Sdim      current_ptr_ptr = &(arch->archive_next);
109333965Sjdp      while (*current_ptr_ptr)
109433965Sjdp	{
109533965Sjdp	  bfd *current_ptr = *current_ptr_ptr;
109661843Sobrien	  if (FILENAME_CMP (normalize (*files_to_move, arch),
109761843Sobrien			    current_ptr->filename) == 0)
109833965Sjdp	    {
109933965Sjdp	      /* Move this file to the end of the list - first cut from
110033965Sjdp		 where it is.  */
110133965Sjdp	      bfd *link;
1102218822Sdim	      *current_ptr_ptr = current_ptr->archive_next;
110333965Sjdp
110433965Sjdp	      /* Now glue to end */
1105218822Sdim	      after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
110633965Sjdp	      link = *after_bfd;
110733965Sjdp	      *after_bfd = current_ptr;
1108218822Sdim	      current_ptr->archive_next = link;
110933965Sjdp
111033965Sjdp	      if (verbose)
111133965Sjdp		printf ("m - %s\n", *files_to_move);
111233965Sjdp
111333965Sjdp	      goto next_file;
111433965Sjdp	    }
111533965Sjdp
1116218822Sdim	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
111733965Sjdp	}
111860484Sobrien      /* xgettext:c-format */
111960484Sobrien      fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
112060484Sobrien
112133965Sjdp    next_file:;
112233965Sjdp    }
112333965Sjdp
112433965Sjdp  write_archive (arch);
112533965Sjdp}
112633965Sjdp
112733965Sjdp/* Ought to default to replacing in place, but this is existing practice!  */
112833965Sjdp
112933965Sjdpstatic void
1130130561Sobrienreplace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
113133965Sjdp{
1132130561Sobrien  bfd_boolean changed = FALSE;
1133218822Sdim  bfd **after_bfd;		/* New entries go after this one.  */
113433965Sjdp  bfd *current;
113533965Sjdp  bfd **current_ptr;
113633965Sjdp
113733965Sjdp  while (files_to_move && *files_to_move)
113833965Sjdp    {
113933965Sjdp      if (! quick)
114033965Sjdp	{
1141218822Sdim	  current_ptr = &arch->archive_next;
114233965Sjdp	  while (*current_ptr)
114333965Sjdp	    {
114433965Sjdp	      current = *current_ptr;
114533965Sjdp
114633965Sjdp	      /* For compatibility with existing ar programs, we
114733965Sjdp		 permit the same file to be added multiple times.  */
114861843Sobrien	      if (FILENAME_CMP (normalize (*files_to_move, arch),
114961843Sobrien				normalize (current->filename, arch)) == 0
115033965Sjdp		  && current->arelt_data != NULL)
115133965Sjdp		{
115233965Sjdp		  if (newer_only)
115333965Sjdp		    {
115433965Sjdp		      struct stat fsbuf, asbuf;
115533965Sjdp
115633965Sjdp		      if (stat (*files_to_move, &fsbuf) != 0)
115733965Sjdp			{
115833965Sjdp			  if (errno != ENOENT)
115933965Sjdp			    bfd_fatal (*files_to_move);
116033965Sjdp			  goto next_file;
116133965Sjdp			}
116233965Sjdp		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
116360484Sobrien			/* xgettext:c-format */
1164104834Sobrien			fatal (_("internal stat error on %s"),
1165104834Sobrien			       current->filename);
116633965Sjdp
116733965Sjdp		      if (fsbuf.st_mtime <= asbuf.st_mtime)
116833965Sjdp			goto next_file;
116933965Sjdp		    }
117033965Sjdp
1171218822Sdim		  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
117238889Sjdp					   current->filename);
1173104834Sobrien		  if (ar_emul_replace (after_bfd, *files_to_move,
1174104834Sobrien				       verbose))
117533965Sjdp		    {
1176104834Sobrien		      /* Snip out this entry from the chain.  */
1177218822Sdim		      *current_ptr = (*current_ptr)->archive_next;
1178130561Sobrien		      changed = TRUE;
117933965Sjdp		    }
118033965Sjdp
118133965Sjdp		  goto next_file;
118233965Sjdp		}
1183218822Sdim	      current_ptr = &(current->archive_next);
118433965Sjdp	    }
118533965Sjdp	}
118633965Sjdp
118733965Sjdp      /* Add to the end of the archive.  */
1188218822Sdim      after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
118933965Sjdp
1190218822Sdim      if (ar_emul_append (after_bfd, *files_to_move, verbose))
1191130561Sobrien	changed = TRUE;
1192130561Sobrien
119333965Sjdp    next_file:;
119433965Sjdp
119533965Sjdp      files_to_move++;
119633965Sjdp    }
119733965Sjdp
119833965Sjdp  if (changed)
119933965Sjdp    write_archive (arch);
120060484Sobrien  else
120160484Sobrien    output_filename = NULL;
120233965Sjdp}
120333965Sjdp
1204218822Sdimstatic int
1205130561Sobrienranlib_only (const char *archname)
120633965Sjdp{
120733965Sjdp  bfd *arch;
120833965Sjdp
1209130561Sobrien  if (get_file_size (archname) < 1)
1210218822Sdim    return 1;
121133965Sjdp  write_armap = 1;
121233965Sjdp  arch = open_inarch (archname, (char *) NULL);
121333965Sjdp  if (arch == NULL)
121433965Sjdp    xexit (1);
121533965Sjdp  write_archive (arch);
1216218822Sdim  return 0;
121733965Sjdp}
121833965Sjdp
121933965Sjdp/* Update the timestamp of the symbol map of an archive.  */
122033965Sjdp
1221218822Sdimstatic int
1222130561Sobrienranlib_touch (const char *archname)
122333965Sjdp{
122433965Sjdp#ifdef __GO32__
122533965Sjdp  /* I don't think updating works on go32.  */
122633965Sjdp  ranlib_only (archname);
122733965Sjdp#else
122833965Sjdp  int f;
122933965Sjdp  bfd *arch;
123033965Sjdp  char **matching;
123133965Sjdp
1232130561Sobrien  if (get_file_size (archname) < 1)
1233218822Sdim    return 1;
123460484Sobrien  f = open (archname, O_RDWR | O_BINARY, 0);
123533965Sjdp  if (f < 0)
123633965Sjdp    {
123733965Sjdp      bfd_set_error (bfd_error_system_call);
123833965Sjdp      bfd_fatal (archname);
123933965Sjdp    }
124033965Sjdp
124133965Sjdp  arch = bfd_fdopenr (archname, (const char *) NULL, f);
124233965Sjdp  if (arch == NULL)
124333965Sjdp    bfd_fatal (archname);
124433965Sjdp  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
124533965Sjdp    {
124633965Sjdp      bfd_nonfatal (archname);
124733965Sjdp      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
124833965Sjdp	{
124933965Sjdp	  list_matching_formats (matching);
125033965Sjdp	  free (matching);
125133965Sjdp	}
125233965Sjdp      xexit (1);
125333965Sjdp    }
125433965Sjdp
125533965Sjdp  if (! bfd_has_map (arch))
125660484Sobrien    /* xgettext:c-format */
125760484Sobrien    fatal (_("%s: no archive map to update"), archname);
125833965Sjdp
125933965Sjdp  bfd_update_armap_timestamp (arch);
126033965Sjdp
126133965Sjdp  if (! bfd_close (arch))
126233965Sjdp    bfd_fatal (archname);
126333965Sjdp#endif
1264218822Sdim  return 0;
126533965Sjdp}
126633965Sjdp
126733965Sjdp/* Things which are interesting to map over all or some of the files: */
126833965Sjdp
126933965Sjdpstatic void
1270130561Sobrienprint_descr (bfd *abfd)
127133965Sjdp{
127233965Sjdp  print_arelt_descr (stdout, abfd, verbose);
127333965Sjdp}
1274