* Makefile.am (INCLUDES): Search intl dirs for headers; define
[external/binutils.git] / binutils / strings.c
1 /* strings -- print the strings of printable characters in files
2    Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17    02111-1307, USA.  */
18 \f
19 /* Usage: strings [options] file...
20
21    Options:
22    --all
23    -a
24    -            Do not scan only the initialized data section of object files.
25
26    --print-file-name
27    -f           Print the name of the file before each string.
28
29    --bytes=min-len
30    -n min-len
31    -min-len     Print graphic char sequences, MIN-LEN or more bytes long,
32                 that are followed by a NUL or a newline.  Default is 4.
33
34    --radix={o,x,d}
35    -t {o,x,d}   Print the offset within the file before each string,
36                 in octal/hex/decimal.
37
38    -o           Like -to.  (Some other implementations have -o like -to,
39                 others like -td.  We chose one arbitrarily.)
40
41    --target=BFDNAME
42                 Specify a non-default object file format.
43
44    --help
45    -h           Print the usage message on the standard output.
46
47    --version
48    -v           Print the program version number.
49
50    Written by Richard Stallman <rms@gnu.ai.mit.edu>
51    and David MacKenzie <djm@gnu.ai.mit.edu>.  */
52
53 #include "bfd.h"
54 #include <stdio.h>
55 #include <getopt.h>
56 #include <ctype.h>
57 #include <errno.h>
58 #include "bucomm.h"
59 #include "libiberty.h"
60
61 #ifdef isascii
62 #define isgraphic(c) (isascii (c) && isprint (c))
63 #else
64 #define isgraphic(c) (isprint (c))
65 #endif
66
67 #ifndef errno
68 extern int errno;
69 #endif
70
71 /* The BFD section flags that identify an initialized data section.  */
72 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
73
74 /* Radix for printing addresses (must be 8, 10 or 16).  */
75 static int address_radix;
76
77 /* Minimum length of sequence of graphic chars to trigger output.  */
78 static int string_min;
79
80 /* true means print address within file for each string.  */
81 static boolean print_addresses;
82
83 /* true means print filename for each string.  */
84 static boolean print_filenames;
85
86 /* true means for object files scan only the data section.  */
87 static boolean datasection_only;
88
89 /* true if we found an initialized data section in the current file.  */
90 static boolean got_a_section;
91
92 /* The BFD object file format.  */
93 static char *target;
94
95 static struct option long_options[] =
96 {
97   {"all", no_argument, NULL, 'a'},
98   {"print-file-name", no_argument, NULL, 'f'},
99   {"bytes", required_argument, NULL, 'n'},
100   {"radix", required_argument, NULL, 't'},
101   {"target", required_argument, NULL, 'T'},
102   {"help", no_argument, NULL, 'h'},
103   {"version", no_argument, NULL, 'v'},
104   {NULL, 0, NULL, 0}
105 };
106
107 static void strings_a_section PARAMS ((bfd *, asection *, PTR));
108 static boolean strings_object_file PARAMS ((const char *));
109 static boolean strings_file PARAMS ((char *file));
110 static int integer_arg PARAMS ((char *s));
111 static void print_strings PARAMS ((const char *filename, FILE *stream,
112                                   file_ptr address, int stop_point,
113                                   int magiccount, char *magic));
114 static void usage PARAMS ((FILE *stream, int status));
115 \f
116 int
117 main (argc, argv)
118      int argc;
119      char **argv;
120 {
121   int optc;
122   int exit_status = 0;
123   boolean files_given = false;
124
125   setlocale (LC_MESSAGES, "");
126   bindtextdomain (PACKAGE, LOCALEDIR);
127   textdomain (PACKAGE);
128
129   program_name = argv[0];
130   xmalloc_set_program_name (program_name);
131   string_min = -1;
132   print_addresses = false;
133   print_filenames = false;
134   datasection_only = true;
135   target = NULL;
136
137   while ((optc = getopt_long (argc, argv, "afn:ot:v0123456789",
138                               long_options, (int *) 0)) != EOF)
139     {
140       switch (optc)
141         {
142         case 'a':
143           datasection_only = false;
144           break;
145
146         case 'f':
147           print_filenames = true;
148           break;
149
150         case 'h':
151           usage (stdout, 0);
152
153         case 'n':
154           string_min = integer_arg (optarg);
155           if (string_min < 1)
156             {
157               fprintf (stderr, _("%s: invalid number %s\n"),
158                        program_name, optarg);
159               exit (1);
160             }
161           break;
162
163         case 'o':
164           print_addresses = true;
165           address_radix = 8;
166           break;
167
168         case 't':
169           print_addresses = true;
170           if (optarg[1] != '\0')
171             usage (stderr, 1);
172           switch (optarg[0])
173             {
174             case 'o':
175               address_radix = 8;
176               break;
177
178             case 'd':
179               address_radix = 10;
180               break;
181
182             case 'x':
183               address_radix = 16;
184               break;
185
186             default:
187               usage (stderr, 1);
188             }
189           break;
190
191         case 'T':
192           target = optarg;
193           break;
194
195         case 'v':
196           print_version ("strings");
197           break;
198
199         case '?':
200           usage (stderr, 1);
201
202         default:
203           if (string_min < 0)
204             string_min = optc;
205           else
206             string_min = string_min * 10 + optc - '0';
207           break;
208         }
209     }
210
211   if (string_min < 0)
212     string_min = 4;
213
214   bfd_init ();
215   set_default_bfd_target ();
216
217   if (optind >= argc)
218     {
219       datasection_only = false;
220       print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
221       files_given = true;
222     }
223   else
224     {
225       for (; optind < argc; ++optind)
226         {
227           if (strcmp (argv[optind], "-") == 0)
228             datasection_only = false;
229           else
230             {
231               files_given = true;
232               exit_status |= (strings_file (argv[optind]) == false);
233             }
234         }
235     }
236
237   if (files_given == false)
238     usage (stderr, 1);
239
240   return (exit_status);
241 }
242 \f
243 /* Scan section SECT of the file ABFD, whose printable name is FILE.
244    If it contains initialized data,
245    set `got_a_section' and print the strings in it.  */
246
247 static void
248 strings_a_section (abfd, sect, filearg)
249      bfd *abfd;
250      asection *sect;
251      PTR filearg;
252 {
253   const char *file = (const char *) filearg;
254
255   if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
256     {
257       bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
258       PTR mem = xmalloc (sz);
259       if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
260         {
261           got_a_section = true;
262           print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem);
263         }
264       free (mem);
265     }
266 }
267
268 /* Scan all of the sections in FILE, and print the strings
269    in the initialized data section(s).
270
271    Return true if successful,
272    false if not (such as if FILE is not an object file).  */
273
274 static boolean
275 strings_object_file (file)
276      const char *file;
277 {
278   bfd *abfd = bfd_openr (file, target);
279
280   if (abfd == NULL)
281     {
282       /* Treat the file as a non-object file.  */
283       return false;
284     }
285
286   /* This call is mainly for its side effect of reading in the sections.
287      We follow the traditional behavior of `strings' in that we don't
288      complain if we don't recognize a file to be an object file.  */
289   if (bfd_check_format (abfd, bfd_object) == false)
290     {
291       bfd_close (abfd);
292       return false;
293     }
294
295   got_a_section = false;
296   bfd_map_over_sections (abfd, strings_a_section, (PTR) file);
297
298   if (!bfd_close (abfd))
299     {
300       bfd_nonfatal (file);
301       return false;
302     }
303
304   return got_a_section;
305 }
306
307 /* Print the strings in FILE.  Return true if ok, false if an error occurs.  */
308
309 static boolean
310 strings_file (file)
311      char *file;
312 {
313   /* If we weren't told to scan the whole file,
314      try to open it as an object file and only look at
315      initialized data sections.  If that fails, fall back to the
316      whole file.  */
317   if (!datasection_only || !strings_object_file (file))
318     {
319       FILE *stream;
320
321       stream = fopen (file, "rb");
322       /* Not all systems permit "rb", so try "r" if it failed.  */
323       if (stream == NULL)
324         stream = fopen (file, "r");
325       if (stream == NULL)
326         {
327           fprintf (stderr, "%s: ", program_name);
328           perror (file);
329           return false;
330         }
331
332       print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
333
334       if (fclose (stream) == EOF)
335         {
336           fprintf (stderr, "%s: ", program_name);
337           perror (file);
338           return false;
339         }
340     }
341
342   return true;
343 }
344 \f
345 /* Find the strings in file FILENAME, read from STREAM.
346    Assume that STREAM is positioned so that the next byte read
347    is at address ADDRESS in the file.
348    Stop reading at address STOP_POINT in the file, if nonzero.
349
350    If STREAM is NULL, do not read from it.
351    The caller can supply a buffer of characters
352    to be processed before the data in STREAM.
353    MAGIC is the address of the buffer and
354    MAGICCOUNT is how many characters are in it.
355    Those characters come at address ADDRESS and the data in STREAM follow.  */
356
357 static void
358 print_strings (filename, stream, address, stop_point, magiccount, magic)
359      const char *filename;
360      FILE *stream;
361      file_ptr address;
362      int stop_point;
363      int magiccount;
364      char *magic;
365 {
366   char *buf = (char *) xmalloc (string_min + 1);
367
368   while (1)
369     {
370       file_ptr start;
371       int i;
372       int c;
373
374       /* See if the next `string_min' chars are all graphic chars.  */
375     tryline:
376       if (stop_point && address >= stop_point)
377         break;
378       start = address;
379       for (i = 0; i < string_min; i++)
380         {
381           if (magiccount)
382             {
383               magiccount--;
384               c = *magic++;
385             }
386           else
387             {
388               if (stream == NULL)
389                 return;
390               c = getc (stream);
391               if (c == EOF)
392                 return;
393             }
394           address++;
395           if (!isgraphic (c))
396             /* Found a non-graphic.  Try again starting with next char.  */
397             goto tryline;
398           buf[i] = c;
399         }
400
401       /* We found a run of `string_min' graphic characters.  Print up
402          to the next non-graphic character.  */
403
404       if (print_filenames)
405         printf ("%s: ", filename);
406       if (print_addresses)
407         switch (address_radix)
408           {
409           case 8:
410             printf ("%7lo ", (unsigned long) start);
411             break;
412
413           case 10:
414             printf ("%7ld ", (long) start);
415             break;
416
417           case 16:
418             printf ("%7lx ", (unsigned long) start);
419             break;
420           }
421
422       buf[i] = '\0';
423       fputs (buf, stdout);
424
425       while (1)
426         {
427           if (magiccount)
428             {
429               magiccount--;
430               c = *magic++;
431             }
432           else
433             {
434               if (stream == NULL)
435                 break;
436               c = getc (stream);
437               if (c == EOF)
438                 break;
439             }
440           address++;
441           if (! isgraphic (c))
442             break;
443           putchar (c);
444         }
445
446       putchar ('\n');
447     }
448 }
449 \f
450 /* Parse string S as an integer, using decimal radix by default,
451    but allowing octal and hex numbers as in C.  */
452
453 static int
454 integer_arg (s)
455      char *s;
456 {
457   int value;
458   int radix = 10;
459   char *p = s;
460   int c;
461
462   if (*p != '0')
463     radix = 10;
464   else if (*++p == 'x')
465     {
466       radix = 16;
467       p++;
468     }
469   else
470     radix = 8;
471
472   value = 0;
473   while (((c = *p++) >= '0' && c <= '9')
474          || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
475     {
476       value *= radix;
477       if (c >= '0' && c <= '9')
478         value += c - '0';
479       else
480         value += (c & ~40) - 'A';
481     }
482
483   if (c == 'b')
484     value *= 512;
485   else if (c == 'B')
486     value *= 1024;
487   else
488     p--;
489
490   if (*p)
491     {
492       fprintf (stderr, _("%s: invalid integer argument %s\n"), program_name, s);
493       exit (1);
494     }
495   return value;
496 }
497
498 static void
499 usage (stream, status)
500      FILE *stream;
501      int status;
502 {
503   fprintf (stream, _("\
504 Usage: %s [-afov] [-n min-len] [-min-len] [-t {o,x,d}] [-]\n\
505        [--all] [--print-file-name] [--bytes=min-len] [--radix={o,x,d}]\n\
506        [--target=bfdname] [--help] [--version] file...\n"),
507            program_name);
508   list_supported_targets (program_name, stream);
509   if (status == 0)
510     fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n"));
511   exit (status);
512 }