Subversion Repositories Kolibri OS

Rev

Rev 5221 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5219 serge 1
/* ar.c - Archive modify and extract.
2
   Copyright 1991-2013 Free Software Foundation, Inc.
3
 
4
   This file is part of GNU Binutils.
5
 
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
 
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
 
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.  */
20
 
21
/*
22
   Bugs: GNU ar used to check file against filesystem in quick_update and
23
   replace operations (would check mtime). Doesn't warn when name truncated.
24
   No way to specify pos_end. Error messages should be more consistent.  */
25
 
26
#include "sysdep.h"
27
#include "bfd.h"
28
#include "libiberty.h"
29
#include "progress.h"
30
#include "getopt.h"
31
#include "aout/ar.h"
32
#include "libbfd.h"
33
#include "bucomm.h"
34
#include "arsup.h"
35
#include "filenames.h"
36
#include "binemul.h"
37
#include "plugin.h"
38
 
39
#ifdef __GO32___
40
#define EXT_NAME_LEN 3		/* Bufflen of addition to name if it's MS-DOS.  */
41
#else
42
#define EXT_NAME_LEN 6		/* Ditto for *NIX.  */
43
#endif
44
 
45
/* Static declarations.  */
46
 
47
static void mri_emul (void);
48
static const char *normalize (const char *, bfd *);
49
static void remove_output (void);
50
static void map_over_members (bfd *, void (*)(bfd *), char **, int);
51
static void print_contents (bfd * member);
52
static void delete_members (bfd *, char **files_to_delete);
53
 
54
static void move_members (bfd *, char **files_to_move);
55
static void replace_members
56
  (bfd *, char **files_to_replace, bfd_boolean quick);
57
static void print_descr (bfd * abfd);
58
static void write_archive (bfd *);
59
static int  ranlib_only (const char *archname);
60
static int  ranlib_touch (const char *archname);
61
static void usage (int);
62
 
63
/** Globals and flags.  */
64
 
65
static int mri_mode;
66
 
67
/* This flag distinguishes between ar and ranlib:
68
   1 means this is 'ranlib'; 0 means this is 'ar'.
69
   -1 means if we should use argv[0] to decide.  */
70
extern int is_ranlib;
71
 
72
/* Nonzero means don't warn about creating the archive file if necessary.  */
73
int silent_create = 0;
74
 
75
/* Nonzero means describe each action performed.  */
76
int verbose = 0;
77
 
78
/* Nonzero means preserve dates of members when extracting them.  */
79
int preserve_dates = 0;
80
 
81
/* Nonzero means don't replace existing members whose dates are more recent
82
   than the corresponding files.  */
83
int newer_only = 0;
84
 
85
/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
86
   member).  -1 means we've been explicitly asked to not write a symbol table;
87
   +1 means we've been explicitly asked to write it;
88
 
89
   Traditionally, the default in BSD has been to not write the table.
90
   However, for POSIX.2 compliance the default is now to write a symbol table
91
   if any of the members are object files.  */
92
int write_armap = 0;
93
 
94
/* Operate in deterministic mode: write zero for timestamps, uids,
95
   and gids for archive members and the archive symbol table, and write
96
   consistent file modes.  */
97
int deterministic = -1;			/* Determinism indeterminate.  */
98
 
99
/* Nonzero means it's the name of an existing member; position new or moved
100
   files with respect to this one.  */
101
char *posname = NULL;
102
 
103
/* Sez how to use `posname': pos_before means position before that member.
104
   pos_after means position after that member. pos_end means always at end.
105
   pos_default means default appropriately. For the latter two, `posname'
106
   should also be zero.  */
107
enum pos
108
  {
109
    pos_default, pos_before, pos_after, pos_end
110
  } postype = pos_default;
111
 
112
enum operations
113
  {
114
    none = 0, del, replace, print_table,
115
    print_files, extract, move, quick_append
116
  } operation = none;
117
 
118
static bfd **
119
get_pos_bfd (bfd **, enum pos, const char *);
120
 
121
/* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
122
   extract the COUNTED_NAME_COUNTER instance of that name.  */
123
static bfd_boolean counted_name_mode = 0;
124
static int counted_name_counter = 0;
125
 
126
/* Whether to truncate names of files stored in the archive.  */
127
static bfd_boolean ar_truncate = FALSE;
128
 
129
/* Whether to use a full file name match when searching an archive.
130
   This is convenient for archives created by the Microsoft lib
131
   program.  */
132
static bfd_boolean full_pathname = FALSE;
133
 
134
/* Whether to create a "thin" archive (symbol index only -- no files).  */
135
static bfd_boolean make_thin_archive = FALSE;
136
 
137
static int show_version = 0;
138
 
139
static int show_help = 0;
140
 
141
static const char *plugin_target = NULL;
142
 
143
static const char *target = NULL;
144
 
145
#define OPTION_PLUGIN 201
146
#define OPTION_TARGET 202
147
 
148
static struct option long_options[] =
149
{
150
  {"help", no_argument, &show_help, 1},
151
  {"plugin", required_argument, NULL, OPTION_PLUGIN},
152
  {"target", required_argument, NULL, OPTION_TARGET},
153
  {"version", no_argument, &show_version, 1},
154
  {NULL, no_argument, NULL, 0}
155
};
156
 
157
int interactive = 0;
158
 
159
static void
160
mri_emul (void)
161
{
162
  interactive = isatty (fileno (stdin));
163
  yyparse ();
164
}
165
 
166
/* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
167
   COUNT is the length of the FILES chain; FUNCTION is called on each entry
168
   whose name matches one in FILES.  */
169
 
