* m10300-opc.c, m10300-dis.c: Add am33 support.
[deliverable/binutils-gdb.git] / binutils / ar.c
index a7cad3960af0f2d48d92c87da08890e30a444be0..ad9e59d347e0317e8331d2498e5fdd39e19ab258 100644 (file)
@@ -1,5 +1,6 @@
 /* ar.c - Archive modify and extract.
-   Copyright 1991, 92, 93, 94 Free Software Foundation, Inc.
+   Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 1999
+   Free Software Foundation, Inc.
 
 This file is part of GNU Binutils.
 
@@ -15,7 +16,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 \f
 /*
    Bugs: should use getopt the way tar does (complete w/optional -) and
@@ -25,27 +26,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
    more consistant.
 */
 #include "bfd.h"
-#include "sysdep.h"
 #include "libiberty.h"
+#include "progress.h"
 #include "bucomm.h"
 #include "aout/ar.h"
 #include "libbfd.h"
 #include "arsup.h"
-#include <stdio.h>
-#ifdef POSIX_UTIME
-#include <utime.h>
-#else /* ! POSIX_UTIME */
-#ifdef USE_UTIME
-#include <time.h>
-#else /* ! USE_UTIME */
-#include <sys/time.h>
-#endif /* ! USE_UTIME */
-#endif /* ! POSIX_UTIME */
-#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-#define BUFSIZE 8192
+#include <sys/stat.h>
 
 #ifdef __GO32___
 #define EXT_NAME_LEN 3         /* bufflen of addition to name if it's MS-DOS */
@@ -53,12 +40,26 @@ extern int errno;
 #define EXT_NAME_LEN 6         /* ditto for *NIX */
 #endif
 
+/* We need to open files in binary modes on system where that makes a
+   difference.  */
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define BUFSIZE 8192
+
 /* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
 
 struct ar_hdr *
-  bfd_special_undocumented_glue PARAMS ((bfd * abfd, char *filename));
+  bfd_special_undocumented_glue PARAMS ((bfd * abfd, const char *filename));
 
-/* Forward declarations */
+/* Static declarations */
+
+static void
+mri_emul PARAMS ((void));
+
+static const char *
+normalize PARAMS ((const char *, bfd *));
 
 static void
 remove_output PARAMS ((void));
@@ -72,15 +73,17 @@ print_contents PARAMS ((bfd * member));
 static void
 delete_members PARAMS ((bfd *, char **files_to_delete));
 
+#if 0
 static void
 do_quick_append PARAMS ((const char *archive_filename,
                         char **files_to_append));
+#endif
 
 static void
 move_members PARAMS ((bfd *, char **files_to_move));
 
 static void
-replace_members PARAMS ((bfd *, char **files_to_replace));
+replace_members PARAMS ((bfd *, char **files_to_replace, boolean quick));
 
 static void
 print_descr PARAMS ((bfd * abfd));
@@ -93,6 +96,9 @@ ranlib_only PARAMS ((const char *archname));
 
 static void
 ranlib_touch PARAMS ((const char *archname));
+
+static void
+usage PARAMS ((int));
 \f
 /** Globals and flags */
 
@@ -138,9 +144,25 @@ enum pos
     pos_default, pos_before, pos_after, pos_end
   } postype = pos_default;
 
+static bfd **
+get_pos_bfd PARAMS ((bfd **, enum pos, const char *));
+
+/* For extract/delete only.  If COUNTED_NAME_MODE is true, we only
+   extract the COUNTED_NAME_COUNTER instance of that name.  */
+static boolean counted_name_mode = 0;
+static int counted_name_counter = 0;
+
+/* Whether to truncate names of files stored in the archive.  */
+static boolean ar_truncate = false;
+
+/* Whether to use a full file name match when searching an archive.
+   This is convenient for archives created by the Microsoft lib
+   program.  */
+static boolean full_pathname = false;
+
 int interactive = 0;
 
-void
+static void
 mri_emul ()
 {
   interactive = isatty (fileno (stdin));
@@ -159,13 +181,18 @@ map_over_members (arch, function, files, count)
      int count;
 {
   bfd *head;
+  int match_count;
 
   if (count == 0)
     {
       for (head = arch->next; head; head = head->next)
-       function (head);
+       {
+         PROGRESS (1);
+         function (head);
+       }
       return;
     }
+
   /* This may appear to be a baroque way of accomplishing what we want.
      However we have to iterate over the filenames in order to notice where
      a filename is requested but does not exist in the archive.  Ditto
@@ -175,8 +202,11 @@ map_over_members (arch, function, files, count)
   for (; count > 0; files++, count--)
     {
       boolean found = false;
+
+      match_count = 0;
       for (head = arch->next; head; head = head->next)
        {
+         PROGRESS (1);
          if (head->filename == NULL)
            {
              /* Some archive formats don't get the filenames filled in
@@ -185,64 +215,117 @@ map_over_members (arch, function, files, count)
              bfd_stat_arch_elt (head, &buf);
            }
          if ((head->filename != NULL) &&
-             (!strcmp (*files, head->filename)))
+             (!strcmp (normalize (*files, arch), head->filename)))
            {
+             ++match_count;
+             if (counted_name_mode
+                 && match_count != counted_name_counter) 
+               {
+                 /* Counting, and didn't match on count; go on to the
+                     next one.  */
+                 continue;
+               }
+
              found = true;
              function (head);
            }
        }
       if (!found)
