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