170
static void
171
map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
172
{
173
  bfd *head;
174
  int match_count;
175
 
176
  if (count == 0)
177
    {
178
      for (head = arch->archive_next; head; head = head->archive_next)
179
	{
180
	  PROGRESS (1);
181
	  function (head);
182
	}
183
      return;
184
    }
185
 
186
  /* This may appear to be a baroque way of accomplishing what we want.
187
     However we have to iterate over the filenames in order to notice where
188
     a filename is requested but does not exist in the archive.  Ditto
189
     mapping over each file each time -- we want to hack multiple
190
     references.  */
191
 
192
  for (head = arch->archive_next; head; head = head->archive_next)
193
    head->archive_pass = 0;
194
 
195
  for (; count > 0; files++, count--)
196
    {
197
      bfd_boolean found = FALSE;
198
 
199
      match_count = 0;
200
      for (head = arch->archive_next; head; head = head->archive_next)
201
	{
202
	  const char * filename;
203
 
204
	  PROGRESS (1);
205
	  /* PR binutils/15796: Once an archive element has been matched
206
	     do not match it again.  If the user provides multiple same-named
207
	     parameters on the command line their intent is to match multiple
208
	     same-named entries in the archive, not the same entry multiple
209
	     times.  */
210
	  if (head->archive_pass)
211
	    continue;
212
 
213
	  filename = head->filename;
214
	  if (filename == NULL)
215
	    {
216
	      /* Some archive formats don't get the filenames filled in
217
		 until the elements are opened.  */
218
	      struct stat buf;
219
	      bfd_stat_arch_elt (head, &buf);
220
	    }
221
	  else if (bfd_is_thin_archive (arch))
222
	    {
223
	      /* Thin archives store full pathnames.  Need to normalize.  */
224
	      filename = normalize (filename, arch);
225
	    }
226
 
227
	  if (filename != NULL
228
	      && !FILENAME_CMP (normalize (*files, arch), filename))
229
	    {
230
	      ++match_count;
231
	      if (counted_name_mode
232
		  && match_count != counted_name_counter)
233
		{
234
		  /* Counting, and didn't match on count; go on to the
235
                     next one.  */
236
		  continue;
237
		}
238
 
239
	      found = TRUE;
240
	      function (head);
241
	      head->archive_pass = 1;
242
	      /* PR binutils/15796: Once a file has been matched, do not
243
		 match any more same-named files in the archive.  If the
244
		 user does want to match multiple same-name files in an
245
		 archive they should provide multiple same-name parameters
246
		 to the ar command.  */
247
	      break;
248
	    }
249
	}
250
 
251
      if (!found)
252
	/* xgettext:c-format */
253
	fprintf (stderr, _("no entry %s in archive\n"), *files);
254
    }
255
}
256
 
257
bfd_boolean operation_alters_arch = FALSE;
258
 
259
static void
260
usage (int help)
261
{
262
  FILE *s;
263
 
264
#if BFD_SUPPORTS_PLUGINS
265
  /* xgettext:c-format */
266
  const char *command_line
267
    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
268
	" [--plugin ] [member-name] [count] archive-file file...\n");
269
 
270
#else
271
  /* xgettext:c-format */
272
  const char *command_line
273
    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
274
	" [member-name] [count] archive-file file...\n");
275
#endif
276
  s = help ? stdout : stderr;
277
 
278
  fprintf (s, command_line, program_name);
279
 
280
  /* xgettext:c-format */