-       fprintf (stderr, "no entry %s in archive\n", *files);
+       /* xgettext:c-format */
+       fprintf (stderr, _("no entry %s in archive\n"), *files);
     }
 }
 \f
 boolean operation_alters_arch = false;
 
-extern char *program_version;
-
-void
-do_show_version ()
+static void
+usage (help)
+     int help;
 {
-  printf ("GNU %s version %s\n", program_name, program_version);
-  xexit (0);
-}
+  FILE *s;
 
-void
-usage ()
-{
-  if (is_ranlib == 0)
-    fprintf (stderr, "\
-Usage: %s [-]{dmpqrtx}[abcilosuvV] [member-name] archive-file file...\n\
-       %s -M [<mri-script]\n",
-            program_name, program_name);
+  s = help ? stdout : stderr;
+  
+  if (! is_ranlib)
+    {
+      /* xgettext:c-format */
+      fprintf (s, _("Usage: %s [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"),
+              program_name);
+      /* xgettext:c-format */
+      fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
+      fprintf (s, _(" commands:\n"));
+      fprintf (s, _("  d            - delete file(s) from the archive\n"));
+      fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
+      fprintf (s, _("  p            - print file(s) found in the archive\n"));
+      fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
+      fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
+      fprintf (s, _("  t            - display contents of archive\n"));
+      fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
+      fprintf (s, _(" command specific modifiers:\n"));
+      fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
+      fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
+      fprintf (s, _("  [N]          - use instance [count] of name\n"));
+      fprintf (s, _("  [f]          - truncate inserted file names\n"));
+      fprintf (s, _("  [P]          - use full path names when matching\n"));
+      fprintf (s, _("  [o]          - preserve original dates\n"));
+      fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
+      fprintf (s, _(" generic modifiers:\n"));
+      fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
+      fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
+      fprintf (s, _("  [S]          - do not build a symbol table\n"));
+      fprintf (s, _("  [v]          - be verbose\n"));
+      fprintf (s, _("  [V]          - display the version number\n"));
+    }
   else
-    fprintf (stderr, "\
-Usage: %s [-vV] archive\n", program_name);
-  xexit (1);
+    /* xgettext:c-format */
+    fprintf (s, _("Usage: %s [-vV] archive\n"), program_name);
+
+  list_supported_targets (program_name, stderr);
+
+  if (help)
+    fprintf (s, _("Report bugs to bug-gnu-utils@gnu.org\n"));
+
+  xexit (help ? 0 : 1);
 }
 
 /* Normalize a file name specified on the command line into a file
    name which we will use in an archive.  */
 
-static char *
-normalize (file)
-     char *file;
+static const char *
+normalize (file, abfd)
+     const char *file;
+     bfd *abfd;
 {
-  char *filename = strrchr (file, '/');
+  const char *filename;
+
+  if (full_pathname)
+    return file;
+
+  filename = strrchr (file, '/');
   if (filename != (char *) NULL)
-    {
-      filename++;
-    }
+    filename++;
   else
+    filename = file;
+
+  if (ar_truncate
+      && abfd != NULL
+      && strlen (filename) > abfd->xvec->ar_max_namelen)
     {
-      filename = file;
+      char *s;
+
+      /* Space leak.  */
+      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
+      memcpy (s, filename, abfd->xvec->ar_max_namelen);
+      s[abfd->xvec->ar_max_namelen] = '\0';
+      filename = s;
     }
+
   return filename;
 }
 
 /* Remove any output file.  This is only called via xatexit.  */
 
-static char *output_filename = NULL;
+static const char *output_filename = NULL;
 static FILE *output_file = NULL;
 static bfd *output_bfd = NULL;
 
@@ -276,34 +359,67 @@ main (argc, argv)
     } operation = none;
   int arg_index;
   char **files;
+  int file_count;
   char *inarch_filename;
-  char *temp;
   int show_version;
 
