X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fod.c;h=d362e66ad80085717465dd850e49e6a2b62cdd57;hb=8f98e0e4ddaaf6a87be975ea8e4e3a20fd3d4925;hp=a2798e6cbf90182678ee52fcbf11309d4bc69a8c;hpb=436f7c405aa2ec21e643f33c303ab29467359471;p=platform%2Fupstream%2Fcoreutils.git diff --git a/src/od.c b/src/od.c index a2798e6..d362e66 100644 --- a/src/od.c +++ b/src/od.c @@ -1,5 +1,5 @@ /* od -- dump files in octal and other formats - Copyright (C) 92, 1995-2001 Free Software Foundation, Inc. + Copyright (C) 92, 1995-2003 Free Software Foundation, Inc. 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 @@ -24,14 +24,14 @@ #include #include #include "system.h" -#include "closeout.h" #include "error.h" +#include "posixver.h" #include "xstrtol.h" /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "od" -#define AUTHORS "Jim Meyering" +#define WRITTEN_BY _("Written by Jim Meyering.") #if defined(__GNUC__) || defined(STDC_HEADERS) # include @@ -43,10 +43,6 @@ typedef long double LONG_DOUBLE; typedef double LONG_DOUBLE; #endif -#if HAVE_VALUES_H -# include -#endif - /* The default number of input bytes per output line. */ #define DEFAULT_BYTES_PER_BLOCK 16 @@ -65,6 +61,14 @@ typedef double LONG_DOUBLE; # define LDBL_DIG DBL_DIG #endif +#if HAVE_UNSIGNED_LONG_LONG +typedef unsigned long long ulonglong_t; +#else +/* 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; +#endif + enum size_spec { NO_SIZE, @@ -76,7 +80,8 @@ enum size_spec /* FIXME: add INTMAX support, too */ FLOAT_SINGLE, FLOAT_DOUBLE, - FLOAT_LONG_DOUBLE + FLOAT_LONG_DOUBLE, + N_SIZE_SPECS }; enum output_format @@ -90,13 +95,13 @@ enum output_format CHARACTER }; -/* Each output format specification (from POSIX `-t spec' or from +/* 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) PARAMS ((size_t, const char *, const char *)); + void (*print_function) (size_t, const char *, const char *); char *fmt_string; int hexl_mode_trailer; int field_width; @@ -135,11 +140,20 @@ static const int width_bytes[] = sizeof (short int), sizeof (int), sizeof (long int), + sizeof (ulonglong_t), sizeof (float), sizeof (double), sizeof (LONG_DOUBLE) }; +/* Ensure that for each member of `enum size_spec' there is an + initializer in the width_bytes array. */ +struct dummy +{ + int assert_width_bytes_matches_size_spec_decl + [sizeof width_bytes / sizeof width_bytes[0] == N_SIZE_SPECS ? 1 : -1]; +}; + /* Names for some non-printing characters. */ static const char *const charname[33] = { @@ -164,7 +178,7 @@ static int address_pad_len; static size_t string_min; static int flag_dump_strings; -/* Non-zero if we should recognize the pre-POSIX non-option arguments +/* Non-zero if we should recognize the older non-option arguments that specified at most one file and optional arguments specifying offset and pseudo-start address. */ static int traditional; @@ -178,7 +192,7 @@ static uintmax_t pseudo_offset; /* Function that accepts an address and an optional following char, and prints the address and char to stdout. */ -static void (*format_address) PARAMS ((uintmax_t, char)); +static void (*format_address) (uintmax_t, char); /* The number of input bytes to skip before formatting and writing. */ static uintmax_t n_bytes_to_skip = 0; @@ -230,32 +244,30 @@ static FILE *in_stream; /* If nonzero, at least one of the files we read was standard input. */ static int have_read_stdin; -#if HAVE_UNSIGNED_LONG_LONG -typedef unsigned long long ulonglong_t; -#else -/* 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; -#endif - #define MAX_INTEGRAL_TYPE_SIZE sizeof (ulonglong_t) static enum size_spec integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1]; #define MAX_FP_TYPE_SIZE sizeof(LONG_DOUBLE) static enum size_spec fp_type_size[MAX_FP_TYPE_SIZE + 1]; +#define COMMON_SHORT_OPTIONS "A:N:abcdfhij:lot:vx" + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TRADITIONAL_OPTION = CHAR_MAX + 1 +}; + static struct option const long_options[] = { - /* POSIX options. */ {"skip-bytes", required_argument, NULL, 'j'}, {"address-radix", required_argument, NULL, 'A'}, {"read-bytes", required_argument, NULL, 'N'}, {"format", required_argument, NULL, 't'}, {"output-duplicates", no_argument, NULL, 'v'}, - - /* non-POSIX options. */ {"strings", optional_argument, NULL, 's'}, - {"traditional", no_argument, NULL, 'B'}, + {"traditional", no_argument, NULL, TRADITIONAL_OPTION}, {"width", optional_argument, NULL, 'w'}, {GETOPT_HELP_OPTION_DECL}, @@ -282,7 +294,11 @@ of FILE to standard output. With more than one FILE argument,\n\ concatenate them in the listed order to form the input.\n\ With no FILE, or when FILE is -, read standard input.\n\ \n\ -Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ +All arguments to long options are mandatory for short options.\n\ +"), stdout); + fputs (_("\ -A, --address-radix=RADIX decide how file offsets are printed\n\ -j, --skip-bytes=BYTES skip BYTES input bytes first\n\ "), stdout); @@ -292,13 +308,13 @@ Mandatory arguments to long options are mandatory for short options too.\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 pre-POSIX form\n\ + --traditional accept arguments in traditional form\n\ "), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ - --help display this help and exit\n\ - --version output version information and exit\n\ \n\ -Pre-POSIX format specifications may be intermixed, they accumulate:\n\ +Traditional format specifications may be intermixed; they accumulate:\n\ -a same as -t a, select named characters\n\ -b same as -t oC, select octal bytes\n\ -c same as -t c, select ASCII characters or backslash escapes\n\ @@ -317,7 +333,7 @@ Pre-POSIX format specifications may be intermixed, they accumulate:\n\ For older syntax (second call format), OFFSET means -j OFFSET. LABEL\n\ is the pseudo-address at first byte printed, incremented when dump is\n\ progressing. For OFFSET and LABEL, a 0x or 0X prefix indicates\n\ -hexadecimal, suffixes maybe . for octal and b multiply by 512.\n\ +hexadecimal, 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\ @@ -330,24 +346,27 @@ TYPE is made up of one or more of these specifications:\n\ o[SIZE] octal, SIZE bytes per integer\n\ u[SIZE] unsigned decimal, SIZE bytes per integer\n\ x[SIZE] hexadecimal, SIZE bytes per integer\n\ +"), stdout); + fputs (_("\ \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\ -"), stdout); - fputs (_("\ 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\ -"), stdout); - fputs (_("\ 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. -s without a number implies 3. -w without a number implies 32.\n\ -By default, od uses -A o -t d2 -w 16.\n\ +of output. \ +"), 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\ "), stdout); - puts (_("\nReport bugs to .")); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); } exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } @@ -631,7 +650,7 @@ simple_strtoul (const char *s, const char **p, long unsigned int *val) return 0; } -/* If S points to a single valid POSIX-style od format string, put +/* If S points to a single valid modern od format string, put a description of that format in *TSPEC, make *NEXT point at the character following the just-decoded format (if *NEXT is non-NULL), and return zero. If S is not valid, don't modify *NEXT or *TSPEC, @@ -656,7 +675,7 @@ decode_one_format (const char *s_orig, const char *s, const char **next, enum output_format fmt; const char *pre_fmt_string; char *fmt_string; - void (*print_function) PARAMS ((size_t, const char *, const char *)); + void (*print_function) (size_t, const char *, const char *); const char *p; unsigned int c; unsigned int field_width = 0; @@ -718,6 +737,11 @@ this system doesn't provide a %lu-byte integral type"), s_orig, size); break; } +#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \ + ((Spec) == LONG_LONG ? (Max_format) \ + : ((Spec) == LONG ? (Long_format) \ + : (Min_format))) \ + #define FMT_BYTES_ALLOCATED 9 fmt_string = xmalloc (FMT_BYTES_ALLOCATED); @@ -727,32 +751,30 @@ this system doesn't provide a %lu-byte integral type"), s_orig, size); { case 'd': fmt = SIGNED_DECIMAL; - sprintf (fmt_string, " %%%u%sd", + sprintf (fmt_string, " %%%u%s", (field_width = bytes_to_signed_dec_digits[size]), - (size_spec == LONG ? "l" - : (size_spec == LONG_LONG ? "ll" - : ""))); + ISPEC_TO_FORMAT (size_spec, "d", "ld", PRIdMAX)); break; case 'o': fmt = OCTAL; - sprintf (fmt_string, " %%0%u%so", + sprintf (fmt_string, " %%0%u%s", (field_width = bytes_to_oct_digits[size]), - (size_spec == LONG ? "l" : "")); + ISPEC_TO_FORMAT (size_spec, "o", "lo", PRIoMAX)); break; case 'u': fmt = UNSIGNED_DECIMAL; - sprintf (fmt_string, " %%%u%su", + sprintf (fmt_string, " %%%u%s", (field_width = bytes_to_unsigned_dec_digits[size]), - (size_spec == LONG ? "l" : "")); + ISPEC_TO_FORMAT (size_spec, "u", "lu", PRIuMAX)); break; case 'x': fmt = HEXADECIMAL; - sprintf (fmt_string, " %%0%u%sx", + sprintf (fmt_string, " %%0%u%s", (field_width = bytes_to_hex_digits[size]), - (size_spec == LONG ? "l" : "")); + ISPEC_TO_FORMAT (size_spec, "x", "lx", PRIxMAX)); break; default: @@ -960,10 +982,11 @@ open_next_file (void) it is not standard input. Return nonzero if there has been an error on in_stream or stdout; return zero otherwise. This function will report more than one error only if both a read and a write error - have occurred. */ + have occurred. IN_ERRNO, if nonzero, is the error number + corresponding to the most recent action for IN_STREAM. */ static int -check_and_close (void) +check_and_close (int in_errno) { int err = 0; @@ -971,7 +994,7 @@ check_and_close (void) { if (ferror (in_stream)) { - error (0, errno, "%s", input_filename); + error (0, in_errno, _("%s: read error"), input_filename); if (in_stream != stdin) fclose (in_stream); err = 1; @@ -987,14 +1010,14 @@ check_and_close (void) if (ferror (stdout)) { - error (0, errno, _("standard output")); + error (0, 0, _("write error")); err = 1; } return err; } -/* Decode the POSIX-style od format string S. Append the decoded +/* Decode the modern od format string S. Append the decoded representation to the global array SPEC, reallocating SPEC if necessary. Return zero if S is valid, nonzero otherwise. */ @@ -1018,9 +1041,7 @@ decode_format_string (const char *s) if (n_specs >= n_specs_allocated) { n_specs_allocated = 1 + (3 * n_specs_allocated) / 2; - spec = (struct tspec *) xrealloc ((char *) spec, - (n_specs_allocated - * sizeof (struct tspec))); + spec = xrealloc (spec, (n_specs_allocated * sizeof (struct tspec))); } memcpy ((char *) &spec[n_specs], (char *) &tspec, @@ -1042,6 +1063,7 @@ static int skip (uintmax_t n_skip) { int err = 0; + int in_errno = 0; if (n_skip == 0) return 0; @@ -1070,13 +1092,13 @@ skip (uintmax_t n_skip) if (S_ISREG (file_stats.st_mode) && 0 <= file_stats.st_size) { - if (file_stats.st_size <= n_skip) + if ((uintmax_t) file_stats.st_size <= n_skip) n_skip -= file_stats.st_size; else { - if (lseek (fileno (in_stream), n_skip, SEEK_CUR) < 0) + if (fseeko (in_stream, n_skip, SEEK_CUR) != 0) { - error (0, errno, "%s", input_filename); + in_errno = errno; err = 1; } n_skip = 0; @@ -1098,7 +1120,12 @@ skip (uintmax_t 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) - break; + { + in_errno = errno; + err = 1; + n_skip = 0; + break; + } } } @@ -1112,7 +1139,7 @@ skip (uintmax_t n_skip) err = 1; } - err |= check_and_close (); + err |= check_and_close (in_errno); err |= open_next_file (); } @@ -1270,7 +1297,7 @@ read_char (int *c) if (*c != EOF) break; - err |= check_and_close (); + err |= check_and_close (errno); err |= open_next_file (); } @@ -1317,7 +1344,7 @@ read_block (size_t n, char *block, size_t *n_bytes_in_buffer) if (n_read == n_needed) break; - err |= check_and_close (); + err |= check_and_close (errno); err |= open_next_file (); } @@ -1339,8 +1366,8 @@ get_lcm (void) return l_c_m; } -/* If S is a valid pre-POSIX offset specification with an optional leading '+' - return nonzero and set *OFFSET to the offset it denotes. */ +/* If S is a valid traditional offset specification with an optional + leading '+' return nonzero and set *OFFSET to the offset it denotes. */ static int parse_old_offset (const char *s, uintmax_t *offset) @@ -1398,8 +1425,8 @@ dump (void) int err; size_t n_bytes_read; - block[0] = (char *) alloca (bytes_per_block); - block[1] = (char *) alloca (bytes_per_block); + block[0] = alloca (bytes_per_block); + block[1] = alloca (bytes_per_block); current_offset = n_bytes_to_skip; @@ -1462,7 +1489,7 @@ dump (void) format_address (current_offset, '\n'); if (limit_bytes_to_format && current_offset >= end_offset) - err |= check_and_close (); + err |= check_and_close (0); return err; } @@ -1471,7 +1498,7 @@ dump (void) 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 - pre-POSIX version of od. Return nonzero if an error + traditional version of od. Return nonzero if an error occurs. Otherwise, return zero. */ static int @@ -1582,7 +1609,7 @@ dump_strings (void) free (buf); - err |= check_and_close (); + err |= check_and_close (0); return err; } @@ -1597,11 +1624,15 @@ main (int argc, char **argv) int width_specified = 0; int n_failed_decodes = 0; int err; + char const *short_options = (posix2_version () < 200112 + ? COMMON_SHORT_OPTIONS "s::w::" + : COMMON_SHORT_OPTIONS "s:w:"); /* The old-style `pseudo starting address' to be printed in parentheses after any true address. */ uintmax_t pseudo_start IF_LINT (= 0); + initialize_main (&argc, &argv); program_name = argv[0]; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); @@ -1619,6 +1650,8 @@ main (int argc, char **argv) integral_type_size[sizeof (int)] = INT; integral_type_size[sizeof (long int)] = LONG; #if HAVE_UNSIGNED_LONG_LONG + /* If `long' and `long long' have the same size, it's fine + to overwrite the entry for `long' with this one. */ integral_type_size[sizeof (ulonglong_t)] = LONG_LONG; #endif @@ -1634,15 +1667,15 @@ main (int argc, char **argv) n_specs = 0; n_specs_allocated = 5; - spec = (struct tspec *) xmalloc (n_specs_allocated * sizeof (struct tspec)); + spec = xmalloc (n_specs_allocated * sizeof (struct tspec)); format_address = format_address_std; address_base = 8; address_pad_len = 7; flag_dump_strings = 0; - while ((c = getopt_long (argc, argv, "abcdfhilos::xw::A:j:N:t:v", - long_options, NULL)) != -1) + while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) + != -1) { uintmax_t tmp; enum strtol_error s_err; @@ -1725,12 +1758,12 @@ it must be one character from [doxn]"), abbreviate_duplicate_blocks = 0; break; - case 'B': + case TRADITIONAL_OPTION: traditional = 1; break; - /* The next several cases map the old, pre-POSIX format - specification options to the corresponding POSIX format + /* 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. */ @@ -1753,6 +1786,13 @@ it must be one character from [doxn]"), CASE_OLD_ARG ('o', "o2"); CASE_OLD_ARG ('x', "x2"); + /* FIXME: POSIX 1003.1-2001 with XSI requires this: + + CASE_OLD_ARG ('s', "d2"); + + for the traditional syntax, but this conflicts with case + 's' above. */ + #undef CASE_OLD_ARG case 'w': @@ -1775,10 +1815,10 @@ it must be one character from [doxn]"), case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY); default: - usage (1); + usage (EXIT_FAILURE); break; } } @@ -1792,11 +1832,14 @@ it must be one character from [doxn]"), n_files = argc - optind; - /* If the --backward-compatible option is used, there may be from + /* 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]]] - The offset and pseudo_start have the same syntax. */ + The offset and pseudo_start have the same syntax. + + FIXME: POSIX 1003.1-2001 with XSI requires support for the + traditional syntax even if --traditional is not given. */ if (traditional) { @@ -1835,7 +1878,7 @@ it must be one character from [doxn]"), error (0, 0, _("invalid second operand in compatibility mode `%s'"), argv[optind + 1]); - usage (1); + usage (EXIT_FAILURE); } } else if (n_files == 3) @@ -1855,14 +1898,14 @@ it must be one character from [doxn]"), { error (0, 0, _("in compatibility mode, the last two arguments must be offsets")); - usage (1); + usage (EXIT_FAILURE); } } else if (n_files > 3) { error (0, 0, _("compatibility mode supports at most three arguments")); - usage (1); + usage (EXIT_FAILURE); } if (flag_pseudo_start) @@ -1882,7 +1925,7 @@ it must be one character from [doxn]"), { 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)