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