/* od -- dump files in octal and other formats
- Copyright (C) 92, 1995-2002 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
{
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] =
{
/* 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];
-static char const short_options[] =
-"abcdfhilos" OPTARG_POSIX "xw" OPTARG_POSIX "A:j:N:t:v";
+#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
{
- STRINGS_OPTION = CHAR_MAX + 1,
- TRADITIONAL_OPTION,
- WIDTH_OPTION
+ TRADITIONAL_OPTION = CHAR_MAX + 1
};
static struct option const long_options[] =
{"read-bytes", required_argument, NULL, 'N'},
{"format", required_argument, NULL, 't'},
{"output-duplicates", no_argument, NULL, 'v'},
-
- {"strings", optional_argument, NULL, STRINGS_OPTION},
+ {"strings", optional_argument, NULL, 's'},
{"traditional", no_argument, NULL, TRADITIONAL_OPTION},
- {"width", optional_argument, NULL, WIDTH_OPTION},
+ {"width", optional_argument, NULL, 'w'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
With no FILE, or when FILE is -, read standard input.\n\
\n\
"), stdout);
- if (POSIX2_VERSION < 200112)
- fputs (_("\
-Mandatory arguments to long options are mandatory for short options too.\n\
-"), stdout);
- else
- fputs (_("\
+ fputs (_("\
All arguments to long options are mandatory for short options.\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\
"), stdout);
- puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
+ printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
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;
}
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 (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 ();
}
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;
}
free (buf);
- err |= check_and_close ();
+ err |= check_and_close (0);
return err;
}
int width_specified = 0;
int n_failed_decodes = 0;
int err;
- bool posix_pedantic = (getenv ("POSIXLY_CORRECT") != NULL);
+ 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;
break;
case 's':
- if (POSIX2_VERSION < 200112 && OBSOLETE_OPTION_WARNINGS
- && ! optarg && ! posix_pedantic)
- error (0, 0,
- _("warning: `od -s' is obsolete; use `od --strings'"));
- /* Fall through. */
- case STRINGS_OPTION:
if (optarg == NULL)
string_min = 3;
else
#undef CASE_OLD_ARG
case 'w':
- if (POSIX2_VERSION < 200112 && OBSOLETE_OPTION_WARNINGS
- && ! optarg && ! posix_pedantic)
- error (0, 0, _("warning: `od -w' is obsolete; use `od --width'"));
- /* Fall through. */
- case WIDTH_OPTION:
width_specified = 1;
if (optarg == NULL)
{
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;
}
}
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)