* Many files: Added gettext invocations around user-visible
[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   program_name = argv[0];
126   xmalloc_set_program_name (program_name);
127   string_min = -1;
128   print_addresses = false;
129   print_filenames = false;
130   datasection_only = true;
131   target = NULL;
132
133   while ((optc = getopt_long (argc, argv, "afn:ot:v0123456789",
134                               long_options, (int *) 0)) != EOF)
135     {
136       switch (optc)
137         {
138         case 'a':
139           datasection_only = false;
140           break;
141
142         case 'f':
143           print_filenames = true;
144           break;
145
146         case 'h':
147           usage (stdout, 0);
148
149         case 'n':
150           string_min = integer_arg (optarg);
151           if (string_min < 1)
152             {
153               fprintf (stderr, _("%s: invalid number %s\n"),
154                        program_name, optarg);
155               exit (1);
156             }
157           break;
158
159         case 'o':
160           print_addresses = true;
161           address_radix = 8;
162           break;
163
164         case 't':
165           print_addresses = true;
166           if (optarg[1] != '\0')
167             usage (stderr, 1);
168           switch (optarg[0])
169             {
170             case 'o':
171               address_radix = 8;
172               break;
173
174             case 'd':
175               address_radix = 10;
176               break;
177
178             case 'x':
179               address_radix = 16;
180               break;
181
182             default:
183               usage (stderr, 1);
184             }
185           break;
186
187         case 'T':
188           target = optarg;
189           break;
190
191         case 'v':
192           print_version ("strings");
193           break;
194
195         case '?':
196           usage (stderr, 1);
197
198         default:
199           if (string_min < 0)
200             string_min = optc;
201           else
202             string_min = string_min * 10 + optc - '0';
203           break;
204         }
205     }
206
207   if (string_min < 0)
208     string_min = 4;
209
210   bfd_init ();
211   set_default_bfd_target ();
212
213   if (optind >= argc)
214     {
215       datasection_only = false;
216       print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
217       files_given = true;
218     }
219   else
220     {
221       for (; optind < argc; ++optind)
222         {
223           if (strcmp (argv[optind], "-") == 0)
224             datasection_only = false;
225           else
226             {
227               files_given = true;
228               exit_status |= (strings_file (argv[optind]) == false);
229             }
230         }
231     }
232
233   if (files_given == false)
234     usage (stderr, 1);
235
236   return (exit_status);
237 }
238 \f
239 /* Scan section SECT of the file ABFD, whose printable name is FILE.
240    If it contains initialized data,
241    set `got_a_section' and print the strings in it.  */
242
243 static void
244 strings_a_section (abfd, sect, filearg)
245      bfd *abfd;
246      asection *sect;
247      PTR filearg;
248 {
249   const char *file = (const char *) filearg;
250
251   if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
252     {
253       bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
254       PTR mem = xmalloc (sz);
255       if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
256         {
257           got_a_section = true;
258           print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem);
259         }
260       free (mem);
261     }
262 }
263
264 /* Scan all of the sections in FILE, and print the strings
265    in the initialized data section(s).
266
267    Return true if successful,
268    false if not (such as if FILE is not an object file).  */
269
270 static boolean
271 strings_object_file (file)
272      const char *file;
273 {
274   bfd *abfd = bfd_openr (file, target);
275
276   if (abfd == NULL)
277     {
278       /* Treat the file as a non-object file.  */
279       return false;
280     }
281
282   /* This call is mainly for its side effect of reading in the sections.
283      We follow the traditional behavior of `strings' in that we don't
284      complain if we don't recognize a file to be an object file.  */
285   if (bfd_check_format (abfd, bfd_object) == false)
286     {
287       bfd_close (abfd);
288       return false;
289     }
290
291   got_a_section = false;
292   bfd_map_over_sections (abfd, strings_a_section, (PTR) file);
293
294   if (!bfd_close (abfd))
295     {
296       bfd_nonfatal (file);
297       return false;
298     }
299
300   return got_a_section;
301 }
302
303 /* Print the strings in FILE.  Return true if ok, false if an error occurs.  */
304
305 static boolean
306 strings_file (file)
307      char *file;
308 {
309   /* If we weren't told to scan the whole file,
310      try to open it as an object file and only look at
311      initialized data sections.  If that fails, fall back to the
312      whole file.  */
313   if (!datasection_only || !strings_object_file (file))
314     {
315       FILE *stream;
316
317       stream = fopen (file, "rb");
318       /* Not all systems permit "rb", so try "r" if it failed.  */
319       if (stream == NULL)
320         stream = fopen (file, "r");
321       if (stream == NULL)
322         {
323           fprintf (stderr, "%s: ", program_name);
324           perror (file);
325           return false;
326         }
327
328       print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
329
330       if (fclose (stream) == EOF)
331         {
332           fprintf (stderr, "%s: ", program_name);
333           perror (file);
334           return false;
335         }
336     }
337
338   return true;
339 }
340 \f
341 /* Find the strings in file FILENAME, read from STREAM.
342    Assume that STREAM is positioned so that the next byte read
343    is at address ADDRESS in the file.
344    Stop reading at address STOP_POINT in the file, if nonzero.
345
346    If STREAM is NULL, do not read from it.
347    The caller can supply a buffer of characters
348    to be processed before the data in STREAM.
349    MAGIC is the address of the buffer and
350    MAGICCOUNT is how many characters are in it.
351    Those characters come at address ADDRESS and the data in STREAM follow.  */
352
353 static void
354 print_strings (filename, stream, address, stop_point, magiccount, magic)
355      const char *filename;
356      FILE *stream;
357      file_ptr address;
358      int stop_point;
359      int magiccount;
360      char *magic;
361 {
362   char *buf = (char *) xmalloc (string_min + 1);
363
364   while (1)
365     {
366       file_ptr start;
367       int i;
368       int c;
369
370       /* See if the next `string_min' chars are all graphic chars.  */
371     tryline:
372       if (stop_point && address >= stop_point)
373         break;
374       start = address;
375       for (i = 0; i < string_min; i++)
376         {
377           if (magiccount)
378             {
379               magiccount--;
380               c = *magic++;
381             }
382           else
383             {
384               if (stream == NULL)
385                 return;
386               c = getc (stream);
387               if (c == EOF)
388                 return;
389             }
390           address++;
391           if (!isgraphic (c))
392             /* Found a non-graphic.  Try again starting with next char.  */
393             goto tryline;
394           buf[i] = c;
395         }
396
397       /* We found a run of `string_min' graphic characters.  Print up
398          to the next non-graphic character.  */
399
400       if (print_filenames)
401         printf ("%s: ", filename);
402       if (print_addresses)
403         switch (address_radix)
404           {
405           case 8:
406             printf ("%7lo ", (unsigned long) start);
407             break;
408
409           case 10:
410             printf ("%7ld ", (long) start);
411             break;
412
413           case 16:
414             printf ("%7lx ", (unsigned long) start);
415             break;
416           }
417
418       buf[i] = '\0';
419       fputs (buf, stdout);
420
421       while (1)
422         {
423           if (magiccount)
424             {
425               magiccount--;
426               c = *magic++;
427             }
428           else
429             {
430               if (stream == NULL)
431                 break;
432               c = getc (stream);
433               if (c == EOF)
434                 break;
435             }
436           address++;
437           if (! isgraphic (c))
438             break;
439           putchar (c);
440         }
441
442       putchar ('\n');
443     }
444 }
445 \f
446 /* Parse string S as an integer, using decimal radix by default,
447    but allowing octal and hex numbers as in C.  */
448
449 static int
450 integer_arg (s)
451      char *s;
452 {
453   int value;
454   int radix = 10;
455   char *p = s;
456   int c;
457
458   if (*p != '0')
459     radix = 10;
460   else if (*++p == 'x')
461     {
462       radix = 16;
463       p++;
464     }
465   else
466     radix = 8;
467
468   value = 0;
469   while (((c = *p++) >= '0' && c <= '9')
470          || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
471     {
472       value *= radix;
473       if (c >= '0' && c <= '9')
474         value += c - '0';
475       else
476         value += (c & ~40) - 'A';
477     }
478
479   if (c == 'b')
480     value *= 512;
481   else if (c == 'B')
482     value *= 1024;
483   else
484     p--;
485
486   if (*p)
487     {
488       fprintf (stderr, _("%s: invalid integer argument %s\n"), program_name, s);
489       exit (1);
490     }
491   return value;
492 }
493
494 static void
495 usage (stream, status)
496      FILE *stream;
497      int status;
498 {
499   fprintf (stream, _("\
500 Usage: %s [-afov] [-n min-len] [-min-len] [-t {o,x,d}] [-]\n\
501        [--all] [--print-file-name] [--bytes=min-len] [--radix={o,x,d}]\n\
502        [--target=bfdname] [--help] [--version] file...\n"),
503            program_name);
504   list_supported_targets (program_name, stream);
505   if (status == 0)
506     fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n"));
507   exit (status);
508 }