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