blob: 1e252caf097241b6745a8c466a36a9525df56f8b [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, \
65 "A:N:abcdfhij:lot:vxsS:w::", \
66 /* -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 { \
220 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
221 G.bytes_per_block = 32; \
222} while (0)
223
Denis Vlasenko1114de72006-10-10 23:26:05 +0000224
Denis Vlasenko1114de72006-10-10 23:26:05 +0000225#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000226static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000227 [sizeof(char)] = CHAR,
228#if USHRT_MAX != UCHAR_MAX
229 [sizeof(short)] = SHORT,
230#endif
231#if UINT_MAX != USHRT_MAX
232 [sizeof(int)] = INT,
233#endif
234#if ULONG_MAX != UINT_MAX
235 [sizeof(long)] = LONG,
236#endif
237#if ULLONG_MAX != ULONG_MAX
238 [sizeof(ulonglong_t)] = LONG_LONG,
239#endif
240};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000241
242#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000243static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200244 /* gcc seems to allow repeated indexes. Last one wins */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000245 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
246 [sizeof(double)] = FLOAT_DOUBLE,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000247 [sizeof(float)] = FLOAT_SINGLE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000248};
249
250
251static unsigned
252gcd(unsigned u, unsigned v)
253{
254 unsigned t;
255 while (v != 0) {
256 t = u % v;
257 u = v;
258 v = t;
259 }
260 return u;
261}
262
263/* Compute the least common multiple of U and V. */
264static unsigned
265lcm(unsigned u, unsigned v) {
266 unsigned t = gcd(u, v);
267 if (t == 0)
268 return 0;
269 return u * v / t;
270}
271
272static void
273print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
274{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000275 while (n_bytes--) {
276 int tmp = *(signed char *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000277 printf(fmt_string, tmp);
278 block += sizeof(unsigned char);
279 }
280}
281
282static void
283print_char(size_t n_bytes, const char *block, const char *fmt_string)
284{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000285 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000286 unsigned tmp = *(unsigned char *) block;
287 printf(fmt_string, tmp);
288 block += sizeof(unsigned char);
289 }
290}
291
292static void
293print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
294{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000295 n_bytes /= sizeof(signed short);
296 while (n_bytes--) {
297 int tmp = *(signed short *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000298 printf(fmt_string, tmp);
299 block += sizeof(unsigned short);
300 }
301}
302
303static void
304print_short(size_t n_bytes, const char *block, const char *fmt_string)
305{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000306 n_bytes /= sizeof(unsigned short);
307 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000308 unsigned tmp = *(unsigned short *) block;
309 printf(fmt_string, tmp);
310 block += sizeof(unsigned short);
311 }
312}
313
314static void
315print_int(size_t n_bytes, const char *block, const char *fmt_string)
316{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000317 n_bytes /= sizeof(unsigned);
318 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000319 unsigned tmp = *(unsigned *) block;
320 printf(fmt_string, tmp);
321 block += sizeof(unsigned);
322 }
323}
324
Denis Vlasenko601ae132006-11-28 23:37:46 +0000325#if UINT_MAX == ULONG_MAX
326# define print_long print_int
327#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000328static void
329print_long(size_t n_bytes, const char *block, const char *fmt_string)
330{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000331 n_bytes /= sizeof(unsigned long);
332 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000333 unsigned long tmp = *(unsigned long *) block;
334 printf(fmt_string, tmp);
335 block += sizeof(unsigned long);
336 }
337}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000338#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000339
Denis Vlasenko601ae132006-11-28 23:37:46 +0000340#if ULONG_MAX == ULLONG_MAX
341# define print_long_long print_long
342#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000343static void
344print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
345{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000346 n_bytes /= sizeof(ulonglong_t);
347 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000348 ulonglong_t tmp = *(ulonglong_t *) block;
349 printf(fmt_string, tmp);
350 block += sizeof(ulonglong_t);
351 }
352}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000353#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000354
355static void
356print_float(size_t n_bytes, const char *block, const char *fmt_string)
357{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000358 n_bytes /= sizeof(float);
359 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000360 float tmp = *(float *) block;
361 printf(fmt_string, tmp);
362 block += sizeof(float);
363 }
364}
365
366static void
367print_double(size_t n_bytes, const char *block, const char *fmt_string)
368{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000369 n_bytes /= sizeof(double);
370 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000371 double tmp = *(double *) block;
372 printf(fmt_string, tmp);
373 block += sizeof(double);
374 }
375}
376
377static void
378print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
379{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000380 n_bytes /= sizeof(longdouble_t);
381 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000382 longdouble_t tmp = *(longdouble_t *) block;
383 printf(fmt_string, tmp);
384 block += sizeof(longdouble_t);
385 }
386}
387
Denis Vlasenko601ae132006-11-28 23:37:46 +0000388/* print_[named]_ascii are optimized for speed.
Bernhard Reutner-Fischera985d302008-02-11 11:44:38 +0000389 * Remember, someday you may want to pump gigabytes through this thing.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000390 * Saving a dozen of .text bytes here is counter-productive */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000391
392static void
393print_named_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000394 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000395{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000396 /* Names for some non-printing characters. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000397 static const char charname[33][3] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000398 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
399 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
400 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
401 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
402 " sp"
403 };
404 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100405 char buf[12] = " x\0 xxx\0";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000406 // [12] because we take three 32bit stack slots anyway, and
407 // gcc is too dumb to initialize with constant stores,
408 // it copies initializer from rodata. Oh well.
Ron Yorston53e9c512015-03-12 20:10:40 +0100409 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410
Denis Vlasenko1114de72006-10-10 23:26:05 +0000410
Denis Vlasenko601ae132006-11-28 23:37:46 +0000411 while (n_bytes--) {
412 unsigned masked_c = *(unsigned char *) block++;
413
414 masked_c &= 0x7f;
415 if (masked_c == 0x7f) {
416 fputs(" del", stdout);
417 continue;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000418 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000419 if (masked_c > ' ') {
420 buf[3] = masked_c;
421 fputs(buf, stdout);
422 continue;
423 }
424 /* Why? Because printf(" %3.3s") is much slower... */
425 buf[6] = charname[masked_c][0];
426 buf[7] = charname[masked_c][1];
427 buf[8] = charname[masked_c][2];
428 fputs(buf+5, stdout);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000429 }
430}
431
432static void
433print_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000434 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000435{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000436 // buf[N] pos: 01234 56789
Ron Yorston53e9c512015-03-12 20:10:40 +0100437 char buf[12] = " x\0 xxx\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000438
Denis Vlasenko601ae132006-11-28 23:37:46 +0000439 while (n_bytes--) {
440 const char *s;
441 unsigned c = *(unsigned char *) block++;
442
443 if (ISPRINT(c)) {
444 buf[3] = c;
445 fputs(buf, stdout);
446 continue;
447 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000448 switch (c) {
449 case '\0':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000450 s = " \\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000451 break;
452 case '\007':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000453 s = " \\a";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000454 break;
455 case '\b':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000456 s = " \\b";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000457 break;
458 case '\f':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000459 s = " \\f";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000460 break;
461 case '\n':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000462 s = " \\n";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000463 break;
464 case '\r':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000465 s = " \\r";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000466 break;
467 case '\t':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000468 s = " \\t";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000469 break;
470 case '\v':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000471 s = " \\v";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000472 break;
Ron Yorston53e9c512015-03-12 20:10:40 +0100473 default:
474 buf[6] = (c >> 6 & 3) + '0';
475 buf[7] = (c >> 3 & 7) + '0';
Denis Vlasenko601ae132006-11-28 23:37:46 +0000476 buf[8] = (c & 7) + '0';
477 s = buf + 5;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000478 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000479 fputs(s, stdout);
480 }
481}
Denis Vlasenko1114de72006-10-10 23:26:05 +0000482
Denis Vlasenko601ae132006-11-28 23:37:46 +0000483/* Given a list of one or more input filenames FILE_LIST, set the global
484 file pointer IN_STREAM and the global string INPUT_FILENAME to the
485 first one that can be successfully opened. Modify FILE_LIST to
486 reference the next filename in the list. A file name of "-" is
487 interpreted as standard input. If any file open fails, give an error
488 message and return nonzero. */
489
490static void
491open_next_file(void)
492{
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000493 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200494 if (!*G.file_list)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000495 return;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200496 G.in_stream = fopen_or_warn_stdin(*G.file_list++);
497 if (G.in_stream) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000498 break;
499 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200500 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000501 }
502
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200503 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200504 setbuf(G.in_stream, NULL);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000505}
506
507/* Test whether there have been errors on in_stream, and close it if
508 it is not standard input. Return nonzero if there has been an error
509 on in_stream or stdout; return zero otherwise. This function will
510 report more than one error only if both a read and a write error
511 have occurred. IN_ERRNO, if nonzero, is the error number
512 corresponding to the most recent action for IN_STREAM. */
513
514static void
515check_and_close(void)
516{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200517 if (G.in_stream) {
518 if (ferror(G.in_stream)) {
519 bb_error_msg("%s: read error", (G.in_stream == stdin)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000520 ? bb_msg_standard_input
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200521 : G.file_list[-1]
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000522 );
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200523 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000524 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200525 fclose_if_not_stdin(G.in_stream);
526 G.in_stream = NULL;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000527 }
528
529 if (ferror(stdout)) {
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200530 bb_error_msg_and_die(bb_msg_write_error);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000531 }
532}
533
534/* If S points to a single valid modern od format string, put
Denis Vlasenko7089c312008-04-14 19:50:06 +0000535 a description of that format in *TSPEC, return pointer to
536 character following the just-decoded format.
537 For example, if S were "d4afL", we will return a rtp to "afL"
538 and *TSPEC would be
Denis Vlasenko1114de72006-10-10 23:26:05 +0000539 {
540 fmt = SIGNED_DECIMAL;
541 size = INT or LONG; (whichever integral_type_size[4] resolves to)
542 print_function = print_int; (assuming size == INT)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000543 fmt_string = "%011d%c";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000544 }
545 S_ORIG is solely for reporting errors. It should be the full format
Denis Vlasenko601ae132006-11-28 23:37:46 +0000546 string argument. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000547
Denys Vlasenkob9542cb2010-06-01 23:16:46 +0200548static NOINLINE const char *
Denis Vlasenko7089c312008-04-14 19:50:06 +0000549decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000550{
551 enum size_spec size_spec;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000552 unsigned size;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000553 enum output_format fmt;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000554 const char *p;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000555 char *end;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000556 char *fmt_string = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000557 void (*print_function) (size_t, const char *, const char *);
558 unsigned c;
559 unsigned field_width = 0;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000560 int pos;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000561
Denis Vlasenko1114de72006-10-10 23:26:05 +0000562 switch (*s) {
563 case 'd':
564 case 'o':
565 case 'u':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000566 case 'x': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000567 static const char CSIL[] ALIGN1 = "CSIL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000568
569 c = *s++;
570 p = strchr(CSIL, *s);
Denys Vlasenko11f3a8b2009-11-22 15:37:16 +0100571 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
572 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000573 size = sizeof(int);
574 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000575 size = bb_strtou(s, &end, 0);
576 if (errno == ERANGE
577 || MAX_INTEGRAL_TYPE_SIZE < size
Denis Vlasenko1114de72006-10-10 23:26:05 +0000578 || integral_type_size[size] == NO_SIZE
579 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000580 bb_error_msg_and_die("invalid type string '%s'; "
581 "%u-byte %s type is not supported",
582 s_orig, size, "integral");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000583 }
584 s = end;
585 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000586 } else {
Denis Vlasenko7089c312008-04-14 19:50:06 +0000587 static const uint8_t CSIL_sizeof[4] = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000588 sizeof(char),
589 sizeof(short),
590 sizeof(int),
591 sizeof(long),
592 };
593 size = CSIL_sizeof[p - CSIL];
Denis Vlasenko7089c312008-04-14 19:50:06 +0000594 s++; /* skip C/S/I/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000595 }
596
597#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
598 ((Spec) == LONG_LONG ? (Max_format) \
599 : ((Spec) == LONG ? (Long_format) : (Min_format)))
600
601#define FMT_BYTES_ALLOCATED 9
Denis Vlasenko1114de72006-10-10 23:26:05 +0000602 size_spec = integral_type_size[size];
603
Denis Vlasenko601ae132006-11-28 23:37:46 +0000604 {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000605 static const char doux[] ALIGN1 = "doux";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000606 static const char doux_fmt_letter[][4] = {
607 "lld", "llo", "llu", "llx"
608 };
609 static const enum output_format doux_fmt[] = {
610 SIGNED_DECIMAL,
611 OCTAL,
612 UNSIGNED_DECIMAL,
613 HEXADECIMAL,
614 };
615 static const uint8_t *const doux_bytes_to_XXX[] = {
616 bytes_to_signed_dec_digits,
617 bytes_to_oct_digits,
618 bytes_to_unsigned_dec_digits,
619 bytes_to_hex_digits,
620 };
621 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
622 " %%%u%s",
623 " %%0%u%s",
624 " %%%u%s",
625 " %%0%u%s",
626 };
Denis Vlasenko1114de72006-10-10 23:26:05 +0000627
Denis Vlasenko601ae132006-11-28 23:37:46 +0000628 pos = strchr(doux, c) - doux;
629 fmt = doux_fmt[pos];
630 field_width = doux_bytes_to_XXX[pos][size];
631 p = doux_fmt_letter[pos] + 2;
632 if (size_spec == LONG) p--;
633 if (size_spec == LONG_LONG) p -= 2;
634 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
635 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000636
637 switch (size_spec) {
638 case CHAR:
639 print_function = (fmt == SIGNED_DECIMAL
640 ? print_s_char
641 : print_char);
642 break;
643 case SHORT:
644 print_function = (fmt == SIGNED_DECIMAL
645 ? print_s_short
646 : print_short);
647 break;
648 case INT:
649 print_function = print_int;
650 break;
651 case LONG:
652 print_function = print_long;
653 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000654 default: /* case LONG_LONG: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000655 print_function = print_long_long;
656 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000657 }
658 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000659 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000660
Denis Vlasenko601ae132006-11-28 23:37:46 +0000661 case 'f': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000662 static const char FDL[] ALIGN1 = "FDL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000663
Denis Vlasenko1114de72006-10-10 23:26:05 +0000664 fmt = FLOATING_POINT;
665 ++s;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000666 p = strchr(FDL, *s);
667 if (!p) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000668 size = sizeof(double);
669 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000670 size = bb_strtou(s, &end, 0);
671 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000672 || fp_type_size[size] == NO_SIZE
673 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000674 bb_error_msg_and_die("invalid type string '%s'; "
675 "%u-byte %s type is not supported",
676 s_orig, size, "floating point");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000677 }
678 s = end;
679 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000680 } else {
681 static const uint8_t FDL_sizeof[] = {
682 sizeof(float),
683 sizeof(double),
684 sizeof(longdouble_t),
685 };
686
687 size = FDL_sizeof[p - FDL];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000688 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000689
Denis Vlasenko1114de72006-10-10 23:26:05 +0000690 size_spec = fp_type_size[size];
691
692 switch (size_spec) {
693 case FLOAT_SINGLE:
694 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000695 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000696 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000697 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000698 break;
699 case FLOAT_DOUBLE:
700 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000701 field_width = DBL_DIG + 8;
702 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000703 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000704 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000705 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000706 field_width = LDBL_DIG + 8;
707 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000708 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000709 }
710 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000711 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000712
713 case 'a':
714 ++s;
715 fmt = NAMED_CHARACTER;
716 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000717 print_function = print_named_ascii;
718 field_width = 3;
719 break;
720 case 'c':
721 ++s;
722 fmt = CHARACTER;
723 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000724 print_function = print_ascii;
725 field_width = 3;
726 break;
727 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000728 bb_error_msg_and_die("invalid character '%c' "
729 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000730 }
731
732 tspec->size = size_spec;
733 tspec->fmt = fmt;
734 tspec->print_function = print_function;
735 tspec->fmt_string = fmt_string;
736
737 tspec->field_width = field_width;
738 tspec->hexl_mode_trailer = (*s == 'z');
739 if (tspec->hexl_mode_trailer)
740 s++;
741
Denis Vlasenko7089c312008-04-14 19:50:06 +0000742 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000743}
744
745/* Decode the modern od format string S. Append the decoded
746 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000747 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000748
Denis Vlasenko601ae132006-11-28 23:37:46 +0000749static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000750decode_format_string(const char *s)
751{
752 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000753
754 while (*s != '\0') {
755 struct tspec tspec;
756 const char *next;
757
Denis Vlasenko7089c312008-04-14 19:50:06 +0000758 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000759
760 assert(s != next);
761 s = next;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200762 G.spec = xrealloc_vector(G.spec, 4, G.n_specs);
763 memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0]));
764 G.n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000765 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000766}
767
768/* Given a list of one or more input filenames FILE_LIST, set the global
769 file pointer IN_STREAM to position N_SKIP in the concatenation of
770 those files. If any file operation fails or if there are fewer than
771 N_SKIP bytes in the combined input, give an error message and return
772 nonzero. When possible, use seek rather than read operations to
773 advance IN_STREAM. */
774
Denis Vlasenko601ae132006-11-28 23:37:46 +0000775static void
776skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000777{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000778 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000779 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000780
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200781 while (G.in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000782 struct stat file_stats;
783
784 /* First try seeking. For large offsets, this extra work is
785 worthwhile. If the offset is below some threshold it may be
786 more efficient to move the pointer by reading. There are two
787 issues when trying to seek:
788 - the file must be seekable.
789 - before seeking to the specified position, make sure
790 that the new position is in the current file.
791 Try to do that by getting file's size using fstat.
792 But that will work only for regular files. */
793
Denis Vlasenko1114de72006-10-10 23:26:05 +0000794 /* The st_size field is valid only for regular files
795 (and for symbolic links, which cannot occur here).
796 If the number of bytes left to skip is at least
797 as large as the size of the current file, we can
798 decrement n_skip and go on to the next file. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200799 if (fstat(fileno(G.in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000800 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000801 ) {
802 if (file_stats.st_size < n_skip) {
803 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000804 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000805 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200806 if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0)
807 G.exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000808 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000809 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000810 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000811 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000812 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000813 char buf[1024];
814 size_t n_bytes_to_read = 1024;
815 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000816
Denis Vlasenko601ae132006-11-28 23:37:46 +0000817 while (n_skip > 0) {
818 if (n_skip < n_bytes_to_read)
819 n_bytes_to_read = n_skip;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200820 n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000821 n_skip -= n_bytes_read;
822 if (n_bytes_read != n_bytes_to_read)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000823 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000824 }
825 }
826 if (n_skip == 0)
827 return;
828
829 check_and_close();
830 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000831 }
832
Denis Vlasenko601ae132006-11-28 23:37:46 +0000833 if (n_skip)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100834 bb_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000835}
836
Denis Vlasenko601ae132006-11-28 23:37:46 +0000837
838typedef void FN_format_address(off_t address, char c);
839
Denis Vlasenko1114de72006-10-10 23:26:05 +0000840static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000841format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000842{
843}
844
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000845static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000846/* Corresponds to 'x' above */
847#define address_base_char address_fmt[sizeof(address_fmt)-3]
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000848/* Corresponds to 'n' above */
849#define address_pad_len_char address_fmt[2]
Denis Vlasenko601ae132006-11-28 23:37:46 +0000850
Denis Vlasenko1114de72006-10-10 23:26:05 +0000851static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000852format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000853{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000854 /* Corresponds to 'c' */
855 address_fmt[sizeof(address_fmt)-2] = c;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000856 printf(address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000857}
858
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200859#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000860/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000861static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000862format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000863{
864 putchar('(');
865 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000866 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000867}
868
869static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000870format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000871{
872 format_address_std(address, ' ');
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200873 format_address_paren(address + G_pseudo_offset, c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000874}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000875#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000876
877static void
878dump_hexl_mode_trailer(size_t n_bytes, const char *block)
879{
880 fputs(" >", stdout);
881 while (n_bytes--) {
882 unsigned c = *(unsigned char *) block++;
883 c = (ISPRINT(c) ? c : '.');
884 putchar(c);
885 }
886 putchar('<');
887}
888
Denis Vlasenko1114de72006-10-10 23:26:05 +0000889/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
890 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
891 CURR_BLOCK in the concatenation of input files, and it is printed
892 (optionally) only before the output line associated with the first
893 format spec. When duplicate blocks are being abbreviated, the output
894 for a sequence of identical input blocks is the output for the first
895 block followed by an asterisk alone on a line. It is valid to compare
896 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
897 That condition may be false only for the last input block -- and then
898 only when it has not been padded to length BYTES_PER_BLOCK. */
899
900static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000901write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000902 const char *prev_block, const char *curr_block)
903{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200904 unsigned i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000905
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200906 if (!(option_mask32 & OPT_v)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200907 && G.not_first
908 && n_bytes == G.bytes_per_block
909 && memcmp(prev_block, curr_block, G.bytes_per_block) == 0
Denis Vlasenko1114de72006-10-10 23:26:05 +0000910 ) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200911 if (G.prev_pair_equal) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000912 /* The two preceding blocks were equal, and the current
913 block is the same as the last one, so print nothing. */
914 } else {
915 puts("*");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200916 G.prev_pair_equal = 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000917 }
918 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200919 G.not_first = 1;
920 G.prev_pair_equal = 0;
921 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000922 if (i == 0)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200923 G.format_address(current_offset, '\0');
Denis Vlasenko1114de72006-10-10 23:26:05 +0000924 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000925 printf("%*s", address_pad_len_char - '0', "");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200926 (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string);
927 if (G.spec[i].hexl_mode_trailer) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000928 /* space-pad out to full line width, then dump the trailer */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200929 unsigned datum_width = width_bytes[G.spec[i].size];
930 unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width;
931 unsigned field_width = G.spec[i].field_width + 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000932 printf("%*s", blank_fields * field_width, "");
933 dump_hexl_mode_trailer(n_bytes, curr_block);
934 }
935 putchar('\n');
936 }
937 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000938}
939
Denis Vlasenko601ae132006-11-28 23:37:46 +0000940static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000941read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
942{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200943 assert(0 < n && n <= G.bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000944
945 *n_bytes_in_buffer = 0;
946
947 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000948 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000949
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200950 while (G.in_stream != NULL) { /* EOF. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000951 size_t n_needed;
952 size_t n_read;
953
954 n_needed = n - *n_bytes_in_buffer;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200955 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000956 *n_bytes_in_buffer += n_read;
957 if (n_read == n_needed)
958 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000959 /* error check is done in check_and_close */
960 check_and_close();
961 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000962 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000963}
964
965/* Return the least common multiple of the sizes associated
966 with the format specs. */
967
968static int
969get_lcm(void)
970{
971 size_t i;
972 int l_c_m = 1;
973
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200974 for (i = 0; i < G.n_specs; i++)
975 l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000976 return l_c_m;
977}
978
Denis Vlasenko1114de72006-10-10 23:26:05 +0000979/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
980 formatted block to standard output, and repeat until the specified
981 maximum number of bytes has been read or until all input has been
982 processed. If the last block read is smaller than BYTES_PER_BLOCK
983 and its size is not a multiple of the size associated with a format
984 spec, extend the input block with zero bytes until its length is a
985 multiple of all format spec sizes. Write the final block. Finally,
986 write on a line by itself the offset of the byte after the last byte
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000987 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000988
Denis Vlasenko601ae132006-11-28 23:37:46 +0000989static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000990dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000991{
992 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000993 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000994 size_t n_bytes_read;
995
Denys Vlasenkof3d58a22015-10-19 02:51:56 +0200996 block[0] = xmalloc(2 * G.bytes_per_block);
997 block[1] = block[0] + G.bytes_per_block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000998
Denis Vlasenko1114de72006-10-10 23:26:05 +0000999 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001000 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001001 while (1) {
1002 size_t n_needed;
1003 if (current_offset >= end_offset) {
1004 n_bytes_read = 0;
1005 break;
1006 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001007 n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001008 read_block(n_needed, block[idx], &n_bytes_read);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001009 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001010 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001011 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001012 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001013 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001014 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001015 }
1016 } else {
1017 while (1) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001018 read_block(G.bytes_per_block, block[idx], &n_bytes_read);
1019 if (n_bytes_read < G.bytes_per_block)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001020 break;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001021 assert(n_bytes_read == G.bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001022 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001023 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001024 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001025 }
1026 }
1027
1028 if (n_bytes_read > 0) {
1029 int l_c_m;
1030 size_t bytes_to_write;
1031
1032 l_c_m = get_lcm();
1033
1034 /* Make bytes_to_write the smallest multiple of l_c_m that
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001035 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001036 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1037
1038 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1039 write_block(current_offset, bytes_to_write,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001040 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001041 current_offset += n_bytes_read;
1042 }
1043
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001044 G.format_address(current_offset, '\n');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001045
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001046 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001047 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001048
1049 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001050}
1051
Denis Vlasenko601ae132006-11-28 23:37:46 +00001052/* Read N bytes into BLOCK from the concatenation of the input files
1053 named in the global array FILE_LIST. On the first call to this
1054 function, the global variable IN_STREAM is expected to be an open
1055 stream associated with the input file INPUT_FILENAME. If all N
1056 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1057 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1058 read the remaining bytes from the newly opened file. Repeat if
1059 necessary until EOF is reached for the last file in FILE_LIST.
1060 On subsequent calls, don't modify BLOCK and return zero. Set
1061 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1062 it will be detected through ferror when the stream is about to be
1063 closed. If there is an error, give a message but continue reading
1064 as usual and return nonzero. Otherwise return zero. */
1065
Denis Vlasenko1114de72006-10-10 23:26:05 +00001066/* STRINGS mode. Find each "string constant" in the input.
1067 A string constant is a run of at least 'string_min' ASCII
1068 graphic (or formatting) characters terminated by a null.
1069 Based on a function written by Richard Stallman for a
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001070 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001071
Denis Vlasenko601ae132006-11-28 23:37:46 +00001072static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001073dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001074{
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001075 unsigned bufsize = MAX(100, G.string_min);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001076 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001077
Denis Vlasenko1114de72006-10-10 23:26:05 +00001078 while (1) {
1079 size_t i;
1080 int c;
1081
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001082 /* See if the next 'G.string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001083 tryline:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001084 if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001085 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001086 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001087 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001088 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001089 bufsize += bufsize/8;
1090 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001091 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001092
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001093 while (G.in_stream) { /* !EOF */
1094 c = fgetc(G.in_stream);
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001095 if (c != EOF)
1096 goto got_char;
1097 check_and_close();
1098 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001099 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001100 /* EOF */
1101 goto ret;
1102 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001103 address++;
1104 if (!c)
1105 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001106 if (!ISPRINT(c))
1107 goto tryline; /* It isn't; give up on this string. */
1108 buf[i++] = c; /* String continues; store it all. */
1109 }
1110
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001111 if (i < G.string_min) /* Too short! */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001112 goto tryline;
1113
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001114 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001115 buf[i] = 0;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001116 G.format_address(address - i - 1, ' ');
Denis Vlasenko1114de72006-10-10 23:26:05 +00001117
1118 for (i = 0; (c = buf[i]); i++) {
1119 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001120 case '\007': fputs("\\a", stdout); break;
1121 case '\b': fputs("\\b", stdout); break;
1122 case '\f': fputs("\\f", stdout); break;
1123 case '\n': fputs("\\n", stdout); break;
1124 case '\r': fputs("\\r", stdout); break;
1125 case '\t': fputs("\\t", stdout); break;
1126 case '\v': fputs("\\v", stdout); break;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001127 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001128 }
1129 }
1130 putchar('\n');
1131 }
1132
1133 /* We reach this point only if we search through
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001134 (max_bytes_to_format - G.string_min) bytes before reaching EOF. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001135 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001136 ret:
1137 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001138}
1139
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001140#if ENABLE_LONG_OPTS
1141/* If S is a valid traditional offset specification with an optional
1142 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1143
1144static int
1145parse_old_offset(const char *s, off_t *offset)
1146{
1147 static const struct suffix_mult Bb[] = {
1148 { "B", 1024 },
1149 { "b", 512 },
1150 { "", 0 }
1151 };
1152 char *p;
1153 int radix;
1154
1155 /* Skip over any leading '+'. */
1156 if (s[0] == '+') ++s;
1157 if (!isdigit(s[0])) return 0; /* not a number */
1158
1159 /* Determine the radix we'll use to interpret S. If there is a '.',
1160 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1161 * it's hexadecimal, else octal. */
1162 p = strchr(s, '.');
1163 radix = 8;
1164 if (p) {
1165 p[0] = '\0'; /* cheating */
1166 radix = 10;
1167 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1168 radix = 16;
1169
1170 *offset = xstrtooff_sfx(s, radix, Bb);
1171 if (p) p[0] = '.';
1172
1173 return (*offset >= 0);
1174}
1175#endif
1176
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001177int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001178int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001179{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001180#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001181 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001182 "skip-bytes\0" Required_argument "j"
1183 "address-radix\0" Required_argument "A"
1184 "read-bytes\0" Required_argument "N"
1185 "format\0" Required_argument "t"
1186 "output-duplicates\0" No_argument "v"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001187 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1188 * that is, NUM is mandatory for -S but optional for --strings!
1189 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001190 "strings\0" Optional_argument "S"
1191 "width\0" Optional_argument "w"
1192 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001193 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001194#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001195 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001196 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001197 unsigned opt;
1198 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001199 /* The number of input bytes to skip before formatting and writing. */
1200 off_t n_bytes_to_skip = 0;
1201 /* The offset of the first byte after the last byte to be formatted. */
1202 off_t end_offset = 0;
1203 /* The maximum number of bytes that will be formatted. */
1204 off_t max_bytes_to_format = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001205
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001206 INIT_G();
1207
1208 /*G.spec = NULL; - already is */
1209 G.format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001210 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001211 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001212
Denis Vlasenko601ae132006-11-28 23:37:46 +00001213 /* Parse command line */
Denis Vlasenko1d426652008-03-17 09:09:09 +00001214 opt_complementary = "w+:t::"; /* -w N, -t is a list */
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001215#if ENABLE_LONG_OPTS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001216 applet_long_options = od_longopts;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001217#endif
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001218 opt = OD_GETOPT32();
Denis Vlasenko601ae132006-11-28 23:37:46 +00001219 argv += optind;
1220 if (opt & OPT_A) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001221 static const char doxn[] ALIGN1 = "doxn";
1222 static const char doxn_address_base_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001223 'u', 'o', 'x', /* '?' fourth one is not important */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001224 };
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001225 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001226 '7', '7', '6', /* '?' */
1227 };
Denis Vlasenko601ae132006-11-28 23:37:46 +00001228 char *p;
1229 int pos;
1230 p = strchr(doxn, str_A[0]);
1231 if (!p)
1232 bb_error_msg_and_die("bad output address radix "
1233 "'%c' (must be [doxn])", str_A[0]);
1234 pos = p - doxn;
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001235 if (pos == 3) G.format_address = format_address_none;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001236 address_base_char = doxn_address_base_char[pos];
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001237 address_pad_len_char = doxn_address_pad_len_char[pos];
Denis Vlasenko1114de72006-10-10 23:26:05 +00001238 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001239 if (opt & OPT_N) {
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001240 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001241 }
1242 if (opt & OPT_a) decode_format_string("a");
1243 if (opt & OPT_b) decode_format_string("oC");
1244 if (opt & OPT_c) decode_format_string("c");
1245 if (opt & OPT_d) decode_format_string("u2");
1246 if (opt & OPT_f) decode_format_string("fF");
1247 if (opt & OPT_h) decode_format_string("x2");
1248 if (opt & OPT_i) decode_format_string("d2");
Denys Vlasenkoc72b43c2013-07-13 23:49:45 +02001249 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001250 if (opt & OPT_l) decode_format_string("d4");
1251 if (opt & OPT_o) decode_format_string("o2");
Denis Vlasenko601ae132006-11-28 23:37:46 +00001252 while (lst_t) {
Denis Vlasenkod50dda82008-06-15 05:40:56 +00001253 decode_format_string(llist_pop(&lst_t));
Denis Vlasenko601ae132006-11-28 23:37:46 +00001254 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001255 if (opt & OPT_x) decode_format_string("x2");
1256 if (opt & OPT_s) decode_format_string("d2");
1257 if (opt & OPT_S) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001258 G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001259 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001260
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001261 // Bloat:
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001262 //if ((option_mask32 & OPT_S) && G.n_specs > 0)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001263 // bb_error_msg_and_die("no type may be specified when dumping strings");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001264
Denis Vlasenko1114de72006-10-10 23:26:05 +00001265 /* If the --traditional option is used, there may be from
Denis Vlasenko601ae132006-11-28 23:37:46 +00001266 * 0 to 3 remaining command line arguments; handle each case
1267 * separately.
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001268 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
Denis Vlasenko601ae132006-11-28 23:37:46 +00001269 * The offset and pseudo_start have the same syntax.
1270 *
1271 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
1272 * traditional syntax even if --traditional is not given. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001273
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001274#if ENABLE_LONG_OPTS
Denis Vlasenko601ae132006-11-28 23:37:46 +00001275 if (opt & OPT_traditional) {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001276 if (argv[0]) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001277 off_t pseudo_start = -1;
1278 off_t o1, o2;
1279
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001280 if (!argv[1]) { /* one arg */
1281 if (parse_old_offset(argv[0], &o1)) {
1282 /* od --traditional OFFSET */
1283 n_bytes_to_skip = o1;
1284 argv++;
1285 }
1286 /* od --traditional FILE */
1287 } else if (!argv[2]) { /* two args */
1288 if (parse_old_offset(argv[0], &o1)
1289 && parse_old_offset(argv[1], &o2)
1290 ) {
1291 /* od --traditional OFFSET LABEL */
1292 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001293 pseudo_start = o2;
1294 argv += 2;
1295 } else if (parse_old_offset(argv[1], &o2)) {
1296 /* od --traditional FILE OFFSET */
1297 n_bytes_to_skip = o2;
1298 argv[1] = NULL;
1299 } else {
1300 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1301 }
1302 } else if (!argv[3]) { /* three args */
1303 if (parse_old_offset(argv[1], &o1)
1304 && parse_old_offset(argv[2], &o2)
1305 ) {
1306 /* od --traditional FILE OFFSET LABEL */
1307 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001308 pseudo_start = o2;
1309 argv[1] = NULL;
1310 } else {
1311 bb_error_msg_and_die("the last two arguments must be offsets");
1312 }
1313 } else { /* >3 args */
1314 bb_error_msg_and_die("too many arguments");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001315 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001316
1317 if (pseudo_start >= 0) {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001318 if (G.format_address == format_address_none) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001319 address_base_char = 'o';
1320 address_pad_len_char = '7';
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001321 G.format_address = format_address_paren;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001322 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001323 G.format_address = format_address_label;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001324 }
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001325 G_pseudo_offset = pseudo_start - n_bytes_to_skip;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001326 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001327 }
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001328 /* else: od --traditional (without args) */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001329 }
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001330#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +00001331
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001332 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001333 end_offset = n_bytes_to_skip + max_bytes_to_format;
1334 if (end_offset < n_bytes_to_skip)
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001335 bb_error_msg_and_die("SKIP + SIZE is too large");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001336 }
1337
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001338 if (G.n_specs == 0) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001339 decode_format_string("o2");
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001340 /*G.n_specs = 1; - done by decode_format_string */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001341 }
1342
Denis Vlasenko601ae132006-11-28 23:37:46 +00001343 /* If no files were listed on the command line,
1344 set the global pointer FILE_LIST so that it
1345 references the null-terminated list of one name: "-". */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001346 G.file_list = bb_argv_dash;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001347 if (argv[0]) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001348 /* Set the global pointer FILE_LIST so that it
1349 references the first file-argument on the command-line. */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001350 G.file_list = (char const *const *) argv;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001351 }
1352
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001353 /* Open the first input file */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001354 open_next_file();
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001355 /* Skip over any unwanted header bytes */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001356 skip(n_bytes_to_skip);
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001357 if (!G.in_stream)
Bernhard Reutner-Fischer7c2db5c2007-11-16 12:39:16 +00001358 return EXIT_FAILURE;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001359
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001360 /* Compute output block length */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001361 l_c_m = get_lcm();
1362
Denis Vlasenko601ae132006-11-28 23:37:46 +00001363 if (opt & OPT_w) { /* -w: width */
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001364 if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001365 bb_error_msg("warning: invalid width %u; using %d instead",
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001366 (unsigned)G.bytes_per_block, l_c_m);
1367 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001368 }
1369 } else {
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001370 G.bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001371 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001372 G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001373 }
1374
1375#ifdef DEBUG
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001376 for (i = 0; i < G.n_specs; i++) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001377 printf("%d: fmt=\"%s\" width=%d\n",
1378 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1379 }
1380#endif
1381
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001382 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001383 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001384 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001385 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001386
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001387 if (fclose(stdin))
Denis Vlasenko601ae132006-11-28 23:37:46 +00001388 bb_perror_msg_and_die(bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001389
Denys Vlasenkof3d58a22015-10-19 02:51:56 +02001390 return G.exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001391}