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