source: MondoRescue/branches/3.3/mindi-busybox/coreutils/od_bloaty.c@ 3621

Last change on this file since 3621 was 3621, checked in by Bruno Cornec, 7 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 36.5 KB
Line 
1/* od -- dump files in octal and other formats
2 Copyright (C) 92, 1995-2004 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 Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18/* Written by Jim Meyering. */
19/* Busyboxed by Denys Vlasenko, based on od.c from coreutils-5.2.1 */
20
21
22/* #include "libbb.h" - done in od.c */
23#include "common_bufsiz.h"
24#define assert(a) ((void)0)
25
26
27//usage:#if ENABLE_DESKTOP
28//usage:#define od_trivial_usage
29//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..."
30// We don't support:
31// ... [FILE] [[+]OFFSET[.][b]]
32// Support is buggy for:
33// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]
34
35//usage:#define od_full_usage "\n\n"
36//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default"
37//usage:#endif
38
39enum {
40 OPT_A = 1 << 0,
41 OPT_N = 1 << 1,
42 OPT_a = 1 << 2,
43 OPT_b = 1 << 3,
44 OPT_c = 1 << 4,
45 OPT_d = 1 << 5,
46 OPT_f = 1 << 6,
47 OPT_h = 1 << 7,
48 OPT_i = 1 << 8,
49 OPT_j = 1 << 9,
50 OPT_l = 1 << 10,
51 OPT_o = 1 << 11,
52 OPT_t = 1 << 12,
53 /* When zero and two or more consecutive blocks are equal, format
54 only the first block and output an asterisk alone on the following
55 line to indicate that identical blocks have been elided: */
56 OPT_v = 1 << 13,
57 OPT_x = 1 << 14,
58 OPT_s = 1 << 15,
59 OPT_S = 1 << 16,
60 OPT_w = 1 << 17,
61 OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS,
62};
63
64#define OD_GETOPT32() getopt32(argv, \
65 "A:N:abcdfhij:lot:vxsS:w::", \
66 /* -w with optional param */ \
67 /* -S was -s and also had optional parameter */ \
68 /* but in coreutils 6.3 it was renamed and now has */ \
69 /* _mandatory_ parameter */ \
70 &str_A, &str_N, &str_j, &lst_t, &str_S, &G.bytes_per_block)
71
72
73/* Check for 0x7f is a coreutils 6.3 addition */
74#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f)
75
76typedef long double longdouble_t;
77typedef unsigned long long ulonglong_t;
78typedef long long llong;
79
80#if ENABLE_LFS
81# define xstrtooff_sfx xstrtoull_sfx
82#else
83# define xstrtooff_sfx xstrtoul_sfx
84#endif
85
86/* The default number of input bytes per output line. */
87#define DEFAULT_BYTES_PER_BLOCK 16
88
89/* The number of decimal digits of precision in a float. */
90#ifndef FLT_DIG
91# define FLT_DIG 7
92#endif
93
94/* The number of decimal digits of precision in a double. */
95#ifndef DBL_DIG
96# define DBL_DIG 15
97#endif
98
99/* The number of decimal digits of precision in a long double. */
100#ifndef LDBL_DIG
101# define LDBL_DIG DBL_DIG
102#endif
103
104enum size_spec {
105 NO_SIZE,
106 CHAR,
107 SHORT,
108 INT,
109 LONG,
110 LONG_LONG,
111 FLOAT_SINGLE,
112 FLOAT_DOUBLE,
113 FLOAT_LONG_DOUBLE,
114 N_SIZE_SPECS
115};
116
117enum output_format {
118 SIGNED_DECIMAL,
119 UNSIGNED_DECIMAL,
120 OCTAL,
121 HEXADECIMAL,
122 FLOATING_POINT,
123 NAMED_CHARACTER,
124 CHARACTER
125};
126
127/* Each output format specification (from '-t spec' or from
128 old-style options) is represented by one of these structures. */
129struct tspec {
130 enum output_format fmt;
131 enum size_spec size;
132 void (*print_function) (size_t, const char *, const char *);
133 char *fmt_string;
134 int hexl_mode_trailer;
135 int field_width;
136};
137
138/* Convert the number of 8-bit bytes of a binary representation to
139 the number of characters (digits + sign if the type is signed)
140 required to represent the same quantity in the specified base/type.
141 For example, a 32-bit (4-byte) quantity may require a field width
142 as wide as the following for these types:
143 11 unsigned octal
144 11 signed decimal
145 10 unsigned decimal
146 8 unsigned hexadecimal */
147
148static const uint8_t bytes_to_oct_digits[] ALIGN1 =
149{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
150
151static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
152{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
153
154static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
155{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
156
157static const uint8_t bytes_to_hex_digits[] ALIGN1 =
158{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
159
160/* Convert enum size_spec to the size of the named type. */
161static const signed char width_bytes[] ALIGN1 = {
162 -1,
163 sizeof(char),
164 sizeof(short),
165 sizeof(int),
166 sizeof(long),
167 sizeof(ulonglong_t),
168 sizeof(float),
169 sizeof(double),
170 sizeof(longdouble_t)
171};
172/* Ensure that for each member of 'enum size_spec' there is an
173 initializer in the width_bytes array. */
174struct ERR_width_bytes_has_bad_size {
175 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
176};
177
178struct globals {
179 smallint exit_code;
180
181 unsigned string_min;
182
183 /* An array of specs describing how to format each input block. */
184 unsigned n_specs;
185 struct tspec *spec;
186
187 /* Function that accepts an address and an optional following char,
188 and prints the address and char to stdout. */
189 void (*format_address)(off_t, char);
190
191 /* The difference between the old-style pseudo starting address and
192 the number of bytes to skip. */
193#if ENABLE_LONG_OPTS
194 off_t pseudo_offset;
195# define G_pseudo_offset G.pseudo_offset
196#endif
197 /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
198 input is formatted. */
199
200 /* The number of input bytes formatted per output line. It must be
201 a multiple of the least common multiple of the sizes associated with
202 the specified output types. It should be as large as possible, but
203 no larger than 16 -- unless specified with the -w option. */
204 unsigned bytes_per_block; /* have to use unsigned, not size_t */
205
206 /* A NULL-terminated list of the file-arguments from the command line. */
207 const char *const *file_list;
208
209 /* The input stream associated with the current file. */
210 FILE *in_stream;
211
212 bool not_first;
213 bool prev_pair_equal;
214} FIX_ALIASING;
215#if !ENABLE_LONG_OPTS
216enum { G_pseudo_offset = 0 };
217#endif
218#define G (*(struct globals*)bb_common_bufsiz1)
219#define INIT_G() do { \
220 setup_common_bufsiz(); \
221 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
222 G.bytes_per_block = 32; \
223} while (0)
224
225
226#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
227static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
228 [sizeof(char)] = CHAR,
229#if USHRT_MAX != UCHAR_MAX
230 [sizeof(short)] = SHORT,
231#endif
232#if UINT_MAX != USHRT_MAX
233 [sizeof(int)] = INT,
234#endif
235#if ULONG_MAX != UINT_MAX
236 [sizeof(long)] = LONG,
237#endif
238#if ULLONG_MAX != ULONG_MAX
239 [sizeof(ulonglong_t)] = LONG_LONG,
240#endif
241};
242
243#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
244static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
245 /* gcc seems to allow repeated indexes. Last one wins */
246 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
247 [sizeof(double)] = FLOAT_DOUBLE,
248 [sizeof(float)] = FLOAT_SINGLE
249};
250
251
252static unsigned
253gcd(unsigned u, unsigned v)
254{
255 unsigned t;
256 while (v != 0) {
257 t = u % v;
258 u = v;
259 v = t;
260 }
261 return u;
262}
263
264/* Compute the least common multiple of U and V. */
265static unsigned
266lcm(unsigned u, unsigned v) {
267 unsigned t = gcd(u, v);
268 if (t == 0)
269 return 0;
270 return u * v / t;
271}
272
273static void
274print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
275{
276 while (n_bytes--) {
277 int tmp = *(signed char *) block;
278 printf(fmt_string, tmp);
279 block += sizeof(unsigned char);
280 }
281}
282
283static void
284print_char(size_t n_bytes, const char *block, const char *fmt_string)
285{
286 while (n_bytes--) {
287 unsigned tmp = *(unsigned char *) block;
288 printf(fmt_string, tmp);
289 block += sizeof(unsigned char);
290 }
291}
292
293static void
294print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
295{
296 n_bytes /= sizeof(signed short);
297 while (n_bytes--) {
298 int tmp = *(signed short *) block;
299 printf(fmt_string, tmp);
300 block += sizeof(unsigned short);
301 }
302}
303
304static void
305print_short(size_t n_bytes, const char *block, const char *fmt_string)
306{
307 n_bytes /= sizeof(unsigned short);
308 while (n_bytes--) {
309 unsigned tmp = *(unsigned short *) block;
310 printf(fmt_string, tmp);
311 block += sizeof(unsigned short);
312 }
313}
314
315static void
316print_int(size_t n_bytes, const char *block, const char *fmt_string)
317{
318 n_bytes /= sizeof(unsigned);
319 while (n_bytes--) {
320 unsigned tmp = *(unsigned *) block;
321 printf(fmt_string, tmp);
322 block += sizeof(unsigned);
323 }
324}
325
326#if UINT_MAX == ULONG_MAX
327# define print_long print_int
328#else
329static void
330print_long(size_t n_bytes, const char *block, const char *fmt_string)
331{
332 n_bytes /= sizeof(unsigned long);
333 while (n_bytes--) {
334 unsigned long tmp = *(unsigned long *) block;
335 printf(fmt_string, tmp);
336 block += sizeof(unsigned long);
337 }
338}
339#endif
340
341#if ULONG_MAX == ULLONG_MAX
342# define print_long_long print_long
343#else
344static void
345print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
346{
347 n_bytes /= sizeof(ulonglong_t);
348 while (n_bytes--) {
349 ulonglong_t tmp = *(ulonglong_t *) block;
350 printf(fmt_string, tmp);
351 block += sizeof(ulonglong_t);
352 }
353}
354#endif
355
356static void
357print_float(size_t n_bytes, const char *block, const char *fmt_string)
358{
359 n_bytes /= sizeof(float);
360 while (n_bytes--) {
361 float tmp = *(float *) block;
362 printf(fmt_string, tmp);
363 block += sizeof(float);
364 }
365}
366
367static void
368print_double(size_t n_bytes, const char *block, const char *fmt_string)
369{
370 n_bytes /= sizeof(double);
371 while (n_bytes--) {
372 double tmp = *(double *) block;
373 printf(fmt_string, tmp);
374 block += sizeof(double);
375 }
376}
377
378static void
379print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
380{
381 n_bytes /= sizeof(longdouble_t);
382 while (n_bytes--) {
383 longdouble_t tmp = *(longdouble_t *) block;
384 printf(fmt_string, tmp);
385 block += sizeof(longdouble_t);
386 }
387}
388
389/* print_[named]_ascii are optimized for speed.
390 * Remember, someday you may want to pump gigabytes through this thing.
391 * Saving a dozen of .text bytes here is counter-productive */
392
393static void
394print_named_ascii(size_t n_bytes, const char *block,
395 const char *unused_fmt_string UNUSED_PARAM)
396{
397 /* Names for some non-printing characters. */
398 static const char charname[33][3] ALIGN1 = {
399 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
400 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
401 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
402 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
403 " sp"
404 };
405 // buf[N] pos: 01234 56789
406 char buf[12] = " x\0 xxx\0";
407 // [12] because we take three 32bit stack slots anyway, and
408 // gcc is too dumb to initialize with constant stores,
409 // it copies initializer from rodata. Oh well.
410 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410
411
412 while (n_bytes--) {
413 unsigned masked_c = *(unsigned char *) block++;
414
415 masked_c &= 0x7f;
416 if (masked_c == 0x7f) {
417 fputs(" del", stdout);
418 continue;
419 }
420 if (masked_c > ' ') {
421 buf[3] = masked_c;
422 fputs(buf, stdout);
423 continue;
424 }
425 /* Why? Because printf(" %3.3s") is much slower... */
426 buf[6] = charname[masked_c][0];
427 buf[7] = charname[masked_c][1];
428 buf[8] = charname[masked_c][2];
429 fputs(buf+5, stdout);
430 }
431}
432
433static void
434print_ascii(size_t n_bytes, const char *block,
435 const char *unused_fmt_string UNUSED_PARAM)
436{
437 // buf[N] pos: 01234 56789
438 char buf[12] = " x\0 xxx\0";
439
440 while (n_bytes--) {
441 const char *s;
442 unsigned c = *(unsigned char *) block++;
443
444 if (ISPRINT(c)) {
445 buf[3] = c;
446 fputs(buf, stdout);
447 continue;
448 }
449 switch (c) {
450 case '\0':
451 s = " \\0";
452 break;
453 case '\007':
454 s = " \\a";
455 break;
456 case '\b':
457 s = " \\b";
458 break;
459 case '\f':
460 s = " \\f";
461 break;
462 case '\n':
463 s = " \\n";
464 break;
465 case '\r':
466 s = " \\r";
467 break;
468 case '\t':
469 s = " \\t";
470 break;
471 case '\v':
472 s = " \\v";
473 break;
474 default:
475 buf[6] = (c >> 6 & 3) + '0';
476 buf[7] = (c >> 3 & 7) + '0';
477 buf[8] = (c & 7) + '0';
478 s = buf + 5;
479 }
480 fputs(s, stdout);
481 }
482}
483
484/* Given a list of one or more input filenames FILE_LIST, set the global
485 file pointer IN_STREAM and the global string INPUT_FILENAME to the
486 first one that can be successfully opened. Modify FILE_LIST to
487 reference the next filename in the list. A file name of "-" is
488 interpreted as standard input. If any file open fails, give an error
489 message and return nonzero. */
490
491static void
492open_next_file(void)
493{
494 while (1) {
495 if (!*G.file_list)
496 return;
497 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
498 if (G.in_stream) {
499 break;
500 }
501 G.exit_code = 1;
502 }
503
504 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
505 setbuf(G.in_stream, NULL);
506}
507
508/* Test whether there have been errors on in_stream, and close it if
509 it is not standard input. Return nonzero if there has been an error
510 on in_stream or stdout; return zero otherwise. This function will
511 report more than one error only if both a read and a write error
512 have occurred. IN_ERRNO, if nonzero, is the error number
513 corresponding to the most recent action for IN_STREAM. */
514
515static void
516check_and_close(void)
517{
518 if (G.in_stream) {
519 if (ferror(G.in_stream)) {
520 bb_error_msg("%s: read error", (G.in_stream == stdin)
521 ? bb_msg_standard_input
522 : G.file_list[-1]
523 );
524 G.exit_code = 1;
525 }
526 fclose_if_not_stdin(G.in_stream);
527 G.in_stream = NULL;
528 }
529
530 if (ferror(stdout)) {
531 bb_error_msg_and_die(bb_msg_write_error);
532 }
533}
534
535/* If S points to a single valid modern od format string, put
536 a description of that format in *TSPEC, return pointer to
537 character following the just-decoded format.
538 For example, if S were "d4afL", we will return a rtp to "afL"
539 and *TSPEC would be
540 {
541 fmt = SIGNED_DECIMAL;
542 size = INT or LONG; (whichever integral_type_size[4] resolves to)
543 print_function = print_int; (assuming size == INT)
544 fmt_string = "%011d%c";
545 }
546 S_ORIG is solely for reporting errors. It should be the full format
547 string argument. */
548
549static NOINLINE const char *
550decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
551{
552 enum size_spec size_spec;
553 unsigned size;
554 enum output_format fmt;
555 const char *p;
556 char *end;
557 char *fmt_string = NULL;
558 void (*print_function) (size_t, const char *, const char *);
559 unsigned c;
560 unsigned field_width = 0;
561 int pos;
562
563 switch (*s) {
564 case 'd':
565 case 'o':
566 case 'u':
567 case 'x': {
568 static const char CSIL[] ALIGN1 = "CSIL";
569
570 c = *s++;
571 p = strchr(CSIL, *s);
572 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
573 if (!p || *p == '\0') {
574 size = sizeof(int);
575 if (isdigit(s[0])) {
576 size = bb_strtou(s, &end, 0);
577 if (errno == ERANGE
578 || MAX_INTEGRAL_TYPE_SIZE < size
579 || integral_type_size[size] == NO_SIZE
580 ) {
581 bb_error_msg_and_die("invalid type string '%s'; "
582 "%u-byte %s type is not supported",
583 s_orig, size, "integral");
584 }
585 s = end;
586 }
587 } else {
588 static const uint8_t CSIL_sizeof[4] = {
589 sizeof(char),
590 sizeof(short),
591 sizeof(int),
592 sizeof(long),
593 };
594 size = CSIL_sizeof[p - CSIL];
595 s++; /* skip C/S/I/L */
596 }
597
598#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
599 ((Spec) == LONG_LONG ? (Max_format) \
600 : ((Spec) == LONG ? (Long_format) : (Min_format)))
601
602#define FMT_BYTES_ALLOCATED 9
603 size_spec = integral_type_size[size];
604
605 {
606 static const char doux[] ALIGN1 = "doux";
607 static const char doux_fmt_letter[][4] = {
608 "lld", "llo", "llu", "llx"
609 };
610 static const enum output_format doux_fmt[] = {
611 SIGNED_DECIMAL,
612 OCTAL,
613 UNSIGNED_DECIMAL,
614 HEXADECIMAL,
615 };
616 static const uint8_t *const doux_bytes_to_XXX[] = {
617 bytes_to_signed_dec_digits,
618 bytes_to_oct_digits,
619 bytes_to_unsigned_dec_digits,
620 bytes_to_hex_digits,
621 };
622 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
623 " %%%u%s",
624 " %%0%u%s",
625 " %%%u%s",
626 " %%0%u%s",
627 };
628
629 pos = strchr(doux, c) - doux;
630 fmt = doux_fmt[pos];
631 field_width = doux_bytes_to_XXX[pos][size];
632 p = doux_fmt_letter[pos] + 2;
633 if (size_spec == LONG) p--;
634 if (size_spec == LONG_LONG) p -= 2;
635 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
636 }
637
638 switch (size_spec) {
639 case CHAR:
640 print_function = (fmt == SIGNED_DECIMAL
641 ? print_s_char
642 : print_char);
643 break;
644 case SHORT:
645 print_function = (fmt == SIGNED_DECIMAL
646 ? print_s_short
647 : print_short);
648 break;
649 case INT:
650 print_function = print_int;
651 break;
652 case LONG:
653 print_function = print_long;
654 break;
655 default: /* case LONG_LONG: */
656 print_function = print_long_long;
657 break;
658 }
659 break;
660 }
661
662 case 'f': {
663 static const char FDL[] ALIGN1 = "FDL";
664
665 fmt = FLOATING_POINT;
666 ++s;
667 p = strchr(FDL, *s);
668 if (!p) {
669 size = sizeof(double);
670 if (isdigit(s[0])) {
671 size = bb_strtou(s, &end, 0);
672 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
673 || fp_type_size[size] == NO_SIZE
674 ) {
675 bb_error_msg_and_die("invalid type string '%s'; "
676 "%u-byte %s type is not supported",
677 s_orig, size, "floating point");
678 }
679 s = end;
680 }
681 } else {
682 static const uint8_t FDL_sizeof[] = {
683 sizeof(float),
684 sizeof(double),
685 sizeof(longdouble_t),
686 };
687
688 size = FDL_sizeof[p - FDL];
689 }
690
691 size_spec = fp_type_size[size];
692
693 switch (size_spec) {
694 case FLOAT_SINGLE:
695 print_function = print_float;
696 field_width = FLT_DIG + 8;
697 /* Don't use %#e; not all systems support it. */
698 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
699 break;
700 case FLOAT_DOUBLE:
701 print_function = print_double;
702 field_width = DBL_DIG + 8;
703 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
704 break;
705 default: /* case FLOAT_LONG_DOUBLE: */
706 print_function = print_long_double;
707 field_width = LDBL_DIG + 8;
708 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
709 break;
710 }
711 break;
712 }
713
714 case 'a':
715 ++s;
716 fmt = NAMED_CHARACTER;
717 size_spec = CHAR;
718 print_function = print_named_ascii;
719 field_width = 3;
720 break;
721 case 'c':
722 ++s;
723 fmt = CHARACTER;
724 size_spec = CHAR;
725 print_function = print_ascii;
726 field_width = 3;
727 break;
728 default:
729 bb_error_msg_and_die("invalid character '%c' "
730 "in type string '%s'", *s, s_orig);
731 }
732
733 tspec->size = size_spec;
734 tspec->fmt = fmt;
735 tspec->print_function = print_function;
736 tspec->fmt_string = fmt_string;
737
738 tspec->field_width = field_width;
739 tspec->hexl_mode_trailer = (*s == 'z');
740 if (tspec->hexl_mode_trailer)
741 s++;
742
743 return s;
744}
745
746/* Decode the modern od format string S. Append the decoded
747 representation to the global array SPEC, reallocating SPEC if
748 necessary. */
749
750static void
751decode_format_string(const char *s)
752{
753 const char *s_orig = s;
754
755 while (*s != '\0') {
756 struct tspec tspec;
757 const char *next;
758
759 next = decode_one_format(s_orig, s, &tspec);
760
761 assert(s != next);
762 s = next;
763 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
764 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
765 G.n_specs++;
766 }
767}
768
769/* Given a list of one or more input filenames FILE_LIST, set the global
770 file pointer IN_STREAM to position N_SKIP in the concatenation of
771 those files. If any file operation fails or if there are fewer than
772 N_SKIP bytes in the combined input, give an error message and return
773 nonzero. When possible, use seek rather than read operations to
774 advance IN_STREAM. */
775
776static void
777skip(off_t n_skip)
778{
779 if (n_skip == 0)
780 return;
781
782 while (G.in_stream) { /* !EOF */
783 struct stat file_stats;
784
785 /* First try seeking. For large offsets, this extra work is
786 worthwhile. If the offset is below some threshold it may be
787 more efficient to move the pointer by reading. There are two
788 issues when trying to seek:
789 - the file must be seekable.
790 - before seeking to the specified position, make sure
791 that the new position is in the current file.
792 Try to do that by getting file's size using fstat.
793 But that will work only for regular files. */
794
795 /* The st_size field is valid only for regular files
796 (and for symbolic links, which cannot occur here).
797 If the number of bytes left to skip is at least
798 as large as the size of the current file, we can
799 decrement n_skip and go on to the next file. */
800 if (fstat(fileno(G.in_stream), &file_stats) == 0
801 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
802 ) {
803 if (file_stats.st_size < n_skip) {
804 n_skip -= file_stats.st_size;
805 /* take "check & close / open_next" route */
806 } else {
807 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
808 G.exit_code = 1;
809 return;
810 }
811 } else {
812 /* If it's not a regular file with positive size,
813 position the file pointer by reading. */
814 char buf[1024];
815 size_t n_bytes_to_read = 1024;
816 size_t n_bytes_read;
817
818 while (n_skip > 0) {
819 if (n_skip < n_bytes_to_read)
820 n_bytes_to_read = n_skip;
821 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
822 n_skip -= n_bytes_read;
823 if (n_bytes_read != n_bytes_to_read)
824 break; /* EOF on this file or error */
825 }
826 }
827 if (n_skip == 0)
828 return;
829
830 check_and_close();
831 open_next_file();
832 }
833
834 if (n_skip)
835 bb_error_msg_and_die("can't skip past end of combined input");
836}
837
838
839typedef void FN_format_address(off_t address, char c);
840
841static void
842format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
843{
844}
845
846static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
847/* Corresponds to 'x' above */
848#define address_base_char address_fmt[sizeof(address_fmt)-3]
849/* Corresponds to 'n' above */
850#define address_pad_len_char address_fmt[2]
851
852static void
853format_address_std(off_t address, char c)
854{
855 /* Corresponds to 'c' */
856 address_fmt[sizeof(address_fmt)-2] = c;
857 printf(address_fmt, address);
858}
859
860#if ENABLE_LONG_OPTS
861/* only used with --traditional */
862static void
863format_address_paren(off_t address, char c)
864{
865 putchar('(');
866 format_address_std(address, ')');
867 if (c) putchar(c);
868}
869
870static void
871format_address_label(off_t address, char c)
872{
873 format_address_std(address, ' ');
874 format_address_paren(address + G_pseudo_offset, c);
875}
876#endif
877
878static void
879dump_hexl_mode_trailer(size_t n_bytes, const char *block)
880{
881 fputs(" >", stdout);
882 while (n_bytes--) {
883 unsigned c = *(unsigned char *) block++;
884 c = (ISPRINT(c) ? c : '.');
885 putchar(c);
886 }
887 putchar('<');
888}
889
890/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
891 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
892 CURR_BLOCK in the concatenation of input files, and it is printed
893 (optionally) only before the output line associated with the first
894 format spec. When duplicate blocks are being abbreviated, the output
895 for a sequence of identical input blocks is the output for the first
896 block followed by an asterisk alone on a line. It is valid to compare
897 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
898 That condition may be false only for the last input block -- and then
899 only when it has not been padded to length BYTES_PER_BLOCK. */
900
901static void
902write_block(off_t current_offset, size_t n_bytes,
903 const char *prev_block, const char *curr_block)
904{
905 unsigned i;
906
907 if (!(option_mask32 & OPT_v)
908 && G.not_first
909 && n_bytes == G.bytes_per_block
910 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
911 ) {
912 if (G.prev_pair_equal) {
913 /* The two preceding blocks were equal, and the current
914 block is the same as the last one, so print nothing. */
915 } else {
916 puts("*");
917 G.prev_pair_equal = 1;
918 }
919 } else {
920 G.not_first = 1;
921 G.prev_pair_equal = 0;
922 for (i = 0; i < G.n_specs; i++) {
923 if (i == 0)
924 G.format_address(current_offset, '\0');
925 else
926 printf("%*s", address_pad_len_char - '0', "");
927 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
928 if (G.spec[i].hexl_mode_trailer) {
929 /* space-pad out to full line width, then dump the trailer */
930 unsigned datum_width = width_bytes[G.spec[i].size];
931 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
932 unsigned field_width = G.spec[i].field_width + 1;
933 printf("%*s", blank_fields * field_width, "");
934 dump_hexl_mode_trailer(n_bytes, curr_block);
935 }
936 putchar('\n');
937 }
938 }
939}
940
941static void
942read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
943{
944 assert(0 < n && n <= G.bytes_per_block);
945
946 *n_bytes_in_buffer = 0;
947
948 if (n == 0)
949 return;
950
951 while (G.in_stream != NULL) { /* EOF. */
952 size_t n_needed;
953 size_t n_read;
954
955 n_needed = n - *n_bytes_in_buffer;
956 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
957 *n_bytes_in_buffer += n_read;
958 if (n_read == n_needed)
959 break;
960 /* error check is done in check_and_close */
961 check_and_close();
962 open_next_file();
963 }
964}
965
966/* Return the least common multiple of the sizes associated
967 with the format specs. */
968
969static int
970get_lcm(void)
971{
972 size_t i;
973 int l_c_m = 1;
974
975 for (i = 0; i < G.n_specs; i++)
976 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
977 return l_c_m;
978}
979
980/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
981 formatted block to standard output, and repeat until the specified
982 maximum number of bytes has been read or until all input has been
983 processed. If the last block read is smaller than BYTES_PER_BLOCK
984 and its size is not a multiple of the size associated with a format
985 spec, extend the input block with zero bytes until its length is a
986 multiple of all format spec sizes. Write the final block. Finally,
987 write on a line by itself the offset of the byte after the last byte
988 read. */
989
990static void
991dump(off_t current_offset, off_t end_offset)
992{
993 char *block[2];
994 int idx;
995 size_t n_bytes_read;
996
997 block[0] = xmalloc(2 * G.bytes_per_block);
998 block[1] = block[0] + G.bytes_per_block;
999
1000 idx = 0;
1001 if (option_mask32 & OPT_N) {
1002 while (1) {
1003 size_t n_needed;
1004 if (current_offset >= end_offset) {
1005 n_bytes_read = 0;
1006 break;
1007 }
1008 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
1009 read_block(n_needed, block[idx], &n_bytes_read);
1010 if (n_bytes_read < G.bytes_per_block)
1011 break;
1012 assert(n_bytes_read == G.bytes_per_block);
1013 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1014 current_offset += n_bytes_read;
1015 idx ^= 1;
1016 }
1017 } else {
1018 while (1) {
1019 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1020 if (n_bytes_read < G.bytes_per_block)
1021 break;
1022 assert(n_bytes_read == G.bytes_per_block);
1023 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
1024 current_offset += n_bytes_read;
1025 idx ^= 1;
1026 }
1027 }
1028
1029 if (n_bytes_read > 0) {
1030 int l_c_m;
1031 size_t bytes_to_write;
1032
1033 l_c_m = get_lcm();
1034
1035 /* Make bytes_to_write the smallest multiple of l_c_m that
1036 is at least as large as n_bytes_read. */
1037 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1038
1039 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1040 write_block(current_offset, bytes_to_write,
1041 block[idx ^ 1], block[idx]);
1042 current_offset += n_bytes_read;
1043 }
1044
1045 G.format_address(current_offset, '\n');
1046
1047 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
1048 check_and_close();
1049
1050 free(block[0]);
1051}
1052
1053/* Read N bytes into BLOCK from the concatenation of the input files
1054 named in the global array FILE_LIST. On the first call to this
1055 function, the global variable IN_STREAM is expected to be an open
1056 stream associated with the input file INPUT_FILENAME. If all N
1057 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1058 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1059 read the remaining bytes from the newly opened file. Repeat if
1060 necessary until EOF is reached for the last file in FILE_LIST.
1061 On subsequent calls, don't modify BLOCK and return zero. Set
1062 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1063 it will be detected through ferror when the stream is about to be
1064 closed. If there is an error, give a message but continue reading
1065 as usual and return nonzero. Otherwise return zero. */
1066
1067/* STRINGS mode. Find each "string constant" in the input.
1068 A string constant is a run of at least 'string_min' ASCII
1069 graphic (or formatting) characters terminated by a null.
1070 Based on a function written by Richard Stallman for a
1071 traditional version of od. */
1072
1073static void
1074dump_strings(off_t address, off_t end_offset)
1075{
1076 unsigned bufsize = MAX(100, G.string_min);
1077 unsigned char *buf = xmalloc(bufsize);
1078
1079 while (1) {
1080 size_t i;
1081 int c;
1082
1083 /* See if the next 'G.string_min' chars are all printing chars. */
1084 tryline:
1085 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
1086 break;
1087 i = 0;
1088 while (!(option_mask32 & OPT_N) || address < end_offset) {
1089 if (i == bufsize) {
1090 bufsize += bufsize/8;
1091 buf = xrealloc(buf, bufsize);
1092 }
1093
1094 while (G.in_stream) { /* !EOF */
1095 c = fgetc(G.in_stream);
1096 if (c != EOF)
1097 goto got_char;
1098 check_and_close();
1099 open_next_file();
1100 }
1101 /* EOF */
1102 goto ret;
1103 got_char:
1104 address++;
1105 if (!c)
1106 break;
1107 if (!ISPRINT(c))
1108 goto tryline; /* It isn't; give up on this string. */
1109 buf[i++] = c; /* String continues; store it all. */
1110 }
1111
1112 if (i < G.string_min) /* Too short! */
1113 goto tryline;
1114
1115 /* If we get here, the string is all printable and NUL-terminated */
1116 buf[i] = 0;
1117 G.format_address(address - i - 1, ' ');
1118
1119 for (i = 0; (c = buf[i]); i++) {
1120 switch (c) {
1121 case '\007': fputs("\\a", stdout); break;
1122 case '\b': fputs("\\b", stdout); break;
1123 case '\f': fputs("\\f", stdout); break;
1124 case '\n': fputs("\\n", stdout); break;
1125 case '\r': fputs("\\r", stdout); break;
1126 case '\t': fputs("\\t", stdout); break;
1127 case '\v': fputs("\\v", stdout); break;
1128 default: putchar(c);
1129 }
1130 }
1131 putchar('\n');
1132 }
1133
1134 /* We reach this point only if we search through
1135 (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
1136 check_and_close();
1137 ret:
1138 free(buf);
1139}
1140
1141#if ENABLE_LONG_OPTS
1142/* If S is a valid traditional offset specification with an optional
1143 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1144
1145static int
1146parse_old_offset(const char *s, off_t *offset)
1147{
1148 static const struct suffix_mult Bb[] = {
1149 { "B", 1024 },
1150 { "b", 512 },
1151 { "", 0 }
1152 };
1153 char *p;
1154 int radix;
1155
1156 /* Skip over any leading '+'. */
1157 if (s[0] == '+') ++s;
1158 if (!isdigit(s[0])) return 0; /* not a number */
1159
1160 /* Determine the radix we'll use to interpret S. If there is a '.',
1161 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1162 * it's hexadecimal, else octal. */
1163 p = strchr(s, '.');
1164 radix = 8;
1165 if (p) {
1166 p[0] = '\0'; /* cheating */
1167 radix = 10;
1168 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1169 radix = 16;
1170
1171 *offset = xstrtooff_sfx(s, radix, Bb);
1172 if (p) p[0] = '.';
1173
1174 return (*offset >= 0);
1175}
1176#endif
1177
1178int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1179int od_main(int argc UNUSED_PARAM, char **argv)
1180{
1181#if ENABLE_LONG_OPTS
1182 static const char od_longopts[] ALIGN1 =
1183 "skip-bytes\0" Required_argument "j"
1184 "address-radix\0" Required_argument "A"
1185 "read-bytes\0" Required_argument "N"
1186 "format\0" Required_argument "t"
1187 "output-duplicates\0" No_argument "v"
1188 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1189 * that is, NUM is mandatory for -S but optional for --strings!
1190 */
1191 "strings\0" Optional_argument "S"
1192 "width\0" Optional_argument "w"
1193 "traditional\0" No_argument "\xff"
1194 ;
1195#endif
1196 const char *str_A, *str_N, *str_j, *str_S = "3";
1197 llist_t *lst_t = NULL;
1198 unsigned opt;
1199 int l_c_m;
1200 /* The number of input bytes to skip before formatting and writing. */
1201 off_t n_bytes_to_skip = 0;
1202 /* The offset of the first byte after the last byte to be formatted. */
1203 off_t end_offset = 0;
1204 /* The maximum number of bytes that will be formatted. */
1205 off_t max_bytes_to_format = 0;
1206
1207 INIT_G();
1208
1209 /*G.spec = NULL; - already is */
1210 G.format_address = format_address_std;
1211 address_base_char = 'o';
1212 address_pad_len_char = '7';
1213
1214 /* Parse command line */
1215 opt_complementary = "w+:t::"; /* -w N, -t is a list */
1216#if ENABLE_LONG_OPTS
1217 applet_long_options = od_longopts;
1218#endif
1219 opt = OD_GETOPT32();
1220 argv += optind;
1221 if (opt & OPT_A) {
1222 static const char doxn[] ALIGN1 = "doxn";
1223 static const char doxn_address_base_char[] ALIGN1 = {
1224 'u', 'o', 'x', /* '?' fourth one is not important */
1225 };
1226 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
1227 '7', '7', '6', /* '?' */
1228 };
1229 char *p;
1230 int pos;
1231 p = strchr(doxn, str_A[0]);
1232 if (!p)
1233 bb_error_msg_and_die("bad output address radix "
1234 "'%c' (must be [doxn])", str_A[0]);
1235 pos = p - doxn;
1236 if (pos == 3) G.format_address = format_address_none;
1237 address_base_char = doxn_address_base_char[pos];
1238 address_pad_len_char = doxn_address_pad_len_char[pos];
1239 }
1240 if (opt & OPT_N) {
1241 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
1242 }
1243 if (opt & OPT_a) decode_format_string("a");
1244 if (opt & OPT_b) decode_format_string("oC");
1245 if (opt & OPT_c) decode_format_string("c");
1246 if (opt & OPT_d) decode_format_string("u2");
1247 if (opt & OPT_f) decode_format_string("fF");
1248 if (opt & OPT_h) decode_format_string("x2");
1249 if (opt & OPT_i) decode_format_string("d2");
1250 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
1251 if (opt & OPT_l) decode_format_string("d4");
1252 if (opt & OPT_o) decode_format_string("o2");
1253 while (lst_t) {
1254 decode_format_string(llist_pop(&lst_t));
1255 }
1256 if (opt & OPT_x) decode_format_string("x2");
1257 if (opt & OPT_s) decode_format_string("d2");
1258 if (opt & OPT_S) {
1259 G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
1260 }
1261
1262 // Bloat:
1263 //if ((option_mask32 & OPT_S) && G.n_specs > 0)
1264 // bb_error_msg_and_die("no type may be specified when dumping strings");
1265
1266 /* If the --traditional option is used, there may be from
1267 * 0 to 3 remaining command line arguments; handle each case
1268 * separately.
1269 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
1270 * The offset and pseudo_start have the same syntax.
1271 *
1272 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
1273 * traditional syntax even if --traditional is not given. */
1274
1275#if ENABLE_LONG_OPTS
1276 if (opt & OPT_traditional) {
1277 if (argv[0]) {
1278 off_t pseudo_start = -1;
1279 off_t o1, o2;
1280
1281 if (!argv[1]) { /* one arg */
1282 if (parse_old_offset(argv[0], &o1)) {
1283 /* od --traditional OFFSET */
1284 n_bytes_to_skip = o1;
1285 argv++;
1286 }
1287 /* od --traditional FILE */
1288 } else if (!argv[2]) { /* two args */
1289 if (parse_old_offset(argv[0], &o1)
1290 && parse_old_offset(argv[1], &o2)
1291 ) {
1292 /* od --traditional OFFSET LABEL */
1293 n_bytes_to_skip = o1;
1294 pseudo_start = o2;
1295 argv += 2;
1296 } else if (parse_old_offset(argv[1], &o2)) {
1297 /* od --traditional FILE OFFSET */
1298 n_bytes_to_skip = o2;
1299 argv[1] = NULL;
1300 } else {
1301 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1302 }
1303 } else if (!argv[3]) { /* three args */
1304 if (parse_old_offset(argv[1], &o1)
1305 && parse_old_offset(argv[2], &o2)
1306 ) {
1307 /* od --traditional FILE OFFSET LABEL */
1308 n_bytes_to_skip = o1;
1309 pseudo_start = o2;
1310 argv[1] = NULL;
1311 } else {
1312 bb_error_msg_and_die("the last two arguments must be offsets");
1313 }
1314 } else { /* >3 args */
1315 bb_error_msg_and_die("too many arguments");
1316 }
1317
1318 if (pseudo_start >= 0) {
1319 if (G.format_address == format_address_none) {
1320 address_base_char = 'o';
1321 address_pad_len_char = '7';
1322 G.format_address = format_address_paren;
1323 } else {
1324 G.format_address = format_address_label;
1325 }
1326 G_pseudo_offset = pseudo_start - n_bytes_to_skip;
1327 }
1328 }
1329 /* else: od --traditional (without args) */
1330 }
1331#endif
1332
1333 if (option_mask32 & OPT_N) {
1334 end_offset = n_bytes_to_skip + max_bytes_to_format;
1335 if (end_offset < n_bytes_to_skip)
1336 bb_error_msg_and_die("SKIP + SIZE is too large");
1337 }
1338
1339 if (G.n_specs == 0) {
1340 decode_format_string("o2");
1341 /*G.n_specs = 1; - done by decode_format_string */
1342 }
1343
1344 /* If no files were listed on the command line,
1345 set the global pointer FILE_LIST so that it
1346 references the null-terminated list of one name: "-". */
1347 G.file_list = bb_argv_dash;
1348 if (argv[0]) {
1349 /* Set the global pointer FILE_LIST so that it
1350 references the first file-argument on the command-line. */
1351 G.file_list = (char const *const *) argv;
1352 }
1353
1354 /* Open the first input file */
1355 open_next_file();
1356 /* Skip over any unwanted header bytes */
1357 skip(n_bytes_to_skip);
1358 if (!G.in_stream)
1359 return EXIT_FAILURE;
1360
1361 /* Compute output block length */
1362 l_c_m = get_lcm();
1363
1364 if (opt & OPT_w) { /* -w: width */
1365 if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
1366 bb_error_msg("warning: invalid width %u; using %d instead",
1367 (unsigned)G.bytes_per_block, l_c_m);
1368 G.bytes_per_block = l_c_m;
1369 }
1370 } else {
1371 G.bytes_per_block = l_c_m;
1372 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
1373 G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
1374 }
1375
1376#ifdef DEBUG
1377 for (i = 0; i < G.n_specs; i++) {
1378 printf("%d: fmt=\"%s\" width=%d\n",
1379 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1380 }
1381#endif
1382
1383 if (option_mask32 & OPT_S)
1384 dump_strings(n_bytes_to_skip, end_offset);
1385 else
1386 dump(n_bytes_to_skip, end_offset);
1387
1388 if (fclose(stdin))
1389 bb_perror_msg_and_die(bb_msg_standard_input);
1390
1391 return G.exit_code;
1392}
Note: See TracBrowser for help on using the repository browser.