This commit was manufactured by cvs2svn to create branch 'binutils-
[external/binutils.git] / binutils / ar.c
index 29dcb4a..f8c977a 100644 (file)
@@ -1,6 +1,6 @@
 /* ar.c - Archive modify and extract.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
    MA 02110-1301, USA.  */
 \f
 /*
-   Bugs: should use getopt the way tar does (complete w/optional -) and
-   should have long options too. GNU ar used to check file against filesystem
-   in quick_update and replace operations (would check mtime). Doesn't warn
-   when name truncated. No way to specify pos_end. Error messages should be
-   more consistent.  */
+   Bugs: GNU ar used to check file against filesystem in quick_update and
+   replace operations (would check mtime). Doesn't warn when name truncated.
+   No way to specify pos_end. Error messages should be more consistent.  */
 
 #include "sysdep.h"
 #include "bfd.h"
 #include "libiberty.h"
 #include "progress.h"
+#include "getopt.h"
 #include "aout/ar.h"
 #include "libbfd.h"
 #include "bucomm.h"
@@ -113,6 +112,12 @@ enum pos
     pos_default, pos_before, pos_after, pos_end
   } postype = pos_default;
 
+enum operations
+  {
+    none = 0, del, replace, print_table,
+    print_files, extract, move, quick_append
+  } operation = none;
+
 static bfd **
 get_pos_bfd (bfd **, enum pos, const char *);
 
@@ -132,8 +137,26 @@ static bfd_boolean full_pathname = FALSE;
 /* Whether to create a "thin" archive (symbol index only -- no files).  */
 static bfd_boolean make_thin_archive = FALSE;
 
+static int show_version = 0;
+
+static int show_help = 0;
+
 static const char *plugin_target = NULL;
 
+static const char *target = NULL;
+
+#define OPTION_PLUGIN 201
+#define OPTION_TARGET 202
+
+static struct option long_options[] =
+{
+  {"help", no_argument, &show_help, 1},
+  {"plugin", required_argument, NULL, OPTION_PLUGIN},
+  {"target", required_argument, NULL, OPTION_TARGET},
+  {"version", no_argument, &show_version, 1},
+  {NULL, no_argument, NULL, 0}
+};
+
 int interactive = 0;
 
 static void
@@ -193,8 +216,8 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
              filename = normalize (filename, arch);
            }
 
-         if ((filename != NULL) &&
-             (!FILENAME_CMP (normalize (*files, arch), filename)))
+         if (filename != NULL
+             && !FILENAME_CMP (normalize (*files, arch), filename))
            {
              ++match_count;
              if (counted_name_mode
@@ -225,12 +248,17 @@ usage (int help)
 
   s = help ? stdout : stderr;
 
-  /* xgettext:c-format */
-  const char * command_line =
 #if BFD_SUPPORTS_PLUGINS
-       _("Usage: %s [emulation options] [--plugin <name>] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n");
+  /* xgettext:c-format */
+  const char *command_line
+    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
+       " [--plugin <name>] [member-name] [count] archive-file file...\n");
+
 #else
-       _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n");
+  /* xgettext:c-format */
+  const char *command_line
+    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
+       " [member-name] [count] archive-file file...\n");
 #endif
   fprintf (s, command_line, program_name);
 
@@ -262,6 +290,7 @@ usage (int help)
   fprintf (s, _("  [v]          - be verbose\n"));
   fprintf (s, _("  [V]          - display the version number\n"));
   fprintf (s, _("  @<file>      - read options from <file>\n"));
+  fprintf (s, _("  --target=BFDNAME - specify the target object format as BFDNAME\n"));
 #if BFD_SUPPORTS_PLUGINS
   fprintf (s, _(" optional:\n"));
   fprintf (s, _("  --plugin <p> - load the specified plugin\n"));
@@ -278,7 +307,7 @@ usage (int help)
 }
 
 static void
-ranlib_usage(int help)
+ranlib_usage (int help)
 {
   FILE *s;
 
@@ -354,39 +383,210 @@ remove_output (void)
     }
 }
 
