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