blob: fa0196ca4fba398106962eabf7ce62dbe39c213b [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);
Ron Yorstona1656032017-07-19 10:43:10 +0100668 if (!p || *p == '\0') {
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];
Ron Yorstona1656032017-07-19 10:43:10 +0100689 s++; /* skip F/D/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000690 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000691
Denis Vlasenko1114de72006-10-10 23:26:05 +0000692 size_spec = fp_type_size[size];
693
694 switch (size_spec) {
695 case FLOAT_SINGLE:
696 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000697 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000698 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000699 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000700 break;
701 case FLOAT_DOUBLE:
702 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000703 field_width = DBL_DIG + 8;
704 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000705 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000706 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000707 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000708 field_width = LDBL_DIG + 8;
709 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000710 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000711 }
712 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000713 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000714
715 case 'a':
716 ++s;
717 fmt = NAMED_CHARACTER;
718 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000719 print_function = print_named_ascii;
720 field_width = 3;
721 break;
722 case 'c':
723 ++s;
724 fmt = CHARACTER;
725 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000726 print_function = print_ascii;
727 field_width = 3;
728 break;
729 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000730 bb_error_msg_and_die("invalid character '%c' "
731 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000732 }
733
734 tspec->size = size_spec;
735 tspec->fmt = fmt;
736 tspec->print_function = print_function;
737 tspec->fmt_string = fmt_string;
738
739 tspec->field_width = field_width;
740 tspec->hexl_mode_trailer = (*s == 'z');
741 if (tspec->hexl_mode_trailer)
742 s++;
743
Denis Vlasenko7089c312008-04-14 19:50:06 +0000744 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000745}
746
747/* Decode the modern od format string S. Append the decoded
748 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000749 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000750
Denis Vlasenko601ae132006-11-28 23:37:46 +0000751static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000752decode_format_string(const char *s)
753{
754 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000755
756 while (*s != '\0') {
757 struct tspec tspec;
758 const char *next;
759
Denis Vlasenko7089c312008-04-14 19:50:06 +0000760 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000761
762 assert(s != next);
763 s = next;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200764 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
765 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
766 G.n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000767 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000768}
769
770/* Given a list of one or more input filenames FILE_LIST, set the global
771 file pointer IN_STREAM to position N_SKIP in the concatenation of
772 those files. If any file operation fails or if there are fewer than
773 N_SKIP bytes in the combined input, give an error message and return
774 nonzero. When possible, use seek rather than read operations to
775 advance IN_STREAM. */
776
Denis Vlasenko601ae132006-11-28 23:37:46 +0000777static void
778skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000779{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000780 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000781 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000782
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200783 while (G.in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000784 struct stat file_stats;
785
786 /* First try seeking. For large offsets, this extra work is
787 worthwhile. If the offset is below some threshold it may be
788 more efficient to move the pointer by reading. There are two
789 issues when trying to seek:
790 - the file must be seekable.
791 - before seeking to the specified position, make sure
792 that the new position is in the current file.
793 Try to do that by getting file's size using fstat.
794 But that will work only for regular files. */
795
Denis Vlasenko1114de72006-10-10 23:26:05 +0000796 /* The st_size field is valid only for regular files
797 (and for symbolic links, which cannot occur here).
798 If the number of bytes left to skip is at least
799 as large as the size of the current file, we can
800 decrement n_skip and go on to the next file. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200801 if (fstat(fileno(G.in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000802 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000803 ) {
804 if (file_stats.st_size < n_skip) {
805 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000806 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000807 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200808 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
809 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000810 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000811 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000812 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000813 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000814 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000815 char buf[1024];
816 size_t n_bytes_to_read = 1024;
817 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000818
Denis Vlasenko601ae132006-11-28 23:37:46 +0000819 while (n_skip > 0) {
820 if (n_skip < n_bytes_to_read)
821 n_bytes_to_read = n_skip;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200822 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000823 n_skip -= n_bytes_read;
824 if (n_bytes_read != n_bytes_to_read)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000825 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000826 }
827 }
828 if (n_skip == 0)
829 return;
830
831 check_and_close();
832 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000833 }
834
Denis Vlasenko601ae132006-11-28 23:37:46 +0000835 if (n_skip)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100836 bb_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000837}
838
Denis Vlasenko601ae132006-11-28 23:37:46 +0000839
840typedef void FN_format_address(off_t address, char c);
841
Denis Vlasenko1114de72006-10-10 23:26:05 +0000842static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000843format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000844{
845}
846
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000847static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000848/* Corresponds to 'x' above */
849#define address_base_char address_fmt[sizeof(address_fmt)-3]
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000850/* Corresponds to 'n' above */
851#define address_pad_len_char address_fmt[2]
Denis Vlasenko601ae132006-11-28 23:37:46 +0000852
Denis Vlasenko1114de72006-10-10 23:26:05 +0000853static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000854format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000855{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000856 /* Corresponds to 'c' */
857 address_fmt[sizeof(address_fmt)-2] = c;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000858 printf(address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000859}
860
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200861#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000862/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000863static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000864format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000865{
866 putchar('(');
867 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000868 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000869}
870
871static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000872format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000873{
874 format_address_std(address, ' ');
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200875 format_address_paren(address + G_pseudo_offset, c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000876}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000877#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000878
879static void
880dump_hexl_mode_trailer(size_t n_bytes, const char *block)
881{
882 fputs(" >", stdout);
883 while (n_bytes--) {
884 unsigned c = *(unsigned char *) block++;
885 c = (ISPRINT(c) ? c : '.');
886 putchar(c);
887 }
888 putchar('<');
889}
890
Denis Vlasenko1114de72006-10-10 23:26:05 +0000891/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
892 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
893 CURR_BLOCK in the concatenation of input files, and it is printed
894 (optionally) only before the output line associated with the first
895 format spec. When duplicate blocks are being abbreviated, the output
896 for a sequence of identical input blocks is the output for the first
897 block followed by an asterisk alone on a line. It is valid to compare
898 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
899 That condition may be false only for the last input block -- and then
900 only when it has not been padded to length BYTES_PER_BLOCK. */
901
902static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000903write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000904 const char *prev_block, const char *curr_block)
905{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200906 unsigned i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000907
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200908 if (!(option_mask32 & OPT_v)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200909 && G.not_first
910 && n_bytes == G.bytes_per_block
911 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
Denis Vlasenko1114de72006-10-10 23:26:05 +0000912 ) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200913 if (G.prev_pair_equal) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000914 /* The two preceding blocks were equal, and the current
915 block is the same as the last one, so print nothing. */
916 } else {
917 puts("*");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200918 G.prev_pair_equal = 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000919 }
920 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200921 G.not_first = 1;
922 G.prev_pair_equal = 0;
923 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000924 if (i == 0)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200925 G.format_address(current_offset, '\0');
Denis Vlasenko1114de72006-10-10 23:26:05 +0000926 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000927 printf("%*s", address_pad_len_char - '0', "");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200928 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
929 if (G.spec[i].hexl_mode_trailer) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000930 /* space-pad out to full line width, then dump the trailer */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200931 unsigned datum_width = width_bytes[G.spec[i].size];
932 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
933 unsigned field_width = G.spec[i].field_width + 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000934 printf("%*s", blank_fields * field_width, "");
935 dump_hexl_mode_trailer(n_bytes, curr_block);
936 }
937 putchar('\n');
938 }
939 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000940}
941
Denis Vlasenko601ae132006-11-28 23:37:46 +0000942static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000943read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
944{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200945 assert(0 < n && n <= G.bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000946
947 *n_bytes_in_buffer = 0;
948
949 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000950 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000951
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200952 while (G.in_stream != NULL) { /* EOF. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000953 size_t n_needed;
954 size_t n_read;
955
956 n_needed = n - *n_bytes_in_buffer;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200957 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000958 *n_bytes_in_buffer += n_read;
959 if (n_read == n_needed)
960 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000961 /* error check is done in check_and_close */
962 check_and_close();
963 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000964 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000965}
966
967/* Return the least common multiple of the sizes associated
968 with the format specs. */
969
970static int
971get_lcm(void)
972{
973 size_t i;
974 int l_c_m = 1;
975
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200976 for (i = 0; i < G.n_specs; i++)
977 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000978 return l_c_m;
979}
980
Denis Vlasenko1114de72006-10-10 23:26:05 +0000981/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
982 formatted block to standard output, and repeat until the specified
983 maximum number of bytes has been read or until all input has been
984 processed. If the last block read is smaller than BYTES_PER_BLOCK
985 and its size is not a multiple of the size associated with a format
986 spec, extend the input block with zero bytes until its length is a
987 multiple of all format spec sizes. Write the final block. Finally,
988 write on a line by itself the offset of the byte after the last byte
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000989 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000990
Denis Vlasenko601ae132006-11-28 23:37:46 +0000991static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000992dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000993{
994 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000995 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000996 size_t n_bytes_read;
997
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200998 block[0] = xmalloc(2 * G.bytes_per_block);
999 block[1] = block[0] + G.bytes_per_block;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001000
Denis Vlasenko1114de72006-10-10 23:26:05 +00001001 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001002 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001003 while (1) {
1004 size_t n_needed;
1005 if (current_offset >= end_offset) {
1006 n_bytes_read = 0;
1007 break;
1008 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001009 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001010 read_block(n_needed, block[idx], &n_bytes_read);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001011 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001012 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001013 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001014 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001015 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001016 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001017 }
1018 } else {
1019 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001020 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1021 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001022 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001023 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001024 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001025 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001026 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001027 }
1028 }
1029
1030 if (n_bytes_read > 0) {
1031 int l_c_m;
1032 size_t bytes_to_write;
1033
1034 l_c_m = get_lcm();
1035
1036 /* Make bytes_to_write the smallest multiple of l_c_m that
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001037 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001038 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1039
1040 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1041 write_block(current_offset, bytes_to_write,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001042 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001043 current_offset += n_bytes_read;
1044 }
1045
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001046 G.format_address(current_offset, '\n');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001047
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001048 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001049 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001050
1051 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001052}
1053
Denis Vlasenko601ae132006-11-28 23:37:46 +00001054/* Read N bytes into BLOCK from the concatenation of the input files
1055 named in the global array FILE_LIST. On the first call to this
1056 function, the global variable IN_STREAM is expected to be an open
1057 stream associated with the input file INPUT_FILENAME. If all N
1058 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1059 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1060 read the remaining bytes from the newly opened file. Repeat if
1061 necessary until EOF is reached for the last file in FILE_LIST.
1062 On subsequent calls, don't modify BLOCK and return zero. Set
1063 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1064 it will be detected through ferror when the stream is about to be
1065 closed. If there is an error, give a message but continue reading
1066 as usual and return nonzero. Otherwise return zero. */
1067
Denis Vlasenko1114de72006-10-10 23:26:05 +00001068/* STRINGS mode. Find each "string constant" in the input.
1069 A string constant is a run of at least 'string_min' ASCII
1070 graphic (or formatting) characters terminated by a null.
1071 Based on a function written by Richard Stallman for a
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001072 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001073
Denis Vlasenko601ae132006-11-28 23:37:46 +00001074static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001075dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001076{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001077 unsigned bufsize = MAX(100, G.string_min);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001078 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001079
Denis Vlasenko1114de72006-10-10 23:26:05 +00001080 while (1) {
1081 size_t i;
1082 int c;
1083
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001084 /* See if the next 'G.string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001085 tryline:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001086 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001087 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001088 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001089 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001090 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001091 bufsize += bufsize/8;
1092 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001093 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001094
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001095 while (G.in_stream) { /* !EOF */
1096 c = fgetc(G.in_stream);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001097 if (c != EOF)
1098 goto got_char;
1099 check_and_close();
1100 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001101 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001102 /* EOF */
1103 goto ret;
1104 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001105 address++;
1106 if (!c)
1107 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001108 if (!ISPRINT(c))
1109 goto tryline; /* It isn't; give up on this string. */
1110 buf[i++] = c; /* String continues; store it all. */
1111 }
1112
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001113 if (i < G.string_min) /* Too short! */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001114 goto tryline;
1115
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001116 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001117 buf[i] = 0;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001118 G.format_address(address - i - 1, ' ');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001119
1120 for (i = 0; (c = buf[i]); i++) {
1121 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001122 case '\007': fputs("\\a", stdout); break;
1123 case '\b': fputs("\\b", stdout); break;
1124 case '\f': fputs("\\f", stdout); break;
1125 case '\n': fputs("\\n", stdout); break;
1126 case '\r': fputs("\\r", stdout); break;
1127 case '\t': fputs("\\t", stdout); break;
1128 case '\v': fputs("\\v", stdout); break;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001129 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001130 }
1131 }
1132 putchar('\n');
1133 }
1134
1135 /* We reach this point only if we search through
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001136 (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001137 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001138 ret:
1139 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001140}
1141
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001142#if ENABLE_LONG_OPTS
1143/* If S is a valid traditional offset specification with an optional
1144 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1145
1146static int
1147parse_old_offset(const char *s, off_t *offset)
1148{
1149 static const struct suffix_mult Bb[] = {
1150 { "B", 1024 },
1151 { "b", 512 },
1152 { "", 0 }
1153 };
1154 char *p;
1155 int radix;
1156
1157 /* Skip over any leading '+'. */
1158 if (s[0] == '+') ++s;
1159 if (!isdigit(s[0])) return 0; /* not a number */
1160
1161 /* Determine the radix we'll use to interpret S. If there is a '.',
1162 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1163 * it's hexadecimal, else octal. */
1164 p = strchr(s, '.');
1165 radix = 8;
1166 if (p) {
1167 p[0] = '\0'; /* cheating */
1168 radix = 10;
1169 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1170 radix = 16;
1171
1172 *offset = xstrtooff_sfx(s, radix, Bb);
1173 if (p) p[0] = '.';
1174
1175 return (*offset >= 0);
1176}
1177#endif
1178
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001179int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001180int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001181{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001182#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001183 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001184 "skip-bytes\0" Required_argument "j"
1185 "address-radix\0" Required_argument "A"
1186 "read-bytes\0" Required_argument "N"
1187 "format\0" Required_argument "t"
1188 "output-duplicates\0" No_argument "v"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001189 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1190 * that is, NUM is mandatory for -S but optional for --strings!
1191 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001192 "strings\0" Optional_argument "S"
1193 "width\0" Optional_argument "w"
1194 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001195 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001196#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001197 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001198 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001199 unsigned opt;
1200 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001201 /* The number of input bytes to skip before formatting and writing. */
1202 off_t n_bytes_to_skip = 0;
1203 /* The offset of the first byte after the last byte to be formatted. */
1204 off_t end_offset = 0;
1205 /* The maximum number of bytes that will be formatted. */
1206 off_t max_bytes_to_format = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001207
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001208 INIT_G();
1209
1210 /*G.spec = NULL; - already is */
1211 G.format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001212 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001213 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001214
Denis Vlasenko601ae132006-11-28 23:37:46 +00001215 /* Parse command line */
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001216#if ENABLE_LONG_OPTS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001217 applet_long_options = od_longopts;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001218#endif
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001219 opt = OD_GETOPT32();
Denis Vlasenko601ae132006-11-28 23:37:46 +00001220 argv += optind;
1221 if (opt & OPT_A) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001222 static const char doxn[] ALIGN1 = "doxn";
1223 static const char doxn_address_base_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001224 'u', 'o', 'x', /* '?' fourth one is not important */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001225 };
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001226 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001227 '7', '7', '6', /* '?' */
1228 };
Denis Vlasenko601ae132006-11-28 23:37:46 +00001229 char *p;
1230 int pos;
1231 p = strchr(doxn, str_A[0]);
1232 if (!p)
1233 bb_error_msg_and_die("bad output address radix "
1234 "'%c' (must be [doxn])", str_A[0]);
1235 pos = p - doxn;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001236 if (pos == 3) G.format_address = format_address_none;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001237 address_base_char = doxn_address_base_char[pos];
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001238 address_pad_len_char = doxn_address_pad_len_char[pos];
Denis Vlasenko1114de72006-10-10 23:26:05 +00001239 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001240 if (opt & OPT_N) {
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001241 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001242 }
1243 if (opt & OPT_a) decode_format_string("a");
1244 if (opt & OPT_b) decode_format_string("oC");
1245 if (opt & OPT_c) decode_format_string("c");
1246 if (opt & OPT_d) decode_format_string("u2");
1247 if (opt & OPT_f) decode_format_string("fF");
1248 if (opt & OPT_h) decode_format_string("x2");
1249 if (opt & OPT_i) decode_format_string("d2");
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001250 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001251 if (opt & OPT_l) decode_format_string("d4");
1252 if (opt & OPT_o) decode_format_string("o2");
Denis Vlasenko601ae132006-11-28 23:37:46 +00001253 while (lst_t) {
Denis Vlasenkod50dda82008-06-15 05:40:56 +00001254 decode_format_string(llist_pop(&lst_t));
Denis Vlasenko601ae132006-11-28 23:37:46 +00001255 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001256 if (opt & OPT_x) decode_format_string("x2");
1257 if (opt & OPT_s) decode_format_string("d2");
1258 if (opt & OPT_S) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001259 G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001260 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001261
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001262 // Bloat:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001263 //if ((option_mask32 & OPT_S) && G.n_specs > 0)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001264 // bb_error_msg_and_die("no type may be specified when dumping strings");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001265
Denis Vlasenko1114de72006-10-10 23:26:05 +00001266 /* If the --traditional option is used, there may be from
Denis Vlasenko601ae132006-11-28 23:37:46 +00001267 * 0 to 3 remaining command line arguments; handle each case
1268 * separately.
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001269 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
Denis Vlasenko601ae132006-11-28 23:37:46 +00001270 * The offset and pseudo_start have the same syntax.
1271 *
1272 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
1273 * traditional syntax even if --traditional is not given. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001274
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001275#if ENABLE_LONG_OPTS
Denis Vlasenko601ae132006-11-28 23:37:46 +00001276 if (opt & OPT_traditional) {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001277 if (argv[0]) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001278 off_t pseudo_start = -1;
1279 off_t o1, o2;
1280
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001281 if (!argv[1]) { /* one arg */
1282 if (parse_old_offset(argv[0], &o1)) {
1283 /* od --traditional OFFSET */
1284 n_bytes_to_skip = o1;
1285 argv++;
1286 }
1287 /* od --traditional FILE */
1288 } else if (!argv[2]) { /* two args */
1289 if (parse_old_offset(argv[0], &o1)
1290 && parse_old_offset(argv[1], &o2)
1291 ) {
1292 /* od --traditional OFFSET LABEL */
1293 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001294 pseudo_start = o2;
1295 argv += 2;
1296 } else if (parse_old_offset(argv[1], &o2)) {
1297 /* od --traditional FILE OFFSET */
1298 n_bytes_to_skip = o2;
1299 argv[1] = NULL;
1300 } else {
1301 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1302 }
1303 } else if (!argv[3]) { /* three args */
1304 if (parse_old_offset(argv[1], &o1)
1305 && parse_old_offset(argv[2], &o2)
1306 ) {
1307 /* od --traditional FILE OFFSET LABEL */
1308 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001309 pseudo_start = o2;
1310 argv[1] = NULL;
1311 } else {
1312 bb_error_msg_and_die("the last two arguments must be offsets");
1313 }
1314 } else { /* >3 args */
1315 bb_error_msg_and_die("too many arguments");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001316 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001317
1318 if (pseudo_start >= 0) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001319 if (G.format_address == format_address_none) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001320 address_base_char = 'o';
1321 address_pad_len_char = '7';
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001322 G.format_address = format_address_paren;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001323 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001324 G.format_address = format_address_label;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001325 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001326 G_pseudo_offset = pseudo_start - n_bytes_to_skip;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001327 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001328 }
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001329 /* else: od --traditional (without args) */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001330 }
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001331#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +00001332
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001333 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001334 end_offset = n_bytes_to_skip + max_bytes_to_format;
1335 if (end_offset < n_bytes_to_skip)
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001336 bb_error_msg_and_die("SKIP + SIZE is too large");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001337 }
1338
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001339 if (G.n_specs == 0) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001340 decode_format_string("o2");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001341 /*G.n_specs = 1; - done by decode_format_string */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001342 }
1343
Denis Vlasenko601ae132006-11-28 23:37:46 +00001344 /* If no files were listed on the command line,
1345 set the global pointer FILE_LIST so that it
1346 references the null-terminated list of one name: "-". */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001347 G.file_list = bb_argv_dash;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001348 if (argv[0]) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001349 /* Set the global pointer FILE_LIST so that it
1350 references the first file-argument on the command-line. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001351 G.file_list = (char const *const *) argv;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001352 }
1353
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001354 /* Open the first input file */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001355 open_next_file();
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001356 /* Skip over any unwanted header bytes */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001357 skip(n_bytes_to_skip);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001358 if (!G.in_stream)
Bernhard Reutner-Fischer7c2db5c2007-11-16 12:39:16 +00001359 return EXIT_FAILURE;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001360
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001361 /* Compute output block length */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001362 l_c_m = get_lcm();
1363
Denis Vlasenko601ae132006-11-28 23:37:46 +00001364 if (opt & OPT_w) { /* -w: width */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001365 if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001366 bb_error_msg("warning: invalid width %u; using %d instead",
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001367 (unsigned)G.bytes_per_block, l_c_m);
1368 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001369 }
1370 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001371 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001372 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001373 G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001374 }
1375
1376#ifdef DEBUG
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001377 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001378 printf("%d: fmt=\"%s\" width=%d\n",
1379 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1380 }
1381#endif
1382
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001383 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001384 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001385 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001386 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001387
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001388 if (fclose(stdin))
Denis Vlasenko601ae132006-11-28 23:37:46 +00001389 bb_perror_msg_and_die(bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001390
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001391 return G.exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001392}