/* Generic BFD support for file formats.
- Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 92, 93, 94, 95, 1999 Free Software Foundation, Inc.
Written by Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
SECTION
- File Formats
+ File formats
A format is a BFD concept of high level file contents type. The
formats supported by BFD are:
#include "sysdep.h"
#include "libbfd.h"
-extern bfd_target *target_vector[];
-extern bfd_target *default_vector[];
-
+/* IMPORT from targets.c. */
+extern const size_t _bfd_target_vector_entries;
/*
FUNCTION
The function returns <<true>> on success, otherwise <<false>>
with one of the following error codes:
- o invalid_operation -
+ o <<bfd_error_invalid_operation>> -
if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or
<<bfd_core>>.
- o system_call_error -
+ o <<bfd_error_system_call>> -
if an error occured during a read - even some file mismatches
- can cause system_call_errors.
+ can cause bfd_error_system_calls.
- o file_not_recognised -
+ o <<file_not_recognised>> -
none of the backends recognised the file format.
- o file_ambiguously_recognized -
+ o <<bfd_error_file_ambiguously_recognized>> -
more than one backend recognised the file format.
+*/
+
+boolean
+bfd_check_format (abfd, format)
+ bfd *abfd;
+ bfd_format format;
+{
+ return bfd_check_format_matches (abfd, format, NULL);
+}
+
+/*
+FUNCTION
+ bfd_check_format_matches
+
+SYNOPSIS
+ boolean bfd_check_format_matches(bfd *abfd, bfd_format format, char ***matching);
+DESCRIPTION
+ Like <<bfd_check_format>>, except when it returns false with
+ <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that
+ case, if @var{matching} is not NULL, it will be filled in with
+ a NULL-terminated list of the names of the formats that matched,
+ allocated with <<malloc>>.
+ Then the user may choose a format and try again.
+
+ When done with the list that @var{matching} points to, the caller
+ should free it.
*/
boolean
-DEFUN(bfd_check_format,(abfd, format),
- bfd *abfd AND
- bfd_format format)
+bfd_check_format_matches (abfd, format, matching)
+ bfd *abfd;
+ bfd_format format;
+ char ***matching;
{
- bfd_target **target, *save_targ, *right_targ;
+ extern const bfd_target binary_vec;
+ const bfd_target * const *target, *save_targ, *right_targ;
+ char **matching_vector = NULL;
int match_count;
if (!bfd_read_p (abfd) ||
((int)(abfd->format) < (int)bfd_unknown) ||
((int)(abfd->format) >= (int)bfd_type_end)) {
- bfd_error = invalid_operation;
+ bfd_set_error (bfd_error_invalid_operation);
return false;
}
save_targ = abfd->xvec;
match_count = 0;
+ if (matching)
+ {
+ matching_vector =
+ (char **) bfd_malloc (sizeof (char *) *
+ (_bfd_target_vector_entries + 1));
+ if (!matching_vector)
+ return false;
+ matching_vector[0] = NULL;
+ *matching = matching_vector;
+ }
right_targ = 0;
/* If the target type was explicitly specified, just check that target. */
if (!abfd->target_defaulted) {
- bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* rewind! */
-
+ if (bfd_seek (abfd, (file_ptr)0, SEEK_SET) != 0) /* rewind! */
+ return false;
right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
if (right_targ) {
abfd->xvec = right_targ; /* Set the target as returned */
+ if (matching)
+ free (matching_vector);
return true; /* File position has moved, BTW */
}
+
+ /* For a long time the code has dropped through to check all
+ targets if the specified target was wrong. I don't know why,
+ and I'm reluctant to change it. However, in the case of an
+ archive, it can cause problems. If the specified target does
+ not permit archives (e.g., the binary target), then we should
+ not allow some other target to recognize it as an archive, but
+ should instead allow the specified target to recognize it as an
+ object. When I first made this change, it broke the PE target,
+ because the specified pei-i386 target did not recognize the
+ actual pe-i386 archive. Since there may be other problems of
+ this sort, I changed this test to check only for the binary
+ target. */
+
+ if (format == bfd_archive && save_targ == &binary_vec)
+ {
+ abfd->xvec = save_targ;
+ abfd->format = bfd_unknown;
+ if (matching)
+ free (matching_vector);
+ bfd_set_error (bfd_error_file_not_recognized);
+ return false;
+ }
}
- for (target = target_vector; *target != NULL; target++) {
- bfd_target *temp;
+ for (target = bfd_target_vector; *target != NULL; target++) {
+ const bfd_target *temp;
+
+ if (*target == &binary_vec)
+ continue;
abfd->xvec = *target; /* Change BFD's target temporarily */
- bfd_seek (abfd, (file_ptr)0, SEEK_SET);
- /* If _bfd_check_format neglects to set bfd_error, assume wrong_format.
+ if (bfd_seek (abfd, (file_ptr)0, SEEK_SET) != 0)
+ return false;
+ /* If _bfd_check_format neglects to set bfd_error, assume bfd_error_wrong_format.
We didn't used to even pay any attention to bfd_error, so I suspect
that some _bfd_check_format might have this problem. */
- bfd_error = wrong_format;
+ bfd_set_error (bfd_error_wrong_format);
temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
if (temp) { /* This format checks out as ok! */
right_targ = temp;
+ if (matching)
+ {
+ matching_vector[match_count] = temp->name;
+ matching_vector[match_count + 1] = NULL;
+ }
match_count++;
/* If this is the default target, accept it, even if other targets
might match. People who want those other targets have to set
the GNUTARGET variable. */
- if (temp == default_vector[0])
+ if (temp == bfd_default_vector[0])
{
+ if (matching)
+ {
+ matching_vector[0] = temp->name;
+ matching_vector[1] = NULL;
+ }
match_count = 1;
break;
}
*/
break;
#endif
- } else if (bfd_error != wrong_format) {
+ } else if (bfd_get_error () != bfd_error_wrong_format) {
abfd->xvec = save_targ;
abfd->format = bfd_unknown;
+ if (matching && bfd_get_error () != bfd_error_file_ambiguously_recognized)
+ free (matching_vector);
return false;
}
}
if (match_count == 1) {
abfd->xvec = right_targ; /* Change BFD's target permanently */
+ if (matching)
+ free (matching_vector);
return true; /* File position has moved, BTW */
}
abfd->xvec = save_targ; /* Restore original target type */
abfd->format = bfd_unknown; /* Restore original format */
- bfd_error = ((match_count == 0) ? file_not_recognized :
- file_ambiguously_recognized);
+ if (match_count == 0)
+ {
+ bfd_set_error (bfd_error_file_not_recognized);
+ if (matching)
+ free (matching_vector);
+ }
+ else
+ bfd_set_error (bfd_error_file_ambiguously_recognized);
return false;
}
-
/*
FUNCTION
bfd_set_format
*/
boolean
-DEFUN(bfd_set_format,(abfd, format),
- bfd *abfd AND
- bfd_format format)
+bfd_set_format (abfd, format)
+ bfd *abfd;
+ bfd_format format;
{
if (bfd_read_p (abfd) ||
((int)abfd->format < (int)bfd_unknown) ||
((int)abfd->format >= (int)bfd_type_end)) {
- bfd_error = invalid_operation;
+ bfd_set_error (bfd_error_invalid_operation);
return false;
}
*/
CONST char *
-DEFUN(bfd_format_string,(format),
- bfd_format format)
+bfd_format_string (format)
+ bfd_format format;
{
if (((int)format <(int) bfd_unknown)
|| ((int)format >=(int) bfd_type_end))