blob: f47f84b545afaf0c9d742769cc9ea1f0ec44c459 [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 */ \
Denys Vlasenkof3d58a22015-10-19 02:51:56 +020069 &str_A, &str_N, &str_j, &lst_t, &str_S, &G.bytes_per_block)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020070
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 Vlasenkof3d58a22015-10-19 02:51:56 +0200177struct globals {
178 smallint exit_code;
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000179
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200180 unsigned string_min;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000181
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200182 /* An array of specs describing how to format each input block. */
183 unsigned n_specs;
184 struct tspec *spec;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000185
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200186 /* Function that accepts an address and an optional following char,
187 and prints the address and char to stdout. */
188 void (*format_address)(off_t, char);
189
190 /* The difference between the old-style pseudo starting address and
191 the number of bytes to skip. */
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200192#if ENABLE_LONG_OPTS
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200193 off_t pseudo_offset;
194# define G_pseudo_offset G.pseudo_offset
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200195#endif
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200196 /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
197 input is formatted. */
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000198
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200199 /* The number of input bytes formatted per output line. It must be
200 a multiple of the least common multiple of the sizes associated with
201 the specified output types. It should be as large as possible, but
202 no larger than 16 -- unless specified with the -w option. */
203 unsigned bytes_per_block; /* have to use unsigned, not size_t */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000204
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200205 /* A NULL-terminated list of the file-arguments from the command line. */
206 const char *const *file_list;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000207
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200208 /* The input stream associated with the current file. */
209 FILE *in_stream;
210
211 bool not_first;
212 bool prev_pair_equal;
213} FIX_ALIASING;
214#if !ENABLE_LONG_OPTS
215enum { G_pseudo_offset = 0 };
216#endif
217#define G (*(struct globals*)&bb_common_bufsiz1)
218#define INIT_G() do { \
219 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
220 G.bytes_per_block = 32; \
221} while (0)
222
Denis Vlasenko1114de72006-10-10 23:26:05 +0000223
Denis Vlasenko1114de72006-10-10 23:26:05 +0000224#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000225static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000226 [sizeof(char)] = CHAR,
227#if USHRT_MAX != UCHAR_MAX
228 [sizeof(short)] = SHORT,
229#endif
230#if UINT_MAX != USHRT_MAX
231 [sizeof(int)] = INT,
232#endif
233#if ULONG_MAX != UINT_MAX
234 [sizeof(long)] = LONG,
235#endif
236#if ULLONG_MAX != ULONG_MAX
237 [sizeof(ulonglong_t)] = LONG_LONG,
238#endif
239};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000240
241#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000242static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200243 /* gcc seems to allow repeated indexes. Last one wins */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000244 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
245 [sizeof(double)] = FLOAT_DOUBLE,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000246 [sizeof(float)] = FLOAT_SINGLE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000247};
248
249
250static unsigned
251gcd(unsigned u, unsigned v)
252{
253 unsigned t;
254 while (v != 0) {
255 t = u % v;
256 u = v;
257 v = t;
258 }
259 return u;
260}
261
262/* Compute the least common multiple of U and V. */
263static unsigned
264lcm(unsigned u, unsigned v) {
265 unsigned t = gcd(u, v);
266 if (t == 0)
267 return 0;
268 return u * v / t;
269}
270
271static void
272print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
273{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000274 while (n_bytes--) {
275 int tmp = *(signed char *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000276 printf(fmt_string, tmp);
277 block += sizeof(unsigned char);
278 }
279}
280
281static void
282print_char(size_t n_bytes, const char *block, const char *fmt_string)
283{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000284 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000285 unsigned tmp = *(unsigned char *) block;
286 printf(fmt_string, tmp);
287 block += sizeof(unsigned char);
288 }
289}
290
291static void
292print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
293{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000294 n_bytes /= sizeof(signed short);
295 while (n_bytes--) {
296 int tmp = *(signed short *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000297 printf(fmt_string, tmp);
298 block += sizeof(unsigned short);
299 }
300}
301
302static void
303print_short(size_t n_bytes, const char *block, const char *fmt_string)
304{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000305 n_bytes /= sizeof(unsigned short);
306 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000307 unsigned tmp = *(unsigned short *) block;
308 printf(fmt_string, tmp);
309 block += sizeof(unsigned short);
310 }
311}
312
313static void
314print_int(size_t n_bytes, const char *block, const char *fmt_string)
315{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000316 n_bytes /= sizeof(unsigned);
317 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000318 unsigned tmp = *(unsigned *) block;
319 printf(fmt_string, tmp);
320 block += sizeof(unsigned);
321 }
322}
323
Denis Vlasenko601ae132006-11-28 23:37:46 +0000324#if UINT_MAX == ULONG_MAX
325# define print_long print_int
326#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000327static void
328print_long(size_t n_bytes, const char *block, const char *fmt_string)
329{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000330 n_bytes /= sizeof(unsigned long);
331 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000332 unsigned long tmp = *(unsigned long *) block;
333 printf(fmt_string, tmp);
334 block += sizeof(unsigned long);
335 }
336}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000337#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000338
Denis Vlasenko601ae132006-11-28 23:37:46 +0000339#if ULONG_MAX == ULLONG_MAX
340# define print_long_long print_long
341#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000342static void
343print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
344{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000345 n_bytes /= sizeof(ulonglong_t);
346 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000347 ulonglong_t tmp = *(ulonglong_t *) block;
348 printf(fmt_string, tmp);
349 block += sizeof(ulonglong_t);
350 }
351}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000352#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000353
354static void
355print_float(size_t n_bytes, const char *block, const char *fmt_string)
356{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000357 n_bytes /= sizeof(float);
358 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000359 float tmp = *(float *) block;
360 printf(fmt_string, tmp);
361 block += sizeof(float);
362 }
363}
364
365static void
366print_double(size_t n_bytes, const char *block, const char *fmt_string)
367{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000368 n_bytes /= sizeof(double);
369 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000370 double tmp = *(double *) block;
371 printf(fmt_string, tmp);
372 block += sizeof(double);
373 }
374}
375
376static void
377print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
378{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000379 n_bytes /= sizeof(longdouble_t);
380 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000381 longdouble_t tmp = *(longdouble_t *) block;
382 printf(fmt_string, tmp);
383 block += sizeof(longdouble_t);
384 }
385}
386
Denis Vlasenko601ae132006-11-28 23:37:46 +0000387/* print_[named]_ascii are optimized for speed.
Bernhard Reutner-Fischera985d302008-02-11 11:44:38 +0000388 * Remember, someday you may want to pump gigabytes through this thing.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000389 * Saving a dozen of .text bytes here is counter-productive */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000390
391static void
392print_named_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000393 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000394{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000395 /* Names for some non-printing characters. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000396 static const char charname[33][3] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000397 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
398 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
399 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
400 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
401 " sp"
402 };
403 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100404 char buf[12] = " x\0 xxx\0";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000405 // [12] because we take three 32bit stack slots anyway, and
406 // gcc is too dumb to initialize with constant stores,
407 // it copies initializer from rodata. Oh well.
Ron Yorston53e9c512015-03-12 20:10:40 +0100408 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410
Denis Vlasenko1114de72006-10-10 23:26:05 +0000409
Denis Vlasenko601ae132006-11-28 23:37:46 +0000410 while (n_bytes--) {
411 unsigned masked_c = *(unsigned char *) block++;
412
413 masked_c &= 0x7f;
414 if (masked_c == 0x7f) {
415 fputs(" del", stdout);
416 continue;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000417 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000418 if (masked_c > ' ') {
419 buf[3] = masked_c;
420 fputs(buf, stdout);
421 continue;
422 }
423 /* Why? Because printf(" %3.3s") is much slower... */
424 buf[6] = charname[masked_c][0];
425 buf[7] = charname[masked_c][1];
426 buf[8] = charname[masked_c][2];
427 fputs(buf+5, stdout);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000428 }
429}
430
431static void
432print_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000433 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000434{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000435 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100436 char buf[12] = " x\0 xxx\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000437
Denis Vlasenko601ae132006-11-28 23:37:46 +0000438 while (n_bytes--) {
439 const char *s;
440 unsigned c = *(unsigned char *) block++;
441
442 if (ISPRINT(c)) {
443 buf[3] = c;
444 fputs(buf, stdout);
445 continue;
446 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000447 switch (c) {
448 case '\0':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000449 s = " \\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000450 break;
451 case '\007':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000452 s = " \\a";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000453 break;
454 case '\b':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000455 s = " \\b";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000456 break;
457 case '\f':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000458 s = " \\f";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000459 break;
460 case '\n':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000461 s = " \\n";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000462 break;
463 case '\r':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000464 s = " \\r";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000465 break;
466 case '\t':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000467 s = " \\t";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000468 break;
469 case '\v':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000470 s = " \\v";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000471 break;
Ron Yorston53e9c512015-03-12 20:10:40 +0100472 default:
473 buf[6] = (c >> 6 & 3) + '0';
474 buf[7] = (c >> 3 & 7) + '0';
Denis Vlasenko601ae132006-11-28 23:37:46 +0000475 buf[8] = (c & 7) + '0';
476 s = buf + 5;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000477 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000478 fputs(s, stdout);
479 }
480}
Denis Vlasenko1114de72006-10-10 23:26:05 +0000481
Denis Vlasenko601ae132006-11-28 23:37:46 +0000482/* Given a list of one or more input filenames FILE_LIST, set the global
483 file pointer IN_STREAM and the global string INPUT_FILENAME to the
484 first one that can be successfully opened. Modify FILE_LIST to
485 reference the next filename in the list. A file name of "-" is
486 interpreted as standard input. If any file open fails, give an error
487 message and return nonzero. */
488
489static void
490open_next_file(void)
491{
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000492 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200493 if (!*G.file_list)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000494 return;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200495 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
496 if (G.in_stream) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000497 break;
498 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200499 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000500 }
501
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200502 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200503 setbuf(G.in_stream, NULL);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000504}
505
506/* Test whether there have been errors on in_stream, and close it if
507 it is not standard input. Return nonzero if there has been an error
508 on in_stream or stdout; return zero otherwise. This function will
509 report more than one error only if both a read and a write error
510 have occurred. IN_ERRNO, if nonzero, is the error number
511 corresponding to the most recent action for IN_STREAM. */
512
513static void
514check_and_close(void)
515{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200516 if (G.in_stream) {
517 if (ferror(G.in_stream)) {
518 bb_error_msg("%s: read error", (G.in_stream == stdin)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000519 ? bb_msg_standard_input
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200520 : G.file_list[-1]
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000521 );
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200522 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000523 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200524 fclose_if_not_stdin(G.in_stream);
525 G.in_stream = NULL;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000526 }
527
528 if (ferror(stdout)) {
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200529 bb_error_msg_and_die(bb_msg_write_error);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000530 }
531}
532
533/* If S points to a single valid modern od format string, put
Denis Vlasenko7089c312008-04-14 19:50:06 +0000534 a description of that format in *TSPEC, return pointer to
535 character following the just-decoded format.
536 For example, if S were "d4afL", we will return a rtp to "afL"
537 and *TSPEC would be
Denis Vlasenko1114de72006-10-10 23:26:05 +0000538 {
539 fmt = SIGNED_DECIMAL;
540 size = INT or LONG; (whichever integral_type_size[4] resolves to)
541 print_function = print_int; (assuming size == INT)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000542 fmt_string = "%011d%c";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000543 }
544 S_ORIG is solely for reporting errors. It should be the full format
Denis Vlasenko601ae132006-11-28 23:37:46 +0000545 string argument. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000546
Denys Vlasenkob9542cb2010-06-01 23:16:46 +0200547static NOINLINE const char *
Denis Vlasenko7089c312008-04-14 19:50:06 +0000548decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000549{
550 enum size_spec size_spec;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000551 unsigned size;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000552 enum output_format fmt;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000553 const char *p;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000554 char *end;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000555 char *fmt_string = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000556 void (*print_function) (size_t, const char *, const char *);
557 unsigned c;
558 unsigned field_width = 0;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000559 int pos;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000560
Denis Vlasenko1114de72006-10-10 23:26:05 +0000561 switch (*s) {
562 case 'd':
563 case 'o':
564 case 'u':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000565 case 'x': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000566 static const char CSIL[] ALIGN1 = "CSIL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000567
568 c = *s++;
569 p = strchr(CSIL, *s);
Denys Vlasenko11f3a8b2009-11-22 15:37:16 +0100570 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
571 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000572 size = sizeof(int);
573 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000574 size = bb_strtou(s, &end, 0);
575 if (errno == ERANGE
576 || MAX_INTEGRAL_TYPE_SIZE < size
Denis Vlasenko1114de72006-10-10 23:26:05 +0000577 || integral_type_size[size] == NO_SIZE
578 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000579 bb_error_msg_and_die("invalid type string '%s'; "
580 "%u-byte %s type is not supported",
581 s_orig, size, "integral");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000582 }
583 s = end;
584 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000585 } else {
Denis Vlasenko7089c312008-04-14 19:50:06 +0000586 static const uint8_t CSIL_sizeof[4] = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000587 sizeof(char),
588 sizeof(short),
589 sizeof(int),
590 sizeof(long),
591 };
592 size = CSIL_sizeof[p - CSIL];
Denis Vlasenko7089c312008-04-14 19:50:06 +0000593 s++; /* skip C/S/I/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000594 }
595
596#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
597 ((Spec) == LONG_LONG ? (Max_format) \
598 : ((Spec) == LONG ? (Long_format) : (Min_format)))
599
600#define FMT_BYTES_ALLOCATED 9
Denis Vlasenko1114de72006-10-10 23:26:05 +0000601 size_spec = integral_type_size[size];
602
Denis Vlasenko601ae132006-11-28 23:37:46 +0000603 {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000604 static const char doux[] ALIGN1 = "doux";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000605 static const char doux_fmt_letter[][4] = {
606 "lld", "llo", "llu", "llx"
607 };
608 static const enum output_format doux_fmt[] = {
609 SIGNED_DECIMAL,
610 OCTAL,
611 UNSIGNED_DECIMAL,
612 HEXADECIMAL,
613 };
614 static const uint8_t *const doux_bytes_to_XXX[] = {
615 bytes_to_signed_dec_digits,
616 bytes_to_oct_digits,
617 bytes_to_unsigned_dec_digits,
618 bytes_to_hex_digits,
619 };
620 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
621 " %%%u%s",
622 " %%0%u%s",
623 " %%%u%s",
624 " %%0%u%s",
625 };
Denis Vlasenko1114de72006-10-10 23:26:05 +0000626
Denis Vlasenko601ae132006-11-28 23:37:46 +0000627 pos = strchr(doux, c) - doux;
628 fmt = doux_fmt[pos];
629 field_width = doux_bytes_to_XXX[pos][size];
630 p = doux_fmt_letter[pos] + 2;
631 if (size_spec == LONG) p--;
632 if (size_spec == LONG_LONG) p -= 2;
633 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
634 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000635
636 switch (size_spec) {
637 case CHAR:
638 print_function = (fmt == SIGNED_DECIMAL
639 ? print_s_char
640 : print_char);
641 break;
642 case SHORT:
643 print_function = (fmt == SIGNED_DECIMAL
644 ? print_s_short
645 : print_short);
646 break;
647 case INT:
648 print_function = print_int;
649 break;
650 case LONG:
651 print_function = print_long;
652 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000653 default: /* case LONG_LONG: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000654 print_function = print_long_long;
655 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000656 }
657 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000658 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000659
Denis Vlasenko601ae132006-11-28 23:37:46 +0000660 case 'f': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000661 static const char FDL[] ALIGN1 = "FDL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000662
Denis Vlasenko1114de72006-10-10 23:26:05 +0000663 fmt = FLOATING_POINT;
664 ++s;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000665 p = strchr(FDL, *s);
666 if (!p) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000667 size = sizeof(double);
668 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000669 size = bb_strtou(s, &end, 0);
670 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000671 || fp_type_size[size] == NO_SIZE
672 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000673 bb_error_msg_and_die("invalid type string '%s'; "
674 "%u-byte %s type is not supported",
675 s_orig, size, "floating point");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000676 }
677 s = end;
678 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000679 } else {
680 static const uint8_t FDL_sizeof[] = {
681 sizeof(float),
682 sizeof(double),
683 sizeof(longdouble_t),
684 };
685
686 size = FDL_sizeof[p - FDL];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000687 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000688
Denis Vlasenko1114de72006-10-10 23:26:05 +0000689 size_spec = fp_type_size[size];
690
691 switch (size_spec) {
692 case FLOAT_SINGLE:
693 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000694 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000695 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000696 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000697 break;
698 case FLOAT_DOUBLE:
699 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000700 field_width = DBL_DIG + 8;
701 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000702 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000703 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000704 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000705 field_width = LDBL_DIG + 8;
706 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000707 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000708 }
709 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000710 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000711
712 case 'a':
713 ++s;
714 fmt = NAMED_CHARACTER;
715 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000716 print_function = print_named_ascii;
717 field_width = 3;
718 break;
719 case 'c':
720 ++s;
721 fmt = CHARACTER;
722 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000723 print_function = print_ascii;
724 field_width = 3;
725 break;
726 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000727 bb_error_msg_and_die("invalid character '%c' "
728 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000729 }
730
731 tspec->size = size_spec;
732 tspec->fmt = fmt;
733 tspec->print_function = print_function;
734 tspec->fmt_string = fmt_string;
735
736 tspec->field_width = field_width;
737 tspec->hexl_mode_trailer = (*s == 'z');
738 if (tspec->hexl_mode_trailer)
739 s++;
740
Denis Vlasenko7089c312008-04-14 19:50:06 +0000741 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000742}
743
744/* Decode the modern od format string S. Append the decoded
745 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000746 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000747
Denis Vlasenko601ae132006-11-28 23:37:46 +0000748static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000749decode_format_string(const char *s)
750{
751 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000752
753 while (*s != '\0') {
754 struct tspec tspec;
755 const char *next;
756
Denis Vlasenko7089c312008-04-14 19:50:06 +0000757 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000758
759 assert(s != next);
760 s = next;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200761 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
762 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
763 G.n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000764 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000765}
766
767/* Given a list of one or more input filenames FILE_LIST, set the global
768 file pointer IN_STREAM to position N_SKIP in the concatenation of
769 those files. If any file operation fails or if there are fewer than
770 N_SKIP bytes in the combined input, give an error message and return
771 nonzero. When possible, use seek rather than read operations to
772 advance IN_STREAM. */
773
Denis Vlasenko601ae132006-11-28 23:37:46 +0000774static void
775skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000776{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000777 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000778 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000779
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200780 while (G.in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000781 struct stat file_stats;
782
783 /* First try seeking. For large offsets, this extra work is
784 worthwhile. If the offset is below some threshold it may be
785 more efficient to move the pointer by reading. There are two
786 issues when trying to seek:
787 - the file must be seekable.
788 - before seeking to the specified position, make sure
789 that the new position is in the current file.
790 Try to do that by getting file's size using fstat.
791 But that will work only for regular files. */
792
Denis Vlasenko1114de72006-10-10 23:26:05 +0000793 /* The st_size field is valid only for regular files
794 (and for symbolic links, which cannot occur here).
795 If the number of bytes left to skip is at least
796 as large as the size of the current file, we can
797 decrement n_skip and go on to the next file. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200798 if (fstat(fileno(G.in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000799 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000800 ) {
801 if (file_stats.st_size < n_skip) {
802 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000803 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000804 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200805 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
806 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000807 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000808 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000809 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000810 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000811 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000812 char buf[1024];
813 size_t n_bytes_to_read = 1024;
814 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000815
Denis Vlasenko601ae132006-11-28 23:37:46 +0000816 while (n_skip > 0) {
817 if (n_skip < n_bytes_to_read)
818 n_bytes_to_read = n_skip;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200819 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000820 n_skip -= n_bytes_read;
821 if (n_bytes_read != n_bytes_to_read)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000822 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000823 }
824 }
825 if (n_skip == 0)
826 return;
827
828 check_and_close();
829 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000830 }
831
Denis Vlasenko601ae132006-11-28 23:37:46 +0000832 if (n_skip)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100833 bb_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000834}
835
Denis Vlasenko601ae132006-11-28 23:37:46 +0000836
837typedef void FN_format_address(off_t address, char c);
838
Denis Vlasenko1114de72006-10-10 23:26:05 +0000839static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000840format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000841{
842}
843
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000844static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000845/* Corresponds to 'x' above */
846#define address_base_char address_fmt[sizeof(address_fmt)-3]
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000847/* Corresponds to 'n' above */
848#define address_pad_len_char address_fmt[2]
Denis Vlasenko601ae132006-11-28 23:37:46 +0000849
Denis Vlasenko1114de72006-10-10 23:26:05 +0000850static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000851format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000852{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000853 /* Corresponds to 'c' */
854 address_fmt[sizeof(address_fmt)-2] = c;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000855 printf(address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000856}
857
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200858#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000859/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000860static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000861format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000862{
863 putchar('(');
864 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000865 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000866}
867
868static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000869format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000870{
871 format_address_std(address, ' ');
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200872 format_address_paren(address + G_pseudo_offset, c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000873}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000874#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000875
876static void
877dump_hexl_mode_trailer(size_t n_bytes, const char *block)
878{
879 fputs(" >", stdout);
880 while (n_bytes--) {
881 unsigned c = *(unsigned char *) block++;
882 c = (ISPRINT(c) ? c : '.');
883 putchar(c);
884 }
885 putchar('<');
886}
887
Denis Vlasenko1114de72006-10-10 23:26:05 +0000888/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
889 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
890 CURR_BLOCK in the concatenation of input files, and it is printed
891 (optionally) only before the output line associated with the first
892 format spec. When duplicate blocks are being abbreviated, the output
893 for a sequence of identical input blocks is the output for the first
894 block followed by an asterisk alone on a line. It is valid to compare
895 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
896 That condition may be false only for the last input block -- and then
897 only when it has not been padded to length BYTES_PER_BLOCK. */
898
899static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000900write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000901 const char *prev_block, const char *curr_block)
902{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200903 unsigned i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000904
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200905 if (!(option_mask32 & OPT_v)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200906 && G.not_first
907 && n_bytes == G.bytes_per_block
908 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
Denis Vlasenko1114de72006-10-10 23:26:05 +0000909 ) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200910 if (G.prev_pair_equal) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000911 /* The two preceding blocks were equal, and the current
912 block is the same as the last one, so print nothing. */
913 } else {
914 puts("*");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200915 G.prev_pair_equal = 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000916 }
917 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200918 G.not_first = 1;
919 G.prev_pair_equal = 0;
920 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000921 if (i == 0)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200922 G.format_address(current_offset, '\0');
Denis Vlasenko1114de72006-10-10 23:26:05 +0000923 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000924 printf("%*s", address_pad_len_char - '0', "");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200925 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
926 if (G.spec[i].hexl_mode_trailer) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000927 /* space-pad out to full line width, then dump the trailer */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200928 unsigned datum_width = width_bytes[G.spec[i].size];
929 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
930 unsigned field_width = G.spec[i].field_width + 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000931 printf("%*s", blank_fields * field_width, "");
932 dump_hexl_mode_trailer(n_bytes, curr_block);
933 }
934 putchar('\n');
935 }
936 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000937}
938
Denis Vlasenko601ae132006-11-28 23:37:46 +0000939static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000940read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
941{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200942 assert(0 < n && n <= G.bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000943
944 *n_bytes_in_buffer = 0;
945
946 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000947 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000948
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200949 while (G.in_stream != NULL) { /* EOF. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000950 size_t n_needed;
951 size_t n_read;
952
953 n_needed = n - *n_bytes_in_buffer;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200954 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000955 *n_bytes_in_buffer += n_read;
956 if (n_read == n_needed)
957 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000958 /* error check is done in check_and_close */
959 check_and_close();
960 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000961 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000962}
963
964/* Return the least common multiple of the sizes associated
965 with the format specs. */
966
967static int
968get_lcm(void)
969{
970 size_t i;
971 int l_c_m = 1;
972
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200973 for (i = 0; i < G.n_specs; i++)
974 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000975 return l_c_m;
976}
977
Denis Vlasenko1114de72006-10-10 23:26:05 +0000978/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
979 formatted block to standard output, and repeat until the specified
980 maximum number of bytes has been read or until all input has been
981 processed. If the last block read is smaller than BYTES_PER_BLOCK
982 and its size is not a multiple of the size associated with a format
983 spec, extend the input block with zero bytes until its length is a
984 multiple of all format spec sizes. Write the final block. Finally,
985 write on a line by itself the offset of the byte after the last byte
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000986 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000987
Denis Vlasenko601ae132006-11-28 23:37:46 +0000988static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000989dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000990{
991 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000992 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000993 size_t n_bytes_read;
994
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200995 block[0] = xmalloc(2 * G.bytes_per_block);
996 block[1] = block[0] + G.bytes_per_block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000997
Denis Vlasenko1114de72006-10-10 23:26:05 +0000998 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200999 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001000 while (1) {
1001 size_t n_needed;
1002 if (current_offset >= end_offset) {
1003 n_bytes_read = 0;
1004 break;
1005 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001006 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001007 read_block(n_needed, block[idx], &n_bytes_read);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001008 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001009 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001010 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001011 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001012 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001013 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001014 }
1015 } else {
1016 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001017 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1018 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001019 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001020 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001021 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001022 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001023 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001024 }
1025 }
1026
1027 if (n_bytes_read > 0) {
1028 int l_c_m;
1029 size_t bytes_to_write;
1030
1031 l_c_m = get_lcm();
1032
1033 /* Make bytes_to_write the smallest multiple of l_c_m that
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001034 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001035 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1036
1037 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1038 write_block(current_offset, bytes_to_write,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001039 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001040 current_offset += n_bytes_read;
1041 }
1042
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001043 G.format_address(current_offset, '\n');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001044
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001045 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001046 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001047
1048 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001049}
1050
Denis Vlasenko601ae132006-11-28 23:37:46 +00001051/* Read N bytes into BLOCK from the concatenation of the input files
1052 named in the global array FILE_LIST. On the first call to this
1053 function, the global variable IN_STREAM is expected to be an open
1054 stream associated with the input file INPUT_FILENAME. If all N
1055 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1056 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1057 read the remaining bytes from the newly opened file. Repeat if
1058 necessary until EOF is reached for the last file in FILE_LIST.
1059 On subsequent calls, don't modify BLOCK and return zero. Set
1060 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1061 it will be detected through ferror when the stream is about to be
1062 closed. If there is an error, give a message but continue reading
1063 as usual and return nonzero. Otherwise return zero. */
1064
Denis Vlasenko1114de72006-10-10 23:26:05 +00001065/* STRINGS mode. Find each "string constant" in the input.
1066 A string constant is a run of at least 'string_min' ASCII
1067 graphic (or formatting) characters terminated by a null.
1068 Based on a function written by Richard Stallman for a
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001069 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001070
Denis Vlasenko601ae132006-11-28 23:37:46 +00001071static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001072dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001073{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001074 unsigned bufsize = MAX(100, G.string_min);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001075 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001076
Denis Vlasenko1114de72006-10-10 23:26:05 +00001077 while (1) {
1078 size_t i;
1079 int c;
1080
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001081 /* See if the next 'G.string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001082 tryline:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001083 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001084 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001085 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001086 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001087 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001088 bufsize += bufsize/8;
1089 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001090 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001091
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001092 while (G.in_stream) { /* !EOF */
1093 c = fgetc(G.in_stream);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001094 if (c != EOF)
1095 goto got_char;
1096 check_and_close();
1097 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001098 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001099 /* EOF */
1100 goto ret;
1101 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001102 address++;
1103 if (!c)
1104 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001105 if (!ISPRINT(c))
1106 goto tryline; /* It isn't; give up on this string. */
1107 buf[i++] = c; /* String continues; store it all. */
1108 }
1109
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001110 if (i < G.string_min) /* Too short! */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001111 goto tryline;
1112
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001113 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001114 buf[i] = 0;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001115 G.format_address(address - i - 1, ' ');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001116
1117 for (i = 0; (c = buf[i]); i++) {
1118 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001119 case '\007': fputs("\\a", stdout); break;
1120 case '\b': fputs("\\b", stdout); break;
1121 case '\f': fputs("\\f", stdout); break;
1122 case '\n': fputs("\\n", stdout); break;
1123 case '\r': fputs("\\r", stdout); break;
1124 case '\t': fputs("\\t", stdout); break;
1125 case '\v': fputs("\\v", stdout); break;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001126 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001127 }
1128 }
1129 putchar('\n');
1130 }
1131
1132 /* We reach this point only if we search through
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001133 (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001134 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001135 ret:
1136 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001137}
1138
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001139#if ENABLE_LONG_OPTS
1140/* If S is a valid traditional offset specification with an optional
1141 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1142
1143static int
1144parse_old_offset(const char *s, off_t *offset)
1145{
1146 static const struct suffix_mult Bb[] = {
1147 { "B", 1024 },
1148 { "b", 512 },
1149 { "", 0 }
1150 };
1151 char *p;
1152 int radix;
1153
1154 /* Skip over any leading '+'. */
1155 if (s[0] == '+') ++s;
1156 if (!isdigit(s[0])) return 0; /* not a number */
1157
1158 /* Determine the radix we'll use to interpret S. If there is a '.',
1159 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1160 * it's hexadecimal, else octal. */
1161 p = strchr(s, '.');
1162 radix = 8;
1163 if (p) {
1164 p[0] = '\0'; /* cheating */
1165 radix = 10;
1166 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1167 radix = 16;
1168
1169 *offset = xstrtooff_sfx(s, radix, Bb);
1170 if (p) p[0] = '.';
1171
1172 return (*offset >= 0);
1173}
1174#endif
1175
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001176int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001177int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001178{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001179#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001180 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001181 "skip-bytes\0" Required_argument "j"
1182 "address-radix\0" Required_argument "A"
1183 "read-bytes\0" Required_argument "N"
1184 "format\0" Required_argument "t"
1185 "output-duplicates\0" No_argument "v"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001186 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1187 * that is, NUM is mandatory for -S but optional for --strings!
1188 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001189 "strings\0" Optional_argument "S"
1190 "width\0" Optional_argument "w"
1191 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001192 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001193#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001194 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001195 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001196 unsigned opt;
1197 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001198 /* The number of input bytes to skip before formatting and writing. */
1199 off_t n_bytes_to_skip = 0;
1200 /* The offset of the first byte after the last byte to be formatted. */
1201 off_t end_offset = 0;
1202 /* The maximum number of bytes that will be formatted. */
1203 off_t max_bytes_to_format = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001204
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001205 INIT_G();
1206
1207 /*G.spec = NULL; - already is */
1208 G.format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001209 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001210 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001211
Denis Vlasenko601ae132006-11-28 23:37:46 +00001212 /* Parse command line */
Denis Vlasenko1d426652008-03-17 09:09:09 +00001213 opt_complementary = "w+:t::"; /* -w N, -t is a list */
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001214#if ENABLE_LONG_OPTS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001215 applet_long_options = od_longopts;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001216#endif
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001217 opt = OD_GETOPT32();
Denis Vlasenko601ae132006-11-28 23:37:46 +00001218 argv += optind;
1219 if (opt & OPT_A) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001220 static const char doxn[] ALIGN1 = "doxn";
1221 static const char doxn_address_base_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001222 'u', 'o', 'x', /* '?' fourth one is not important */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001223 };
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001224 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001225 '7', '7', '6', /* '?' */
1226 };
Denis Vlasenko601ae132006-11-28 23:37:46 +00001227 char *p;
1228 int pos;
1229 p = strchr(doxn, str_A[0]);
1230 if (!p)
1231 bb_error_msg_and_die("bad output address radix "
1232 "'%c' (must be [doxn])", str_A[0]);
1233 pos = p - doxn;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001234 if (pos == 3) G.format_address = format_address_none;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001235 address_base_char = doxn_address_base_char[pos];
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001236 address_pad_len_char = doxn_address_pad_len_char[pos];
Denis Vlasenko1114de72006-10-10 23:26:05 +00001237 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001238 if (opt & OPT_N) {
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001239 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001240 }
1241 if (opt & OPT_a) decode_format_string("a");
1242 if (opt & OPT_b) decode_format_string("oC");
1243 if (opt & OPT_c) decode_format_string("c");
1244 if (opt & OPT_d) decode_format_string("u2");
1245 if (opt & OPT_f) decode_format_string("fF");
1246 if (opt & OPT_h) decode_format_string("x2");
1247 if (opt & OPT_i) decode_format_string("d2");
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001248 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001249 if (opt & OPT_l) decode_format_string("d4");
1250 if (opt & OPT_o) decode_format_string("o2");
Denis Vlasenko601ae132006-11-28 23:37:46 +00001251 while (lst_t) {
Denis Vlasenkod50dda82008-06-15 05:40:56 +00001252 decode_format_string(llist_pop(&lst_t));
Denis Vlasenko601ae132006-11-28 23:37:46 +00001253 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001254 if (opt & OPT_x) decode_format_string("x2");
1255 if (opt & OPT_s) decode_format_string("d2");
1256 if (opt & OPT_S) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001257 G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001258 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001259
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001260 // Bloat:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001261 //if ((option_mask32 & OPT_S) && G.n_specs > 0)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001262 // bb_error_msg_and_die("no type may be specified when dumping strings");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001263
Denis Vlasenko1114de72006-10-10 23:26:05 +00001264 /* If the --traditional option is used, there may be from
Denis Vlasenko601ae132006-11-28 23:37:46 +00001265 * 0 to 3 remaining command line arguments; handle each case
1266 * separately.
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001267 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
Denis Vlasenko601ae132006-11-28 23:37:46 +00001268 * The offset and pseudo_start have the same syntax.
1269 *
1270 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
1271 * traditional syntax even if --traditional is not given. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001272
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001273#if ENABLE_LONG_OPTS
Denis Vlasenko601ae132006-11-28 23:37:46 +00001274 if (opt & OPT_traditional) {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001275 if (argv[0]) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001276 off_t pseudo_start = -1;
1277 off_t o1, o2;
1278
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001279 if (!argv[1]) { /* one arg */
1280 if (parse_old_offset(argv[0], &o1)) {
1281 /* od --traditional OFFSET */
1282 n_bytes_to_skip = o1;
1283 argv++;
1284 }
1285 /* od --traditional FILE */
1286 } else if (!argv[2]) { /* two args */
1287 if (parse_old_offset(argv[0], &o1)
1288 && parse_old_offset(argv[1], &o2)
1289 ) {
1290 /* od --traditional OFFSET LABEL */
1291 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001292 pseudo_start = o2;
1293 argv += 2;
1294 } else if (parse_old_offset(argv[1], &o2)) {
1295 /* od --traditional FILE OFFSET */
1296 n_bytes_to_skip = o2;
1297 argv[1] = NULL;
1298 } else {
1299 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1300 }
1301 } else if (!argv[3]) { /* three args */
1302 if (parse_old_offset(argv[1], &o1)
1303 && parse_old_offset(argv[2], &o2)
1304 ) {
1305 /* od --traditional FILE OFFSET LABEL */
1306 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001307 pseudo_start = o2;
1308 argv[1] = NULL;
1309 } else {
1310 bb_error_msg_and_die("the last two arguments must be offsets");
1311 }
1312 } else { /* >3 args */
1313 bb_error_msg_and_die("too many arguments");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001314 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001315
1316 if (pseudo_start >= 0) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001317 if (G.format_address == format_address_none) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001318 address_base_char = 'o';
1319 address_pad_len_char = '7';
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001320 G.format_address = format_address_paren;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001321 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001322 G.format_address = format_address_label;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001323 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001324 G_pseudo_offset = pseudo_start - n_bytes_to_skip;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001325 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001326 }
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001327 /* else: od --traditional (without args) */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001328 }
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001329#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +00001330
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001331 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001332 end_offset = n_bytes_to_skip + max_bytes_to_format;
1333 if (end_offset < n_bytes_to_skip)
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001334 bb_error_msg_and_die("SKIP + SIZE is too large");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001335 }
1336
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001337 if (G.n_specs == 0) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001338 decode_format_string("o2");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001339 /*G.n_specs = 1; - done by decode_format_string */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001340 }
1341
Denis Vlasenko601ae132006-11-28 23:37:46 +00001342 /* If no files were listed on the command line,
1343 set the global pointer FILE_LIST so that it
1344 references the null-terminated list of one name: "-". */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001345 G.file_list = bb_argv_dash;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001346 if (argv[0]) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001347 /* Set the global pointer FILE_LIST so that it
1348 references the first file-argument on the command-line. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001349 G.file_list = (char const *const *) argv;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001350 }
1351
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001352 /* Open the first input file */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001353 open_next_file();
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001354 /* Skip over any unwanted header bytes */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001355 skip(n_bytes_to_skip);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001356 if (!G.in_stream)
Bernhard Reutner-Fischer7c2db5c2007-11-16 12:39:16 +00001357 return EXIT_FAILURE;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001358
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001359 /* Compute output block length */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001360 l_c_m = get_lcm();
1361
Denis Vlasenko601ae132006-11-28 23:37:46 +00001362 if (opt & OPT_w) { /* -w: width */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001363 if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001364 bb_error_msg("warning: invalid width %u; using %d instead",
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001365 (unsigned)G.bytes_per_block, l_c_m);
1366 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001367 }
1368 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001369 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001370 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001371 G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001372 }
1373
1374#ifdef DEBUG
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001375 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001376 printf("%d: fmt=\"%s\" width=%d\n",
1377 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1378 }
1379#endif
1380
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001381 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001382 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001383 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001384 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001385
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001386 if (fclose(stdin))
Denis Vlasenko601ae132006-11-28 23:37:46 +00001387 bb_perror_msg_and_die(bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001388
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001389 return G.exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001390}