summaryrefslogtreecommitdiff
path: root/src/od.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2001-09-20 08:44:12 +0000
committerJim Meyering <jim@meyering.net>2001-09-20 08:44:12 +0000
commitb6baea64d103ee59950ac8f779ba2c307aeb71f1 (patch)
tree57a08b15d29c587d4f4e23f6ae211cc1045f3e43 /src/od.c
parent447637fb37e207c7fa1f9088e269a12f8003f064 (diff)
downloadcoreutils-b6baea64d103ee59950ac8f779ba2c307aeb71f1.tar.xz
(MAX_ADDRESS_LENGTH, pseudo_offset, format_address,
n_bytes_to_skip, skip, format_address_none, format_address_std, format_address_paren, format_address_label, write_block, parse_old_offset, dump, dump_strings, main): Use uintmax_t, not off_t, for file addresses, so that we can handle multiple large files even if the sum of their sizes exceeds off_t limits. (print_s_char, print_char, print_s_short, print_short, print_int, print_long, print_long_long, print_float, print_double, print_long_double, dump_hexl_mode_trailer, print_named_ascii, print_ascii, decode_one_format): Use size_t, not off_t, for in-memory byte counts. (end_offset): New var. (dump, dump_strings): Use it. (main): Set it, but check for overflow while doing so. (skip): Report an error if an in-range lseek fails on a regular file, as something's seriously wrong. Check for negative regular file sizes (possible with some broken NFS implementations). (parse_old_offset): Now all offsets are valid, so return a success boolean and take a pointer to an offset as an argument. All callers changed. (dump_strings): Check for overflow when computing end_offset - string_min. (main): Remove OFF_T_MAX checks that are no longer needed. Don't bother assigning through temporary when there's no size limit to check.
Diffstat (limited to 'src/od.c')
-rw-r--r--src/od.c186
1 files changed, 90 insertions, 96 deletions
diff --git a/src/od.c b/src/od.c
index 1bb0a720e..fdcbd143b 100644
--- a/src/od.c
+++ b/src/od.c
@@ -153,9 +153,10 @@ static const char *const charname[33] =
/* Address base (8, 10 or 16). */
static int address_base;
-/* The number of octal digits required to represent the largest off_t value. */
+/* The number of octal digits required to represent the largest
+ address value. */
#define MAX_ADDRESS_LENGTH \
- ((sizeof (off_t) * CHAR_BIT + CHAR_BIT - 1) / 3)
+ ((sizeof (uintmax_t) * CHAR_BIT + CHAR_BIT - 1) / 3)
/* Width of a normal address. */
static int address_pad_len;
@@ -173,22 +174,24 @@ static int flag_pseudo_start;
/* The difference between the old-style pseudo starting address and
the number of bytes to skip. */
-static off_t pseudo_offset;
+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 ((off_t, char));
+static void (*format_address) PARAMS ((uintmax_t, char));
/* The number of input bytes to skip before formatting and writing. */
-static off_t n_bytes_to_skip = 0;
+static uintmax_t n_bytes_to_skip = 0;
-/* When nonzero, MAX_BYTES_TO_FORMAT is the maximum number of bytes
- to be read and formatted. Otherwise all input is formatted. */
+/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
+ input is formatted. */
static int limit_bytes_to_format = 0;
-/* The maximum number of bytes that will be formatted. This
- value is used only when LIMIT_BYTES_TO_FORMAT is nonzero. */
-static off_t max_bytes_to_format;
+/* The maximum number of bytes that will be formatted. */
+static uintmax_t max_bytes_to_format;
+
+/* The offset of the first byte after the last byte to be formatted. */
+static uintmax_t end_offset;
/* When nonzero and two or more consecutive blocks are equal, format
only the first block and output an asterisk alone on the following
@@ -364,9 +367,9 @@ lcm (unsigned int u, unsigned int v)
}
static void
-print_s_char (off_t n_bytes, const char *block, const char *fmt_string)
+print_s_char (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes; i > 0; i--)
{
int tmp = (unsigned) *(const unsigned char *) block;
@@ -379,9 +382,9 @@ print_s_char (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_char (off_t n_bytes, const char *block, const char *fmt_string)
+print_char (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes; i > 0; i--)
{
unsigned int tmp = *(const unsigned char *) block;
@@ -391,9 +394,9 @@ print_char (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_s_short (off_t n_bytes, const char *block, const char *fmt_string)
+print_s_short (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (unsigned short); i > 0; i--)
{
int tmp = (unsigned) *(const unsigned short *) block;
@@ -406,9 +409,9 @@ print_s_short (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_short (off_t n_bytes, const char *block, const char *fmt_string)
+print_short (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (unsigned short); i > 0; i--)
{
unsigned int tmp = *(const unsigned short *) block;
@@ -418,9 +421,9 @@ print_short (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_int (off_t n_bytes, const char *block, const char *fmt_string)
+print_int (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (unsigned int); i > 0; i--)
{
unsigned int tmp = *(const unsigned int *) block;
@@ -430,9 +433,9 @@ print_int (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_long (off_t n_bytes, const char *block, const char *fmt_string)
+print_long (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (unsigned long); i > 0; i--)
{
unsigned long tmp = *(const unsigned long *) block;
@@ -442,9 +445,9 @@ print_long (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_long_long (off_t n_bytes, const char *block, const char *fmt_string)
+print_long_long (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (ulonglong_t); i > 0; i--)
{
ulonglong_t tmp = *(const ulonglong_t *) block;
@@ -454,9 +457,9 @@ print_long_long (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_float (off_t n_bytes, const char *block, const char *fmt_string)
+print_float (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (float); i > 0; i--)
{
float tmp = *(const float *) block;
@@ -466,9 +469,9 @@ print_float (off_t n_bytes, const char *block, const char *fmt_string)
}
static void
-print_double (off_t n_bytes, const char *block, const char *fmt_string)
+print_double (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (double); i > 0; i--)
{
double tmp = *(const double *) block;
@@ -479,9 +482,9 @@ print_double (off_t n_bytes, const char *block, const char *fmt_string)
#ifdef HAVE_LONG_DOUBLE
static void
-print_long_double (off_t n_bytes, const char *block, const char *fmt_string)
+print_long_double (size_t n_bytes, const char *block, const char *fmt_string)
{
- off_t i;
+ size_t i;
for (i = n_bytes / sizeof (LONG_DOUBLE); i > 0; i--)
{
LONG_DOUBLE tmp = *(const LONG_DOUBLE *) block;
@@ -493,9 +496,9 @@ print_long_double (off_t n_bytes, const char *block, const char *fmt_string)
#endif
static void
-dump_hexl_mode_trailer (off_t n_bytes, const char *block)
+dump_hexl_mode_trailer (size_t n_bytes, const char *block)
{
- off_t i;
+ size_t i;
fputs (" >", stdout);
for (i = n_bytes; i > 0; i--)
{
@@ -508,10 +511,10 @@ dump_hexl_mode_trailer (off_t n_bytes, const char *block)
}
static void
-print_named_ascii (off_t n_bytes, const char *block,
+print_named_ascii (size_t n_bytes, const char *block,
const char *unused_fmt_string ATTRIBUTE_UNUSED)
{
- off_t i;
+ size_t i;
for (i = n_bytes; i > 0; i--)
{
unsigned int c = *(const unsigned char *) block;
@@ -535,10 +538,10 @@ print_named_ascii (off_t n_bytes, const char *block,
}
static void
-print_ascii (off_t n_bytes, const char *block,
+print_ascii (size_t n_bytes, const char *block,
const char *unused_fmt_string ATTRIBUTE_UNUSED)
{
- off_t i;
+ size_t i;
for (i = n_bytes; i > 0; i--)
{
unsigned int c = *(const unsigned char *) block;
@@ -640,7 +643,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 ((off_t, const char *, const char *));
+ void (*print_function) PARAMS ((size_t, const char *, const char *));
const char *p;
unsigned int c;
unsigned int field_width = 0;
@@ -1023,7 +1026,7 @@ decode_format_string (const char *s)
advance IN_STREAM. */
static int
-skip (off_t n_skip)
+skip (uintmax_t n_skip)
{
int err = 0;
@@ -1052,21 +1055,22 @@ skip (off_t n_skip)
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) && file_stats.st_size <= n_skip)
+ if (S_ISREG (file_stats.st_mode) && 0 <= file_stats.st_size)
{
- n_skip -= file_stats.st_size;
- }
-
- /* If the number of bytes left to skip is less than the size
- of the current file, try seeking to the correct offset. */
-
- else if (S_ISREG (file_stats.st_mode)
- && 0 <= lseek (fileno (in_stream), n_skip, SEEK_CUR))
- {
- n_skip = 0;
+ if (file_stats.st_size <= n_skip)
+ n_skip -= file_stats.st_size;
+ else
+ {
+ if (lseek (fileno (in_stream), n_skip, SEEK_CUR) < 0)
+ {
+ error (0, errno, "%s", input_filename);
+ err = 1;
+ }
+ n_skip = 0;
+ }
}
- /* If seek didn't work or wasn't attempted,
+ /* If it's not a regular file with nonnegative size,
position the file pointer by reading. */
else
@@ -1107,12 +1111,12 @@ skip (off_t n_skip)
}
static void
-format_address_none (off_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED)
+format_address_none (uintmax_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED)
{
}
static void
-format_address_std (off_t address, char c)
+format_address_std (uintmax_t address, char c)
{
char buf[MAX_ADDRESS_LENGTH + 2];
char *p = buf + sizeof buf;
@@ -1152,7 +1156,7 @@ format_address_std (off_t address, char c)
}
static void
-format_address_paren (off_t address, char c)
+format_address_paren (uintmax_t address, char c)
{
putchar ('(');
format_address_std (address, ')');
@@ -1160,7 +1164,7 @@ format_address_paren (off_t address, char c)
}
static void
-format_address_label (off_t address, char c)
+format_address_label (uintmax_t address, char c)
{
format_address_std (address, ' ');
format_address_paren (address + pseudo_offset, c);
@@ -1178,7 +1182,7 @@ format_address_label (off_t address, char c)
only when it has not been padded to length BYTES_PER_BLOCK. */
static void
-write_block (off_t current_offset, off_t n_bytes,
+write_block (uintmax_t current_offset, size_t n_bytes,
const char *prev_block, const char *curr_block)
{
static int first = 1;
@@ -1323,18 +1327,16 @@ get_lcm (void)
}
/* If S is a valid pre-POSIX offset specification with an optional leading '+'
- return the offset it denotes. Otherwise, return -1. */
+ return nonzero and set *OFFSET to the offset it denotes. */
-off_t
-parse_old_offset (const char *s)
+int
+parse_old_offset (const char *s, uintmax_t *offset)
{
int radix;
- off_t offset;
enum strtol_error s_err;
- uintmax_t tmp;
if (*s == '\0')
- return -1;
+ return 0;
/* Skip over any leading '+'. */
if (s[0] == '+')
@@ -1353,17 +1355,13 @@ parse_old_offset (const char *s)
radix = 8;
}
- s_err = xstrtoumax (s, NULL, radix, &tmp, "Bb");
+ s_err = xstrtoumax (s, NULL, radix, offset, "Bb");
if (s_err != LONGINT_OK)
{
STRTOL_FAIL_WARN (s, _("old-style offset"), s_err);
- return -1;
+ return 0;
}
- if (OFF_T_MAX < tmp)
- error (EXIT_FAILURE, 0,
- _("%s is larger than the maximum file size on this system"), s);
- offset = tmp;
- return offset;
+ return 1;
}
/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
@@ -1382,8 +1380,7 @@ static int
dump (void)
{
char *block[2];
- off_t current_offset;
- off_t end_offset IF_LINT (= 0);
+ uintmax_t current_offset;
int idx;
int err;
size_t n_bytes_read;
@@ -1397,8 +1394,6 @@ dump (void)
err = 0;
if (limit_bytes_to_format)
{
- end_offset = n_bytes_to_skip + max_bytes_to_format;
-
while (1)
{
size_t n_needed;
@@ -1408,7 +1403,7 @@ dump (void)
break;
}
n_needed = MIN (end_offset - current_offset,
- (off_t) bytes_per_block);
+ (uintmax_t) bytes_per_block);
err |= read_block (n_needed, block[idx], &n_bytes_read);
if (n_bytes_read < bytes_per_block)
break;
@@ -1471,7 +1466,7 @@ dump_strings (void)
{
size_t bufsize = MAX (100, string_min);
char *buf = xmalloc (bufsize);
- off_t address = n_bytes_to_skip;
+ uintmax_t address = n_bytes_to_skip;
int err;
err = 0;
@@ -1484,7 +1479,7 @@ dump_strings (void)
tryline:
if (limit_bytes_to_format
- && address >= (n_bytes_to_skip + max_bytes_to_format - string_min))
+ && (end_offset < string_min || end_offset - string_min <= address))
break;
for (i = 0; i < string_min; i++)
@@ -1504,8 +1499,7 @@ dump_strings (void)
/* 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 < n_bytes_to_skip + max_bytes_to_format)
+ while (!limit_bytes_to_format || address < end_offset)
{
if (i == bufsize)
{
@@ -1593,7 +1587,7 @@ main (int argc, char **argv)
/* The old-style `pseudo starting address' to be printed in parentheses
after any true address. */
- off_t pseudo_start IF_LINT (= 0);
+ uintmax_t pseudo_start IF_LINT (= 0);
program_name = argv[0];
setlocale (LC_ALL, "");
@@ -1677,8 +1671,7 @@ it must be one character from [doxn]"),
break;
case 'j':
- s_err = xstrtoumax (optarg, NULL, 0, &tmp, "bkm");
- n_bytes_to_skip = tmp;
+ 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;
@@ -1686,15 +1679,9 @@ it must be one character from [doxn]"),
case 'N':
limit_bytes_to_format = 1;
- s_err = xstrtoumax (optarg, NULL, 0, &tmp, "bkm");
- max_bytes_to_format = tmp;
+ s_err = xstrtoumax (optarg, NULL, 0, &max_bytes_to_format, "bkm");
if (s_err != LONGINT_OK)
STRTOL_FATAL_ERROR (optarg, _("limit argument"), s_err);
-
- if (OFF_T_MAX < tmp)
- error (EXIT_FAILURE, 0,
- _("%s is larger than the maximum file size on this system"),
- optarg);
break;
case 's':
@@ -1800,11 +1787,11 @@ it must be one character from [doxn]"),
if (traditional)
{
- off_t offset;
+ uintmax_t offset;
if (n_files == 1)
{
- if ((offset = parse_old_offset (argv[optind])) >= 0)
+ if (parse_old_offset (argv[optind], &offset))
{
n_bytes_to_skip = offset;
--n_files;
@@ -1813,9 +1800,9 @@ it must be one character from [doxn]"),
}
else if (n_files == 2)
{
- off_t o1, o2;
- if ((o1 = parse_old_offset (argv[optind])) >= 0
- && (o2 = parse_old_offset (argv[optind + 1])) >= 0)
+ uintmax_t o1, o2;
+ if (parse_old_offset (argv[optind], &o1)
+ && parse_old_offset (argv[optind + 1], &o2))
{
n_bytes_to_skip = o1;
flag_pseudo_start = 1;
@@ -1823,7 +1810,7 @@ it must be one character from [doxn]"),
argv += 2;
n_files -= 2;
}
- else if ((o2 = parse_old_offset (argv[optind + 1])) >= 0)
+ else if (parse_old_offset (argv[optind + 1], &o2))
{
n_bytes_to_skip = o2;
--n_files;
@@ -1840,9 +1827,9 @@ it must be one character from [doxn]"),
}
else if (n_files == 3)
{
- off_t o1, o2;
- if ((o1 = parse_old_offset (argv[optind + 1])) >= 0
- && (o2 = parse_old_offset (argv[optind + 2])) >= 0)
+ uintmax_t o1, o2;
+ if (parse_old_offset (argv[optind + 1], &o1)
+ && parse_old_offset (argv[optind + 2], &o2))
{
n_bytes_to_skip = o1;
flag_pseudo_start = 1;
@@ -1878,6 +1865,13 @@ it must be one character from [doxn]"),
}
}
+ 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");
+ }
+
if (n_specs == 0)
{
if (decode_one_format ("o2", "o2", NULL, &(spec[0])))