blob: ab7ea997d565a73e33bec9b22df5cb19d13a31ef [file] [log] [blame]
Denis Vlasenko1114de72006-10-10 23:26:05 +00001/* 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,
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020016 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
Denis Vlasenko1114de72006-10-10 23:26:05 +000018/* Written by Jim Meyering. */
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020019/* Busyboxed by Denys Vlasenko, based on od.c from coreutils-5.2.1 */
Denis Vlasenko1114de72006-10-10 23:26:05 +000020
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020021
22/* #include "libbb.h" - done in od.c */
23#define assert(a) ((void)0)
24
25
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020026//usage:#if ENABLE_DESKTOP
27//usage:#define od_trivial_usage
Denys Vlasenkoe3e0d2b2012-06-19 12:46:59 +020028//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..."
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020029// We don't support:
30// ... [FILE] [[+]OFFSET[.][b]]
31// Support is buggy for:
32// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]
Denis Vlasenko601ae132006-11-28 23:37:46 +000033
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020034//usage:#define od_full_usage "\n\n"
35//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default"
36//usage:#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +000037
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020038enum {
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};
Denis Vlasenko1114de72006-10-10 23:26:05 +000062
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020063#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
Denis Vlasenko601ae132006-11-28 23:37:46 +000071
72/* Check for 0x7f is a coreutils 6.3 addition */
Denys Vlasenko9d96e272011-05-21 18:38:59 +020073#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f)
Denis Vlasenko1114de72006-10-10 23:26:05 +000074
75typedef long double longdouble_t;
76typedef unsigned long long ulonglong_t;
Denis Vlasenko601ae132006-11-28 23:37:46 +000077typedef long long llong;
78
79#if ENABLE_LFS
80# define xstrtooff_sfx xstrtoull_sfx
81#else
82# define xstrtooff_sfx xstrtoul_sfx
83#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +000084
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
103enum size_spec {
104 NO_SIZE,
105 CHAR,
106 SHORT,
107 INT,
108 LONG,
109 LONG_LONG,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000110 FLOAT_SINGLE,
111 FLOAT_DOUBLE,
112 FLOAT_LONG_DOUBLE,
113 N_SIZE_SPECS
114};
115
116enum 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. */
128struct 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
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000147static const uint8_t bytes_to_oct_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000148{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
149
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000150static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000151{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
152
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000153static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000154{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
155
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000156static const uint8_t bytes_to_hex_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000157{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. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000160static const signed char width_bytes[] ALIGN1 = {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000161 -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};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000171/* Ensure that for each member of 'enum size_spec' there is an
172 initializer in the width_bytes array. */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000173struct ERR_width_bytes_has_bad_size {
174 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000175};
176
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200177static smallint exit_code;
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000178
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200179static unsigned string_min;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000180
181/* An array of specs describing how to format each input block. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000182static size_t n_specs;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000183static struct tspec *spec;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000184
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000185/* Function that accepts an address and an optional following char,
186 and prints the address and char to stdout. */
187static void (*format_address)(off_t, char);
188/* The difference between the old-style pseudo starting address and
189 the number of bytes to skip. */
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200190#if ENABLE_LONG_OPTS
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000191static off_t pseudo_offset;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200192#else
193enum { pseudo_offset = 0 };
194#endif
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000195/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
196 input is formatted. */
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000197
Denis Vlasenko1114de72006-10-10 23:26:05 +0000198/* 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. */
Denis Vlasenko1d426652008-03-17 09:09:09 +0000202static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000203
Denis Vlasenko1114de72006-10-10 23:26:05 +0000204/* A NULL-terminated list of the file-arguments from the command line. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000205static const char *const *file_list;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000206
207/* The input stream associated with the current file. */
208static FILE *in_stream;
209
Denis Vlasenko1114de72006-10-10 23:26:05 +0000210#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000211static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000212 [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};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000226
227#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000228static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200229 /* gcc seems to allow repeated indexes. Last one wins */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000230 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
231 [sizeof(double)] = FLOAT_DOUBLE,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000232 [sizeof(float)] = FLOAT_SINGLE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000233};
234
235
236static unsigned
237gcd(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. */
249static unsigned
250lcm(unsigned u, unsigned v) {
251 unsigned t = gcd(u, v);
252 if (t == 0)
253 return 0;
254 return u * v / t;
255}
256
257static void
258print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
259{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000260 while (n_bytes--) {
261 int tmp = *(signed char *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000262 printf(fmt_string, tmp);
263 block += sizeof(unsigned char);
264 }
265}
266
267static void
268print_char(size_t n_bytes, const char *block, const char *fmt_string)
269{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000270 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000271 unsigned tmp = *(unsigned char *) block;
272 printf(fmt_string, tmp);
273 block += sizeof(unsigned char);
274 }
275}
276
277static void
278print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
279{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000280 n_bytes /= sizeof(signed short);
281 while (n_bytes--) {
282 int tmp = *(signed short *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000283 printf(fmt_string, tmp);
284 block += sizeof(unsigned short);
285 }
286}
287
288static void
289print_short(size_t n_bytes, const char *block, const char *fmt_string)
290{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000291 n_bytes /= sizeof(unsigned short);
292 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000293 unsigned tmp = *(unsigned short *) block;
294 printf(fmt_string, tmp);
295 block += sizeof(unsigned short);
296 }
297}
298
299static void
300print_int(size_t n_bytes, const char *block, const char *fmt_string)
301{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000302 n_bytes /= sizeof(unsigned);
303 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000304 unsigned tmp = *(unsigned *) block;
305 printf(fmt_string, tmp);
306 block += sizeof(unsigned);
307 }
308}
309
Denis Vlasenko601ae132006-11-28 23:37:46 +0000310#if UINT_MAX == ULONG_MAX
311# define print_long print_int
312#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000313static void
314print_long(size_t n_bytes, const char *block, const char *fmt_string)
315{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000316 n_bytes /= sizeof(unsigned long);
317 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000318 unsigned long tmp = *(unsigned long *) block;
319 printf(fmt_string, tmp);
320 block += sizeof(unsigned long);
321 }
322}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000323#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000324
Denis Vlasenko601ae132006-11-28 23:37:46 +0000325#if ULONG_MAX == ULLONG_MAX
326# define print_long_long print_long
327#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000328static void
329print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
330{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000331 n_bytes /= sizeof(ulonglong_t);
332 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000333 ulonglong_t tmp = *(ulonglong_t *) block;
334 printf(fmt_string, tmp);
335 block += sizeof(ulonglong_t);
336 }
337}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000338#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000339
340static void
341print_float(size_t n_bytes, const char *block, const char *fmt_string)
342{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000343 n_bytes /= sizeof(float);
344 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000345 float tmp = *(float *) block;
346 printf(fmt_string, tmp);
347 block += sizeof(float);
348 }
349}
350
351static void
352print_double(size_t n_bytes, const char *block, const char *fmt_string)
353{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000354 n_bytes /= sizeof(double);
355 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000356 double tmp = *(double *) block;
357 printf(fmt_string, tmp);
358 block += sizeof(double);
359 }
360}
361
362static void
363print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
364{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000365 n_bytes /= sizeof(longdouble_t);
366 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000367 longdouble_t tmp = *(longdouble_t *) block;
368 printf(fmt_string, tmp);
369 block += sizeof(longdouble_t);
370 }
371}
372
Denis Vlasenko601ae132006-11-28 23:37:46 +0000373/* print_[named]_ascii are optimized for speed.
Bernhard Reutner-Fischera985d302008-02-11 11:44:38 +0000374 * Remember, someday you may want to pump gigabytes through this thing.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000375 * Saving a dozen of .text bytes here is counter-productive */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000376
377static void
378print_named_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000379 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000380{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000381 /* Names for some non-printing characters. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000382 static const char charname[33][3] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000383 "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
Ron Yorston53e9c512015-03-12 20:10:40 +0100390 char buf[12] = " x\0 xxx\0";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000391 // [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.
Ron Yorston53e9c512015-03-12 20:10:40 +0100394 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410
Denis Vlasenko1114de72006-10-10 23:26:05 +0000395
Denis Vlasenko601ae132006-11-28 23:37:46 +0000396 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;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000403 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000404 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);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000414 }
415}
416
417static void
418print_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000419 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000420{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000421 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100422 char buf[12] = " x\0 xxx\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000423
Denis Vlasenko601ae132006-11-28 23:37:46 +0000424 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 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000433 switch (c) {
434 case '\0':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000435 s = " \\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000436 break;
437 case '\007':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000438 s = " \\a";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000439 break;
440 case '\b':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000441 s = " \\b";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000442 break;
443 case '\f':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000444 s = " \\f";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000445 break;
446 case '\n':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000447 s = " \\n";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000448 break;
449 case '\r':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000450 s = " \\r";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000451 break;
452 case '\t':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000453 s = " \\t";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000454 break;
455 case '\v':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000456 s = " \\v";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000457 break;
Ron Yorston53e9c512015-03-12 20:10:40 +0100458 default:
459 buf[6] = (c >> 6 & 3) + '0';
460 buf[7] = (c >> 3 & 7) + '0';
Denis Vlasenko601ae132006-11-28 23:37:46 +0000461 buf[8] = (c & 7) + '0';
462 s = buf + 5;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000463 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000464 fputs(s, stdout);
465 }
466}
Denis Vlasenko1114de72006-10-10 23:26:05 +0000467
Denis Vlasenko601ae132006-11-28 23:37:46 +0000468/* 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
475static void
476open_next_file(void)
477{
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000478 while (1) {
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000479 if (!*file_list)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000480 return;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000481 in_stream = fopen_or_warn_stdin(*file_list++);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000482 if (in_stream) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000483 break;
484 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200485 exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000486 }
487
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200488 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000489 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
499static void
500check_and_close(void)
501{
502 if (in_stream) {
503 if (ferror(in_stream)) {
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000504 bb_error_msg("%s: read error", (in_stream == stdin)
505 ? bb_msg_standard_input
506 : file_list[-1]
507 );
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200508 exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000509 }
510 fclose_if_not_stdin(in_stream);
511 in_stream = NULL;
512 }
513
514 if (ferror(stdout)) {
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200515 bb_error_msg_and_die(bb_msg_write_error);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000516 }
517}
518
519/* If S points to a single valid modern od format string, put
Denis Vlasenko7089c312008-04-14 19:50:06 +0000520 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
Denis Vlasenko1114de72006-10-10 23:26:05 +0000524 {
525 fmt = SIGNED_DECIMAL;
526 size = INT or LONG; (whichever integral_type_size[4] resolves to)
527 print_function = print_int; (assuming size == INT)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000528 fmt_string = "%011d%c";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000529 }
530 S_ORIG is solely for reporting errors. It should be the full format
Denis Vlasenko601ae132006-11-28 23:37:46 +0000531 string argument. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000532
Denys Vlasenkob9542cb2010-06-01 23:16:46 +0200533static NOINLINE const char *
Denis Vlasenko7089c312008-04-14 19:50:06 +0000534decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000535{
536 enum size_spec size_spec;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000537 unsigned size;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000538 enum output_format fmt;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000539 const char *p;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000540 char *end;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000541 char *fmt_string = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000542 void (*print_function) (size_t, const char *, const char *);
543 unsigned c;
544 unsigned field_width = 0;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000545 int pos;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000546
Denis Vlasenko1114de72006-10-10 23:26:05 +0000547 switch (*s) {
548 case 'd':
549 case 'o':
550 case 'u':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000551 case 'x': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000552 static const char CSIL[] ALIGN1 = "CSIL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000553
554 c = *s++;
555 p = strchr(CSIL, *s);
Denys Vlasenko11f3a8b2009-11-22 15:37:16 +0100556 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
557 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000558 size = sizeof(int);
559 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000560 size = bb_strtou(s, &end, 0);
561 if (errno == ERANGE
562 || MAX_INTEGRAL_TYPE_SIZE < size
Denis Vlasenko1114de72006-10-10 23:26:05 +0000563 || integral_type_size[size] == NO_SIZE
564 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000565 bb_error_msg_and_die("invalid type string '%s'; "
566 "%u-byte %s type is not supported",
567 s_orig, size, "integral");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000568 }
569 s = end;
570 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000571 } else {
Denis Vlasenko7089c312008-04-14 19:50:06 +0000572 static const uint8_t CSIL_sizeof[4] = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000573 sizeof(char),
574 sizeof(short),
575 sizeof(int),
576 sizeof(long),
577 };
578 size = CSIL_sizeof[p - CSIL];
Denis Vlasenko7089c312008-04-14 19:50:06 +0000579 s++; /* skip C/S/I/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000580 }
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
Denis Vlasenko1114de72006-10-10 23:26:05 +0000587 size_spec = integral_type_size[size];
588
Denis Vlasenko601ae132006-11-28 23:37:46 +0000589 {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000590 static const char doux[] ALIGN1 = "doux";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000591 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 };
Denis Vlasenko1114de72006-10-10 23:26:05 +0000612
Denis Vlasenko601ae132006-11-28 23:37:46 +0000613 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 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000621
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;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000639 default: /* case LONG_LONG: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000640 print_function = print_long_long;
641 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000642 }
643 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000644 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000645
Denis Vlasenko601ae132006-11-28 23:37:46 +0000646 case 'f': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000647 static const char FDL[] ALIGN1 = "FDL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000648
Denis Vlasenko1114de72006-10-10 23:26:05 +0000649 fmt = FLOATING_POINT;
650 ++s;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000651 p = strchr(FDL, *s);
652 if (!p) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000653 size = sizeof(double);
654 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000655 size = bb_strtou(s, &end, 0);
656 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000657 || fp_type_size[size] == NO_SIZE
658 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000659 bb_error_msg_and_die("invalid type string '%s'; "
660 "%u-byte %s type is not supported",
661 s_orig, size, "floating point");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000662 }
663 s = end;
664 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000665 } 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];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000673 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000674
Denis Vlasenko1114de72006-10-10 23:26:05 +0000675 size_spec = fp_type_size[size];
676
677 switch (size_spec) {
678 case FLOAT_SINGLE:
679 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000680 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000681 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000682 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000683 break;
684 case FLOAT_DOUBLE:
685 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000686 field_width = DBL_DIG + 8;
687 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000688 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000689 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000690 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000691 field_width = LDBL_DIG + 8;
692 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000693 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000694 }
695 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000696 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000697
698 case 'a':
699 ++s;
700 fmt = NAMED_CHARACTER;
701 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000702 print_function = print_named_ascii;
703 field_width = 3;
704 break;
705 case 'c':
706 ++s;
707 fmt = CHARACTER;
708 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000709 print_function = print_ascii;
710 field_width = 3;
711 break;
712 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000713 bb_error_msg_and_die("invalid character '%c' "
714 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000715 }
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
Denis Vlasenko7089c312008-04-14 19:50:06 +0000727 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000728}
729
730/* Decode the modern od format string S. Append the decoded
731 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000732 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000733
Denis Vlasenko601ae132006-11-28 23:37:46 +0000734static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000735decode_format_string(const char *s)
736{
737 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000738
739 while (*s != '\0') {
740 struct tspec tspec;
741 const char *next;
742
Denis Vlasenko7089c312008-04-14 19:50:06 +0000743 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000744
745 assert(s != next);
746 s = next;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000747 spec = xrealloc_vector(spec, 4, n_specs);
748 memcpy(&spec[n_specs], &tspec, sizeof(spec[0]));
Denis Vlasenko1114de72006-10-10 23:26:05 +0000749 n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000750 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000751}
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
Denis Vlasenko601ae132006-11-28 23:37:46 +0000760static void
761skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000762{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000763 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000764 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000765
Denis Vlasenko601ae132006-11-28 23:37:46 +0000766 while (in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000767 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
Denis Vlasenko1114de72006-10-10 23:26:05 +0000779 /* 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. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000784 if (fstat(fileno(in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000785 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000786 ) {
787 if (file_stats.st_size < n_skip) {
788 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000789 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000790 } else {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000791 if (fseeko(in_stream, n_skip, SEEK_CUR) != 0)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200792 exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000793 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000794 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000795 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000796 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000797 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000798 char buf[1024];
799 size_t n_bytes_to_read = 1024;
800 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000801
Denis Vlasenko601ae132006-11-28 23:37:46 +0000802 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)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000808 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000809 }
810 }
811 if (n_skip == 0)
812 return;
813
814 check_and_close();
815 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000816 }
817
Denis Vlasenko601ae132006-11-28 23:37:46 +0000818 if (n_skip)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100819 bb_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000820}
821
Denis Vlasenko601ae132006-11-28 23:37:46 +0000822
823typedef void FN_format_address(off_t address, char c);
824
Denis Vlasenko1114de72006-10-10 23:26:05 +0000825static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000826format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000827{
828}
829
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000830static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000831/* Corresponds to 'x' above */
832#define address_base_char address_fmt[sizeof(address_fmt)-3]
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000833/* Corresponds to 'n' above */
834#define address_pad_len_char address_fmt[2]
Denis Vlasenko601ae132006-11-28 23:37:46 +0000835
Denis Vlasenko1114de72006-10-10 23:26:05 +0000836static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000837format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000838{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000839 /* Corresponds to 'c' */
840 address_fmt[sizeof(address_fmt)-2] = c;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000841 printf(address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000842}
843
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200844#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000845/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000846static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000847format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000848{
849 putchar('(');
850 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000851 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000852}
853
854static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000855format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000856{
857 format_address_std(address, ' ');
858 format_address_paren(address + pseudo_offset, c);
859}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000860#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000861
862static void
863dump_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
Denis Vlasenko1114de72006-10-10 23:26:05 +0000874/* 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
885static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000886write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000887 const char *prev_block, const char *curr_block)
888{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000889 static char first = 1;
890 static char prev_pair_equal = 0;
891 size_t i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000892
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200893 if (!(option_mask32 & OPT_v)
894 && !first
Denis Vlasenko1114de72006-10-10 23:26:05 +0000895 && 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 {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000906 first = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000907 prev_pair_equal = 0;
908 for (i = 0; i < n_specs; i++) {
909 if (i == 0)
910 format_address(current_offset, '\0');
911 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000912 printf("%*s", address_pad_len_char - '0', "");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000913 (*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 */
Denys Vlasenkob8086142011-05-21 19:15:55 +0200916 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;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000919 printf("%*s", blank_fields * field_width, "");
920 dump_hexl_mode_trailer(n_bytes, curr_block);
921 }
922 putchar('\n');
923 }
924 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000925}
926
Denis Vlasenko601ae132006-11-28 23:37:46 +0000927static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000928read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
929{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000930 assert(0 < n && n <= bytes_per_block);
931
932 *n_bytes_in_buffer = 0;
933
934 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000935 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000936
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;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000946 /* error check is done in check_and_close */
947 check_and_close();
948 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000949 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000950}
951
952/* Return the least common multiple of the sizes associated
953 with the format specs. */
954
955static int
956get_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
Denis Vlasenko1114de72006-10-10 23:26:05 +0000966/* 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
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000974 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000975
Denis Vlasenko601ae132006-11-28 23:37:46 +0000976static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000977dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000978{
979 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000980 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000981 size_t n_bytes_read;
982
Denys Vlasenkob8086142011-05-21 19:15:55 +0200983 block[0] = xmalloc(2 * bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000984 block[1] = block[0] + bytes_per_block;
985
Denis Vlasenko1114de72006-10-10 23:26:05 +0000986 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200987 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000988 while (1) {
989 size_t n_needed;
990 if (current_offset >= end_offset) {
991 n_bytes_read = 0;
992 break;
993 }
Denys Vlasenkob8086142011-05-21 19:15:55 +0200994 n_needed = MIN(end_offset - current_offset, (off_t) bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000995 read_block(n_needed, block[idx], &n_bytes_read);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000996 if (n_bytes_read < bytes_per_block)
997 break;
998 assert(n_bytes_read == bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +0200999 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001000 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001001 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001002 }
1003 } else {
1004 while (1) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001005 read_block(bytes_per_block, block[idx], &n_bytes_read);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001006 if (n_bytes_read < bytes_per_block)
1007 break;
1008 assert(n_bytes_read == bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001009 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001010 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001011 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001012 }
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
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001022 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001023 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,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001027 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001028 current_offset += n_bytes_read;
1029 }
1030
1031 format_address(current_offset, '\n');
1032
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001033 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001034 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001035
1036 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001037}
1038
Denis Vlasenko601ae132006-11-28 23:37:46 +00001039/* 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
Denis Vlasenko1114de72006-10-10 23:26:05 +00001053/* 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
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001057 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001058
Denis Vlasenko601ae132006-11-28 23:37:46 +00001059static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001060dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001061{
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001062 unsigned bufsize = MAX(100, string_min);
1063 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001064
Denis Vlasenko1114de72006-10-10 23:26:05 +00001065 while (1) {
1066 size_t i;
1067 int c;
1068
1069 /* See if the next 'string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001070 tryline:
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001071 if ((option_mask32 & OPT_N) && (end_offset - string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001072 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001073 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001074 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001075 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001076 bufsize += bufsize/8;
1077 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001078 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001079
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();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001086 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001087 /* EOF */
1088 goto ret;
1089 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001090 address++;
1091 if (!c)
1092 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001093 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
Denis Vlasenko601ae132006-11-28 23:37:46 +00001098 if (i < string_min) /* Too short! */
1099 goto tryline;
1100
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001101 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001102 buf[i] = 0;
1103 format_address(address - i - 1, ' ');
1104
1105 for (i = 0; (c = buf[i]); i++) {
1106 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001107 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;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001114 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001115 }
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. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001122 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001123 ret:
1124 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001125}
1126
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001127#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
1131static int
1132parse_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
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001164int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001165int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001166{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001167#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001168 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001169 "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"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001174 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1175 * that is, NUM is mandatory for -S but optional for --strings!
1176 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001177 "strings\0" Optional_argument "S"
1178 "width\0" Optional_argument "w"
1179 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001180 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001181#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001182 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001183 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001184 unsigned opt;
1185 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001186 /* 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;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001192
1193 spec = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001194 format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001195 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001196 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001197
Denis Vlasenko601ae132006-11-28 23:37:46 +00001198 /* Parse command line */
Denis Vlasenko1d426652008-03-17 09:09:09 +00001199 opt_complementary = "w+:t::"; /* -w N, -t is a list */
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001200#if ENABLE_LONG_OPTS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001201 applet_long_options = od_longopts;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001202#endif
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001203 opt = OD_GETOPT32();
Denis Vlasenko601ae132006-11-28 23:37:46 +00001204 argv += optind;
1205 if (opt & OPT_A) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001206 static const char doxn[] ALIGN1 = "doxn";
1207 static const char doxn_address_base_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001208 'u', 'o', 'x', /* '?' fourth one is not important */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001209 };
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001210 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001211 '7', '7', '6', /* '?' */
1212 };
Denis Vlasenko601ae132006-11-28 23:37:46 +00001213 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;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001220 if (pos == 3) format_address = format_address_none;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001221 address_base_char = doxn_address_base_char[pos];
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001222 address_pad_len_char = doxn_address_pad_len_char[pos];
Denis Vlasenko1114de72006-10-10 23:26:05 +00001223 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001224 if (opt & OPT_N) {
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001225 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001226 }
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");
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001234 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001235 if (opt & OPT_l) decode_format_string("d4");
1236 if (opt & OPT_o) decode_format_string("o2");
Denis Vlasenko601ae132006-11-28 23:37:46 +00001237 while (lst_t) {
Denis Vlasenkod50dda82008-06-15 05:40:56 +00001238 decode_format_string(llist_pop(&lst_t));
Denis Vlasenko601ae132006-11-28 23:37:46 +00001239 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001240 if (opt & OPT_x) decode_format_string("x2");
1241 if (opt & OPT_s) decode_format_string("d2");
1242 if (opt & OPT_S) {
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001243 string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001244 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001245
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001246 // Bloat:
1247 //if ((option_mask32 & OPT_S) && n_specs > 0)
1248 // bb_error_msg_and_die("no type may be specified when dumping strings");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001249
Denis Vlasenko1114de72006-10-10 23:26:05 +00001250 /* If the --traditional option is used, there may be from
Denis Vlasenko601ae132006-11-28 23:37:46 +00001251 * 0 to 3 remaining command line arguments; handle each case
1252 * separately.
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001253 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
Denis Vlasenko601ae132006-11-28 23:37:46 +00001254 * 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. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001258
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001259#if ENABLE_LONG_OPTS
Denis Vlasenko601ae132006-11-28 23:37:46 +00001260 if (opt & OPT_traditional) {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001261 if (argv[0]) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001262 off_t pseudo_start = -1;
1263 off_t o1, o2;
1264
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001265 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;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001278 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;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001293 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");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001300 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001301
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 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001312 }
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001313 /* else: od --traditional (without args) */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001314 }
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001315#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +00001316
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001317 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001318 end_offset = n_bytes_to_skip + max_bytes_to_format;
1319 if (end_offset < n_bytes_to_skip)
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001320 bb_error_msg_and_die("SKIP + SIZE is too large");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001321 }
1322
1323 if (n_specs == 0) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001324 decode_format_string("o2");
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001325 /*n_specs = 1; - done by decode_format_string */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001326 }
1327
Denis Vlasenko601ae132006-11-28 23:37:46 +00001328 /* 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: "-". */
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001331 file_list = bb_argv_dash;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001332 if (argv[0]) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001333 /* Set the global pointer FILE_LIST so that it
1334 references the first file-argument on the command-line. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001335 file_list = (char const *const *) argv;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001336 }
1337
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001338 /* Open the first input file */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001339 open_next_file();
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001340 /* Skip over any unwanted header bytes */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001341 skip(n_bytes_to_skip);
1342 if (!in_stream)
Bernhard Reutner-Fischer7c2db5c2007-11-16 12:39:16 +00001343 return EXIT_FAILURE;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001344
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001345 /* Compute output block length */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001346 l_c_m = get_lcm();
1347
Denis Vlasenko601ae132006-11-28 23:37:46 +00001348 if (opt & OPT_w) { /* -w: width */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001349 if (!bytes_per_block || bytes_per_block % l_c_m != 0) {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001350 bb_error_msg("warning: invalid width %u; using %d instead",
1351 (unsigned)bytes_per_block, l_c_m);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001352 bytes_per_block = l_c_m;
1353 }
1354 } else {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001355 bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001356 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001357 bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001358 }
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
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001367 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001368 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001369 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001370 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001371
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001372 if (fclose(stdin))
Denis Vlasenko601ae132006-11-28 23:37:46 +00001373 bb_perror_msg_and_die(bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001374
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001375 return exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001376}