*: add most of the required setup_common_bufsiz() calls
[oweals/busybox.git] / coreutils / od_bloaty.c
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
39 enum {
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
76 typedef long double longdouble_t;
77 typedef unsigned long long ulonglong_t;
78 typedef 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
104 enum 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
117 enum 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.  */
129 struct 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
148 static 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
151 static 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
154 static 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
157 static 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.  */
161 static 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.  */
174 struct 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
178 struct 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
216 enum { 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)
227 static 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)
244 static 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
252 static unsigned
253 gcd(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.  */
265 static unsigned
266 lcm(unsigned u, unsigned v) {
267         unsigned t = gcd(u, v);
268         if (t == 0)
269                 return 0;
270         return u * v / t;
271 }
272
273 static void
274 print_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
283 static void
284 print_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
293 static void
294 print_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
304 static void
305 print_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
315 static void
316 print_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
329 static void
330 print_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
344 static void
345 print_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
356 static void
357 print_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
367 static void
368 print_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
378 static void
379 print_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
393 static void
394 print_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
433 static void
434 print_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
491 static void
492 open_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
515 static void
516 check_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
549 static NOINLINE const char *
550 decode_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
750 static void
751 decode_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
776 static void
777 skip(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
839 typedef void FN_format_address(off_t address, char c);
840
841 static void
842 format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
843 {
844 }
845
846 static 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
852 static void
853 format_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 */
862 static void
863 format_address_paren(off_t address, char c)
864 {
865         putchar('(');
866         format_address_std(address, ')');
867         if (c) putchar(c);
868 }
869
870 static void
871 format_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
878 static void
879 dump_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
901 static void
902 write_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
941 static void
942 read_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
969 static int
970 get_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
990 static void
991 dump(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
1073 static void
1074 dump_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
1145 static int
1146 parse_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
1178 int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1179 int 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 }