blob: f13bdfc11cfb111c46f941641c3f516a27237b86 [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 */
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020023#include "common_bufsiz.h"
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020024#define assert(a) ((void)0)
25
26
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020027//usage:#if ENABLE_DESKTOP
28//usage:#define od_trivial_usage
Denys Vlasenkoe3e0d2b2012-06-19 12:46:59 +020029//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..."
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020030// We don't support:
31// ... [FILE] [[+]OFFSET[.][b]]
32// Support is buggy for:
33// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]
Denis Vlasenko601ae132006-11-28 23:37:46 +000034
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020035//usage:#define od_full_usage "\n\n"
36//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default"
37//usage:#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +000038
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020039enum {
40 OPT_A = 1 << 0,
41 OPT_N = 1 << 1,
42 OPT_a = 1 << 2,
43 OPT_b = 1 << 3,
44 OPT_c = 1 << 4,
45 OPT_d = 1 << 5,
46 OPT_f = 1 << 6,
47 OPT_h = 1 << 7,
48 OPT_i = 1 << 8,
49 OPT_j = 1 << 9,
50 OPT_l = 1 << 10,
51 OPT_o = 1 << 11,
52 OPT_t = 1 << 12,
53 /* When zero and two or more consecutive blocks are equal, format
54 only the first block and output an asterisk alone on the following
55 line to indicate that identical blocks have been elided: */
56 OPT_v = 1 << 13,
57 OPT_x = 1 << 14,
58 OPT_s = 1 << 15,
59 OPT_S = 1 << 16,
60 OPT_w = 1 << 17,
61 OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS,
62};
Denis Vlasenko1114de72006-10-10 23:26:05 +000063
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020064#define OD_GETOPT32() getopt32(argv, \
Denys Vlasenko237bedd2016-07-06 21:58:02 +020065 "A:N:abcdfhij:lot:*vxsS:w:+:", \
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020066 /* -w with optional param */ \
67 /* -S was -s and also had optional parameter */ \
68 /* but in coreutils 6.3 it was renamed and now has */ \
69 /* _mandatory_ parameter */ \
Denys Vlasenkof3d58a22015-10-19 02:51:56 +020070 &str_A, &str_N, &str_j, &lst_t, &str_S, &G.bytes_per_block)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020071
Denis Vlasenko601ae132006-11-28 23:37:46 +000072
73/* Check for 0x7f is a coreutils 6.3 addition */
Denys Vlasenko9d96e272011-05-21 18:38:59 +020074#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f)
Denis Vlasenko1114de72006-10-10 23:26:05 +000075
76typedef long double longdouble_t;
77typedef unsigned long long ulonglong_t;
Denis Vlasenko601ae132006-11-28 23:37:46 +000078typedef long long llong;
79
80#if ENABLE_LFS
81# define xstrtooff_sfx xstrtoull_sfx
82#else
83# define xstrtooff_sfx xstrtoul_sfx
84#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +000085
86/* The default number of input bytes per output line. */
87#define DEFAULT_BYTES_PER_BLOCK 16
88
89/* The number of decimal digits of precision in a float. */
90#ifndef FLT_DIG
91# define FLT_DIG 7
92#endif
93
94/* The number of decimal digits of precision in a double. */
95#ifndef DBL_DIG
96# define DBL_DIG 15
97#endif
98
99/* The number of decimal digits of precision in a long double. */
100#ifndef LDBL_DIG
101# define LDBL_DIG DBL_DIG
102#endif
103
104enum size_spec {
105 NO_SIZE,
106 CHAR,
107 SHORT,
108 INT,
109 LONG,
110 LONG_LONG,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000111 FLOAT_SINGLE,
112 FLOAT_DOUBLE,
113 FLOAT_LONG_DOUBLE,
114 N_SIZE_SPECS
115};
116
117enum output_format {
118 SIGNED_DECIMAL,
119 UNSIGNED_DECIMAL,
120 OCTAL,
121 HEXADECIMAL,
122 FLOATING_POINT,
123 NAMED_CHARACTER,
124 CHARACTER
125};
126
127/* Each output format specification (from '-t spec' or from
128 old-style options) is represented by one of these structures. */
129struct tspec {
130 enum output_format fmt;
131 enum size_spec size;
132 void (*print_function) (size_t, const char *, const char *);
133 char *fmt_string;
134 int hexl_mode_trailer;
135 int field_width;
136};
137
138/* Convert the number of 8-bit bytes of a binary representation to
139 the number of characters (digits + sign if the type is signed)
140 required to represent the same quantity in the specified base/type.
141 For example, a 32-bit (4-byte) quantity may require a field width
142 as wide as the following for these types:
143 11 unsigned octal
144 11 signed decimal
145 10 unsigned decimal
146 8 unsigned hexadecimal */
147
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000148static const uint8_t bytes_to_oct_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000149{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
150
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000151static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000152{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
153
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000154static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000155{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
156
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000157static const uint8_t bytes_to_hex_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000158{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
159
160/* Convert enum size_spec to the size of the named type. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000161static const signed char width_bytes[] ALIGN1 = {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000162 -1,
163 sizeof(char),
164 sizeof(short),
165 sizeof(int),
166 sizeof(long),
167 sizeof(ulonglong_t),
168 sizeof(float),
169 sizeof(double),
170 sizeof(longdouble_t)
171};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000172/* Ensure that for each member of 'enum size_spec' there is an
173 initializer in the width_bytes array. */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000174struct ERR_width_bytes_has_bad_size {
175 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000176};
177
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200178struct globals {
179 smallint exit_code;
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000180
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200181 unsigned string_min;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000182
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200183 /* An array of specs describing how to format each input block. */
184 unsigned n_specs;
185 struct tspec *spec;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000186
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200187 /* Function that accepts an address and an optional following char,
188 and prints the address and char to stdout. */
189 void (*format_address)(off_t, char);
190
191 /* The difference between the old-style pseudo starting address and
192 the number of bytes to skip. */
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200193#if ENABLE_LONG_OPTS
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200194 off_t pseudo_offset;
195# define G_pseudo_offset G.pseudo_offset
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200196#endif
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200197 /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
198 input is formatted. */
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000199
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200200 /* The number of input bytes formatted per output line. It must be
201 a multiple of the least common multiple of the sizes associated with
202 the specified output types. It should be as large as possible, but
203 no larger than 16 -- unless specified with the -w option. */
204 unsigned bytes_per_block; /* have to use unsigned, not size_t */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000205
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200206 /* A NULL-terminated list of the file-arguments from the command line. */
207 const char *const *file_list;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000208
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200209 /* The input stream associated with the current file. */
210 FILE *in_stream;
211
212 bool not_first;
213 bool prev_pair_equal;
214} FIX_ALIASING;
215#if !ENABLE_LONG_OPTS
216enum { G_pseudo_offset = 0 };
217#endif
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200218#define G (*(struct globals*)bb_common_bufsiz1)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200219#define INIT_G() do { \
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200220 setup_common_bufsiz(); \
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200221 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
222 G.bytes_per_block = 32; \
223} while (0)
224
Denis Vlasenko1114de72006-10-10 23:26:05 +0000225
Denis Vlasenko1114de72006-10-10 23:26:05 +0000226#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000227static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000228 [sizeof(char)] = CHAR,
229#if USHRT_MAX != UCHAR_MAX
230 [sizeof(short)] = SHORT,
231#endif
232#if UINT_MAX != USHRT_MAX
233 [sizeof(int)] = INT,
234#endif
235#if ULONG_MAX != UINT_MAX
236 [sizeof(long)] = LONG,
237#endif
238#if ULLONG_MAX != ULONG_MAX
239 [sizeof(ulonglong_t)] = LONG_LONG,
240#endif
241};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000242
243#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000244static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200245 /* gcc seems to allow repeated indexes. Last one wins */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000246 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
247 [sizeof(double)] = FLOAT_DOUBLE,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000248 [sizeof(float)] = FLOAT_SINGLE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000249};
250
251
252static unsigned
253gcd(unsigned u, unsigned v)
254{
255 unsigned t;
256 while (v != 0) {
257 t = u % v;
258 u = v;
259 v = t;
260 }
261 return u;
262}
263
264/* Compute the least common multiple of U and V. */
265static unsigned
266lcm(unsigned u, unsigned v) {
267 unsigned t = gcd(u, v);
268 if (t == 0)
269 return 0;
270 return u * v / t;
271}
272
273static void
274print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
275{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000276 while (n_bytes--) {
277 int tmp = *(signed char *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000278 printf(fmt_string, tmp);
279 block += sizeof(unsigned char);
280 }
281}
282
283static void
284print_char(size_t n_bytes, const char *block, const char *fmt_string)
285{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000286 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000287 unsigned tmp = *(unsigned char *) block;
288 printf(fmt_string, tmp);
289 block += sizeof(unsigned char);
290 }
291}
292
293static void
294print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
295{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000296 n_bytes /= sizeof(signed short);
297 while (n_bytes--) {
298 int tmp = *(signed short *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000299 printf(fmt_string, tmp);
300 block += sizeof(unsigned short);
301 }
302}
303
304static void
305print_short(size_t n_bytes, const char *block, const char *fmt_string)
306{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000307 n_bytes /= sizeof(unsigned short);
308 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000309 unsigned tmp = *(unsigned short *) block;
310 printf(fmt_string, tmp);
311 block += sizeof(unsigned short);
312 }
313}
314
315static void
316print_int(size_t n_bytes, const char *block, const char *fmt_string)
317{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000318 n_bytes /= sizeof(unsigned);
319 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000320 unsigned tmp = *(unsigned *) block;
321 printf(fmt_string, tmp);
322 block += sizeof(unsigned);
323 }
324}
325
Denis Vlasenko601ae132006-11-28 23:37:46 +0000326#if UINT_MAX == ULONG_MAX
327# define print_long print_int
328#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000329static void
330print_long(size_t n_bytes, const char *block, const char *fmt_string)
331{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000332 n_bytes /= sizeof(unsigned long);
333 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000334 unsigned long tmp = *(unsigned long *) block;
335 printf(fmt_string, tmp);
336 block += sizeof(unsigned long);
337 }
338}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000339#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000340
Denis Vlasenko601ae132006-11-28 23:37:46 +0000341#if ULONG_MAX == ULLONG_MAX
342# define print_long_long print_long
343#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000344static void
345print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
346{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000347 n_bytes /= sizeof(ulonglong_t);
348 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000349 ulonglong_t tmp = *(ulonglong_t *) block;
350 printf(fmt_string, tmp);
351 block += sizeof(ulonglong_t);
352 }
353}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000354#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000355
356static void
357print_float(size_t n_bytes, const char *block, const char *fmt_string)
358{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000359 n_bytes /= sizeof(float);
360 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000361 float tmp = *(float *) block;
362 printf(fmt_string, tmp);
363 block += sizeof(float);
364 }
365}
366
367static void
368print_double(size_t n_bytes, const char *block, const char *fmt_string)
369{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000370 n_bytes /= sizeof(double);
371 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000372 double tmp = *(double *) block;
373 printf(fmt_string, tmp);
374 block += sizeof(double);
375 }
376}
377
378static void
379print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
380{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000381 n_bytes /= sizeof(longdouble_t);
382 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000383 longdouble_t tmp = *(longdouble_t *) block;
384 printf(fmt_string, tmp);
385 block += sizeof(longdouble_t);
386 }
387}
388
Denis Vlasenko601ae132006-11-28 23:37:46 +0000389/* print_[named]_ascii are optimized for speed.
Bernhard Reutner-Fischera985d302008-02-11 11:44:38 +0000390 * Remember, someday you may want to pump gigabytes through this thing.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000391 * Saving a dozen of .text bytes here is counter-productive */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000392
393static void
394print_named_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000395 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000396{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000397 /* Names for some non-printing characters. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000398 static const char charname[33][3] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000399 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
400 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
401 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
402 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
403 " sp"
404 };
405 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100406 char buf[12] = " x\0 xxx\0";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000407 // [12] because we take three 32bit stack slots anyway, and
408 // gcc is too dumb to initialize with constant stores,
409 // it copies initializer from rodata. Oh well.
Ron Yorston53e9c512015-03-12 20:10:40 +0100410 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410
Denis Vlasenko1114de72006-10-10 23:26:05 +0000411
Denis Vlasenko601ae132006-11-28 23:37:46 +0000412 while (n_bytes--) {
413 unsigned masked_c = *(unsigned char *) block++;
414
415 masked_c &= 0x7f;
416 if (masked_c == 0x7f) {
417 fputs(" del", stdout);
418 continue;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000419 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000420 if (masked_c > ' ') {
421 buf[3] = masked_c;
422 fputs(buf, stdout);
423 continue;
424 }
425 /* Why? Because printf(" %3.3s") is much slower... */
426 buf[6] = charname[masked_c][0];
427 buf[7] = charname[masked_c][1];
428 buf[8] = charname[masked_c][2];
429 fputs(buf+5, stdout);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000430 }
431}
432
433static void
434print_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000435 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000436{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000437 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100438 char buf[12] = " x\0 xxx\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000439
Denis Vlasenko601ae132006-11-28 23:37:46 +0000440 while (n_bytes--) {
441 const char *s;
442 unsigned c = *(unsigned char *) block++;
443
444 if (ISPRINT(c)) {
445 buf[3] = c;
446 fputs(buf, stdout);
447 continue;
448 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000449 switch (c) {
450 case '\0':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000451 s = " \\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000452 break;
453 case '\007':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000454 s = " \\a";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000455 break;
456 case '\b':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000457 s = " \\b";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000458 break;
459 case '\f':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000460 s = " \\f";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000461 break;
462 case '\n':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000463 s = " \\n";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000464 break;
465 case '\r':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000466 s = " \\r";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000467 break;
468 case '\t':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000469 s = " \\t";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000470 break;
471 case '\v':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000472 s = " \\v";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000473 break;
Ron Yorston53e9c512015-03-12 20:10:40 +0100474 default:
475 buf[6] = (c >> 6 & 3) + '0';
476 buf[7] = (c >> 3 & 7) + '0';
Denis Vlasenko601ae132006-11-28 23:37:46 +0000477 buf[8] = (c & 7) + '0';
478 s = buf + 5;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000479 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000480 fputs(s, stdout);
481 }
482}
Denis Vlasenko1114de72006-10-10 23:26:05 +0000483
Denis Vlasenko601ae132006-11-28 23:37:46 +0000484/* Given a list of one or more input filenames FILE_LIST, set the global
485 file pointer IN_STREAM and the global string INPUT_FILENAME to the
486 first one that can be successfully opened. Modify FILE_LIST to
487 reference the next filename in the list. A file name of "-" is
488 interpreted as standard input. If any file open fails, give an error
489 message and return nonzero. */
490
491static void
492open_next_file(void)
493{
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000494 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200495 if (!*G.file_list)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000496 return;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200497 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
498 if (G.in_stream) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000499 break;
500 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200501 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000502 }
503
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200504 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200505 setbuf(G.in_stream, NULL);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000506}
507
508/* Test whether there have been errors on in_stream, and close it if
509 it is not standard input. Return nonzero if there has been an error
510 on in_stream or stdout; return zero otherwise. This function will
511 report more than one error only if both a read and a write error
512 have occurred. IN_ERRNO, if nonzero, is the error number
513 corresponding to the most recent action for IN_STREAM. */
514
515static void
516check_and_close(void)
517{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200518 if (G.in_stream) {
519 if (ferror(G.in_stream)) {
520 bb_error_msg("%s: read error", (G.in_stream == stdin)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000521 ? bb_msg_standard_input
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200522 : G.file_list[-1]
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000523 );
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200524 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000525 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200526 fclose_if_not_stdin(G.in_stream);
527 G.in_stream = NULL;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000528 }
529
530 if (ferror(stdout)) {
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200531 bb_error_msg_and_die(bb_msg_write_error);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000532 }
533}
534
535/* If S points to a single valid modern od format string, put
Denis Vlasenko7089c312008-04-14 19:50:06 +0000536 a description of that format in *TSPEC, return pointer to
537 character following the just-decoded format.
538 For example, if S were "d4afL", we will return a rtp to "afL"
539 and *TSPEC would be
Denis Vlasenko1114de72006-10-10 23:26:05 +0000540 {
541 fmt = SIGNED_DECIMAL;
542 size = INT or LONG; (whichever integral_type_size[4] resolves to)
543 print_function = print_int; (assuming size == INT)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000544 fmt_string = "%011d%c";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000545 }
546 S_ORIG is solely for reporting errors. It should be the full format
Denis Vlasenko601ae132006-11-28 23:37:46 +0000547 string argument. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000548
Denys Vlasenkob9542cb2010-06-01 23:16:46 +0200549static NOINLINE const char *
Denis Vlasenko7089c312008-04-14 19:50:06 +0000550decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000551{
552 enum size_spec size_spec;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000553 unsigned size;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000554 enum output_format fmt;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000555 const char *p;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000556 char *end;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000557 char *fmt_string = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000558 void (*print_function) (size_t, const char *, const char *);
559 unsigned c;
560 unsigned field_width = 0;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000561 int pos;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000562
Denis Vlasenko1114de72006-10-10 23:26:05 +0000563 switch (*s) {
564 case 'd':
565 case 'o':
566 case 'u':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000567 case 'x': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000568 static const char CSIL[] ALIGN1 = "CSIL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000569
570 c = *s++;
571 p = strchr(CSIL, *s);
Denys Vlasenko11f3a8b2009-11-22 15:37:16 +0100572 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
573 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000574 size = sizeof(int);
575 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000576 size = bb_strtou(s, &end, 0);
577 if (errno == ERANGE
578 || MAX_INTEGRAL_TYPE_SIZE < size
Denis Vlasenko1114de72006-10-10 23:26:05 +0000579 || integral_type_size[size] == NO_SIZE
580 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000581 bb_error_msg_and_die("invalid type string '%s'; "
582 "%u-byte %s type is not supported",
583 s_orig, size, "integral");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000584 }
585 s = end;
586 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000587 } else {
Denis Vlasenko7089c312008-04-14 19:50:06 +0000588 static const uint8_t CSIL_sizeof[4] = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000589 sizeof(char),
590 sizeof(short),
591 sizeof(int),
592 sizeof(long),
593 };
594 size = CSIL_sizeof[p - CSIL];
Denis Vlasenko7089c312008-04-14 19:50:06 +0000595 s++; /* skip C/S/I/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000596 }
597
598#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
599 ((Spec) == LONG_LONG ? (Max_format) \
600 : ((Spec) == LONG ? (Long_format) : (Min_format)))
601
602#define FMT_BYTES_ALLOCATED 9
Denis Vlasenko1114de72006-10-10 23:26:05 +0000603 size_spec = integral_type_size[size];
604
Denis Vlasenko601ae132006-11-28 23:37:46 +0000605 {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000606 static const char doux[] ALIGN1 = "doux";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000607 static const char doux_fmt_letter[][4] = {
608 "lld", "llo", "llu", "llx"
609 };
610 static const enum output_format doux_fmt[] = {
611 SIGNED_DECIMAL,
612 OCTAL,
613 UNSIGNED_DECIMAL,
614 HEXADECIMAL,
615 };
616 static const uint8_t *const doux_bytes_to_XXX[] = {
617 bytes_to_signed_dec_digits,
618 bytes_to_oct_digits,
619 bytes_to_unsigned_dec_digits,
620 bytes_to_hex_digits,
621 };
622 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
623 " %%%u%s",
624 " %%0%u%s",
625 " %%%u%s",
626 " %%0%u%s",
627 };
Denis Vlasenko1114de72006-10-10 23:26:05 +0000628
Denis Vlasenko601ae132006-11-28 23:37:46 +0000629 pos = strchr(doux, c) - doux;
630 fmt = doux_fmt[pos];
631 field_width = doux_bytes_to_XXX[pos][size];
632 p = doux_fmt_letter[pos] + 2;
633 if (size_spec == LONG) p--;
634 if (size_spec == LONG_LONG) p -= 2;
635 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
636 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000637
638 switch (size_spec) {
639 case CHAR:
640 print_function = (fmt == SIGNED_DECIMAL
641 ? print_s_char
642 : print_char);
643 break;
644 case SHORT:
645 print_function = (fmt == SIGNED_DECIMAL
646 ? print_s_short
647 : print_short);
648 break;
649 case INT:
650 print_function = print_int;
651 break;
652 case LONG:
653 print_function = print_long;
654 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000655 default: /* case LONG_LONG: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000656 print_function = print_long_long;
657 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000658 }
659 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000660 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000661
Denis Vlasenko601ae132006-11-28 23:37:46 +0000662 case 'f': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000663 static const char FDL[] ALIGN1 = "FDL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000664
Denis Vlasenko1114de72006-10-10 23:26:05 +0000665 fmt = FLOATING_POINT;
666 ++s;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000667 p = strchr(FDL, *s);
668 if (!p) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000669 size = sizeof(double);
670 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000671 size = bb_strtou(s, &end, 0);
672 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000673 || fp_type_size[size] == NO_SIZE
674 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000675 bb_error_msg_and_die("invalid type string '%s'; "
676 "%u-byte %s type is not supported",
677 s_orig, size, "floating point");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000678 }
679 s = end;
680 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000681 } else {
682 static const uint8_t FDL_sizeof[] = {
683 sizeof(float),
684 sizeof(double),
685 sizeof(longdouble_t),
686 };
687
688 size = FDL_sizeof[p - FDL];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000689 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000690
Denis Vlasenko1114de72006-10-10 23:26:05 +0000691 size_spec = fp_type_size[size];
692
693 switch (size_spec) {
694 case FLOAT_SINGLE:
695 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000696 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000697 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000698 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000699 break;
700 case FLOAT_DOUBLE:
701 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000702 field_width = DBL_DIG + 8;
703 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000704 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000705 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000706 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000707 field_width = LDBL_DIG + 8;
708 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000709 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000710 }
711 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000712 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000713
714 case 'a':
715 ++s;
716 fmt = NAMED_CHARACTER;
717 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000718 print_function = print_named_ascii;
719 field_width = 3;
720 break;
721 case 'c':
722 ++s;
723 fmt = CHARACTER;
724 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000725 print_function = print_ascii;
726 field_width = 3;
727 break;
728 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000729 bb_error_msg_and_die("invalid character '%c' "
730 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000731 }
732
733 tspec->size = size_spec;
734 tspec->fmt = fmt;
735 tspec->print_function = print_function;
736 tspec->fmt_string = fmt_string;
737
738 tspec->field_width = field_width;
739 tspec->hexl_mode_trailer = (*s == 'z');
740 if (tspec->hexl_mode_trailer)
741 s++;
742
Denis Vlasenko7089c312008-04-14 19:50:06 +0000743 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000744}
745
746/* Decode the modern od format string S. Append the decoded
747 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000748 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000749
Denis Vlasenko601ae132006-11-28 23:37:46 +0000750static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000751decode_format_string(const char *s)
752{
753 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000754
755 while (*s != '\0') {
756 struct tspec tspec;
757 const char *next;
758
Denis Vlasenko7089c312008-04-14 19:50:06 +0000759 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000760
761 assert(s != next);
762 s = next;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200763 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
764 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
765 G.n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000766 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000767}
768
769/* Given a list of one or more input filenames FILE_LIST, set the global
770 file pointer IN_STREAM to position N_SKIP in the concatenation of
771 those files. If any file operation fails or if there are fewer than
772 N_SKIP bytes in the combined input, give an error message and return
773 nonzero. When possible, use seek rather than read operations to
774 advance IN_STREAM. */
775
Denis Vlasenko601ae132006-11-28 23:37:46 +0000776static void
777skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000778{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000779 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000780 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000781
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200782 while (G.in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000783 struct stat file_stats;
784
785 /* First try seeking. For large offsets, this extra work is
786 worthwhile. If the offset is below some threshold it may be
787 more efficient to move the pointer by reading. There are two
788 issues when trying to seek:
789 - the file must be seekable.
790 - before seeking to the specified position, make sure
791 that the new position is in the current file.
792 Try to do that by getting file's size using fstat.
793 But that will work only for regular files. */
794
Denis Vlasenko1114de72006-10-10 23:26:05 +0000795 /* The st_size field is valid only for regular files
796 (and for symbolic links, which cannot occur here).
797 If the number of bytes left to skip is at least
798 as large as the size of the current file, we can
799 decrement n_skip and go on to the next file. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200800 if (fstat(fileno(G.in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000801 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000802 ) {
803 if (file_stats.st_size < n_skip) {
804 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000805 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000806 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200807 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
808 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000809 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000810 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000811 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000812 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000813 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000814 char buf[1024];
815 size_t n_bytes_to_read = 1024;
816 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000817
Denis Vlasenko601ae132006-11-28 23:37:46 +0000818 while (n_skip > 0) {
819 if (n_skip < n_bytes_to_read)
820 n_bytes_to_read = n_skip;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200821 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000822 n_skip -= n_bytes_read;
823 if (n_bytes_read != n_bytes_to_read)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000824 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000825 }
826 }
827 if (n_skip == 0)
828 return;
829
830 check_and_close();
831 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000832 }
833
Denis Vlasenko601ae132006-11-28 23:37:46 +0000834 if (n_skip)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100835 bb_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000836}
837
Denis Vlasenko601ae132006-11-28 23:37:46 +0000838
839typedef void FN_format_address(off_t address, char c);
840
Denis Vlasenko1114de72006-10-10 23:26:05 +0000841static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000842format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000843{
844}
845
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000846static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000847/* Corresponds to 'x' above */
848#define address_base_char address_fmt[sizeof(address_fmt)-3]
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000849/* Corresponds to 'n' above */
850#define address_pad_len_char address_fmt[2]
Denis Vlasenko601ae132006-11-28 23:37:46 +0000851
Denis Vlasenko1114de72006-10-10 23:26:05 +0000852static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000853format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000854{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000855 /* Corresponds to 'c' */
856 address_fmt[sizeof(address_fmt)-2] = c;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000857 printf(address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000858}
859
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200860#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000861/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000862static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000863format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000864{
865 putchar('(');
866 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000867 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000868}
869
870static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000871format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000872{
873 format_address_std(address, ' ');
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200874 format_address_paren(address + G_pseudo_offset, c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000875}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000876#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000877
878static void
879dump_hexl_mode_trailer(size_t n_bytes, const char *block)
880{
881 fputs(" >", stdout);
882 while (n_bytes--) {
883 unsigned c = *(unsigned char *) block++;
884 c = (ISPRINT(c) ? c : '.');
885 putchar(c);
886 }
887 putchar('<');
888}
889
Denis Vlasenko1114de72006-10-10 23:26:05 +0000890/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
891 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
892 CURR_BLOCK in the concatenation of input files, and it is printed
893 (optionally) only before the output line associated with the first
894 format spec. When duplicate blocks are being abbreviated, the output
895 for a sequence of identical input blocks is the output for the first
896 block followed by an asterisk alone on a line. It is valid to compare
897 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
898 That condition may be false only for the last input block -- and then
899 only when it has not been padded to length BYTES_PER_BLOCK. */
900
901static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000902write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000903 const char *prev_block, const char *curr_block)
904{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200905 unsigned i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000906
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200907 if (!(option_mask32 & OPT_v)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200908 && G.not_first
909 && n_bytes == G.bytes_per_block
910 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
Denis Vlasenko1114de72006-10-10 23:26:05 +0000911 ) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200912 if (G.prev_pair_equal) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000913 /* The two preceding blocks were equal, and the current
914 block is the same as the last one, so print nothing. */
915 } else {
916 puts("*");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200917 G.prev_pair_equal = 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000918 }
919 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200920 G.not_first = 1;
921 G.prev_pair_equal = 0;
922 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000923 if (i == 0)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200924 G.format_address(current_offset, '\0');
Denis Vlasenko1114de72006-10-10 23:26:05 +0000925 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000926 printf("%*s", address_pad_len_char - '0', "");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200927 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
928 if (G.spec[i].hexl_mode_trailer) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000929 /* space-pad out to full line width, then dump the trailer */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200930 unsigned datum_width = width_bytes[G.spec[i].size];
931 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
932 unsigned field_width = G.spec[i].field_width + 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000933 printf("%*s", blank_fields * field_width, "");
934 dump_hexl_mode_trailer(n_bytes, curr_block);
935 }
936 putchar('\n');
937 }
938 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000939}
940
Denis Vlasenko601ae132006-11-28 23:37:46 +0000941static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000942read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
943{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200944 assert(0 < n && n <= G.bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000945
946 *n_bytes_in_buffer = 0;
947
948 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000949 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000950
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200951 while (G.in_stream != NULL) { /* EOF. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000952 size_t n_needed;
953 size_t n_read;
954
955 n_needed = n - *n_bytes_in_buffer;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200956 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000957 *n_bytes_in_buffer += n_read;
958 if (n_read == n_needed)
959 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000960 /* error check is done in check_and_close */
961 check_and_close();
962 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000963 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000964}
965
966/* Return the least common multiple of the sizes associated
967 with the format specs. */
968
969static int
970get_lcm(void)
971{
972 size_t i;
973 int l_c_m = 1;
974
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200975 for (i = 0; i < G.n_specs; i++)
976 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000977 return l_c_m;
978}
979
Denis Vlasenko1114de72006-10-10 23:26:05 +0000980/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
981 formatted block to standard output, and repeat until the specified
982 maximum number of bytes has been read or until all input has been
983 processed. If the last block read is smaller than BYTES_PER_BLOCK
984 and its size is not a multiple of the size associated with a format
985 spec, extend the input block with zero bytes until its length is a
986 multiple of all format spec sizes. Write the final block. Finally,
987 write on a line by itself the offset of the byte after the last byte
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000988 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000989
Denis Vlasenko601ae132006-11-28 23:37:46 +0000990static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000991dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000992{
993 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000994 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000995 size_t n_bytes_read;
996
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200997 block[0] = xmalloc(2 * G.bytes_per_block);
998 block[1] = block[0] + G.bytes_per_block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000999
Denis Vlasenko1114de72006-10-10 23:26:05 +00001000 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001001 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001002 while (1) {
1003 size_t n_needed;
1004 if (current_offset >= end_offset) {
1005 n_bytes_read = 0;
1006 break;
1007 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001008 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001009 read_block(n_needed, block[idx], &n_bytes_read);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001010 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001011 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001012 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001013 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001014 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001015 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001016 }
1017 } else {
1018 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001019 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1020 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001021 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001022 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001023 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001024 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001025 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001026 }
1027 }
1028
1029 if (n_bytes_read > 0) {
1030 int l_c_m;
1031 size_t bytes_to_write;
1032
1033 l_c_m = get_lcm();
1034
1035 /* Make bytes_to_write the smallest multiple of l_c_m that
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001036 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001037 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1038
1039 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1040 write_block(current_offset, bytes_to_write,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001041 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001042 current_offset += n_bytes_read;
1043 }
1044
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001045 G.format_address(current_offset, '\n');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001046
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001047 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001048 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001049
1050 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001051}
1052
Denis Vlasenko601ae132006-11-28 23:37:46 +00001053/* Read N bytes into BLOCK from the concatenation of the input files
1054 named in the global array FILE_LIST. On the first call to this
1055 function, the global variable IN_STREAM is expected to be an open
1056 stream associated with the input file INPUT_FILENAME. If all N
1057 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1058 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1059 read the remaining bytes from the newly opened file. Repeat if
1060 necessary until EOF is reached for the last file in FILE_LIST.
1061 On subsequent calls, don't modify BLOCK and return zero. Set
1062 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1063 it will be detected through ferror when the stream is about to be
1064 closed. If there is an error, give a message but continue reading
1065 as usual and return nonzero. Otherwise return zero. */
1066
Denis Vlasenko1114de72006-10-10 23:26:05 +00001067/* STRINGS mode. Find each "string constant" in the input.
1068 A string constant is a run of at least 'string_min' ASCII
1069 graphic (or formatting) characters terminated by a null.
1070 Based on a function written by Richard Stallman for a
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001071 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001072
Denis Vlasenko601ae132006-11-28 23:37:46 +00001073static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001074dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001075{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001076 unsigned bufsize = MAX(100, G.string_min);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001077 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001078
Denis Vlasenko1114de72006-10-10 23:26:05 +00001079 while (1) {
1080 size_t i;
1081 int c;
1082
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001083 /* See if the next 'G.string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001084 tryline:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001085 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001086 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001087 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001088 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001089 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001090 bufsize += bufsize/8;
1091 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001092 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001093
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001094 while (G.in_stream) { /* !EOF */
1095 c = fgetc(G.in_stream);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001096 if (c != EOF)
1097 goto got_char;
1098 check_and_close();
1099 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001100 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001101 /* EOF */
1102 goto ret;
1103 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001104 address++;
1105 if (!c)
1106 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001107 if (!ISPRINT(c))
1108 goto tryline; /* It isn't; give up on this string. */
1109 buf[i++] = c; /* String continues; store it all. */
1110 }
1111
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001112 if (i < G.string_min) /* Too short! */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001113 goto tryline;
1114
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001115 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001116 buf[i] = 0;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001117 G.format_address(address - i - 1, ' ');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001118
1119 for (i = 0; (c = buf[i]); i++) {
1120 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001121 case '\007': fputs("\\a", stdout); break;
1122 case '\b': fputs("\\b", stdout); break;
1123 case '\f': fputs("\\f", stdout); break;
1124 case '\n': fputs("\\n", stdout); break;
1125 case '\r': fputs("\\r", stdout); break;
1126 case '\t': fputs("\\t", stdout); break;
1127 case '\v': fputs("\\v", stdout); break;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001128 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001129 }
1130 }
1131 putchar('\n');
1132 }
1133
1134 /* We reach this point only if we search through
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001135 (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001136 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001137 ret:
1138 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001139}
1140
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001141#if ENABLE_LONG_OPTS
1142/* If S is a valid traditional offset specification with an optional
1143 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1144
1145static int
1146parse_old_offset(const char *s, off_t *offset)
1147{
1148 static const struct suffix_mult Bb[] = {
1149 { "B", 1024 },
1150 { "b", 512 },
1151 { "", 0 }
1152 };
1153 char *p;
1154 int radix;
1155
1156 /* Skip over any leading '+'. */
1157 if (s[0] == '+') ++s;
1158 if (!isdigit(s[0])) return 0; /* not a number */
1159
1160 /* Determine the radix we'll use to interpret S. If there is a '.',
1161 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1162 * it's hexadecimal, else octal. */
1163 p = strchr(s, '.');
1164 radix = 8;
1165 if (p) {
1166 p[0] = '\0'; /* cheating */
1167 radix = 10;
1168 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1169 radix = 16;
1170
1171 *offset = xstrtooff_sfx(s, radix, Bb);
1172 if (p) p[0] = '.';
1173
1174 return (*offset >= 0);
1175}
1176#endif
1177
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001178int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001179int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001180{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001181#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001182 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001183 "skip-bytes\0" Required_argument "j"
1184 "address-radix\0" Required_argument "A"
1185 "read-bytes\0" Required_argument "N"
1186 "format\0" Required_argument "t"
1187 "output-duplicates\0" No_argument "v"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001188 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1189 * that is, NUM is mandatory for -S but optional for --strings!
1190 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001191 "strings\0" Optional_argument "S"
1192 "width\0" Optional_argument "w"
1193 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001194 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001195#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001196 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001197 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001198 unsigned opt;
1199 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001200 /* The number of input bytes to skip before formatting and writing. */
1201 off_t n_bytes_to_skip = 0;
1202 /* The offset of the first byte after the last byte to be formatted. */
1203 off_t end_offset = 0;
1204 /* The maximum number of bytes that will be formatted. */
1205 off_t max_bytes_to_format = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001206
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001207 INIT_G();
1208
1209 /*G.spec = NULL; - already is */
1210 G.format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001211 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001212 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001213
Denis Vlasenko601ae132006-11-28 23:37:46 +00001214 /* Parse command line */
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001215#if ENABLE_LONG_OPTS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001216 applet_long_options = od_longopts;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001217#endif
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001218 opt = OD_GETOPT32();
Denis Vlasenko601ae132006-11-28 23:37:46 +00001219 argv += optind;
1220 if (opt & OPT_A) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001221 static const char doxn[] ALIGN1 = "doxn";
1222 static const char doxn_address_base_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001223 'u', 'o', 'x', /* '?' fourth one is not important */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001224 };
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001225 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001226 '7', '7', '6', /* '?' */
1227 };
Denis Vlasenko601ae132006-11-28 23:37:46 +00001228 char *p;
1229 int pos;
1230 p = strchr(doxn, str_A[0]);
1231 if (!p)
1232 bb_error_msg_and_die("bad output address radix "
1233 "'%c' (must be [doxn])", str_A[0]);
1234 pos = p - doxn;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001235 if (pos == 3) G.format_address = format_address_none;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001236 address_base_char = doxn_address_base_char[pos];
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001237 address_pad_len_char = doxn_address_pad_len_char[pos];
Denis Vlasenko1114de72006-10-10 23:26:05 +00001238 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001239 if (opt & OPT_N) {
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001240 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001241 }
1242 if (opt & OPT_a) decode_format_string("a");
1243 if (opt & OPT_b) decode_format_string("oC");
1244 if (opt & OPT_c) decode_format_string("c");
1245 if (opt & OPT_d) decode_format_string("u2");
1246 if (opt & OPT_f) decode_format_string("fF");
1247 if (opt & OPT_h) decode_format_string("x2");
1248 if (opt & OPT_i) decode_format_string("d2");
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001249 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001250 if (opt & OPT_l) decode_format_string("d4");
1251 if (opt & OPT_o) decode_format_string("o2");
Denis Vlasenko601ae132006-11-28 23:37:46 +00001252 while (lst_t) {
Denis Vlasenkod50dda82008-06-15 05:40:56 +00001253 decode_format_string(llist_pop(&lst_t));
Denis Vlasenko601ae132006-11-28 23:37:46 +00001254 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001255 if (opt & OPT_x) decode_format_string("x2");
1256 if (opt & OPT_s) decode_format_string("d2");
1257 if (opt & OPT_S) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001258 G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001259 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001260
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001261 // Bloat:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001262 //if ((option_mask32 & OPT_S) && G.n_specs > 0)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001263 // bb_error_msg_and_die("no type may be specified when dumping strings");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001264
Denis Vlasenko1114de72006-10-10 23:26:05 +00001265 /* If the --traditional option is used, there may be from
Denis Vlasenko601ae132006-11-28 23:37:46 +00001266 * 0 to 3 remaining command line arguments; handle each case
1267 * separately.
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001268 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
Denis Vlasenko601ae132006-11-28 23:37:46 +00001269 * The offset and pseudo_start have the same syntax.
1270 *
1271 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
1272 * traditional syntax even if --traditional is not given. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001273
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001274#if ENABLE_LONG_OPTS
Denis Vlasenko601ae132006-11-28 23:37:46 +00001275 if (opt & OPT_traditional) {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001276 if (argv[0]) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001277 off_t pseudo_start = -1;
1278 off_t o1, o2;
1279
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001280 if (!argv[1]) { /* one arg */
1281 if (parse_old_offset(argv[0], &o1)) {
1282 /* od --traditional OFFSET */
1283 n_bytes_to_skip = o1;
1284 argv++;
1285 }
1286 /* od --traditional FILE */
1287 } else if (!argv[2]) { /* two args */
1288 if (parse_old_offset(argv[0], &o1)
1289 && parse_old_offset(argv[1], &o2)
1290 ) {
1291 /* od --traditional OFFSET LABEL */
1292 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001293 pseudo_start = o2;
1294 argv += 2;
1295 } else if (parse_old_offset(argv[1], &o2)) {
1296 /* od --traditional FILE OFFSET */
1297 n_bytes_to_skip = o2;
1298 argv[1] = NULL;
1299 } else {
1300 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1301 }
1302 } else if (!argv[3]) { /* three args */
1303 if (parse_old_offset(argv[1], &o1)
1304 && parse_old_offset(argv[2], &o2)
1305 ) {
1306 /* od --traditional FILE OFFSET LABEL */
1307 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001308 pseudo_start = o2;
1309 argv[1] = NULL;
1310 } else {
1311 bb_error_msg_and_die("the last two arguments must be offsets");
1312 }
1313 } else { /* >3 args */
1314 bb_error_msg_and_die("too many arguments");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001315 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001316
1317 if (pseudo_start >= 0) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001318 if (G.format_address == format_address_none) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001319 address_base_char = 'o';
1320 address_pad_len_char = '7';
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001321 G.format_address = format_address_paren;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001322 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001323 G.format_address = format_address_label;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001324 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001325 G_pseudo_offset = pseudo_start - n_bytes_to_skip;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001326 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001327 }
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001328 /* else: od --traditional (without args) */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001329 }
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001330#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +00001331
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001332 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001333 end_offset = n_bytes_to_skip + max_bytes_to_format;
1334 if (end_offset < n_bytes_to_skip)
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001335 bb_error_msg_and_die("SKIP + SIZE is too large");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001336 }
1337
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001338 if (G.n_specs == 0) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001339 decode_format_string("o2");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001340 /*G.n_specs = 1; - done by decode_format_string */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001341 }
1342
Denis Vlasenko601ae132006-11-28 23:37:46 +00001343 /* If no files were listed on the command line,
1344 set the global pointer FILE_LIST so that it
1345 references the null-terminated list of one name: "-". */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001346 G.file_list = bb_argv_dash;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001347 if (argv[0]) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001348 /* Set the global pointer FILE_LIST so that it
1349 references the first file-argument on the command-line. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001350 G.file_list = (char const *const *) argv;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001351 }
1352
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001353 /* Open the first input file */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001354 open_next_file();
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001355 /* Skip over any unwanted header bytes */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001356 skip(n_bytes_to_skip);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001357 if (!G.in_stream)
Bernhard Reutner-Fischer7c2db5c2007-11-16 12:39:16 +00001358 return EXIT_FAILURE;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001359
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001360 /* Compute output block length */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001361 l_c_m = get_lcm();
1362
Denis Vlasenko601ae132006-11-28 23:37:46 +00001363 if (opt & OPT_w) { /* -w: width */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001364 if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001365 bb_error_msg("warning: invalid width %u; using %d instead",
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001366 (unsigned)G.bytes_per_block, l_c_m);
1367 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001368 }
1369 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001370 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001371 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001372 G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001373 }
1374
1375#ifdef DEBUG
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001376 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001377 printf("%d: fmt=\"%s\" width=%d\n",
1378 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1379 }
1380#endif
1381
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001382 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001383 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001384 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001385 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001386
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001387 if (fclose(stdin))
Denis Vlasenko601ae132006-11-28 23:37:46 +00001388 bb_perror_msg_and_die(bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001389
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001390 return G.exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001391}