ar.c revision 77298
133965Sjdp/* ar.c - Archive modify and extract.
260484Sobrien   Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000
360484Sobrien   Free Software Foundation, Inc.
433965Sjdp
533965SjdpThis file is part of GNU Binutils.
633965Sjdp
733965SjdpThis program is free software; you can redistribute it and/or modify
833965Sjdpit under the terms of the GNU General Public License as published by
933965Sjdpthe Free Software Foundation; either version 2 of the License, or
1033965Sjdp(at your option) any later version.
1133965Sjdp
1233965SjdpThis program is distributed in the hope that it will be useful,
1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1533965SjdpGNU General Public License for more details.
1633965Sjdp
1733965SjdpYou should have received a copy of the GNU General Public License
1833965Sjdpalong with this program; if not, write to the Free Software
1933965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2033965Sjdp
2133965Sjdp/*
2233965Sjdp   Bugs: should use getopt the way tar does (complete w/optional -) and
2333965Sjdp   should have long options too. GNU ar used to check file against filesystem
2433965Sjdp   in quick_update and replace operations (would check mtime). Doesn't warn
2533965Sjdp   when name truncated. No way to specify pos_end. Error messages should be
2633965Sjdp   more consistant.
2733965Sjdp*/
2833965Sjdp#include "bfd.h"
2933965Sjdp#include "libiberty.h"
3033965Sjdp#include "progress.h"
3133965Sjdp#include "bucomm.h"
3233965Sjdp#include "aout/ar.h"
3333965Sjdp#include "libbfd.h"
3433965Sjdp#include "arsup.h"
3561843Sobrien#include "filenames.h"
3633965Sjdp#include <sys/stat.h>
3733965Sjdp
3833965Sjdp#ifdef __GO32___
3933965Sjdp#define EXT_NAME_LEN 3		/* bufflen of addition to name if it's MS-DOS */
4033965Sjdp#else
4133965Sjdp#define EXT_NAME_LEN 6		/* ditto for *NIX */
4233965Sjdp#endif
4333965Sjdp
4460484Sobrien/* We need to open files in binary modes on system where that makes a
4560484Sobrien   difference.  */
4660484Sobrien#ifndef O_BINARY
4760484Sobrien#define O_BINARY 0
4860484Sobrien#endif
4960484Sobrien
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
15160484Sobrien/* For extract/delete only.  If COUNTED_NAME_MODE is true, we only
15260484Sobrien   extract the COUNTED_NAME_COUNTER instance of that name.  */
15360484Sobrienstatic boolean counted_name_mode = 0;
15460484Sobrienstatic int counted_name_counter = 0;
15560484Sobrien
15633965Sjdp/* Whether to truncate names of files stored in the archive.  */
15733965Sjdpstatic boolean ar_truncate = false;
15833965Sjdp
15960484Sobrien/* Whether to use a full file name match when searching an archive.
16060484Sobrien   This is convenient for archives created by the Microsoft lib
16160484Sobrien   program.  */
16260484Sobrienstatic boolean full_pathname = false;
16360484Sobrien
16433965Sjdpint interactive = 0;
16533965Sjdp
16633965Sjdpstatic void
16733965Sjdpmri_emul ()
16833965Sjdp{
16933965Sjdp  interactive = isatty (fileno (stdin));
17033965Sjdp  yyparse ();
17133965Sjdp}
17233965Sjdp
17333965Sjdp/* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
17433965Sjdp   COUNT is the length of the FILES chain; FUNCTION is called on each entry
17533965Sjdp   whose name matches one in FILES.  */
17633965Sjdp
17733965Sjdpstatic void
17833965Sjdpmap_over_members (arch, function, files, count)
17933965Sjdp     bfd *arch;
18033965Sjdp     void (*function) PARAMS ((bfd *));
18133965Sjdp     char **files;
18233965Sjdp     int count;
18333965Sjdp{
18433965Sjdp  bfd *head;
18560484Sobrien  int match_count;
18633965Sjdp
18733965Sjdp  if (count == 0)
18833965Sjdp    {
18933965Sjdp      for (head = arch->next; head; head = head->next)
19033965Sjdp	{
19133965Sjdp	  PROGRESS (1);
19233965Sjdp	  function (head);
19333965Sjdp	}
19433965Sjdp      return;
19533965Sjdp    }
19660484Sobrien
19733965Sjdp  /* This may appear to be a baroque way of accomplishing what we want.
19833965Sjdp     However we have to iterate over the filenames in order to notice where
19933965Sjdp     a filename is requested but does not exist in the archive.  Ditto
20033965Sjdp     mapping over each file each time -- we want to hack multiple
20133965Sjdp     references.  */
20233965Sjdp
20333965Sjdp  for (; count > 0; files++, count--)
20433965Sjdp    {
20533965Sjdp      boolean found = false;
20633965Sjdp
20760484Sobrien      match_count = 0;
20833965Sjdp      for (head = arch->next; head; head = head->next)
20933965Sjdp	{
21033965Sjdp	  PROGRESS (1);
21133965Sjdp	  if (head->filename == NULL)
21233965Sjdp	    {
21333965Sjdp	      /* Some archive formats don't get the filenames filled in
21433965Sjdp		 until the elements are opened.  */
21533965Sjdp	      struct stat buf;
21633965Sjdp	      bfd_stat_arch_elt (head, &buf);
21733965Sjdp	    }
21833965Sjdp	  if ((head->filename != NULL) &&
21961843Sobrien	      (!FILENAME_CMP (normalize (*files, arch), head->filename)))
22033965Sjdp	    {
22160484Sobrien	      ++match_count;
22260484Sobrien	      if (counted_name_mode
22360484Sobrien		  && match_count != counted_name_counter)
22460484Sobrien		{
22560484Sobrien		  /* Counting, and didn't match on count; go on to the
22660484Sobrien                     next one.  */
22760484Sobrien		  continue;
22860484Sobrien		}
22960484Sobrien
23033965Sjdp	      found = true;
23133965Sjdp	      function (head);
23233965Sjdp	    }
23333965Sjdp	}
23433965Sjdp      if (!found)
23560484Sobrien	/* xgettext:c-format */
23660484Sobrien	fprintf (stderr, _("no entry %s in archive\n"), *files);
23733965Sjdp    }
23833965Sjdp}
23933965Sjdp
24033965Sjdpboolean operation_alters_arch = false;
24133965Sjdp
24233965Sjdpstatic void
24333965Sjdpusage (help)
24433965Sjdp     int help;
24533965Sjdp{
24633965Sjdp  FILE *s;
24733965Sjdp
24833965Sjdp  s = help ? stdout : stderr;
24960484Sobrien
25033965Sjdp  if (! is_ranlib)
25160484Sobrien    {
25260484Sobrien      /* xgettext:c-format */
25377298Sobrien      fprintf (s, _("Usage: %s [-X32_64] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"),
25460484Sobrien	       program_name);
25560484Sobrien      /* xgettext:c-format */
25660484Sobrien      fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
25760484Sobrien      fprintf (s, _(" commands:\n"));
25860484Sobrien      fprintf (s, _("  d            - delete file(s) from the archive\n"));
25960484Sobrien      fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
26060484Sobrien      fprintf (s, _("  p            - print file(s) found in the archive\n"));
26160484Sobrien      fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
26260484Sobrien      fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
26360484Sobrien      fprintf (s, _("  t            - display contents of archive\n"));
26460484Sobrien      fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
26560484Sobrien      fprintf (s, _(" command specific modifiers:\n"));
26660484Sobrien      fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
26760484Sobrien      fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
26860484Sobrien      fprintf (s, _("  [N]          - use instance [count] of name\n"));
26960484Sobrien      fprintf (s, _("  [f]          - truncate inserted file names\n"));
27060484Sobrien      fprintf (s, _("  [P]          - use full path names when matching\n"));
27160484Sobrien      fprintf (s, _("  [o]          - preserve original dates\n"));
27260484Sobrien      fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
27360484Sobrien      fprintf (s, _(" generic modifiers:\n"));
27460484Sobrien      fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
27560484Sobrien      fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
27660484Sobrien      fprintf (s, _("  [S]          - do not build a symbol table\n"));
27760484Sobrien      fprintf (s, _("  [v]          - be verbose\n"));
27860484Sobrien      fprintf (s, _("  [V]          - display the version number\n"));
27977298Sobrien      fprintf (s, _("  [-X32_64]    - (ignored)\n"));
28060484Sobrien    }
28133965Sjdp  else
28260484Sobrien    /* xgettext:c-format */
28360484Sobrien    fprintf (s, _("Usage: %s [-vV] archive\n"), program_name);
28433965Sjdp
28533965Sjdp  list_supported_targets (program_name, stderr);
28633965Sjdp
28733965Sjdp  if (help)
28860484Sobrien    fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
28933965Sjdp
29033965Sjdp  xexit (help ? 0 : 1);
29133965Sjdp}
29233965Sjdp
29333965Sjdp/* Normalize a file name specified on the command line into a file
29433965Sjdp   name which we will use in an archive.  */
29533965Sjdp
29633965Sjdpstatic const char *
29733965Sjdpnormalize (file, abfd)
29833965Sjdp     const char *file;
29933965Sjdp     bfd *abfd;
30033965Sjdp{
30133965Sjdp  const char *filename;
30233965Sjdp
30360484Sobrien  if (full_pathname)
30460484Sobrien    return file;
30560484Sobrien
30633965Sjdp  filename = strrchr (file, '/');
30761843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
30861843Sobrien  {
30961843Sobrien    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
31061843Sobrien    char *bslash = strrchr (file, '\\');
31177298Sobrien    if (filename == NULL || (bslash != NULL && bslash > filename))
31261843Sobrien      filename = bslash;
31361843Sobrien    if (filename == NULL && file[0] != '\0' && file[1] == ':')
31477298Sobrien      filename = file + 1;
31561843Sobrien  }
31661843Sobrien#endif
31733965Sjdp  if (filename != (char *) NULL)
31833965Sjdp    filename++;
31933965Sjdp  else
32033965Sjdp    filename = file;
32133965Sjdp
32233965Sjdp  if (ar_truncate
32333965Sjdp      && abfd != NULL
32433965Sjdp      && strlen (filename) > abfd->xvec->ar_max_namelen)
32533965Sjdp    {
32633965Sjdp      char *s;
32733965Sjdp
32833965Sjdp      /* Space leak.  */
32933965Sjdp      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
33033965Sjdp      memcpy (s, filename, abfd->xvec->ar_max_namelen);
33133965Sjdp      s[abfd->xvec->ar_max_namelen] = '\0';
33233965Sjdp      filename = s;
33333965Sjdp    }
33433965Sjdp
33533965Sjdp  return filename;
33633965Sjdp}
33733965Sjdp
33833965Sjdp/* Remove any output file.  This is only called via xatexit.  */
33933965Sjdp
34060484Sobrienstatic const char *output_filename = NULL;
34133965Sjdpstatic FILE *output_file = NULL;
34233965Sjdpstatic bfd *output_bfd = NULL;
34333965Sjdp
34433965Sjdpstatic void
34533965Sjdpremove_output ()
34633965Sjdp{
34733965Sjdp  if (output_filename != NULL)
34833965Sjdp    {
34933965Sjdp      if (output_bfd != NULL && output_bfd->iostream != NULL)
35033965Sjdp	fclose ((FILE *) (output_bfd->iostream));
35133965Sjdp      if (output_file != NULL)
35233965Sjdp	fclose (output_file);
35333965Sjdp      unlink (output_filename);
35433965Sjdp    }
35533965Sjdp}
35633965Sjdp
35733965Sjdp/* The option parsing should be in its own function.
35833965Sjdp   It will be when I have getopt working.  */
35933965Sjdp
36033965Sjdpint
36133965Sjdpmain (argc, argv)
36233965Sjdp     int argc;
36333965Sjdp     char **argv;
36433965Sjdp{
36533965Sjdp  char *arg_ptr;
36633965Sjdp  char c;
36733965Sjdp  enum
36833965Sjdp    {
36933965Sjdp      none = 0, delete, replace, print_table,
37033965Sjdp      print_files, extract, move, quick_append
37133965Sjdp    } operation = none;
37233965Sjdp  int arg_index;
37333965Sjdp  char **files;
37460484Sobrien  int file_count;
37533965Sjdp  char *inarch_filename;
37633965Sjdp  int show_version;
37733965Sjdp
37860484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
37960484Sobrien  setlocale (LC_MESSAGES, "");
38060484Sobrien#endif
38160484Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
38260484Sobrien  textdomain (PACKAGE);
38360484Sobrien
38433965Sjdp  program_name = argv[0];
38533965Sjdp  xmalloc_set_program_name (program_name);
38633965Sjdp
38733965Sjdp  if (is_ranlib < 0)
38833965Sjdp    {
38933965Sjdp      char *temp;
39033965Sjdp
39133965Sjdp      temp = strrchr (program_name, '/');
39261843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
39361843Sobrien	{
39461843Sobrien	  /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
39561843Sobrien	  char *bslash = strrchr (program_name, '\\');
39677298Sobrien	  if (temp == NULL || (bslash != NULL && bslash > temp))
39761843Sobrien	    temp = bslash;
39861843Sobrien	  if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':')
39961843Sobrien	    temp = program_name + 1;
40061843Sobrien	}
40161843Sobrien#endif
40233965Sjdp      if (temp == NULL)
40333965Sjdp	temp = program_name;
40433965Sjdp      else
40533965Sjdp	++temp;
40633965Sjdp      if (strlen (temp) >= 6
40761843Sobrien	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
40833965Sjdp	is_ranlib = 1;
40933965Sjdp      else
41033965Sjdp	is_ranlib = 0;
41133965Sjdp    }
41233965Sjdp
41333965Sjdp  if (argc > 1 && argv[1][0] == '-')
41433965Sjdp    {
41533965Sjdp      if (strcmp (argv[1], "--help") == 0)
41633965Sjdp	usage (1);
41733965Sjdp      else if (strcmp (argv[1], "--version") == 0)
41833965Sjdp	{
41933965Sjdp	  if (is_ranlib)
42033965Sjdp	    print_version ("ranlib");
42133965Sjdp	  else
42233965Sjdp	    print_version ("ar");
42333965Sjdp	}
42433965Sjdp    }
42533965Sjdp
42633965Sjdp  START_PROGRESS (program_name, 0);
42733965Sjdp
42833965Sjdp  bfd_init ();
42933965Sjdp  set_default_bfd_target ();
43033965Sjdp
43133965Sjdp  show_version = 0;
43233965Sjdp
43333965Sjdp  xatexit (remove_output);
43433965Sjdp
43577298Sobrien  /* Ignored for (partial) AIX compatibility.  On AIX,
43677298Sobrien     the -X option can be used to ignore certain kinds
43777298Sobrien     of object files in the archive (the 64-bit objects
43877298Sobrien     or the 32-bit objects).  GNU ar always looks at all
43977298Sobrien     kinds of objects in an archive.  */
44077298Sobrien  while (argc > 1 && strcmp (argv[1], "-X32_64") == 0)
44177298Sobrien    {
44277298Sobrien      argv++;
44377298Sobrien      argc--;
44477298Sobrien    }
44577298Sobrien
44633965Sjdp  if (is_ranlib)
44733965Sjdp    {
44833965Sjdp      boolean touch = false;
44933965Sjdp
45033965Sjdp      if (argc < 2 || strcmp (argv[1], "--help") == 0)
45133965Sjdp	usage (0);
45233965Sjdp      if (strcmp (argv[1], "-V") == 0
45333965Sjdp	  || strcmp (argv[1], "-v") == 0
45433965Sjdp	  || strncmp (argv[1], "--v", 3) == 0)
45533965Sjdp	print_version ("ranlib");
45633965Sjdp      arg_index = 1;
45733965Sjdp      if (strcmp (argv[1], "-t") == 0)
45833965Sjdp	{
45933965Sjdp	  ++arg_index;
46033965Sjdp	  touch = true;
46133965Sjdp	}
46233965Sjdp      while (arg_index < argc)
46333965Sjdp	{
46433965Sjdp	  if (! touch)
46533965Sjdp	    ranlib_only (argv[arg_index]);
46633965Sjdp	  else
46733965Sjdp	    ranlib_touch (argv[arg_index]);
46833965Sjdp	  ++arg_index;
46933965Sjdp	}
47033965Sjdp      xexit (0);
47133965Sjdp    }
47233965Sjdp
47333965Sjdp  if (argc == 2 && strcmp (argv[1], "-M") == 0)
47433965Sjdp    {
47533965Sjdp      mri_emul ();
47633965Sjdp      xexit (0);
47733965Sjdp    }
47833965Sjdp
47933965Sjdp  if (argc < 2)
48033965Sjdp    usage (0);
48133965Sjdp
48233965Sjdp  arg_ptr = argv[1];
48333965Sjdp
48433965Sjdp  if (*arg_ptr == '-')
48533965Sjdp    ++arg_ptr;			/* compatibility */
48633965Sjdp
48733965Sjdp  while ((c = *arg_ptr++) != '\0')
48833965Sjdp    {
48933965Sjdp      switch (c)
49033965Sjdp	{
49133965Sjdp	case 'd':
49233965Sjdp	case 'm':
49333965Sjdp	case 'p':
49433965Sjdp	case 'q':
49533965Sjdp	case 'r':
49633965Sjdp	case 't':
49733965Sjdp	case 'x':
49833965Sjdp	  if (operation != none)
49960484Sobrien	    fatal (_("two different operation options specified"));
50033965Sjdp	  switch (c)
50133965Sjdp	    {
50233965Sjdp	    case 'd':
50333965Sjdp	      operation = delete;
50433965Sjdp	      operation_alters_arch = true;
50533965Sjdp	      break;
50633965Sjdp	    case 'm':
50733965Sjdp	      operation = move;
50833965Sjdp	      operation_alters_arch = true;
50933965Sjdp	      break;
51033965Sjdp	    case 'p':
51133965Sjdp	      operation = print_files;
51233965Sjdp	      break;
51333965Sjdp	    case 'q':
51433965Sjdp	      operation = quick_append;
51533965Sjdp	      operation_alters_arch = true;
51633965Sjdp	      break;
51733965Sjdp	    case 'r':
51833965Sjdp	      operation = replace;
51933965Sjdp	      operation_alters_arch = true;
52033965Sjdp	      break;
52133965Sjdp	    case 't':
52233965Sjdp	      operation = print_table;
52333965Sjdp	      break;
52433965Sjdp	    case 'x':
52533965Sjdp	      operation = extract;
52633965Sjdp	      break;
52733965Sjdp	    }
52833965Sjdp	case 'l':
52933965Sjdp	  break;
53033965Sjdp	case 'c':
53133965Sjdp	  silent_create = 1;
53233965Sjdp	  break;
53333965Sjdp	case 'o':
53433965Sjdp	  preserve_dates = 1;
53533965Sjdp	  break;
53633965Sjdp	case 'V':
53733965Sjdp	  show_version = true;
53833965Sjdp	  break;
53933965Sjdp	case 's':
54033965Sjdp	  write_armap = 1;
54133965Sjdp	  break;
54238889Sjdp	case 'S':
54338889Sjdp	  write_armap = -1;
54438889Sjdp	  break;
54533965Sjdp	case 'u':
54633965Sjdp	  newer_only = 1;
54733965Sjdp	  break;
54833965Sjdp	case 'v':
54933965Sjdp	  verbose = 1;
55033965Sjdp	  break;
55133965Sjdp	case 'a':
55233965Sjdp	  postype = pos_after;
55333965Sjdp	  break;
55433965Sjdp	case 'b':
55533965Sjdp	  postype = pos_before;
55633965Sjdp	  break;
55733965Sjdp	case 'i':
55833965Sjdp	  postype = pos_before;
55933965Sjdp	  break;
56033965Sjdp	case 'M':
56133965Sjdp	  mri_mode = 1;
56233965Sjdp	  break;
56360484Sobrien	case 'N':
56460484Sobrien	  counted_name_mode = true;
56560484Sobrien	  break;
56633965Sjdp	case 'f':
56733965Sjdp	  ar_truncate = true;
56833965Sjdp	  break;
56960484Sobrien	case 'P':
57060484Sobrien	  full_pathname = true;
57160484Sobrien	  break;
57233965Sjdp	default:
57360484Sobrien	  /* xgettext:c-format */
57460484Sobrien	  non_fatal (_("illegal option -- %c"), c);
57533965Sjdp	  usage (0);
57633965Sjdp	}
57733965Sjdp    }
57833965Sjdp
57933965Sjdp  if (show_version)
58033965Sjdp    print_version ("ar");
58133965Sjdp
58233965Sjdp  if (argc < 3)
58333965Sjdp    usage (0);
58433965Sjdp
58533965Sjdp  if (mri_mode)
58633965Sjdp    {
58733965Sjdp      mri_emul ();
58833965Sjdp    }
58933965Sjdp  else
59033965Sjdp    {
59133965Sjdp      bfd *arch;
59233965Sjdp
59333965Sjdp      /* We can't write an armap when using ar q, so just do ar r
59433965Sjdp         instead.  */
59533965Sjdp      if (operation == quick_append && write_armap)
59633965Sjdp	operation = replace;
59733965Sjdp
59833965Sjdp      if ((operation == none || operation == print_table)
59933965Sjdp	  && write_armap == 1)
60033965Sjdp	{
60133965Sjdp	  ranlib_only (argv[2]);
60233965Sjdp	  xexit (0);
60333965Sjdp	}
60433965Sjdp
60533965Sjdp      if (operation == none)
60660484Sobrien	fatal (_("no operation specified"));
60733965Sjdp
60833965Sjdp      if (newer_only && operation != replace)
60960484Sobrien	fatal (_("`u' is only meaningful with the `r' option."));
61033965Sjdp
61133965Sjdp      arg_index = 2;
61233965Sjdp
61333965Sjdp      if (postype != pos_default)
61433965Sjdp	posname = argv[arg_index++];
61533965Sjdp
61660484Sobrien      if (counted_name_mode)
61760484Sobrien	{
61860484Sobrien          if (operation != extract && operation != delete)
61960484Sobrien	     fatal (_("`N' is only meaningful with the `x' and `d' options."));
62060484Sobrien	  counted_name_counter = atoi (argv[arg_index++]);
62160484Sobrien          if (counted_name_counter <= 0)
62260484Sobrien	    fatal (_("Value for `N' must be positive."));
62360484Sobrien	}
62460484Sobrien
62533965Sjdp      inarch_filename = argv[arg_index++];
62633965Sjdp
62733965Sjdp      files = arg_index < argc ? argv + arg_index : NULL;
62860484Sobrien      file_count = argc - arg_index;
62933965Sjdp
63033965Sjdp#if 0
63133965Sjdp      /* We don't use do_quick_append any more.  Too many systems
63233965Sjdp         expect ar to always rebuild the symbol table even when q is
63333965Sjdp         used.  */
63433965Sjdp
63533965Sjdp      /* We can't do a quick append if we need to construct an
63633965Sjdp	 extended name table, because do_quick_append won't be able to
63733965Sjdp	 rebuild the name table.  Unfortunately, at this point we
63833965Sjdp	 don't actually know the maximum name length permitted by this
63933965Sjdp	 object file format.  So, we guess.  FIXME.  */
64033965Sjdp      if (operation == quick_append && ! ar_truncate)
64133965Sjdp	{
64233965Sjdp	  char **chk;
64333965Sjdp
64433965Sjdp	  for (chk = files; chk != NULL && *chk != '\0'; chk++)
64533965Sjdp	    {
64633965Sjdp	      if (strlen (normalize (*chk, (bfd *) NULL)) > 14)
64733965Sjdp		{
64833965Sjdp		  operation = replace;
64933965Sjdp		  break;
65033965Sjdp		}
65133965Sjdp	    }
65233965Sjdp	}
65333965Sjdp
65433965Sjdp      if (operation == quick_append)
65533965Sjdp	{
65633965Sjdp	  /* Note that quick appending to a non-existent archive creates it,
65733965Sjdp	     even if there are no files to append. */
65833965Sjdp	  do_quick_append (inarch_filename, files);
65933965Sjdp	  xexit (0);
66033965Sjdp	}
66133965Sjdp#endif
66233965Sjdp
66333965Sjdp      arch = open_inarch (inarch_filename,
66433965Sjdp			  files == NULL ? (char *) NULL : files[0]);
66533965Sjdp
66633965Sjdp      switch (operation)
66733965Sjdp	{
66833965Sjdp	case print_table:
66960484Sobrien	  map_over_members (arch, print_descr, files, file_count);
67033965Sjdp	  break;
67133965Sjdp
67233965Sjdp	case print_files:
67360484Sobrien	  map_over_members (arch, print_contents, files, file_count);
67433965Sjdp	  break;
67533965Sjdp
67633965Sjdp	case extract:
67760484Sobrien	  map_over_members (arch, extract_file, files, file_count);
67833965Sjdp	  break;
67933965Sjdp
68033965Sjdp	case delete:
68133965Sjdp	  if (files != NULL)
68233965Sjdp	    delete_members (arch, files);
68360484Sobrien	  else
68460484Sobrien	    output_filename = NULL;
68533965Sjdp	  break;
68633965Sjdp
68733965Sjdp	case move:
68833965Sjdp	  if (files != NULL)
68933965Sjdp	    move_members (arch, files);
69060484Sobrien	  else
69160484Sobrien	    output_filename = NULL;
69233965Sjdp	  break;
69333965Sjdp
69433965Sjdp	case replace:
69533965Sjdp	case quick_append:
69633965Sjdp	  if (files != NULL || write_armap > 0)
69733965Sjdp	    replace_members (arch, files, operation == quick_append);
69860484Sobrien	  else
69960484Sobrien	    output_filename = NULL;
70033965Sjdp	  break;
70133965Sjdp
70233965Sjdp	  /* Shouldn't happen! */
70333965Sjdp	default:
70460484Sobrien	  /* xgettext:c-format */
70560484Sobrien	  fatal (_("internal error -- this option not implemented"));
70633965Sjdp	}
70733965Sjdp    }
70833965Sjdp
70933965Sjdp  END_PROGRESS (program_name);
71033965Sjdp
71133965Sjdp  xexit (0);
71233965Sjdp  return 0;
71333965Sjdp}
71433965Sjdp
71533965Sjdpbfd *
71633965Sjdpopen_inarch (archive_filename, file)
71733965Sjdp     const char *archive_filename;
71833965Sjdp     const char *file;
71933965Sjdp{
72033965Sjdp  const char *target;
72133965Sjdp  bfd **last_one;
72233965Sjdp  bfd *next_one;
72333965Sjdp  struct stat sbuf;
72433965Sjdp  bfd *arch;
72533965Sjdp  char **matching;
72633965Sjdp
72733965Sjdp  bfd_set_error (bfd_error_no_error);
72833965Sjdp
72933965Sjdp  target = NULL;
73033965Sjdp
73133965Sjdp  if (stat (archive_filename, &sbuf) != 0)
73233965Sjdp    {
73361843Sobrien#if !defined(__GO32__) || defined(__DJGPP__)
73433965Sjdp
73561843Sobrien      /* FIXME: I don't understand why this fragment was ifndef'ed
73661843Sobrien	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
73761843Sobrien	 stat() works just fine in v2.x, so I think this should be
73861843Sobrien	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
73961843Sobrien
74033965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why
74161843Sobrien   stat() is wrong ... think it's buried in GO32's IDT - Jax */
74233965Sjdp      if (errno != ENOENT)
74333965Sjdp	bfd_fatal (archive_filename);
74433965Sjdp#endif
74533965Sjdp
74633965Sjdp      if (!operation_alters_arch)
74733965Sjdp	{
74833965Sjdp	  fprintf (stderr, "%s: ", program_name);
74933965Sjdp	  perror (archive_filename);
75033965Sjdp	  maybequit ();
75133965Sjdp	  return NULL;
75233965Sjdp	}
75333965Sjdp
75433965Sjdp      /* Try to figure out the target to use for the archive from the
75533965Sjdp         first object on the list.  */
75633965Sjdp      if (file != NULL)
75733965Sjdp	{
75833965Sjdp	  bfd *obj;
75933965Sjdp
76033965Sjdp	  obj = bfd_openr (file, NULL);
76133965Sjdp	  if (obj != NULL)
76233965Sjdp	    {
76333965Sjdp	      if (bfd_check_format (obj, bfd_object))
76433965Sjdp		target = bfd_get_target (obj);
76533965Sjdp	      (void) bfd_close (obj);
76633965Sjdp	    }
76733965Sjdp	}
76833965Sjdp
76933965Sjdp      /* Create an empty archive.  */
77033965Sjdp      arch = bfd_openw (archive_filename, target);
77133965Sjdp      if (arch == NULL
77233965Sjdp	  || ! bfd_set_format (arch, bfd_archive)
77333965Sjdp	  || ! bfd_close (arch))
77433965Sjdp	bfd_fatal (archive_filename);
77560484Sobrien
77660484Sobrien      /* If we die creating a new archive, don't leave it around.  */
77760484Sobrien      output_filename = archive_filename;
77833965Sjdp    }
77933965Sjdp
78033965Sjdp  arch = bfd_openr (archive_filename, target);
78133965Sjdp  if (arch == NULL)
78233965Sjdp    {
78333965Sjdp    bloser:
78433965Sjdp      bfd_fatal (archive_filename);
78533965Sjdp    }
78633965Sjdp
78733965Sjdp  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
78833965Sjdp    {
78933965Sjdp      bfd_nonfatal (archive_filename);
79033965Sjdp      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
79133965Sjdp	{
79233965Sjdp	  list_matching_formats (matching);
79333965Sjdp	  free (matching);
79433965Sjdp	}
79533965Sjdp      xexit (1);
79633965Sjdp    }
79733965Sjdp
79833965Sjdp  last_one = &(arch->next);
79933965Sjdp  /* Read all the contents right away, regardless.  */
80033965Sjdp  for (next_one = bfd_openr_next_archived_file (arch, NULL);
80133965Sjdp       next_one;
80233965Sjdp       next_one = bfd_openr_next_archived_file (arch, next_one))
80333965Sjdp    {
80433965Sjdp      PROGRESS (1);
80533965Sjdp      *last_one = next_one;
80633965Sjdp      last_one = &next_one->next;
80733965Sjdp    }
80833965Sjdp  *last_one = (bfd *) NULL;
80933965Sjdp  if (bfd_get_error () != bfd_error_no_more_archived_files)
81033965Sjdp    goto bloser;
81133965Sjdp  return arch;
81233965Sjdp}
81333965Sjdp
81433965Sjdpstatic void
81533965Sjdpprint_contents (abfd)
81633965Sjdp     bfd *abfd;
81733965Sjdp{
81833965Sjdp  int ncopied = 0;
81933965Sjdp  char *cbuf = xmalloc (BUFSIZE);
82033965Sjdp  struct stat buf;
82133965Sjdp  long size;
82233965Sjdp  if (bfd_stat_arch_elt (abfd, &buf) != 0)
82360484Sobrien    /* xgettext:c-format */
82460484Sobrien    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
82533965Sjdp
82633965Sjdp  if (verbose)
82777298Sobrien    /* xgettext:c-format */
82877298Sobrien    printf (_("\n<member %s>\n\n"), bfd_get_filename (abfd));
82933965Sjdp
83033965Sjdp  bfd_seek (abfd, 0, SEEK_SET);
83133965Sjdp
83233965Sjdp  size = buf.st_size;
83333965Sjdp  while (ncopied < size)
83433965Sjdp    {
83533965Sjdp
83633965Sjdp      int nread;
83733965Sjdp      int tocopy = size - ncopied;
83833965Sjdp      if (tocopy > BUFSIZE)
83933965Sjdp	tocopy = BUFSIZE;
84033965Sjdp
84133965Sjdp      nread = bfd_read (cbuf, 1, tocopy, abfd);	/* oops -- broke
84233965Sjdp							   abstraction!  */
84333965Sjdp      if (nread != tocopy)
84460484Sobrien	/* xgettext:c-format */
84560484Sobrien	fatal (_("%s is not a valid archive"),
84633965Sjdp	       bfd_get_filename (bfd_my_archive (abfd)));
84733965Sjdp      fwrite (cbuf, 1, nread, stdout);
84833965Sjdp      ncopied += tocopy;
84933965Sjdp    }
85033965Sjdp  free (cbuf);
85133965Sjdp}
85233965Sjdp
85333965Sjdp/* Extract a member of the archive into its own file.
85433965Sjdp
85533965Sjdp   We defer opening the new file until after we have read a BUFSIZ chunk of the
85633965Sjdp   old one, since we know we have just read the archive header for the old
85733965Sjdp   one.  Since most members are shorter than BUFSIZ, this means we will read
85833965Sjdp   the old header, read the old data, write a new inode for the new file, and
85933965Sjdp   write the new data, and be done. This 'optimization' is what comes from
86033965Sjdp   sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
86133965Sjdp   Gilmore  */
86233965Sjdp
86333965Sjdpvoid
86433965Sjdpextract_file (abfd)
86533965Sjdp     bfd *abfd;
86633965Sjdp{
86733965Sjdp  FILE *ostream;
86833965Sjdp  char *cbuf = xmalloc (BUFSIZE);
86933965Sjdp  int nread, tocopy;
87060484Sobrien  long ncopied = 0;
87133965Sjdp  long size;
87233965Sjdp  struct stat buf;
87360484Sobrien
87433965Sjdp  if (bfd_stat_arch_elt (abfd, &buf) != 0)
87560484Sobrien    /* xgettext:c-format */
87660484Sobrien    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
87733965Sjdp  size = buf.st_size;
87833965Sjdp
87960484Sobrien  if (size < 0)
88060484Sobrien    /* xgettext:c-format */
88160484Sobrien    fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
88260484Sobrien
88333965Sjdp  if (verbose)
88433965Sjdp    printf ("x - %s\n", bfd_get_filename (abfd));
88533965Sjdp
88633965Sjdp  bfd_seek (abfd, 0, SEEK_SET);
88733965Sjdp
88860484Sobrien  ostream = NULL;
88933965Sjdp  if (size == 0)
89033965Sjdp    {
89133965Sjdp      /* Seems like an abstraction violation, eh?  Well it's OK! */
89233965Sjdp      output_filename = bfd_get_filename (abfd);
89333965Sjdp
89433965Sjdp      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
89560484Sobrien      if (ostream == NULL)
89633965Sjdp	{
89733965Sjdp	  perror (bfd_get_filename (abfd));
89833965Sjdp	  xexit (1);
89933965Sjdp	}
90033965Sjdp
90133965Sjdp      output_file = ostream;
90233965Sjdp    }
90333965Sjdp  else
90433965Sjdp    while (ncopied < size)
90533965Sjdp      {
90633965Sjdp	tocopy = size - ncopied;
90733965Sjdp	if (tocopy > BUFSIZE)
90833965Sjdp	  tocopy = BUFSIZE;
90933965Sjdp
91033965Sjdp	nread = bfd_read (cbuf, 1, tocopy, abfd);
91133965Sjdp	if (nread != tocopy)
91260484Sobrien	  /* xgettext:c-format */
91360484Sobrien	  fatal (_("%s is not a valid archive"),
91433965Sjdp		 bfd_get_filename (bfd_my_archive (abfd)));
91533965Sjdp
91633965Sjdp	/* See comment above; this saves disk arm motion */
91760484Sobrien	if (ostream == NULL)
91833965Sjdp	  {
91933965Sjdp	    /* Seems like an abstraction violation, eh?  Well it's OK! */
92033965Sjdp	    output_filename = bfd_get_filename (abfd);
92133965Sjdp
92233965Sjdp	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
92360484Sobrien	    if (ostream == NULL)
92433965Sjdp	      {
92533965Sjdp		perror (bfd_get_filename (abfd));
92633965Sjdp		xexit (1);
92733965Sjdp	      }
92833965Sjdp
92933965Sjdp	    output_file = ostream;
93033965Sjdp	  }
93133965Sjdp	fwrite (cbuf, 1, nread, ostream);
93233965Sjdp	ncopied += tocopy;
93333965Sjdp      }
93433965Sjdp
93560484Sobrien  if (ostream != NULL)
93660484Sobrien    fclose (ostream);
93733965Sjdp
93833965Sjdp  output_file = NULL;
93933965Sjdp  output_filename = NULL;
94033965Sjdp
94133965Sjdp  chmod (bfd_get_filename (abfd), buf.st_mode);
94233965Sjdp
94333965Sjdp  if (preserve_dates)
94460484Sobrien    set_times (bfd_get_filename (abfd), &buf);
94560484Sobrien
94660484Sobrien  free (cbuf);
94733965Sjdp}
94833965Sjdp
94933965Sjdp#if 0
95033965Sjdp
95133965Sjdp/* We don't use this anymore.  Too many systems expect ar to rebuild
95233965Sjdp   the symbol table even when q is used.  */
95333965Sjdp
95433965Sjdp/* Just do it quickly; don't worry about dups, armap, or anything like that */
95533965Sjdp
95633965Sjdpstatic void
95733965Sjdpdo_quick_append (archive_filename, files_to_append)
95833965Sjdp     const char *archive_filename;
95933965Sjdp     char **files_to_append;
96033965Sjdp{
96133965Sjdp  FILE *ofile, *ifile;
96233965Sjdp  char *buf = xmalloc (BUFSIZE);
96333965Sjdp  long tocopy, thistime;
96433965Sjdp  bfd *temp;
96533965Sjdp  struct stat sbuf;
96633965Sjdp  boolean newfile = false;
96733965Sjdp  bfd_set_error (bfd_error_no_error);
96833965Sjdp
96933965Sjdp  if (stat (archive_filename, &sbuf) != 0)
97033965Sjdp    {
97133965Sjdp
97261843Sobrien#if !defined(__GO32__) || defined(__DJGPP__)
97333965Sjdp
97461843Sobrien      /* FIXME: I don't understand why this fragment was ifndef'ed
97561843Sobrien	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
97661843Sobrien	 stat() works just fine in v2.x, so I think this should be
97761843Sobrien	 removed.  For now, I enable it for DJGPP v2.
97861843Sobrien
97961843Sobrien	 (And yes, I know this is all unused, but somebody, someday,
98061843Sobrien	 might wish to resurrect this again... -- EZ.  */
98161843Sobrien
98233965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why
98361843Sobrien   stat() is wrong ... think it's buried in GO32's IDT - Jax  */
98433965Sjdp
98533965Sjdp      if (errno != ENOENT)
98633965Sjdp	bfd_fatal (archive_filename);
98733965Sjdp#endif
98833965Sjdp
98933965Sjdp      newfile = true;
99033965Sjdp    }
99133965Sjdp
99233965Sjdp  ofile = fopen (archive_filename, FOPEN_AUB);
99333965Sjdp  if (ofile == NULL)
99433965Sjdp    {
99533965Sjdp      perror (program_name);
99633965Sjdp      xexit (1);
99733965Sjdp    }
99833965Sjdp
99933965Sjdp  temp = bfd_openr (archive_filename, NULL);
100033965Sjdp  if (temp == NULL)
100133965Sjdp    {
100233965Sjdp      bfd_fatal (archive_filename);
100333965Sjdp    }
100433965Sjdp  if (newfile == false)
100533965Sjdp    {
100633965Sjdp      if (bfd_check_format (temp, bfd_archive) != true)
100760484Sobrien	/* xgettext:c-format */
100860484Sobrien	fatal (_("%s is not an archive"), archive_filename);
100933965Sjdp    }
101033965Sjdp  else
101133965Sjdp    {
101233965Sjdp      fwrite (ARMAG, 1, SARMAG, ofile);
101333965Sjdp      if (!silent_create)
101460484Sobrien	/* xgettext:c-format */
101560484Sobrien	non_fatal (_("creating %s"), archive_filename);
101633965Sjdp    }
101733965Sjdp
101833965Sjdp  if (ar_truncate)
101933965Sjdp    temp->flags |= BFD_TRADITIONAL_FORMAT;
102033965Sjdp
102133965Sjdp  /* assume it's an achive, go straight to the end, sans $200 */
102233965Sjdp  fseek (ofile, 0, 2);
102333965Sjdp
102433965Sjdp  for (; files_to_append && *files_to_append; ++files_to_append)
102533965Sjdp    {
102633965Sjdp      struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append);
102733965Sjdp      if (hdr == NULL)
102833965Sjdp	{
102933965Sjdp	  bfd_fatal (*files_to_append);
103033965Sjdp	}
103133965Sjdp
103233965Sjdp      BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
103333965Sjdp
103433965Sjdp      ifile = fopen (*files_to_append, FOPEN_RB);
103533965Sjdp      if (ifile == NULL)
103633965Sjdp	{
103733965Sjdp	  bfd_nonfatal (*files_to_append);
103833965Sjdp	}
103933965Sjdp
104033965Sjdp      if (stat (*files_to_append, &sbuf) != 0)
104133965Sjdp	{
104233965Sjdp	  bfd_nonfatal (*files_to_append);
104333965Sjdp	}
104433965Sjdp
104533965Sjdp      tocopy = sbuf.st_size;
104633965Sjdp
104733965Sjdp      /* XXX should do error-checking! */
104833965Sjdp      fwrite (hdr, 1, sizeof (struct ar_hdr), ofile);
104933965Sjdp
105033965Sjdp      while (tocopy > 0)
105133965Sjdp	{
105233965Sjdp	  thistime = tocopy;
105333965Sjdp	  if (thistime > BUFSIZE)
105433965Sjdp	    thistime = BUFSIZE;
105533965Sjdp	  fread (buf, 1, thistime, ifile);
105633965Sjdp	  fwrite (buf, 1, thistime, ofile);
105733965Sjdp	  tocopy -= thistime;
105833965Sjdp	}
105933965Sjdp      fclose (ifile);
106033965Sjdp      if ((sbuf.st_size % 2) == 1)
106133965Sjdp	putc ('\012', ofile);
106233965Sjdp    }
106333965Sjdp  fclose (ofile);
106433965Sjdp  bfd_close (temp);
106533965Sjdp  free (buf);
106633965Sjdp}
106733965Sjdp
106833965Sjdp#endif /* 0 */
106933965Sjdp
107033965Sjdpstatic void
107133965Sjdpwrite_archive (iarch)
107233965Sjdp     bfd *iarch;
107333965Sjdp{
107433965Sjdp  bfd *obfd;
107533965Sjdp  char *old_name, *new_name;
107633965Sjdp  bfd *contents_head = iarch->next;
107733965Sjdp
107833965Sjdp  old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
107933965Sjdp  strcpy (old_name, bfd_get_filename (iarch));
108033965Sjdp  new_name = make_tempname (old_name);
108133965Sjdp
108233965Sjdp  output_filename = new_name;
108333965Sjdp
108433965Sjdp  obfd = bfd_openw (new_name, bfd_get_target (iarch));
108533965Sjdp
108633965Sjdp  if (obfd == NULL)
108733965Sjdp    bfd_fatal (old_name);
108833965Sjdp
108933965Sjdp  output_bfd = obfd;
109033965Sjdp
109133965Sjdp  bfd_set_format (obfd, bfd_archive);
109233965Sjdp
109333965Sjdp  /* Request writing the archive symbol table unless we've
109433965Sjdp     been explicitly requested not to.  */
109533965Sjdp  obfd->has_armap = write_armap >= 0;
109633965Sjdp
109733965Sjdp  if (ar_truncate)
109833965Sjdp    {
109933965Sjdp      /* This should really use bfd_set_file_flags, but that rejects
110033965Sjdp         archives.  */
110133965Sjdp      obfd->flags |= BFD_TRADITIONAL_FORMAT;
110233965Sjdp    }
110333965Sjdp
110433965Sjdp  if (bfd_set_archive_head (obfd, contents_head) != true)
110533965Sjdp    bfd_fatal (old_name);
110633965Sjdp
110733965Sjdp  if (!bfd_close (obfd))
110833965Sjdp    bfd_fatal (old_name);
110933965Sjdp
111033965Sjdp  output_bfd = NULL;
111133965Sjdp  output_filename = NULL;
111233965Sjdp
111333965Sjdp  /* We don't care if this fails; we might be creating the archive.  */
111433965Sjdp  bfd_close (iarch);
111533965Sjdp
111660484Sobrien  if (smart_rename (new_name, old_name, 0) != 0)
111760484Sobrien    xexit (1);
111833965Sjdp}
111933965Sjdp
112033965Sjdp/* Return a pointer to the pointer to the entry which should be rplacd'd
112133965Sjdp   into when altering.  DEFAULT_POS should be how to interpret pos_default,
112233965Sjdp   and should be a pos value.  */
112333965Sjdp
112433965Sjdpstatic bfd **
112538889Sjdpget_pos_bfd (contents, default_pos, default_posname)
112633965Sjdp     bfd **contents;
112733965Sjdp     enum pos default_pos;
112838889Sjdp     const char *default_posname;
112933965Sjdp{
113033965Sjdp  bfd **after_bfd = contents;
113138889Sjdp  enum pos realpos;
113238889Sjdp  const char *realposname;
113333965Sjdp
113438889Sjdp  if (postype == pos_default)
113538889Sjdp    {
113638889Sjdp      realpos = default_pos;
113738889Sjdp      realposname = default_posname;
113838889Sjdp    }
113938889Sjdp  else
114038889Sjdp    {
114138889Sjdp      realpos = postype;
114238889Sjdp      realposname = posname;
114338889Sjdp    }
114438889Sjdp
114533965Sjdp  if (realpos == pos_end)
114633965Sjdp    {
114733965Sjdp      while (*after_bfd)
114833965Sjdp	after_bfd = &((*after_bfd)->next);
114933965Sjdp    }
115033965Sjdp  else
115133965Sjdp    {
115233965Sjdp      for (; *after_bfd; after_bfd = &(*after_bfd)->next)
115361843Sobrien	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
115433965Sjdp	  {
115533965Sjdp	    if (realpos == pos_after)
115633965Sjdp	      after_bfd = &(*after_bfd)->next;
115733965Sjdp	    break;
115833965Sjdp	  }
115933965Sjdp    }
116033965Sjdp  return after_bfd;
116133965Sjdp}
116233965Sjdp
116333965Sjdpstatic void
116433965Sjdpdelete_members (arch, files_to_delete)
116533965Sjdp     bfd *arch;
116633965Sjdp     char **files_to_delete;
116733965Sjdp{
116833965Sjdp  bfd **current_ptr_ptr;
116933965Sjdp  boolean found;
117033965Sjdp  boolean something_changed = false;
117160484Sobrien  int match_count;
117260484Sobrien
117333965Sjdp  for (; *files_to_delete != NULL; ++files_to_delete)
117433965Sjdp    {
117533965Sjdp      /* In a.out systems, the armap is optional.  It's also called
117633965Sjdp	 __.SYMDEF.  So if the user asked to delete it, we should remember
117733965Sjdp	 that fact. This isn't quite right for COFF systems (where
117833965Sjdp	 __.SYMDEF might be regular member), but it's very unlikely
117933965Sjdp	 to be a problem.  FIXME */
118033965Sjdp
118133965Sjdp      if (!strcmp (*files_to_delete, "__.SYMDEF"))
118233965Sjdp	{
118333965Sjdp	  arch->has_armap = false;
118433965Sjdp	  write_armap = -1;
118533965Sjdp	  continue;
118633965Sjdp	}
118733965Sjdp
118833965Sjdp      found = false;
118960484Sobrien      match_count = 0;
119033965Sjdp      current_ptr_ptr = &(arch->next);
119133965Sjdp      while (*current_ptr_ptr)
119233965Sjdp	{
119361843Sobrien	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
119460484Sobrien		      (*current_ptr_ptr)->filename) == 0)
119533965Sjdp	    {
119660484Sobrien	      ++match_count;
119760484Sobrien	      if (counted_name_mode
119860484Sobrien		  && match_count != counted_name_counter)
119960484Sobrien		{
120060484Sobrien		  /* Counting, and didn't match on count; go on to the
120160484Sobrien                     next one.  */
120260484Sobrien		}
120360484Sobrien	      else
120460484Sobrien		{
120560484Sobrien		  found = true;
120660484Sobrien		  something_changed = true;
120760484Sobrien		  if (verbose)
120860484Sobrien		    printf ("d - %s\n",
120960484Sobrien			    *files_to_delete);
121060484Sobrien		  *current_ptr_ptr = ((*current_ptr_ptr)->next);
121160484Sobrien		  goto next_file;
121260484Sobrien		}
121333965Sjdp	    }
121460484Sobrien
121560484Sobrien	  current_ptr_ptr = &((*current_ptr_ptr)->next);
121633965Sjdp	}
121733965Sjdp
121833965Sjdp      if (verbose && found == false)
121933965Sjdp	{
122060484Sobrien	  /* xgettext:c-format */
122160484Sobrien	  printf (_("No member named `%s'\n"), *files_to_delete);
122233965Sjdp	}
122333965Sjdp    next_file:
122433965Sjdp      ;
122533965Sjdp    }
122633965Sjdp
122733965Sjdp  if (something_changed == true)
122860484Sobrien    write_archive (arch);
122960484Sobrien  else
123060484Sobrien    output_filename = NULL;
123133965Sjdp}
123233965Sjdp
123333965Sjdp
123433965Sjdp/* Reposition existing members within an archive */
123533965Sjdp
123633965Sjdpstatic void
123733965Sjdpmove_members (arch, files_to_move)
123833965Sjdp     bfd *arch;
123933965Sjdp     char **files_to_move;
124033965Sjdp{
124133965Sjdp  bfd **after_bfd;		/* New entries go after this one */
124233965Sjdp  bfd **current_ptr_ptr;	/* cdr pointer into contents */
124333965Sjdp
124433965Sjdp  for (; *files_to_move; ++files_to_move)
124533965Sjdp    {
124633965Sjdp      current_ptr_ptr = &(arch->next);
124733965Sjdp      while (*current_ptr_ptr)
124833965Sjdp	{
124933965Sjdp	  bfd *current_ptr = *current_ptr_ptr;
125061843Sobrien	  if (FILENAME_CMP (normalize (*files_to_move, arch),
125161843Sobrien			    current_ptr->filename) == 0)
125233965Sjdp	    {
125333965Sjdp	      /* Move this file to the end of the list - first cut from
125433965Sjdp		 where it is.  */
125533965Sjdp	      bfd *link;
125633965Sjdp	      *current_ptr_ptr = current_ptr->next;
125733965Sjdp
125833965Sjdp	      /* Now glue to end */
125938889Sjdp	      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
126033965Sjdp	      link = *after_bfd;
126133965Sjdp	      *after_bfd = current_ptr;
126233965Sjdp	      current_ptr->next = link;
126333965Sjdp
126433965Sjdp	      if (verbose)
126533965Sjdp		printf ("m - %s\n", *files_to_move);
126633965Sjdp
126733965Sjdp	      goto next_file;
126833965Sjdp	    }
126933965Sjdp
127033965Sjdp	  current_ptr_ptr = &((*current_ptr_ptr)->next);
127133965Sjdp	}
127260484Sobrien      /* xgettext:c-format */
127360484Sobrien      fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
127460484Sobrien
127533965Sjdp    next_file:;
127633965Sjdp    }
127733965Sjdp
127833965Sjdp  write_archive (arch);
127933965Sjdp}
128033965Sjdp
128133965Sjdp/* Ought to default to replacing in place, but this is existing practice!  */
128233965Sjdp
128333965Sjdpstatic void
128433965Sjdpreplace_members (arch, files_to_move, quick)
128533965Sjdp     bfd *arch;
128633965Sjdp     char **files_to_move;
128733965Sjdp     boolean quick;
128833965Sjdp{
128933965Sjdp  boolean changed = false;
129033965Sjdp  bfd **after_bfd;		/* New entries go after this one */
129133965Sjdp  bfd *current;
129233965Sjdp  bfd **current_ptr;
129333965Sjdp  bfd *temp;
129433965Sjdp
129533965Sjdp  while (files_to_move && *files_to_move)
129633965Sjdp    {
129733965Sjdp      if (! quick)
129833965Sjdp	{
129933965Sjdp	  current_ptr = &arch->next;
130033965Sjdp	  while (*current_ptr)
130133965Sjdp	    {
130233965Sjdp	      current = *current_ptr;
130333965Sjdp
130433965Sjdp	      /* For compatibility with existing ar programs, we
130533965Sjdp		 permit the same file to be added multiple times.  */
130661843Sobrien	      if (FILENAME_CMP (normalize (*files_to_move, arch),
130761843Sobrien				normalize (current->filename, arch)) == 0
130833965Sjdp		  && current->arelt_data != NULL)
130933965Sjdp		{
131033965Sjdp		  if (newer_only)
131133965Sjdp		    {
131233965Sjdp		      struct stat fsbuf, asbuf;
131333965Sjdp
131433965Sjdp		      if (stat (*files_to_move, &fsbuf) != 0)
131533965Sjdp			{
131633965Sjdp			  if (errno != ENOENT)
131733965Sjdp			    bfd_fatal (*files_to_move);
131833965Sjdp			  goto next_file;
131933965Sjdp			}
132033965Sjdp		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
132160484Sobrien			/* xgettext:c-format */
132260484Sobrien			fatal (_("internal stat error on %s"), current->filename);
132333965Sjdp
132433965Sjdp		      if (fsbuf.st_mtime <= asbuf.st_mtime)
132533965Sjdp			goto next_file;
132633965Sjdp		    }
132733965Sjdp
132838889Sjdp		  after_bfd = get_pos_bfd (&arch->next, pos_after,
132938889Sjdp					   current->filename);
133038889Sjdp		  temp = *after_bfd;
133133965Sjdp
133233965Sjdp		  *after_bfd = bfd_openr (*files_to_move, NULL);
133333965Sjdp		  if (*after_bfd == (bfd *) NULL)
133433965Sjdp		    {
133533965Sjdp		      bfd_fatal (*files_to_move);
133633965Sjdp		    }
133733965Sjdp		  (*after_bfd)->next = temp;
133833965Sjdp
133938889Sjdp		  /* snip out this entry from the chain */
134038889Sjdp		  *current_ptr = (*current_ptr)->next;
134138889Sjdp
134233965Sjdp		  if (verbose)
134333965Sjdp		    {
134433965Sjdp		      printf ("r - %s\n", *files_to_move);
134533965Sjdp		    }
134633965Sjdp
134733965Sjdp		  changed = true;
134833965Sjdp
134933965Sjdp		  goto next_file;
135033965Sjdp		}
135133965Sjdp	      current_ptr = &(current->next);
135233965Sjdp	    }
135333965Sjdp	}
135433965Sjdp
135533965Sjdp      /* Add to the end of the archive.  */
135633965Sjdp
135738889Sjdp      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
135833965Sjdp      temp = *after_bfd;
135933965Sjdp      *after_bfd = bfd_openr (*files_to_move, NULL);
136033965Sjdp      if (*after_bfd == (bfd *) NULL)
136133965Sjdp	{
136233965Sjdp	  bfd_fatal (*files_to_move);
136333965Sjdp	}
136433965Sjdp      if (verbose)
136533965Sjdp	{
136633965Sjdp	  printf ("a - %s\n", *files_to_move);
136733965Sjdp	}
136833965Sjdp
136933965Sjdp      (*after_bfd)->next = temp;
137033965Sjdp
137133965Sjdp      changed = true;
137233965Sjdp
137333965Sjdp    next_file:;
137433965Sjdp
137533965Sjdp      files_to_move++;
137633965Sjdp    }
137733965Sjdp
137833965Sjdp  if (changed)
137933965Sjdp    write_archive (arch);
138060484Sobrien  else
138160484Sobrien    output_filename = NULL;
138233965Sjdp}
138333965Sjdp
138433965Sjdpstatic void
138533965Sjdpranlib_only (archname)
138633965Sjdp     const char *archname;
138733965Sjdp{
138833965Sjdp  bfd *arch;
138933965Sjdp
139033965Sjdp  write_armap = 1;
139133965Sjdp  arch = open_inarch (archname, (char *) NULL);
139233965Sjdp  if (arch == NULL)
139333965Sjdp    xexit (1);
139433965Sjdp  write_archive (arch);
139533965Sjdp}
139633965Sjdp
139733965Sjdp/* Update the timestamp of the symbol map of an archive.  */
139833965Sjdp
139933965Sjdpstatic void
140033965Sjdpranlib_touch (archname)
140133965Sjdp     const char *archname;
140233965Sjdp{
140333965Sjdp#ifdef __GO32__
140433965Sjdp  /* I don't think updating works on go32.  */
140533965Sjdp  ranlib_only (archname);
140633965Sjdp#else
140733965Sjdp  int f;
140833965Sjdp  bfd *arch;
140933965Sjdp  char **matching;
141033965Sjdp
141160484Sobrien  f = open (archname, O_RDWR | O_BINARY, 0);
141233965Sjdp  if (f < 0)
141333965Sjdp    {
141433965Sjdp      bfd_set_error (bfd_error_system_call);
141533965Sjdp      bfd_fatal (archname);
141633965Sjdp    }
141733965Sjdp
141833965Sjdp  arch = bfd_fdopenr (archname, (const char *) NULL, f);
141933965Sjdp  if (arch == NULL)
142033965Sjdp    bfd_fatal (archname);
142133965Sjdp  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
142233965Sjdp    {
142333965Sjdp      bfd_nonfatal (archname);
142433965Sjdp      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
142533965Sjdp	{
142633965Sjdp	  list_matching_formats (matching);
142733965Sjdp	  free (matching);
142833965Sjdp	}
142933965Sjdp      xexit (1);
143033965Sjdp    }
143133965Sjdp
143233965Sjdp  if (! bfd_has_map (arch))
143360484Sobrien    /* xgettext:c-format */
143460484Sobrien    fatal (_("%s: no archive map to update"), archname);
143533965Sjdp
143633965Sjdp  bfd_update_armap_timestamp (arch);
143733965Sjdp
143833965Sjdp  if (! bfd_close (arch))
143933965Sjdp    bfd_fatal (archname);
144033965Sjdp#endif
144133965Sjdp}
144233965Sjdp
144333965Sjdp/* Things which are interesting to map over all or some of the files: */
144433965Sjdp
144533965Sjdpstatic void
144633965Sjdpprint_descr (abfd)
144733965Sjdp     bfd *abfd;
144833965Sjdp{
144933965Sjdp  print_arelt_descr (stdout, abfd, verbose);
145033965Sjdp}
1451