*/
#include "bfd.h"
#include "sysdep.h"
+#include "libiberty.h"
+#include "progress.h"
#include "bucomm.h"
#include "aout/ar.h"
#include "libbfd.h"
/* Forward declarations */
+static const char *
+normalize PARAMS ((const char *, bfd *));
+
+static void
+remove_output PARAMS ((void));
+
+static void
+map_over_members PARAMS ((bfd *, void (*)(bfd *), char **, int));
+
static void
print_contents PARAMS ((bfd * member));
static void
-delete_members PARAMS ((char **files_to_delete));
+delete_members PARAMS ((bfd *, char **files_to_delete));
static void
-do_quick_append PARAMS ((char *archive_filename, char **files_to_append));
+do_quick_append PARAMS ((const char *archive_filename,
+ char **files_to_append));
static void
-move_members PARAMS ((char **files_to_move));
+move_members PARAMS ((bfd *, char **files_to_move));
static void
-replace_members PARAMS ((char **files_to_replace));
+replace_members PARAMS ((bfd *, char **files_to_replace));
static void
print_descr PARAMS ((bfd * abfd));
static void
-ranlib_only PARAMS ((char *archname));
+write_archive PARAMS ((bfd *));
+
+static void
+ranlib_only PARAMS ((const char *archname));
+
+static void
+ranlib_touch PARAMS ((const char *archname));
\f
/** Globals and flags */
-/* The input archive we're manipulating. */
-bfd *inarch;
-
int mri_mode;
/* This flag distinguishes between ar and ranlib:
pos_default, pos_before, pos_after, pos_end
} postype = pos_default;
+/* Whether to truncate names of files stored in the archive. */
+static boolean ar_truncate = false;
+
int interactive = 0;
void
COUNT is the length of the FILES chain; FUNCTION is called on each entry
whose name matches one in FILES. */
-void
-map_over_members (function, files, count)
- void (*function) ();
+static void
+map_over_members (arch, function, files, count)
+ bfd *arch;
+ void (*function) PARAMS ((bfd *));
char **files;
int count;
{
if (count == 0)
{
- for (head = inarch->next; head; head = head->next)
- function (head);
+ for (head = arch->next; head; head = head->next)
+ {
+ PROGRESS (1);
+ function (head);
+ }
return;
}
/* This may appear to be a baroque way of accomplishing what we want.
for (; count > 0; files++, count--)
{
boolean found = false;
- for (head = inarch->next; head; head = head->next)
+
+ for (head = arch->next; head; head = head->next)
{
+ PROGRESS (1);
if (head->filename == NULL)
{
/* Some archive formats don't get the filenames filled in
do_show_version ()
{
printf ("GNU %s version %s\n", program_name, program_version);
- exit (0);
+ xexit (0);
}
void
else
fprintf (stderr, "\
Usage: %s [-vV] archive\n", program_name);
- exit (1);
+ list_supported_targets (program_name, stderr);
+ xexit (1);
+}
+
+/* Normalize a file name specified on the command line into a file
+ name which we will use in an archive. */
+
+static const char *
+normalize (file, abfd)
+ const char *file;
+ bfd *abfd;
+{
+ const char *filename;
+
+ filename = strrchr (file, '/');
+ if (filename != (char *) NULL)
+ filename++;
+ else
+ filename = file;
+
+ if (ar_truncate
+ && abfd != NULL
+ && strlen (filename) > abfd->xvec->ar_max_namelen)
+ {
+ 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 FILE *output_file = NULL;
+static bfd *output_bfd = NULL;
+
+static void
+remove_output ()
+{
+ if (output_filename != NULL)
+ {
+ if (output_bfd != NULL && output_bfd->iostream != NULL)
+ fclose ((FILE *) (output_bfd->iostream));
+ if (output_file != NULL)
+ fclose (output_file);
+ unlink (output_filename);
+ }
}
/* The option parsing should be in its own function.
program_name = argv[0];
xmalloc_set_program_name (program_name);
+ START_PROGRESS (program_name, 0);
+
bfd_init ();
show_version = 0;
+ xatexit (remove_output);
+
temp = strrchr (program_name, '/');
if (temp == (char *) NULL)
temp = program_name; /* shouldn't happen, but... */
++temp;
if (is_ranlib > 0 || (is_ranlib < 0 && strcmp (temp, "ranlib") == 0))
{
+ boolean touch = false;
+
is_ranlib = 1;
- if (argc < 2 || argc > 3)
+ if (argc < 2)
usage ();
- arg_ptr = argv[1];
- if (strcmp (argv[1], "-V") == 0 || strcmp (argv[1], "-v") == 0)
+ if (strcmp (argv[1], "-V") == 0
+ || strcmp (argv[1], "-v") == 0
+ || strncmp (argv[1], "--v", 3) == 0)
do_show_version ();
- ranlib_only (arg_ptr);
+ arg_index = 1;
+ if (strcmp (argv[1], "-t") == 0)
+ {
+ ++arg_index;
+ touch = true;
+ }
+ while (arg_index < argc)
+ {
+ if (! touch)
+ ranlib_only (argv[arg_index]);
+ else
+ ranlib_touch (argv[arg_index]);
+ ++arg_index;
+ }
+ xexit (0);
}
else
is_ranlib = 0;
if (argc == 2 && strcmp (argv[1], "-M") == 0)
{
mri_emul ();
- exit (0);
+ xexit (0);
}
if (argc < 2)
case 'M':
mri_mode = 1;
break;
+ case 'f':
+ ar_truncate = true;
+ break;
default:
fprintf (stderr, "%s: illegal option -- %c\n", program_name, c);
usage ();
}
else
{
+ bfd *arch;
+
+ /* We can't write an armap when using ar q, so just do ar r
+ instead. */
+ if (operation == quick_append && write_armap)
+ operation = replace;
+
if ((operation == none || operation == print_table)
&& write_armap == 1)
- ranlib_only (argv[2]);
+ {
+ ranlib_only (argv[2]);
+ xexit (0);
+ }
if (operation == none)
fatal ("no operation specified");
files = arg_index < argc ? argv + arg_index : NULL;
+ /* 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 && ! ar_truncate)
+ {
+ char **chk;
+
+ for (chk = files; chk != NULL && *chk != '\0'; chk++)
+ {
+ if (strlen (normalize (*chk, (bfd *) NULL)) > 14)
+ {
+ operation = replace;
+ break;
+ }
+ }
+ }
+
if (operation == quick_append)
{
/* Note that quick appending to a non-existent archive creates it,
even if there are no files to append. */
do_quick_append (inarch_filename, files);
- exit (0);
+ xexit (0);
}
- open_inarch (inarch_filename);
+ arch = open_inarch (inarch_filename);
switch (operation)
{
case print_table:
- map_over_members (print_descr, files, argc - 3);
+ map_over_members (arch, print_descr, files, argc - 3);
break;
case print_files:
- map_over_members (print_contents, files, argc - 3);
+ map_over_members (arch, print_contents, files, argc - 3);
break;
case extract:
- map_over_members (extract_file, files, argc - 3);
+ map_over_members (arch, extract_file, files, argc - 3);
break;
case delete:
if (files != NULL)
- delete_members (files);
+ delete_members (arch, files);
break;
case move:
if (files != NULL)
- move_members (files);
+ move_members (arch, files);
break;
case replace:
if (files != NULL || write_armap > 0)
- replace_members (files);
+ replace_members (arch, files);
break;
/* Shouldn't happen! */
default:
fprintf (stderr, "%s: internal error -- this option not implemented\n",
program_name);
- exit (1);
+ xexit (1);
}
}
- return 0;
-}
-static char *
-normalize (file)
- char *file;
-{
- char *filename = strrchr (file, '/');
- if (filename != (char *) NULL)
- {
- filename++;
- }
- else
- {
- filename = file;
- }
- return filename;
+ END_PROGRESS (program_name);
+
+ xexit (0);
+ return 0;
}
-int
+bfd *
open_inarch (archive_filename)
- char *archive_filename;
+ const char *archive_filename;
{
bfd **last_one;
bfd *next_one;
struct stat sbuf;
+ bfd *arch;
+
bfd_set_error (bfd_error_no_error);
if (stat (archive_filename, &sbuf) != 0)
fprintf (stderr, "%s: ", program_name);
perror (archive_filename);
maybequit ();
- return 0;
+ return NULL;
}
/* This routine is one way to forcibly create the archive. */
do_quick_append (archive_filename, 0);
}
- inarch = bfd_openr (archive_filename, NULL);
- if (inarch == NULL)
+ arch = bfd_openr (archive_filename, NULL);
+ if (arch == NULL)
{
bloser:
bfd_fatal (archive_filename);
}
- if (bfd_check_format (inarch, bfd_archive) != true)
+ if (bfd_check_format (arch, bfd_archive) != true)
fatal ("%s is not an archive", archive_filename);
- last_one = &(inarch->next);
+ last_one = &(arch->next);
/* Read all the contents right away, regardless. */
- for (next_one = bfd_openr_next_archived_file (inarch, NULL);
+ for (next_one = bfd_openr_next_archived_file (arch, NULL);
next_one;
- next_one = bfd_openr_next_archived_file (inarch, next_one))
+ next_one = bfd_openr_next_archived_file (arch, next_one))
{
+ PROGRESS (1);
*last_one = next_one;
last_one = &next_one->next;
}
*last_one = (bfd *) NULL;
if (bfd_get_error () != bfd_error_no_more_archived_files)
goto bloser;
- return 1;
+ return arch;
}
static void
bfd *abfd;
{
int ncopied = 0;
+ char *cbuf = xmalloc (BUFSIZE);
struct stat buf;
long size;
if (bfd_stat_arch_elt (abfd, &buf) != 0)
size = buf.st_size;
while (ncopied < size)
{
- char cbuf[BUFSIZE];
+
int nread;
int tocopy = size - ncopied;
if (tocopy > BUFSIZE)
fwrite (cbuf, 1, nread, stdout);
ncopied += tocopy;
}
+ free (cbuf);
}
/* Extract a member of the archive into its own file.
bfd *abfd;
{
FILE *ostream;
- char cbuf[BUFSIZE];
+ char *cbuf = xmalloc (BUFSIZE);
int nread, tocopy;
int ncopied = 0;
long size;
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)
{
perror (bfd_get_filename (abfd));
- exit (1);
+ xexit (1);
}
+
+ output_file = ostream;
}
else
while (ncopied < size)
if (!ostream)
{
/* 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)
{
perror (bfd_get_filename (abfd));
- exit (1);
+ xexit (1);
}
+
+ output_file = ostream;
}
fwrite (cbuf, 1, nread, ostream);
ncopied += tocopy;
}
fclose (ostream);
+
+ output_file = NULL;
+ output_filename = NULL;
+
chmod (bfd_get_filename (abfd), buf.st_mode);
if (preserve_dates)
#endif /* ! USE_UTIME */
#endif /* ! POSIX_UTIME */
}
+free (cbuf);
}
/* Just do it quickly; don't worry about dups, armap, or anything like that */
static void
do_quick_append (archive_filename, files_to_append)
- char *archive_filename;
+ const char *archive_filename;
char **files_to_append;
{
FILE *ofile, *ifile;
- char buf[BUFSIZE];
+ char *buf = xmalloc (BUFSIZE);
long tocopy, thistime;
bfd *temp;
struct stat sbuf;
if (ofile == NULL)
{
perror (program_name);
- exit (1);
+ xexit (1);
}
temp = bfd_openr (archive_filename, NULL);
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);
}
fclose (ofile);
bfd_close (temp);
+ free (buf);
}
-void
-write_archive ()
+static void
+write_archive (iarch)
+ bfd *iarch;
{
bfd *obfd;
- int namelen = strlen (inarch->filename);
- char *new_name = xmalloc (namelen + EXT_NAME_LEN);
- bfd *contents_head = inarch->next;
+ char *old_name, *new_name;
+ bfd *contents_head = iarch->next;
- strcpy (new_name, inarch->filename);
+ old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
+ strcpy (old_name, bfd_get_filename (iarch));
+ new_name = make_tempname (old_name);
-#ifdef __GO32__ /* avoid long .extensions for MS-DOS */
- strcpy (new_name + namelen, "-a");
-#else
- strcpy (new_name + namelen, "-art");
-#endif
+ output_filename = new_name;
- obfd = bfd_openw (new_name,
- /* FIXME: violates abstraction; need a better protocol */
- (inarch->xvec ? bfd_get_target (inarch) : NULL));
+ obfd = bfd_openw (new_name, bfd_get_target (iarch));
if (obfd == NULL)
- bfd_fatal (inarch->filename);
+ bfd_fatal (old_name);
+
+ output_bfd = obfd;
bfd_set_format (obfd, bfd_archive);
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 (inarch->filename);
+ bfd_fatal (old_name);
if (!bfd_close (obfd))
- bfd_fatal (inarch->filename);
+ bfd_fatal (old_name);
+
+ output_bfd = NULL;
+ output_filename = NULL;
/* We don't care if this fails; we might be creating the archive. */
- unlink (inarch->filename);
+ bfd_close (iarch);
+ unlink (old_name);
- if (rename (new_name, inarch->filename) != 0)
- bfd_fatal (inarch->filename);
+ if (rename (new_name, old_name) != 0)
+ bfd_fatal (old_name);
}
/* Return a pointer to the pointer to the entry which should be rplacd'd
}
static void
-delete_members (files_to_delete)
+delete_members (arch, files_to_delete)
+ bfd *arch;
char **files_to_delete;
{
bfd **current_ptr_ptr;
if (!strcmp (*files_to_delete, "__.SYMDEF"))
{
- inarch->has_armap = false;
+ arch->has_armap = false;
write_armap = -1;
continue;
}
found = false;
- current_ptr_ptr = &(inarch->next);
+ current_ptr_ptr = &(arch->next);
while (*current_ptr_ptr)
{
if (strcmp (*files_to_delete, (*current_ptr_ptr)->filename) == 0)
if (something_changed == true)
{
- write_archive ();
+ write_archive (arch);
}
}
/* Reposition existing members within an archive */
static void
-move_members (files_to_move)
+move_members (arch, files_to_move)
+ bfd *arch;
char **files_to_move;
{
bfd **after_bfd; /* New entries go after this one */
for (; *files_to_move; ++files_to_move)
{
- current_ptr_ptr = &(inarch->next);
+ current_ptr_ptr = &(arch->next);
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 (&inarch->next, pos_end);
+ after_bfd = get_pos_bfd (&arch->next, pos_end);
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",
- program_name, *files_to_move, inarch->filename);
- exit (1);
+ program_name, *files_to_move, arch->filename);
+ xexit (1);
next_file:;
}
- write_archive ();
+ write_archive (arch);
}
/* Ought to default to replacing in place, but this is existing practice! */
static void
-replace_members (files_to_move)
+replace_members (arch, files_to_move)
+ bfd *arch;
char **files_to_move;
{
bfd **after_bfd; /* New entries go after this one */
while (files_to_move && *files_to_move)
{
- current_ptr = &inarch->next;
+ current_ptr = &arch->next;
while (*current_ptr)
{
current = *current_ptr;
- if (!strcmp (normalize (*files_to_move), current->filename))
+ if (!strcmp (normalize (*files_to_move, arch),
+ normalize (current->filename, arch)))
{
if (newer_only)
{
/* snip out this entry from the chain */
*current_ptr = current->next;
- after_bfd = get_pos_bfd (&inarch->next, pos_end);
+ 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)
if (verbose)
{
- printf ("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
- *files_to_move);
+ printf ("r - %s\n", *files_to_move);
}
goto next_file;
}
/* It isn't in there, so add to end */
- after_bfd = get_pos_bfd (&inarch->next, pos_end);
+ 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)
}
if (verbose)
{
- printf ("c - %s\n", *files_to_move);
+ printf ("a - %s\n", *files_to_move);
}
(*after_bfd)->next = temp;
files_to_move++;
}
- write_archive ();
+ write_archive (arch);
}
static void
ranlib_only (archname)
- char *archname;
+ const char *archname;
{
+ bfd *arch;
+
write_armap = 1;
- open_inarch (archname);
- write_archive ();
- exit (0);
+ arch = open_inarch (archname);
+ if (arch == NULL)
+ xexit (1);
+ write_archive (arch);
+}
+
+/* Update the timestamp of the symbol map of an archive. */
+
+static void
+ranlib_touch (archname)
+ const char *archname;
+{
+#ifdef __GO32__
+ /* I don't think updating works on go32. */
+ ranlib_only (archname);
+#else
+ int f;
+ bfd *arch;
+
+ f = open (archname, O_RDWR, 0);
+ if (f < 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ bfd_fatal (archname);
+ }
+
+ arch = bfd_fdopenr (archname, (const char *) NULL, f);
+ if (arch == NULL
+ || ! bfd_check_format (arch, bfd_archive))
+ bfd_fatal (archname);
+
+ if (! bfd_has_map (arch))
+ fatal ("%s: no archive map to update", archname);
+
+ bfd_update_armap_timestamp (arch);
+
+ if (! bfd_close (arch))
+ bfd_fatal (archname);
+#endif
}
/* Things which are interesting to map over all or some of the files: */