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