/* Written by Jim Meyering. */
-/* Busyboxed by Denis Vlasenko
+/* Busyboxed by Denys Vlasenko
Based on od.c from coreutils-5.2.1
Top bloat sources:
*/
#include "libbb.h"
-#include <getopt.h>
#define assert(a) ((void)0)
/* The difference between the old-style pseudo starting address and
the number of bytes to skip. */
static off_t pseudo_offset;
-/* The number of input bytes to skip before formatting and writing. */
-static off_t n_bytes_to_skip;
/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
input is formatted. */
-/* The maximum number of bytes that will be formatted. */
-static off_t max_bytes_to_format;
-/* The offset of the first byte after the last byte to be formatted. */
-static off_t end_offset;
/* The number of input bytes formatted per output line. It must be
a multiple of the least common multiple of the sizes associated with
the specified output types. It should be as large as possible, but
no larger than 16 -- unless specified with the -w option. */
-static size_t bytes_per_block;
-
-/* Human-readable representation of *file_list (for error messages).
- It differs from *file_list only when *file_list is "-". */
-static char const *input_filename;
+static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */
/* A NULL-terminated list of the file-arguments from the command line. */
-static char const *const *file_list;
-
-/* Initializer for file_list if no file-arguments
- were specified on the command line. */
-static char const *const default_file_list[] = { "-", NULL };
+static const char *const *file_list;
/* The input stream associated with the current file. */
static FILE *in_stream;
#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
-static unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
+static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
[sizeof(char)] = CHAR,
#if USHRT_MAX != UCHAR_MAX
[sizeof(short)] = SHORT,
};
#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
-static unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
+static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
/* gcc seems to allow repeated indexes. Last one stays */
[sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
[sizeof(double)] = FLOAT_DOUBLE,
}
/* print_[named]_ascii are optimized for speed.
- * Remember, someday you may want to pump gigabytes thru this thing.
+ * Remember, someday you may want to pump gigabytes through this thing.
* Saving a dozen of .text bytes here is counter-productive */
static void
print_named_ascii(size_t n_bytes, const char *block,
- const char *unused_fmt_string ATTRIBUTE_UNUSED)
+ const char *unused_fmt_string UNUSED_PARAM)
{
/* Names for some non-printing characters. */
static const char charname[33][3] ALIGN1 = {
static void
print_ascii(size_t n_bytes, const char *block,
- const char *unused_fmt_string ATTRIBUTE_UNUSED)
+ const char *unused_fmt_string UNUSED_PARAM)
{
// buf[N] pos: 01234 56789
char buf[12] = " x\0 0xx\0";
open_next_file(void)
{
while (1) {
- input_filename = *file_list;
- if (!input_filename)
+ if (!*file_list)
return;
- file_list++;
- in_stream = fopen_or_warn_stdin(input_filename);
+ in_stream = fopen_or_warn_stdin(*file_list++);
if (in_stream) {
- if (in_stream == stdin)
- input_filename = bb_msg_standard_input;
break;
}
ioerror = 1;
{
if (in_stream) {
if (ferror(in_stream)) {
- bb_error_msg("%s: read error", input_filename);
+ bb_error_msg("%s: read error", (in_stream == stdin)
+ ? bb_msg_standard_input
+ : file_list[-1]
+ );
ioerror = 1;
}
fclose_if_not_stdin(in_stream);
}
/* If S points to a single valid modern od format string, put
- a description of that format in *TSPEC, make *NEXT point at the
- character following the just-decoded format (if *NEXT is non-NULL),
- and return zero. For example, if S were "d4afL"
- *NEXT would be set to "afL" and *TSPEC would be
+ a description of that format in *TSPEC, return pointer to
+ character following the just-decoded format.
+ For example, if S were "d4afL", we will return a rtp to "afL"
+ and *TSPEC would be
{
fmt = SIGNED_DECIMAL;
size = INT or LONG; (whichever integral_type_size[4] resolves to)
S_ORIG is solely for reporting errors. It should be the full format
string argument. */
-static void
-decode_one_format(const char *s_orig, const char *s, const char **next,
- struct tspec *tspec)
+static const char *
+decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
{
enum size_spec size_spec;
unsigned size;
unsigned field_width = 0;
int pos;
- assert(tspec != NULL);
switch (*s) {
case 'd':
s = end;
}
} else {
- static const uint8_t CSIL_sizeof[] = {
+ static const uint8_t CSIL_sizeof[4] = {
sizeof(char),
sizeof(short),
sizeof(int),
sizeof(long),
};
size = CSIL_sizeof[p - CSIL];
+ s++; /* skip C/S/I/L */
}
#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
if (tspec->hexl_mode_trailer)
s++;
- if (next != NULL)
- *next = s;
+ return s;
}
/* Decode the modern od format string S. Append the decoded
representation to the global array SPEC, reallocating SPEC if
- necessary. Return zero if S is valid, nonzero otherwise. */
+ necessary. */
static void
decode_format_string(const char *s)
struct tspec tspec;
const char *next;
- decode_one_format(s_orig, s, &next, &tspec);
+ next = decode_one_format(s_orig, s, &tspec);
assert(s != next);
s = next;
+ spec = xrealloc_vector(spec, 4, n_specs);
+ memcpy(&spec[n_specs], &tspec, sizeof(spec[0]));
n_specs++;
- spec = xrealloc(spec, n_specs * sizeof(*spec));
- memcpy(&spec[n_specs-1], &tspec, sizeof *spec);
}
}
as large as the size of the current file, we can
decrement n_skip and go on to the next file. */
if (fstat(fileno(in_stream), &file_stats) == 0
- && S_ISREG(file_stats.st_mode) && file_stats.st_size >= 0
+ && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
) {
if (file_stats.st_size < n_skip) {
n_skip -= file_stats.st_size;
- /* take check&close / open_next route */
+ /* take "check & close / open_next" route */
} else {
if (fseeko(in_stream, n_skip, SEEK_CUR) != 0)
ioerror = 1;
return;
}
} else {
- /* If it's not a regular file with nonnegative size,
+ /* If it's not a regular file with positive size,
position the file pointer by reading. */
- char buf[BUFSIZ];
- size_t n_bytes_read, n_bytes_to_read = BUFSIZ;
+ char buf[1024];
+ size_t n_bytes_to_read = 1024;
+ size_t n_bytes_read;
while (n_skip > 0) {
if (n_skip < n_bytes_to_read)
typedef void FN_format_address(off_t address, char c);
static void
-format_address_none(off_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED)
+format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
{
}
printf(address_fmt, address);
}
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS
/* only used with --traditional */
static void
format_address_paren(off_t address, char c)
return l_c_m;
}
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS
/* If S is a valid traditional offset specification with an optional
leading '+' return nonzero and set *OFFSET to the offset it denotes. */
static const struct suffix_mult Bb[] = {
{ "B", 1024 },
{ "b", 512 },
- { }
+ { "", 0 }
};
char *p;
int radix;
spec, extend the input block with zero bytes until its length is a
multiple of all format spec sizes. Write the final block. Finally,
write on a line by itself the offset of the byte after the last byte
- read. Accumulate return values from calls to read_block and
- check_and_close, and if any was nonzero, return nonzero.
- Otherwise, return zero. */
+ read. */
static void
-dump(void)
+dump(off_t current_offset, off_t end_offset)
{
char *block[2];
- off_t current_offset;
int idx;
size_t n_bytes_read;
block[0] = xmalloc(2*bytes_per_block);
block[1] = block[0] + bytes_per_block;
- current_offset = n_bytes_to_skip;
-
idx = 0;
if (limit_bytes_to_format) {
while (1) {
and INPUT_FILENAME so they correspond to the next file in the list.
Then try to read a byte from the newly opened file. Repeat if
necessary until EOF is reached for the last file in FILE_LIST, then
- set *C to EOF and return. Subsequent calls do likewise. The return
- value is nonzero if any errors occured, zero otherwise. */
+ set *C to EOF and return. Subsequent calls do likewise. */
static void
read_char(int *c)
A string constant is a run of at least 'string_min' ASCII
graphic (or formatting) characters terminated by a null.
Based on a function written by Richard Stallman for a
- traditional version of od. Return nonzero if an error
- occurs. Otherwise, return zero. */
+ traditional version of od. */
static void
-dump_strings(void)
+dump_strings(off_t address, off_t end_offset)
{
size_t bufsize = MAX(100, string_min);
char *buf = xmalloc(bufsize);
- off_t address = n_bytes_to_skip;
while (1) {
size_t i;
if (i < string_min) /* Too short! */
goto tryline;
- /* If we get here, the string is all printable and null-terminated,
+ /* If we get here, the string is all printable and NUL-terminated,
* so print it. It is all in 'buf' and 'i' is its length. */
buf[i] = 0;
format_address(address - i - 1, ' ');
case '\r': fputs("\\r", stdout); break;
case '\t': fputs("\\t", stdout); break;
case '\v': fputs("\\v", stdout); break;
- default: bb_putchar(c);
+ default: putchar(c);
}
}
putchar('\n');
{ "b", 512 },
{ "k", 1024 },
{ "m", 1024*1024 },
- { }
+ { "", 0 }
};
- unsigned opt;
- int l_c_m;
- /* The old-style 'pseudo starting address' to be printed in parentheses
- after any true address. */
- off_t pseudo_start = 0; // only for gcc
enum {
OPT_A = 1 << 0,
OPT_N = 1 << 1,
OPT_s = 1 << 15,
OPT_S = 1 << 16,
OPT_w = 1 << 17,
- OPT_traditional = (1 << 18) * ENABLE_GETOPT_LONG,
+ OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS,
};
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS
static const char od_longopts[] ALIGN1 =
"skip-bytes\0" Required_argument "j"
"address-radix\0" Required_argument "A"
;
#endif
char *str_A, *str_N, *str_j, *str_S;
- char *str_w = NULL;
llist_t *lst_t = NULL;
+ unsigned opt;
+ int l_c_m;
+ /* The old-style 'pseudo starting address' to be printed in parentheses
+ after any true address. */
+ off_t pseudo_start = pseudo_start; // for gcc
+ /* The number of input bytes to skip before formatting and writing. */
+ off_t n_bytes_to_skip = 0;
+ /* The offset of the first byte after the last byte to be formatted. */
+ off_t end_offset = 0;
+ /* The maximum number of bytes that will be formatted. */
+ off_t max_bytes_to_format = 0;
spec = NULL;
format_address = format_address_std;
/* flag_dump_strings = 0; - already is */
/* Parse command line */
- opt_complementary = "t::"; // list
-#if ENABLE_GETOPT_LONG
+ opt_complementary = "w+:t::"; /* -w N, -t is a list */
+#if ENABLE_LONG_OPTS
applet_long_options = od_longopts;
#endif
opt = getopt32(argv, "A:N:abcdfhij:lot:vxsS:"
// -S was -s and also had optional parameter
// but in coreutils 6.3 it was renamed and now has
// _mandatory_ parameter
- &str_A, &str_N, &str_j, &lst_t, &str_S, &str_w);
+ &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block);
argc -= optind;
argv += optind;
if (opt & OPT_A) {
if (opt & OPT_o) decode_format_string("o2");
//if (opt & OPT_t)...
while (lst_t) {
- decode_format_string(lst_t->data);
- lst_t = lst_t->link;
+ decode_format_string(llist_pop(&lst_t));
}
if (opt & OPT_v) verbose = 1;
if (opt & OPT_x) decode_format_string("x2");
* FIXME: POSIX 1003.1-2001 with XSI requires support for the
* traditional syntax even if --traditional is not given. */
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS
if (opt & OPT_traditional) {
off_t o1, o2;
/* If no files were listed on the command line,
set the global pointer FILE_LIST so that it
references the null-terminated list of one name: "-". */
- file_list = default_file_list;
+ file_list = bb_argv_dash;
if (argc > 0) {
/* Set the global pointer FILE_LIST so that it
references the first file-argument on the command-line. */
l_c_m = get_lcm();
if (opt & OPT_w) { /* -w: width */
- bytes_per_block = 32;
- if (str_w)
- bytes_per_block = xatou(str_w);
if (!bytes_per_block || bytes_per_block % l_c_m != 0) {
- bb_error_msg("warning: invalid width %zu; using %d instead",
- bytes_per_block, l_c_m);
+ bb_error_msg("warning: invalid width %u; using %d instead",
+ (unsigned)bytes_per_block, l_c_m);
bytes_per_block = l_c_m;
}
} else {
#endif
if (flag_dump_strings)
- dump_strings();
+ dump_strings(n_bytes_to_skip, end_offset);
else
- dump();
+ dump(n_bytes_to_skip, end_offset);
if (fclose(stdin) == EOF)
bb_perror_msg_and_die(bb_msg_standard_input);