xref: /openbsd-src/gnu/usr.bin/binutils-2.17/binutils/strings.c (revision c9d030158940138bbf3a8ffc0f3f0d0e2eba1687)
13d8817e4Smiod /* strings -- print the strings of printable characters in files
23d8817e4Smiod    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
33d8817e4Smiod    2002, 2003, 2004, 2005 Free Software Foundation, Inc.
43d8817e4Smiod 
53d8817e4Smiod    This program is free software; you can redistribute it and/or modify
63d8817e4Smiod    it under the terms of the GNU General Public License as published by
73d8817e4Smiod    the Free Software Foundation; either version 2, or (at your option)
83d8817e4Smiod    any later version.
93d8817e4Smiod 
103d8817e4Smiod    This program is distributed in the hope that it will be useful,
113d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
123d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
133d8817e4Smiod    GNU General Public License for more details.
143d8817e4Smiod 
153d8817e4Smiod    You should have received a copy of the GNU General Public License
163d8817e4Smiod    along with this program; if not, write to the Free Software
173d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
183d8817e4Smiod    02110-1301, USA.  */
193d8817e4Smiod 
203d8817e4Smiod /* Usage: strings [options] file...
213d8817e4Smiod 
223d8817e4Smiod    Options:
233d8817e4Smiod    --all
243d8817e4Smiod    -a
253d8817e4Smiod    -		Do not scan only the initialized data section of object files.
263d8817e4Smiod 
273d8817e4Smiod    --print-file-name
283d8817e4Smiod    -f		Print the name of the file before each string.
293d8817e4Smiod 
303d8817e4Smiod    --bytes=min-len
313d8817e4Smiod    -n min-len
323d8817e4Smiod    -min-len	Print graphic char sequences, MIN-LEN or more bytes long,
333d8817e4Smiod 		that are followed by a NUL or a newline.  Default is 4.
343d8817e4Smiod 
353d8817e4Smiod    --radix={o,x,d}
363d8817e4Smiod    -t {o,x,d}	Print the offset within the file before each string,
373d8817e4Smiod 		in octal/hex/decimal.
383d8817e4Smiod 
393d8817e4Smiod    -o		Like -to.  (Some other implementations have -o like -to,
403d8817e4Smiod 		others like -td.  We chose one arbitrarily.)
413d8817e4Smiod 
423d8817e4Smiod    --encoding={s,S,b,l,B,L}
433d8817e4Smiod    -e {s,S,b,l,B,L}
443d8817e4Smiod 		Select character encoding: 7-bit-character, 8-bit-character,
453d8817e4Smiod 		bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
463d8817e4Smiod 		littleendian 32-bit.
473d8817e4Smiod 
483d8817e4Smiod    --target=BFDNAME
493d8817e4Smiod 		Specify a non-default object file format.
503d8817e4Smiod 
513d8817e4Smiod    --help
523d8817e4Smiod    -h		Print the usage message on the standard output.
533d8817e4Smiod 
543d8817e4Smiod    --version
553d8817e4Smiod    -v		Print the program version number.
563d8817e4Smiod 
573d8817e4Smiod    Written by Richard Stallman <rms@gnu.ai.mit.edu>
583d8817e4Smiod    and David MacKenzie <djm@gnu.ai.mit.edu>.  */
593d8817e4Smiod 
603d8817e4Smiod #ifdef HAVE_CONFIG_H
613d8817e4Smiod #include "config.h"
623d8817e4Smiod #endif
633d8817e4Smiod #include "bfd.h"
643d8817e4Smiod #include <stdio.h>
653d8817e4Smiod #include "getopt.h"
663d8817e4Smiod #include <errno.h>
673d8817e4Smiod #include "bucomm.h"
683d8817e4Smiod #include "libiberty.h"
693d8817e4Smiod #include "safe-ctype.h"
703d8817e4Smiod #include <sys/stat.h>
713d8817e4Smiod 
723d8817e4Smiod /* Some platforms need to put stdin into binary mode, to read
733d8817e4Smiod     binary files.  */
743d8817e4Smiod #ifdef HAVE_SETMODE
753d8817e4Smiod #ifndef O_BINARY
763d8817e4Smiod #ifdef _O_BINARY
773d8817e4Smiod #define O_BINARY _O_BINARY
783d8817e4Smiod #define setmode _setmode
793d8817e4Smiod #else
803d8817e4Smiod #define O_BINARY 0
813d8817e4Smiod #endif
823d8817e4Smiod #endif
833d8817e4Smiod #if O_BINARY
843d8817e4Smiod #include <io.h>
853d8817e4Smiod #define SET_BINARY(f) do { if (!isatty (f)) setmode (f,O_BINARY); } while (0)
863d8817e4Smiod #endif
873d8817e4Smiod #endif
883d8817e4Smiod 
893d8817e4Smiod #define STRING_ISGRAPHIC(c) \
903d8817e4Smiod       (   (c) >= 0 \
913d8817e4Smiod        && (c) <= 255 \
923d8817e4Smiod        && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127)))
933d8817e4Smiod 
943d8817e4Smiod #ifndef errno
953d8817e4Smiod extern int errno;
963d8817e4Smiod #endif
973d8817e4Smiod 
983d8817e4Smiod /* The BFD section flags that identify an initialized data section.  */
993d8817e4Smiod #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
1003d8817e4Smiod 
1013d8817e4Smiod #ifdef HAVE_FOPEN64
1023d8817e4Smiod typedef off64_t file_off;
1033d8817e4Smiod #define file_open(s,m) fopen64(s, m)
1043d8817e4Smiod #else
1053d8817e4Smiod typedef off_t file_off;
1063d8817e4Smiod #define file_open(s,m) fopen(s, m)
1073d8817e4Smiod #endif
1083d8817e4Smiod #ifdef HAVE_STAT64
1093d8817e4Smiod typedef struct stat64 statbuf;
1103d8817e4Smiod #define file_stat(f,s) stat64(f, s)
1113d8817e4Smiod #else
1123d8817e4Smiod typedef struct stat statbuf;
1133d8817e4Smiod #define file_stat(f,s) stat(f, s)
1143d8817e4Smiod #endif
1153d8817e4Smiod 
1163d8817e4Smiod /* Radix for printing addresses (must be 8, 10 or 16).  */
1173d8817e4Smiod static int address_radix;
1183d8817e4Smiod 
1193d8817e4Smiod /* Minimum length of sequence of graphic chars to trigger output.  */
1203d8817e4Smiod static int string_min;
1213d8817e4Smiod 
1223d8817e4Smiod /* TRUE means print address within file for each string.  */
1233d8817e4Smiod static bfd_boolean print_addresses;
1243d8817e4Smiod 
1253d8817e4Smiod /* TRUE means print filename for each string.  */
1263d8817e4Smiod static bfd_boolean print_filenames;
1273d8817e4Smiod 
1283d8817e4Smiod /* TRUE means for object files scan only the data section.  */
1293d8817e4Smiod static bfd_boolean datasection_only;
1303d8817e4Smiod 
1313d8817e4Smiod /* TRUE if we found an initialized data section in the current file.  */
1323d8817e4Smiod static bfd_boolean got_a_section;
1333d8817e4Smiod 
1343d8817e4Smiod /* The BFD object file format.  */
1353d8817e4Smiod static char *target;
1363d8817e4Smiod 
1373d8817e4Smiod /* The character encoding format.  */
1383d8817e4Smiod static char encoding;
1393d8817e4Smiod static int encoding_bytes;
1403d8817e4Smiod 
1413d8817e4Smiod static struct option long_options[] =
1423d8817e4Smiod {
1433d8817e4Smiod   {"all", no_argument, NULL, 'a'},
1443d8817e4Smiod   {"print-file-name", no_argument, NULL, 'f'},
1453d8817e4Smiod   {"bytes", required_argument, NULL, 'n'},
1463d8817e4Smiod   {"radix", required_argument, NULL, 't'},
1473d8817e4Smiod   {"encoding", required_argument, NULL, 'e'},
1483d8817e4Smiod   {"target", required_argument, NULL, 'T'},
1493d8817e4Smiod   {"help", no_argument, NULL, 'h'},
1503d8817e4Smiod   {"version", no_argument, NULL, 'v'},
1513d8817e4Smiod   {NULL, 0, NULL, 0}
1523d8817e4Smiod };
1533d8817e4Smiod 
1543d8817e4Smiod /* Records the size of a named file so that we
1553d8817e4Smiod    do not repeatedly run bfd_stat() on it.  */
1563d8817e4Smiod 
1573d8817e4Smiod typedef struct
1583d8817e4Smiod {
1593d8817e4Smiod   const char *  filename;
1603d8817e4Smiod   bfd_size_type filesize;
1613d8817e4Smiod } filename_and_size_t;
1623d8817e4Smiod 
1633d8817e4Smiod static void strings_a_section (bfd *, asection *, void *);
1643d8817e4Smiod static bfd_boolean strings_object_file (const char *);
1653d8817e4Smiod static bfd_boolean strings_file (char *file);
1663d8817e4Smiod static int integer_arg (char *s);
1673d8817e4Smiod static void print_strings (const char *, FILE *, file_off, int, int, char *);
1683d8817e4Smiod static void usage (FILE *, int);
1693d8817e4Smiod static long get_char (FILE *, file_off *, int *, char **);
1703d8817e4Smiod 
1713d8817e4Smiod int main (int, char **);
1723d8817e4Smiod 
1733d8817e4Smiod int
main(int argc,char ** argv)1743d8817e4Smiod main (int argc, char **argv)
1753d8817e4Smiod {
1763d8817e4Smiod   int optc;
1773d8817e4Smiod   int exit_status = 0;
1783d8817e4Smiod   bfd_boolean files_given = FALSE;
1793d8817e4Smiod 
1803d8817e4Smiod #if defined (HAVE_SETLOCALE)
1813d8817e4Smiod   setlocale (LC_ALL, "");
1823d8817e4Smiod #endif
1833d8817e4Smiod   bindtextdomain (PACKAGE, LOCALEDIR);
1843d8817e4Smiod   textdomain (PACKAGE);
1853d8817e4Smiod 
186c1f838d9Spascal   if (pledge ("stdio rpath", NULL) == -1)
187c1f838d9Spascal     fatal (_("Failed to pledge"));
188c1f838d9Spascal 
1893d8817e4Smiod   program_name = argv[0];
1903d8817e4Smiod   xmalloc_set_program_name (program_name);
1913d8817e4Smiod 
1923d8817e4Smiod   expandargv (&argc, &argv);
1933d8817e4Smiod 
1943d8817e4Smiod   string_min = -1;
1953d8817e4Smiod   print_addresses = FALSE;
1963d8817e4Smiod   print_filenames = FALSE;
1973d8817e4Smiod   datasection_only = TRUE;
1983d8817e4Smiod   target = NULL;
1993d8817e4Smiod   encoding = 's';
2003d8817e4Smiod 
2013d8817e4Smiod   while ((optc = getopt_long (argc, argv, "afhHn:ot:e:Vv0123456789",
2023d8817e4Smiod 			      long_options, (int *) 0)) != EOF)
2033d8817e4Smiod     {
2043d8817e4Smiod       switch (optc)
2053d8817e4Smiod 	{
2063d8817e4Smiod 	case 'a':
2073d8817e4Smiod 	  datasection_only = FALSE;
2083d8817e4Smiod 	  break;
2093d8817e4Smiod 
2103d8817e4Smiod 	case 'f':
2113d8817e4Smiod 	  print_filenames = TRUE;
2123d8817e4Smiod 	  break;
2133d8817e4Smiod 
2143d8817e4Smiod 	case 'H':
2153d8817e4Smiod 	case 'h':
2163d8817e4Smiod 	  usage (stdout, 0);
2173d8817e4Smiod 
2183d8817e4Smiod 	case 'n':
2193d8817e4Smiod 	  string_min = integer_arg (optarg);
2203d8817e4Smiod 	  if (string_min < 1)
2213d8817e4Smiod 	    fatal (_("invalid number %s"), optarg);
2223d8817e4Smiod 	  break;
2233d8817e4Smiod 
2243d8817e4Smiod 	case 'o':
2253d8817e4Smiod 	  print_addresses = TRUE;
2263d8817e4Smiod 	  address_radix = 8;
2273d8817e4Smiod 	  break;
2283d8817e4Smiod 
2293d8817e4Smiod 	case 't':
2303d8817e4Smiod 	  print_addresses = TRUE;
2313d8817e4Smiod 	  if (optarg[1] != '\0')
2323d8817e4Smiod 	    usage (stderr, 1);
2333d8817e4Smiod 	  switch (optarg[0])
2343d8817e4Smiod 	    {
2353d8817e4Smiod 	    case 'o':
2363d8817e4Smiod 	      address_radix = 8;
2373d8817e4Smiod 	      break;
2383d8817e4Smiod 
2393d8817e4Smiod 	    case 'd':
2403d8817e4Smiod 	      address_radix = 10;
2413d8817e4Smiod 	      break;
2423d8817e4Smiod 
2433d8817e4Smiod 	    case 'x':
2443d8817e4Smiod 	      address_radix = 16;
2453d8817e4Smiod 	      break;
2463d8817e4Smiod 
2473d8817e4Smiod 	    default:
2483d8817e4Smiod 	      usage (stderr, 1);
2493d8817e4Smiod 	    }
2503d8817e4Smiod 	  break;
2513d8817e4Smiod 
2523d8817e4Smiod 	case 'T':
2533d8817e4Smiod 	  target = optarg;
2543d8817e4Smiod 	  break;
2553d8817e4Smiod 
2563d8817e4Smiod 	case 'e':
2573d8817e4Smiod 	  if (optarg[1] != '\0')
2583d8817e4Smiod 	    usage (stderr, 1);
2593d8817e4Smiod 	  encoding = optarg[0];
2603d8817e4Smiod 	  break;
2613d8817e4Smiod 
2623d8817e4Smiod 	case 'V':
2633d8817e4Smiod 	case 'v':
2643d8817e4Smiod 	  print_version ("strings");
2653d8817e4Smiod 	  break;
2663d8817e4Smiod 
2673d8817e4Smiod 	case '?':
2683d8817e4Smiod 	  usage (stderr, 1);
2693d8817e4Smiod 
2703d8817e4Smiod 	default:
2713d8817e4Smiod 	  if (string_min < 0)
2723d8817e4Smiod 	    string_min = optc - '0';
2733d8817e4Smiod 	  else
2743d8817e4Smiod 	    string_min = string_min * 10 + optc - '0';
2753d8817e4Smiod 	  break;
2763d8817e4Smiod 	}
2773d8817e4Smiod     }
2783d8817e4Smiod 
2793d8817e4Smiod   if (string_min < 0)
2803d8817e4Smiod     string_min = 4;
2813d8817e4Smiod 
2823d8817e4Smiod   switch (encoding)
2833d8817e4Smiod     {
2843d8817e4Smiod     case 'S':
2853d8817e4Smiod     case 's':
2863d8817e4Smiod       encoding_bytes = 1;
2873d8817e4Smiod       break;
2883d8817e4Smiod     case 'b':
2893d8817e4Smiod     case 'l':
2903d8817e4Smiod       encoding_bytes = 2;
2913d8817e4Smiod       break;
2923d8817e4Smiod     case 'B':
2933d8817e4Smiod     case 'L':
2943d8817e4Smiod       encoding_bytes = 4;
2953d8817e4Smiod       break;
2963d8817e4Smiod     default:
2973d8817e4Smiod       usage (stderr, 1);
2983d8817e4Smiod     }
2993d8817e4Smiod 
3003d8817e4Smiod   bfd_init ();
3013d8817e4Smiod   set_default_bfd_target ();
3023d8817e4Smiod 
3033d8817e4Smiod   if (optind >= argc)
3043d8817e4Smiod     {
3053d8817e4Smiod       datasection_only = FALSE;
3063d8817e4Smiod #ifdef SET_BINARY
3073d8817e4Smiod       SET_BINARY (fileno (stdin));
3083d8817e4Smiod #endif
3093d8817e4Smiod       print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
3103d8817e4Smiod       files_given = TRUE;
3113d8817e4Smiod     }
3123d8817e4Smiod   else
3133d8817e4Smiod     {
3143d8817e4Smiod       for (; optind < argc; ++optind)
3153d8817e4Smiod 	{
3163d8817e4Smiod 	  if (strcmp (argv[optind], "-") == 0)
3173d8817e4Smiod 	    datasection_only = FALSE;
3183d8817e4Smiod 	  else
3193d8817e4Smiod 	    {
3203d8817e4Smiod 	      files_given = TRUE;
3213d8817e4Smiod 	      exit_status |= strings_file (argv[optind]) == FALSE;
3223d8817e4Smiod 	    }
3233d8817e4Smiod 	}
3243d8817e4Smiod     }
3253d8817e4Smiod 
3263d8817e4Smiod   if (!files_given)
3273d8817e4Smiod     usage (stderr, 1);
3283d8817e4Smiod 
3293d8817e4Smiod   return (exit_status);
3303d8817e4Smiod }
3313d8817e4Smiod 
3323d8817e4Smiod /* Scan section SECT of the file ABFD, whose printable name is in
3333d8817e4Smiod    ARG->filename and whose size might be in ARG->filesize.  If it
3343d8817e4Smiod    contains initialized data set `got_a_section' and print the
3353d8817e4Smiod    strings in it.
3363d8817e4Smiod 
3373d8817e4Smiod    FIXME: We ought to be able to return error codes/messages for
3383d8817e4Smiod    certain conditions.  */
3393d8817e4Smiod 
3403d8817e4Smiod static void
strings_a_section(bfd * abfd,asection * sect,void * arg)3413d8817e4Smiod strings_a_section (bfd *abfd, asection *sect, void *arg)
3423d8817e4Smiod {
3433d8817e4Smiod   filename_and_size_t * filename_and_sizep;
3443d8817e4Smiod   bfd_size_type *filesizep;
3453d8817e4Smiod   bfd_size_type sectsize;
3463d8817e4Smiod   void *mem;
3473d8817e4Smiod 
3483d8817e4Smiod   if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
3493d8817e4Smiod     return;
3503d8817e4Smiod 
3513d8817e4Smiod   sectsize = bfd_get_section_size (sect);
3523d8817e4Smiod 
3533d8817e4Smiod   if (sectsize <= 0)
3543d8817e4Smiod     return;
3553d8817e4Smiod 
3563d8817e4Smiod   /* Get the size of the file.  This might have been cached for us.  */
3573d8817e4Smiod   filename_and_sizep = (filename_and_size_t *) arg;
3583d8817e4Smiod   filesizep = & filename_and_sizep->filesize;
3593d8817e4Smiod 
3603d8817e4Smiod   if (*filesizep == 0)
3613d8817e4Smiod     {
3623d8817e4Smiod       struct stat st;
3633d8817e4Smiod 
3643d8817e4Smiod       if (bfd_stat (abfd, &st))
3653d8817e4Smiod 	return;
3663d8817e4Smiod 
3673d8817e4Smiod       /* Cache the result so that we do not repeatedly stat this file.  */
3683d8817e4Smiod       *filesizep = st.st_size;
3693d8817e4Smiod     }
3703d8817e4Smiod 
3713d8817e4Smiod   /* Compare the size of the section against the size of the file.
3723d8817e4Smiod      If the section is bigger then the file must be corrupt and
3733d8817e4Smiod      we should not try dumping it.  */
3743d8817e4Smiod   if (sectsize >= *filesizep)
3753d8817e4Smiod     return;
3763d8817e4Smiod 
3773d8817e4Smiod   mem = xmalloc (sectsize);
3783d8817e4Smiod 
3793d8817e4Smiod   if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize))
3803d8817e4Smiod     {
3813d8817e4Smiod       got_a_section = TRUE;
3823d8817e4Smiod 
3833d8817e4Smiod       print_strings (filename_and_sizep->filename, NULL, sect->filepos,
3843d8817e4Smiod 		     0, sectsize, mem);
3853d8817e4Smiod     }
3863d8817e4Smiod 
3873d8817e4Smiod   free (mem);
3883d8817e4Smiod }
3893d8817e4Smiod 
3903d8817e4Smiod /* Scan all of the sections in FILE, and print the strings
3913d8817e4Smiod    in the initialized data section(s).
3923d8817e4Smiod 
3933d8817e4Smiod    Return TRUE if successful,
3943d8817e4Smiod    FALSE if not (such as if FILE is not an object file).  */
3953d8817e4Smiod 
3963d8817e4Smiod static bfd_boolean
strings_object_file(const char * file)3973d8817e4Smiod strings_object_file (const char *file)
3983d8817e4Smiod {
3993d8817e4Smiod   filename_and_size_t filename_and_size;
4003d8817e4Smiod   bfd *abfd;
4013d8817e4Smiod 
4023d8817e4Smiod   abfd = bfd_openr (file, target);
4033d8817e4Smiod 
4043d8817e4Smiod   if (abfd == NULL)
4053d8817e4Smiod     /* Treat the file as a non-object file.  */
4063d8817e4Smiod     return FALSE;
4073d8817e4Smiod 
4083d8817e4Smiod   /* This call is mainly for its side effect of reading in the sections.
4093d8817e4Smiod      We follow the traditional behavior of `strings' in that we don't
4103d8817e4Smiod      complain if we don't recognize a file to be an object file.  */
4113d8817e4Smiod   if (!bfd_check_format (abfd, bfd_object))
4123d8817e4Smiod     {
4133d8817e4Smiod       bfd_close (abfd);
4143d8817e4Smiod       return FALSE;
4153d8817e4Smiod     }
4163d8817e4Smiod 
4173d8817e4Smiod   got_a_section = FALSE;
4183d8817e4Smiod   filename_and_size.filename = file;
4193d8817e4Smiod   filename_and_size.filesize = 0;
4203d8817e4Smiod   bfd_map_over_sections (abfd, strings_a_section, & filename_and_size);
4213d8817e4Smiod 
4223d8817e4Smiod   if (!bfd_close (abfd))
4233d8817e4Smiod     {
4243d8817e4Smiod       bfd_nonfatal (file);
4253d8817e4Smiod       return FALSE;
4263d8817e4Smiod     }
4273d8817e4Smiod 
4283d8817e4Smiod   return got_a_section;
4293d8817e4Smiod }
4303d8817e4Smiod 
4313d8817e4Smiod /* Print the strings in FILE.  Return TRUE if ok, FALSE if an error occurs.  */
4323d8817e4Smiod 
4333d8817e4Smiod static bfd_boolean
strings_file(char * file)4343d8817e4Smiod strings_file (char *file)
4353d8817e4Smiod {
4363d8817e4Smiod   statbuf st;
4373d8817e4Smiod 
4383d8817e4Smiod   if (file_stat (file, &st) < 0)
4393d8817e4Smiod     {
4403d8817e4Smiod       if (errno == ENOENT)
4413d8817e4Smiod 	non_fatal (_("'%s': No such file"), file);
4423d8817e4Smiod       else
4433d8817e4Smiod 	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
4443d8817e4Smiod 		   file, strerror (errno));
4453d8817e4Smiod       return FALSE;
4463d8817e4Smiod     }
4473d8817e4Smiod 
4483d8817e4Smiod   /* If we weren't told to scan the whole file,
4493d8817e4Smiod      try to open it as an object file and only look at
4503d8817e4Smiod      initialized data sections.  If that fails, fall back to the
4513d8817e4Smiod      whole file.  */
4523d8817e4Smiod   if (!datasection_only || !strings_object_file (file))
4533d8817e4Smiod     {
4543d8817e4Smiod       FILE *stream;
4553d8817e4Smiod 
4563d8817e4Smiod       stream = file_open (file, FOPEN_RB);
4573d8817e4Smiod       if (stream == NULL)
4583d8817e4Smiod 	{
4593d8817e4Smiod 	  fprintf (stderr, "%s: ", program_name);
4603d8817e4Smiod 	  perror (file);
4613d8817e4Smiod 	  return FALSE;
4623d8817e4Smiod 	}
4633d8817e4Smiod 
4643d8817e4Smiod       print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0);
4653d8817e4Smiod 
4663d8817e4Smiod       if (fclose (stream) == EOF)
4673d8817e4Smiod 	{
4683d8817e4Smiod 	  fprintf (stderr, "%s: ", program_name);
4693d8817e4Smiod 	  perror (file);
4703d8817e4Smiod 	  return FALSE;
4713d8817e4Smiod 	}
4723d8817e4Smiod     }
4733d8817e4Smiod 
4743d8817e4Smiod   return TRUE;
4753d8817e4Smiod }
4763d8817e4Smiod 
4773d8817e4Smiod /* Read the next character, return EOF if none available.
4783d8817e4Smiod    Assume that STREAM is positioned so that the next byte read
4793d8817e4Smiod    is at address ADDRESS in the file.
4803d8817e4Smiod 
4813d8817e4Smiod    If STREAM is NULL, do not read from it.
4823d8817e4Smiod    The caller can supply a buffer of characters
4833d8817e4Smiod    to be processed before the data in STREAM.
4843d8817e4Smiod    MAGIC is the address of the buffer and
4853d8817e4Smiod    MAGICCOUNT is how many characters are in it.  */
4863d8817e4Smiod 
4873d8817e4Smiod static long
get_char(FILE * stream,file_off * address,int * magiccount,char ** magic)4883d8817e4Smiod get_char (FILE *stream, file_off *address, int *magiccount, char **magic)
4893d8817e4Smiod {
4903d8817e4Smiod   int c, i;
4913d8817e4Smiod   long r = EOF;
4923d8817e4Smiod   unsigned char buf[4];
4933d8817e4Smiod 
4943d8817e4Smiod   for (i = 0; i < encoding_bytes; i++)
4953d8817e4Smiod     {
4963d8817e4Smiod       if (*magiccount)
4973d8817e4Smiod 	{
4983d8817e4Smiod 	  (*magiccount)--;
4993d8817e4Smiod 	  c = *(*magic)++;
5003d8817e4Smiod 	}
5013d8817e4Smiod       else
5023d8817e4Smiod 	{
5033d8817e4Smiod 	  if (stream == NULL)
5043d8817e4Smiod 	    return EOF;
5053d8817e4Smiod 
5063d8817e4Smiod 	  /* Only use getc_unlocked if we found a declaration for it.
5073d8817e4Smiod 	     Otherwise, libc is not thread safe by default, and we
5083d8817e4Smiod 	     should not use it.  */
5093d8817e4Smiod 
5103d8817e4Smiod #if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
5113d8817e4Smiod 	  c = getc_unlocked (stream);
5123d8817e4Smiod #else
5133d8817e4Smiod 	  c = getc (stream);
5143d8817e4Smiod #endif
5153d8817e4Smiod 	  if (c == EOF)
5163d8817e4Smiod 	    return EOF;
5173d8817e4Smiod 	}
5183d8817e4Smiod 
5193d8817e4Smiod       (*address)++;
5203d8817e4Smiod       buf[i] = c;
5213d8817e4Smiod     }
5223d8817e4Smiod 
5233d8817e4Smiod   switch (encoding)
5243d8817e4Smiod     {
5253d8817e4Smiod     case 'S':
5263d8817e4Smiod     case 's':
5273d8817e4Smiod       r = buf[0];
5283d8817e4Smiod       break;
5293d8817e4Smiod     case 'b':
5303d8817e4Smiod       r = (buf[0] << 8) | buf[1];
5313d8817e4Smiod       break;
5323d8817e4Smiod     case 'l':
5333d8817e4Smiod       r = buf[0] | (buf[1] << 8);
5343d8817e4Smiod       break;
5353d8817e4Smiod     case 'B':
5363d8817e4Smiod       r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
5373d8817e4Smiod 	((long) buf[2] << 8) | buf[3];
5383d8817e4Smiod       break;
5393d8817e4Smiod     case 'L':
5403d8817e4Smiod       r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
5413d8817e4Smiod 	((long) buf[3] << 24);
5423d8817e4Smiod       break;
5433d8817e4Smiod     }
5443d8817e4Smiod 
5453d8817e4Smiod   if (r == EOF)
5463d8817e4Smiod     return 0;
5473d8817e4Smiod 
5483d8817e4Smiod   return r;
5493d8817e4Smiod }
5503d8817e4Smiod 
5513d8817e4Smiod /* Find the strings in file FILENAME, read from STREAM.
5523d8817e4Smiod    Assume that STREAM is positioned so that the next byte read
5533d8817e4Smiod    is at address ADDRESS in the file.
5543d8817e4Smiod    Stop reading at address STOP_POINT in the file, if nonzero.
5553d8817e4Smiod 
5563d8817e4Smiod    If STREAM is NULL, do not read from it.
5573d8817e4Smiod    The caller can supply a buffer of characters
5583d8817e4Smiod    to be processed before the data in STREAM.
5593d8817e4Smiod    MAGIC is the address of the buffer and
5603d8817e4Smiod    MAGICCOUNT is how many characters are in it.
5613d8817e4Smiod    Those characters come at address ADDRESS and the data in STREAM follow.  */
5623d8817e4Smiod 
5633d8817e4Smiod static void
print_strings(const char * filename,FILE * stream,file_off address,int stop_point,int magiccount,char * magic)5643d8817e4Smiod print_strings (const char *filename, FILE *stream, file_off address,
5653d8817e4Smiod 	       int stop_point, int magiccount, char *magic)
5663d8817e4Smiod {
5673d8817e4Smiod   char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
5683d8817e4Smiod 
5693d8817e4Smiod   while (1)
5703d8817e4Smiod     {
5713d8817e4Smiod       file_off start;
5723d8817e4Smiod       int i;
5733d8817e4Smiod       long c;
5743d8817e4Smiod 
5753d8817e4Smiod       /* See if the next `string_min' chars are all graphic chars.  */
5763d8817e4Smiod     tryline:
5773d8817e4Smiod       if (stop_point && address >= stop_point)
5783d8817e4Smiod 	break;
5793d8817e4Smiod       start = address;
5803d8817e4Smiod       for (i = 0; i < string_min; i++)
5813d8817e4Smiod 	{
5823d8817e4Smiod 	  c = get_char (stream, &address, &magiccount, &magic);
5833d8817e4Smiod 	  if (c == EOF)
5843d8817e4Smiod 	    return;
5853d8817e4Smiod 	  if (! STRING_ISGRAPHIC (c))
5863d8817e4Smiod 	    /* Found a non-graphic.  Try again starting with next char.  */
5873d8817e4Smiod 	    goto tryline;
5883d8817e4Smiod 	  buf[i] = c;
5893d8817e4Smiod 	}
5903d8817e4Smiod 
5913d8817e4Smiod       /* We found a run of `string_min' graphic characters.  Print up
5923d8817e4Smiod 	 to the next non-graphic character.  */
5933d8817e4Smiod 
5943d8817e4Smiod       if (print_filenames)
5953d8817e4Smiod 	printf ("%s: ", filename);
5963d8817e4Smiod       if (print_addresses)
5973d8817e4Smiod 	switch (address_radix)
5983d8817e4Smiod 	  {
5993d8817e4Smiod 	  case 8:
6003d8817e4Smiod #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
6013d8817e4Smiod 	    if (sizeof (start) > sizeof (long))
6023d8817e4Smiod 	      printf ("%7Lo ", (unsigned long long) start);
6033d8817e4Smiod 	    else
6043d8817e4Smiod #else
6053d8817e4Smiod # if !BFD_HOST_64BIT_LONG
6063d8817e4Smiod 	    if (start != (unsigned long) start)
6073d8817e4Smiod 	      printf ("++%7lo ", (unsigned long) start);
6083d8817e4Smiod 	    else
6093d8817e4Smiod # endif
6103d8817e4Smiod #endif
6113d8817e4Smiod 	      printf ("%7lo ", (unsigned long) start);
6123d8817e4Smiod 	    break;
6133d8817e4Smiod 
6143d8817e4Smiod 	  case 10:
6153d8817e4Smiod #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
6163d8817e4Smiod 	    if (sizeof (start) > sizeof (long))
617*c9d03015Sjsg 	      printf ("%7lld ", (unsigned long long) start);
6183d8817e4Smiod 	    else
6193d8817e4Smiod #else
6203d8817e4Smiod # if !BFD_HOST_64BIT_LONG
6213d8817e4Smiod 	    if (start != (unsigned long) start)
6223d8817e4Smiod 	      printf ("++%7ld ", (unsigned long) start);
6233d8817e4Smiod 	    else
6243d8817e4Smiod # endif
6253d8817e4Smiod #endif
6263d8817e4Smiod 	      printf ("%7ld ", (long) start);
6273d8817e4Smiod 	    break;
6283d8817e4Smiod 
6293d8817e4Smiod 	  case 16:
6303d8817e4Smiod #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
6313d8817e4Smiod 	    if (sizeof (start) > sizeof (long))
632*c9d03015Sjsg 	      printf ("%7llx ", (unsigned long long) start);
6333d8817e4Smiod 	    else
6343d8817e4Smiod #else
6353d8817e4Smiod # if !BFD_HOST_64BIT_LONG
6363d8817e4Smiod 	    if (start != (unsigned long) start)
6373d8817e4Smiod 	      printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
6383d8817e4Smiod 		      (unsigned long) (start & 0xffffffff));
6393d8817e4Smiod 	    else
6403d8817e4Smiod # endif
6413d8817e4Smiod #endif
6423d8817e4Smiod 	      printf ("%7lx ", (unsigned long) start);
6433d8817e4Smiod 	    break;
6443d8817e4Smiod 	  }
6453d8817e4Smiod 
6463d8817e4Smiod       buf[i] = '\0';
6473d8817e4Smiod       fputs (buf, stdout);
6483d8817e4Smiod 
6493d8817e4Smiod       while (1)
6503d8817e4Smiod 	{
6513d8817e4Smiod 	  c = get_char (stream, &address, &magiccount, &magic);
6523d8817e4Smiod 	  if (c == EOF)
6533d8817e4Smiod 	    break;
6543d8817e4Smiod 	  if (! STRING_ISGRAPHIC (c))
6553d8817e4Smiod 	    break;
6563d8817e4Smiod 	  putchar (c);
6573d8817e4Smiod 	}
6583d8817e4Smiod 
6593d8817e4Smiod       putchar ('\n');
6603d8817e4Smiod     }
6613d8817e4Smiod }
6623d8817e4Smiod 
6633d8817e4Smiod /* Parse string S as an integer, using decimal radix by default,
6643d8817e4Smiod    but allowing octal and hex numbers as in C.  */
6653d8817e4Smiod 
6663d8817e4Smiod static int
integer_arg(char * s)6673d8817e4Smiod integer_arg (char *s)
6683d8817e4Smiod {
6693d8817e4Smiod   int value;
6703d8817e4Smiod   int radix = 10;
6713d8817e4Smiod   char *p = s;
6723d8817e4Smiod   int c;
6733d8817e4Smiod 
6743d8817e4Smiod   if (*p != '0')
6753d8817e4Smiod     radix = 10;
6763d8817e4Smiod   else if (*++p == 'x')
6773d8817e4Smiod     {
6783d8817e4Smiod       radix = 16;
6793d8817e4Smiod       p++;
6803d8817e4Smiod     }
6813d8817e4Smiod   else
6823d8817e4Smiod     radix = 8;
6833d8817e4Smiod 
6843d8817e4Smiod   value = 0;
6853d8817e4Smiod   while (((c = *p++) >= '0' && c <= '9')
6863d8817e4Smiod 	 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
6873d8817e4Smiod     {
6883d8817e4Smiod       value *= radix;
6893d8817e4Smiod       if (c >= '0' && c <= '9')
6903d8817e4Smiod 	value += c - '0';
6913d8817e4Smiod       else
6923d8817e4Smiod 	value += (c & ~40) - 'A';
6933d8817e4Smiod     }
6943d8817e4Smiod 
6953d8817e4Smiod   if (c == 'b')
6963d8817e4Smiod     value *= 512;
6973d8817e4Smiod   else if (c == 'B')
6983d8817e4Smiod     value *= 1024;
6993d8817e4Smiod   else
7003d8817e4Smiod     p--;
7013d8817e4Smiod 
7023d8817e4Smiod   if (*p)
7033d8817e4Smiod     fatal (_("invalid integer argument %s"), s);
7043d8817e4Smiod 
7053d8817e4Smiod   return value;
7063d8817e4Smiod }
7073d8817e4Smiod 
7083d8817e4Smiod static void
usage(FILE * stream,int status)7093d8817e4Smiod usage (FILE *stream, int status)
7103d8817e4Smiod {
7113d8817e4Smiod   fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
7123d8817e4Smiod   fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
7133d8817e4Smiod   fprintf (stream, _(" The options are:\n\
7143d8817e4Smiod   -a - --all                Scan the entire file, not just the data section\n\
7153d8817e4Smiod   -f --print-file-name      Print the name of the file before each string\n\
7163d8817e4Smiod   -n --bytes=[number]       Locate & print any NUL-terminated sequence of at\n\
7173d8817e4Smiod   -<number>                 least [number] characters (default 4).\n\
7183d8817e4Smiod   -t --radix={o,d,x}        Print the location of the string in base 8, 10 or 16\n\
7193d8817e4Smiod   -o                        An alias for --radix=o\n\
7203d8817e4Smiod   -T --target=<BFDNAME>     Specify the binary file format\n\
7213d8817e4Smiod   -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
7223d8817e4Smiod                             s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
7233d8817e4Smiod   @<file>                   Read options from <file>\n\
7243d8817e4Smiod   -h --help                 Display this information\n\
7253d8817e4Smiod   -v --version              Print the program's version number\n"));
7263d8817e4Smiod   list_supported_targets (program_name, stream);
7273d8817e4Smiod   if (status == 0)
7283d8817e4Smiod     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
7293d8817e4Smiod   exit (status);
7303d8817e4Smiod }
731