+#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
+  setlocale (LC_MESSAGES, "");
+#endif
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
   program_name = argv[0];
   xmalloc_set_program_name (program_name);
 
+  if (is_ranlib < 0)
+    {
+      char *temp;
+
+      temp = strrchr (program_name, '/');
+      if (temp == NULL)
+       temp = program_name;
+      else
+       ++temp;
+      if (strlen (temp) >= 6
+         && strcmp (temp + strlen (temp) - 6, "ranlib") == 0)
+       is_ranlib = 1;
+      else
+       is_ranlib = 0;
+    }
+
+  if (argc > 1 && argv[1][0] == '-')
+    {
+      if (strcmp (argv[1], "--help") == 0)
+       usage (1);
+      else if (strcmp (argv[1], "--version") == 0)
+       {
+         if (is_ranlib)
+           print_version ("ranlib");
+         else
+           print_version ("ar");
+       }
+    }
+
+  START_PROGRESS (program_name, 0);
+
   bfd_init ();
+  set_default_bfd_target ();
+
   show_version = 0;
 
   xatexit (remove_output);
 
-  temp = strrchr (program_name, '/');
-  if (temp == (char *) NULL)
-    temp = program_name;       /* shouldn't happen, but... */
-  else
-    ++temp;
-  if (is_ranlib > 0 || (is_ranlib < 0 && strcmp (temp, "ranlib") == 0))
+  if (is_ranlib)
     {
       boolean touch = false;
 
-      is_ranlib = 1;
-      if (argc < 2)
-       usage ();
+      if (argc < 2 || strcmp (argv[1], "--help") == 0)
+       usage (0);
       if (strcmp (argv[1], "-V") == 0
          || strcmp (argv[1], "-v") == 0
          || strncmp (argv[1], "--v", 3) == 0)
-       do_show_version ();
+       print_version ("ranlib");
       arg_index = 1;
       if (strcmp (argv[1], "-t") == 0)
        {
@@ -320,8 +436,6 @@ main (argc, argv)
        }
       xexit (0);
     }
-  else
-    is_ranlib = 0;
 
   if (argc == 2 && strcmp (argv[1], "-M") == 0)
     {
@@ -330,7 +444,7 @@ main (argc, argv)
     }
 
   if (argc < 2)
-    usage ();
+    usage (0);
 
   arg_ptr = argv[1];
 
@@ -349,7 +463,7 @@ main (argc, argv)
        case 't':
        case 'x':
          if (operation != none)
-           fatal ("two different operation options specified");
+           fatal (_("two different operation options specified"));
          switch (c)
            {
            case 'd':
@@ -392,6 +506,9 @@ main (argc, argv)
        case 's':
          write_armap = 1;
          break;
+       case 'S':
+         write_armap = -1;
+         break;
        case 'u':
          newer_only = 1;
          break;
@@ -410,17 +527,27 @@ main (argc, argv)
        case 'M':
          mri_mode = 1;
          break;
+       case 'N':
+         counted_name_mode = true;
+         break;
+       case 'f':
+         ar_truncate = true;
+         break;
+       case 'P':
+         full_pathname = true;
+         break;
        default:
-         fprintf (stderr, "%s: illegal option -- %c\n", program_name, c);
-         usage ();
+         /* xgettext:c-format */
+         fprintf (stderr, _("%s: illegal option -- %c\n"), program_name, c);
+         usage (0);
        }
     }
 
   if (show_version)
-    do_show_version ();
+    print_version ("ar");
 
   if (argc < 3)
-    usage ();
+    usage (0);
 
   if (mri_mode)
     {
@@ -443,32 +570,47 @@ main (argc, argv)
        }
 
       if (operation == none)
-       fatal ("no operation specified");
+       fatal (_("no operation specified"));
 
       if (newer_only && operation != replace)
-       fatal ("`u' is only meaningful with the `r' option.");
+       fatal (_("`u' is only meaningful with the `r' option."));
 
       arg_index = 2;
 
       if (postype != pos_default)
        posname = argv[arg_index++];
 
+      if (counted_name_mode) 
+       {
+          if (operation != extract && operation != delete) 
+            fatal (_("`N' is only meaningful with the `x' and 'd' options."));
+         counted_name_counter = atoi (argv[arg_index++]);
+          if (counted_name_counter <= 0)
+           fatal (_("Value for `N' must be positive."));
+       }
+
       inarch_filename = argv[arg_index++];
 
       files = arg_index < argc ? argv + arg_index : NULL;
+      file_count = argc - arg_index;
+
+#if 0
+      /* We don't use do_quick_append any more.  Too many systems
+         expect ar to always rebuild the symbol table even when q is
+         used.  */
 
       /* We can't do a quick append if we need to construct an
         extended name table, because do_quick_append won't be able to
         rebuild the name table.  Unfortunately, at this point we
         don't actually know the maximum name length permitted by this
         object file format.  So, we guess.  FIXME.  */
