X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fod.c;h=e7ec59a2e2ae9c8da27cef7e0d5bf09990fc0ae5;hb=77da73c75432f3c5b4beebae7b0797a1e33160bc;hp=651ebf29a24d51b1a98d7b9534591c2b91a0f983;hpb=971c8d4c1f18977aa9c1ade1267ee14b62cf359f;p=platform%2Fupstream%2Fcoreutils.git diff --git a/src/od.c b/src/od.c index 651ebf2..e7ec59a 100644 --- a/src/od.c +++ b/src/od.c @@ -1,10 +1,10 @@ /* 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 @@ -12,8 +12,7 @@ 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 . */ /* Written by Jim Meyering. */ @@ -25,48 +24,26 @@ #include #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 -#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 @@ -95,35 +72,44 @@ enum output_format 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. @@ -134,18 +120,28 @@ char *program_name; 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[] = { @@ -154,18 +150,18 @@ 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 (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", @@ -185,7 +181,10 @@ static int address_base; /* 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 @@ -193,7 +192,7 @@ static bool flag_dump_strings; 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 @@ -254,10 +253,10 @@ static FILE *in_stream; /* 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"; @@ -289,8 +288,7 @@ void usage (int status) { if (status != EXIT_SUCCESS) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); + emit_try_help (); else { printf (_("\ @@ -298,7 +296,7 @@ Usage: %s [OPTION]... [FILE]...\n\ 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\ @@ -307,26 +305,40 @@ With no FILE, or when FILE is -, read standard input.\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\ @@ -341,16 +353,9 @@ Traditional format specifications may be intermixed; they accumulate:\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 (_("\ @@ -362,121 +367,75 @@ TYPE is made up of one or more of these specifications:\n\ "), 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) @@ -486,90 +445,99 @@ 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; } } @@ -591,7 +559,7 @@ simple_strtoul (const char *s, const char **p, unsigned long int *val) { int c = *s++ - '0'; if (sum > (ULONG_MAX - c) / 10) - return false; + return false; sum = sum * 10 + c; } *p = s; @@ -609,25 +577,27 @@ simple_strtoul (const char *s, const char **p, unsigned long int *val) 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); @@ -640,51 +610,52 @@ decode_one_format (const char *s_orig, const char *s, const char **next, 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"), 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;\n\ -this system doesn't provide a %lu-byte integral type"), quote (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) \ @@ -694,149 +665,149 @@ this system doesn't provide a %lu-byte integral type"), quote (s_orig), size); 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"), 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; - } + { + 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; @@ -855,8 +826,8 @@ this system doesn't provide a %lu-byte floating point type"), break; default: - error (0, 0, _("invalid character `%c' in type string %s"), - *s, quote (s_orig)); + error (0, 0, _("invalid character '%c' in type string %s"), + *s, quote (s_orig)); return false; } @@ -891,30 +862,31 @@ open_next_file (void) { 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; } @@ -934,17 +906,17 @@ check_and_close (int in_errno) 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; } @@ -973,10 +945,10 @@ decode_format_string (const char *s) 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; @@ -1007,71 +979,71 @@ skip (uintmax_t n_skip) 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); @@ -1085,7 +1057,8 @@ skip (uintmax_t n_skip) } 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) { } @@ -1106,19 +1079,19 @@ format_address_std (uintmax_t address, char c) { 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; } @@ -1153,32 +1126,31 @@ format_address_label (uintmax_t address, char c) 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 { @@ -1186,23 +1158,28 @@ write_block (uintmax_t current_offset, size_t n_bytes, 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; } @@ -1230,7 +1207,7 @@ read_char (int *c) *c = fgetc (in_stream); if (*c != EOF) - break; + break; ok &= check_and_close (errno); @@ -1277,7 +1254,7 @@ read_block (size_t n, char *block, size_t *n_bytes_in_buffer) *n_bytes_in_buffer += n_read; if (n_read == n_needed) - break; + break; ok &= check_and_close (errno); @@ -1290,7 +1267,7 @@ read_block (size_t n, char *block, size_t *n_bytes_in_buffer) /* 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; @@ -1316,17 +1293,17 @@ parse_old_offset (const char *s, uintmax_t *offset) 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; @@ -1361,38 +1338,38 @@ dump (void) 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) @@ -1402,13 +1379,12 @@ dump (void) 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; } @@ -1423,7 +1399,7 @@ dump (void) } /* 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. */ @@ -1441,91 +1417,91 @@ dump_strings (void) 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 = 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 (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'); } @@ -1541,21 +1517,22 @@ dump_strings (void) 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); @@ -1569,20 +1546,20 @@ main (int argc, char **argv) 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; @@ -1594,157 +1571,161 @@ main (int argc, char **argv) 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) @@ -1752,103 +1733,103 @@ it must be one character from [doxn]"), 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) @@ -1857,15 +1838,15 @@ it must be one character from [doxn]"), 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; } @@ -1888,33 +1869,53 @@ it must be one character from [doxn]"), 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"));