strings.c revision 104837
133965Sjdp/* strings -- print the strings of printable characters in files
289865Sobrien   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
389865Sobrien   2002 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
1733965Sjdp   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1833965Sjdp   02111-1307, USA.  */
1960513Sobrien
2060513Sobrien/* $FreeBSD: head/contrib/binutils/binutils/strings.c 104837 2002-10-11 06:06:01Z obrien $ */
2133965Sjdp
2233965Sjdp/* Usage: strings [options] file...
2333965Sjdp
2433965Sjdp   Options:
2533965Sjdp   --all
2633965Sjdp   -a
2733965Sjdp   -		Do not scan only the initialized data section of object files.
2833965Sjdp
2933965Sjdp   --print-file-name
3033965Sjdp   -f		Print the name of the file before each string.
3133965Sjdp
3233965Sjdp   --bytes=min-len
3333965Sjdp   -n min-len
3433965Sjdp   -min-len	Print graphic char sequences, MIN-LEN or more bytes long,
3533965Sjdp		that are followed by a NUL or a newline.  Default is 4.
3633965Sjdp
3733965Sjdp   --radix={o,x,d}
3833965Sjdp   -t {o,x,d}	Print the offset within the file before each string,
3933965Sjdp		in octal/hex/decimal.
4033965Sjdp
4133965Sjdp   -o		Like -to.  (Some other implementations have -o like -to,
4233965Sjdp		others like -td.  We chose one arbitrarily.)
4333965Sjdp
4489865Sobrien   --encoding={s,b,l,B,L}
4589865Sobrien   -e {s,b,l,B,L}
4689865Sobrien		Select character encoding: single-byte, bigendian 16-bit,
4789865Sobrien		littleendian 16-bit, bigendian 32-bit, littleendian 32-bit
4889865Sobrien
4933965Sjdp   --target=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
6189865Sobrien#ifdef HAVE_CONFIG_H
6289865Sobrien#include "config.h"
6389865Sobrien#endif
6433965Sjdp#include "bfd.h"
6533965Sjdp#include <stdio.h>
66104837Sobrien#include "getopt.h"
6733965Sjdp#include <errno.h>
6833965Sjdp#include "bucomm.h"
6933965Sjdp#include "libiberty.h"
7089865Sobrien#include "safe-ctype.h"
7133965Sjdp
7261846Sobrien/* Some platforms need to put stdin into binary mode, to read
7361846Sobrien    binary files.  */
7461846Sobrien#ifdef HAVE_SETMODE
7561846Sobrien#ifndef O_BINARY
7661846Sobrien#ifdef _O_BINARY
7761846Sobrien#define O_BINARY _O_BINARY
7861846Sobrien#define setmode _setmode
7961846Sobrien#else
8061846Sobrien#define O_BINARY 0
8161846Sobrien#endif
8261846Sobrien#endif
8361846Sobrien#if O_BINARY
8461846Sobrien#include <io.h>
8561846Sobrien#define SET_BINARY(f) do { if (!isatty(f)) setmode(f,O_BINARY); } while (0)
8661846Sobrien#endif
8761846Sobrien#endif
8861846Sobrien
8989865Sobrien#define isgraphic(c) (ISPRINT (c) || (c) == '\t')
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;
10089865Sobrien#define file_open(s,m) fopen64(s,m)
10189865Sobrien#else
10289865Sobrientypedef off_t file_off;
10389865Sobrien#define file_open(s,m) fopen(s,m)
10489865Sobrien#endif
10589865Sobrien
10633965Sjdp/* Radix for printing addresses (must be 8, 10 or 16).  */
10733965Sjdpstatic int address_radix;
10833965Sjdp
10933965Sjdp/* Minimum length of sequence of graphic chars to trigger output.  */
11033965Sjdpstatic int string_min;
11133965Sjdp
11233965Sjdp/* true means print address within file for each string.  */
11333965Sjdpstatic boolean print_addresses;
11433965Sjdp
11533965Sjdp/* true means print filename for each string.  */
11633965Sjdpstatic boolean print_filenames;
11733965Sjdp
11833965Sjdp/* true means for object files scan only the data section.  */
11933965Sjdpstatic boolean datasection_only;
12033965Sjdp
12133965Sjdp/* true if we found an initialized data section in the current file.  */
12233965Sjdpstatic boolean got_a_section;
12333965Sjdp
12433965Sjdp/* The BFD object file format.  */
12533965Sjdpstatic char *target;
12633965Sjdp
12789865Sobrien/* The character encoding format.  */
12889865Sobrienstatic char encoding;
12989865Sobrienstatic int encoding_bytes;
13089865Sobrien
13133965Sjdpstatic struct option long_options[] =
13233965Sjdp{
13333965Sjdp  {"all", no_argument, NULL, 'a'},
13433965Sjdp  {"print-file-name", no_argument, NULL, 'f'},
13533965Sjdp  {"bytes", required_argument, NULL, 'n'},
13633965Sjdp  {"radix", required_argument, NULL, 't'},
13789865Sobrien  {"encoding", required_argument, NULL, 'e'},
13833965Sjdp  {"target", required_argument, NULL, 'T'},
13933965Sjdp  {"help", no_argument, NULL, 'h'},
14033965Sjdp  {"version", no_argument, NULL, 'v'},
14133965Sjdp  {NULL, 0, NULL, 0}
14233965Sjdp};
14333965Sjdp
14433965Sjdpstatic void strings_a_section PARAMS ((bfd *, asection *, PTR));
14533965Sjdpstatic boolean strings_object_file PARAMS ((const char *));
14633965Sjdpstatic boolean strings_file PARAMS ((char *file));
14733965Sjdpstatic int integer_arg PARAMS ((char *s));
14833965Sjdpstatic void print_strings PARAMS ((const char *filename, FILE *stream,
14989865Sobrien				  file_off address, int stop_point,
15033965Sjdp				  int magiccount, char *magic));
15133965Sjdpstatic void usage PARAMS ((FILE *stream, int status));
15289865Sobrienstatic long get_char PARAMS ((FILE *stream, file_off *address,
15389865Sobrien			      int *magiccount, char **magic));
15433965Sjdp
15589865Sobrienint main PARAMS ((int, char **));
15689865Sobrien
15733965Sjdpint
15833965Sjdpmain (argc, argv)
15933965Sjdp     int argc;
16033965Sjdp     char **argv;
16133965Sjdp{
16233965Sjdp  int optc;
16333965Sjdp  int exit_status = 0;
16433965Sjdp  boolean files_given = false;
16533965Sjdp
16689865Sobrien#if defined (HAVE_SETLOCALE)
16778837Sobrien  setlocale (LC_ALL, "");
16860513Sobrien#endif
16960513Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
17060513Sobrien  textdomain (PACKAGE);
17160513Sobrien
17233965Sjdp  program_name = argv[0];
17333965Sjdp  xmalloc_set_program_name (program_name);
17433965Sjdp  string_min = -1;
17533965Sjdp  print_addresses = false;
17633965Sjdp  print_filenames = false;
17733965Sjdp  datasection_only = true;
17833965Sjdp  target = NULL;
17989865Sobrien  encoding = 's';
18033965Sjdp
18189865Sobrien  while ((optc = getopt_long (argc, argv, "afhHn:ot:e:Vv0123456789",
18233965Sjdp			      long_options, (int *) 0)) != EOF)
18333965Sjdp    {
18433965Sjdp      switch (optc)
18533965Sjdp	{
18633965Sjdp	case 'a':
18733965Sjdp	  datasection_only = false;
18833965Sjdp	  break;
18933965Sjdp
19033965Sjdp	case 'f':
19133965Sjdp	  print_filenames = true;
19233965Sjdp	  break;
19333965Sjdp
19489865Sobrien	case 'H':
19533965Sjdp	case 'h':
19633965Sjdp	  usage (stdout, 0);
19733965Sjdp
19833965Sjdp	case 'n':
19933965Sjdp	  string_min = integer_arg (optarg);
20033965Sjdp	  if (string_min < 1)
20133965Sjdp	    {
20260513Sobrien	      fatal (_("invalid number %s"), optarg);
20333965Sjdp	    }
20433965Sjdp	  break;
20533965Sjdp
20633965Sjdp	case 'o':
20733965Sjdp	  print_addresses = true;
20833965Sjdp	  address_radix = 8;
20933965Sjdp	  break;
21033965Sjdp
21133965Sjdp	case 't':
21233965Sjdp	  print_addresses = true;
21333965Sjdp	  if (optarg[1] != '\0')
21433965Sjdp	    usage (stderr, 1);
21533965Sjdp	  switch (optarg[0])
21633965Sjdp	    {
21733965Sjdp	    case 'o':
21833965Sjdp	      address_radix = 8;
21933965Sjdp	      break;
22033965Sjdp
22133965Sjdp	    case 'd':
22233965Sjdp	      address_radix = 10;
22333965Sjdp	      break;
22433965Sjdp
22533965Sjdp	    case 'x':
22633965Sjdp	      address_radix = 16;
22733965Sjdp	      break;
22833965Sjdp
22933965Sjdp	    default:
23033965Sjdp	      usage (stderr, 1);
23133965Sjdp	    }
23233965Sjdp	  break;
23333965Sjdp
23433965Sjdp	case 'T':
23533965Sjdp	  target = optarg;
23633965Sjdp	  break;
23733965Sjdp
23889865Sobrien	case 'e':
23989865Sobrien	  if (optarg[1] != '\0')
24089865Sobrien	    usage (stderr, 1);
24189865Sobrien	  encoding = optarg[0];
24289865Sobrien	  break;
24389865Sobrien
24489865Sobrien	case 'V':
24533965Sjdp	case 'v':
24633965Sjdp	  print_version ("strings");
24733965Sjdp	  break;
24833965Sjdp
24933965Sjdp	case '?':
25033965Sjdp	  usage (stderr, 1);
25133965Sjdp
25233965Sjdp	default:
25333965Sjdp	  if (string_min < 0)
25460513Sobrien	    string_min = optc - '0';
25533965Sjdp	  else
25633965Sjdp	    string_min = string_min * 10 + optc - '0';
25733965Sjdp	  break;
25833965Sjdp	}
25933965Sjdp    }
26033965Sjdp
26133965Sjdp  if (string_min < 0)
26233965Sjdp    string_min = 4;
26333965Sjdp
26489865Sobrien  switch (encoding)
26589865Sobrien    {
26689865Sobrien    case 's':
26789865Sobrien      encoding_bytes = 1;
26889865Sobrien      break;
26989865Sobrien    case 'b':
27089865Sobrien    case 'l':
27189865Sobrien      encoding_bytes = 2;
27289865Sobrien      break;
27389865Sobrien    case 'B':
27489865Sobrien    case 'L':
27589865Sobrien      encoding_bytes = 4;
27689865Sobrien      break;
27789865Sobrien    default:
27889865Sobrien      usage (stderr, 1);
27989865Sobrien    }
28089865Sobrien
28133965Sjdp  bfd_init ();
28233965Sjdp  set_default_bfd_target ();
28333965Sjdp
28433965Sjdp  if (optind >= argc)
28533965Sjdp    {
28633965Sjdp      datasection_only = false;
28761846Sobrien#ifdef SET_BINARY
28861846Sobrien      SET_BINARY (fileno (stdin));
28961846Sobrien#endif
29033965Sjdp      print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
29133965Sjdp      files_given = true;
29233965Sjdp    }
29333965Sjdp  else
29433965Sjdp    {
29533965Sjdp      for (; optind < argc; ++optind)
29633965Sjdp	{
29733965Sjdp	  if (strcmp (argv[optind], "-") == 0)
29833965Sjdp	    datasection_only = false;
29933965Sjdp	  else
30033965Sjdp	    {
30133965Sjdp	      files_given = true;
30233965Sjdp	      exit_status |= (strings_file (argv[optind]) == false);
30333965Sjdp	    }
30433965Sjdp	}
30533965Sjdp    }
30633965Sjdp
30733965Sjdp  if (files_given == false)
30833965Sjdp    usage (stderr, 1);
30933965Sjdp
31033965Sjdp  return (exit_status);
31133965Sjdp}
31233965Sjdp
31333965Sjdp/* Scan section SECT of the file ABFD, whose printable name is FILE.
31433965Sjdp   If it contains initialized data,
31533965Sjdp   set `got_a_section' and print the strings in it.  */
31633965Sjdp
31733965Sjdpstatic void
31833965Sjdpstrings_a_section (abfd, sect, filearg)
31933965Sjdp     bfd *abfd;
32033965Sjdp     asection *sect;
32133965Sjdp     PTR filearg;
32233965Sjdp{
32333965Sjdp  const char *file = (const char *) filearg;
32433965Sjdp
32533965Sjdp  if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
32633965Sjdp    {
32733965Sjdp      bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
32833965Sjdp      PTR mem = xmalloc (sz);
32933965Sjdp      if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
33033965Sjdp	{
33133965Sjdp	  got_a_section = true;
33233965Sjdp	  print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem);
33333965Sjdp	}
33433965Sjdp      free (mem);
33533965Sjdp    }
33633965Sjdp}
33733965Sjdp
33833965Sjdp/* Scan all of the sections in FILE, and print the strings
33933965Sjdp   in the initialized data section(s).
34033965Sjdp
34133965Sjdp   Return true if successful,
34233965Sjdp   false if not (such as if FILE is not an object file).  */
34333965Sjdp
34433965Sjdpstatic boolean
34533965Sjdpstrings_object_file (file)
34633965Sjdp     const char *file;
34733965Sjdp{
34833965Sjdp  bfd *abfd = bfd_openr (file, target);
34933965Sjdp
35033965Sjdp  if (abfd == NULL)
35133965Sjdp    {
35233965Sjdp      /* Treat the file as a non-object file.  */
35333965Sjdp      return false;
35433965Sjdp    }
35533965Sjdp
35633965Sjdp  /* This call is mainly for its side effect of reading in the sections.
35733965Sjdp     We follow the traditional behavior of `strings' in that we don't
35833965Sjdp     complain if we don't recognize a file to be an object file.  */
35933965Sjdp  if (bfd_check_format (abfd, bfd_object) == false)
36033965Sjdp    {
36133965Sjdp      bfd_close (abfd);
36233965Sjdp      return false;
36333965Sjdp    }
36433965Sjdp
36533965Sjdp  got_a_section = false;
36633965Sjdp  bfd_map_over_sections (abfd, strings_a_section, (PTR) file);
36733965Sjdp
36833965Sjdp  if (!bfd_close (abfd))
36933965Sjdp    {
37033965Sjdp      bfd_nonfatal (file);
37133965Sjdp      return false;
37233965Sjdp    }
37333965Sjdp
37433965Sjdp  return got_a_section;
37533965Sjdp}
37633965Sjdp
37733965Sjdp/* Print the strings in FILE.  Return true if ok, false if an error occurs.  */
37833965Sjdp
37933965Sjdpstatic boolean
38033965Sjdpstrings_file (file)
38133965Sjdp     char *file;
38233965Sjdp{
38333965Sjdp  /* If we weren't told to scan the whole file,
38433965Sjdp     try to open it as an object file and only look at
38533965Sjdp     initialized data sections.  If that fails, fall back to the
38633965Sjdp     whole file.  */
38733965Sjdp  if (!datasection_only || !strings_object_file (file))
38833965Sjdp    {
38933965Sjdp      FILE *stream;
39033965Sjdp
39189865Sobrien      stream = file_open (file, FOPEN_RB);
39233965Sjdp      if (stream == NULL)
39333965Sjdp	{
39433965Sjdp	  fprintf (stderr, "%s: ", program_name);
39533965Sjdp	  perror (file);
39633965Sjdp	  return false;
39733965Sjdp	}
39833965Sjdp
39989865Sobrien      print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0);
40033965Sjdp
40133965Sjdp      if (fclose (stream) == EOF)
40233965Sjdp	{
40333965Sjdp	  fprintf (stderr, "%s: ", program_name);
40433965Sjdp	  perror (file);
40533965Sjdp	  return false;
40633965Sjdp	}
40733965Sjdp    }
40833965Sjdp
40933965Sjdp  return true;
41033965Sjdp}
41133965Sjdp
41289865Sobrien/* Read the next character, return EOF if none available.
41389865Sobrien   Assume that STREAM is positioned so that the next byte read
41489865Sobrien   is at address ADDRESS in the file.
41589865Sobrien
41689865Sobrien   If STREAM is NULL, do not read from it.
41789865Sobrien   The caller can supply a buffer of characters
41889865Sobrien   to be processed before the data in STREAM.
41989865Sobrien   MAGIC is the address of the buffer and
42089865Sobrien   MAGICCOUNT is how many characters are in it.  */
42189865Sobrien
42289865Sobrienstatic long
42389865Sobrienget_char (stream, address, magiccount, magic)
42489865Sobrien     FILE *stream;
42589865Sobrien     file_off *address;
42689865Sobrien     int *magiccount;
42789865Sobrien     char **magic;
42889865Sobrien{
42989865Sobrien  int c, i;
43089865Sobrien  long r = EOF;
43189865Sobrien  unsigned char buf[4];
43289865Sobrien
43389865Sobrien  for (i = 0; i < encoding_bytes; i++)
43489865Sobrien    {
43589865Sobrien      if (*magiccount)
43689865Sobrien	{
43789865Sobrien	  (*magiccount)--;
43889865Sobrien	  c = *(*magic)++;
43989865Sobrien	}
44089865Sobrien      else
44189865Sobrien	{
44289865Sobrien	  if (stream == NULL)
44389865Sobrien	    return EOF;
44489865Sobrien#ifdef HAVE_GETC_UNLOCKED
44589865Sobrien	  c = getc_unlocked (stream);
44689865Sobrien#else
44789865Sobrien	  c = getc (stream);
44889865Sobrien#endif
44989865Sobrien	  if (c == EOF)
45089865Sobrien	    return EOF;
45189865Sobrien	}
45289865Sobrien
45389865Sobrien      (*address)++;
45489865Sobrien      buf[i] = c;
45589865Sobrien    }
45689865Sobrien
45789865Sobrien  switch (encoding)
45889865Sobrien    {
45989865Sobrien    case 's':
46089865Sobrien      r = buf[0];
46189865Sobrien      break;
46289865Sobrien    case 'b':
46389865Sobrien      r = (buf[0] << 8) | buf[1];
46489865Sobrien      break;
46589865Sobrien    case 'l':
46689865Sobrien      r = buf[0] | (buf[1] << 8);
46789865Sobrien      break;
46889865Sobrien    case 'B':
46989865Sobrien      r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
47089865Sobrien	((long) buf[2] << 8) | buf[3];
47189865Sobrien      break;
47289865Sobrien    case 'L':
47389865Sobrien      r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
47489865Sobrien	((long) buf[3] << 24);
47589865Sobrien      break;
47689865Sobrien    }
47789865Sobrien
47889865Sobrien  if (r == EOF)
47989865Sobrien    return 0;
48089865Sobrien
48189865Sobrien  return r;
48289865Sobrien}
48389865Sobrien
48433965Sjdp/* Find the strings in file FILENAME, read from STREAM.
48533965Sjdp   Assume that STREAM is positioned so that the next byte read
48633965Sjdp   is at address ADDRESS in the file.
48733965Sjdp   Stop reading at address STOP_POINT in the file, if nonzero.
48833965Sjdp
48933965Sjdp   If STREAM is NULL, do not read from it.
49033965Sjdp   The caller can supply a buffer of characters
49133965Sjdp   to be processed before the data in STREAM.
49233965Sjdp   MAGIC is the address of the buffer and
49333965Sjdp   MAGICCOUNT is how many characters are in it.
49433965Sjdp   Those characters come at address ADDRESS and the data in STREAM follow.  */
49533965Sjdp
49633965Sjdpstatic void
49733965Sjdpprint_strings (filename, stream, address, stop_point, magiccount, magic)
49833965Sjdp     const char *filename;
49933965Sjdp     FILE *stream;
50089865Sobrien     file_off address;
50133965Sjdp     int stop_point;
50233965Sjdp     int magiccount;
50333965Sjdp     char *magic;
50433965Sjdp{
50589865Sobrien  char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
50633965Sjdp
50733965Sjdp  while (1)
50833965Sjdp    {
50989865Sobrien      file_off start;
51033965Sjdp      int i;
51189865Sobrien      long c;
51233965Sjdp
51333965Sjdp      /* See if the next `string_min' chars are all graphic chars.  */
51433965Sjdp    tryline:
51533965Sjdp      if (stop_point && address >= stop_point)
51633965Sjdp	break;
51733965Sjdp      start = address;
51833965Sjdp      for (i = 0; i < string_min; i++)
51933965Sjdp	{
52089865Sobrien	  c = get_char (stream, &address, &magiccount, &magic);
52189865Sobrien	  if (c == EOF)
52289865Sobrien	    return;
52389865Sobrien	  if (c > 255 || c < 0 || !isgraphic (c))
52433965Sjdp	    /* Found a non-graphic.  Try again starting with next char.  */
52533965Sjdp	    goto tryline;
52633965Sjdp	  buf[i] = c;
52733965Sjdp	}
52833965Sjdp
52933965Sjdp      /* We found a run of `string_min' graphic characters.  Print up
53033965Sjdp         to the next non-graphic character.  */
53133965Sjdp
53233965Sjdp      if (print_filenames)
53333965Sjdp	printf ("%s: ", filename);
53433965Sjdp      if (print_addresses)
53533965Sjdp	switch (address_radix)
53633965Sjdp	  {
53733965Sjdp	  case 8:
53889865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
53989865Sobrien	    if (sizeof (start) > sizeof (long))
54089865Sobrien	      printf ("%7Lo ", (unsigned long long) start);
54189865Sobrien	    else
54289865Sobrien#else
54389865Sobrien# if !BFD_HOST_64BIT_LONG
54489865Sobrien	    if (start != (unsigned long) start)
54589865Sobrien	      printf ("++%7lo ", (unsigned long) start);
54689865Sobrien	    else
54789865Sobrien# endif
54889865Sobrien#endif
54989865Sobrien	      printf ("%7lo ", (unsigned long) start);
55033965Sjdp	    break;
55133965Sjdp
55233965Sjdp	  case 10:
55389865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
55489865Sobrien	    if (sizeof (start) > sizeof (long))
55589865Sobrien	      printf ("%7Ld ", (unsigned long long) start);
55689865Sobrien	    else
55789865Sobrien#else
55889865Sobrien# if !BFD_HOST_64BIT_LONG
55989865Sobrien	    if (start != (unsigned long) start)
56089865Sobrien	      printf ("++%7ld ", (unsigned long) start);
56189865Sobrien	    else
56289865Sobrien# endif
56389865Sobrien#endif
56489865Sobrien	      printf ("%7ld ", (long) start);
56533965Sjdp	    break;
56633965Sjdp
56733965Sjdp	  case 16:
56889865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
56989865Sobrien	    if (sizeof (start) > sizeof (long))
57089865Sobrien	      printf ("%7Lx ", (unsigned long long) start);
57189865Sobrien	    else
57289865Sobrien#else
57389865Sobrien# if !BFD_HOST_64BIT_LONG
57489865Sobrien	    if (start != (unsigned long) start)
57589865Sobrien	      printf ("%lx%8.8lx ", start >> 32, start & 0xffffffff);
57689865Sobrien	    else
57789865Sobrien# endif
57889865Sobrien#endif
57989865Sobrien	      printf ("%7lx ", (unsigned long) start);
58033965Sjdp	    break;
58133965Sjdp	  }
58233965Sjdp
58333965Sjdp      buf[i] = '\0';
58433965Sjdp      fputs (buf, stdout);
58533965Sjdp
58633965Sjdp      while (1)
58733965Sjdp	{
58889865Sobrien	  c = get_char (stream, &address, &magiccount, &magic);
58989865Sobrien	  if (c == EOF)
59033965Sjdp	    break;
59189865Sobrien	  if (c > 255 || c < 0 || !isgraphic (c))
59289865Sobrien	    break;
59333965Sjdp	  putchar (c);
59433965Sjdp	}
59533965Sjdp
59633965Sjdp      putchar ('\n');
59733965Sjdp    }
59833965Sjdp}
59933965Sjdp
60033965Sjdp/* Parse string S as an integer, using decimal radix by default,
60133965Sjdp   but allowing octal and hex numbers as in C.  */
60233965Sjdp
60333965Sjdpstatic int
60433965Sjdpinteger_arg (s)
60533965Sjdp     char *s;
60633965Sjdp{
60733965Sjdp  int value;
60833965Sjdp  int radix = 10;
60933965Sjdp  char *p = s;
61033965Sjdp  int c;
61133965Sjdp
61233965Sjdp  if (*p != '0')
61333965Sjdp    radix = 10;
61433965Sjdp  else if (*++p == 'x')
61533965Sjdp    {
61633965Sjdp      radix = 16;
61733965Sjdp      p++;
61833965Sjdp    }
61933965Sjdp  else
62033965Sjdp    radix = 8;
62133965Sjdp
62233965Sjdp  value = 0;
62333965Sjdp  while (((c = *p++) >= '0' && c <= '9')
62433965Sjdp	 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
62533965Sjdp    {
62633965Sjdp      value *= radix;
62733965Sjdp      if (c >= '0' && c <= '9')
62833965Sjdp	value += c - '0';
62933965Sjdp      else
63033965Sjdp	value += (c & ~40) - 'A';
63133965Sjdp    }
63233965Sjdp
63333965Sjdp  if (c == 'b')
63433965Sjdp    value *= 512;
63533965Sjdp  else if (c == 'B')
63633965Sjdp    value *= 1024;
63733965Sjdp  else
63833965Sjdp    p--;
63933965Sjdp
64033965Sjdp  if (*p)
64133965Sjdp    {
64260513Sobrien      fatal (_("invalid integer argument %s"), s);
64333965Sjdp    }
64433965Sjdp  return value;
64533965Sjdp}
64633965Sjdp
64733965Sjdpstatic void
64833965Sjdpusage (stream, status)
64933965Sjdp     FILE *stream;
65033965Sjdp     int status;
65133965Sjdp{
65289865Sobrien  fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
65389865Sobrien  fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
65489865Sobrien  fprintf (stream, _(" The options are:\n\
65589865Sobrien  -a - --all                Scan the entire file, not just the data section\n\
65689865Sobrien  -f --print-file-name      Print the name of the file before each string\n\
65789865Sobrien  -n --bytes=[number]       Locate & print any NUL-terminated sequence of at\n\
65889865Sobrien  -<number>                 least [number] characters (default 4).\n\
65989865Sobrien  -t --radix={o,x,d}        Print the location of the string in base 8, 10 or 16\n\
66089865Sobrien  -o                        An alias for --radix=o\n\
66189865Sobrien  -T --target=<BFDNAME>     Specify the binary file format\n\
66289865Sobrien  -e --encoding={s,b,l,B,L} Select character size and endianness:\n\
66389865Sobrien                            s = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
66489865Sobrien  -h --help                 Display this information\n\
66589865Sobrien  -v --version              Print the program's version number\n"));
66633965Sjdp  list_supported_targets (program_name, stream);
66733965Sjdp  if (status == 0)
66860513Sobrien    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
66933965Sjdp  exit (status);
67033965Sjdp}
671