/* 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.
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
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 */
#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));
+
+/* Static declarations */
+
+static void
+mri_emul PARAMS ((void));
-/* Forward declarations */
+static const char *
+normalize PARAMS ((const char *, bfd *));
static void
remove_output PARAMS ((void));
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));
static void
ranlib_touch PARAMS ((const char *archname));
+
+static void
+usage PARAMS ((int));
\f
/** Globals and flags */
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));
int count;
{
bfd *head;
+ int match_count;
if (count == 0)
{
}
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
{
boolean found = false;
+ match_count = 0;
for (head = arch->next; head; head = head->next)
{
PROGRESS (1);
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);
+ /* xgettext:c-format */
+ fprintf (s, _("Usage: %s [-vV] archive\n"), program_name);
+
list_supported_targets (program_name, stderr);
- xexit (1);
+
+ 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;
} 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)
{
}
xexit (0);
}
- else
- is_ranlib = 0;
if (argc == 2 && strcmp (argv[1], "-M") == 0)
{
}
if (argc < 2)
- usage ();
+ usage (0);
arg_ptr = argv[1];
case 't':
case 'x':
if (operation != none)
- fatal ("two different operation options specified");
+ fatal (_("two different operation options specified"));
switch (c)
{
case 'd':
case 's':
write_armap = 1;
break;
+ case 'S':
+ write_armap = -1;
+ break;
case 'u':
newer_only = 1;
break;
case 'M':
mri_mode = 1;
break;
+ case 'N':
+ counted_name_mode = true;
+ break;
case 'f':
- /* On HP/UX 9, the f modifier means to truncate names to 14
- characters when comparing them to existing names. We
- always use an extended name table, so the truncation has
- no purpose for us. We ignore the modifier for
- compatibility with the AR_FLAGS definition in make. */
+ 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)
{
}
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;
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);
}
}
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
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;
- do_quick_append (archive_filename, 0);
+ 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);
+
+ /* 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);
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);
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;
FILE *ostream;
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);
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);
ncopied += tocopy;
}
- fclose (ostream);
+ if (ostream != NULL)
+ fclose (ostream);
output_file = NULL;
output_filename = NULL;
chmod (bfd_get_filename (abfd), buf.st_mode);
if (preserve_dates)
- {
-#if 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 */
- }
-free (cbuf);
+ 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
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);
free (buf);
}
+#endif /* 0 */
static void
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);
/* 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)
{
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;
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
}
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;
}
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. */
*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;
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:;
/* 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;
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),
- normalize (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)
}
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
bfd *arch;
write_armap = 1;
- arch = open_inarch (archname);
+ arch = open_inarch (archname, (char *) NULL);
if (arch == NULL)
xexit (1);
write_archive (arch);
#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);
}
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);