+static char **
+decode_options (int argc, char **argv)
+{
+  int c;
+
+  /* Convert old-style tar call by exploding option element and rearranging
+     options accordingly.  */
+
+  if (argc > 1 && argv[1][0] != '-')
+    {
+      int new_argc;            /* argc value for rearranged arguments */
+      char **new_argv;         /* argv value for rearranged arguments */
+      char *const *in;         /* cursor into original argv */
+      char **out;              /* cursor into rearranged argv */
+      const char *letter;      /* cursor into old option letters */
+      char buffer[3];          /* constructed option buffer */
+
+      /* Initialize a constructed option.  */
+
+      buffer[0] = '-';
+      buffer[2] = '\0';
+
+      /* Allocate a new argument array, and copy program name in it.  */
+
+      new_argc = argc - 1 + strlen (argv[1]);
+      new_argv = xmalloc ((new_argc + 1) * sizeof (*argv));
+      in = argv;
+      out = new_argv;
+      *out++ = *in++;
+
+      /* Copy each old letter option as a separate option.  */
+
+      for (letter = *in++; *letter; letter++)
+       {
+         buffer[1] = *letter;
+         *out++ = xstrdup (buffer);
+       }
+
+      /* Copy all remaining options.  */
+
+      while (in < argv + argc)
+       *out++ = *in++;
+      *out = NULL;
+
+      /* Replace the old option list by the new one.  */
+
+      argc = new_argc;
+      argv = new_argv;
+    }
+
+  while ((c = getopt_long (argc, argv, "hdmpqrtxlcoVsSuvabiMNfPTD",
+                          long_options, NULL)) != EOF)
+    {
+      switch (c)
+        {
+        case 'd':
+        case 'm':
+        case 'p':
+        case 'q':
+        case 'r':
+        case 't':
+        case 'x':
+          if (operation != none)
+            fatal (_("two different operation options specified"));
+         break;
+       }
+
+      switch (c)
+        {
+        case 'h':
+         show_help = 1;
+         break;
+        case 'd':
+          operation = del;
+          operation_alters_arch = TRUE;
+          break;
+        case 'm':
+          operation = move;
+          operation_alters_arch = TRUE;
+          break;
+        case 'p':
+          operation = print_files;
+          break;
+        case 'q':
+          operation = quick_append;
+          operation_alters_arch = TRUE;
+          break;
+        case 'r':
+          operation = replace;
+          operation_alters_arch = TRUE;
+          break;
+        case 't':
+          operation = print_table;
+          break;
+        case 'x':
+          operation = extract;
+          break;
+        case 'l':
+          break;
+        case 'c':
+          silent_create = 1;
+          break;
+        case 'o':
+          preserve_dates = 1;
+          break;
+        case 'V':
+          show_version = TRUE;
+          break;
+        case 's':
+          write_armap = 1;
+          break;
+        case 'S':
+          write_armap = -1;
+          break;
+        case 'u':
+          newer_only = 1;
+          break;
+        case 'v':
+          verbose = 1;
+          break;
+        case 'a':
+          postype = pos_after;
+          break;
+        case 'b':
+          postype = pos_before;
+          break;
+        case 'i':
+          postype = pos_before;
+          break;
+        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;
+        case 'T':
+          make_thin_archive = TRUE;
+          break;
+        case 'D':
+          deterministic = TRUE;
+          break;
+       case OPTION_PLUGIN:
+#if BFD_SUPPORTS_PLUGINS
+         plugin_target = "plugin";
+         bfd_plugin_set_plugin (optarg);
+#else
+         fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
+         xexit (1);
+#endif
+         break;
+       case OPTION_TARGET:
+         target = optarg;
+         break;
+       case 0:         /* A long option that just sets a flag.  */
+         break;
+        default:
+          usage (0);
+        }
+    }
+
+  return &argv[optind];
+}
+
 static void
