* Many files: Added gettext invocations around user-visible
[binutils-gdb.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 }