/* ar.c - Archive modify and extract. Copyright (C) 1991-2026 Free Software Foundation, Inc. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. *//* 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 "getopt.h"#include "aout/ar.h"#include "bucomm.h"#include "arsup.h"#include "filenames.h"#include "binemul.h"#include "plugin.h" #ifdef __GO32___#define EXT_NAME_LEN 3 /* Bufflen of addition to name if it's MS-DOS. */#else#define EXT_NAME_LEN 6 /* Ditto for *NIX. */#endif /* Forward declarations. */ static const char *normalize (const char *, bfd *);static void print_contents (bfd * member);static void delete_members (bfd *, char **files_to_delete); static void move_members (bfd *, char **files_to_move);static void replace_members (bfd *, char **files_to_replace, bool quick);static void print_descr (bfd * abfd);static void write_archive (bfd *);static int ranlib_only (const char *archname);static int ranlib_touch (const char *archname); /** Globals and flags. */ static int mri_mode; /* This flag distinguishes between ar and ranlib: 1 means this is 'ranlib'; 0 means this is 'ar'. -1 means if we should use argv[0] to decide. */#ifndef is_ranlibextern int is_ranlib;#endif /* Nonzero means don't warn about creating the archive file if necessary. */int silent_create = 0; /* Nonzero means describe each action performed. */int verbose = 0; /* Nonzero means display offsets of files in the archive. */int display_offsets = 0; /* Nonzero means preserve dates of members when extracting them. */int preserve_dates = 0; /* Nonzero means don't replace existing members whose dates are more recent than the corresponding files. */int newer_only = 0; /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF member). -1 means we've been explicitly asked to not write a symbol table; +1 means we've been explicitly asked to write it; 0 is the default. Traditionally, the default in BSD has been to not write the table. However, for POSIX.2 compliance the default is now to write a symbol table if any of the members are object files. */int write_armap = 0; /* Operate in deterministic mode: write zero for timestamps, uids, and gids for archive members and the archive symbol table, and write consistent file modes. */int deterministic = -1; /* Determinism indeterminate. */ /* Nonzero means it's the name of an existing member; position new or moved files with respect to this one. */char *posname = NULL; /* Sez how to use `posname': pos_before means position before that member. pos_after means position after that member. pos_end means always at end. pos_default means default appropriately. For the latter two, `posname' should also be zero. */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 *); /* For extract/delete only. If COUNTED_NAME_MODE is TRUE, we only extract the COUNTED_NAME_COUNTER instance of that name. */static bool counted_name_mode = 0;static int counted_name_counter = 0; /* Whether to truncate names of files stored in the archive. */static bool 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 bool full_pathname = false; /* Whether to create a "thin" archive (symbol index only -- no files). */static bool make_thin_archive = false; #define LIBDEPS "__.LIBDEP"/* Text to store in the __.LIBDEP archive element for the linker to use. */static char * libdeps = NULL;static bfd * libdeps_bfd = NULL; static int show_version = 0; static int show_help = 0; static const char *target = NULL; enum long_option_numbers{ OPTION_PLUGIN = 201, OPTION_TARGET, OPTION_OUTPUT}; static const char * output_dir = NULL; 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}, {"output", required_argument, NULL, OPTION_OUTPUT}, {"record-libdeps", required_argument, NULL, 'l'}, {"thin", no_argument, NULL, 'T'}, {NULL, no_argument, NULL, 0}}; int interactive = 0; static voidmri_emul (void){ interactive = isatty (fileno (stdin)); yyparse ();} /* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero, COUNT is the length of the FILES chain; FUNCTION is called on each entry whose name matches one in FILES. */ static voidmap_over_members (bfd *arch, void (*function)(bfd *), char **files, int count){ bfd *head; int match_count; if (count == 0) { for (head = arch->archive_next; head; head = head->archive_next) 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 mapping over each file each time -- we want to hack multiple references. */ for (head = arch->archive_next; head; head = head->archive_next) head->archive_pass = 0; for (; count > 0; files++, count--) { bool found = false; match_count = 0; for (head = arch->archive_next; head; head = head->archive_next) { const char * filename; /* PR binutils/15796: Once an archive element has been matched do not match it again. If the user provides multiple same-named parameters on the command line their intent is to match multiple same-named entries in the archive, not the same entry multiple times. */ if (head->archive_pass) continue; filename = bfd_get_filename (head); if (filename == NULL) { /* Some archive formats don't get the filenames filled in until the elements are opened. */ struct stat buf; bfd_stat_arch_elt (head, &buf); } else if (bfd_is_thin_archive (arch)) { /* Thin archives store full pathnames. Need to normalize. */ filename = normalize (filename, arch); } if (filename != NULL && !FILENAME_CMP (normalize (*files, arch), 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); head->archive_pass = 1; /* PR binutils/15796: Once a file has been matched, do not match any more same-named files in the archive. If the user does want to match multiple same-name files in an archive they should provide multiple same-name parameters to the ar command. */ break; } } if (!found) /* xgettext:c-format */ fprintf (stderr, _("no entry %s in archive\n"), *files); }}bool operation_alters_arch = false; static voidusage (int help){ FILE *s; const char *command_line; if (bfd_plugin_enabled ()) /* xgettext:c-format */ command_line = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" " [--plugin <name>] [member-name] [count] archive-file file...\n"); else /* xgettext:c-format */ command_line = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" " [member-name] [count] archive-file file...\n"); s = help ? stdout : stderr; fprintf (s, command_line, 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, _(" s - act as ranlib\n")); fprintf (s, _(" t[O][v] - display contents of the 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")); if (DEFAULT_AR_DETERMINISTIC) { fprintf (s, _("\ [D] - use zero for timestamps and uids/gids (default)\n")); fprintf (s, _("\ [U] - use actual timestamps and uids/gids\n")); } else { fprintf (s, _("\ [D] - use zero for timestamps and uids/gids\n")); fprintf (s, _("\ [U] - use actual timestamps and uids/gids (default)\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, _(" [O] - display offsets of files in the archive\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, _(" [l <text> ] - specify the dependencies of this library\n")); fprintf (s, _(" [S] - do not build a symbol table\n")); fprintf (s, _(" [T] - deprecated, use --thin instead\n")); 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")); fprintf (s, _(" --output=DIRNAME - specify the output directory for extraction operations\n")); fprintf (s, _(" --record-libdeps=<text> - specify the dependencies of this library\n")); fprintf (s, _(" --thin - make a thin archive\n")); if (bfd_plugin_enabled ()) { fprintf (s, _(" optional:\n")); fprintf (s, _(" --plugin <p> - load the specified plugin\n")); } ar_emul_usage (s); list_supported_targets (program_name, s); if (REPORT_BUGS_TO[0] && help) fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); xexit (help ? 0 : 1);} static voidranlib_usage (int help){ FILE *s; s = help ? stdout : stderr; /* xgettext:c-format */ fprintf (s, _("Usage: %s [options] archive\n"), program_name); fprintf (s, _(" Generate an index to speed access to archives\n")); fprintf (s, _(" The options are:\n\ @<file> Read options from <file>\n")); if (bfd_plugin_enabled ()) fprintf (s, _("\ --plugin <name> Load the specified plugin\n")); if (DEFAULT_AR_DETERMINISTIC) fprintf (s, _("\ -D Use zero for symbol map timestamp (default)\n\ -U Use an actual symbol map timestamp\n")); else fprintf (s, _("\ -D Use zero for symbol map timestamp\n\ -U Use actual symbol map timestamp (default)\n")); fprintf (s, _("\ -t Update the archive's symbol map timestamp\n\ -h --help Print this help message\n\ -v --version Print version information\n")); list_supported_targets (program_name, s); if (REPORT_BUGS_TO[0] && help) fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); 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 const char *normalize (const char *file, bfd *abfd){ const char *filename; if (full_pathname) return file; filename = lbasename (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 voidremove_output (void){ if (output_filename != NULL) { if (output_file != NULL) fclose (output_file); unlink_if_ordinary (output_filename); free (output_filename); output_filename = NULL; }} static char **decode_options (int argc, char **argv){ int c; /* Convert old-style ar call by exploding option element and rearranging options accordingly. */ restart: 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, "hdmpqrtxl:coOVsSuvabiMNfPTDU", 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; } Lines 1–500 of 1661. Load more
/* ar.c - Archive modify and extract. Copyright (C) 1991-2026 Free Software Foundation, Inc. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* 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 "getopt.h" #include "aout/ar.h" #include "bucomm.h" #include "arsup.h" #include "filenames.h" #include "binemul.h" #include "plugin.h" #ifdef __GO32___ #define EXT_NAME_LEN 3 /* Bufflen of addition to name if it's MS-DOS. */ #else #define EXT_NAME_LEN 6 /* Ditto for *NIX. */ #endif /* Forward declarations. */ static const char *normalize (const char *, bfd *); static void print_contents (bfd * member); static void delete_members (bfd *, char **files_to_delete); static void move_members (bfd *, char **files_to_move); static void replace_members (bfd *, char **files_to_replace, bool quick); static void print_descr (bfd * abfd); static void write_archive (bfd *); static int ranlib_only (const char *archname); static int ranlib_touch (const char *archname); /** Globals and flags. */ static int mri_mode; /* This flag distinguishes between ar and ranlib: 1 means this is 'ranlib'; 0 means this is 'ar'. -1 means if we should use argv[0] to decide. */ #ifndef is_ranlib extern int is_ranlib; #endif /* Nonzero means don't warn about creating the archive file if necessary. */ int silent_create = 0; /* Nonzero means describe each action performed. */ int verbose = 0; /* Nonzero means display offsets of files in the archive. */ int display_offsets = 0; /* Nonzero means preserve dates of members when extracting them. */ int preserve_dates = 0; /* Nonzero means don't replace existing members whose dates are more recent than the corresponding files. */ int newer_only = 0; /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF member). -1 means we've been explicitly asked to not write a symbol table; +1 means we've been explicitly asked to write it; 0 is the default. Traditionally, the default in BSD has been to not write the table. However, for POSIX.2 compliance the default is now to write a symbol table if any of the members are object files. */ int write_armap = 0; /* Operate in deterministic mode: write zero for timestamps, uids, and gids for archive members and the archive symbol table, and write consistent file modes. */ int deterministic = -1; /* Determinism indeterminate. */ /* Nonzero means it's the name of an existing member; position new or moved files with respect to this one. */ char *posname = NULL; /* Sez how to use `posname': pos_before means position before that member. pos_after means position after that member. pos_end means always at end. pos_default means default appropriately. For the latter two, `posname' should also be zero. */ 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 *); /* For extract/delete only. If COUNTED_NAME_MODE is TRUE, we only extract the COUNTED_NAME_COUNTER instance of that name. */ static bool counted_name_mode = 0; static int counted_name_counter = 0; /* Whether to truncate names of files stored in the archive. */ static bool 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 bool full_pathname = false; /* Whether to create a "thin" archive (symbol index only -- no files). */ static bool make_thin_archive = false; #define LIBDEPS "__.LIBDEP" /* Text to store in the __.LIBDEP archive element for the linker to use. */ static char * libdeps = NULL; static bfd * libdeps_bfd = NULL; static int show_version = 0; static int show_help = 0; static const char *target = NULL; enum long_option_numbers { OPTION_PLUGIN = 201, OPTION_TARGET, OPTION_OUTPUT }; static const char * output_dir = NULL; 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}, {"output", required_argument, NULL, OPTION_OUTPUT}, {"record-libdeps", required_argument, NULL, 'l'}, {"thin", no_argument, NULL, 'T'}, {NULL, no_argument, NULL, 0} }; int interactive = 0; static void mri_emul (void) { interactive = isatty (fileno (stdin)); yyparse (); } /* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero, COUNT is the length of the FILES chain; FUNCTION is called on each entry whose name matches one in FILES. */ static void map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count) { bfd *head; int match_count; if (count == 0) { for (head = arch->archive_next; head; head = head->archive_next) 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 mapping over each file each time -- we want to hack multiple references. */ for (head = arch->archive_next; head; head = head->archive_next) head->archive_pass = 0; for (; count > 0; files++, count--) { bool found = false; match_count = 0; for (head = arch->archive_next; head; head = head->archive_next) { const char * filename; /* PR binutils/15796: Once an archive element has been matched do not match it again. If the user provides multiple same-named parameters on the command line their intent is to match multiple same-named entries in the archive, not the same entry multiple times. */ if (head->archive_pass) continue; filename = bfd_get_filename (head); if (filename == NULL) { /* Some archive formats don't get the filenames filled in until the elements are opened. */ struct stat buf; bfd_stat_arch_elt (head, &buf); } else if (bfd_is_thin_archive (arch)) { /* Thin archives store full pathnames. Need to normalize. */ filename = normalize (filename, arch); } if (filename != NULL && !FILENAME_CMP (normalize (*files, arch), 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); head->archive_pass = 1; /* PR binutils/15796: Once a file has been matched, do not match any more same-named files in the archive. If the user does want to match multiple same-name files in an archive they should provide multiple same-name parameters to the ar command. */ break; } } if (!found) /* xgettext:c-format */ fprintf (stderr, _("no entry %s in archive\n"), *files); } } bool operation_alters_arch = false; static void usage (int help) { FILE *s; const char *command_line; if (bfd_plugin_enabled ()) /* xgettext:c-format */ command_line = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" " [--plugin <name>] [member-name] [count] archive-file file...\n"); else /* xgettext:c-format */ command_line = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" " [member-name] [count] archive-file file...\n"); s = help ? stdout : stderr; fprintf (s, command_line, 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, _(" s - act as ranlib\n")); fprintf (s, _(" t[O][v] - display contents of the 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")); if (DEFAULT_AR_DETERMINISTIC) { fprintf (s, _("\ [D] - use zero for timestamps and uids/gids (default)\n")); fprintf (s, _("\ [U] - use actual timestamps and uids/gids\n")); } else { fprintf (s, _("\ [D] - use zero for timestamps and uids/gids\n")); fprintf (s, _("\ [U] - use actual timestamps and uids/gids (default)\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, _(" [O] - display offsets of files in the archive\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, _(" [l <text> ] - specify the dependencies of this library\n")); fprintf (s, _(" [S] - do not build a symbol table\n")); fprintf (s, _(" [T] - deprecated, use --thin instead\n")); 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")); fprintf (s, _(" --output=DIRNAME - specify the output directory for extraction operations\n")); fprintf (s, _(" --record-libdeps=<text> - specify the dependencies of this library\n")); fprintf (s, _(" --thin - make a thin archive\n")); if (bfd_plugin_enabled ()) { fprintf (s, _(" optional:\n")); fprintf (s, _(" --plugin <p> - load the specified plugin\n")); } ar_emul_usage (s); list_supported_targets (program_name, s); if (REPORT_BUGS_TO[0] && help) fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); xexit (help ? 0 : 1); } static void ranlib_usage (int help) { FILE *s; s = help ? stdout : stderr; /* xgettext:c-format */ fprintf (s, _("Usage: %s [options] archive\n"), program_name); fprintf (s, _(" Generate an index to speed access to archives\n")); fprintf (s, _(" The options are:\n\ @<file> Read options from <file>\n")); if (bfd_plugin_enabled ()) fprintf (s, _("\ --plugin <name> Load the specified plugin\n")); if (DEFAULT_AR_DETERMINISTIC) fprintf (s, _("\ -D Use zero for symbol map timestamp (default)\n\ -U Use an actual symbol map timestamp\n")); else fprintf (s, _("\ -D Use zero for symbol map timestamp\n\ -U Use actual symbol map timestamp (default)\n")); fprintf (s, _("\ -t Update the archive's symbol map timestamp\n\ -h --help Print this help message\n\ -v --version Print version information\n")); list_supported_targets (program_name, s); if (REPORT_BUGS_TO[0] && help) fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); 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 const char * normalize (const char *file, bfd *abfd) { const char *filename; if (full_pathname) return file; filename = lbasename (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 void remove_output (void) { if (output_filename != NULL) { if (output_file != NULL) fclose (output_file); unlink_if_ordinary (output_filename); free (output_filename); output_filename = NULL; } } static char ** decode_options (int argc, char **argv) { int c; /* Convert old-style ar call by exploding option element and rearranging options accordingly. */ restart: 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, "hdmpqrtxl:coOVsSuvabiMNfPTDU", 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; }