-ranlib_main(int argc, char **argv)
+ranlib_main (int argc, char **argv)
 {
   int arg_index, status = 0;
   bfd_boolean touch = FALSE;
+  int c;
 
-  if (argc > 1 && argv[1][0] == '-')
+  while ((c = getopt_long (argc, argv, "hHvVt", long_options, NULL)) != EOF)
     {
-      if (strcmp (argv[1], "--help") == 0)
-       ranlib_usage (1);
-      else if (strcmp (argv[1], "--version") == 0)
-       {
-         print_version ("ranlib");
-       }
+      switch (c)
+        {
+       case 'h':
+       case 'H':
+         show_help = 1;
+         break;
+       case 't':
+         touch = TRUE;
+         break;
+       case 'v':
+       case 'V':
+         show_version = 1;
+         break;
+        }
     }
 
-  if (argc < 2
-      || strcmp (argv[1], "--help") == 0
-      || strcmp (argv[1], "-h") == 0
-      || strcmp (argv[1], "-H") == 0)
+  if (argc < 2)
     ranlib_usage (0);
 
-  if (strcmp (argv[1], "-V") == 0
-      || strcmp (argv[1], "-v") == 0
-      || CONST_STRNEQ (argv[1], "--v"))
+  if (show_help)
+    usage (1);
+
+  if (show_version)
     print_version ("ranlib");
-  arg_index = 1;
 
-  if (strcmp (argv[1], "-t") == 0)
-    {
-      ++arg_index;
-      touch = TRUE;
-    }
+  arg_index = optind;
 
   while (arg_index < argc)
     {
@@ -400,28 +600,16 @@ ranlib_main(int argc, char **argv)
   xexit (status);
 }
 
-/* The option parsing should be in its own function.
-   It will be when I have getopt working.  */
-
 int main (int, char **);
 
 int
 main (int argc, char **argv)
 {
-  char *arg_ptr;
-  char c;
-  enum
-    {
-      none = 0, del, replace, print_table,
-      print_files, extract, move, quick_append
-    } operation = none;
   int arg_index;
   char **files;
   int file_count;
   char *inarch_filename;
-  int show_version;
   int i;
-  int do_posix = 0;
 
 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
   setlocale (LC_MESSAGES, "");
@@ -451,14 +639,11 @@ main (int argc, char **argv)
        is_ranlib = 0;
     }
 
-
   START_PROGRESS (program_name, 0);
 
   bfd_init ();
   set_default_bfd_target ();
 
-  show_version = 0;
-
   xatexit (remove_output);
 
   for (i = 1; i < argc; i++)
@@ -468,169 +653,20 @@ main (int argc, char **argv)
   argc -= (i - 1);
 
   if (is_ranlib)
-    ranlib_main(argc, argv);
-
-  if (argc > 1 && argv[1][0] == '-')
-    {
-      if (strcmp (argv[1], "--help") == 0)
-       usage (1);
-      else if (strcmp (argv[1], "--version") == 0)
-       print_version ("ar");
-    }
-
-  if (argc == 2 && strcmp (argv[1], "-M") == 0)
-    {
-      mri_emul ();
-      xexit (0);
-    }
+    ranlib_main (argc, argv);
 
   if (argc < 2)
     usage (0);
 
-  arg_index = 1;
-  arg_ptr = argv[arg_index];
-
-  if (strcmp (arg_ptr, "--plugin") == 0)
-    {
-#if BFD_SUPPORTS_PLUGINS
-      if (argc < 4)
-       usage (1);
-
-      bfd_plugin_set_plugin (argv[2]);
-
-      arg_index += 2;
-      arg_ptr = argv[arg_index];
-
-      plugin_target = "plugin";
-#else
-      fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
-      xexit (1);
-#endif
-    }
+  argv = decode_options (argc, argv);
 
-  if (*arg_ptr == '-')
-    {
-      /* When the first option starts with '-' we support POSIX-compatible
-        option parsing.  */
-      do_posix = 1;
-      ++arg_ptr;                       /* compatibility */
-    }
-
-  do
-    {
-      while ((c = *arg_ptr++) != '\0')
-       {
-         switch (c)
-           {
-           case 'd':
-           case 'm':
-           case 'p':
-           case 'q':
-           case 'r':
-           case 't':
-           case 'x':
-             if (operation != none)
-               fatal (_("two different operation options specified"));
-             switch (c)
-               {
-               case 'd':
-                 operation = del;
-                 operation_alters_arch = TRUE;
-                 break;
-               case 'm':
-                 operation = move;
-                 operation_alters_arch = TRUE;
-                 break;
-               case 'p':
-                 operation = print_files;
-                 break;
-               case 'q':
-                 operation = quick_append;
-                 operation_alters_arch = TRUE;
-                 break;
-               case 'r':
-                 operation = replace;
-                 operation_alters_arch = TRUE;
-                 break;
-               case 't':
-                 operation = print_table;
-                 break;
-               case 'x':
-                 operation = extract;
-                 break;
-               }
-           case 'l':
-             break;
-           case 'c':
-             silent_create = 1;
-             break;
-           case 'o':
-             preserve_dates = 1;
-             break;
-           case 'V':
-             show_version = TRUE;
-             break;
-           case 's':
-             write_armap = 1;
-             break;
-           case 'S':
-             write_armap = -1;
-             break;
-           case 'u':
-             newer_only = 1;
-             break;
-           case 'v':
-             verbose = 1;
-             break;
-           case 'a':
-             postype = pos_after;
-             break;
-           case 'b':
-             postype = pos_before;
-             break;
-           case 'i':
-             postype = pos_before;
-             break;
-           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;
-           case 'T':
-             make_thin_archive = TRUE;
-             break;
-           case 'D':
-             deterministic = TRUE;
-             break;
-           default:
-             /* xgettext:c-format */
-             non_fatal (_("illegal option -- %c"), c);
-             usage (0);
-           }
-       }
-
-      /* With POSIX-compatible option parsing continue with the next
-        argument if it starts with '-'.  */
-      if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-')
-       arg_ptr = argv[++arg_index] + 1;
-      else
-       do_posix = 0;
-    }
-  while (do_posix);
+  if (show_help)
+    usage (1);
 
   if (show_version)
     print_version ("ar");
 
-  ++arg_index;
-  if (arg_index >= argc)
-    usage (0);
+  arg_index = 0;
 
   if (mri_mode)
     {
@@ -668,7 +704,7 @@ main (int argc, char **argv)
       if (counted_name_mode)
        {
          if (operation != extract && operation != del)
-            fatal (_("`N' is only meaningful with the `x' and `d' options."));
+           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."));
@@ -676,8 +712,10 @@ main (int argc, char **argv)
 
       inarch_filename = argv[arg_index++];
 
-      files = arg_index < argc ? argv + arg_index : NULL;
-      file_count = argc - arg_index;
+      for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++)
+       continue;
+
+      files = (file_count > 0) ? argv + arg_index : NULL;
 
       arch = open_inarch (inarch_filename,
                          files == NULL ? (char *) NULL : files[0]);
@@ -707,11 +745,17 @@ main (int argc, char **argv)
          break;
 
        case move:
-         if (files != NULL)
-           move_members (arch, files);
-         else
-           output_filename = NULL;
-         break;
+         /* PR 12558: Creating and moving at the same time does
+            not make sense.  Just create the archive instead.  */
+         if (! silent_create)
+           {
+             if (files != NULL)
+               move_members (arch, files);
+             else
+               output_filename = NULL;
+             break;
+           }
+         /* Fall through.  */
 
        case replace:
        case quick_append:
@@ -737,7 +781,6 @@ main (int argc, char **argv)
 bfd *
 open_inarch (const char *archive_filename, const char *file)
 {
-  const char *target;
   bfd **last_one;
   bfd *next_one;
   struct stat sbuf;
@@ -746,7 +789,8 @@ open_inarch (const char *archive_filename, const char *file)
 
   bfd_set_error (bfd_error_no_error);
 
-  target = plugin_target;
+  if (target == NULL)
+    target = plugin_target;
 
   if (stat (archive_filename, &sbuf) != 0)
     {
@@ -757,8 +801,8 @@ open_inarch (const char *archive_filename, const char *file)
         stat() works just fine in v2.x, so I think this should be
         removed.  For now, I enable it for DJGPP v2. -- EZ.  */
 
-/* KLUDGE ALERT! Temporary fix until I figger why
-   stat() is wrong ... think it's buried in GO32's IDT - Jax */
+      /* KLUDGE ALERT! Temporary fix until I figger why
+        stat() is wrong ... think it's buried in GO32's IDT - Jax */
       if (errno != ENOENT)
        bfd_fatal (archive_filename);
 #endif
@@ -1031,6 +1075,7 @@ write_archive (bfd *iarch)
 
   if (smart_rename (new_name, old_name, 0) != 0)
     xexit (1);
+  free (old_name);
 }
 
 /* Return a pointer to the pointer to the entry which should be rplacd'd
@@ -1234,7 +1279,7 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
                  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
                                           current->filename);
                  if (ar_emul_replace (after_bfd, *files_to_move,
-                                      plugin_target, verbose))
+                                      target, verbose))
                    {
                      /* Snip out this entry from the chain.  */
                      *current_ptr = (*current_ptr)->archive_next;
@@ -1250,7 +1295,7 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
       /* Add to the end of the archive.  */
       after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
 
-      if (ar_emul_append (after_bfd, *files_to_move, plugin_target,
+      if (ar_emul_append (after_bfd, *files_to_move, target,
                          verbose, make_thin_archive))
        changed = TRUE;