blob: 6b00a4381da50bf90e75d4c82fff915ffe3393bc [file] [log] [blame]
Denis Vlasenko1114de72006-10-10 23:26:05 +00001/* od -- dump files in octal and other formats
2 Copyright (C) 92, 1995-2004 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020016 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
Denis Vlasenko1114de72006-10-10 23:26:05 +000018/* Written by Jim Meyering. */
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020019/* Busyboxed by Denys Vlasenko, based on od.c from coreutils-5.2.1 */
Denis Vlasenko1114de72006-10-10 23:26:05 +000020
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020021
22/* #include "libbb.h" - done in od.c */
23#define assert(a) ((void)0)
24
25
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020026//usage:#if ENABLE_DESKTOP
27//usage:#define od_trivial_usage
Tanguy Pruvot823694d2012-11-18 13:20:29 +010028//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..."
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020029// We don't support:
30// ... [FILE] [[+]OFFSET[.][b]]
31// Support is buggy for:
32// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]
Denis Vlasenko601ae132006-11-28 23:37:46 +000033
Denys Vlasenko5c10fa52011-05-21 17:43:06 +020034//usage:#define od_full_usage "\n\n"
35//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default"
36//usage:#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +000037
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020038enum {
39 OPT_A = 1 << 0,
40 OPT_N = 1 << 1,
41 OPT_a = 1 << 2,
42 OPT_b = 1 << 3,
43 OPT_c = 1 << 4,
44 OPT_d = 1 << 5,
45 OPT_f = 1 << 6,
46 OPT_h = 1 << 7,
47 OPT_i = 1 << 8,
48 OPT_j = 1 << 9,
49 OPT_l = 1 << 10,
50 OPT_o = 1 << 11,
51 OPT_t = 1 << 12,
52 /* When zero and two or more consecutive blocks are equal, format
53 only the first block and output an asterisk alone on the following
54 line to indicate that identical blocks have been elided: */
55 OPT_v = 1 << 13,
56 OPT_x = 1 << 14,
57 OPT_s = 1 << 15,
58 OPT_S = 1 << 16,
59 OPT_w = 1 << 17,
60 OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS,
61};
Denis Vlasenko1114de72006-10-10 23:26:05 +000062
Denys Vlasenko3ef344b2011-05-21 18:38:40 +020063#define OD_GETOPT32() getopt32(argv, \
64 "A:N:abcdfhij:lot:vxsS:w::", \
65 /* -w with optional param */ \
66 /* -S was -s and also had optional parameter */ \
67 /* but in coreutils 6.3 it was renamed and now has */ \
68 /* _mandatory_ parameter */ \
69 &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block)
70
Denis Vlasenko601ae132006-11-28 23:37:46 +000071
72/* Check for 0x7f is a coreutils 6.3 addition */
Denys Vlasenko9d96e272011-05-21 18:38:59 +020073#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f)
Denis Vlasenko1114de72006-10-10 23:26:05 +000074
75typedef long double longdouble_t;
76typedef unsigned long long ulonglong_t;
Denis Vlasenko601ae132006-11-28 23:37:46 +000077typedef long long llong;
78
79#if ENABLE_LFS
80# define xstrtooff_sfx xstrtoull_sfx
81#else
82# define xstrtooff_sfx xstrtoul_sfx
83#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +000084
85/* The default number of input bytes per output line. */
86#define DEFAULT_BYTES_PER_BLOCK 16
87
88/* The number of decimal digits of precision in a float. */
89#ifndef FLT_DIG
90# define FLT_DIG 7
91#endif
92
93/* The number of decimal digits of precision in a double. */
94#ifndef DBL_DIG
95# define DBL_DIG 15
96#endif
97
98/* The number of decimal digits of precision in a long double. */
99#ifndef LDBL_DIG
100# define LDBL_DIG DBL_DIG
101#endif
102
103enum size_spec {
104 NO_SIZE,
105 CHAR,
106 SHORT,
107 INT,
108 LONG,
109 LONG_LONG,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000110 FLOAT_SINGLE,
111 FLOAT_DOUBLE,
112 FLOAT_LONG_DOUBLE,
113 N_SIZE_SPECS
114};
115
116enum output_format {
117 SIGNED_DECIMAL,
118 UNSIGNED_DECIMAL,
119 OCTAL,
120 HEXADECIMAL,
121 FLOATING_POINT,
122 NAMED_CHARACTER,
123 CHARACTER
124};
125
126/* Each output format specification (from '-t spec' or from
127 old-style options) is represented by one of these structures. */
128struct tspec {
129 enum output_format fmt;
130 enum size_spec size;
131 void (*print_function) (size_t, const char *, const char *);
132 char *fmt_string;
133 int hexl_mode_trailer;
134 int field_width;
135};
136
137/* Convert the number of 8-bit bytes of a binary representation to
138 the number of characters (digits + sign if the type is signed)
139 required to represent the same quantity in the specified base/type.
140 For example, a 32-bit (4-byte) quantity may require a field width
141 as wide as the following for these types:
142 11 unsigned octal
143 11 signed decimal
144 10 unsigned decimal
145 8 unsigned hexadecimal */
146
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000147static const uint8_t bytes_to_oct_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000148{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
149
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000150static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000151{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
152
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000153static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000154{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
155
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000156static const uint8_t bytes_to_hex_digits[] ALIGN1 =
Denis Vlasenko1114de72006-10-10 23:26:05 +0000157{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
158
159/* Convert enum size_spec to the size of the named type. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000160static const signed char width_bytes[] ALIGN1 = {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000161 -1,
162 sizeof(char),
163 sizeof(short),
164 sizeof(int),
165 sizeof(long),
166 sizeof(ulonglong_t),
167 sizeof(float),
168 sizeof(double),
169 sizeof(longdouble_t)
170};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000171/* Ensure that for each member of 'enum size_spec' there is an
172 initializer in the width_bytes array. */
Denis Vlasenko45946f82007-08-20 17:27:40 +0000173struct ERR_width_bytes_has_bad_size {
174 char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000175};
176
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200177static smallint exit_code;
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000178
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200179static unsigned string_min;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000180
181/* An array of specs describing how to format each input block. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000182static size_t n_specs;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000183static struct tspec *spec;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000184
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000185/* Function that accepts an address and an optional following char,
186 and prints the address and char to stdout. */
187static void (*format_address)(off_t, char);
188/* The difference between the old-style pseudo starting address and
189 the number of bytes to skip. */
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200190#if ENABLE_LONG_OPTS
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000191static off_t pseudo_offset;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200192#else
193enum { pseudo_offset = 0 };
194#endif
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000195/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
196 input is formatted. */
Denis Vlasenkobcb66ec2007-07-24 12:28:03 +0000197
Denis Vlasenko1114de72006-10-10 23:26:05 +0000198/* The number of input bytes formatted per output line. It must be
199 a multiple of the least common multiple of the sizes associated with
200 the specified output types. It should be as large as possible, but
201 no larger than 16 -- unless specified with the -w option. */
Denis Vlasenko1d426652008-03-17 09:09:09 +0000202static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000203
Denis Vlasenko1114de72006-10-10 23:26:05 +0000204/* A NULL-terminated list of the file-arguments from the command line. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000205static const char *const *file_list;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000206
207/* The input stream associated with the current file. */
208static FILE *in_stream;
209
Denis Vlasenko1114de72006-10-10 23:26:05 +0000210#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000211static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000212 [sizeof(char)] = CHAR,
213#if USHRT_MAX != UCHAR_MAX
214 [sizeof(short)] = SHORT,
215#endif
216#if UINT_MAX != USHRT_MAX
217 [sizeof(int)] = INT,
218#endif
219#if ULONG_MAX != UINT_MAX
220 [sizeof(long)] = LONG,
221#endif
222#if ULLONG_MAX != ULONG_MAX
223 [sizeof(ulonglong_t)] = LONG_LONG,
224#endif
225};
Denis Vlasenko1114de72006-10-10 23:26:05 +0000226
227#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000228static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200229 /* gcc seems to allow repeated indexes. Last one wins */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000230 [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
231 [sizeof(double)] = FLOAT_DOUBLE,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000232 [sizeof(float)] = FLOAT_SINGLE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000233};
234
235
236static unsigned
237gcd(unsigned u, unsigned v)
238{
239 unsigned t;
240 while (v != 0) {
241 t = u % v;
242 u = v;
243 v = t;
244 }
245 return u;
246}
247
248/* Compute the least common multiple of U and V. */
249static unsigned
250lcm(unsigned u, unsigned v) {
251 unsigned t = gcd(u, v);
252 if (t == 0)
253 return 0;
254 return u * v / t;
255}
256
257static void
258print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
259{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000260 while (n_bytes--) {
261 int tmp = *(signed char *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000262 printf(fmt_string, tmp);
263 block += sizeof(unsigned char);
264 }
265}
266
267static void
268print_char(size_t n_bytes, const char *block, const char *fmt_string)
269{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000270 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000271 unsigned tmp = *(unsigned char *) block;
272 printf(fmt_string, tmp);
273 block += sizeof(unsigned char);
274 }
275}
276
277static void
278print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
279{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000280 n_bytes /= sizeof(signed short);
281 while (n_bytes--) {
282 int tmp = *(signed short *) block;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000283 printf(fmt_string, tmp);
284 block += sizeof(unsigned short);
285 }
286}
287
288static void
289print_short(size_t n_bytes, const char *block, const char *fmt_string)
290{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000291 n_bytes /= sizeof(unsigned short);
292 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000293 unsigned tmp = *(unsigned short *) block;
294 printf(fmt_string, tmp);
295 block += sizeof(unsigned short);
296 }
297}
298
299static void
300print_int(size_t n_bytes, const char *block, const char *fmt_string)
301{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000302 n_bytes /= sizeof(unsigned);
303 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000304 unsigned tmp = *(unsigned *) block;
305 printf(fmt_string, tmp);
306 block += sizeof(unsigned);
307 }
308}
309
Denis Vlasenko601ae132006-11-28 23:37:46 +0000310#if UINT_MAX == ULONG_MAX
311# define print_long print_int
312#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000313static void
314print_long(size_t n_bytes, const char *block, const char *fmt_string)
315{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000316 n_bytes /= sizeof(unsigned long);
317 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000318 unsigned long tmp = *(unsigned long *) block;
319 printf(fmt_string, tmp);
320 block += sizeof(unsigned long);
321 }
322}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000323#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000324
Denis Vlasenko601ae132006-11-28 23:37:46 +0000325#if ULONG_MAX == ULLONG_MAX
326# define print_long_long print_long
327#else
Denis Vlasenko1114de72006-10-10 23:26:05 +0000328static void
329print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
330{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000331 n_bytes /= sizeof(ulonglong_t);
332 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000333 ulonglong_t tmp = *(ulonglong_t *) block;
334 printf(fmt_string, tmp);
335 block += sizeof(ulonglong_t);
336 }
337}
Denis Vlasenko601ae132006-11-28 23:37:46 +0000338#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +0000339
340static void
341print_float(size_t n_bytes, const char *block, const char *fmt_string)
342{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000343 n_bytes /= sizeof(float);
344 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000345 float tmp = *(float *) block;
346 printf(fmt_string, tmp);
347 block += sizeof(float);
348 }
349}
350
351static void
352print_double(size_t n_bytes, const char *block, const char *fmt_string)
353{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000354 n_bytes /= sizeof(double);
355 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000356 double tmp = *(double *) block;
357 printf(fmt_string, tmp);
358 block += sizeof(double);
359 }
360}
361
362static void
363print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
364{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000365 n_bytes /= sizeof(longdouble_t);
366 while (n_bytes--) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000367 longdouble_t tmp = *(longdouble_t *) block;
368 printf(fmt_string, tmp);
369 block += sizeof(longdouble_t);
370 }
371}
372
Denis Vlasenko601ae132006-11-28 23:37:46 +0000373/* print_[named]_ascii are optimized for speed.
Bernhard Reutner-Fischera985d302008-02-11 11:44:38 +0000374 * Remember, someday you may want to pump gigabytes through this thing.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000375 * Saving a dozen of .text bytes here is counter-productive */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000376
377static void
378print_named_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000379 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000380{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000381 /* Names for some non-printing characters. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000382 static const char charname[33][3] ALIGN1 = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000383 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
384 " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
385 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
386 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
387 " sp"
388 };
389 // buf[N] pos: 01234 56789
390 char buf[12] = " x\0 0xx\0";
Denys Vlasenko5c10fa52011-05-21 17:43:06 +0200391 // actually " x\0 xxx\0", but want to share string with print_ascii.
Denis Vlasenko601ae132006-11-28 23:37:46 +0000392 // [12] because we take three 32bit stack slots anyway, and
393 // gcc is too dumb to initialize with constant stores,
394 // it copies initializer from rodata. Oh well.
Denis Vlasenko1114de72006-10-10 23:26:05 +0000395
Denis Vlasenko601ae132006-11-28 23:37:46 +0000396 while (n_bytes--) {
397 unsigned masked_c = *(unsigned char *) block++;
398
399 masked_c &= 0x7f;
400 if (masked_c == 0x7f) {
401 fputs(" del", stdout);
402 continue;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000403 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000404 if (masked_c > ' ') {
405 buf[3] = masked_c;
406 fputs(buf, stdout);
407 continue;
408 }
409 /* Why? Because printf(" %3.3s") is much slower... */
410 buf[6] = charname[masked_c][0];
411 buf[7] = charname[masked_c][1];
412 buf[8] = charname[masked_c][2];
413 fputs(buf+5, stdout);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000414 }
415}
416
417static void
418print_ascii(size_t n_bytes, const char *block,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000419 const char *unused_fmt_string UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000420{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000421 // buf[N] pos: 01234 56789
422 char buf[12] = " x\0 0xx\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000423
Denis Vlasenko601ae132006-11-28 23:37:46 +0000424 while (n_bytes--) {
425 const char *s;
426 unsigned c = *(unsigned char *) block++;
427
428 if (ISPRINT(c)) {
429 buf[3] = c;
430 fputs(buf, stdout);
431 continue;
432 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000433 switch (c) {
434 case '\0':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000435 s = " \\0";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000436 break;
437 case '\007':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000438 s = " \\a";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000439 break;
440 case '\b':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000441 s = " \\b";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000442 break;
443 case '\f':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000444 s = " \\f";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000445 break;
446 case '\n':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000447 s = " \\n";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000448 break;
449 case '\r':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000450 s = " \\r";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000451 break;
452 case '\t':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000453 s = " \\t";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000454 break;
455 case '\v':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000456 s = " \\v";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000457 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000458 case '\x7f':
459 s = " 177";
460 break;
461 default: /* c is never larger than 040 */
462 buf[7] = (c >> 3) + '0';
463 buf[8] = (c & 7) + '0';
464 s = buf + 5;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000465 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000466 fputs(s, stdout);
467 }
468}
Denis Vlasenko1114de72006-10-10 23:26:05 +0000469
Denis Vlasenko601ae132006-11-28 23:37:46 +0000470/* Given a list of one or more input filenames FILE_LIST, set the global
471 file pointer IN_STREAM and the global string INPUT_FILENAME to the
472 first one that can be successfully opened. Modify FILE_LIST to
473 reference the next filename in the list. A file name of "-" is
474 interpreted as standard input. If any file open fails, give an error
475 message and return nonzero. */
476
477static void
478open_next_file(void)
479{
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000480 while (1) {
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000481 if (!*file_list)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000482 return;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000483 in_stream = fopen_or_warn_stdin(*file_list++);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000484 if (in_stream) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000485 break;
486 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200487 exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000488 }
489
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200490 if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000491 setbuf(in_stream, NULL);
492}
493
494/* Test whether there have been errors on in_stream, and close it if
495 it is not standard input. Return nonzero if there has been an error
496 on in_stream or stdout; return zero otherwise. This function will
497 report more than one error only if both a read and a write error
498 have occurred. IN_ERRNO, if nonzero, is the error number
499 corresponding to the most recent action for IN_STREAM. */
500
501static void
502check_and_close(void)
503{
504 if (in_stream) {
505 if (ferror(in_stream)) {
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000506 bb_error_msg("%s: read error", (in_stream == stdin)
507 ? bb_msg_standard_input
508 : file_list[-1]
509 );
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200510 exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000511 }
512 fclose_if_not_stdin(in_stream);
513 in_stream = NULL;
514 }
515
516 if (ferror(stdout)) {
Denys Vlasenko9d96e272011-05-21 18:38:59 +0200517 bb_error_msg_and_die(bb_msg_write_error);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000518 }
519}
520
521/* If S points to a single valid modern od format string, put
Denis Vlasenko7089c312008-04-14 19:50:06 +0000522 a description of that format in *TSPEC, return pointer to
523 character following the just-decoded format.
524 For example, if S were "d4afL", we will return a rtp to "afL"
525 and *TSPEC would be
Denis Vlasenko1114de72006-10-10 23:26:05 +0000526 {
527 fmt = SIGNED_DECIMAL;
528 size = INT or LONG; (whichever integral_type_size[4] resolves to)
529 print_function = print_int; (assuming size == INT)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000530 fmt_string = "%011d%c";
Denis Vlasenko1114de72006-10-10 23:26:05 +0000531 }
532 S_ORIG is solely for reporting errors. It should be the full format
Denis Vlasenko601ae132006-11-28 23:37:46 +0000533 string argument. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000534
Denys Vlasenkob9542cb2010-06-01 23:16:46 +0200535static NOINLINE const char *
Denis Vlasenko7089c312008-04-14 19:50:06 +0000536decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000537{
538 enum size_spec size_spec;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000539 unsigned size;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000540 enum output_format fmt;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000541 const char *p;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000542 char *end;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000543 char *fmt_string = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000544 void (*print_function) (size_t, const char *, const char *);
545 unsigned c;
546 unsigned field_width = 0;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000547 int pos;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000548
Denis Vlasenko1114de72006-10-10 23:26:05 +0000549 switch (*s) {
550 case 'd':
551 case 'o':
552 case 'u':
Denis Vlasenko601ae132006-11-28 23:37:46 +0000553 case 'x': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000554 static const char CSIL[] ALIGN1 = "CSIL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000555
556 c = *s++;
557 p = strchr(CSIL, *s);
Denys Vlasenko11f3a8b2009-11-22 15:37:16 +0100558 /* if *s == NUL, p != NULL! Testcase: "od -tx" */
559 if (!p || *p == '\0') {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000560 size = sizeof(int);
561 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000562 size = bb_strtou(s, &end, 0);
563 if (errno == ERANGE
564 || MAX_INTEGRAL_TYPE_SIZE < size
Denis Vlasenko1114de72006-10-10 23:26:05 +0000565 || integral_type_size[size] == NO_SIZE
566 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000567 bb_error_msg_and_die("invalid type string '%s'; "
568 "%u-byte %s type is not supported",
569 s_orig, size, "integral");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000570 }
571 s = end;
572 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000573 } else {
Denis Vlasenko7089c312008-04-14 19:50:06 +0000574 static const uint8_t CSIL_sizeof[4] = {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000575 sizeof(char),
576 sizeof(short),
577 sizeof(int),
578 sizeof(long),
579 };
580 size = CSIL_sizeof[p - CSIL];
Denis Vlasenko7089c312008-04-14 19:50:06 +0000581 s++; /* skip C/S/I/L */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000582 }
583
584#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
585 ((Spec) == LONG_LONG ? (Max_format) \
586 : ((Spec) == LONG ? (Long_format) : (Min_format)))
587
588#define FMT_BYTES_ALLOCATED 9
Denis Vlasenko1114de72006-10-10 23:26:05 +0000589 size_spec = integral_type_size[size];
590
Denis Vlasenko601ae132006-11-28 23:37:46 +0000591 {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000592 static const char doux[] ALIGN1 = "doux";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000593 static const char doux_fmt_letter[][4] = {
594 "lld", "llo", "llu", "llx"
595 };
596 static const enum output_format doux_fmt[] = {
597 SIGNED_DECIMAL,
598 OCTAL,
599 UNSIGNED_DECIMAL,
600 HEXADECIMAL,
601 };
602 static const uint8_t *const doux_bytes_to_XXX[] = {
603 bytes_to_signed_dec_digits,
604 bytes_to_oct_digits,
605 bytes_to_unsigned_dec_digits,
606 bytes_to_hex_digits,
607 };
608 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
609 " %%%u%s",
610 " %%0%u%s",
611 " %%%u%s",
612 " %%0%u%s",
613 };
Denis Vlasenko1114de72006-10-10 23:26:05 +0000614
Denis Vlasenko601ae132006-11-28 23:37:46 +0000615 pos = strchr(doux, c) - doux;
616 fmt = doux_fmt[pos];
617 field_width = doux_bytes_to_XXX[pos][size];
618 p = doux_fmt_letter[pos] + 2;
619 if (size_spec == LONG) p--;
620 if (size_spec == LONG_LONG) p -= 2;
621 fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
622 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000623
624 switch (size_spec) {
625 case CHAR:
626 print_function = (fmt == SIGNED_DECIMAL
627 ? print_s_char
628 : print_char);
629 break;
630 case SHORT:
631 print_function = (fmt == SIGNED_DECIMAL
632 ? print_s_short
633 : print_short);
634 break;
635 case INT:
636 print_function = print_int;
637 break;
638 case LONG:
639 print_function = print_long;
640 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000641 default: /* case LONG_LONG: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000642 print_function = print_long_long;
643 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000644 }
645 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000646 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000647
Denis Vlasenko601ae132006-11-28 23:37:46 +0000648 case 'f': {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000649 static const char FDL[] ALIGN1 = "FDL";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000650
Denis Vlasenko1114de72006-10-10 23:26:05 +0000651 fmt = FLOATING_POINT;
652 ++s;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000653 p = strchr(FDL, *s);
654 if (!p) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000655 size = sizeof(double);
656 if (isdigit(s[0])) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000657 size = bb_strtou(s, &end, 0);
658 if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
Denis Vlasenko1114de72006-10-10 23:26:05 +0000659 || fp_type_size[size] == NO_SIZE
660 ) {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000661 bb_error_msg_and_die("invalid type string '%s'; "
662 "%u-byte %s type is not supported",
663 s_orig, size, "floating point");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000664 }
665 s = end;
666 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000667 } else {
668 static const uint8_t FDL_sizeof[] = {
669 sizeof(float),
670 sizeof(double),
671 sizeof(longdouble_t),
672 };
673
674 size = FDL_sizeof[p - FDL];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000675 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000676
Denis Vlasenko1114de72006-10-10 23:26:05 +0000677 size_spec = fp_type_size[size];
678
679 switch (size_spec) {
680 case FLOAT_SINGLE:
681 print_function = print_float;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000682 field_width = FLT_DIG + 8;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000683 /* Don't use %#e; not all systems support it. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000684 fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000685 break;
686 case FLOAT_DOUBLE:
687 print_function = print_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000688 field_width = DBL_DIG + 8;
689 fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000690 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000691 default: /* case FLOAT_LONG_DOUBLE: */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000692 print_function = print_long_double;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000693 field_width = LDBL_DIG + 8;
694 fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000695 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000696 }
697 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000698 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000699
700 case 'a':
701 ++s;
702 fmt = NAMED_CHARACTER;
703 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000704 print_function = print_named_ascii;
705 field_width = 3;
706 break;
707 case 'c':
708 ++s;
709 fmt = CHARACTER;
710 size_spec = CHAR;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000711 print_function = print_ascii;
712 field_width = 3;
713 break;
714 default:
Denis Vlasenko601ae132006-11-28 23:37:46 +0000715 bb_error_msg_and_die("invalid character '%c' "
716 "in type string '%s'", *s, s_orig);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000717 }
718
719 tspec->size = size_spec;
720 tspec->fmt = fmt;
721 tspec->print_function = print_function;
722 tspec->fmt_string = fmt_string;
723
724 tspec->field_width = field_width;
725 tspec->hexl_mode_trailer = (*s == 'z');
726 if (tspec->hexl_mode_trailer)
727 s++;
728
Denis Vlasenko7089c312008-04-14 19:50:06 +0000729 return s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000730}
731
732/* Decode the modern od format string S. Append the decoded
733 representation to the global array SPEC, reallocating SPEC if
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000734 necessary. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000735
Denis Vlasenko601ae132006-11-28 23:37:46 +0000736static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000737decode_format_string(const char *s)
738{
739 const char *s_orig = s;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000740
741 while (*s != '\0') {
742 struct tspec tspec;
743 const char *next;
744
Denis Vlasenko7089c312008-04-14 19:50:06 +0000745 next = decode_one_format(s_orig, s, &tspec);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000746
747 assert(s != next);
748 s = next;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000749 spec = xrealloc_vector(spec, 4, n_specs);
750 memcpy(&spec[n_specs], &tspec, sizeof(spec[0]));
Denis Vlasenko1114de72006-10-10 23:26:05 +0000751 n_specs++;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000752 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000753}
754
755/* Given a list of one or more input filenames FILE_LIST, set the global
756 file pointer IN_STREAM to position N_SKIP in the concatenation of
757 those files. If any file operation fails or if there are fewer than
758 N_SKIP bytes in the combined input, give an error message and return
759 nonzero. When possible, use seek rather than read operations to
760 advance IN_STREAM. */
761
Denis Vlasenko601ae132006-11-28 23:37:46 +0000762static void
763skip(off_t n_skip)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000764{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000765 if (n_skip == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000766 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000767
Denis Vlasenko601ae132006-11-28 23:37:46 +0000768 while (in_stream) { /* !EOF */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000769 struct stat file_stats;
770
771 /* First try seeking. For large offsets, this extra work is
772 worthwhile. If the offset is below some threshold it may be
773 more efficient to move the pointer by reading. There are two
774 issues when trying to seek:
775 - the file must be seekable.
776 - before seeking to the specified position, make sure
777 that the new position is in the current file.
778 Try to do that by getting file's size using fstat.
779 But that will work only for regular files. */
780
Denis Vlasenko1114de72006-10-10 23:26:05 +0000781 /* The st_size field is valid only for regular files
782 (and for symbolic links, which cannot occur here).
783 If the number of bytes left to skip is at least
784 as large as the size of the current file, we can
785 decrement n_skip and go on to the next file. */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000786 if (fstat(fileno(in_stream), &file_stats) == 0
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000787 && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
Denis Vlasenko601ae132006-11-28 23:37:46 +0000788 ) {
789 if (file_stats.st_size < n_skip) {
790 n_skip -= file_stats.st_size;
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000791 /* take "check & close / open_next" route */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000792 } else {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000793 if (fseeko(in_stream, n_skip, SEEK_CUR) != 0)
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200794 exit_code = 1;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000795 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000796 }
Denis Vlasenko601ae132006-11-28 23:37:46 +0000797 } else {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000798 /* If it's not a regular file with positive size,
Denis Vlasenko601ae132006-11-28 23:37:46 +0000799 position the file pointer by reading. */
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000800 char buf[1024];
801 size_t n_bytes_to_read = 1024;
802 size_t n_bytes_read;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000803
Denis Vlasenko601ae132006-11-28 23:37:46 +0000804 while (n_skip > 0) {
805 if (n_skip < n_bytes_to_read)
806 n_bytes_to_read = n_skip;
807 n_bytes_read = fread(buf, 1, n_bytes_to_read, in_stream);
808 n_skip -= n_bytes_read;
809 if (n_bytes_read != n_bytes_to_read)
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000810 break; /* EOF on this file or error */
Denis Vlasenko601ae132006-11-28 23:37:46 +0000811 }
812 }
813 if (n_skip == 0)
814 return;
815
816 check_and_close();
817 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000818 }
819
Denis Vlasenko601ae132006-11-28 23:37:46 +0000820 if (n_skip)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100821 bb_error_msg_and_die("can't skip past end of combined input");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000822}
823
Denis Vlasenko601ae132006-11-28 23:37:46 +0000824
825typedef void FN_format_address(off_t address, char c);
826
Denis Vlasenko1114de72006-10-10 23:26:05 +0000827static void
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000828format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000829{
830}
831
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000832static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
Denis Vlasenko601ae132006-11-28 23:37:46 +0000833/* Corresponds to 'x' above */
834#define address_base_char address_fmt[sizeof(address_fmt)-3]
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000835/* Corresponds to 'n' above */
836#define address_pad_len_char address_fmt[2]
Denis Vlasenko601ae132006-11-28 23:37:46 +0000837
Denis Vlasenko1114de72006-10-10 23:26:05 +0000838static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000839format_address_std(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000840{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000841 /* Corresponds to 'c' */
842 address_fmt[sizeof(address_fmt)-2] = c;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000843 printf(address_fmt, address);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000844}
845
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200846#if ENABLE_LONG_OPTS
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000847/* only used with --traditional */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000848static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000849format_address_paren(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000850{
851 putchar('(');
852 format_address_std(address, ')');
Denis Vlasenko0f5905e2006-12-17 19:21:13 +0000853 if (c) putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000854}
855
856static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000857format_address_label(off_t address, char c)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000858{
859 format_address_std(address, ' ');
860 format_address_paren(address + pseudo_offset, c);
861}
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000862#endif
Denis Vlasenko601ae132006-11-28 23:37:46 +0000863
864static void
865dump_hexl_mode_trailer(size_t n_bytes, const char *block)
866{
867 fputs(" >", stdout);
868 while (n_bytes--) {
869 unsigned c = *(unsigned char *) block++;
870 c = (ISPRINT(c) ? c : '.');
871 putchar(c);
872 }
873 putchar('<');
874}
875
Denis Vlasenko1114de72006-10-10 23:26:05 +0000876/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
877 of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
878 CURR_BLOCK in the concatenation of input files, and it is printed
879 (optionally) only before the output line associated with the first
880 format spec. When duplicate blocks are being abbreviated, the output
881 for a sequence of identical input blocks is the output for the first
882 block followed by an asterisk alone on a line. It is valid to compare
883 the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
884 That condition may be false only for the last input block -- and then
885 only when it has not been padded to length BYTES_PER_BLOCK. */
886
887static void
Denis Vlasenko601ae132006-11-28 23:37:46 +0000888write_block(off_t current_offset, size_t n_bytes,
Denis Vlasenko1114de72006-10-10 23:26:05 +0000889 const char *prev_block, const char *curr_block)
890{
Denis Vlasenko601ae132006-11-28 23:37:46 +0000891 static char first = 1;
892 static char prev_pair_equal = 0;
893 size_t i;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000894
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200895 if (!(option_mask32 & OPT_v)
896 && !first
Denis Vlasenko1114de72006-10-10 23:26:05 +0000897 && n_bytes == bytes_per_block
898 && memcmp(prev_block, curr_block, bytes_per_block) == 0
899 ) {
900 if (prev_pair_equal) {
901 /* The two preceding blocks were equal, and the current
902 block is the same as the last one, so print nothing. */
903 } else {
904 puts("*");
905 prev_pair_equal = 1;
906 }
907 } else {
Denis Vlasenko601ae132006-11-28 23:37:46 +0000908 first = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000909 prev_pair_equal = 0;
910 for (i = 0; i < n_specs; i++) {
911 if (i == 0)
912 format_address(current_offset, '\0');
913 else
Denis Vlasenko2425bdc2006-11-29 14:32:01 +0000914 printf("%*s", address_pad_len_char - '0', "");
Denis Vlasenko1114de72006-10-10 23:26:05 +0000915 (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string);
916 if (spec[i].hexl_mode_trailer) {
917 /* space-pad out to full line width, then dump the trailer */
Denys Vlasenkob8086142011-05-21 19:15:55 +0200918 unsigned datum_width = width_bytes[spec[i].size];
919 unsigned blank_fields = (bytes_per_block - n_bytes) / datum_width;
920 unsigned field_width = spec[i].field_width + 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000921 printf("%*s", blank_fields * field_width, "");
922 dump_hexl_mode_trailer(n_bytes, curr_block);
923 }
924 putchar('\n');
925 }
926 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000927}
928
Denis Vlasenko601ae132006-11-28 23:37:46 +0000929static void
Denis Vlasenko1114de72006-10-10 23:26:05 +0000930read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
931{
Denis Vlasenko1114de72006-10-10 23:26:05 +0000932 assert(0 < n && n <= bytes_per_block);
933
934 *n_bytes_in_buffer = 0;
935
936 if (n == 0)
Denis Vlasenko601ae132006-11-28 23:37:46 +0000937 return;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000938
939 while (in_stream != NULL) { /* EOF. */
940 size_t n_needed;
941 size_t n_read;
942
943 n_needed = n - *n_bytes_in_buffer;
944 n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, in_stream);
945 *n_bytes_in_buffer += n_read;
946 if (n_read == n_needed)
947 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +0000948 /* error check is done in check_and_close */
949 check_and_close();
950 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +0000951 }
Denis Vlasenko1114de72006-10-10 23:26:05 +0000952}
953
954/* Return the least common multiple of the sizes associated
955 with the format specs. */
956
957static int
958get_lcm(void)
959{
960 size_t i;
961 int l_c_m = 1;
962
963 for (i = 0; i < n_specs; i++)
964 l_c_m = lcm(l_c_m, width_bytes[(int) spec[i].size]);
965 return l_c_m;
966}
967
Denis Vlasenko1114de72006-10-10 23:26:05 +0000968/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
969 formatted block to standard output, and repeat until the specified
970 maximum number of bytes has been read or until all input has been
971 processed. If the last block read is smaller than BYTES_PER_BLOCK
972 and its size is not a multiple of the size associated with a format
973 spec, extend the input block with zero bytes until its length is a
974 multiple of all format spec sizes. Write the final block. Finally,
975 write on a line by itself the offset of the byte after the last byte
Denis Vlasenko97bd0e02008-02-08 15:41:01 +0000976 read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +0000977
Denis Vlasenko601ae132006-11-28 23:37:46 +0000978static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +0000979dump(off_t current_offset, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +0000980{
981 char *block[2];
Denis Vlasenko1114de72006-10-10 23:26:05 +0000982 int idx;
Denis Vlasenko1114de72006-10-10 23:26:05 +0000983 size_t n_bytes_read;
984
Denys Vlasenkob8086142011-05-21 19:15:55 +0200985 block[0] = xmalloc(2 * bytes_per_block);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000986 block[1] = block[0] + bytes_per_block;
987
Denis Vlasenko1114de72006-10-10 23:26:05 +0000988 idx = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +0200989 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +0000990 while (1) {
991 size_t n_needed;
992 if (current_offset >= end_offset) {
993 n_bytes_read = 0;
994 break;
995 }
Denys Vlasenkob8086142011-05-21 19:15:55 +0200996 n_needed = MIN(end_offset - current_offset, (off_t) bytes_per_block);
Denis Vlasenko601ae132006-11-28 23:37:46 +0000997 read_block(n_needed, block[idx], &n_bytes_read);
Denis Vlasenko1114de72006-10-10 23:26:05 +0000998 if (n_bytes_read < bytes_per_block)
999 break;
1000 assert(n_bytes_read == bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001001 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001002 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001003 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001004 }
1005 } else {
1006 while (1) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001007 read_block(bytes_per_block, block[idx], &n_bytes_read);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001008 if (n_bytes_read < bytes_per_block)
1009 break;
1010 assert(n_bytes_read == bytes_per_block);
Denys Vlasenkob8086142011-05-21 19:15:55 +02001011 write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001012 current_offset += n_bytes_read;
Denys Vlasenkob8086142011-05-21 19:15:55 +02001013 idx ^= 1;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001014 }
1015 }
1016
1017 if (n_bytes_read > 0) {
1018 int l_c_m;
1019 size_t bytes_to_write;
1020
1021 l_c_m = get_lcm();
1022
1023 /* Make bytes_to_write the smallest multiple of l_c_m that
Tanguy Pruvot823694d2012-11-18 13:20:29 +01001024 is at least as large as n_bytes_read. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001025 bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
1026
1027 memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
1028 write_block(current_offset, bytes_to_write,
Tanguy Pruvot823694d2012-11-18 13:20:29 +01001029 block[idx ^ 1], block[idx]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001030 current_offset += n_bytes_read;
1031 }
1032
1033 format_address(current_offset, '\n');
1034
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001035 if ((option_mask32 & OPT_N) && current_offset >= end_offset)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001036 check_and_close();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001037
1038 free(block[0]);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001039}
1040
Denis Vlasenko601ae132006-11-28 23:37:46 +00001041/* Read N bytes into BLOCK from the concatenation of the input files
1042 named in the global array FILE_LIST. On the first call to this
1043 function, the global variable IN_STREAM is expected to be an open
1044 stream associated with the input file INPUT_FILENAME. If all N
1045 bytes cannot be read from IN_STREAM, close IN_STREAM and update
1046 the global variables IN_STREAM and INPUT_FILENAME. Then try to
1047 read the remaining bytes from the newly opened file. Repeat if
1048 necessary until EOF is reached for the last file in FILE_LIST.
1049 On subsequent calls, don't modify BLOCK and return zero. Set
1050 *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
1051 it will be detected through ferror when the stream is about to be
1052 closed. If there is an error, give a message but continue reading
1053 as usual and return nonzero. Otherwise return zero. */
1054
Denis Vlasenko1114de72006-10-10 23:26:05 +00001055/* STRINGS mode. Find each "string constant" in the input.
1056 A string constant is a run of at least 'string_min' ASCII
1057 graphic (or formatting) characters terminated by a null.
1058 Based on a function written by Richard Stallman for a
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001059 traditional version of od. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001060
Denis Vlasenko601ae132006-11-28 23:37:46 +00001061static void
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001062dump_strings(off_t address, off_t end_offset)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001063{
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001064 unsigned bufsize = MAX(100, string_min);
1065 unsigned char *buf = xmalloc(bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001066
Denis Vlasenko1114de72006-10-10 23:26:05 +00001067 while (1) {
1068 size_t i;
1069 int c;
1070
1071 /* See if the next 'string_min' chars are all printing chars. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001072 tryline:
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001073 if ((option_mask32 & OPT_N) && (end_offset - string_min <= address))
Denis Vlasenko1114de72006-10-10 23:26:05 +00001074 break;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001075 i = 0;
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001076 while (!(option_mask32 & OPT_N) || address < end_offset) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001077 if (i == bufsize) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001078 bufsize += bufsize/8;
1079 buf = xrealloc(buf, bufsize);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001080 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001081
1082 while (in_stream) { /* !EOF */
1083 c = fgetc(in_stream);
1084 if (c != EOF)
1085 goto got_char;
1086 check_and_close();
1087 open_next_file();
Denis Vlasenko1114de72006-10-10 23:26:05 +00001088 }
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001089 /* EOF */
1090 goto ret;
1091 got_char:
Denis Vlasenko601ae132006-11-28 23:37:46 +00001092 address++;
1093 if (!c)
1094 break;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001095 if (!ISPRINT(c))
1096 goto tryline; /* It isn't; give up on this string. */
1097 buf[i++] = c; /* String continues; store it all. */
1098 }
1099
Denis Vlasenko601ae132006-11-28 23:37:46 +00001100 if (i < string_min) /* Too short! */
1101 goto tryline;
1102
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001103 /* If we get here, the string is all printable and NUL-terminated */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001104 buf[i] = 0;
1105 format_address(address - i - 1, ' ');
1106
1107 for (i = 0; (c = buf[i]); i++) {
1108 switch (c) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001109 case '\007': fputs("\\a", stdout); break;
1110 case '\b': fputs("\\b", stdout); break;
1111 case '\f': fputs("\\f", stdout); break;
1112 case '\n': fputs("\\n", stdout); break;
1113 case '\r': fputs("\\r", stdout); break;
1114 case '\t': fputs("\\t", stdout); break;
1115 case '\v': fputs("\\v", stdout); break;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001116 default: putchar(c);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001117 }
1118 }
1119 putchar('\n');
1120 }
1121
1122 /* We reach this point only if we search through
1123 (max_bytes_to_format - string_min) bytes before reaching EOF. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001124 check_and_close();
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001125 ret:
1126 free(buf);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001127}
1128
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001129#if ENABLE_LONG_OPTS
1130/* If S is a valid traditional offset specification with an optional
1131 leading '+' return nonzero and set *OFFSET to the offset it denotes. */
1132
1133static int
1134parse_old_offset(const char *s, off_t *offset)
1135{
1136 static const struct suffix_mult Bb[] = {
1137 { "B", 1024 },
1138 { "b", 512 },
1139 { "", 0 }
1140 };
1141 char *p;
1142 int radix;
1143
1144 /* Skip over any leading '+'. */
1145 if (s[0] == '+') ++s;
1146 if (!isdigit(s[0])) return 0; /* not a number */
1147
1148 /* Determine the radix we'll use to interpret S. If there is a '.',
1149 * it's decimal, otherwise, if the string begins with '0X'or '0x',
1150 * it's hexadecimal, else octal. */
1151 p = strchr(s, '.');
1152 radix = 8;
1153 if (p) {
1154 p[0] = '\0'; /* cheating */
1155 radix = 10;
1156 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1157 radix = 16;
1158
1159 *offset = xstrtooff_sfx(s, radix, Bb);
1160 if (p) p[0] = '.';
1161
1162 return (*offset >= 0);
1163}
1164#endif
1165
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001166int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001167int od_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1114de72006-10-10 23:26:05 +00001168{
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001169#if ENABLE_LONG_OPTS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001170 static const char od_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001171 "skip-bytes\0" Required_argument "j"
1172 "address-radix\0" Required_argument "A"
1173 "read-bytes\0" Required_argument "N"
1174 "format\0" Required_argument "t"
1175 "output-duplicates\0" No_argument "v"
Denys Vlasenkod3733552011-05-21 18:47:51 +02001176 /* Yes, it's true: -S NUM, but --strings[=NUM]!
1177 * that is, NUM is mandatory for -S but optional for --strings!
1178 */
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001179 "strings\0" Optional_argument "S"
1180 "width\0" Optional_argument "w"
1181 "traditional\0" No_argument "\xff"
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001182 ;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001183#endif
Denys Vlasenkod3733552011-05-21 18:47:51 +02001184 const char *str_A, *str_N, *str_j, *str_S = "3";
Denis Vlasenko601ae132006-11-28 23:37:46 +00001185 llist_t *lst_t = NULL;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001186 unsigned opt;
1187 int l_c_m;
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001188 /* The number of input bytes to skip before formatting and writing. */
1189 off_t n_bytes_to_skip = 0;
1190 /* The offset of the first byte after the last byte to be formatted. */
1191 off_t end_offset = 0;
1192 /* The maximum number of bytes that will be formatted. */
1193 off_t max_bytes_to_format = 0;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001194
1195 spec = NULL;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001196 format_address = format_address_std;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001197 address_base_char = 'o';
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001198 address_pad_len_char = '7';
Denis Vlasenko1114de72006-10-10 23:26:05 +00001199
Denis Vlasenko601ae132006-11-28 23:37:46 +00001200 /* Parse command line */
Denis Vlasenko1d426652008-03-17 09:09:09 +00001201 opt_complementary = "w+:t::"; /* -w N, -t is a list */
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001202#if ENABLE_LONG_OPTS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +00001203 applet_long_options = od_longopts;
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001204#endif
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001205 opt = OD_GETOPT32();
Denis Vlasenko601ae132006-11-28 23:37:46 +00001206 argv += optind;
1207 if (opt & OPT_A) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001208 static const char doxn[] ALIGN1 = "doxn";
1209 static const char doxn_address_base_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001210 'u', 'o', 'x', /* '?' fourth one is not important */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001211 };
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001212 static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001213 '7', '7', '6', /* '?' */
1214 };
Denis Vlasenko601ae132006-11-28 23:37:46 +00001215 char *p;
1216 int pos;
1217 p = strchr(doxn, str_A[0]);
1218 if (!p)
1219 bb_error_msg_and_die("bad output address radix "
1220 "'%c' (must be [doxn])", str_A[0]);
1221 pos = p - doxn;
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001222 if (pos == 3) format_address = format_address_none;
Denis Vlasenko601ae132006-11-28 23:37:46 +00001223 address_base_char = doxn_address_base_char[pos];
Denis Vlasenko2425bdc2006-11-29 14:32:01 +00001224 address_pad_len_char = doxn_address_pad_len_char[pos];
Denis Vlasenko1114de72006-10-10 23:26:05 +00001225 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001226 if (opt & OPT_N) {
maxwen27116ba2015-08-14 21:41:28 +02001227 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001228 }
1229 if (opt & OPT_a) decode_format_string("a");
1230 if (opt & OPT_b) decode_format_string("oC");
1231 if (opt & OPT_c) decode_format_string("c");
1232 if (opt & OPT_d) decode_format_string("u2");
1233 if (opt & OPT_f) decode_format_string("fF");
1234 if (opt & OPT_h) decode_format_string("x2");
1235 if (opt & OPT_i) decode_format_string("d2");
maxwen27116ba2015-08-14 21:41:28 +02001236 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001237 if (opt & OPT_l) decode_format_string("d4");
1238 if (opt & OPT_o) decode_format_string("o2");
Denis Vlasenko601ae132006-11-28 23:37:46 +00001239 while (lst_t) {
Denis Vlasenkod50dda82008-06-15 05:40:56 +00001240 decode_format_string(llist_pop(&lst_t));
Denis Vlasenko601ae132006-11-28 23:37:46 +00001241 }
Denis Vlasenko601ae132006-11-28 23:37:46 +00001242 if (opt & OPT_x) decode_format_string("x2");
1243 if (opt & OPT_s) decode_format_string("d2");
1244 if (opt & OPT_S) {
maxwen27116ba2015-08-14 21:41:28 +02001245 string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001246 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001247
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001248 // Bloat:
1249 //if ((option_mask32 & OPT_S) && n_specs > 0)
1250 // bb_error_msg_and_die("no type may be specified when dumping strings");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001251
Denis Vlasenko1114de72006-10-10 23:26:05 +00001252 /* If the --traditional option is used, there may be from
Denis Vlasenko601ae132006-11-28 23:37:46 +00001253 * 0 to 3 remaining command line arguments; handle each case
1254 * separately.
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001255 * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]]
Denis Vlasenko601ae132006-11-28 23:37:46 +00001256 * The offset and pseudo_start have the same syntax.
1257 *
1258 * FIXME: POSIX 1003.1-2001 with XSI requires support for the
1259 * traditional syntax even if --traditional is not given. */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001260
Denys Vlasenkof3b92d32009-06-19 12:10:38 +02001261#if ENABLE_LONG_OPTS
Denis Vlasenko601ae132006-11-28 23:37:46 +00001262 if (opt & OPT_traditional) {
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001263 if (argv[0]) {
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001264 off_t pseudo_start = -1;
1265 off_t o1, o2;
1266
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001267 if (!argv[1]) { /* one arg */
1268 if (parse_old_offset(argv[0], &o1)) {
1269 /* od --traditional OFFSET */
1270 n_bytes_to_skip = o1;
1271 argv++;
1272 }
1273 /* od --traditional FILE */
1274 } else if (!argv[2]) { /* two args */
1275 if (parse_old_offset(argv[0], &o1)
1276 && parse_old_offset(argv[1], &o2)
1277 ) {
1278 /* od --traditional OFFSET LABEL */
1279 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001280 pseudo_start = o2;
1281 argv += 2;
1282 } else if (parse_old_offset(argv[1], &o2)) {
1283 /* od --traditional FILE OFFSET */
1284 n_bytes_to_skip = o2;
1285 argv[1] = NULL;
1286 } else {
1287 bb_error_msg_and_die("invalid second argument '%s'", argv[1]);
1288 }
1289 } else if (!argv[3]) { /* three args */
1290 if (parse_old_offset(argv[1], &o1)
1291 && parse_old_offset(argv[2], &o2)
1292 ) {
1293 /* od --traditional FILE OFFSET LABEL */
1294 n_bytes_to_skip = o1;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001295 pseudo_start = o2;
1296 argv[1] = NULL;
1297 } else {
1298 bb_error_msg_and_die("the last two arguments must be offsets");
1299 }
1300 } else { /* >3 args */
1301 bb_error_msg_and_die("too many arguments");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001302 }
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001303
1304 if (pseudo_start >= 0) {
1305 if (format_address == format_address_none) {
1306 address_base_char = 'o';
1307 address_pad_len_char = '7';
1308 format_address = format_address_paren;
1309 } else {
1310 format_address = format_address_label;
1311 }
1312 pseudo_offset = pseudo_start - n_bytes_to_skip;
1313 }
Denis Vlasenko1114de72006-10-10 23:26:05 +00001314 }
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001315 /* else: od --traditional (without args) */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001316 }
Denis Vlasenkoc61852a2006-11-29 11:09:43 +00001317#endif
Denis Vlasenko1114de72006-10-10 23:26:05 +00001318
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001319 if (option_mask32 & OPT_N) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001320 end_offset = n_bytes_to_skip + max_bytes_to_format;
1321 if (end_offset < n_bytes_to_skip)
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001322 bb_error_msg_and_die("SKIP + SIZE is too large");
Denis Vlasenko1114de72006-10-10 23:26:05 +00001323 }
1324
1325 if (n_specs == 0) {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001326 decode_format_string("o2");
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001327 /*n_specs = 1; - done by decode_format_string */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001328 }
1329
Denis Vlasenko601ae132006-11-28 23:37:46 +00001330 /* If no files were listed on the command line,
1331 set the global pointer FILE_LIST so that it
1332 references the null-terminated list of one name: "-". */
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001333 file_list = bb_argv_dash;
Denys Vlasenko5c10fa52011-05-21 17:43:06 +02001334 if (argv[0]) {
Denis Vlasenko1114de72006-10-10 23:26:05 +00001335 /* Set the global pointer FILE_LIST so that it
1336 references the first file-argument on the command-line. */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001337 file_list = (char const *const *) argv;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001338 }
1339
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001340 /* Open the first input file */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001341 open_next_file();
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001342 /* Skip over any unwanted header bytes */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001343 skip(n_bytes_to_skip);
1344 if (!in_stream)
Bernhard Reutner-Fischer7c2db5c2007-11-16 12:39:16 +00001345 return EXIT_FAILURE;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001346
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001347 /* Compute output block length */
Denis Vlasenko1114de72006-10-10 23:26:05 +00001348 l_c_m = get_lcm();
1349
Denis Vlasenko601ae132006-11-28 23:37:46 +00001350 if (opt & OPT_w) { /* -w: width */
Denis Vlasenko601ae132006-11-28 23:37:46 +00001351 if (!bytes_per_block || bytes_per_block % l_c_m != 0) {
Denis Vlasenko97bd0e02008-02-08 15:41:01 +00001352 bb_error_msg("warning: invalid width %u; using %d instead",
1353 (unsigned)bytes_per_block, l_c_m);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001354 bytes_per_block = l_c_m;
1355 }
1356 } else {
Denis Vlasenko601ae132006-11-28 23:37:46 +00001357 bytes_per_block = l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001358 if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
Denis Vlasenko601ae132006-11-28 23:37:46 +00001359 bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001360 }
1361
1362#ifdef DEBUG
1363 for (i = 0; i < n_specs; i++) {
1364 printf("%d: fmt=\"%s\" width=%d\n",
1365 i, spec[i].fmt_string, width_bytes[spec[i].size]);
1366 }
1367#endif
1368
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001369 if (option_mask32 & OPT_S)
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001370 dump_strings(n_bytes_to_skip, end_offset);
Denis Vlasenko601ae132006-11-28 23:37:46 +00001371 else
Denis Vlasenkoe4bc6032007-12-24 12:14:24 +00001372 dump(n_bytes_to_skip, end_offset);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001373
Denys Vlasenko9d96e272011-05-21 18:38:59 +02001374 if (fclose(stdin))
Tanguy Pruvot8aeb3712011-06-30 08:59:26 +02001375 bb_perror_msg_and_die("%s", bb_msg_standard_input);
Denis Vlasenko1114de72006-10-10 23:26:05 +00001376
Denys Vlasenko3ef344b2011-05-21 18:38:40 +02001377 return exit_code;
Denis Vlasenko1114de72006-10-10 23:26:05 +00001378}