/* od -- dump files in octal and other formats
- Copyright (C) 92, 1995-2005 Free Software Foundation, Inc.
+ Copyright (C) 1992-2013 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Jim Meyering. */
#include <sys/types.h>
#include "system.h"
#include "error.h"
+#include "ftoastr.h"
#include "quote.h"
+#include "xfreopen.h"
+#include "xprintf.h"
#include "xstrtol.h"
-/* The official name of this program (e.g., no `g' prefix). */
+/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "od"
-#define AUTHORS "Jim Meyering"
-
-#if defined(__GNUC__) || defined(STDC_HEADERS)
-# include <float.h>
-#endif
-
-#ifdef HAVE_LONG_DOUBLE
-typedef long double LONG_DOUBLE;
-#else
-typedef double LONG_DOUBLE;
-#endif
+#define AUTHORS proper_name ("Jim Meyering")
/* The default number of input bytes per output line. */
#define DEFAULT_BYTES_PER_BLOCK 16
-/* The number of decimal digits of precision in a float. */
-#ifndef FLT_DIG
-# define FLT_DIG 7
-#endif
-
-/* The number of decimal digits of precision in a double. */
-#ifndef DBL_DIG
-# define DBL_DIG 15
-#endif
-
-/* The number of decimal digits of precision in a long double. */
-#ifndef LDBL_DIG
-# define LDBL_DIG DBL_DIG
-#endif
-
-#if HAVE_UNSIGNED_LONG_LONG
-typedef unsigned long long int ulonglong_t;
+#if HAVE_UNSIGNED_LONG_LONG_INT
+typedef unsigned long long int unsigned_long_long_int;
#else
-/* This is just a place-holder to avoid a few `#if' directives.
+/* This is just a place-holder to avoid a few '#if' directives.
In this case, the type isn't actually used. */
-typedef unsigned long int ulonglong_t;
+typedef unsigned long int unsigned_long_long_int;
#endif
enum size_spec
CHARACTER
};
-/* The maximum number of bytes needed for a format string,
- including the trailing null. */
+#define MAX_INTEGRAL_TYPE_SIZE sizeof (unsigned_long_long_int)
+
+/* The maximum number of bytes needed for a format string, including
+ the trailing nul. Each format string expects a variable amount of
+ padding (guaranteed to be at least 1 plus the field width), then an
+ element that will be formatted in the field. */
enum
{
FMT_BYTES_ALLOCATED =
- MAX ((sizeof " %0" - 1 + INT_STRLEN_BOUND (int)
- + MAX (sizeof "ld",
- MAX (sizeof PRIdMAX,
- MAX (sizeof PRIoMAX,
- MAX (sizeof PRIuMAX,
- sizeof PRIxMAX))))),
- sizeof " %.Le" + 2 * INT_STRLEN_BOUND (int))
+ (sizeof "%*.99" - 1
+ + MAX (sizeof "ld",
+ MAX (sizeof PRIdMAX,
+ MAX (sizeof PRIoMAX,
+ MAX (sizeof PRIuMAX,
+ sizeof PRIxMAX)))))
};
-/* Each output format specification (from `-t spec' or from
+/* Ensure that our choice for FMT_BYTES_ALLOCATED is reasonable. */
+verify (MAX_INTEGRAL_TYPE_SIZE * CHAR_BIT / 3 <= 99);
+
+/* Each output format specification (from '-t spec' or from
old-style options) is represented by one of these structures. */
struct tspec
{
enum output_format fmt;
- enum size_spec size;
- void (*print_function) (size_t, void const *, char const *);
- char fmt_string[FMT_BYTES_ALLOCATED];
+ enum size_spec size; /* Type of input object. */
+ /* FIELDS is the number of fields per line, BLANK is the number of
+ fields to leave blank. WIDTH is width of one field, excluding
+ leading space, and PAD is total pad to divide among FIELDS.
+ PAD is at least as large as FIELDS. */
+ void (*print_function) (size_t fields, size_t blank, void const *data,
+ char const *fmt, int width, int pad);
+ char fmt_string[FMT_BYTES_ALLOCATED]; /* Of the style "%*d". */
bool hexl_mode_trailer;
- int field_width;
+ int field_width; /* Minimum width of a field, excluding leading space. */
+ int pad_width; /* Total padding to be divided among fields. */
};
-/* The name this program was run with. */
-char *program_name;
-
/* Convert the number of 8-bit bytes of a binary representation to
the number of characters (digits + sign if the type is signed)
required to represent the same quantity in the specified base/type.
10 unsigned decimal
8 unsigned hexadecimal */
-static char const bytes_to_oct_digits[] =
+static unsigned int const bytes_to_oct_digits[] =
{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
-static char const bytes_to_signed_dec_digits[] =
+static unsigned int const bytes_to_signed_dec_digits[] =
{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
-static char const bytes_to_unsigned_dec_digits[] =
+static unsigned int const bytes_to_unsigned_dec_digits[] =
{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
-static char const bytes_to_hex_digits[] =
+static unsigned int const bytes_to_hex_digits[] =
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
+/* It'll be a while before we see integral types wider than 16 bytes,
+ but if/when it happens, this check will catch it. Without this check,
+ a wider type would provoke a buffer overrun. */
+verify (MAX_INTEGRAL_TYPE_SIZE < ARRAY_CARDINALITY (bytes_to_hex_digits));
+
+/* Make sure the other arrays have the same length. */
+verify (sizeof bytes_to_oct_digits == sizeof bytes_to_signed_dec_digits);
+verify (sizeof bytes_to_oct_digits == sizeof bytes_to_unsigned_dec_digits);
+verify (sizeof bytes_to_oct_digits == sizeof bytes_to_hex_digits);
+
/* Convert enum size_spec to the size of the named type. */
static const int width_bytes[] =
{
sizeof (short int),
sizeof (int),
sizeof (long int),
- sizeof (ulonglong_t),
+ sizeof (unsigned_long_long_int),
sizeof (float),
sizeof (double),
- sizeof (LONG_DOUBLE)
+ sizeof (long double)
};
-/* Ensure that for each member of `enum size_spec' there is an
+/* Ensure that for each member of 'enum size_spec' there is an
initializer in the width_bytes array. */
-VERIFY (assert_width_bytes_matches_size_spec_decl,
- sizeof width_bytes / sizeof width_bytes[0] == N_SIZE_SPECS);
+verify (ARRAY_CARDINALITY (width_bytes) == N_SIZE_SPECS);
/* Names for some non-printing characters. */
-static const char *const charname[33] =
+static char const charname[33][4] =
{
"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
"bs", "ht", "nl", "vt", "ff", "cr", "so", "si",
/* Width of a normal address. */
static int address_pad_len;
+/* Minimum length when detecting --strings. */
static size_t string_min;
+
+/* True when in --strings mode. */
static bool flag_dump_strings;
/* True if we should recognize the older non-option arguments
offset and pseudo-start address. */
static bool traditional;
-/* True if an old-style `pseudo-address' was specified. */
+/* True if an old-style 'pseudo-address' was specified. */
static bool flag_pseudo_start;
/* The difference between the old-style pseudo starting address and
/* If true, at least one of the files we read was standard input. */
static bool have_read_stdin;
-#define MAX_INTEGRAL_TYPE_SIZE sizeof (ulonglong_t)
+/* Map the size in bytes to a type identifier. */
static enum size_spec integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1];
-#define MAX_FP_TYPE_SIZE sizeof (LONG_DOUBLE)
+#define MAX_FP_TYPE_SIZE sizeof (long double)
static enum size_spec fp_type_size[MAX_FP_TYPE_SIZE + 1];
static char const short_options[] = "A:aBbcDdeFfHhIij:LlN:OoS:st:vw::Xx";
usage (int status)
{
if (status != EXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
+ emit_try_help ();
else
{
printf (_("\
or: %s [-abcdfilosx]... [FILE] [[+]OFFSET[.][b]]\n\
or: %s --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]]\n\
"),
- program_name, program_name, program_name);
+ program_name, program_name, program_name);
fputs (_("\n\
Write an unambiguous representation, octal bytes by default,\n\
of FILE to standard output. With more than one FILE argument,\n\
\n\
"), stdout);
fputs (_("\
-All arguments to long options are mandatory for short options.\n\
+If first and second call formats both apply, the second format is assumed\n\
+if the last operand begins with + or (if there are 2 operands) a digit.\n\
+An OFFSET operand means -j OFFSET. LABEL is the pseudo-address\n\
+at first byte printed, incremented when dump is progressing.\n\
+For OFFSET and LABEL, a 0x or 0X prefix indicates hexadecimal;\n\
+suffixes may be . for octal and b for multiply by 512.\n\
+\n\
"), stdout);
fputs (_("\
- -A, --address-radix=RADIX decide how file offsets are printed\n\
+Mandatory arguments to long options are mandatory for short options too.\n\
+"), stdout);
+ fputs (_("\
+ -A, --address-radix=RADIX output format for file offsets. RADIX is one\n\
+ of [doxn], for Decimal, Octal, Hex or None\n\
-j, --skip-bytes=BYTES skip BYTES input bytes first\n\
"), stdout);
fputs (_("\
-N, --read-bytes=BYTES limit dump to BYTES input bytes\n\
- -S, --strings[=BYTES] output strings of at least BYTES graphic chars\n\
+ -S BYTES, --strings[=BYTES] output strings of at least BYTES graphic chars.\
+\n\
+ 3 is implied when BYTES is not specified\n\
-t, --format=TYPE select output format or formats\n\
-v, --output-duplicates do not use * to mark line suppression\n\
- -w, --width[=BYTES] output BYTES bytes per output line\n\
- --traditional accept arguments in traditional form\n\
+ -w[BYTES], --width[=BYTES] output BYTES bytes per output line.\n\
+ 32 is implied when BYTES is not specified\n\
+ --traditional accept arguments in third form above\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
+\n\
Traditional format specifications may be intermixed; they accumulate:\n\
- -a same as -t a, select named characters\n\
+ -a same as -t a, select named characters, ignoring high-order bit\n\
-b same as -t o1, select octal bytes\n\
-c same as -t c, select ASCII characters or backslash escapes\n\
-d same as -t u2, select unsigned decimal 2-byte units\n\
"), stdout);
fputs (_("\
\n\
-If first and second call formats both apply, the second format is assumed\n\
-if the last operand begins with + or (if there are 2 operands) a digit.\n\
-An OFFSET operand means -j OFFSET. LABEL is the pseudo-address\n\
-at first byte printed, incremented when dump is progressing.\n\
-For OFFSET and LABEL, a 0x or 0X prefix indicates hexadecimal;\n\
-suffixes may be . for octal and b for multiply by 512.\n\
\n\
TYPE is made up of one or more of these specifications:\n\
-\n\
- a named character\n\
+ a named character, ignoring high-order bit\n\
c ASCII character or backslash escape\n\
"), stdout);
fputs (_("\
"), stdout);
fputs (_("\
\n\
-SIZE is a number. For TYPE in doux, SIZE may also be C for\n\
+SIZE is a number. For TYPE in [doux], SIZE may also be C for\n\
sizeof(char), S for sizeof(short), I for sizeof(int) or L for\n\
sizeof(long). If TYPE is f, SIZE may also be F for sizeof(float), D\n\
for sizeof(double) or L for sizeof(long double).\n\
"), stdout);
fputs (_("\
\n\
-RADIX is d for decimal, o for octal, x for hexadecimal or n for none.\n\
-BYTES is hexadecimal with 0x or 0X prefix, it is multiplied by 512\n\
-with b suffix, by 1024 with k and by 1048576 with m. Adding a z suffix to\n\
-any type adds a display of printable characters to the end of each line\n\
-of output. \
+Adding a z suffix to any type displays printable characters at the end of\n\
+each output line.\n\
"), stdout);
fputs (_("\
---string without a number implies 3. --width without a number\n\
-implies 32. By default, od uses -A o -t d2 -w 16.\n\
+\n\
+\n\
+BYTES is hex with 0x or 0X prefix, and may have a multiplier suffix:\n\
+ b 512\n\
+ KB 1000\n\
+ K 1024\n\
+ MB 1000*1000\n\
+ M 1024*1024\n\
+and so on for G, T, P, E, Z, Y.\n\
"), stdout);
- printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ emit_ancillary_info ();
}
exit (status);
}
/* Define the print functions. */
-static void
-print_s_char (size_t n_bytes, void const *block, char const *fmt_string)
-{
- signed char const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
+#define PRINT_FIELDS(N, T, FMT_STRING, ACTION) \
+static void \
+N (size_t fields, size_t blank, void const *block, \
+ char const *FMT_STRING, int width, int pad) \
+{ \
+ T const *p = block; \
+ size_t i; \
+ int pad_remaining = pad; \
+ for (i = fields; blank < i; i--) \
+ { \
+ int next_pad = pad * (i - 1) / fields; \
+ int adjusted_width = pad_remaining - next_pad + width; \
+ T x = *p++; \
+ ACTION; \
+ pad_remaining = next_pad; \
+ } \
}
-static void
-print_char (size_t n_bytes, void const *block, char const *fmt_string)
-{
- unsigned char const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
+#define PRINT_TYPE(N, T) \
+ PRINT_FIELDS (N, T, fmt_string, xprintf (fmt_string, adjusted_width, x))
-static void
-print_s_short (size_t n_bytes, void const *block, char const *fmt_string)
-{
- short int const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
+#define PRINT_FLOATTYPE(N, T, FTOASTR, BUFSIZE) \
+ PRINT_FIELDS (N, T, fmt_string ATTRIBUTE_UNUSED, \
+ char buf[BUFSIZE]; \
+ FTOASTR (buf, sizeof buf, 0, 0, x); \
+ xprintf ("%*s", adjusted_width, buf))
-static void
-print_short (size_t n_bytes, void const *block, char const *fmt_string)
-{
- unsigned short int const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
+PRINT_TYPE (print_s_char, signed char)
+PRINT_TYPE (print_char, unsigned char)
+PRINT_TYPE (print_s_short, short int)
+PRINT_TYPE (print_short, unsigned short int)
+PRINT_TYPE (print_int, unsigned int)
+PRINT_TYPE (print_long, unsigned long int)
+PRINT_TYPE (print_long_long, unsigned_long_long_int)
-static void
-print_int (size_t n_bytes, void const *block, char const *fmt_string)
-{
- unsigned int const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
-
-static void
-print_long (size_t n_bytes, void const *block, char const *fmt_string)
-{
- unsigned long int const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
+PRINT_FLOATTYPE (print_float, float, ftoastr, FLT_BUFSIZE_BOUND)
+PRINT_FLOATTYPE (print_double, double, dtoastr, DBL_BUFSIZE_BOUND)
+PRINT_FLOATTYPE (print_long_double, long double, ldtoastr, LDBL_BUFSIZE_BOUND)
-static void
-print_long_long (size_t n_bytes, void const *block, char const *fmt_string)
-{
- ulonglong_t const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
-
-static void
-print_float (size_t n_bytes, void const *block, char const *fmt_string)
-{
- float const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
-
-static void
-print_double (size_t n_bytes, void const *block, char const *fmt_string)
-{
- double const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
-
-#ifdef HAVE_LONG_DOUBLE
-static void
-print_long_double (size_t n_bytes, void const *block, char const *fmt_string)
-{
- long double const *p = block;
- size_t i;
- for (i = n_bytes / sizeof *p; i != 0; i--)
- printf (fmt_string, *p++);
-}
-#endif
+#undef PRINT_TYPE
+#undef PRINT_FLOATTYPE
static void
dump_hexl_mode_trailer (size_t n_bytes, const char *block)
for (i = n_bytes; i > 0; i--)
{
unsigned char c = *block++;
- unsigned char c2 = (ISPRINT(c) ? c : '.');
+ unsigned char c2 = (isprint (c) ? c : '.');
putchar (c2);
}
putchar ('<');
}
static void
-print_named_ascii (size_t n_bytes, void const *block,
- const char *unused_fmt_string ATTRIBUTE_UNUSED)
+print_named_ascii (size_t fields, size_t blank, void const *block,
+ const char *unused_fmt_string ATTRIBUTE_UNUSED,
+ int width, int pad)
{
unsigned char const *p = block;
size_t i;
- for (i = n_bytes; i > 0; i--)
+ int pad_remaining = pad;
+ for (i = fields; blank < i; i--)
{
+ int next_pad = pad * (i - 1) / fields;
int masked_c = *p++ & 0x7f;
const char *s;
- char buf[5];
+ char buf[2];
if (masked_c == 127)
- s = "del";
+ s = "del";
else if (masked_c <= 040)
- s = charname[masked_c];
+ s = charname[masked_c];
else
- {
- sprintf (buf, " %c", masked_c);
- s = buf;
- }
-
- printf (" %3s", s);
+ {
+ buf[0] = masked_c;
+ buf[1] = 0;
+ s = buf;
+ }
+
+ xprintf ("%*s", pad_remaining - next_pad + width, s);
+ pad_remaining = next_pad;
}
}
static void
-print_ascii (size_t n_bytes, void const *block,
- const char *unused_fmt_string ATTRIBUTE_UNUSED)
+print_ascii (size_t fields, size_t blank, void const *block,
+ const char *unused_fmt_string ATTRIBUTE_UNUSED, int width,
+ int pad)
{
unsigned char const *p = block;
size_t i;
- for (i = n_bytes; i > 0; i--)
+ int pad_remaining = pad;
+ for (i = fields; blank < i; i--)
{
+ int next_pad = pad * (i - 1) / fields;
unsigned char c = *p++;
const char *s;
- char buf[5];
+ char buf[4];
switch (c)
- {
- case '\0':
- s = " \\0";
- break;
-
- case '\a':
- s = " \\a";
- break;
-
- case '\b':
- s = " \\b";
- break;
-
- case '\f':
- s = " \\f";
- break;
-
- case '\n':
- s = " \\n";
- break;
-
- case '\r':
- s = " \\r";
- break;
-
- case '\t':
- s = " \\t";
- break;
-
- case '\v':
- s = " \\v";
- break;
-
- default:
- sprintf (buf, (ISPRINT (c) ? " %c" : "%03o"), c);
- s = buf;
- }
-
- printf (" %3s", s);
+ {
+ case '\0':
+ s = "\\0";
+ break;
+
+ case '\a':
+ s = "\\a";
+ break;
+
+ case '\b':
+ s = "\\b";
+ break;
+
+ case '\f':
+ s = "\\f";
+ break;
+
+ case '\n':
+ s = "\\n";
+ break;
+
+ case '\r':
+ s = "\\r";
+ break;
+
+ case '\t':
+ s = "\\t";
+ break;
+
+ case '\v':
+ s = "\\v";
+ break;
+
+ default:
+ sprintf (buf, (isprint (c) ? "%c" : "%03o"), c);
+ s = buf;
+ }
+
+ xprintf ("%*s", pad_remaining - next_pad + width, s);
+ pad_remaining = next_pad;
}
}
{
int c = *s++ - '0';
if (sum > (ULONG_MAX - c) / 10)
- return false;
+ return false;
sum = sum * 10 + c;
}
*p = s;
fmt = SIGNED_DECIMAL;
size = INT or LONG; (whichever integral_type_size[4] resolves to)
print_function = print_int; (assuming size == INT)
- fmt_string = "%011d%c";
+ field_width = 11;
+ fmt_string = "%*d";
}
+ pad_width is determined later, but is at least as large as the
+ number of fields printed per row.
S_ORIG is solely for reporting errors. It should be the full format
string argument.
*/
static bool
decode_one_format (const char *s_orig, const char *s, const char **next,
- struct tspec *tspec)
+ struct tspec *tspec)
{
enum size_spec size_spec;
unsigned long int size;
enum output_format fmt;
- const char *pre_fmt_string;
- void (*print_function) (size_t, void const *, char const *);
+ void (*print_function) (size_t, size_t, void const *, char const *,
+ int, int);
const char *p;
char c;
int field_width;
- int precision;
assert (tspec != NULL);
c = *s;
++s;
switch (*s)
- {
- case 'C':
- ++s;
- size = sizeof (char);
- break;
-
- case 'S':
- ++s;
- size = sizeof (short int);
- break;
-
- case 'I':
- ++s;
- size = sizeof (int);
- break;
-
- case 'L':
- ++s;
- size = sizeof (long int);
- break;
-
- default:
- if (! simple_strtoul (s, &p, &size))
- {
- /* The integer at P in S would overflow an unsigned long int.
- A digit string that long is sufficiently odd looking
- that the following diagnostic is sufficient. */
- error (0, 0, _("invalid type string `%s'"), s_orig);
- return false;
- }
- if (p == s)
- size = sizeof (int);
- else
- {
- if (MAX_INTEGRAL_TYPE_SIZE < size
- || integral_type_size[size] == NO_SIZE)
- {
- error (0, 0, _("invalid type string `%s';\n\
-this system doesn't provide a %lu-byte integral type"), s_orig, size);
- return false;
- }
- s = p;
- }
- break;
- }
+ {
+ case 'C':
+ ++s;
+ size = sizeof (char);
+ break;
+
+ case 'S':
+ ++s;
+ size = sizeof (short int);
+ break;
+
+ case 'I':
+ ++s;
+ size = sizeof (int);
+ break;
+
+ case 'L':
+ ++s;
+ size = sizeof (long int);
+ break;
+
+ default:
+ if (! simple_strtoul (s, &p, &size))
+ {
+ /* The integer at P in S would overflow an unsigned long int.
+ A digit string that long is sufficiently odd looking
+ that the following diagnostic is sufficient. */
+ error (0, 0, _("invalid type string %s"), quote (s_orig));
+ return false;
+ }
+ if (p == s)
+ size = sizeof (int);
+ else
+ {
+ if (MAX_INTEGRAL_TYPE_SIZE < size
+ || integral_type_size[size] == NO_SIZE)
+ {
+ error (0, 0, _("invalid type string %s;\nthis system"
+ " doesn't provide a %lu-byte integral type"),
+ quote (s_orig), size);
+ return false;
+ }
+ s = p;
+ }
+ break;
+ }
#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
((Spec) == LONG_LONG ? (Max_format) \
size_spec = integral_type_size[size];
switch (c)
- {
- case 'd':
- fmt = SIGNED_DECIMAL;
- sprintf (tspec->fmt_string, " %%%d%s",
- (field_width = bytes_to_signed_dec_digits[size]),
- ISPEC_TO_FORMAT (size_spec, "d", "ld", PRIdMAX));
- break;
-
- case 'o':
- fmt = OCTAL;
- sprintf (tspec->fmt_string, " %%0%d%s",
- (field_width = bytes_to_oct_digits[size]),
- ISPEC_TO_FORMAT (size_spec, "o", "lo", PRIoMAX));
- break;
-
- case 'u':
- fmt = UNSIGNED_DECIMAL;
- sprintf (tspec->fmt_string, " %%%d%s",
- (field_width = bytes_to_unsigned_dec_digits[size]),
- ISPEC_TO_FORMAT (size_spec, "u", "lu", PRIuMAX));
- break;
-
- case 'x':
- fmt = HEXADECIMAL;
- sprintf (tspec->fmt_string, " %%0%d%s",
- (field_width = bytes_to_hex_digits[size]),
- ISPEC_TO_FORMAT (size_spec, "x", "lx", PRIxMAX));
- break;
-
- default:
- abort ();
- }
+ {
+ case 'd':
+ fmt = SIGNED_DECIMAL;
+ field_width = bytes_to_signed_dec_digits[size];
+ sprintf (tspec->fmt_string, "%%*%s",
+ ISPEC_TO_FORMAT (size_spec, "d", "ld", PRIdMAX));
+ break;
+
+ case 'o':
+ fmt = OCTAL;
+ sprintf (tspec->fmt_string, "%%*.%d%s",
+ (field_width = bytes_to_oct_digits[size]),
+ ISPEC_TO_FORMAT (size_spec, "o", "lo", PRIoMAX));
+ break;
+
+ case 'u':
+ fmt = UNSIGNED_DECIMAL;
+ field_width = bytes_to_unsigned_dec_digits[size];
+ sprintf (tspec->fmt_string, "%%*%s",
+ ISPEC_TO_FORMAT (size_spec, "u", "lu", PRIuMAX));
+ break;
+
+ case 'x':
+ fmt = HEXADECIMAL;
+ sprintf (tspec->fmt_string, "%%*.%d%s",
+ (field_width = bytes_to_hex_digits[size]),
+ ISPEC_TO_FORMAT (size_spec, "x", "lx", PRIxMAX));
+ break;
+
+ default:
+ abort ();
+ }
assert (strlen (tspec->fmt_string) < FMT_BYTES_ALLOCATED);
switch (size_spec)
- {
- case CHAR:
- print_function = (fmt == SIGNED_DECIMAL
- ? print_s_char
- : print_char);
- break;
-
- case SHORT:
- print_function = (fmt == SIGNED_DECIMAL
- ? print_s_short
- : print_short);
- break;
-
- case INT:
- print_function = print_int;
- break;
-
- case LONG:
- print_function = print_long;
- break;
-
- case LONG_LONG:
- print_function = print_long_long;
- break;
-
- default:
- abort ();
- }
+ {
+ case CHAR:
+ print_function = (fmt == SIGNED_DECIMAL
+ ? print_s_char
+ : print_char);
+ break;
+
+ case SHORT:
+ print_function = (fmt == SIGNED_DECIMAL
+ ? print_s_short
+ : print_short);
+ break;
+
+ case INT:
+ print_function = print_int;
+ break;
+
+ case LONG:
+ print_function = print_long;
+ break;
+
+ case LONG_LONG:
+ print_function = print_long_long;
+ break;
+
+ default:
+ abort ();
+ }
break;
case 'f':
fmt = FLOATING_POINT;
++s;
switch (*s)
- {
- case 'F':
- ++s;
- size = sizeof (float);
- break;
-
- case 'D':
- ++s;
- size = sizeof (double);
- break;
-
- case 'L':
- ++s;
- size = sizeof (LONG_DOUBLE);
- break;
-
- default:
- if (! simple_strtoul (s, &p, &size))
- {
- /* The integer at P in S would overflow an unsigned long int.
- A digit string that long is sufficiently odd looking
- that the following diagnostic is sufficient. */
- error (0, 0, _("invalid type string `%s'"), s_orig);
- return false;
- }
- if (p == s)
- size = sizeof (double);
- else
- {
- if (size > MAX_FP_TYPE_SIZE
- || fp_type_size[size] == NO_SIZE)
- {
- error (0, 0, _("invalid type string `%s';\n\
-this system doesn't provide a %lu-byte floating point type"), s_orig, size);
- return false;
- }
- s = p;
- }
- break;
- }
+ {
+ case 'F':
+ ++s;
+ size = sizeof (float);
+ break;
+
+ case 'D':
+ ++s;
+ size = sizeof (double);
+ break;
+
+ case 'L':
+ ++s;
+ size = sizeof (long double);
+ break;
+
+ default:
+ if (! simple_strtoul (s, &p, &size))
+ {
+ /* The integer at P in S would overflow an unsigned long int.
+ A digit string that long is sufficiently odd looking
+ that the following diagnostic is sufficient. */
+ error (0, 0, _("invalid type string %s"), quote (s_orig));
+ return false;
+ }
+ if (p == s)
+ size = sizeof (double);
+ else
+ {
+ if (size > MAX_FP_TYPE_SIZE
+ || fp_type_size[size] == NO_SIZE)
+ {
+ error (0, 0,
+ _("invalid type string %s;\n"
+ "this system doesn't provide a %lu-byte"
+ " floating point type"),
+ quote (s_orig), size);
+ return false;
+ }
+ s = p;
+ }
+ break;
+ }
size_spec = fp_type_size[size];
- switch (size_spec)
- {
- case FLOAT_SINGLE:
- print_function = print_float;
- /* Don't use %#e; not all systems support it. */
- pre_fmt_string = " %%%d.%de";
- precision = FLT_DIG;
- break;
-
- case FLOAT_DOUBLE:
- print_function = print_double;
- pre_fmt_string = " %%%d.%de";
- precision = DBL_DIG;
- break;
-
-#ifdef HAVE_LONG_DOUBLE
- case FLOAT_LONG_DOUBLE:
- print_function = print_long_double;
- pre_fmt_string = " %%%d.%dLe";
- precision = LDBL_DIG;
- break;
-#endif
-
- default:
- abort ();
- }
-
- field_width = precision + 8;
- sprintf (tspec->fmt_string, pre_fmt_string, field_width, precision);
- break;
+ {
+ struct lconv const *locale = localeconv ();
+ size_t decimal_point_len =
+ (locale->decimal_point[0] ? strlen (locale->decimal_point) : 1);
+
+ switch (size_spec)
+ {
+ case FLOAT_SINGLE:
+ print_function = print_float;
+ field_width = FLT_STRLEN_BOUND_L (decimal_point_len);
+ break;
+
+ case FLOAT_DOUBLE:
+ print_function = print_double;
+ field_width = DBL_STRLEN_BOUND_L (decimal_point_len);
+ break;
+
+ case FLOAT_LONG_DOUBLE:
+ print_function = print_long_double;
+ field_width = LDBL_STRLEN_BOUND_L (decimal_point_len);
+ break;
+
+ default:
+ abort ();
+ }
+
+ break;
+ }
case 'a':
++s;
break;
default:
- error (0, 0, _("invalid character `%c' in type string `%s'"),
- *s, s_orig);
+ error (0, 0, _("invalid character '%c' in type string %s"),
+ *s, quote (s_orig));
return false;
}
{
input_filename = *file_list;
if (input_filename == NULL)
- return ok;
+ return ok;
++file_list;
if (STREQ (input_filename, "-"))
- {
- input_filename = _("standard input");
- in_stream = stdin;
- have_read_stdin = true;
- }
+ {
+ input_filename = _("standard input");
+ in_stream = stdin;
+ have_read_stdin = true;
+ if (O_BINARY && ! isatty (STDIN_FILENO))
+ xfreopen (NULL, "rb", stdin);
+ }
else
- {
- in_stream = fopen (input_filename, "r");
- if (in_stream == NULL)
- {
- error (0, errno, "%s", input_filename);
- ok = false;
- }
- }
+ {
+ in_stream = fopen (input_filename, (O_BINARY ? "rb" : "r"));
+ if (in_stream == NULL)
+ {
+ error (0, errno, "%s", input_filename);
+ ok = false;
+ }
+ }
}
while (in_stream == NULL);
- if (limit_bytes_to_format & !flag_dump_strings)
- SETVBUF (in_stream, NULL, _IONBF, 0);
- SET_BINARY (fileno (in_stream));
+ if (limit_bytes_to_format && !flag_dump_strings)
+ setvbuf (in_stream, NULL, _IONBF, 0);
return ok;
}
if (in_stream != NULL)
{
if (ferror (in_stream))
- {
- error (0, in_errno, _("%s: read error"), input_filename);
- if (! STREQ (file_list[-1], "-"))
- fclose (in_stream);
- ok = false;
- }
+ {
+ error (0, in_errno, _("%s: read error"), input_filename);
+ if (! STREQ (file_list[-1], "-"))
+ fclose (in_stream);
+ ok = false;
+ }
else if (! STREQ (file_list[-1], "-") && fclose (in_stream) != 0)
- {
- error (0, errno, "%s", input_filename);
- ok = false;
- }
+ {
+ error (0, errno, "%s", input_filename);
+ ok = false;
+ }
in_stream = NULL;
}
const char *next;
if (n_specs_allocated <= n_specs)
- spec = x2nrealloc (spec, &n_specs_allocated, sizeof *spec);
+ spec = X2NREALLOC (spec, &n_specs_allocated);
if (! decode_one_format (s_orig, s, &next, &spec[n_specs]))
- return false;
+ return false;
assert (s != next);
s = next;
struct stat file_stats;
/* First try seeking. For large offsets, this extra work is
- worthwhile. If the offset is below some threshold it may be
- more efficient to move the pointer by reading. There are two
- issues when trying to seek:
- - the file must be seekable.
- - before seeking to the specified position, make sure
- that the new position is in the current file.
- Try to do that by getting file's size using fstat.
- But that will work only for regular files. */
+ worthwhile. If the offset is below some threshold it may be
+ more efficient to move the pointer by reading. There are two
+ issues when trying to seek:
+ - the file must be seekable.
+ - before seeking to the specified position, make sure
+ that the new position is in the current file.
+ Try to do that by getting file's size using fstat.
+ But that will work only for regular files. */
if (fstat (fileno (in_stream), &file_stats) == 0)
- {
- /* The st_size field is valid only for regular files
- (and for symbolic links, which cannot occur here).
- If the number of bytes left to skip is at least
- as large as the size of the current file, we can
- decrement n_skip and go on to the next file. */
-
- if (S_ISREG (file_stats.st_mode) && 0 <= file_stats.st_size)
- {
- if ((uintmax_t) file_stats.st_size <= n_skip)
- n_skip -= file_stats.st_size;
- else
- {
- if (fseeko (in_stream, n_skip, SEEK_CUR) != 0)
- {
- in_errno = errno;
- ok = false;
- }
- n_skip = 0;
- }
- }
-
- /* If it's not a regular file with nonnegative size,
- position the file pointer by reading. */
-
- else
- {
- char buf[BUFSIZ];
- size_t n_bytes_read, n_bytes_to_read = BUFSIZ;
-
- while (0 < n_skip)
- {
- if (n_skip < n_bytes_to_read)
- n_bytes_to_read = n_skip;
- n_bytes_read = fread (buf, 1, n_bytes_to_read, in_stream);
- n_skip -= n_bytes_read;
- if (n_bytes_read != n_bytes_to_read)
- {
- in_errno = errno;
- ok = false;
- n_skip = 0;
- break;
- }
- }
- }
-
- if (n_skip == 0)
- break;
- }
+ {
+ /* The st_size field is valid for regular files.
+ If the number of bytes left to skip is larger than
+ the size of the current file, we can decrement n_skip
+ and go on to the next file. Skip this optimization also
+ when st_size is 0, because some kernels report that
+ nonempty files in /proc have st_size == 0. */
+ if (S_ISREG (file_stats.st_mode) && 0 < file_stats.st_size)
+ {
+ if ((uintmax_t) file_stats.st_size < n_skip)
+ n_skip -= file_stats.st_size;
+ else
+ {
+ if (fseeko (in_stream, n_skip, SEEK_CUR) != 0)
+ {
+ in_errno = errno;
+ ok = false;
+ }
+ n_skip = 0;
+ }
+ }
+
+ /* If it's not a regular file with nonnegative size,
+ position the file pointer by reading. */
+
+ else
+ {
+ char buf[BUFSIZ];
+ size_t n_bytes_read, n_bytes_to_read = BUFSIZ;
+
+ while (0 < n_skip)
+ {
+ if (n_skip < n_bytes_to_read)
+ n_bytes_to_read = n_skip;
+ n_bytes_read = fread (buf, 1, n_bytes_to_read, in_stream);
+ n_skip -= n_bytes_read;
+ if (n_bytes_read != n_bytes_to_read)
+ {
+ in_errno = errno;
+ ok = false;
+ n_skip = 0;
+ break;
+ }
+ }
+ }
+
+ if (n_skip == 0)
+ break;
+ }
else /* cannot fstat() file */
- {
- error (0, errno, "%s", input_filename);
- ok = false;
- }
+ {
+ error (0, errno, "%s", input_filename);
+ ok = false;
+ }
ok &= check_and_close (in_errno);
}
static void
-format_address_none (uintmax_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED)
+format_address_none (uintmax_t address ATTRIBUTE_UNUSED,
+ char c ATTRIBUTE_UNUSED)
{
}
{
case 8:
do
- *--p = '0' + (address & 7);
+ *--p = '0' + (address & 7);
while ((address >>= 3) != 0);
break;
case 10:
do
- *--p = '0' + (address % 10);
+ *--p = '0' + (address % 10);
while ((address /= 10) != 0);
break;
case 16:
do
- *--p = "0123456789abcdef"[address & 15];
+ *--p = "0123456789abcdef"[address & 15];
while ((address >>= 4) != 0);
break;
}
for a sequence of identical input blocks is the output for the first
block followed by an asterisk alone on a line. It is valid to compare
the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
- That condition may be false only for the last input block -- and then
- only when it has not been padded to length BYTES_PER_BLOCK. */
+ That condition may be false only for the last input block. */
static void
write_block (uintmax_t current_offset, size_t n_bytes,
- const char *prev_block, const char *curr_block)
+ const char *prev_block, const char *curr_block)
{
static bool first = true;
static bool prev_pair_equal = false;
-#define EQUAL_BLOCKS(b1, b2) (memcmp ((b1), (b2), bytes_per_block) == 0)
+#define EQUAL_BLOCKS(b1, b2) (memcmp (b1, b2, bytes_per_block) == 0)
if (abbreviate_duplicate_blocks
&& !first && n_bytes == bytes_per_block
&& EQUAL_BLOCKS (prev_block, curr_block))
{
if (prev_pair_equal)
- {
- /* The two preceding blocks were equal, and the current
- block is the same as the last one, so print nothing. */
- }
+ {
+ /* The two preceding blocks were equal, and the current
+ block is the same as the last one, so print nothing. */
+ }
else
- {
- printf ("*\n");
- prev_pair_equal = true;
- }
+ {
+ printf ("*\n");
+ prev_pair_equal = true;
+ }
}
else
{
prev_pair_equal = false;
for (i = 0; i < n_specs; i++)
- {
- if (i == 0)
- format_address (current_offset, '\0');
- else
- printf ("%*s", address_pad_len, "");
- (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string);
- if (spec[i].hexl_mode_trailer)
- {
- /* space-pad out to full line width, then dump the trailer */
- int datum_width = width_bytes[spec[i].size];
- int blank_fields = (bytes_per_block - n_bytes) / datum_width;
- int field_width = spec[i].field_width + 1;
- printf ("%*s", blank_fields * field_width, "");
- dump_hexl_mode_trailer (n_bytes, curr_block);
- }
- putchar ('\n');
- }
+ {
+ int datum_width = width_bytes[spec[i].size];
+ int fields_per_block = bytes_per_block / datum_width;
+ int blank_fields = (bytes_per_block - n_bytes) / datum_width;
+ if (i == 0)
+ format_address (current_offset, '\0');
+ else
+ printf ("%*s", address_pad_len, "");
+ (*spec[i].print_function) (fields_per_block, blank_fields,
+ curr_block, spec[i].fmt_string,
+ spec[i].field_width, spec[i].pad_width);
+ if (spec[i].hexl_mode_trailer)
+ {
+ /* space-pad out to full line width, then dump the trailer */
+ int field_width = spec[i].field_width;
+ int pad_width = (spec[i].pad_width * blank_fields
+ / fields_per_block);
+ printf ("%*s", blank_fields * field_width + pad_width, "");
+ dump_hexl_mode_trailer (n_bytes, curr_block);
+ }
+ putchar ('\n');
+ }
}
first = false;
}
*c = fgetc (in_stream);
if (*c != EOF)
- break;
+ break;
ok &= check_and_close (errno);
*n_bytes_in_buffer += n_read;
if (n_read == n_needed)
- break;
+ break;
ok &= check_and_close (errno);
/* Return the least common multiple of the sizes associated
with the format specs. */
-static int
+static int _GL_ATTRIBUTE_PURE
get_lcm (void)
{
size_t i;
if (s[0] == '+')
++s;
- /* Determine the radix we'll use to interpret S. If there is a `.',
- it's decimal, otherwise, if the string begins with `0X'or `0x',
+ /* Determine the radix we'll use to interpret S. If there is a '.',
+ it's decimal, otherwise, if the string begins with '0X'or '0x',
it's hexadecimal, else octal. */
if (strchr (s, '.') != NULL)
radix = 10;
else
{
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
- radix = 16;
+ radix = 16;
else
- radix = 8;
+ radix = 8;
}
return xstrtoumax (s, NULL, radix, offset, "Bb") == LONGINT_OK;
if (limit_bytes_to_format)
{
while (1)
- {
- size_t n_needed;
- if (current_offset >= end_offset)
- {
- n_bytes_read = 0;
- break;
- }
- n_needed = MIN (end_offset - current_offset,
- (uintmax_t) bytes_per_block);
- ok &= read_block (n_needed, block[idx], &n_bytes_read);
- if (n_bytes_read < bytes_per_block)
- break;
- assert (n_bytes_read == bytes_per_block);
- write_block (current_offset, n_bytes_read,
- block[!idx], block[idx]);
- current_offset += n_bytes_read;
- idx = !idx;
- }
+ {
+ size_t n_needed;
+ if (current_offset >= end_offset)
+ {
+ n_bytes_read = 0;
+ break;
+ }
+ n_needed = MIN (end_offset - current_offset,
+ (uintmax_t) bytes_per_block);
+ ok &= read_block (n_needed, block[idx], &n_bytes_read);
+ if (n_bytes_read < bytes_per_block)
+ break;
+ assert (n_bytes_read == bytes_per_block);
+ write_block (current_offset, n_bytes_read,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ idx = !idx;
+ }
}
else
{
while (1)
- {
- ok &= read_block (bytes_per_block, block[idx], &n_bytes_read);
- if (n_bytes_read < bytes_per_block)
- break;
- assert (n_bytes_read == bytes_per_block);
- write_block (current_offset, n_bytes_read,
- block[!idx], block[idx]);
- current_offset += n_bytes_read;
- idx = !idx;
- }
+ {
+ ok &= read_block (bytes_per_block, block[idx], &n_bytes_read);
+ if (n_bytes_read < bytes_per_block)
+ break;
+ assert (n_bytes_read == bytes_per_block);
+ write_block (current_offset, n_bytes_read,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ idx = !idx;
+ }
}
if (n_bytes_read > 0)
l_c_m = get_lcm ();
- /* Make bytes_to_write the smallest multiple of l_c_m that
- is at least as large as n_bytes_read. */
+ /* Ensure zero-byte padding up to the smallest multiple of l_c_m that
+ is at least as large as n_bytes_read. */
bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
memset (block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
- write_block (current_offset, bytes_to_write,
- block[!idx], block[idx]);
+ write_block (current_offset, n_bytes_read, block[!idx], block[idx]);
current_offset += n_bytes_read;
}
}
/* STRINGS mode. Find each "string constant" in the input.
- A string constant is a run of at least `string_min' ASCII
+ 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 true if successful. */
size_t i;
int c;
- /* See if the next `string_min' chars are all printing chars. */
+ /* See if the next 'string_min' chars are all printing chars. */
tryline:
if (limit_bytes_to_format
- && (end_offset < string_min || end_offset - string_min <= address))
- break;
+ && (end_offset < string_min || end_offset - string_min <= address))
+ break;
for (i = 0; i < string_min; i++)
- {
- ok &= read_char (&c);
- address++;
- if (c < 0)
- {
- free (buf);
- return ok;
- }
- if (!ISPRINT (c))
- /* Found a non-printing. Try again starting with next char. */
- goto tryline;
- buf[i] = c;
- }
-
- /* We found a run of `string_min' printable characters.
- Now see if it is terminated with a null byte. */
+ {
+ ok &= read_char (&c);
+ address++;
+ if (c < 0)
+ {
+ free (buf);
+ return ok;
+ }
+ if (! isprint (c))
+ /* Found a non-printing. Try again starting with next char. */
+ goto tryline;
+ buf[i] = c;
+ }
+
+ /* We found a run of 'string_min' printable characters.
+ Now see if it is terminated with a null byte. */
while (!limit_bytes_to_format || address < end_offset)
- {
- if (i == bufsize)
- {
- buf = x2nrealloc (buf, &bufsize, sizeof *buf);
- }
- ok &= read_char (&c);
- address++;
- if (c < 0)
- {
- free (buf);
- return ok;
- }
- if (c == '\0')
- break; /* It is; print this string. */
- if (!ISPRINT (c))
- goto tryline; /* It isn't; give up on this string. */
- buf[i++] = c; /* String continues; store it all. */
- }
+ {
+ if (i == bufsize)
+ {
+ buf = X2REALLOC (buf, &bufsize);
+ }
+ ok &= read_char (&c);
+ address++;
+ if (c < 0)
+ {
+ free (buf);
+ return ok;
+ }
+ if (c == '\0')
+ break; /* It is; print this string. */
+ if (! isprint (c))
+ goto tryline; /* It isn't; give up on this string. */
+ buf[i++] = c; /* String continues; store it all. */
+ }
/* If we get here, the string is all printable and null-terminated,
- so print it. It is all in `buf' and `i' is its length. */
+ so print it. It is all in 'buf' and 'i' is its length. */
buf[i] = 0;
format_address (address - i - 1, ' ');
for (i = 0; (c = buf[i]); i++)
- {
- switch (c)
- {
- case '\a':
- fputs ("\\a", stdout);
- break;
-
- case '\b':
- fputs ("\\b", stdout);
- break;
-
- case '\f':
- fputs ("\\f", stdout);
- break;
-
- case '\n':
- fputs ("\\n", stdout);
- break;
-
- case '\r':
- fputs ("\\r", stdout);
- break;
-
- case '\t':
- fputs ("\\t", stdout);
- break;
-
- case '\v':
- fputs ("\\v", stdout);
- break;
-
- default:
- putc (c, stdout);
- }
- }
+ {
+ switch (c)
+ {
+ case '\a':
+ fputs ("\\a", stdout);
+ break;
+
+ case '\b':
+ fputs ("\\b", stdout);
+ break;
+
+ case '\f':
+ fputs ("\\f", stdout);
+ break;
+
+ case '\n':
+ fputs ("\\n", stdout);
+ break;
+
+ case '\r':
+ fputs ("\\r", stdout);
+ break;
+
+ case '\t':
+ fputs ("\\t", stdout);
+ break;
+
+ case '\v':
+ fputs ("\\v", stdout);
+ break;
+
+ default:
+ putc (c, stdout);
+ }
+ }
putchar ('\n');
}
int
main (int argc, char **argv)
{
- int c;
int n_files;
size_t i;
int l_c_m;
- size_t desired_width IF_LINT (= 0);
+ size_t desired_width IF_LINT ( = 0);
bool modern = false;
bool width_specified = false;
bool ok = true;
+ size_t width_per_block = 0;
+ static char const multipliers[] = "bEGKkMmPTYZ0";
- /* The old-style `pseudo starting address' to be printed in parentheses
+ /* The old-style 'pseudo starting address' to be printed in parentheses
after any true address. */
- uintmax_t pseudo_start IF_LINT (= 0);
+ uintmax_t pseudo_start IF_LINT ( = 0);
initialize_main (&argc, &argv);
- program_name = argv[0];
+ set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
integral_type_size[sizeof (short int)] = SHORT;
integral_type_size[sizeof (int)] = INT;
integral_type_size[sizeof (long int)] = LONG;
-#if HAVE_UNSIGNED_LONG_LONG
- /* If `long int' and `long long int' have the same size, it's fine
- to overwrite the entry for `long' with this one. */
- integral_type_size[sizeof (ulonglong_t)] = LONG_LONG;
+#if HAVE_UNSIGNED_LONG_LONG_INT
+ /* If 'long int' and 'long long int' have the same size, it's fine
+ to overwrite the entry for 'long' with this one. */
+ integral_type_size[sizeof (unsigned_long_long_int)] = LONG_LONG;
#endif
for (i = 0; i <= MAX_FP_TYPE_SIZE; i++)
fp_type_size[i] = NO_SIZE;
fp_type_size[sizeof (float)] = FLOAT_SINGLE;
- /* The array entry for `double' is filled in after that for LONG_DOUBLE
- so that if `long double' is the same type or if long double isn't
- supported FLOAT_LONG_DOUBLE will never be used. */
- fp_type_size[sizeof (LONG_DOUBLE)] = FLOAT_LONG_DOUBLE;
+ /* The array entry for 'double' is filled in after that for 'long double'
+ so that if they are the same size, we avoid any overhead of
+ long double computation in libc. */
+ fp_type_size[sizeof (long double)] = FLOAT_LONG_DOUBLE;
fp_type_size[sizeof (double)] = FLOAT_DOUBLE;
n_specs = 0;
address_pad_len = 7;
flag_dump_strings = false;
- while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
- != -1)
+ while (true)
{
uintmax_t tmp;
enum strtol_error s_err;
+ int oi = -1;
+ int c = getopt_long (argc, argv, short_options, long_options, &oi);
+ if (c == -1)
+ break;
switch (c)
- {
- case 'A':
- modern = true;
- switch (optarg[0])
- {
- case 'd':
- format_address = format_address_std;
- address_base = 10;
- address_pad_len = 7;
- break;
- case 'o':
- format_address = format_address_std;
- address_base = 8;
- address_pad_len = 7;
- break;
- case 'x':
- format_address = format_address_std;
- address_base = 16;
- address_pad_len = 6;
- break;
- case 'n':
- format_address = format_address_none;
- address_pad_len = 0;
- break;
- default:
- error (EXIT_FAILURE, 0,
- _("invalid output address radix `%c'; \
-it must be one character from [doxn]"),
- optarg[0]);
- break;
- }
- break;
-
- case 'j':
- modern = true;
- s_err = xstrtoumax (optarg, NULL, 0, &n_bytes_to_skip, "bkm");
- if (s_err != LONGINT_OK)
- STRTOL_FATAL_ERROR (optarg, _("skip argument"), s_err);
- break;
-
- case 'N':
- modern = true;
- limit_bytes_to_format = true;
-
- s_err = xstrtoumax (optarg, NULL, 0, &max_bytes_to_format, "bkm");
- if (s_err != LONGINT_OK)
- STRTOL_FATAL_ERROR (optarg, _("limit argument"), s_err);
- break;
-
- case 'S':
- modern = true;
- if (optarg == NULL)
- string_min = 3;
- else
- {
- s_err = xstrtoumax (optarg, NULL, 0, &tmp, "bkm");
- if (s_err != LONGINT_OK)
- STRTOL_FATAL_ERROR (optarg, _("minimum string length"), s_err);
-
- /* The minimum string length may be no larger than SIZE_MAX,
- since we may allocate a buffer of this size. */
- if (SIZE_MAX < tmp)
- error (EXIT_FAILURE, 0, _("%s is too large"), optarg);
-
- string_min = tmp;
- }
- flag_dump_strings = true;
- break;
-
- case 't':
- modern = true;
- ok &= decode_format_string (optarg);
- break;
-
- case 'v':
- modern = true;
- abbreviate_duplicate_blocks = false;
- break;
-
- case TRADITIONAL_OPTION:
- traditional = true;
- break;
-
- /* The next several cases map the traditional format
- specification options to the corresponding modern format
- specs. GNU od accepts any combination of old- and
- new-style options. Format specification options accumulate.
- The obsolescent and undocumented formats are compatible
- with FreeBSD 4.10 od. */
+ {
+ case 'A':
+ modern = true;
+ switch (optarg[0])
+ {
+ case 'd':
+ format_address = format_address_std;
+ address_base = 10;
+ address_pad_len = 7;
+ break;
+ case 'o':
+ format_address = format_address_std;
+ address_base = 8;
+ address_pad_len = 7;
+ break;
+ case 'x':
+ format_address = format_address_std;
+ address_base = 16;
+ address_pad_len = 6;
+ break;
+ case 'n':
+ format_address = format_address_none;
+ address_pad_len = 0;
+ break;
+ default:
+ error (EXIT_FAILURE, 0,
+ _("invalid output address radix '%c';\
+ it must be one character from [doxn]"),
+ optarg[0]);
+ break;
+ }
+ break;
+
+ case 'j':
+ modern = true;
+ s_err = xstrtoumax (optarg, NULL, 0, &n_bytes_to_skip, multipliers);
+ if (s_err != LONGINT_OK)
+ xstrtol_fatal (s_err, oi, c, long_options, optarg);
+ break;
+
+ case 'N':
+ modern = true;
+ limit_bytes_to_format = true;
+
+ s_err = xstrtoumax (optarg, NULL, 0, &max_bytes_to_format,
+ multipliers);
+ if (s_err != LONGINT_OK)
+ xstrtol_fatal (s_err, oi, c, long_options, optarg);
+ break;
+
+ case 'S':
+ modern = true;
+ if (optarg == NULL)
+ string_min = 3;
+ else
+ {
+ s_err = xstrtoumax (optarg, NULL, 0, &tmp, multipliers);
+ if (s_err != LONGINT_OK)
+ xstrtol_fatal (s_err, oi, c, long_options, optarg);
+
+ /* The minimum string length may be no larger than SIZE_MAX,
+ since we may allocate a buffer of this size. */
+ if (SIZE_MAX < tmp)
+ error (EXIT_FAILURE, 0, _("%s is too large"), optarg);
+
+ string_min = tmp;
+ }
+ flag_dump_strings = true;
+ break;
+
+ case 't':
+ modern = true;
+ ok &= decode_format_string (optarg);
+ break;
+
+ case 'v':
+ modern = true;
+ abbreviate_duplicate_blocks = false;
+ break;
+
+ case TRADITIONAL_OPTION:
+ traditional = true;
+ break;
+
+ /* The next several cases map the traditional format
+ specification options to the corresponding modern format
+ specs. GNU od accepts any combination of old- and
+ new-style options. Format specification options accumulate.
+ The obsolescent and undocumented formats are compatible
+ with FreeBSD 4.10 od. */
#define CASE_OLD_ARG(old_char,new_string) \
- case old_char: \
- ok &= decode_format_string (new_string); \
- break
-
- CASE_OLD_ARG ('a', "a");
- CASE_OLD_ARG ('b', "o1");
- CASE_OLD_ARG ('c', "c");
- CASE_OLD_ARG ('D', "u4"); /* obsolescent and undocumented */
- CASE_OLD_ARG ('d', "u2");
- case 'F': /* obsolescent and undocumented alias */
- CASE_OLD_ARG ('e', "fD"); /* obsolescent and undocumented */
- CASE_OLD_ARG ('f', "fF");
- case 'X': /* obsolescent and undocumented alias */
- CASE_OLD_ARG ('H', "x4"); /* obsolescent and undocumented */
- CASE_OLD_ARG ('i', "dI");
- case 'I': case 'L': /* obsolescent and undocumented aliases */
- CASE_OLD_ARG ('l', "dL");
- CASE_OLD_ARG ('O', "o4"); /* obsolesent and undocumented */
- case 'B': /* obsolescent and undocumented alias */
- CASE_OLD_ARG ('o', "o2");
- CASE_OLD_ARG ('s', "d2");
- case 'h': /* obsolescent and undocumented alias */
- CASE_OLD_ARG ('x', "x2");
+ case old_char: \
+ ok &= decode_format_string (new_string); \
+ break
+
+ CASE_OLD_ARG ('a', "a");
+ CASE_OLD_ARG ('b', "o1");
+ CASE_OLD_ARG ('c', "c");
+ CASE_OLD_ARG ('D', "u4"); /* obsolescent and undocumented */
+ CASE_OLD_ARG ('d', "u2");
+ case 'F': /* obsolescent and undocumented alias */
+ CASE_OLD_ARG ('e', "fD"); /* obsolescent and undocumented */
+ CASE_OLD_ARG ('f', "fF");
+ case 'X': /* obsolescent and undocumented alias */
+ CASE_OLD_ARG ('H', "x4"); /* obsolescent and undocumented */
+ CASE_OLD_ARG ('i', "dI");
+ case 'I': case 'L': /* obsolescent and undocumented aliases */
+ CASE_OLD_ARG ('l', "dL");
+ CASE_OLD_ARG ('O', "o4"); /* obsolesent and undocumented */
+ case 'B': /* obsolescent and undocumented alias */
+ CASE_OLD_ARG ('o', "o2");
+ CASE_OLD_ARG ('s', "d2");
+ case 'h': /* obsolescent and undocumented alias */
+ CASE_OLD_ARG ('x', "x2");
#undef CASE_OLD_ARG
- case 'w':
- modern = true;
- width_specified = true;
- if (optarg == NULL)
- {
- desired_width = 32;
- }
- else
- {
- uintmax_t w_tmp;
- s_err = xstrtoumax (optarg, NULL, 10, &w_tmp, "");
- if (s_err != LONGINT_OK)
- STRTOL_FATAL_ERROR (optarg, _("width specification"), s_err);
- if (SIZE_MAX < w_tmp)
- error (EXIT_FAILURE, 0, _("%s is too large"), optarg);
- desired_width = w_tmp;
- }
- break;
-
- case_GETOPT_HELP_CHAR;
-
- case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
-
- default:
- usage (EXIT_FAILURE);
- break;
- }
+ case 'w':
+ modern = true;
+ width_specified = true;
+ if (optarg == NULL)
+ {
+ desired_width = 32;
+ }
+ else
+ {
+ uintmax_t w_tmp;
+ s_err = xstrtoumax (optarg, NULL, 10, &w_tmp, "");
+ if (s_err != LONGINT_OK)
+ xstrtol_fatal (s_err, oi, c, long_options, optarg);
+ if (SIZE_MAX < w_tmp)
+ error (EXIT_FAILURE, 0, _("%s is too large"), optarg);
+ desired_width = w_tmp;
+ }
+ break;
+
+ case_GETOPT_HELP_CHAR;
+
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+
+ default:
+ usage (EXIT_FAILURE);
+ break;
+ }
}
if (!ok)
if (flag_dump_strings && n_specs > 0)
error (EXIT_FAILURE, 0,
- _("no type may be specified when dumping strings"));
+ _("no type may be specified when dumping strings"));
n_files = argc - optind;
/* If the --traditional option is used, there may be from
0 to 3 remaining command line arguments; handle each case
separately.
- od [file] [[+]offset[.][b] [[+]label[.][b]]]
+ od [file] [[+]offset[.][b] [[+]label[.][b]]]
The offset and label have the same syntax.
If --traditional is not given, and if no modern options are
given, and if the offset begins with + or (if there are two
operands) a digit, accept only this form, as per POSIX:
- od [file] [[+]offset[.][b]]
+ od [file] [[+]offset[.][b]]
*/
- if (!modern | traditional)
+ if (!modern || traditional)
{
uintmax_t o1;
uintmax_t o2;
switch (n_files)
- {
- case 1:
- if ((traditional || argv[optind][0] == '+')
- && parse_old_offset (argv[optind], &o1))
- {
- n_bytes_to_skip = o1;
- --n_files;
- ++argv;
- }
- break;
-
- case 2:
- if ((traditional || argv[optind + 1][0] == '+'
- || ISDIGIT (argv[optind + 1][0]))
- && parse_old_offset (argv[optind + 1], &o2))
- {
- if (traditional && parse_old_offset (argv[optind], &o1))
- {
- n_bytes_to_skip = o1;
- flag_pseudo_start = true;
- pseudo_start = o2;
- argv += 2;
- n_files -= 2;
- }
- else
- {
- n_bytes_to_skip = o2;
- --n_files;
- argv[optind + 1] = argv[optind];
- ++argv;
- }
- }
- break;
-
- case 3:
- if (traditional
- && parse_old_offset (argv[optind + 1], &o1)
- && parse_old_offset (argv[optind + 2], &o2))
- {
- n_bytes_to_skip = o1;
- flag_pseudo_start = true;
- pseudo_start = o2;
- argv[optind + 2] = argv[optind];
- argv += 2;
- n_files -= 2;
- }
- break;
- }
+ {
+ case 1:
+ if ((traditional || argv[optind][0] == '+')
+ && parse_old_offset (argv[optind], &o1))
+ {
+ n_bytes_to_skip = o1;
+ --n_files;
+ ++argv;
+ }
+ break;
+
+ case 2:
+ if ((traditional || argv[optind + 1][0] == '+'
+ || ISDIGIT (argv[optind + 1][0]))
+ && parse_old_offset (argv[optind + 1], &o2))
+ {
+ if (traditional && parse_old_offset (argv[optind], &o1))
+ {
+ n_bytes_to_skip = o1;
+ flag_pseudo_start = true;
+ pseudo_start = o2;
+ argv += 2;
+ n_files -= 2;
+ }
+ else
+ {
+ n_bytes_to_skip = o2;
+ --n_files;
+ argv[optind + 1] = argv[optind];
+ ++argv;
+ }
+ }
+ break;
+
+ case 3:
+ if (traditional
+ && parse_old_offset (argv[optind + 1], &o1)
+ && parse_old_offset (argv[optind + 2], &o2))
+ {
+ n_bytes_to_skip = o1;
+ flag_pseudo_start = true;
+ pseudo_start = o2;
+ argv[optind + 2] = argv[optind];
+ argv += 2;
+ n_files -= 2;
+ }
+ break;
+ }
if (traditional && 1 < n_files)
- {
- error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
- error (0, 0, "%s\n",
- _("Compatibility mode supports at most one file."));
- usage (EXIT_FAILURE);
- }
+ {
+ error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
+ error (0, 0, "%s",
+ _("compatibility mode supports at most one file"));
+ usage (EXIT_FAILURE);
+ }
}
if (flag_pseudo_start)
{
if (format_address == format_address_none)
- {
- address_base = 8;
- address_pad_len = 7;
- format_address = format_address_paren;
- }
+ {
+ address_base = 8;
+ address_pad_len = 7;
+ format_address = format_address_paren;
+ }
else
- format_address = format_address_label;
+ format_address = format_address_label;
}
if (limit_bytes_to_format)
{
end_offset = n_bytes_to_skip + max_bytes_to_format;
if (end_offset < n_bytes_to_skip)
- error (EXIT_FAILURE, 0, _("skip-bytes + read-bytes is too large"));
+ error (EXIT_FAILURE, 0, _("skip-bytes + read-bytes is too large"));
}
if (n_specs == 0)
if (n_files > 0)
{
/* Set the global pointer FILE_LIST so that it
- references the first file-argument on the command-line. */
+ references the first file-argument on the command-line. */
file_list = (char const *const *) &argv[optind];
}
else
{
/* 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: "-". */
+ Set the global pointer FILE_LIST so that it
+ references the null-terminated list of one name: "-". */
file_list = default_file_list;
}
if (width_specified)
{
if (desired_width != 0 && desired_width % l_c_m == 0)
- bytes_per_block = desired_width;
+ bytes_per_block = desired_width;
else
- {
- error (0, 0, _("warning: invalid width %lu; using %d instead"),
- (unsigned long int) desired_width, l_c_m);
- bytes_per_block = l_c_m;
- }
+ {
+ error (0, 0, _("warning: invalid width %lu; using %d instead"),
+ (unsigned long int) desired_width, l_c_m);
+ bytes_per_block = l_c_m;
+ }
}
else
{
if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
- bytes_per_block = l_c_m * (DEFAULT_BYTES_PER_BLOCK / l_c_m);
+ bytes_per_block = l_c_m * (DEFAULT_BYTES_PER_BLOCK / l_c_m);
else
- bytes_per_block = l_c_m;
+ bytes_per_block = l_c_m;
+ }
+
+ /* Compute padding necessary to align output block. */
+ for (i = 0; i < n_specs; i++)
+ {
+ int fields_per_block = bytes_per_block / width_bytes[spec[i].size];
+ int block_width = (spec[i].field_width + 1) * fields_per_block;
+ if (width_per_block < block_width)
+ width_per_block = block_width;
+ }
+ for (i = 0; i < n_specs; i++)
+ {
+ int fields_per_block = bytes_per_block / width_bytes[spec[i].size];
+ int block_width = spec[i].field_width * fields_per_block;
+ spec[i].pad_width = width_per_block - block_width;
}
#ifdef DEBUG
+ printf ("lcm=%d, width_per_block=%zu\n", l_c_m, width_per_block);
for (i = 0; i < n_specs; i++)
{
- printf (_("%d: fmt=\"%s\" width=%d\n"),
- i, spec[i].fmt_string, width_bytes[spec[i].size]);
+ int fields_per_block = bytes_per_block / width_bytes[spec[i].size];
+ assert (bytes_per_block % width_bytes[spec[i].size] == 0);
+ assert (1 <= spec[i].pad_width / fields_per_block);
+ printf ("%d: fmt=\"%s\" in_width=%d out_width=%d pad=%d\n",
+ i, spec[i].fmt_string, width_bytes[spec[i].size],
+ spec[i].field_width, spec[i].pad_width);
}
#endif
ok &= (flag_dump_strings ? dump_strings () : dump ());
-cleanup:;
+cleanup:
if (have_read_stdin && fclose (stdin) == EOF)
error (EXIT_FAILURE, errno, _("standard input"));