133965Sjdp/* strings -- print the strings of printable characters in files
289865Sobrien   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3218822Sdim   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
433965Sjdp
533965Sjdp   This program is free software; you can redistribute it and/or modify
633965Sjdp   it under the terms of the GNU General Public License as published by
733965Sjdp   the Free Software Foundation; either version 2, or (at your option)
833965Sjdp   any later version.
933965Sjdp
1033965Sjdp   This program is distributed in the hope that it will be useful,
1133965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1233965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1333965Sjdp   GNU General Public License for more details.
1433965Sjdp
1533965Sjdp   You should have received a copy of the GNU General Public License
1633965Sjdp   along with this program; if not, write to the Free Software
17218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
18218822Sdim   02110-1301, USA.  */
1933965Sjdp
2033965Sjdp/* Usage: strings [options] file...
2133965Sjdp
2233965Sjdp   Options:
2333965Sjdp   --all
2433965Sjdp   -a
2533965Sjdp   -		Do not scan only the initialized data section of object files.
2633965Sjdp
2733965Sjdp   --print-file-name
2833965Sjdp   -f		Print the name of the file before each string.
2933965Sjdp
3033965Sjdp   --bytes=min-len
3133965Sjdp   -n min-len
3233965Sjdp   -min-len	Print graphic char sequences, MIN-LEN or more bytes long,
3333965Sjdp		that are followed by a NUL or a newline.  Default is 4.
3433965Sjdp
3533965Sjdp   --radix={o,x,d}
3633965Sjdp   -t {o,x,d}	Print the offset within the file before each string,
3733965Sjdp		in octal/hex/decimal.
3833965Sjdp
3933965Sjdp   -o		Like -to.  (Some other implementations have -o like -to,
4033965Sjdp		others like -td.  We chose one arbitrarily.)
4133965Sjdp
42130570Sobrien   --encoding={s,S,b,l,B,L}
43130570Sobrien   -e {s,S,b,l,B,L}
44130570Sobrien		Select character encoding: 7-bit-character, 8-bit-character,
45130570Sobrien		bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
46130570Sobrien		littleendian 32-bit.
4789865Sobrien
4833965Sjdp   --target=BFDNAME
49218822Sdim   -T {bfdname}
5033965Sjdp		Specify a non-default object file format.
5133965Sjdp
5233965Sjdp   --help
5333965Sjdp   -h		Print the usage message on the standard output.
5433965Sjdp
5533965Sjdp   --version
5633965Sjdp   -v		Print the program version number.
5733965Sjdp
5833965Sjdp   Written by Richard Stallman <rms@gnu.ai.mit.edu>
5933965Sjdp   and David MacKenzie <djm@gnu.ai.mit.edu>.  */
6033965Sjdp
61218822Sdim#include "sysdep.h"
6233965Sjdp#include "bfd.h"
63104837Sobrien#include "getopt.h"
6433965Sjdp#include "libiberty.h"
6589865Sobrien#include "safe-ctype.h"
66218822Sdim#include <sys/stat.h>
67218822Sdim#include "bucomm.h"
6833965Sjdp
6961846Sobrien/* Some platforms need to put stdin into binary mode, to read
7061846Sobrien    binary files.  */
7161846Sobrien#ifdef HAVE_SETMODE
7261846Sobrien#ifndef O_BINARY
7361846Sobrien#ifdef _O_BINARY
7461846Sobrien#define O_BINARY _O_BINARY
7561846Sobrien#define setmode _setmode
7661846Sobrien#else
7761846Sobrien#define O_BINARY 0
7861846Sobrien#endif
7961846Sobrien#endif
8061846Sobrien#if O_BINARY
8161846Sobrien#include <io.h>
82130570Sobrien#define SET_BINARY(f) do { if (!isatty (f)) setmode (f,O_BINARY); } while (0)
8361846Sobrien#endif
8461846Sobrien#endif
8561846Sobrien
86130570Sobrien#define STRING_ISGRAPHIC(c) \
87130570Sobrien      (   (c) >= 0 \
88130570Sobrien       && (c) <= 255 \
89130570Sobrien       && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127)))
9033965Sjdp
9133965Sjdp#ifndef errno
9233965Sjdpextern int errno;
9333965Sjdp#endif
9433965Sjdp
9533965Sjdp/* The BFD section flags that identify an initialized data section.  */
9633965Sjdp#define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
9733965Sjdp
9889865Sobrien#ifdef HAVE_FOPEN64
9989865Sobrientypedef off64_t file_off;
100130570Sobrien#define file_open(s,m) fopen64(s, m)
10189865Sobrien#else
10289865Sobrientypedef off_t file_off;
103130570Sobrien#define file_open(s,m) fopen(s, m)
10489865Sobrien#endif
105218822Sdim#ifdef HAVE_STAT64
106218822Sdimtypedef struct stat64 statbuf;
107218822Sdim#define file_stat(f,s) stat64(f, s)
108218822Sdim#else
109218822Sdimtypedef struct stat statbuf;
110218822Sdim#define file_stat(f,s) stat(f, s)
111218822Sdim#endif
11289865Sobrien
11333965Sjdp/* Radix for printing addresses (must be 8, 10 or 16).  */
11433965Sjdpstatic int address_radix;
11533965Sjdp
11633965Sjdp/* Minimum length of sequence of graphic chars to trigger output.  */
11733965Sjdpstatic int string_min;
11833965Sjdp
119130570Sobrien/* TRUE means print address within file for each string.  */
120130570Sobrienstatic bfd_boolean print_addresses;
12133965Sjdp
122130570Sobrien/* TRUE means print filename for each string.  */
123130570Sobrienstatic bfd_boolean print_filenames;
12433965Sjdp
125130570Sobrien/* TRUE means for object files scan only the data section.  */
126130570Sobrienstatic bfd_boolean datasection_only;
12733965Sjdp
128130570Sobrien/* TRUE if we found an initialized data section in the current file.  */
129130570Sobrienstatic bfd_boolean got_a_section;
13033965Sjdp
13133965Sjdp/* The BFD object file format.  */
13233965Sjdpstatic char *target;
13333965Sjdp
13489865Sobrien/* The character encoding format.  */
13589865Sobrienstatic char encoding;
13689865Sobrienstatic int encoding_bytes;
13789865Sobrien
13833965Sjdpstatic struct option long_options[] =
13933965Sjdp{
14033965Sjdp  {"all", no_argument, NULL, 'a'},
14133965Sjdp  {"print-file-name", no_argument, NULL, 'f'},
14233965Sjdp  {"bytes", required_argument, NULL, 'n'},
14333965Sjdp  {"radix", required_argument, NULL, 't'},
14489865Sobrien  {"encoding", required_argument, NULL, 'e'},
14533965Sjdp  {"target", required_argument, NULL, 'T'},
14633965Sjdp  {"help", no_argument, NULL, 'h'},
14733965Sjdp  {"version", no_argument, NULL, 'v'},
14833965Sjdp  {NULL, 0, NULL, 0}
14933965Sjdp};
15033965Sjdp
151218822Sdim/* Records the size of a named file so that we
152218822Sdim   do not repeatedly run bfd_stat() on it.  */
153218822Sdim
154218822Sdimtypedef struct
155218822Sdim{
156218822Sdim  const char *  filename;
157218822Sdim  bfd_size_type filesize;
158218822Sdim} filename_and_size_t;
159218822Sdim
160130570Sobrienstatic void strings_a_section (bfd *, asection *, void *);
161130570Sobrienstatic bfd_boolean strings_object_file (const char *);
162130570Sobrienstatic bfd_boolean strings_file (char *file);
163130570Sobrienstatic int integer_arg (char *s);
164130570Sobrienstatic void print_strings (const char *, FILE *, file_off, int, int, char *);
165130570Sobrienstatic void usage (FILE *, int);
166130570Sobrienstatic long get_char (FILE *, file_off *, int *, char **);
16733965Sjdp
168130570Sobrienint main (int, char **);
16989865Sobrien
17033965Sjdpint
171130570Sobrienmain (int argc, char **argv)
17233965Sjdp{
17333965Sjdp  int optc;
17433965Sjdp  int exit_status = 0;
175130570Sobrien  bfd_boolean files_given = FALSE;
17633965Sjdp
17789865Sobrien#if defined (HAVE_SETLOCALE)
17878837Sobrien  setlocale (LC_ALL, "");
17960513Sobrien#endif
18060513Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
18160513Sobrien  textdomain (PACKAGE);
18260513Sobrien
18333965Sjdp  program_name = argv[0];
18433965Sjdp  xmalloc_set_program_name (program_name);
185218822Sdim
186218822Sdim  expandargv (&argc, &argv);
187218822Sdim
18833965Sjdp  string_min = -1;
189130570Sobrien  print_addresses = FALSE;
190130570Sobrien  print_filenames = FALSE;
191130570Sobrien  datasection_only = TRUE;
19233965Sjdp  target = NULL;
19389865Sobrien  encoding = 's';
19433965Sjdp
195218822Sdim  while ((optc = getopt_long (argc, argv, "afhHn:ot:e:T:Vv0123456789",
19633965Sjdp			      long_options, (int *) 0)) != EOF)
19733965Sjdp    {
19833965Sjdp      switch (optc)
19933965Sjdp	{
20033965Sjdp	case 'a':
201130570Sobrien	  datasection_only = FALSE;
20233965Sjdp	  break;
20333965Sjdp
20433965Sjdp	case 'f':
205130570Sobrien	  print_filenames = TRUE;
20633965Sjdp	  break;
20733965Sjdp
20889865Sobrien	case 'H':
20933965Sjdp	case 'h':
21033965Sjdp	  usage (stdout, 0);
21133965Sjdp
21233965Sjdp	case 'n':
21333965Sjdp	  string_min = integer_arg (optarg);
21433965Sjdp	  if (string_min < 1)
215130570Sobrien	    fatal (_("invalid number %s"), optarg);
21633965Sjdp	  break;
21733965Sjdp
21833965Sjdp	case 'o':
219130570Sobrien	  print_addresses = TRUE;
22033965Sjdp	  address_radix = 8;
22133965Sjdp	  break;
22233965Sjdp
22333965Sjdp	case 't':
224130570Sobrien	  print_addresses = TRUE;
22533965Sjdp	  if (optarg[1] != '\0')
22633965Sjdp	    usage (stderr, 1);
22733965Sjdp	  switch (optarg[0])
22833965Sjdp	    {
22933965Sjdp	    case 'o':
23033965Sjdp	      address_radix = 8;
23133965Sjdp	      break;
23233965Sjdp
23333965Sjdp	    case 'd':
23433965Sjdp	      address_radix = 10;
23533965Sjdp	      break;
23633965Sjdp
23733965Sjdp	    case 'x':
23833965Sjdp	      address_radix = 16;
23933965Sjdp	      break;
24033965Sjdp
24133965Sjdp	    default:
24233965Sjdp	      usage (stderr, 1);
24333965Sjdp	    }
24433965Sjdp	  break;
24533965Sjdp
24633965Sjdp	case 'T':
24733965Sjdp	  target = optarg;
24833965Sjdp	  break;
24933965Sjdp
25089865Sobrien	case 'e':
25189865Sobrien	  if (optarg[1] != '\0')
25289865Sobrien	    usage (stderr, 1);
25389865Sobrien	  encoding = optarg[0];
25489865Sobrien	  break;
25589865Sobrien
25689865Sobrien	case 'V':
25733965Sjdp	case 'v':
25833965Sjdp	  print_version ("strings");
25933965Sjdp	  break;
26033965Sjdp
26133965Sjdp	case '?':
26233965Sjdp	  usage (stderr, 1);
26333965Sjdp
26433965Sjdp	default:
26533965Sjdp	  if (string_min < 0)
26660513Sobrien	    string_min = optc - '0';
26733965Sjdp	  else
26833965Sjdp	    string_min = string_min * 10 + optc - '0';
26933965Sjdp	  break;
27033965Sjdp	}
27133965Sjdp    }
27233965Sjdp
27333965Sjdp  if (string_min < 0)
27433965Sjdp    string_min = 4;
27533965Sjdp
27689865Sobrien  switch (encoding)
27789865Sobrien    {
278130570Sobrien    case 'S':
27989865Sobrien    case 's':
28089865Sobrien      encoding_bytes = 1;
28189865Sobrien      break;
28289865Sobrien    case 'b':
28389865Sobrien    case 'l':
28489865Sobrien      encoding_bytes = 2;
28589865Sobrien      break;
28689865Sobrien    case 'B':
28789865Sobrien    case 'L':
28889865Sobrien      encoding_bytes = 4;
28989865Sobrien      break;
29089865Sobrien    default:
29189865Sobrien      usage (stderr, 1);
29289865Sobrien    }
29389865Sobrien
29433965Sjdp  bfd_init ();
29533965Sjdp  set_default_bfd_target ();
29633965Sjdp
29733965Sjdp  if (optind >= argc)
29833965Sjdp    {
299130570Sobrien      datasection_only = FALSE;
30061846Sobrien#ifdef SET_BINARY
30161846Sobrien      SET_BINARY (fileno (stdin));
30261846Sobrien#endif
30333965Sjdp      print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
304130570Sobrien      files_given = TRUE;
30533965Sjdp    }
30633965Sjdp  else
30733965Sjdp    {
30833965Sjdp      for (; optind < argc; ++optind)
30933965Sjdp	{
31033965Sjdp	  if (strcmp (argv[optind], "-") == 0)
311130570Sobrien	    datasection_only = FALSE;
31233965Sjdp	  else
31333965Sjdp	    {
314130570Sobrien	      files_given = TRUE;
315130570Sobrien	      exit_status |= strings_file (argv[optind]) == FALSE;
31633965Sjdp	    }
31733965Sjdp	}
31833965Sjdp    }
31933965Sjdp
320130570Sobrien  if (!files_given)
32133965Sjdp    usage (stderr, 1);
32233965Sjdp
32333965Sjdp  return (exit_status);
32433965Sjdp}
32533965Sjdp
326218822Sdim/* Scan section SECT of the file ABFD, whose printable name is in
327218822Sdim   ARG->filename and whose size might be in ARG->filesize.  If it
328218822Sdim   contains initialized data set `got_a_section' and print the
329218822Sdim   strings in it.
33033965Sjdp
331218822Sdim   FIXME: We ought to be able to return error codes/messages for
332218822Sdim   certain conditions.  */
333218822Sdim
33433965Sjdpstatic void
335218822Sdimstrings_a_section (bfd *abfd, asection *sect, void *arg)
33633965Sjdp{
337218822Sdim  filename_and_size_t * filename_and_sizep;
338218822Sdim  bfd_size_type *filesizep;
339218822Sdim  bfd_size_type sectsize;
340218822Sdim  void *mem;
341218822Sdim
342218822Sdim  if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
343218822Sdim    return;
34433965Sjdp
345218822Sdim  sectsize = bfd_get_section_size (sect);
346218822Sdim
347218822Sdim  if (sectsize <= 0)
348218822Sdim    return;
349218822Sdim
350218822Sdim  /* Get the size of the file.  This might have been cached for us.  */
351218822Sdim  filename_and_sizep = (filename_and_size_t *) arg;
352218822Sdim  filesizep = & filename_and_sizep->filesize;
353218822Sdim
354218822Sdim  if (*filesizep == 0)
35533965Sjdp    {
356218822Sdim      struct stat st;
357218822Sdim
358218822Sdim      if (bfd_stat (abfd, &st))
359218822Sdim	return;
360130570Sobrien
361218822Sdim      /* Cache the result so that we do not repeatedly stat this file.  */
362218822Sdim      *filesizep = st.st_size;
36333965Sjdp    }
364218822Sdim
365218822Sdim  /* Compare the size of the section against the size of the file.
366218822Sdim     If the section is bigger then the file must be corrupt and
367218822Sdim     we should not try dumping it.  */
368218822Sdim  if (sectsize >= *filesizep)
369218822Sdim    return;
370218822Sdim
371218822Sdim  mem = xmalloc (sectsize);
372218822Sdim
373218822Sdim  if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize))
374218822Sdim    {
375218822Sdim      got_a_section = TRUE;
376218822Sdim
377218822Sdim      print_strings (filename_and_sizep->filename, NULL, sect->filepos,
378218822Sdim		     0, sectsize, mem);
379218822Sdim    }
380218822Sdim
381218822Sdim  free (mem);
38233965Sjdp}
38333965Sjdp
38433965Sjdp/* Scan all of the sections in FILE, and print the strings
38533965Sjdp   in the initialized data section(s).
38633965Sjdp
387130570Sobrien   Return TRUE if successful,
388130570Sobrien   FALSE if not (such as if FILE is not an object file).  */
38933965Sjdp
390130570Sobrienstatic bfd_boolean
391130570Sobrienstrings_object_file (const char *file)
39233965Sjdp{
393218822Sdim  filename_and_size_t filename_and_size;
394218822Sdim  bfd *abfd;
39533965Sjdp
396218822Sdim  abfd = bfd_openr (file, target);
397218822Sdim
39833965Sjdp  if (abfd == NULL)
399130570Sobrien    /* Treat the file as a non-object file.  */
400130570Sobrien    return FALSE;
40133965Sjdp
40233965Sjdp  /* This call is mainly for its side effect of reading in the sections.
40333965Sjdp     We follow the traditional behavior of `strings' in that we don't
40433965Sjdp     complain if we don't recognize a file to be an object file.  */
405130570Sobrien  if (!bfd_check_format (abfd, bfd_object))
40633965Sjdp    {
40733965Sjdp      bfd_close (abfd);
408130570Sobrien      return FALSE;
40933965Sjdp    }
41033965Sjdp
411130570Sobrien  got_a_section = FALSE;
412218822Sdim  filename_and_size.filename = file;
413218822Sdim  filename_and_size.filesize = 0;
414218822Sdim  bfd_map_over_sections (abfd, strings_a_section, & filename_and_size);
41533965Sjdp
41633965Sjdp  if (!bfd_close (abfd))
41733965Sjdp    {
41833965Sjdp      bfd_nonfatal (file);
419130570Sobrien      return FALSE;
42033965Sjdp    }
42133965Sjdp
42233965Sjdp  return got_a_section;
42333965Sjdp}
42433965Sjdp
425130570Sobrien/* Print the strings in FILE.  Return TRUE if ok, FALSE if an error occurs.  */
42633965Sjdp
427130570Sobrienstatic bfd_boolean
428130570Sobrienstrings_file (char *file)
42933965Sjdp{
430218822Sdim  statbuf st;
431130570Sobrien
432218822Sdim  if (file_stat (file, &st) < 0)
433218822Sdim    {
434218822Sdim      if (errno == ENOENT)
435218822Sdim	non_fatal (_("'%s': No such file"), file);
436218822Sdim      else
437218822Sdim	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
438218822Sdim		   file, strerror (errno));
439218822Sdim      return FALSE;
440218822Sdim    }
441218822Sdim
44233965Sjdp  /* If we weren't told to scan the whole file,
44333965Sjdp     try to open it as an object file and only look at
44433965Sjdp     initialized data sections.  If that fails, fall back to the
44533965Sjdp     whole file.  */
44633965Sjdp  if (!datasection_only || !strings_object_file (file))
44733965Sjdp    {
44833965Sjdp      FILE *stream;
44933965Sjdp
45089865Sobrien      stream = file_open (file, FOPEN_RB);
45133965Sjdp      if (stream == NULL)
45233965Sjdp	{
45333965Sjdp	  fprintf (stderr, "%s: ", program_name);
45433965Sjdp	  perror (file);
455130570Sobrien	  return FALSE;
45633965Sjdp	}
45733965Sjdp
45889865Sobrien      print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0);
45933965Sjdp
46033965Sjdp      if (fclose (stream) == EOF)
46133965Sjdp	{
46233965Sjdp	  fprintf (stderr, "%s: ", program_name);
46333965Sjdp	  perror (file);
464130570Sobrien	  return FALSE;
46533965Sjdp	}
46633965Sjdp    }
46733965Sjdp
468130570Sobrien  return TRUE;
46933965Sjdp}
47033965Sjdp
47189865Sobrien/* Read the next character, return EOF if none available.
47289865Sobrien   Assume that STREAM is positioned so that the next byte read
47389865Sobrien   is at address ADDRESS in the file.
47489865Sobrien
47589865Sobrien   If STREAM is NULL, do not read from it.
47689865Sobrien   The caller can supply a buffer of characters
47789865Sobrien   to be processed before the data in STREAM.
47889865Sobrien   MAGIC is the address of the buffer and
47989865Sobrien   MAGICCOUNT is how many characters are in it.  */
48089865Sobrien
48189865Sobrienstatic long
482130570Sobrienget_char (FILE *stream, file_off *address, int *magiccount, char **magic)
48389865Sobrien{
48489865Sobrien  int c, i;
48589865Sobrien  long r = EOF;
48689865Sobrien  unsigned char buf[4];
48789865Sobrien
48889865Sobrien  for (i = 0; i < encoding_bytes; i++)
48989865Sobrien    {
49089865Sobrien      if (*magiccount)
49189865Sobrien	{
49289865Sobrien	  (*magiccount)--;
49389865Sobrien	  c = *(*magic)++;
49489865Sobrien	}
49589865Sobrien      else
49689865Sobrien	{
49789865Sobrien	  if (stream == NULL)
49889865Sobrien	    return EOF;
499218822Sdim
500218822Sdim	  /* Only use getc_unlocked if we found a declaration for it.
501218822Sdim	     Otherwise, libc is not thread safe by default, and we
502218822Sdim	     should not use it.  */
503218822Sdim
504218822Sdim#if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
50589865Sobrien	  c = getc_unlocked (stream);
50689865Sobrien#else
50789865Sobrien	  c = getc (stream);
50889865Sobrien#endif
50989865Sobrien	  if (c == EOF)
51089865Sobrien	    return EOF;
51189865Sobrien	}
51289865Sobrien
51389865Sobrien      (*address)++;
51489865Sobrien      buf[i] = c;
51589865Sobrien    }
51689865Sobrien
51789865Sobrien  switch (encoding)
51889865Sobrien    {
519130570Sobrien    case 'S':
52089865Sobrien    case 's':
52189865Sobrien      r = buf[0];
52289865Sobrien      break;
52389865Sobrien    case 'b':
52489865Sobrien      r = (buf[0] << 8) | buf[1];
52589865Sobrien      break;
52689865Sobrien    case 'l':
52789865Sobrien      r = buf[0] | (buf[1] << 8);
52889865Sobrien      break;
52989865Sobrien    case 'B':
53089865Sobrien      r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
53189865Sobrien	((long) buf[2] << 8) | buf[3];
53289865Sobrien      break;
53389865Sobrien    case 'L':
53489865Sobrien      r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
53589865Sobrien	((long) buf[3] << 24);
53689865Sobrien      break;
53789865Sobrien    }
53889865Sobrien
53989865Sobrien  if (r == EOF)
54089865Sobrien    return 0;
54189865Sobrien
54289865Sobrien  return r;
54389865Sobrien}
54489865Sobrien
54533965Sjdp/* Find the strings in file FILENAME, read from STREAM.
54633965Sjdp   Assume that STREAM is positioned so that the next byte read
54733965Sjdp   is at address ADDRESS in the file.
54833965Sjdp   Stop reading at address STOP_POINT in the file, if nonzero.
54933965Sjdp
55033965Sjdp   If STREAM is NULL, do not read from it.
55133965Sjdp   The caller can supply a buffer of characters
55233965Sjdp   to be processed before the data in STREAM.
55333965Sjdp   MAGIC is the address of the buffer and
55433965Sjdp   MAGICCOUNT is how many characters are in it.
55533965Sjdp   Those characters come at address ADDRESS and the data in STREAM follow.  */
55633965Sjdp
55733965Sjdpstatic void
558130570Sobrienprint_strings (const char *filename, FILE *stream, file_off address,
559130570Sobrien	       int stop_point, int magiccount, char *magic)
56033965Sjdp{
56189865Sobrien  char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
56233965Sjdp
56333965Sjdp  while (1)
56433965Sjdp    {
56589865Sobrien      file_off start;
56633965Sjdp      int i;
56789865Sobrien      long c;
56833965Sjdp
56933965Sjdp      /* See if the next `string_min' chars are all graphic chars.  */
57033965Sjdp    tryline:
57133965Sjdp      if (stop_point && address >= stop_point)
57233965Sjdp	break;
57333965Sjdp      start = address;
57433965Sjdp      for (i = 0; i < string_min; i++)
57533965Sjdp	{
57689865Sobrien	  c = get_char (stream, &address, &magiccount, &magic);
57789865Sobrien	  if (c == EOF)
57889865Sobrien	    return;
579130570Sobrien	  if (! STRING_ISGRAPHIC (c))
58033965Sjdp	    /* Found a non-graphic.  Try again starting with next char.  */
58133965Sjdp	    goto tryline;
58233965Sjdp	  buf[i] = c;
58333965Sjdp	}
58433965Sjdp
58533965Sjdp      /* We found a run of `string_min' graphic characters.  Print up
586218822Sdim	 to the next non-graphic character.  */
58733965Sjdp
58833965Sjdp      if (print_filenames)
58933965Sjdp	printf ("%s: ", filename);
59033965Sjdp      if (print_addresses)
59133965Sjdp	switch (address_radix)
59233965Sjdp	  {
59333965Sjdp	  case 8:
59489865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
59589865Sobrien	    if (sizeof (start) > sizeof (long))
596222204Sbenl	      printf ("%7llo ", (unsigned long long) start);
59789865Sobrien	    else
59889865Sobrien#else
59989865Sobrien# if !BFD_HOST_64BIT_LONG
60089865Sobrien	    if (start != (unsigned long) start)
60189865Sobrien	      printf ("++%7lo ", (unsigned long) start);
60289865Sobrien	    else
60389865Sobrien# endif
60489865Sobrien#endif
60589865Sobrien	      printf ("%7lo ", (unsigned long) start);
60633965Sjdp	    break;
60733965Sjdp
60833965Sjdp	  case 10:
60989865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
61089865Sobrien	    if (sizeof (start) > sizeof (long))
611222204Sbenl	      printf ("%7lld ", (unsigned long long) start);
61289865Sobrien	    else
61389865Sobrien#else
61489865Sobrien# if !BFD_HOST_64BIT_LONG
61589865Sobrien	    if (start != (unsigned long) start)
61689865Sobrien	      printf ("++%7ld ", (unsigned long) start);
61789865Sobrien	    else
61889865Sobrien# endif
61989865Sobrien#endif
62089865Sobrien	      printf ("%7ld ", (long) start);
62133965Sjdp	    break;
62233965Sjdp
62333965Sjdp	  case 16:
62489865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
62589865Sobrien	    if (sizeof (start) > sizeof (long))
626222204Sbenl	      printf ("%7llx ", (unsigned long long) start);
62789865Sobrien	    else
62889865Sobrien#else
62989865Sobrien# if !BFD_HOST_64BIT_LONG
63089865Sobrien	    if (start != (unsigned long) start)
631218822Sdim	      printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
632218822Sdim		      (unsigned long) (start & 0xffffffff));
63389865Sobrien	    else
63489865Sobrien# endif
63589865Sobrien#endif
63689865Sobrien	      printf ("%7lx ", (unsigned long) start);
63733965Sjdp	    break;
63833965Sjdp	  }
63933965Sjdp
64033965Sjdp      buf[i] = '\0';
64133965Sjdp      fputs (buf, stdout);
64233965Sjdp
64333965Sjdp      while (1)
64433965Sjdp	{
64589865Sobrien	  c = get_char (stream, &address, &magiccount, &magic);
64689865Sobrien	  if (c == EOF)
64733965Sjdp	    break;
648130570Sobrien	  if (! STRING_ISGRAPHIC (c))
64989865Sobrien	    break;
65033965Sjdp	  putchar (c);
65133965Sjdp	}
65233965Sjdp
65333965Sjdp      putchar ('\n');
65433965Sjdp    }
65533965Sjdp}
65633965Sjdp
65733965Sjdp/* Parse string S as an integer, using decimal radix by default,
65833965Sjdp   but allowing octal and hex numbers as in C.  */
65933965Sjdp
66033965Sjdpstatic int
661130570Sobrieninteger_arg (char *s)
66233965Sjdp{
66333965Sjdp  int value;
66433965Sjdp  int radix = 10;
66533965Sjdp  char *p = s;
66633965Sjdp  int c;
66733965Sjdp
66833965Sjdp  if (*p != '0')
66933965Sjdp    radix = 10;
67033965Sjdp  else if (*++p == 'x')
67133965Sjdp    {
67233965Sjdp      radix = 16;
67333965Sjdp      p++;
67433965Sjdp    }
67533965Sjdp  else
67633965Sjdp    radix = 8;
67733965Sjdp
67833965Sjdp  value = 0;
67933965Sjdp  while (((c = *p++) >= '0' && c <= '9')
68033965Sjdp	 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
68133965Sjdp    {
68233965Sjdp      value *= radix;
68333965Sjdp      if (c >= '0' && c <= '9')
68433965Sjdp	value += c - '0';
68533965Sjdp      else
68633965Sjdp	value += (c & ~40) - 'A';
68733965Sjdp    }
68833965Sjdp
68933965Sjdp  if (c == 'b')
69033965Sjdp    value *= 512;
69133965Sjdp  else if (c == 'B')
69233965Sjdp    value *= 1024;
69333965Sjdp  else
69433965Sjdp    p--;
69533965Sjdp
69633965Sjdp  if (*p)
697130570Sobrien    fatal (_("invalid integer argument %s"), s);
698130570Sobrien
69933965Sjdp  return value;
70033965Sjdp}
70133965Sjdp
70233965Sjdpstatic void
703130570Sobrienusage (FILE *stream, int status)
70433965Sjdp{
70589865Sobrien  fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
70689865Sobrien  fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
70789865Sobrien  fprintf (stream, _(" The options are:\n\
70889865Sobrien  -a - --all                Scan the entire file, not just the data section\n\
70989865Sobrien  -f --print-file-name      Print the name of the file before each string\n\
71089865Sobrien  -n --bytes=[number]       Locate & print any NUL-terminated sequence of at\n\
71189865Sobrien  -<number>                 least [number] characters (default 4).\n\
712218822Sdim  -t --radix={o,d,x}        Print the location of the string in base 8, 10 or 16\n\
71389865Sobrien  -o                        An alias for --radix=o\n\
71489865Sobrien  -T --target=<BFDNAME>     Specify the binary file format\n\
715130570Sobrien  -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
716130570Sobrien                            s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
717218822Sdim  @<file>                   Read options from <file>\n\
71889865Sobrien  -h --help                 Display this information\n\
71989865Sobrien  -v --version              Print the program's version number\n"));
72033965Sjdp  list_supported_targets (program_name, stream);
721218822Sdim  if (REPORT_BUGS_TO[0] && status == 0)
72260513Sobrien    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
72333965Sjdp  exit (status);
72433965Sjdp}
725