-      if (operation == quick_append)
+      if (operation == quick_append && ! ar_truncate)
        {
          char **chk;
 
          for (chk = files; chk != NULL && *chk != '\0'; chk++)
            {
-             if (strlen (normalize (*chk)) > 14)
+             if (strlen (normalize (*chk, (bfd *) NULL)) > 14)
                {
                  operation = replace;
                  break;
@@ -483,64 +625,80 @@ main (argc, argv)
          do_quick_append (inarch_filename, files);
          xexit (0);
        }
+#endif
 
-      arch = open_inarch (inarch_filename);
+      arch = open_inarch (inarch_filename,
+                         files == NULL ? (char *) NULL : files[0]);
 
       switch (operation)
        {
        case print_table:
-         map_over_members (arch, print_descr, files, argc - 3);
+         map_over_members (arch, print_descr, files, file_count);
          break;
 
        case print_files:
-         map_over_members (arch, print_contents, files, argc - 3);
+         map_over_members (arch, print_contents, files, file_count);
          break;
 
        case extract:
-         map_over_members (arch, extract_file, files, argc - 3);
+         map_over_members (arch, extract_file, files, file_count);
          break;
 
        case delete:
          if (files != NULL)
            delete_members (arch, files);
+         else
+           output_filename = NULL;
          break;
 
        case move:
          if (files != NULL)
            move_members (arch, files);
+         else
+           output_filename = NULL;
          break;
 
        case replace:
+       case quick_append:
          if (files != NULL || write_armap > 0)
-           replace_members (arch, files);
+           replace_members (arch, files, operation == quick_append);
+         else
+           output_filename = NULL;
          break;
 
          /* Shouldn't happen! */
        default:
-         fprintf (stderr, "%s: internal error -- this option not implemented\n",
+         /* xgettext:c-format */
+         fprintf (stderr, _("%s: internal error -- this option not implemented\n"),
                   program_name);
          xexit (1);
        }
     }
 
+  END_PROGRESS (program_name);
+
   xexit (0);
   return 0;
 }
 
 bfd *
-open_inarch (archive_filename)
+open_inarch (archive_filename, file)
      const char *archive_filename;
+     const char *file;
 {
+  const char *target;
   bfd **last_one;
   bfd *next_one;
   struct stat sbuf;
   bfd *arch;
+  char **matching;
 
   bfd_set_error (bfd_error_no_error);
 
+  target = NULL;
+
   if (stat (archive_filename, &sbuf) != 0)
     {
-
 #ifndef __GO32__
 
 /* KLUDGE ALERT! Temporary fix until I figger why
@@ -559,26 +717,57 @@ open_inarch (archive_filename)
          return NULL;
        }
 
-      /* This routine is one way to forcibly create the archive. */
+      /* Try to figure out the target to use for the archive from the
+         first object on the list.  */
+      if (file != NULL)
+       {
+         bfd *obj;
+
+         obj = bfd_openr (file, NULL);
+         if (obj != NULL)
+           {
+             if (bfd_check_format (obj, bfd_object))
+               target = bfd_get_target (obj);
+             (void) bfd_close (obj);
+           }
+       }
+
+      /* Create an empty archive.  */
+      arch = bfd_openw (archive_filename, target);
+      if (arch == NULL
+         || ! bfd_set_format (arch, bfd_archive)
+         || ! bfd_close (arch))
+       bfd_fatal (archive_filename);
 
-      do_quick_append (archive_filename, 0);
+      /* If we die creating a new archive, don't leave it around.  */
+      output_filename = archive_filename;
     }
 
-  arch = bfd_openr (archive_filename, NULL);
+  arch = bfd_openr (archive_filename, target);
   if (arch == NULL)
     {
     bloser:
       bfd_fatal (archive_filename);
     }
 
-  if (bfd_check_format (arch, bfd_archive) != true)
-    fatal ("%s is not an archive", archive_filename);
+  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
+    {
+      bfd_nonfatal (archive_filename);
+      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
+       {
+         list_matching_formats (matching);
+         free (matching);
+       }
+      xexit (1);
+    }
+
   last_one = &(arch->next);
   /* Read all the contents right away, regardless.  */
   for (next_one = bfd_openr_next_archived_file (arch, NULL);
        next_one;
        next_one = bfd_openr_next_archived_file (arch, next_one))
     {
+      PROGRESS (1);
       *last_one = next_one;
       last_one = &next_one->next;
     }
@@ -593,20 +782,22 @@ print_contents (abfd)
      bfd *abfd;
 {
   int ncopied = 0;
+  char *cbuf = xmalloc (BUFSIZE);
   struct stat buf;
   long size;
   if (bfd_stat_arch_elt (abfd, &buf) != 0)
-    fatal ("internal stat error on %s", bfd_get_filename (abfd));
+    /* xgettext:c-format */
+    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
 
   if (verbose)
-    printf ("\n<member %s>\n\n", bfd_get_filename (abfd));
+    printf ("\n<%s>\n\n", bfd_get_filename (abfd));
 
   bfd_seek (abfd, 0, SEEK_SET);
 
   size = buf.st_size;
   while (ncopied < size)
     {
-      char cbuf[BUFSIZE];
+
       int nread;
       int tocopy = size - ncopied;
       if (tocopy > BUFSIZE)
@@ -615,11 +806,13 @@ print_contents (abfd)
       nread = bfd_read (cbuf, 1, tocopy, abfd);        /* oops -- broke
                                                           abstraction!  */
       if (nread != tocopy)
-       fatal ("%s is not a valid archive",
+       /* xgettext:c-format */
+       fatal (_("%s is not a valid archive"),
               bfd_get_filename (bfd_my_archive (abfd)));
       fwrite (cbuf, 1, nread, stdout);
       ncopied += tocopy;
     }
+  free (cbuf);
 }
 
 /* Extract a member of the archive into its own file.
@@ -637,28 +830,34 @@ extract_file (abfd)
      bfd *abfd;
 {
   FILE *ostream;
-  char cbuf[BUFSIZE];
+  char *cbuf = xmalloc (BUFSIZE);
   int nread, tocopy;
-  int ncopied = 0;
+  long ncopied = 0;
   long size;
   struct stat buf;
+  
   if (bfd_stat_arch_elt (abfd, &buf) != 0)
-    fatal ("internal stat error on %s", bfd_get_filename (abfd));
+    /* xgettext:c-format */
+    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
   size = buf.st_size;
 
+  if (size < 0)
+    /* xgettext:c-format */
+    fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
+  
   if (verbose)
     printf ("x - %s\n", bfd_get_filename (abfd));
 
   bfd_seek (abfd, 0, SEEK_SET);
 
-  ostream = 0;
+  ostream = NULL;
   if (size == 0)
     {
       /* Seems like an abstraction violation, eh?  Well it's OK! */
       output_filename = bfd_get_filename (abfd);
 
       ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
-      if (!ostream)
+      if (ostream == NULL)
        {
          perror (bfd_get_filename (abfd));
          xexit (1);
@@ -675,17 +874,18 @@ extract_file (abfd)
 
        nread = bfd_read (cbuf, 1, tocopy, abfd);
        if (nread != tocopy)
-         fatal ("%s is not a valid archive",
+         /* xgettext:c-format */
+         fatal (_("%s is not a valid archive"),
                 bfd_get_filename (bfd_my_archive (abfd)));
 
        /* See comment above; this saves disk arm motion */
-       if (!ostream)
+       if (ostream == NULL)
          {
            /* Seems like an abstraction violation, eh?  Well it's OK! */
            output_filename = bfd_get_filename (abfd);
 
            ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
-           if (!ostream)
+           if (ostream == NULL)
              {
                perror (bfd_get_filename (abfd));
                xexit (1);
@@ -697,7 +897,8 @@ extract_file (abfd)
        ncopied += tocopy;
       }
 
-  fclose (ostream);
+  if (ostream != NULL)
+    fclose (ostream);
 
   output_file = NULL;
   output_filename = NULL;
@@ -705,30 +906,16 @@ extract_file (abfd)
   chmod (bfd_get_filename (abfd), buf.st_mode);
 
   if (preserve_dates)
-    {
-#ifdef POSIX_UTIME
-      struct utimbuf tb;
-      tb.actime = buf.st_mtime;
-      tb.modtime = buf.st_mtime;
-      utime (bfd_get_filename (abfd), &tb);    /* FIXME check result */
-#else /* ! POSIX_UTIME */
-#ifdef USE_UTIME
-      long tb[2];
-      tb[0] = buf.st_mtime;
-      tb[1] = buf.st_mtime;
-      utime (bfd_get_filename (abfd), tb);     /* FIXME check result */
-#else /* ! USE_UTIME */
-      struct timeval tv[2];
-      tv[0].tv_sec = buf.st_mtime;
-      tv[0].tv_usec = 0;
-      tv[1].tv_sec = buf.st_mtime;
-      tv[1].tv_usec = 0;
-      utimes (bfd_get_filename (abfd), tv);    /* FIXME check result */
-#endif /* ! USE_UTIME */
-#endif /* ! POSIX_UTIME */
-    }
+    set_times (bfd_get_filename (abfd), &buf);
+
+  free (cbuf);
 }
 
+#if 0
+
+/* We don't use this anymore.  Too many systems expect ar to rebuild
+   the symbol table even when q is used.  */
+
 /* Just do it quickly; don't worry about dups, armap, or anything like that */
 
 static void
@@ -737,7 +924,7 @@ do_quick_append (archive_filename, files_to_append)
      char **files_to_append;
 {
   FILE *ofile, *ifile;
-  char buf[BUFSIZE];
+  char *buf = xmalloc (BUFSIZE);
   long tocopy, thistime;
   bfd *temp;
   struct stat sbuf;
@@ -776,16 +963,21 @@ do_quick_append (archive_filename, files_to_append)
   if (newfile == false)
     {
       if (bfd_check_format (temp, bfd_archive) != true)
-       fatal ("%s is not an archive", archive_filename);
+       /* xgettext:c-format */
+       fatal (_("%s is not an archive"), archive_filename);
     }
   else
     {
       fwrite (ARMAG, 1, SARMAG, ofile);
       if (!silent_create)
-       fprintf (stderr, "%s: creating %s\n",
+       /* xgettext:c-format */
+       fprintf (stderr, _("%s: creating %s\n"),
                 program_name, archive_filename);
     }
 
+  if (ar_truncate)
+    temp->flags |= BFD_TRADITIONAL_FORMAT;
+
   /* assume it's an achive, go straight to the end, sans $200 */
   fseek (ofile, 0, 2);
 
@@ -830,27 +1022,22 @@ do_quick_append (archive_filename, files_to_append)
     }
   fclose (ofile);
   bfd_close (temp);
+  free (buf);
 }
 
+#endif /* 0 */
 
 static void
 write_archive (iarch)
      bfd *iarch;
 {
   bfd *obfd;
-  int namelen = strlen (bfd_get_filename (iarch));
-  char *old_name = xmalloc (namelen + 1);
-  char *new_name = xmalloc (namelen + EXT_NAME_LEN);
+  char *old_name, *new_name;
   bfd *contents_head = iarch->next;
 
+  old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
   strcpy (old_name, bfd_get_filename (iarch));
-  strcpy (new_name, bfd_get_filename (iarch));
-
-#ifdef __GO32__                        /* avoid long .extensions for MS-DOS */
-  strcpy (new_name + namelen, "-a");
-#else
-  strcpy (new_name + namelen, "-art");
-#endif
+  new_name = make_tempname (old_name);
 
   output_filename = new_name;
 
@@ -867,6 +1054,13 @@ write_archive (iarch)
      been explicitly requested not to.  */
   obfd->has_armap = write_armap >= 0;
 
+  if (ar_truncate)
+    {
+      /* This should really use bfd_set_file_flags, but that rejects
+         archives.  */
+      obfd->flags |= BFD_TRADITIONAL_FORMAT;
+    }
+
   if (bfd_set_archive_head (obfd, contents_head) != true)
     bfd_fatal (old_name);
 
@@ -878,23 +1072,35 @@ write_archive (iarch)
 
   /* We don't care if this fails; we might be creating the archive.  */
   bfd_close (iarch);
-  unlink (old_name);
 
-  if (rename (new_name, old_name) != 0)
-    bfd_fatal (old_name);
+  if (smart_rename (new_name, old_name, 0) != 0)
+    xexit (1);
 }
 
 /* Return a pointer to the pointer to the entry which should be rplacd'd
    into when altering.  DEFAULT_POS should be how to interpret pos_default,
    and should be a pos value.  */
 
-bfd **
-get_pos_bfd (contents, default_pos)
+static bfd **
+get_pos_bfd (contents, default_pos, default_posname)
      bfd **contents;
      enum pos default_pos;
+     const char *default_posname;
 {
   bfd **after_bfd = contents;
-  enum pos realpos = (postype == pos_default ? default_pos : postype);
+  enum pos realpos;
+  const char *realposname;
+
+  if (postype == pos_default)
+    {
+      realpos = default_pos;
+      realposname = default_posname;
+    }
+  else
+    {
+      realpos = postype;
+      realposname = posname;
+    }
 
   if (realpos == pos_end)
     {
@@ -904,7 +1110,7 @@ get_pos_bfd (contents, default_pos)
   else
     {
       for (; *after_bfd; after_bfd = &(*after_bfd)->next)
-       if (!strcmp ((*after_bfd)->filename, posname))
+       if (strcmp ((*after_bfd)->filename, realposname) == 0)
          {
            if (realpos == pos_after)
              after_bfd = &(*after_bfd)->next;
@@ -922,6 +1128,8 @@ delete_members (arch, files_to_delete)
   bfd **current_ptr_ptr;
   boolean found;
   boolean something_changed = false;
+  int match_count;
+
   for (; *files_to_delete != NULL; ++files_to_delete)
     {
       /* In a.out systems, the armap is optional.  It's also called
@@ -938,37 +1146,48 @@ delete_members (arch, files_to_delete)
        }
 
       found = false;
+      match_count = 0;
       current_ptr_ptr = &(arch->next);
       while (*current_ptr_ptr)
        {
-         if (strcmp (*files_to_delete, (*current_ptr_ptr)->filename) == 0)
-           {
-             found = true;
-             something_changed = true;
-             if (verbose)
-               printf ("d - %s\n",
-                       *files_to_delete);
-             *current_ptr_ptr = ((*current_ptr_ptr)->next);
-             goto next_file;
-           }
-         else
+         if (strcmp (normalize (*files_to_delete, arch),
+                     (*current_ptr_ptr)->filename) == 0)
            {
-             current_ptr_ptr = &((*current_ptr_ptr)->next);
+             ++match_count;
+             if (counted_name_mode
+                 && match_count != counted_name_counter) 
+               {
+                 /* Counting, and didn't match on count; go on to the
+                     next one.  */
+               }
+             else
+               {
+                 found = true;
+                 something_changed = true;
+                 if (verbose)
+                   printf ("d - %s\n",
+                           *files_to_delete);
+                 *current_ptr_ptr = ((*current_ptr_ptr)->next);
+                 goto next_file;
+               }
            }
+
+         current_ptr_ptr = &((*current_ptr_ptr)->next);
        }
 
       if (verbose && found == false)
        {
-         printf ("No member named `%s'\n", *files_to_delete);
+         /* xgettext:c-format */
+         printf (_("No member named `%s'\n"), *files_to_delete);
        }
     next_file:
       ;
     }
 
   if (something_changed == true)
-    {
-      write_archive (arch);
-    }
+    write_archive (arch);
+  else
+    output_filename = NULL;
 }
 
 
@@ -988,7 +1207,8 @@ move_members (arch, files_to_move)
       while (*current_ptr_ptr)
        {
          bfd *current_ptr = *current_ptr_ptr;
-         if (strcmp (normalize (*files_to_move), current_ptr->filename) == 0)
+         if (strcmp (normalize (*files_to_move, arch),
+                     current_ptr->filename) == 0)
            {
              /* Move this file to the end of the list - first cut from
                 where it is.  */
@@ -996,7 +1216,7 @@ move_members (arch, files_to_move)
              *current_ptr_ptr = current_ptr->next;
 
              /* Now glue to end */
-             after_bfd = get_pos_bfd (&arch->next, pos_end);
+             after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
              link = *after_bfd;
              *after_bfd = current_ptr;
              current_ptr->next = link;
@@ -1009,7 +1229,8 @@ move_members (arch, files_to_move)
 
          current_ptr_ptr = &((*current_ptr_ptr)->next);
        }
-      fprintf (stderr, "%s: no entry %s in archive %s!\n",
+      /* xgettext:c-format */
+      fprintf (stderr, _("%s: no entry %s in archive %s!\n"),
               program_name, *files_to_move, arch->filename);
       xexit (1);
     next_file:;
@@ -1021,10 +1242,12 @@ move_members (arch, files_to_move)
 /* Ought to default to replacing in place, but this is existing practice!  */
 
 static void
-replace_members (arch, files_to_move)
+replace_members (arch, files_to_move, quick)
      bfd *arch;
      char **files_to_move;
+     boolean quick;
 {
+  boolean changed = false;
   bfd **after_bfd;             /* New entries go after this one */
   bfd *current;
   bfd **current_ptr;
@@ -1032,65 +1255,67 @@ replace_members (arch, files_to_move)
 
   while (files_to_move && *files_to_move)
     {
-      current_ptr = &arch->next;
-      while (*current_ptr)
+      if (! quick)
        {
-         current = *current_ptr;
-
-         if (!strcmp (normalize (*files_to_move), current->filename))
+         current_ptr = &arch->next;
+         while (*current_ptr)
            {
-             if (newer_only)
-               {
-                 struct stat fsbuf, asbuf;
+             current = *current_ptr;
 
-                 if (current->arelt_data == NULL)
+             /* For compatibility with existing ar programs, we
+                permit the same file to be added multiple times.  */
+             if (strcmp (normalize (*files_to_move, arch),
+                         normalize (current->filename, arch)) == 0
+                 && current->arelt_data != NULL)
+               {
+                 if (newer_only)
                    {
-                     /* This can only happen if you specify a file on the
-                        command line more than once. */
-                     fprintf (stderr,
-                              "%s: duplicate file specified: %s -- skipping\n",
-                              program_name, *files_to_move);
-                     goto next_file;
+                     struct stat fsbuf, asbuf;
+
+                     if (stat (*files_to_move, &fsbuf) != 0)
+                       {
+                         if (errno != ENOENT)
+                           bfd_fatal (*files_to_move);
+                         goto next_file;
+                       }
+                     if (bfd_stat_arch_elt (current, &asbuf) != 0)
+                       /* xgettext:c-format */
+                       fatal (_("internal stat error on %s"), current->filename);
+
+                     if (fsbuf.st_mtime <= asbuf.st_mtime)
+                       goto next_file;
                    }
 
-                 if (stat (*files_to_move, &fsbuf) != 0)
+                 after_bfd = get_pos_bfd (&arch->next, pos_after,
+                                          current->filename);
+                 temp = *after_bfd;
+
+                 *after_bfd = bfd_openr (*files_to_move, NULL);
+                 if (*after_bfd == (bfd *) NULL)
                    {
-                     if (errno != ENOENT)
-                       bfd_fatal (*files_to_move);
-                     goto next_file;
+                     bfd_fatal (*files_to_move);
                    }
-                 if (bfd_stat_arch_elt (current, &asbuf) != 0)
-                   fatal ("internal stat error on %s", current->filename);
+                 (*after_bfd)->next = temp;
 
-                 if (fsbuf.st_mtime <= asbuf.st_mtime)
-                   goto next_file;
-               }
+                 /* snip out this entry from the chain */
+                 *current_ptr = (*current_ptr)->next;
 
-             /* snip out this entry from the chain */
-             *current_ptr = current->next;
+                 if (verbose)
+                   {
+                     printf ("r - %s\n", *files_to_move);
+                   }
 
-             after_bfd = get_pos_bfd (&arch->next, pos_end);
-             temp = *after_bfd;
-             *after_bfd = bfd_openr (*files_to_move, NULL);
-             if (*after_bfd == (bfd *) NULL)
-               {
-                 bfd_fatal (*files_to_move);
-               }
-             (*after_bfd)->next = temp;
+                 changed = true;
 
-             if (verbose)
-               {
-                 printf ("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
-                         *files_to_move);
+                 goto next_file;
                }
-             goto next_file;
+             current_ptr = &(current->next);
            }
-         current_ptr = &(current->next);
        }
 
-      /* It isn't in there, so add to end */
+      /* Add to the end of the archive.  */
 
-      after_bfd = get_pos_bfd (&arch->next, pos_end);
+      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
       temp = *after_bfd;
       *after_bfd = bfd_openr (*files_to_move, NULL);
       if (*after_bfd == (bfd *) NULL)
@@ -1099,17 +1324,22 @@ replace_members (arch, files_to_move)
        }
       if (verbose)
        {
-         printf ("c - %s\n", *files_to_move);
+         printf ("a - %s\n", *files_to_move);
        }
 
       (*after_bfd)->next = temp;
 
+      changed = true;
+
     next_file:;
 
       files_to_move++;
     }
 
-  write_archive (arch);
+  if (changed)
+    write_archive (arch);
+  else
+    output_filename = NULL;
 }
 
 static void
@@ -1119,7 +1349,7 @@ ranlib_only (archname)
   bfd *arch;
 
   write_armap = 1;
-  arch = open_inarch (archname);
+  arch = open_inarch (archname, (char *) NULL);
   if (arch == NULL)
     xexit (1);
   write_archive (arch);
@@ -1137,8 +1367,9 @@ ranlib_touch (archname)
 #else
   int f;
   bfd *arch;
+  char **matching;
 
-  f = open (archname, O_RDWR, 0);
+  f = open (archname, O_RDWR | O_BINARY, 0);
   if (f < 0)
     {
       bfd_set_error (bfd_error_system_call);
@@ -1146,12 +1377,22 @@ ranlib_touch (archname)
     }
 
   arch = bfd_fdopenr (archname, (const char *) NULL, f);
-  if (arch == NULL
-      || ! bfd_check_format (arch, bfd_archive))
+  if (arch == NULL)
     bfd_fatal (archname);
+  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
+    {
+      bfd_nonfatal (archname);
+      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
+       {
+         list_matching_formats (matching);
+         free (matching);
+       }
+      xexit (1);
+    }
 
   if (! bfd_has_map (arch))
-    fatal ("%s: no archive map to update", archname);
+    /* xgettext:c-format */
+    fatal (_("%s: no archive map to update"), archname);
 
   bfd_update_armap_timestamp (arch);
 
This page took 0.047188 seconds and 4 git commands to generate.