/* 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
#include <getopt.h>
#include <sys/types.h>
#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 <float.h>
typedef double LONG_DOUBLE;
#endif
-#if HAVE_VALUES_H
-# include <values.h>
-#endif
-
/* The default number of input bytes per output line. */
#define DEFAULT_BYTES_PER_BLOCK 16
# 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,
/* FIXME: add INTMAX support, too */
FLOAT_SINGLE,
FLOAT_DOUBLE,
- FLOAT_LONG_DOUBLE
+ FLOAT_LONG_DOUBLE,
+ N_SIZE_SPECS
};
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;
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] =
{
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;
/* 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;
/* 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},
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);
-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\
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\
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 <bug-textutils@gnu.org>."));
+ printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
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,
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;
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);
{
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:
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;
{
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;
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. */
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,
skip (uintmax_t n_skip)
{
int err = 0;
+ int in_errno = 0;
if (n_skip == 0)
return 0;
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;
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;
+ }
}
}
err = 1;
}
- err |= check_and_close ();
+ err |= check_and_close (in_errno);
err |= open_next_file ();
}
if (*c != EOF)
break;
- err |= check_and_close ();
+ err |= check_and_close (errno);
err |= open_next_file ();
}
if (n_read == n_needed)
break;
- err |= check_and_close ();
+ err |= check_and_close (errno);
err |= open_next_file ();
}
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)
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;
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;
}
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
free (buf);
- err |= check_and_close ();
+ err |= check_and_close (0);
return err;
}
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);
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
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;
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. */
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':
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;
}
}
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)
{
error (0, 0,
_("invalid second operand in compatibility mode `%s'"),
argv[optind + 1]);
- usage (1);
+ usage (EXIT_FAILURE);
}
}
else if (n_files == 3)
{
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)
{
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)