blob: d5bd7bfe8b27af565061ccab7cdd37af6f391d35 [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 Vlasenko036585a2017-08-08 16:38:18 +020064#define OD_GETOPT32() getopt32long(argv, \
65 "A:N:abcdfhij:lot:*vxsS:w:+:", od_longopts, \
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;
Denys Vlasenko31776262018-02-22 12:14:55 +0100214
215 char address_fmt[sizeof("%0n"OFF_FMT"xc")];
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200216} FIX_ALIASING;
Denys Vlasenko31776262018-02-22 12:14:55 +0100217/* Corresponds to 'x' above */
218#define address_base_char G.address_fmt[sizeof(G.address_fmt)-3]
219/* Corresponds to 'n' above */
220#define address_pad_len_char G.address_fmt[2]
221
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200222#if !ENABLE_LONG_OPTS
223enum { G_pseudo_offset = 0 };
224#endif
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200225#define G (*(struct globals*)bb_common_bufsiz1)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200226#define INIT_G() do { \
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200227 setup_common_bufsiz(); \
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200228 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
229 G.bytes_per_block = 32; \
Denys Vlasenko31776262018-02-22 12:14:55 +0100230 strcpy(G.address_fmt, "%0n"OFF_FMT"xc"); \
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200231} while (0)
232
Denis Vlasenko1114de72006-10-10 23:26:05 +0000233
Denis Vlasenko1114de72006-10-10 23:26:05 +0000234#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000235static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000236 [sizeof(char)] = CHAR,
237#if USHRT_MAX != UCHAR_MAX
238 [sizeof(short)] = SHORT,
239#endif
240#if UINT_MAX != USHRT_MAX
241 [sizeof(int)] = INT,
242#endif
243#if ULONG_MAX != UINT_MAX
244 [sizeof(long)] = LONG,
245#endif
246#if ULLONG_MAX != ULONG_MAX
247 [sizeof(ulonglong_t)] = LONG_LONG,
248#endif
249};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000250
251#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000252static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200253 /* gcc seems to allow repeated indexes. Last one wins */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000254 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
255 [sizeof(double)] = FLOAT_DOUBLE,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000256 [sizeof(float)] = FLOAT_SINGLE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000257};
258
259
260static unsigned
261gcd(unsigned u, unsigned v)
262{
263 unsigned t;
264 while (v != 0) {
265 t = u % v;
266 u = v;
267 v = t;
268 }
269 return u;
270}
271
272/* Compute the least common multiple of U and V. */
273static unsigned
274lcm(unsigned u, unsigned v) {
275 unsigned t = gcd(u, v);
276 if (t == 0)
277 return 0;
278 return u * v / t;
279}
280
281static void
282print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
283{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000284 while (n_bytes--) {
285 int tmp = *(signed char *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000286 printf(fmt_string, tmp);
287 block += sizeof(unsigned char);
288 }
289}
290
291static void
292print_char(size_t n_bytes, const char *block, const char *fmt_string)
293{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000294 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000295 unsigned tmp = *(unsigned char *) block;
296 printf(fmt_string, tmp);
297 block += sizeof(unsigned char);
298 }
299}
300
301static void
302print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
303{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000304 n_bytes /= sizeof(signed short);
305 while (n_bytes--) {
306 int tmp = *(signed short *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000307 printf(fmt_string, tmp);
308 block += sizeof(unsigned short);
309 }
310}
311
312static void
313print_short(size_t n_bytes, const char *block, const char *fmt_string)
314{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000315 n_bytes /= sizeof(unsigned short);
316 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000317 unsigned tmp = *(unsigned short *) block;
318 printf(fmt_string, tmp);
319 block += sizeof(unsigned short);
320 }
321}
322
323static void
324print_int(size_t n_bytes, const char *block, const char *fmt_string)
325{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000326 n_bytes /= sizeof(unsigned);
327 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000328 unsigned tmp = *(unsigned *) block;
329 printf(fmt_string, tmp);
330 block += sizeof(unsigned);
331 }
332}
333
Denis Vlasenko601ae132006-11-28 23:37:46 +0000334#if UINT_MAX == ULONG_MAX
335# define print_long print_int
336#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000337static void
338print_long(size_t n_bytes, const char *block, const char *fmt_string)
339{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000340 n_bytes /= sizeof(unsigned long);
341 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000342 unsigned long tmp = *(unsigned long *) block;
343 printf(fmt_string, tmp);
344 block += sizeof(unsigned long);
345 }
346}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000347#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000348
Denis Vlasenko601ae132006-11-28 23:37:46 +0000349#if ULONG_MAX == ULLONG_MAX
350# define print_long_long print_long
351#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000352static void
353print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
354{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000355 n_bytes /= sizeof(ulonglong_t);
356 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000357 ulonglong_t tmp = *(ulonglong_t *) block;
358 printf(fmt_string, tmp);
359 block += sizeof(ulonglong_t);
360 }
361}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000362#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000363
364static void
365print_float(size_t n_bytes, const char *block, const char *fmt_string)
366{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000367 n_bytes /= sizeof(float);
368 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000369 float tmp = *(float *) block;
370 printf(fmt_string, tmp);
371 block += sizeof(float);
372 }
373}
374
375static void
376print_double(size_t n_bytes, const char *block, const char *fmt_string)
377{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000378 n_bytes /= sizeof(double);
379 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000380 double tmp = *(double *) block;
381 printf(fmt_string, tmp);
382 block += sizeof(double);
383 }
384}
385
386static void
387print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
388{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000389 n_bytes /= sizeof(longdouble_t);
390 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000391 longdouble_t tmp = *(longdouble_t *) block;
392 printf(fmt_string, tmp);
393 block += sizeof(longdouble_t);
394 }
395}
396
Denis Vlasenko601ae132006-11-28 23:37:46 +0000397/* print_[named]_ascii are optimized for speed.
Bernhard Reutner-Fischera985d302008-02-11 11:44:38 +0000398 * Remember, someday you may want to pump gigabytes through this thing.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000399 * Saving a dozen of .text bytes here is counter-productive */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000400
401static void
402print_named_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000403 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000404{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000405 /* Names for some non-printing characters. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000406 static const char charname[33][3] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000407 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
408 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
409 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
410 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
411 " sp"
412 };
413 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100414 char buf[12] = " x\0 xxx\0";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000415 // [12] because we take three 32bit stack slots anyway, and
416 // gcc is too dumb to initialize with constant stores,
417 // it copies initializer from rodata. Oh well.
Ron Yorston53e9c512015-03-12 20:10:40 +0100418 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410
Denis Vlasenko1114de72006-10-10 23:26:05 +0000419
Denis Vlasenko601ae132006-11-28 23:37:46 +0000420 while (n_bytes--) {
421 unsigned masked_c = *(unsigned char *) block++;
422
423 masked_c &= 0x7f;
424 if (masked_c == 0x7f) {
425 fputs(" del", stdout);
426 continue;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000427 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000428 if (masked_c > ' ') {
429 buf[3] = masked_c;
430 fputs(buf, stdout);
431 continue;
432 }
433 /* Why? Because printf(" %3.3s") is much slower... */
434 buf[6] = charname[masked_c][0];
435 buf[7] = charname[masked_c][1];
436 buf[8] = charname[masked_c][2];
437 fputs(buf+5, stdout);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000438 }
439}
440
441static void
442print_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000443 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000444{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000445 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100446 char buf[12] = " x\0 xxx\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000447
Denis Vlasenko601ae132006-11-28 23:37:46 +0000448 while (n_bytes--) {
449 const char *s;
450 unsigned c = *(unsigned char *) block++;
451
452 if (ISPRINT(c)) {
453 buf[3] = c;
454 fputs(buf, stdout);
455 continue;
456 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000457 switch (c) {
458 case '\0':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000459 s = " \\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000460 break;
461 case '\007':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000462 s = " \\a";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000463 break;
464 case '\b':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000465 s = " \\b";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000466 break;
467 case '\f':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000468 s = " \\f";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000469 break;
470 case '\n':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000471 s = " \\n";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000472 break;
473 case '\r':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000474 s = " \\r";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000475 break;
476 case '\t':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000477 s = " \\t";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000478 break;
479 case '\v':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000480 s = " \\v";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000481 break;
Ron Yorston53e9c512015-03-12 20:10:40 +0100482 default:
483 buf[6] = (c >> 6 & 3) + '0';
484 buf[7] = (c >> 3 & 7) + '0';
Denis Vlasenko601ae132006-11-28 23:37:46 +0000485 buf[8] = (c & 7) + '0';
486 s = buf + 5;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000487 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000488 fputs(s, stdout);
489 }
490}
Denis Vlasenko1114de72006-10-10 23:26:05 +0000491
Denis Vlasenko601ae132006-11-28 23:37:46 +0000492/* Given a list of one or more input filenames FILE_LIST, set the global
493 file pointer IN_STREAM and the global string INPUT_FILENAME to the
494 first one that can be successfully opened. Modify FILE_LIST to
495 reference the next filename in the list. A file name of "-" is
496 interpreted as standard input. If any file open fails, give an error
497 message and return nonzero. */
498
499static void
500open_next_file(void)
501{
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000502 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200503 if (!*G.file_list)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000504 return;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200505 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
506 if (G.in_stream) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000507 break;
508 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200509 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000510 }
511
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200512 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200513 setbuf(G.in_stream, NULL);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000514}
515
516/* Test whether there have been errors on in_stream, and close it if
517 it is not standard input. Return nonzero if there has been an error
518 on in_stream or stdout; return zero otherwise. This function will
519 report more than one error only if both a read and a write error
520 have occurred. IN_ERRNO, if nonzero, is the error number
521 corresponding to the most recent action for IN_STREAM. */
522
523static void
524check_and_close(void)
525{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200526 if (G.in_stream) {
527 if (ferror(G.in_stream)) {
528 bb_error_msg("%s: read error", (G.in_stream == stdin)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000529 ? bb_msg_standard_input
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200530 : G.file_list[-1]
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000531 );
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200532 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000533 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200534 fclose_if_not_stdin(G.in_stream);
535 G.in_stream = NULL;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000536 }
537
538 if (ferror(stdout)) {
James Byrne69374872019-07-02 11:35:03 +0200539 bb_simple_error_msg_and_die(bb_msg_write_error);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000540 }
541}
542
543/* If S points to a single valid modern od format string, put
Denis Vlasenko7089c312008-04-14 19:50:06 +0000544 a description of that format in *TSPEC, return pointer to
545 character following the just-decoded format.
546 For example, if S were "d4afL", we will return a rtp to "afL"
547 and *TSPEC would be
Denis Vlasenko1114de72006-10-10 23:26:05 +0000548 {
549 fmt = SIGNED_DECIMAL;
550 size = INT or LONG; (whichever integral_type_size[4] resolves to)
551 print_function = print_int; (assuming size == INT)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000552 fmt_string = "%011d%c";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000553 }
554 S_ORIG is solely for reporting errors. It should be the full format
Denis Vlasenko601ae132006-11-28 23:37:46 +0000555 string argument. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000556
Denys Vlasenkob9542cb2010-06-01 23:16:46 +0200557static NOINLINE const char *
Denis Vlasenko7089c312008-04-14 19:50:06 +0000558decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000559{
560 enum size_spec size_spec;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000561 unsigned size;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000562 enum output_format fmt;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000563 const char *p;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000564 char *end;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000565 char *fmt_string = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000566 void (*print_function) (size_t, const char *, const char *);
567 unsigned c;
568 unsigned field_width = 0;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000569 int pos;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000570
Denis Vlasenko1114de72006-10-10 23:26:05 +0000571 switch (*s) {
572 case 'd':
573 case 'o':
574 case 'u':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000575 case 'x': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000576 static const char CSIL[] ALIGN1 = "CSIL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000577
578 c = *s++;
579 p = strchr(CSIL, *s);
Denys Vlasenko11f3a8b2009-11-22 15:37:16 +0100580 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
581 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000582 size = sizeof(int);
583 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000584 size = bb_strtou(s, &end, 0);
585 if (errno == ERANGE
586 || MAX_INTEGRAL_TYPE_SIZE < size
Denis Vlasenko1114de72006-10-10 23:26:05 +0000587 || integral_type_size[size] == NO_SIZE
588 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000589 bb_error_msg_and_die("invalid type string '%s'; "
590 "%u-byte %s type is not supported",
591 s_orig, size, "integral");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000592 }
593 s = end;
594 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000595 } else {
Denis Vlasenko7089c312008-04-14 19:50:06 +0000596 static const uint8_t CSIL_sizeof[4] = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000597 sizeof(char),
598 sizeof(short),
599 sizeof(int),
600 sizeof(long),
601 };
602 size = CSIL_sizeof[p - CSIL];
Denis Vlasenko7089c312008-04-14 19:50:06 +0000603 s++; /* skip C/S/I/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000604 }
605
606#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
607 ((Spec) == LONG_LONG ? (Max_format) \
608 : ((Spec) == LONG ? (Long_format) : (Min_format)))
609
610#define FMT_BYTES_ALLOCATED 9
Denis Vlasenko1114de72006-10-10 23:26:05 +0000611 size_spec = integral_type_size[size];
612
Denis Vlasenko601ae132006-11-28 23:37:46 +0000613 {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000614 static const char doux[] ALIGN1 = "doux";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000615 static const char doux_fmt_letter[][4] = {
616 "lld", "llo", "llu", "llx"
617 };
618 static const enum output_format doux_fmt[] = {
619 SIGNED_DECIMAL,
620 OCTAL,
621 UNSIGNED_DECIMAL,
622 HEXADECIMAL,
623 };
624 static const uint8_t *const doux_bytes_to_XXX[] = {
625 bytes_to_signed_dec_digits,
626 bytes_to_oct_digits,
627 bytes_to_unsigned_dec_digits,
628 bytes_to_hex_digits,
629 };
Denys Vlasenko965b7952020-11-30 13:03:03 +0100630 static const char doux_fmtstring[][sizeof(" %%0%u%s")] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000631 " %%%u%s",
632 " %%0%u%s",
633 " %%%u%s",
634 " %%0%u%s",
635 };
Denis Vlasenko1114de72006-10-10 23:26:05 +0000636
Denis Vlasenko601ae132006-11-28 23:37:46 +0000637 pos = strchr(doux, c) - doux;
638 fmt = doux_fmt[pos];
639 field_width = doux_bytes_to_XXX[pos][size];
640 p = doux_fmt_letter[pos] + 2;
641 if (size_spec == LONG) p--;
642 if (size_spec == LONG_LONG) p -= 2;
643 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
644 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000645
646 switch (size_spec) {
647 case CHAR:
648 print_function = (fmt == SIGNED_DECIMAL
649 ? print_s_char
650 : print_char);
651 break;
652 case SHORT:
653 print_function = (fmt == SIGNED_DECIMAL
654 ? print_s_short
655 : print_short);
656 break;
657 case INT:
658 print_function = print_int;
659 break;
660 case LONG:
661 print_function = print_long;
662 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000663 default: /* case LONG_LONG: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000664 print_function = print_long_long;
665 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000666 }
667 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000668 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000669
Denis Vlasenko601ae132006-11-28 23:37:46 +0000670 case 'f': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000671 static const char FDL[] ALIGN1 = "FDL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000672
Denis Vlasenko1114de72006-10-10 23:26:05 +0000673 fmt = FLOATING_POINT;
674 ++s;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000675 p = strchr(FDL, *s);
Ron Yorstona1656032017-07-19 10:43:10 +0100676 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000677 size = sizeof(double);
678 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000679 size = bb_strtou(s, &end, 0);
680 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000681 || fp_type_size[size] == NO_SIZE
682 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000683 bb_error_msg_and_die("invalid type string '%s'; "
684 "%u-byte %s type is not supported",
685 s_orig, size, "floating point");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000686 }
687 s = end;
688 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000689 } else {
690 static const uint8_t FDL_sizeof[] = {
691 sizeof(float),
692 sizeof(double),
693 sizeof(longdouble_t),
694 };
695
696 size = FDL_sizeof[p - FDL];
Ron Yorstona1656032017-07-19 10:43:10 +0100697 s++; /* skip F/D/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000698 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000699
Denis Vlasenko1114de72006-10-10 23:26:05 +0000700 size_spec = fp_type_size[size];
701
702 switch (size_spec) {
703 case FLOAT_SINGLE:
704 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000705 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000706 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000707 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000708 break;
709 case FLOAT_DOUBLE:
710 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000711 field_width = DBL_DIG + 8;
712 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000713 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000714 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000715 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000716 field_width = LDBL_DIG + 8;
717 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000718 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000719 }
720 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000721 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000722
723 case 'a':
724 ++s;
725 fmt = NAMED_CHARACTER;
726 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000727 print_function = print_named_ascii;
728 field_width = 3;
729 break;
730 case 'c':
731 ++s;
732 fmt = CHARACTER;
733 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000734 print_function = print_ascii;
735 field_width = 3;
736 break;
737 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000738 bb_error_msg_and_die("invalid character '%c' "
739 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000740 }
741
742 tspec->size = size_spec;
743 tspec->fmt = fmt;
744 tspec->print_function = print_function;
745 tspec->fmt_string = fmt_string;
746
747 tspec->field_width = field_width;
748 tspec->hexl_mode_trailer = (*s == 'z');
749 if (tspec->hexl_mode_trailer)
750 s++;
751
Denis Vlasenko7089c312008-04-14 19:50:06 +0000752 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000753}
754
755/* Decode the modern od format string S. Append the decoded
756 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000757 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000758
Denis Vlasenko601ae132006-11-28 23:37:46 +0000759static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000760decode_format_string(const char *s)
761{
762 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000763
764 while (*s != '\0') {
765 struct tspec tspec;
766 const char *next;
767
Denis Vlasenko7089c312008-04-14 19:50:06 +0000768 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000769
770 assert(s != next);
771 s = next;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200772 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
773 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
774 G.n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000775 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000776}
777
778/* Given a list of one or more input filenames FILE_LIST, set the global
779 file pointer IN_STREAM to position N_SKIP in the concatenation of
780 those files. If any file operation fails or if there are fewer than
781 N_SKIP bytes in the combined input, give an error message and return
782 nonzero. When possible, use seek rather than read operations to
783 advance IN_STREAM. */
784
Denis Vlasenko601ae132006-11-28 23:37:46 +0000785static void
786skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000787{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000788 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000789 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000790
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200791 while (G.in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000792 struct stat file_stats;
793
794 /* First try seeking. For large offsets, this extra work is
795 worthwhile. If the offset is below some threshold it may be
796 more efficient to move the pointer by reading. There are two
797 issues when trying to seek:
798 - the file must be seekable.
799 - before seeking to the specified position, make sure
800 that the new position is in the current file.
801 Try to do that by getting file's size using fstat.
802 But that will work only for regular files. */
803
Denis Vlasenko1114de72006-10-10 23:26:05 +0000804 /* The st_size field is valid only for regular files
805 (and for symbolic links, which cannot occur here).
806 If the number of bytes left to skip is at least
807 as large as the size of the current file, we can
808 decrement n_skip and go on to the next file. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200809 if (fstat(fileno(G.in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000810 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000811 ) {
812 if (file_stats.st_size < n_skip) {
813 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000814 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000815 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200816 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
817 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000818 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000819 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000820 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000821 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000822 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000823 char buf[1024];
824 size_t n_bytes_to_read = 1024;
825 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000826
Denis Vlasenko601ae132006-11-28 23:37:46 +0000827 while (n_skip > 0) {
828 if (n_skip < n_bytes_to_read)
829 n_bytes_to_read = n_skip;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200830 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000831 n_skip -= n_bytes_read;
832 if (n_bytes_read != n_bytes_to_read)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000833 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000834 }
835 }
836 if (n_skip == 0)
837 return;
838
839 check_and_close();
840 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000841 }
842
Denis Vlasenko601ae132006-11-28 23:37:46 +0000843 if (n_skip)
James Byrne69374872019-07-02 11:35:03 +0200844 bb_simple_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000845}
846
Denis Vlasenko601ae132006-11-28 23:37:46 +0000847
848typedef void FN_format_address(off_t address, char c);
849
Denis Vlasenko1114de72006-10-10 23:26:05 +0000850static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000851format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000852{
853}
854
855static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000856format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000857{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000858 /* Corresponds to 'c' */
Denys Vlasenko31776262018-02-22 12:14:55 +0100859 G.address_fmt[sizeof(G.address_fmt)-2] = c;
860 printf(G.address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000861}
862
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200863#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000864/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000865static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000866format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000867{
868 putchar('(');
869 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000870 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000871}
872
873static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000874format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000875{
876 format_address_std(address, ' ');
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200877 format_address_paren(address + G_pseudo_offset, c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000878}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000879#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000880
881static void
882dump_hexl_mode_trailer(size_t n_bytes, const char *block)
883{
884 fputs(" >", stdout);
885 while (n_bytes--) {
886 unsigned c = *(unsigned char *) block++;
887 c = (ISPRINT(c) ? c : '.');
888 putchar(c);
889 }
890 putchar('<');
891}
892
Denis Vlasenko1114de72006-10-10 23:26:05 +0000893/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
894 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
895 CURR_BLOCK in the concatenation of input files, and it is printed
896 (optionally) only before the output line associated with the first
897 format spec. When duplicate blocks are being abbreviated, the output
898 for a sequence of identical input blocks is the output for the first
899 block followed by an asterisk alone on a line. It is valid to compare
900 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
901 That condition may be false only for the last input block -- and then
902 only when it has not been padded to length BYTES_PER_BLOCK. */
903
904static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000905write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000906 const char *prev_block, const char *curr_block)
907{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200908 unsigned i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000909
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200910 if (!(option_mask32 & OPT_v)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200911 && G.not_first
912 && n_bytes == G.bytes_per_block
913 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
Denis Vlasenko1114de72006-10-10 23:26:05 +0000914 ) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200915 if (G.prev_pair_equal) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000916 /* The two preceding blocks were equal, and the current
917 block is the same as the last one, so print nothing. */
918 } else {
919 puts("*");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200920 G.prev_pair_equal = 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000921 }
922 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200923 G.not_first = 1;
924 G.prev_pair_equal = 0;
925 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000926 if (i == 0)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200927 G.format_address(current_offset, '\0');
Denis Vlasenko1114de72006-10-10 23:26:05 +0000928 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000929 printf("%*s", address_pad_len_char - '0', "");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200930 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
931 if (G.spec[i].hexl_mode_trailer) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000932 /* space-pad out to full line width, then dump the trailer */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200933 unsigned datum_width = width_bytes[G.spec[i].size];
934 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
935 unsigned field_width = G.spec[i].field_width + 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000936 printf("%*s", blank_fields * field_width, "");
937 dump_hexl_mode_trailer(n_bytes, curr_block);
938 }
939 putchar('\n');
940 }
941 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000942}
943
Denis Vlasenko601ae132006-11-28 23:37:46 +0000944static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000945read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
946{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200947 assert(0 < n && n <= G.bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000948
949 *n_bytes_in_buffer = 0;
950
951 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000952 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000953
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200954 while (G.in_stream != NULL) { /* EOF. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000955 size_t n_needed;
956 size_t n_read;
957
958 n_needed = n - *n_bytes_in_buffer;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200959 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000960 *n_bytes_in_buffer += n_read;
961 if (n_read == n_needed)
962 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000963 /* error check is done in check_and_close */
964 check_and_close();
965 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000966 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000967}
968
969/* Return the least common multiple of the sizes associated
970 with the format specs. */
971
972static int
973get_lcm(void)
974{
975 size_t i;
976 int l_c_m = 1;
977
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200978 for (i = 0; i < G.n_specs; i++)
979 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000980 return l_c_m;
981}
982
Denis Vlasenko1114de72006-10-10 23:26:05 +0000983/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
984 formatted block to standard output, and repeat until the specified
985 maximum number of bytes has been read or until all input has been
986 processed. If the last block read is smaller than BYTES_PER_BLOCK
987 and its size is not a multiple of the size associated with a format
988 spec, extend the input block with zero bytes until its length is a
989 multiple of all format spec sizes. Write the final block. Finally,
990 write on a line by itself the offset of the byte after the last byte
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000991 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000992
Denis Vlasenko601ae132006-11-28 23:37:46 +0000993static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000994dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000995{
996 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000997 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000998 size_t n_bytes_read;
999
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001000 block[0] = xmalloc(2 * G.bytes_per_block);
1001 block[1] = block[0] + G.bytes_per_block;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001002
Denis Vlasenko1114de72006-10-10 23:26:05 +00001003 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001004 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001005 while (1) {
1006 size_t n_needed;
1007 if (current_offset >= end_offset) {
1008 n_bytes_read = 0;
1009 break;
1010 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001011 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001012 read_block(n_needed, block[idx], &n_bytes_read);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001013 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001014 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001015 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001016 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001017 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001018 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001019 }
1020 } else {
1021 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001022 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1023 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001024 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001025 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001026 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001027 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001028 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001029 }
1030 }
1031
1032 if (n_bytes_read > 0) {
1033 int l_c_m;
1034 size_t bytes_to_write;
1035
1036 l_c_m = get_lcm();
1037
1038 /* Make bytes_to_write the smallest multiple of l_c_m that
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001039 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001040 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1041
1042 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1043 write_block(current_offset, bytes_to_write,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001044 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001045 current_offset += n_bytes_read;
1046 }
1047
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001048 G.format_address(current_offset, '\n');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001049
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001050 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001051 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001052
1053 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001054}
1055
Denis Vlasenko601ae132006-11-28 23:37:46 +00001056/* Read N bytes into BLOCK from the concatenation of the input files
1057 named in the global array FILE_LIST. On the first call to this
1058 function, the global variable IN_STREAM is expected to be an open
1059 stream associated with the input file INPUT_FILENAME. If all N
1060 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1061 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1062 read the remaining bytes from the newly opened file. Repeat if
1063 necessary until EOF is reached for the last file in FILE_LIST.
1064 On subsequent calls, don't modify BLOCK and return zero. Set
1065 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1066 it will be detected through ferror when the stream is about to be
1067 closed. If there is an error, give a message but continue reading
1068 as usual and return nonzero. Otherwise return zero. */
1069
Denis Vlasenko1114de72006-10-10 23:26:05 +00001070/* STRINGS mode. Find each "string constant" in the input.
1071 A string constant is a run of at least 'string_min' ASCII
1072 graphic (or formatting) characters terminated by a null.
1073 Based on a function written by Richard Stallman for a
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001074 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001075
Denis Vlasenko601ae132006-11-28 23:37:46 +00001076static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001077dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001078{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001079 unsigned bufsize = MAX(100, G.string_min);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001080 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001081
Denis Vlasenko1114de72006-10-10 23:26:05 +00001082 while (1) {
1083 size_t i;
1084 int c;
1085
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001086 /* See if the next 'G.string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001087 tryline:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001088 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001089 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001090 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001091 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001092 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001093 bufsize += bufsize/8;
1094 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001095 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001096
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001097 while (G.in_stream) { /* !EOF */
1098 c = fgetc(G.in_stream);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001099 if (c != EOF)
1100 goto got_char;
1101 check_and_close();
1102 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001103 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001104 /* EOF */
1105 goto ret;
1106 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001107 address++;
1108 if (!c)
1109 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001110 if (!ISPRINT(c))
1111 goto tryline; /* It isn't; give up on this string. */
1112 buf[i++] = c; /* String continues; store it all. */
1113 }
1114
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001115 if (i < G.string_min) /* Too short! */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001116 goto tryline;
1117
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001118 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001119 buf[i] = 0;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001120 G.format_address(address - i - 1, ' ');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001121
1122 for (i = 0; (c = buf[i]); i++) {
1123 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001124 case '\007': fputs("\\a", stdout); break;
1125 case '\b': fputs("\\b", stdout); break;
1126 case '\f': fputs("\\f", stdout); break;
1127 case '\n': fputs("\\n", stdout); break;
1128 case '\r': fputs("\\r", stdout); break;
1129 case '\t': fputs("\\t", stdout); break;
1130 case '\v': fputs("\\v", stdout); break;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001131 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001132 }
1133 }
1134 putchar('\n');
1135 }
1136
1137 /* We reach this point only if we search through
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001138 (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001139 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001140 ret:
1141 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001142}
1143
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001144#if ENABLE_LONG_OPTS
1145/* If S is a valid traditional offset specification with an optional
1146 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1147
1148static int
1149parse_old_offset(const char *s, off_t *offset)
1150{
Denys Vlasenko965b7952020-11-30 13:03:03 +01001151 static const struct suffix_mult Bb[] ALIGN_SUFFIX = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001152 { "B", 1024 },
1153 { "b", 512 },
1154 { "", 0 }
1155 };
1156 char *p;
1157 int radix;
1158
1159 /* Skip over any leading '+'. */
1160 if (s[0] == '+') ++s;
1161 if (!isdigit(s[0])) return 0; /* not a number */
1162
1163 /* Determine the radix we'll use to interpret S. If there is a '.',
1164 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1165 * it's hexadecimal, else octal. */
1166 p = strchr(s, '.');
1167 radix = 8;
1168 if (p) {
1169 p[0] = '\0'; /* cheating */
1170 radix = 10;
1171 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1172 radix = 16;
1173
1174 *offset = xstrtooff_sfx(s, radix, Bb);
1175 if (p) p[0] = '.';
1176
1177 return (*offset >= 0);
1178}
1179#endif
1180
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001181int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001182int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001183{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001184#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001185 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001186 "skip-bytes\0" Required_argument "j"
1187 "address-radix\0" Required_argument "A"
1188 "read-bytes\0" Required_argument "N"
1189 "format\0" Required_argument "t"
1190 "output-duplicates\0" No_argument "v"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001191 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1192 * that is, NUM is mandatory for -S but optional for --strings!
1193 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001194 "strings\0" Optional_argument "S"
1195 "width\0" Optional_argument "w"
1196 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001197 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001198#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001199 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001200 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001201 unsigned opt;
1202 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001203 /* The number of input bytes to skip before formatting and writing. */
1204 off_t n_bytes_to_skip = 0;
1205 /* The offset of the first byte after the last byte to be formatted. */
1206 off_t end_offset = 0;
1207 /* The maximum number of bytes that will be formatted. */
1208 off_t max_bytes_to_format = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001209
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001210 INIT_G();
1211
1212 /*G.spec = NULL; - already is */
1213 G.format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001214 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001215 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001216
Denis Vlasenko601ae132006-11-28 23:37:46 +00001217 /* Parse command line */
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 {
James Byrne69374872019-07-02 11:35:03 +02001311 bb_simple_error_msg_and_die("the last two arguments must be offsets");
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001312 }
1313 } else { /* >3 args */
James Byrne69374872019-07-02 11:35:03 +02001314 bb_simple_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)
James Byrne69374872019-07-02 11:35:03 +02001335 bb_simple_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 Vlasenko2b9a45b2018-01-23 14:49:12 +01001376 {
1377 int i;
1378 for (i = 0; i < G.n_specs; i++) {
1379 printf("%d: fmt='%s' width=%d\n",
1380 i, G.spec[i].fmt_string,
1381 width_bytes[G.spec[i].size]);
1382 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001383 }
1384#endif
1385
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001386 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001387 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001388 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001389 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001390
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001391 if (fclose(stdin))
James Byrne69374872019-07-02 11:35:03 +02001392 bb_simple_perror_msg_and_die(bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001393
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001394 return G.exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001395}