171671b9obrien/* strings -- print the strings of printable characters in files
271671b9obrien   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3d0f678fdim   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
471671b9obrien
571671b9obrien   This program is free software; you can redistribute it and/or modify
671671b9obrien   it under the terms of the GNU General Public License as published by
771671b9obrien   the Free Software Foundation; either version 2, or (at your option)
871671b9obrien   any later version.
971671b9obrien
1071671b9obrien   This program is distributed in the hope that it will be useful,
1171671b9obrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1271671b9obrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1371671b9obrien   GNU General Public License for more details.
1471671b9obrien
1571671b9obrien   You should have received a copy of the GNU General Public License
1671671b9obrien   along with this program; if not, write to the Free Software
170acbbeedim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
180acbbeedim   02110-1301, USA.  */
1971671b9obrien
2071671b9obrien/* Usage: strings [options] file...
2171671b9obrien
2271671b9obrien   Options:
2371671b9obrien   --all
2471671b9obrien   -a
2571671b9obrien   -		Do not scan only the initialized data section of object files.
2671671b9obrien
2771671b9obrien   --print-file-name
2871671b9obrien   -f		Print the name of the file before each string.
2971671b9obrien
3071671b9obrien   --bytes=min-len
3171671b9obrien   -n min-len
3271671b9obrien   -min-len	Print graphic char sequences, MIN-LEN or more bytes long,
3371671b9obrien		that are followed by a NUL or a newline.  Default is 4.
3471671b9obrien
3571671b9obrien   --radix={o,x,d}
3671671b9obrien   -t {o,x,d}	Print the offset within the file before each string,
3771671b9obrien		in octal/hex/decimal.
3871671b9obrien
3971671b9obrien   -o		Like -to.  (Some other implementations have -o like -to,
4071671b9obrien		others like -td.  We chose one arbitrarily.)
4171671b9obrien
4271671b9obrien   --encoding={s,S,b,l,B,L}
4371671b9obrien   -e {s,S,b,l,B,L}
4471671b9obrien		Select character encoding: 7-bit-character, 8-bit-character,
4571671b9obrien		bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
4671671b9obrien		littleendian 32-bit.
4771671b9obrien
4871671b9obrien   --target=BFDNAME
49d0f678fdim   -T {bfdname}
5071671b9obrien		Specify a non-default object file format.
5171671b9obrien
5271671b9obrien   --help
5371671b9obrien   -h		Print the usage message on the standard output.
5471671b9obrien
5571671b9obrien   --version
5671671b9obrien   -v		Print the program version number.
5771671b9obrien
5871671b9obrien   Written by Richard Stallman <rms@gnu.ai.mit.edu>
5971671b9obrien   and David MacKenzie <djm@gnu.ai.mit.edu>.  */
6071671b9obrien
61d0f678fdim#include "sysdep.h"
6271671b9obrien#include "bfd.h"
6371671b9obrien#include "getopt.h"
6471671b9obrien#include "libiberty.h"
6571671b9obrien#include "safe-ctype.h"
660acbbeedim#include <sys/stat.h>
67d0f678fdim#include "bucomm.h"
6871671b9obrien
6971671b9obrien/* Some platforms need to put stdin into binary mode, to read
7071671b9obrien    binary files.  */
7171671b9obrien#ifdef HAVE_SETMODE
7271671b9obrien#ifndef O_BINARY
7371671b9obrien#ifdef _O_BINARY
7471671b9obrien#define O_BINARY _O_BINARY
7571671b9obrien#define setmode _setmode
7671671b9obrien#else
7771671b9obrien#define O_BINARY 0
7871671b9obrien#endif
7971671b9obrien#endif
8071671b9obrien#if O_BINARY
8171671b9obrien#include <io.h>
8271671b9obrien#define SET_BINARY(f) do { if (!isatty (f)) setmode (f,O_BINARY); } while (0)
8371671b9obrien#endif
8471671b9obrien#endif
8571671b9obrien
8671671b9obrien#define STRING_ISGRAPHIC(c) \
8771671b9obrien      (   (c) >= 0 \
8871671b9obrien       && (c) <= 255 \
8971671b9obrien       && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127)))
9071671b9obrien
9171671b9obrien#ifndef errno
9271671b9obrienextern int errno;
9371671b9obrien#endif
9471671b9obrien
9571671b9obrien/* The BFD section flags that identify an initialized data section.  */
9671671b9obrien#define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
9771671b9obrien
9871671b9obrien#ifdef HAVE_FOPEN64
9971671b9obrientypedef off64_t file_off;
10071671b9obrien#define file_open(s,m) fopen64(s, m)
10171671b9obrien#else
10271671b9obrientypedef off_t file_off;
10371671b9obrien#define file_open(s,m) fopen(s, m)
10471671b9obrien#endif
1050acbbeedim#ifdef HAVE_STAT64
1060acbbeedimtypedef struct stat64 statbuf;
1070acbbeedim#define file_stat(f,s) stat64(f, s)
1080acbbeedim#else
1090acbbeedimtypedef struct stat statbuf;
1100acbbeedim#define file_stat(f,s) stat(f, s)
1110acbbeedim#endif
11271671b9obrien
11371671b9obrien/* Radix for printing addresses (must be 8, 10 or 16).  */
11471671b9obrienstatic int address_radix;
11571671b9obrien
11671671b9obrien/* Minimum length of sequence of graphic chars to trigger output.  */
11771671b9obrienstatic int string_min;
11871671b9obrien
11971671b9obrien/* TRUE means print address within file for each string.  */
12071671b9obrienstatic bfd_boolean print_addresses;
12171671b9obrien
12271671b9obrien/* TRUE means print filename for each string.  */
12371671b9obrienstatic bfd_boolean print_filenames;
12471671b9obrien
12571671b9obrien/* TRUE means for object files scan only the data section.  */
12671671b9obrienstatic bfd_boolean datasection_only;
12771671b9obrien
12871671b9obrien/* TRUE if we found an initialized data section in the current file.  */
12971671b9obrienstatic bfd_boolean got_a_section;
13071671b9obrien
13171671b9obrien/* The BFD object file format.  */
13271671b9obrienstatic char *target;
13371671b9obrien
13471671b9obrien/* The character encoding format.  */
13571671b9obrienstatic char encoding;
13671671b9obrienstatic int encoding_bytes;
13771671b9obrien
13871671b9obrienstatic struct option long_options[] =
13971671b9obrien{
14071671b9obrien  {"all", no_argument, NULL, 'a'},
14171671b9obrien  {"print-file-name", no_argument, NULL, 'f'},
14271671b9obrien  {"bytes", required_argument, NULL, 'n'},
14371671b9obrien  {"radix", required_argument, NULL, 't'},
14471671b9obrien  {"encoding", required_argument, NULL, 'e'},
14571671b9obrien  {"target", required_argument, NULL, 'T'},
14671671b9obrien  {"help", no_argument, NULL, 'h'},
14771671b9obrien  {"version", no_argument, NULL, 'v'},
14871671b9obrien  {NULL, 0, NULL, 0}
14971671b9obrien};
15071671b9obrien
1510acbbeedim/* Records the size of a named file so that we
1520acbbeedim   do not repeatedly run bfd_stat() on it.  */
1530acbbeedim
1540acbbeedimtypedef struct
1550acbbeedim{
1560acbbeedim  const char *  filename;
1570acbbeedim  bfd_size_type filesize;
1580acbbeedim} filename_and_size_t;
1590acbbeedim
16071671b9obrienstatic void strings_a_section (bfd *, asection *, void *);
16171671b9obrienstatic bfd_boolean strings_object_file (const char *);
16271671b9obrienstatic bfd_boolean strings_file (char *file);
16371671b9obrienstatic int integer_arg (char *s);
16471671b9obrienstatic void print_strings (const char *, FILE *, file_off, int, int, char *);
16571671b9obrienstatic void usage (FILE *, int);
16671671b9obrienstatic long get_char (FILE *, file_off *, int *, char **);
16771671b9obrien
16871671b9obrienint main (int, char **);
16971671b9obrien
17071671b9obrienint
17171671b9obrienmain (int argc, char **argv)
17271671b9obrien{
17371671b9obrien  int optc;
17471671b9obrien  int exit_status = 0;
17571671b9obrien  bfd_boolean files_given = FALSE;
17671671b9obrien
17771671b9obrien#if defined (HAVE_SETLOCALE)
17871671b9obrien  setlocale (LC_ALL, "");
17971671b9obrien#endif
18071671b9obrien  bindtextdomain (PACKAGE, LOCALEDIR);
18171671b9obrien  textdomain (PACKAGE);
18271671b9obrien
18371671b9obrien  program_name = argv[0];
18471671b9obrien  xmalloc_set_program_name (program_name);
1850acbbeedim
1860acbbeedim  expandargv (&argc, &argv);
1870acbbeedim
18871671b9obrien  string_min = -1;
18971671b9obrien  print_addresses = FALSE;
19071671b9obrien  print_filenames = FALSE;
19171671b9obrien  datasection_only = TRUE;
19271671b9obrien  target = NULL;
19371671b9obrien  encoding = 's';
19471671b9obrien
195d0f678fdim  while ((optc = getopt_long (argc, argv, "afhHn:ot:e:T:Vv0123456789",
19671671b9obrien			      long_options, (int *) 0)) != EOF)
19771671b9obrien    {
19871671b9obrien      switch (optc)
19971671b9obrien	{
20071671b9obrien	case 'a':
20171671b9obrien	  datasection_only = FALSE;
20271671b9obrien	  break;
20371671b9obrien
20471671b9obrien	case 'f':
20571671b9obrien	  print_filenames = TRUE;
20671671b9obrien	  break;
20771671b9obrien
20871671b9obrien	case 'H':
20971671b9obrien	case 'h':
21071671b9obrien	  usage (stdout, 0);
21171671b9obrien
21271671b9obrien	case 'n':
21371671b9obrien	  string_min = integer_arg (optarg);
21471671b9obrien	  if (string_min < 1)
21571671b9obrien	    fatal (_("invalid number %s"), optarg);
21671671b9obrien	  break;
21771671b9obrien
21871671b9obrien	case 'o':
21971671b9obrien	  print_addresses = TRUE;
22071671b9obrien	  address_radix = 8;
22171671b9obrien	  break;
22271671b9obrien
22371671b9obrien	case 't':
22471671b9obrien	  print_addresses = TRUE;
22571671b9obrien	  if (optarg[1] != '\0')
22671671b9obrien	    usage (stderr, 1);
22771671b9obrien	  switch (optarg[0])
22871671b9obrien	    {
22971671b9obrien	    case 'o':
23071671b9obrien	      address_radix = 8;
23171671b9obrien	      break;
23271671b9obrien
23371671b9obrien	    case 'd':
23471671b9obrien	      address_radix = 10;
23571671b9obrien	      break;
23671671b9obrien
23771671b9obrien	    case 'x':
23871671b9obrien	      address_radix = 16;
23971671b9obrien	      break;
24071671b9obrien
24171671b9obrien	    default:
24271671b9obrien	      usage (stderr, 1);
24371671b9obrien	    }
24471671b9obrien	  break;
24571671b9obrien
24671671b9obrien	case 'T':
24771671b9obrien	  target = optarg;
24871671b9obrien	  break;
24971671b9obrien
25071671b9obrien	case 'e':
25171671b9obrien	  if (optarg[1] != '\0')
25271671b9obrien	    usage (stderr, 1);
25371671b9obrien	  encoding = optarg[0];
25471671b9obrien	  break;
25571671b9obrien
25671671b9obrien	case 'V':
25771671b9obrien	case 'v':
25871671b9obrien	  print_version ("strings");
25971671b9obrien	  break;
26071671b9obrien
26171671b9obrien	case '?':
26271671b9obrien	  usage (stderr, 1);
26371671b9obrien
26471671b9obrien	default:
26571671b9obrien	  if (string_min < 0)
26671671b9obrien	    string_min = optc - '0';
26771671b9obrien	  else
26871671b9obrien	    string_min = string_min * 10 + optc - '0';
26971671b9obrien	  break;
27071671b9obrien	}
27171671b9obrien    }
27271671b9obrien
27371671b9obrien  if (string_min < 0)
27471671b9obrien    string_min = 4;
27571671b9obrien
27671671b9obrien  switch (encoding)
27771671b9obrien    {
27871671b9obrien    case 'S':
27971671b9obrien    case 's':
28071671b9obrien      encoding_bytes = 1;
28171671b9obrien      break;
28271671b9obrien    case 'b':
28371671b9obrien    case 'l':
28471671b9obrien      encoding_bytes = 2;
28571671b9obrien      break;
28671671b9obrien    case 'B':
28771671b9obrien    case 'L':
28871671b9obrien      encoding_bytes = 4;
28971671b9obrien      break;
29071671b9obrien    default:
29171671b9obrien      usage (stderr, 1);
29271671b9obrien    }
29371671b9obrien
29471671b9obrien  bfd_init ();
29571671b9obrien  set_default_bfd_target ();
29671671b9obrien
29771671b9obrien  if (optind >= argc)
29871671b9obrien    {
29971671b9obrien      datasection_only = FALSE;
30071671b9obrien#ifdef SET_BINARY
30171671b9obrien      SET_BINARY (fileno (stdin));
30271671b9obrien#endif
30371671b9obrien      print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
30471671b9obrien      files_given = TRUE;
30571671b9obrien    }
30671671b9obrien  else
30771671b9obrien    {
30871671b9obrien      for (; optind < argc; ++optind)
30971671b9obrien	{
31071671b9obrien	  if (strcmp (argv[optind], "-") == 0)
31171671b9obrien	    datasection_only = FALSE;
31271671b9obrien	  else
31371671b9obrien	    {
31471671b9obrien	      files_given = TRUE;
31571671b9obrien	      exit_status |= strings_file (argv[optind]) == FALSE;
31671671b9obrien	    }
31771671b9obrien	}
31871671b9obrien    }
31971671b9obrien
32071671b9obrien  if (!files_given)
32171671b9obrien    usage (stderr, 1);
32271671b9obrien
32371671b9obrien  return (exit_status);
32471671b9obrien}
32571671b9obrien
3260acbbeedim/* Scan section SECT of the file ABFD, whose printable name is in
3270acbbeedim   ARG->filename and whose size might be in ARG->filesize.  If it
3280acbbeedim   contains initialized data set `got_a_section' and print the
3290acbbeedim   strings in it.
3300acbbeedim
3310acbbeedim   FIXME: We ought to be able to return error codes/messages for
3320acbbeedim   certain conditions.  */
33371671b9obrien
33471671b9obrienstatic void
3350acbbeedimstrings_a_section (bfd *abfd, asection *sect, void *arg)
33671671b9obrien{
3370acbbeedim  filename_and_size_t * filename_and_sizep;
3380acbbeedim  bfd_size_type *filesizep;
3390acbbeedim  bfd_size_type sectsize;
3400acbbeedim  void *mem;
3410acbbeedim
3420acbbeedim  if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
3430acbbeedim    return;
3440acbbeedim
3450acbbeedim  sectsize = bfd_get_section_size (sect);
3460acbbeedim
3470acbbeedim  if (sectsize <= 0)
3480acbbeedim    return;
3490acbbeedim
3500acbbeedim  /* Get the size of the file.  This might have been cached for us.  */
3510acbbeedim  filename_and_sizep = (filename_and_size_t *) arg;
3520acbbeedim  filesizep = & filename_and_sizep->filesize;
3530acbbeedim
3540acbbeedim  if (*filesizep == 0)
3550acbbeedim    {
3560acbbeedim      struct stat st;
3570acbbeedim
3580acbbeedim      if (bfd_stat (abfd, &st))
3590acbbeedim	return;
3600acbbeedim
3610acbbeedim      /* Cache the result so that we do not repeatedly stat this file.  */
3620acbbeedim      *filesizep = st.st_size;
3630acbbeedim    }
3640acbbeedim
3650acbbeedim  /* Compare the size of the section against the size of the file.
3660acbbeedim     If the section is bigger then the file must be corrupt and
3670acbbeedim     we should not try dumping it.  */
3680acbbeedim  if (sectsize >= *filesizep)
3690acbbeedim    return;
3700acbbeedim
3710acbbeedim  mem = xmalloc (sectsize);
37271671b9obrien
3730acbbeedim  if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize))
37471671b9obrien    {
3750acbbeedim      got_a_section = TRUE;
37671671b9obrien
3770acbbeedim      print_strings (filename_and_sizep->filename, NULL, sect->filepos,
3780acbbeedim		     0, sectsize, mem);
37971671b9obrien    }
3800acbbeedim
3810acbbeedim  free (mem);
38271671b9obrien}
38371671b9obrien
38471671b9obrien/* Scan all of the sections in FILE, and print the strings
38571671b9obrien   in the initialized data section(s).
38671671b9obrien
38771671b9obrien   Return TRUE if successful,
38871671b9obrien   FALSE if not (such as if FILE is not an object file).  */
38971671b9obrien
39071671b9obrienstatic bfd_boolean
39171671b9obrienstrings_object_file (const char *file)
39271671b9obrien{
3930acbbeedim  filename_and_size_t filename_and_size;
3940acbbeedim  bfd *abfd;
3950acbbeedim
3960acbbeedim  abfd = bfd_openr (file, target);
39771671b9obrien
39871671b9obrien  if (abfd == NULL)
39971671b9obrien    /* Treat the file as a non-object file.  */
40071671b9obrien    return FALSE;
40171671b9obrien
40271671b9obrien  /* This call is mainly for its side effect of reading in the sections.
40371671b9obrien     We follow the traditional behavior of `strings' in that we don't
40471671b9obrien     complain if we don't recognize a file to be an object file.  */
40571671b9obrien  if (!bfd_check_format (abfd, bfd_object))
40671671b9obrien    {
40771671b9obrien      bfd_close (abfd);
40871671b9obrien      return FALSE;
40971671b9obrien    }
41071671b9obrien
41171671b9obrien  got_a_section = FALSE;
4120acbbeedim  filename_and_size.filename = file;
4130acbbeedim  filename_and_size.filesize = 0;
4140acbbeedim  bfd_map_over_sections (abfd, strings_a_section, & filename_and_size);
41571671b9obrien
41671671b9obrien  if (!bfd_close (abfd))
41771671b9obrien    {
41871671b9obrien      bfd_nonfatal (file);
41971671b9obrien      return FALSE;
42071671b9obrien    }
42171671b9obrien
42271671b9obrien  return got_a_section;
42371671b9obrien}
42471671b9obrien
42571671b9obrien/* Print the strings in FILE.  Return TRUE if ok, FALSE if an error occurs.  */
42671671b9obrien
42771671b9obrienstatic bfd_boolean
42871671b9obrienstrings_file (char *file)
42971671b9obrien{
4300acbbeedim  statbuf st;
4310acbbeedim
4320acbbeedim  if (file_stat (file, &st) < 0)
4330acbbeedim    {
4340acbbeedim      if (errno == ENOENT)
4350acbbeedim	non_fatal (_("'%s': No such file"), file);
4360acbbeedim      else
4370acbbeedim	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
4380acbbeedim		   file, strerror (errno));
4390acbbeedim      return FALSE;
4400acbbeedim    }
44171671b9obrien
44271671b9obrien  /* If we weren't told to scan the whole file,
44371671b9obrien     try to open it as an object file and only look at
44471671b9obrien     initialized data sections.  If that fails, fall back to the
44571671b9obrien     whole file.  */
44671671b9obrien  if (!datasection_only || !strings_object_file (file))
44771671b9obrien    {
44871671b9obrien      FILE *stream;
44971671b9obrien
45071671b9obrien      stream = file_open (file, FOPEN_RB);
45171671b9obrien      if (stream == NULL)
45271671b9obrien	{
45371671b9obrien	  fprintf (stderr, "%s: ", program_name);
45471671b9obrien	  perror (file);
45571671b9obrien	  return FALSE;
45671671b9obrien	}
45771671b9obrien
45871671b9obrien      print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0);
45971671b9obrien
46071671b9obrien      if (fclose (stream) == EOF)
46171671b9obrien	{
46271671b9obrien	  fprintf (stderr, "%s: ", program_name);
46371671b9obrien	  perror (file);
46471671b9obrien	  return FALSE;
46571671b9obrien	}
46671671b9obrien    }
46771671b9obrien
46871671b9obrien  return TRUE;
46971671b9obrien}
47071671b9obrien
47171671b9obrien/* Read the next character, return EOF if none available.
47271671b9obrien   Assume that STREAM is positioned so that the next byte read
47371671b9obrien   is at address ADDRESS in the file.
47471671b9obrien
47571671b9obrien   If STREAM is NULL, do not read from it.
47671671b9obrien   The caller can supply a buffer of characters
47771671b9obrien   to be processed before the data in STREAM.
47871671b9obrien   MAGIC is the address of the buffer and
47971671b9obrien   MAGICCOUNT is how many characters are in it.  */
48071671b9obrien
48171671b9obrienstatic long
48271671b9obrienget_char (FILE *stream, file_off *address, int *magiccount, char **magic)
48371671b9obrien{
48471671b9obrien  int c, i;
48571671b9obrien  long r = EOF;
48671671b9obrien  unsigned char buf[4];
48771671b9obrien
48871671b9obrien  for (i = 0; i < encoding_bytes; i++)
48971671b9obrien    {
49071671b9obrien      if (*magiccount)
49171671b9obrien	{
49271671b9obrien	  (*magiccount)--;
49371671b9obrien	  c = *(*magic)++;
49471671b9obrien	}
49571671b9obrien      else
49671671b9obrien	{
49771671b9obrien	  if (stream == NULL)
49871671b9obrien	    return EOF;
4990acbbeedim
5000acbbeedim	  /* Only use getc_unlocked if we found a declaration for it.
5010acbbeedim	     Otherwise, libc is not thread safe by default, and we
5020acbbeedim	     should not use it.  */
5030acbbeedim
5040acbbeedim#if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
50571671b9obrien	  c = getc_unlocked (stream);
50671671b9obrien#else
50771671b9obrien	  c = getc (stream);
50871671b9obrien#endif
50971671b9obrien	  if (c == EOF)
51071671b9obrien	    return EOF;
51171671b9obrien	}
51271671b9obrien
51371671b9obrien      (*address)++;
51471671b9obrien      buf[i] = c;
51571671b9obrien    }
51671671b9obrien
51771671b9obrien  switch (encoding)
51871671b9obrien    {
51971671b9obrien    case 'S':
52071671b9obrien    case 's':
52171671b9obrien      r = buf[0];
52271671b9obrien      break;
52371671b9obrien    case 'b':
52471671b9obrien      r = (buf[0] << 8) | buf[1];
52571671b9obrien      break;
52671671b9obrien    case 'l':
52771671b9obrien      r = buf[0] | (buf[1] << 8);
52871671b9obrien      break;
52971671b9obrien    case 'B':
53071671b9obrien      r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
53171671b9obrien	((long) buf[2] << 8) | buf[3];
53271671b9obrien      break;
53371671b9obrien    case 'L':
53471671b9obrien      r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
53571671b9obrien	((long) buf[3] << 24);
53671671b9obrien      break;
53771671b9obrien    }
53871671b9obrien
53971671b9obrien  if (r == EOF)
54071671b9obrien    return 0;
54171671b9obrien
54271671b9obrien  return r;
54371671b9obrien}
54471671b9obrien
54571671b9obrien/* Find the strings in file FILENAME, read from STREAM.
54671671b9obrien   Assume that STREAM is positioned so that the next byte read
54771671b9obrien   is at address ADDRESS in the file.
54871671b9obrien   Stop reading at address STOP_POINT in the file, if nonzero.
54971671b9obrien
55071671b9obrien   If STREAM is NULL, do not read from it.
55171671b9obrien   The caller can supply a buffer of characters
55271671b9obrien   to be processed before the data in STREAM.
55371671b9obrien   MAGIC is the address of the buffer and
55471671b9obrien   MAGICCOUNT is how many characters are in it.
55571671b9obrien   Those characters come at address ADDRESS and the data in STREAM follow.  */
55671671b9obrien
55771671b9obrienstatic void
55871671b9obrienprint_strings (const char *filename, FILE *stream, file_off address,
55971671b9obrien	       int stop_point, int magiccount, char *magic)
56071671b9obrien{
56171671b9obrien  char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
56271671b9obrien
56371671b9obrien  while (1)
56471671b9obrien    {
56571671b9obrien      file_off start;
56671671b9obrien      int i;
56771671b9obrien      long c;
56871671b9obrien
56971671b9obrien      /* See if the next `string_min' chars are all graphic chars.  */
57071671b9obrien    tryline:
57171671b9obrien      if (stop_point && address >= stop_point)
57271671b9obrien	break;
57371671b9obrien      start = address;
57471671b9obrien      for (i = 0; i < string_min; i++)
57571671b9obrien	{
57671671b9obrien	  c = get_char (stream, &address, &magiccount, &magic);
57771671b9obrien	  if (c == EOF)
57871671b9obrien	    return;
57971671b9obrien	  if (! STRING_ISGRAPHIC (c))
58071671b9obrien	    /* Found a non-graphic.  Try again starting with next char.  */
58171671b9obrien	    goto tryline;
58271671b9obrien	  buf[i] = c;
58371671b9obrien	}
58471671b9obrien
58571671b9obrien      /* We found a run of `string_min' graphic characters.  Print up
5860acbbeedim	 to the next non-graphic character.  */
58771671b9obrien
58871671b9obrien      if (print_filenames)
58971671b9obrien	printf ("%s: ", filename);
59071671b9obrien      if (print_addresses)
59171671b9obrien	switch (address_radix)
59271671b9obrien	  {
59371671b9obrien	  case 8:
59471671b9obrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
59571671b9obrien	    if (sizeof (start) > sizeof (long))
596fe2c179benl	      printf ("%7llo ", (unsigned long long) start);
59771671b9obrien	    else
59871671b9obrien#else
59971671b9obrien# if !BFD_HOST_64BIT_LONG
60071671b9obrien	    if (start != (unsigned long) start)
60171671b9obrien	      printf ("++%7lo ", (unsigned long) start);
60271671b9obrien	    else
60371671b9obrien# endif
60471671b9obrien#endif
60571671b9obrien	      printf ("%7lo ", (unsigned long) start);
60671671b9obrien	    break;
60771671b9obrien
60871671b9obrien	  case 10:
60971671b9obrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
61071671b9obrien	    if (sizeof (start) > sizeof (long))
611fe2c179benl	      printf ("%7lld ", (unsigned long long) start);
61271671b9obrien	    else
61371671b9obrien#else
61471671b9obrien# if !BFD_HOST_64BIT_LONG
61571671b9obrien	    if (start != (unsigned long) start)
61671671b9obrien	      printf ("++%7ld ", (unsigned long) start);
61771671b9obrien	    else
61871671b9obrien# endif
61971671b9obrien#endif
62071671b9obrien	      printf ("%7ld ", (long) start);
62171671b9obrien	    break;
62271671b9obrien
62371671b9obrien	  case 16:
62471671b9obrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
62571671b9obrien	    if (sizeof (start) > sizeof (long))
626fe2c179benl	      printf ("%7llx ", (unsigned long long) start);
62771671b9obrien	    else
62871671b9obrien#else
62971671b9obrien# if !BFD_HOST_64BIT_LONG
63071671b9obrien	    if (start != (unsigned long) start)
6310acbbeedim	      printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
6320acbbeedim		      (unsigned long) (start & 0xffffffff));
63371671b9obrien	    else
63471671b9obrien# endif
63571671b9obrien#endif
63671671b9obrien	      printf ("%7lx ", (unsigned long) start);
63771671b9obrien	    break;
63871671b9obrien	  }
63971671b9obrien
64071671b9obrien      buf[i] = '\0';
64171671b9obrien      fputs (buf, stdout);
64271671b9obrien
64371671b9obrien      while (1)
64471671b9obrien	{
64571671b9obrien	  c = get_char (stream, &address, &magiccount, &magic);
64671671b9obrien	  if (c == EOF)
64771671b9obrien	    break;
64871671b9obrien	  if (! STRING_ISGRAPHIC (c))
64971671b9obrien	    break;
65071671b9obrien	  putchar (c);
65171671b9obrien	}
65271671b9obrien
65371671b9obrien      putchar ('\n');
65471671b9obrien    }
65571671b9obrien}
65671671b9obrien
65771671b9obrien/* Parse string S as an integer, using decimal radix by default,
65871671b9obrien   but allowing octal and hex numbers as in C.  */
65971671b9obrien
66071671b9obrienstatic int
66171671b9obrieninteger_arg (char *s)
66271671b9obrien{
66371671b9obrien  int value;
66471671b9obrien  int radix = 10;
66571671b9obrien  char *p = s;
66671671b9obrien  int c;
66771671b9obrien
66871671b9obrien  if (*p != '0')
66971671b9obrien    radix = 10;
67071671b9obrien  else if (*++p == 'x')
67171671b9obrien    {
67271671b9obrien      radix = 16;
67371671b9obrien      p++;
67471671b9obrien    }
67571671b9obrien  else
67671671b9obrien    radix = 8;
67771671b9obrien
67871671b9obrien  value = 0;
67971671b9obrien  while (((c = *p++) >= '0' && c <= '9')
68071671b9obrien	 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
68171671b9obrien    {
68271671b9obrien      value *= radix;
68371671b9obrien      if (c >= '0' && c <= '9')
68471671b9obrien	value += c - '0';
68571671b9obrien      else
68671671b9obrien	value += (c & ~40) - 'A';
68771671b9obrien    }
68871671b9obrien
68971671b9obrien  if (c == 'b')
69071671b9obrien    value *= 512;
69171671b9obrien  else if (c == 'B')
69271671b9obrien    value *= 1024;
69371671b9obrien  else
69471671b9obrien    p--;
69571671b9obrien
69671671b9obrien  if (*p)
69771671b9obrien    fatal (_("invalid integer argument %s"), s);
69871671b9obrien
69971671b9obrien  return value;
70071671b9obrien}
70171671b9obrien
70271671b9obrienstatic void
70371671b9obrienusage (FILE *stream, int status)
70471671b9obrien{
70571671b9obrien  fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
70671671b9obrien  fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
70771671b9obrien  fprintf (stream, _(" The options are:\n\
70871671b9obrien  -a - --all                Scan the entire file, not just the data section\n\
70971671b9obrien  -f --print-file-name      Print the name of the file before each string\n\
71071671b9obrien  -n --bytes=[number]       Locate & print any NUL-terminated sequence of at\n\
71171671b9obrien  -<number>                 least [number] characters (default 4).\n\
7120acbbeedim  -t --radix={o,d,x}        Print the location of the string in base 8, 10 or 16\n\
71371671b9obrien  -o                        An alias for --radix=o\n\
71471671b9obrien  -T --target=<BFDNAME>     Specify the binary file format\n\
71571671b9obrien  -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
71671671b9obrien                            s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
7170acbbeedim  @<file>                   Read options from <file>\n\
71871671b9obrien  -h --help                 Display this information\n\
71971671b9obrien  -v --version              Print the program's version number\n"));
72071671b9obrien  list_supported_targets (program_name, stream);
721d0f678fdim  if (REPORT_BUGS_TO[0] && status == 0)
72271671b9obrien    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
72371671b9obrien  exit (status);
72471671b9obrien}
725