+ free (arches);
+}
+\f
+static const char *
+endian_string (enum bfd_endian endian)
+{
+ switch (endian)
+ {
+ case BFD_ENDIAN_BIG: return _("big endian");
+ case BFD_ENDIAN_LITTLE: return _("little endian");
+ default: return _("endianness unknown");
+ }
+}
+
+/* Data passed to do_display_target and other target iterators. */
+
+struct display_target {
+ /* Temp file. */
+ char *filename;
+ /* Return status. */
+ int error;
+ /* Number of targets. */
+ int count;
+ /* Size of info in bytes. */
+ size_t alloc;
+ /* Per-target info. */
+ struct {
+ /* Target name. */
+ const char *name;
+ /* Non-zero if target/arch combination supported. */
+ unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1];
+ } *info;
+};
+
+/* List the targets that BFD is configured to support, each followed
+ by its endianness and the architectures it supports. Also build
+ info about target/archs. */
+
+static int
+do_display_target (const bfd_target *targ, void *data)
+{
+ struct display_target *param = (struct display_target *) data;
+ bfd *abfd;
+ size_t amt;
+
+ param->count += 1;
+ amt = param->count * sizeof (*param->info);
+ if (param->alloc < amt)
+ {
+ size_t size = ((param->count < 64 ? 64 : param->count)
+ * sizeof (*param->info) * 2);
+ param->info = xrealloc (param->info, size);
+ memset ((char *) param->info + param->alloc, 0, size - param->alloc);
+ param->alloc = size;
+ }
+ param->info[param->count - 1].name = targ->name;
+
+ printf (_("%s\n (header %s, data %s)\n"), targ->name,
+ endian_string (targ->header_byteorder),
+ endian_string (targ->byteorder));
+
+ abfd = bfd_openw (param->filename, targ->name);
+ if (abfd == NULL)
+ {
+ bfd_nonfatal (param->filename);
+ param->error = 1;
+ }
+ else if (!bfd_set_format (abfd, bfd_object))
+ {
+ if (bfd_get_error () != bfd_error_invalid_operation)
+ {
+ bfd_nonfatal (targ->name);
+ param->error = 1;
+ }
+ }
+ else
+ {
+ enum bfd_architecture a;
+
+ for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
+ if (bfd_set_arch_mach (abfd, a, 0))
+ {
+ printf (" %s\n", bfd_printable_arch_mach (a, 0));
+ param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
+ }
+ }
+ if (abfd != NULL)
+ bfd_close_all_done (abfd);
+
+ return param->error;
+}
+
+static void
+display_target_list (struct display_target *arg)
+{
+ arg->filename = make_temp_file (NULL);
+ arg->error = 0;
+ arg->count = 0;
+ arg->alloc = 0;
+ arg->info = NULL;
+
+ bfd_iterate_over_targets (do_display_target, arg);
+
+ unlink (arg->filename);
+ free (arg->filename);
+}
+
+/* Calculate how many targets we can print across the page. */
+
+static int
+do_info_size (int targ, int width, const struct display_target *arg)
+{
+ while (targ < arg->count)
+ {
+ width -= strlen (arg->info[targ].name) + 1;
+ if (width < 0)
+ return targ;
+ ++targ;
+ }
+ return targ;
+}
+
+/* Print header of target names. */
+
+static void
+do_info_header (int targ, int stop_targ, const struct display_target *arg)
+{
+ while (targ != stop_targ)
+ printf ("%s ", arg->info[targ++].name);
+}
+
+/* Print a table row. */
+
+static void
+do_info_row (int targ, int stop_targ, enum bfd_architecture a,
+ const struct display_target *arg)
+{
+ while (targ != stop_targ)
+ {
+ if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
+ fputs (arg->info[targ].name, stdout);
+ else
+ {
+ int l = strlen (arg->info[targ].name);
+ while (l--)
+ putchar ('-');
+ }
+ ++targ;
+ if (targ != stop_targ)
+ putchar (' ');
+ }
+}
+
+/* Print tables of all the target-architecture combinations that
+ BFD has been configured to support. */
+
+static void
+display_target_tables (const struct display_target *arg)
+{
+ const char *columns;
+ int width, start_targ, stop_targ;
+ enum bfd_architecture arch;
+ int longest_arch = 0;
+
+ for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
+ {
+ const char *s = bfd_printable_arch_mach (arch, 0);
+ int len = strlen (s);
+ if (len > longest_arch)
+ longest_arch = len;
+ }
+
+ width = 0;
+ columns = getenv ("COLUMNS");
+ if (columns != NULL)
+ width = atoi (columns);
+ if (width == 0)
+ width = 80;
+
+ for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
+ {
+ stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
+
+ printf ("\n%*s", longest_arch + 1, " ");
+ do_info_header (start_targ, stop_targ, arg);
+ putchar ('\n');
+
+ for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
+ {
+ if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
+ {
+ printf ("%*s ", longest_arch,
+ bfd_printable_arch_mach (arch, 0));
+
+ do_info_row (start_targ, stop_targ, arch, arg);
+ putchar ('\n');
+ }
+ }
+ }
+}
+
+int
+display_info (void)
+{
+ struct display_target arg;
+
+ printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
+
+ display_target_list (&arg);
+ if (!arg.error)
+ display_target_tables (&arg);
+
+ return arg.error;