281
  fprintf (s, _("       %s -M [
282
  fprintf (s, _(" commands:\n"));
283
  fprintf (s, _("  d            - delete file(s) from the archive\n"));
284
  fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
285
  fprintf (s, _("  p            - print file(s) found in the archive\n"));
286
  fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
287
  fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
288
  fprintf (s, _("  s            - act as ranlib\n"));
289
  fprintf (s, _("  t            - display contents of archive\n"));
290
  fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
291
  fprintf (s, _(" command specific modifiers:\n"));
292
  fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
293
  fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
294
  if (DEFAULT_AR_DETERMINISTIC)
295
    {
296
      fprintf (s, _("\
297
  [D]          - use zero for timestamps and uids/gids (default)\n"));
298
      fprintf (s, _("\
299
  [U]          - use actual timestamps and uids/gids\n"));
300
    }
301
  else
302
    {
303
      fprintf (s, _("\
304
  [D]          - use zero for timestamps and uids/gids\n"));
305
      fprintf (s, _("\
306
  [U]          - use actual timestamps and uids/gids (default)\n"));
307
    }
308
  fprintf (s, _("  [N]          - use instance [count] of name\n"));
309
  fprintf (s, _("  [f]          - truncate inserted file names\n"));
310
  fprintf (s, _("  [P]          - use full path names when matching\n"));
311
  fprintf (s, _("  [o]          - preserve original dates\n"));
312
  fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
313
  fprintf (s, _(" generic modifiers:\n"));
314
  fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
315
  fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
316
  fprintf (s, _("  [S]          - do not build a symbol table\n"));
317
  fprintf (s, _("  [T]          - make a thin archive\n"));
318
  fprintf (s, _("  [v]          - be verbose\n"));
319
  fprintf (s, _("  [V]          - display the version number\n"));
320
  fprintf (s, _("  @      - read options from \n"));
321
  fprintf (s, _("  --target=BFDNAME - specify the target object format as BFDNAME\n"));
322
#if BFD_SUPPORTS_PLUGINS
323
  fprintf (s, _(" optional:\n"));
324
  fprintf (s, _("  --plugin 

- load the specified plugin\n"));

325
#endif
326
 
327
  ar_emul_usage (s);
328
 
329
  list_supported_targets (program_name, s);
330
 
331
  if (REPORT_BUGS_TO[0] && help)
332
    fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
333
 
334
  xexit (help ? 0 : 1);
335
}
336
 
337
static void
338
ranlib_usage (int help)
339
{
340
  FILE *s;
341
 
342
  s = help ? stdout : stderr;
343
 
344
  /* xgettext:c-format */
345
  fprintf (s, _("Usage: %s [options] archive\n"), program_name);
346
  fprintf (s, _(" Generate an index to speed access to archives\n"));
347
  fprintf (s, _(" The options are:\n\
348
  @                      Read options from \n"));
349
#if BFD_SUPPORTS_PLUGINS
350
  fprintf (s, _("\
351
  --plugin               Load the specified plugin\n"));
352
#endif
353
  if (DEFAULT_AR_DETERMINISTIC)
354
    fprintf (s, _("\
355
  -D                           Use zero for symbol map timestamp (default)\n\
356
  -U                           Use an actual symbol map timestamp\n"));
357
  else
358
    fprintf (s, _("\
359
  -D                           Use zero for symbol map timestamp\n\
360
  -U                           Use actual symbol map timestamp (default)\n"));
361
  fprintf (s, _("\
362
  -t                           Update the archive's symbol map timestamp\n\
363
  -h --help                    Print this help message\n\
364
  -v --version                 Print version information\n"));
365
 
366
  list_supported_targets (program_name, s);
367
 
368
  if (REPORT_BUGS_TO[0] && help)
369
    fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
370
 
371
  xexit (help ? 0 : 1);
372
}
373
 
374
/* Normalize a file name specified on the command line into a file
375
   name which we will use in an archive.  */
376
 
377
static const char *
378
normalize (const char *file, bfd *abfd)
379
{
380
  const char *filename;
381
 
382
  if (full_pathname)
383
    return file;
384
 
385
  filename = lbasename (file);
386
 
387
  if (ar_truncate
388
      && abfd != NULL
389
      && strlen (filename) > abfd->xvec->ar_max_namelen)
390
    {
391
      char *s;
392
 
393
      /* Space leak.  */
394
      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
395
      memcpy (s, filename, abfd->xvec->ar_max_namelen);
396
      s[abfd->xvec->ar_max_namelen] = '\0';
397
      filename = s;
398
    }
399
 
400
  return filename;
401
}
402
 
403
/* Remove any output file.  This is only called via xatexit.  */
404
 
405
static const char *output_filename = NULL;
406
static FILE *output_file = NULL;
407
static bfd *output_bfd = NULL;
408
 
409
static void
410
remove_output (void)
411
{
412
  if (output_filename != NULL)
413
    {
414
      if (output_bfd != NULL)
415
	bfd_cache_close (output_bfd);
416
      if (output_file != NULL)
417
	fclose (output_file);
418
      unlink_if_ordinary (output_filename);
419
    }
420
}
421
 
422
static char **
423
decode_options (int argc, char **argv)
424
{
425
  int c;
426
 
427
  /* Convert old-style tar call by exploding option element and rearranging
428
     options accordingly.  */
429
 
430
  if (argc > 1 && argv[1][0] != '-')
431
    {
432
      int new_argc;		/* argc value for rearranged arguments */
433
      char **new_argv;		/* argv value for rearranged arguments */
434
      char *const *in;		/* cursor into original argv */
435
      char **out;		/* cursor into rearranged argv */
436
      const char *letter;	/* cursor into old option letters */
437
      char buffer[3];		/* constructed option buffer */
438
 
439
      /* Initialize a constructed option.  */
440
 
441
      buffer[0] = '-';
442
      buffer[2] = '\0';
443
 
444
      /* Allocate a new argument array, and copy program name in it.  */
445
 
446
      new_argc = argc - 1 + strlen (argv[1]);
447
      new_argv = xmalloc ((new_argc + 1) * sizeof (*argv));
448
      in = argv;
449
      out = new_argv;
450
      *out++ = *in++;
451
 
452
      /* Copy each old letter option as a separate option.  */
453
 
454
      for (letter = *in++; *letter; letter++)
455
	{
456
	  buffer[1] = *letter;
457
	  *out++ = xstrdup (buffer);
458
	}
459
 
460
      /* Copy all remaining options.  */
461
 
462
      while (in < argv + argc)
463
	*out++ = *in++;
464
      *out = NULL;
465
 
466
      /* Replace the old option list by the new one.  */
467
 
468
      argc = new_argc;
469
      argv = new_argv;
470
    }
471
 
472
  while ((c = getopt_long (argc, argv, "hdmpqrtxlcoVsSuvabiMNfPTDU",
473
			   long_options, NULL)) != EOF)
474
    {
475
      switch (c)
476
        {
477
        case 'd':
478
        case 'm':
479
        case 'p':
480
        case 'q':
481
        case 'r':
482
        case 't':
483
        case 'x':
484
          if (operation != none)
485
            fatal (_("two different operation options specified"));
486
	  break;
487
	}
488
 
489
      switch (c)
490
        {
491
        case 'h':
492
	  show_help = 1;
493
	  break;
494
        case 'd':
495
          operation = del;
496
          operation_alters_arch = TRUE;
497
          break;
498
        case 'm':
499
          operation = move;
500
          operation_alters_arch = TRUE;
501
          break;
502
        case 'p':
503
          operation = print_files;
504
          break;
505
        case 'q':
506
          operation = quick_append;
507
          operation_alters_arch = TRUE;
508
          break;
509
        case 'r':
510
          operation = replace;
511
          operation_alters_arch = TRUE;
512
          break;
513
        case 't':
514
          operation = print_table;
515
          break;
516
        case 'x':
517
          operation = extract;
518
          break;
519
        case 'l':
520
          break;
521
        case 'c':
522
          silent_create = 1;
523
          break;
524
        case 'o':
525
          preserve_dates = 1;
526
          break;
527
        case 'V':
528
          show_version = TRUE;
529
          break;
530
        case 's':
531
          write_armap = 1;
532
          break;
533
        case 'S':
534
          write_armap = -1;
535
          break;
536
        case 'u':
537
          newer_only = 1;
538
          break;
539
        case 'v':
540
          verbose = 1;
541
          break;
542
        case 'a':
543
          postype = pos_after;
544
          break;
545
        case 'b':
546
          postype = pos_before;
547
          break;
548
        case 'i':
549
          postype = pos_before;
550
          break;
551
        case 'M':
552
          mri_mode = 1;
553
          break;
554
        case 'N':
555
          counted_name_mode = TRUE;
556
          break;
557
        case 'f':
558
          ar_truncate = TRUE;
559
          break;
560
        case 'P':
561
          full_pathname = TRUE;
562
          break;
563
        case 'T':
564
          make_thin_archive = TRUE;
565
          break;
566
        case 'D':
567
          deterministic = TRUE;
568
          break;
569
        case 'U':
570
          deterministic = FALSE;
571
          break;
572
	case OPTION_PLUGIN:
573
#if BFD_SUPPORTS_PLUGINS
574
	  plugin_target = "plugin";
575
	  bfd_plugin_set_plugin (optarg);
576
#else
577
	  fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
578
	  xexit (1);
579
#endif
580
	  break;
581
	case OPTION_TARGET:
582
	  target = optarg;
583
	  break;
584
	case 0:		/* A long option that just sets a flag.  */
585
	  break;
586
        default:
587
          usage (0);
588
        }
589
    }
590
 
591
  return &argv[optind];
592
}
593
 
594
/* If neither -D nor -U was specified explicitly,
595
   then use the configured default.  */
596
static void
597
default_deterministic (void)
598
{
599
  if (deterministic < 0)
600
    deterministic = DEFAULT_AR_DETERMINISTIC;
601
}
602
 
603
static void
604
ranlib_main (int argc, char **argv)
605
{
606
  int arg_index, status = 0;
607
  bfd_boolean touch = FALSE;
608
  int c;
609
 
610
  while ((c = getopt_long (argc, argv, "DhHUvVt", long_options, NULL)) != EOF)
611
    {
612
      switch (c)
613
        {
614
	case 'D':
615
	  deterministic = TRUE;
616
	  break;
617
        case 'U':
618
          deterministic = FALSE;
619
          break;
620
	case 'h':
621
	case 'H':
622
	  show_help = 1;
623
	  break;
624
	case 't':
625
	  touch = TRUE;
626
	  break;
627
	case 'v':
628
	case 'V':
629
	  show_version = 1;
630
	  break;
631
 
632
	  /* PR binutils/13493: Support plugins.  */
633
	case OPTION_PLUGIN:
634
#if BFD_SUPPORTS_PLUGINS
635
	  plugin_target = "plugin";
636
	  bfd_plugin_set_plugin (optarg);
637
#else
638
	  fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
639
	  xexit (1);
640
#endif
641
	  break;
642
	}
643
    }
644
 
645
  if (argc < 2)
646
    ranlib_usage (0);
647
 
648
  if (show_help)
649
    ranlib_usage (1);
650
 
651
  if (show_version)
652
    print_version ("ranlib");
653
 
654
  default_deterministic ();
655
 
656
  arg_index = optind;
657
 
658
  while (arg_index < argc)
659
    {
660
      if (! touch)
661
        status |= ranlib_only (argv[arg_index]);
662
      else
663
        status |= ranlib_touch (argv[arg_index]);
664
      ++arg_index;
665
    }
666
 
667
  xexit (status);
668
}
669
 
670
int main (int, char **);
671
 
672
int
673
main (int argc, char **argv)
674
{
675
  int arg_index;
676
  char **files;
677
  int file_count;
678
  char *inarch_filename;
679
  int i;
680
 
681
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
682
  setlocale (LC_MESSAGES, "");
683
#endif
684
#if defined (HAVE_SETLOCALE)
685
  setlocale (LC_CTYPE, "");
686
#endif
687
  bindtextdomain (PACKAGE, LOCALEDIR);
688
  textdomain (PACKAGE);
689
 
690
  program_name = argv[0];
691
  xmalloc_set_program_name (program_name);
692
#if BFD_SUPPORTS_PLUGINS
693
  bfd_plugin_set_program_name (program_name);
694
#endif
695
 
696
  expandargv (&argc, &argv);
697
 
698
  if (is_ranlib < 0)
699
    {
700
      const char *temp = lbasename (program_name);
701
 
702
      if (strlen (temp) >= 6
703
	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
704
	is_ranlib = 1;
705
      else
706
	is_ranlib = 0;
707
    }
708
 
709
  START_PROGRESS (program_name, 0);
710
 
711
  bfd_init ();
712
  set_default_bfd_target ();
713
 
714
  xatexit (remove_output);
715
 
716
  for (i = 1; i < argc; i++)
717
    if (! ar_emul_parse_arg (argv[i]))
718
      break;
719
  argv += (i - 1);
720
  argc -= (i - 1);
721
 
722
  if (is_ranlib)
723
    ranlib_main (argc, argv);
724
 
725
  if (argc < 2)
726
    usage (0);
727
 
728
  argv = decode_options (argc, argv);
729
 
730
  if (show_help)
731
    usage (1);
732
 
733
  if (show_version)
734
    print_version ("ar");
735
 
736
  arg_index = 0;
737
 
738
  if (mri_mode)
739
    {
740
      mri_emul ();
741
    }
742
  else
743
    {
744
      bfd *arch;
745
 
746
      /* We don't use do_quick_append any more.  Too many systems
747
	 expect ar to always rebuild the symbol table even when q is
748
	 used.  */
749
 
750
      /* We can't write an armap when using ar q, so just do ar r
751
         instead.  */
752
      if (operation == quick_append && write_armap)
753
	operation = replace;
754
 
755
      if ((operation == none || operation == print_table)
756
	  && write_armap == 1)
757
	xexit (ranlib_only (argv[arg_index]));
758
 
759
      if (operation == none)
760
	fatal (_("no operation specified"));
761
 
762
      if (newer_only && operation != replace)
763
	fatal (_("`u' is only meaningful with the `r' option."));
764
 
765
      if (newer_only && deterministic > 0)
766
        fatal (_("`u' is not meaningful with the `D' option."));
767
 
768
      if (newer_only && deterministic < 0 && DEFAULT_AR_DETERMINISTIC)
769
        non_fatal (_("\
770
`u' modifier ignored since `D' is the default (see `U')"));
771
 
772
      default_deterministic ();
773
 
774
      if (postype != pos_default)
775
	posname = argv[arg_index++];
776
 
777
      if (counted_name_mode)
778
	{
779
	  if (operation != extract && operation != del)
780
	    fatal (_("`N' is only meaningful with the `x' and `d' options."));
781
	  counted_name_counter = atoi (argv[arg_index++]);
782
	  if (counted_name_counter <= 0)
783
	    fatal (_("Value for `N' must be positive."));
784
	}
785
 
786
      inarch_filename = argv[arg_index++];
787
 
788
      for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++)
789
	continue;
790
 
791
      files = (file_count > 0) ? argv + arg_index : NULL;
792
 
793
      arch = open_inarch (inarch_filename,
794
			  files == NULL ? (char *) NULL : files[0]);
795
 
796
      if (operation == extract && bfd_is_thin_archive (arch))
797
	fatal (_("`x' cannot be used on thin archives."));
798
 
799
      switch (operation)
800
	{
801
	case print_table:
802
	  map_over_members (arch, print_descr, files, file_count);
803
	  break;
804
 
805
	case print_files:
806
	  map_over_members (arch, print_contents, files, file_count);
807
	  break;
808
 
809
	case extract:
810
	  map_over_members (arch, extract_file, files, file_count);
811
	  break;
812
 
813
	case del:
814
	  if (files != NULL)
815
	    delete_members (arch, files);
816
	  else
817
	    output_filename = NULL;
818
	  break;
819
 
820
	case move:
821
	  /* PR 12558: Creating and moving at the same time does
822
	     not make sense.  Just create the archive instead.  */
823
	  if (! silent_create)
824
	    {
825
	      if (files != NULL)
826
		move_members (arch, files);
827
	      else
828
		output_filename = NULL;
829
	      break;
830
	    }
831
	  /* Fall through.  */
832
 
833
	case replace:
834
	case quick_append:
835
	  if (files != NULL || write_armap > 0)
836
	    replace_members (arch, files, operation == quick_append);
837
	  else
838
	    output_filename = NULL;
839
	  break;
840
 
841
	  /* Shouldn't happen! */
842
	default:
843
	  /* xgettext:c-format */
844
	  fatal (_("internal error -- this option not implemented"));
845
	}
846
    }
847
 
848
  END_PROGRESS (program_name);
849
 
850
  xexit (0);
851
  return 0;
852
}
853
 
854
bfd *
855
open_inarch (const char *archive_filename, const char *file)
856
{
857
  bfd **last_one;
858
  bfd *next_one;
859
  struct stat sbuf;
860
  bfd *arch;
861
  char **matching;
862
 
863
  bfd_set_error (bfd_error_no_error);
864
 
865
  if (target == NULL)
866
    target = plugin_target;
867
 
868
  if (stat (archive_filename, &sbuf) != 0)
869
    {
870
#if !defined(__GO32__) || defined(__DJGPP__)
871
 
872
      /* FIXME: I don't understand why this fragment was ifndef'ed
873
	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
874
	 stat() works just fine in v2.x, so I think this should be
875
	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
876
 
877
      /* KLUDGE ALERT! Temporary fix until I figger why
878
	 stat() is wrong ... think it's buried in GO32's IDT - Jax */
879
      if (errno != ENOENT)
880
	bfd_fatal (archive_filename);
881
#endif
882
 
883
      if (!operation_alters_arch)
884
	{
885
	  fprintf (stderr, "%s: ", program_name);
886
//     perror (archive_filename);
887
	  maybequit ();
888
	  return NULL;
889
	}
890
 
891
      /* If the target isn't set, try to figure out the target to use
892
	 for the archive from the first object on the list.  */
893
      if (target == NULL && file != NULL)
894
	{
895
	  bfd *obj;
896
 
897
	  obj = bfd_openr (file, target);
898
	  if (obj != NULL)
899
	    {
900
	      if (bfd_check_format (obj, bfd_object))
901
		target = bfd_get_target (obj);
902
	      (void) bfd_close (obj);
903
	    }
904
	}
905
 
906
      /* Create an empty archive.  */
907
      arch = bfd_openw (archive_filename, target);
908
      if (arch == NULL
909
	  || ! bfd_set_format (arch, bfd_archive)
910
	  || ! bfd_close (arch))
911
	bfd_fatal (archive_filename);
912
      else if (!silent_create)
913
        non_fatal (_("creating %s"), archive_filename);
914
 
915
      /* If we die creating a new archive, don't leave it around.  */
916
      output_filename = archive_filename;
917
    }
918
 
919
  arch = bfd_openr (archive_filename, target);
920
  if (arch == NULL)
921
    {
922
    bloser:
923
      bfd_fatal (archive_filename);
924
    }
925
 
926
  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
927
    {
928
      bfd_nonfatal (archive_filename);
929
      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
930
	{
931
	  list_matching_formats (matching);
932
	  free (matching);
933
	}
934
      xexit (1);
935
    }
936
 
937
  if ((operation == replace || operation == quick_append)
938
      && bfd_openr_next_archived_file (arch, NULL) != NULL)
939
    {
940
      /* PR 15140: Catch attempts to convert a normal
941
	 archive into a thin archive or vice versa.  */
942
      if (make_thin_archive && ! bfd_is_thin_archive (arch))
943
	{
944
	  fatal (_("Cannot convert existing library %s to thin format"),
945
		 bfd_get_filename (arch));
946
	  goto bloser;
947
	}
948
      else if (! make_thin_archive && bfd_is_thin_archive (arch))
949
	{
950
	  fatal (_("Cannot convert existing thin library %s to normal format"),
951
		 bfd_get_filename (arch));
952
	  goto bloser;
953
	}
954
    }
955
 
956
  last_one = &(arch->archive_next);
957
  /* Read all the contents right away, regardless.  */
958
  for (next_one = bfd_openr_next_archived_file (arch, NULL);
959
       next_one;
960
       next_one = bfd_openr_next_archived_file (arch, next_one))
961
    {
962
      PROGRESS (1);
963
      *last_one = next_one;
964
      last_one = &next_one->archive_next;
965
    }
966
  *last_one = (bfd *) NULL;
967
  if (bfd_get_error () != bfd_error_no_more_archived_files)
968
    goto bloser;
969
  return arch;
970
}
971
 
972
static void
973
print_contents (bfd *abfd)
974
{
975
  bfd_size_type ncopied = 0;
976
  bfd_size_type size;
977
  char *cbuf = (char *) xmalloc (BUFSIZE);
978
  struct stat buf;
979
 
980
  if (bfd_stat_arch_elt (abfd, &buf) != 0)
981
    /* xgettext:c-format */
982
    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
983
 
984
  if (verbose)
985
    printf ("\n<%s>\n\n", bfd_get_filename (abfd));
986
 
987
  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
988
 
989
  size = buf.st_size;
990
  while (ncopied < size)
991
    {
992
      bfd_size_type nread;
993
      bfd_size_type tocopy = size - ncopied;
994
 
995
      if (tocopy > BUFSIZE)
996
	tocopy = BUFSIZE;
997
 
998
      nread = bfd_bread (cbuf, tocopy, abfd);
999
      if (nread != tocopy)
1000
	/* xgettext:c-format */
1001
	fatal (_("%s is not a valid archive"),
1002
	       bfd_get_filename (bfd_my_archive (abfd)));
1003
 
1004
      /* fwrite in mingw32 may return int instead of bfd_size_type. Cast the
1005
	 return value to bfd_size_type to avoid comparison between signed and
1006
	 unsigned values.  */
1007
      if ((bfd_size_type) fwrite (cbuf, 1, nread, stdout) != nread)
1008
	fatal ("stdout: %s", strerror (errno));
1009
      ncopied += tocopy;
1010
    }
1011
  free (cbuf);
1012
}
1013
 
1014
/* Extract a member of the archive into its own file.
1015
 
1016
   We defer opening the new file until after we have read a BUFSIZ chunk of the
1017
   old one, since we know we have just read the archive header for the old
1018
   one.  Since most members are shorter than BUFSIZ, this means we will read
1019
   the old header, read the old data, write a new inode for the new file, and
1020
   write the new data, and be done. This 'optimization' is what comes from
1021
   sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
1022
   Gilmore  */
1023
 
1024
void
1025
extract_file (bfd *abfd)
1026
{
1027
  FILE *ostream;
1028
  char *cbuf = (char *) xmalloc (BUFSIZE);
1029
  bfd_size_type nread, tocopy;
1030
  bfd_size_type ncopied = 0;
1031
  bfd_size_type size;
1032
  struct stat buf;
1033
 
1034
  if (bfd_stat_arch_elt (abfd, &buf) != 0)
1035
    /* xgettext:c-format */
1036
    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
1037
  size = buf.st_size;
1038
 
1039
  if (verbose)
1040
    printf ("x - %s\n", bfd_get_filename (abfd));
1041
 
1042
  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
1043
 
1044
  ostream = NULL;
1045
  if (size == 0)
1046
    {
1047
      /* Seems like an abstraction violation, eh?  Well it's OK! */
1048
      output_filename = bfd_get_filename (abfd);
1049
 
1050
      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
1051
      if (ostream == NULL)
1052
	{
1053
//     perror (bfd_get_filename (abfd));
1054
	  xexit (1);
1055
	}
1056
 
1057
      output_file = ostream;
1058
    }
1059
  else
1060
    while (ncopied < size)
1061
      {
1062
	tocopy = size - ncopied;
1063
	if (tocopy > BUFSIZE)
1064
	  tocopy = BUFSIZE;
1065
 
1066
	nread = bfd_bread (cbuf, tocopy, abfd);
1067
	if (nread != tocopy)
1068
	  /* xgettext:c-format */
1069
	  fatal (_("%s is not a valid archive"),
1070
		 bfd_get_filename (bfd_my_archive (abfd)));
1071
 
1072
	/* See comment above; this saves disk arm motion */
1073
	if (ostream == NULL)
1074
	  {
1075
	    /* Seems like an abstraction violation, eh?  Well it's OK! */
1076
	    output_filename = bfd_get_filename (abfd);
1077
 
1078
	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
1079
	    if (ostream == NULL)
1080
	      {
1081
//       perror (bfd_get_filename (abfd));
1082
		xexit (1);
1083
	      }
1084
 
1085
	    output_file = ostream;
1086
	  }
1087
 
1088
	/* fwrite in mingw32 may return int instead of bfd_size_type. Cast
1089
	   the return value to bfd_size_type to avoid comparison between
1090
	   signed and unsigned values.  */
1091
	if ((bfd_size_type) fwrite (cbuf, 1, nread, ostream) != nread)
1092
	  fatal ("%s: %s", output_filename, strerror (errno));
1093
	ncopied += tocopy;
1094
      }
1095
 
1096
  if (ostream != NULL)
1097
    fclose (ostream);
1098
 
1099
  output_file = NULL;
1100
  output_filename = NULL;
1101
 
1102
//  chmod (bfd_get_filename (abfd), buf.st_mode);
1103
 
1104
  if (preserve_dates)
1105
    {
1106
      /* Set access time to modification time.  Only st_mtime is
1107
	 initialized by bfd_stat_arch_elt.  */
1108
      buf.st_atime = buf.st_mtime;
1109
      set_times (bfd_get_filename (abfd), &buf);
1110
    }
1111
 
1112
  free (cbuf);
1113
}
1114
 
1115
static void
1116
write_archive (bfd *iarch)
1117
{
1118
  bfd *obfd;
1119
  char *old_name, *new_name;
1120
  bfd *contents_head = iarch->archive_next;
1121
 
1122
  old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1);
1123
  strcpy (old_name, bfd_get_filename (iarch));
1124
  new_name = make_tempname (old_name);
1125
 
1126
  if (new_name == NULL)
1127
    bfd_fatal (_("could not create temporary file whilst writing archive"));
1128
 
1129
  output_filename = new_name;
1130
 
1131
  obfd = bfd_openw (new_name, bfd_get_target (iarch));
1132
 
1133
  if (obfd == NULL)
1134
    bfd_fatal (old_name);
1135
 
1136
  output_bfd = obfd;
1137
 
1138
  bfd_set_format (obfd, bfd_archive);
1139
 
1140
  /* Request writing the archive symbol table unless we've
1141
     been explicitly requested not to.  */
1142
  obfd->has_armap = write_armap >= 0;
1143
 
1144
  if (ar_truncate)
1145
    {
1146
      /* This should really use bfd_set_file_flags, but that rejects
1147
         archives.  */
1148
      obfd->flags |= BFD_TRADITIONAL_FORMAT;
1149
    }
1150
 
1151
  if (deterministic)
1152
    obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
1153
 
1154
  if (make_thin_archive || bfd_is_thin_archive (iarch))
1155
    bfd_is_thin_archive (obfd) = 1;
1156
 
1157
  if (!bfd_set_archive_head (obfd, contents_head))
1158
    bfd_fatal (old_name);
1159
 
1160
  if (!bfd_close (obfd))
1161
    bfd_fatal (old_name);
1162
 
1163
  output_bfd = NULL;
1164
  output_filename = NULL;
1165
 
1166
  /* We don't care if this fails; we might be creating the archive.  */
1167
  bfd_close (iarch);
1168
 
1169
  if (smart_rename (new_name, old_name, 0) != 0)
1170
    xexit (1);
1171
  free (old_name);
1172
}
1173
 
1174
/* Return a pointer to the pointer to the entry which should be rplacd'd
1175
   into when altering.  DEFAULT_POS should be how to interpret pos_default,
1176
   and should be a pos value.  */
1177
 
1178
static bfd **
1179
get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
1180
{
1181
  bfd **after_bfd = contents;
1182
  enum pos realpos;
1183
  const char *realposname;
1184
 
1185
  if (postype == pos_default)
1186
    {
1187
      realpos = default_pos;
1188
      realposname = default_posname;
1189
    }
1190
  else
1191
    {
1192
      realpos = postype;
1193
      realposname = posname;
1194
    }
1195
 
1196
  if (realpos == pos_end)
1197
    {
1198
      while (*after_bfd)
1199
	after_bfd = &((*after_bfd)->archive_next);
1200
    }
1201
  else
1202
    {
1203
      for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next)
1204
	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
1205
	  {
1206
	    if (realpos == pos_after)
1207
	      after_bfd = &(*after_bfd)->archive_next;
1208
	    break;
1209
	  }
1210
    }
1211
  return after_bfd;
1212
}
1213
 
1214
static void
1215
delete_members (bfd *arch, char **files_to_delete)
1216
{
1217
  bfd **current_ptr_ptr;
1218
  bfd_boolean found;
1219
  bfd_boolean something_changed = FALSE;
1220
  int match_count;
1221
 
1222
  for (; *files_to_delete != NULL; ++files_to_delete)
1223
    {
1224
      /* In a.out systems, the armap is optional.  It's also called
1225
	 __.SYMDEF.  So if the user asked to delete it, we should remember
1226
	 that fact. This isn't quite right for COFF systems (where
1227
	 __.SYMDEF might be regular member), but it's very unlikely
1228
	 to be a problem.  FIXME */
1229
 
1230
      if (!strcmp (*files_to_delete, "__.SYMDEF"))
1231
	{
1232
	  arch->has_armap = FALSE;
1233
	  write_armap = -1;
1234
	  continue;
1235
	}
1236
 
1237
      found = FALSE;
1238
      match_count = 0;
1239
      current_ptr_ptr = &(arch->archive_next);
1240
      while (*current_ptr_ptr)
1241
	{
1242
	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
1243
			    (*current_ptr_ptr)->filename) == 0)
1244
	    {
1245
	      ++match_count;
1246
	      if (counted_name_mode
1247
		  && match_count != counted_name_counter)
1248
		{
1249
		  /* Counting, and didn't match on count; go on to the
1250
                     next one.  */
1251
		}
1252
	      else
1253
		{
1254
		  found = TRUE;
1255
		  something_changed = TRUE;
1256
		  if (verbose)
1257
		    printf ("d - %s\n",
1258
			    *files_to_delete);
1259
		  *current_ptr_ptr = ((*current_ptr_ptr)->archive_next);
1260
		  goto next_file;
1261
		}
1262
	    }
1263
 
1264
	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
1265
	}
1266
 
1267
      if (verbose && !found)
1268
	{
1269
	  /* xgettext:c-format */
1270
	  printf (_("No member named `%s'\n"), *files_to_delete);
1271
	}
1272
    next_file:
1273
      ;
1274
    }
1275
 
1276
  if (something_changed)
1277
    write_archive (arch);
1278
  else
1279
    output_filename = NULL;
1280
}
1281
 
1282
 
1283
/* Reposition existing members within an archive */
1284
 
1285
static void
1286
move_members (bfd *arch, char **files_to_move)
1287
{
1288
  bfd **after_bfd;		/* New entries go after this one */
1289
  bfd **current_ptr_ptr;	/* cdr pointer into contents */
1290
 
1291
  for (; *files_to_move; ++files_to_move)
1292
    {
1293
      current_ptr_ptr = &(arch->archive_next);
1294
      while (*current_ptr_ptr)
1295
	{
1296
	  bfd *current_ptr = *current_ptr_ptr;
1297
	  if (FILENAME_CMP (normalize (*files_to_move, arch),
1298
			    current_ptr->filename) == 0)
1299
	    {
1300
	      /* Move this file to the end of the list - first cut from
1301
		 where it is.  */
1302
	      bfd *link_bfd;
1303
	      *current_ptr_ptr = current_ptr->archive_next;
1304
 
1305
	      /* Now glue to end */
1306
	      after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
1307
	      link_bfd = *after_bfd;
1308
	      *after_bfd = current_ptr;
1309
	      current_ptr->archive_next = link_bfd;
1310
 
1311
	      if (verbose)
1312
		printf ("m - %s\n", *files_to_move);
1313
 
1314
	      goto next_file;
1315
	    }
1316
 
1317
	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
1318
	}
1319
      /* xgettext:c-format */
1320
      fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
1321
 
1322
    next_file:;
1323
    }
1324
 
1325
  write_archive (arch);
1326
}
1327
 
1328
/* Ought to default to replacing in place, but this is existing practice!  */
1329
 
1330
static void
1331
replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
1332
{
1333
  bfd_boolean changed = FALSE;
1334
  bfd **after_bfd;		/* New entries go after this one.  */
1335
  bfd *current;
1336
  bfd **current_ptr;
1337
 
1338
  while (files_to_move && *files_to_move)
1339
    {
1340
      if (! quick)
1341
	{
1342
	  current_ptr = &arch->archive_next;
1343
	  while (*current_ptr)
1344
	    {
1345
	      current = *current_ptr;
1346
 
1347
	      /* For compatibility with existing ar programs, we
1348
		 permit the same file to be added multiple times.  */
1349
	      if (FILENAME_CMP (normalize (*files_to_move, arch),
1350
				normalize (current->filename, arch)) == 0
1351
		  && current->arelt_data != NULL)
1352
		{
1353
		  if (newer_only)
1354
		    {
1355
		      struct stat fsbuf, asbuf;
1356
 
1357
		      if (stat (*files_to_move, &fsbuf) != 0)
1358
			{
1359
			  if (errno != ENOENT)
1360
			    bfd_fatal (*files_to_move);
1361
			  goto next_file;
1362
			}
1363
		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
1364
			/* xgettext:c-format */
1365
			fatal (_("internal stat error on %s"),
1366
			       current->filename);
1367
 
1368
		      if (fsbuf.st_mtime <= asbuf.st_mtime)
1369
			goto next_file;
1370
		    }
1371
 
1372
		  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
1373
					   current->filename);
1374
		  if (ar_emul_replace (after_bfd, *files_to_move,
1375
				       target, verbose))
1376
		    {
1377
		      /* Snip out this entry from the chain.  */
1378
		      *current_ptr = (*current_ptr)->archive_next;
1379
		      changed = TRUE;
1380
		    }
1381
 
1382
		  goto next_file;
1383
		}
1384
	      current_ptr = &(current->archive_next);
1385
	    }
1386
	}
1387
 
1388
      /* Add to the end of the archive.  */
1389
      after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
1390
 
1391
      if (ar_emul_append (after_bfd, *files_to_move, target,
1392
			  verbose, make_thin_archive))
1393
	changed = TRUE;
1394
 
1395
    next_file:;
1396
 
1397
      files_to_move++;
1398
    }
1399
 
1400
  if (changed)
1401
    write_archive (arch);
1402
  else
1403
    output_filename = NULL;
1404
}
1405
 
1406
static int
1407
ranlib_only (const char *archname)
1408
{
1409
  bfd *arch;
1410
 
1411
  if (get_file_size (archname) < 1)
1412
    return 1;
1413
  write_armap = 1;
1414
  arch = open_inarch (archname, (char *) NULL);
1415
  if (arch == NULL)
1416
    xexit (1);
1417
  write_archive (arch);
1418
  return 0;
1419
}
1420
 
1421
/* Update the timestamp of the symbol map of an archive.  */
1422
 
1423
static int
1424
ranlib_touch (const char *archname)
1425
{
1426
#ifdef __GO32__
1427
  /* I don't think updating works on go32.  */
1428
  ranlib_only (archname);
1429
#else
1430
  int f;
1431
  bfd *arch;
1432
  char **matching;
1433
 
1434
  if (get_file_size (archname) < 1)
1435
    return 1;
1436
  f = open (archname, O_RDWR | O_BINARY, 0);
1437
  if (f < 0)
1438
    {
1439
      bfd_set_error (bfd_error_system_call);
1440
      bfd_fatal (archname);
1441
    }
1442
 
1443
  arch = bfd_fdopenr (archname, (const char *) NULL, f);
1444
  if (arch == NULL)
1445
    bfd_fatal (archname);
1446
  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
1447
    {
1448
      bfd_nonfatal (archname);
1449
      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
1450
	{
1451
	  list_matching_formats (matching);
1452
	  free (matching);
1453
	}
1454
      xexit (1);
1455
    }
1456
 
1457
  if (! bfd_has_map (arch))
1458
    /* xgettext:c-format */
1459
    fatal (_("%s: no archive map to update"), archname);
1460
 
1461
  if (deterministic)
1462
    arch->flags |= BFD_DETERMINISTIC_OUTPUT;
1463
 
1464
  bfd_update_armap_timestamp (arch);
1465
 
1466
  if (! bfd_close (arch))
1467
    bfd_fatal (archname);
1468
#endif
1469
  return 0;
1470
}
1471
 
1472
/* Things which are interesting to map over all or some of the files: */
1473
 
1474
static void
1475
print_descr (bfd *abfd)
1476
{
1477
  print_arelt_descr (stdout, abfd, verbose);
1478
}