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