diff options
author | Jim Meyering <jim@meyering.net> | 1993-03-23 05:27:39 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1993-03-23 05:27:39 +0000 |
commit | 38456f092f5a5200a20d234c671f72f0a909a5d3 (patch) | |
tree | f3b63915e018c8ec9beead781598456bea28f193 /src/od.c | |
parent | 4f0f13ad001be68c381caae8efb9d72b3dc89ef1 (diff) | |
download | coreutils-38456f092f5a5200a20d234c671f72f0a909a5d3.tar.xz |
New option: -C, --compatible.
A few new small functions.
Diffstat (limited to 'src/od.c')
-rw-r--r-- | src/od.c | 235 |
1 files changed, 219 insertions, 16 deletions
@@ -188,12 +188,31 @@ static const char *output_address_fmt_string; /* FIXME: make this the number of octal digits in an unsigned long. */ #define MAX_ADDRESS_LENGTH 13 -static char address_fmt_buffer[MAX_ADDRESS_LENGTH + 1]; + +/* Space for a normal address, a space, a pseudo address, parentheses + around the pseudo address, and a trailing zero byte. */ +static char address_fmt_buffer[2 * MAX_ADDRESS_LENGTH + 4]; static char address_pad[MAX_ADDRESS_LENGTH + 1]; static unsigned long int string_min; static unsigned long int flag_dump_strings; +/* Non-zero if we should recognize the pre-POSIX non-option arguments + that specified at most one file and optional arguments specifying + offset and pseudo-start address. */ +static int flag_compatibility; + +/* Non-zero if an old-style `pseudo-address' was specified. */ +static long int flag_pseudo_start; + +/* The difference between the old-style pseudo starting address and + the number of bytes to skip. */ +static long int pseudo_offset; + +/* Function to format an address and optionally an additional parenthesized + pseudo-address; it returns the formatted string. */ +static const char *(*format_address) (/* long unsigned int */); + /* The number of input bytes to skip before formatting and writing. */ static unsigned long int n_bytes_to_skip = 0; @@ -258,6 +277,7 @@ static struct option const long_options[] = {"output-duplicates", no_argument, NULL, 'v'}, /* non-POSIX options. */ + {"compatible", no_argument, NULL, 'C'}, {"strings", optional_argument, NULL, 's'}, {"width", optional_argument, NULL, 'w'}, {NULL, 0, NULL, 0} @@ -342,25 +362,25 @@ my_strtoul (s, base, val, allow_bkm_suffix) case '\0': break; -#define BKM_SCALE(x,scale_factor) \ +#define BKM_SCALE(x,scale_factor,error_return) \ do \ { \ if (x > (double) ULONG_MAX / scale_factor) \ - return UINT_OVERFLOW; \ + return error_return; \ x *= scale_factor; \ } \ while (0) case 'b': - BKM_SCALE (tmp, 512); + BKM_SCALE (tmp, 512, UINT_OVERFLOW); break; case 'k': - BKM_SCALE (tmp, 1024); + BKM_SCALE (tmp, 1024, UINT_OVERFLOW); break; case 'm': - BKM_SCALE (tmp, 1024 * 1024); + BKM_SCALE (tmp, 1024 * 1024, UINT_OVERFLOW); break; default: @@ -1047,18 +1067,33 @@ skip (n_skip) } static const char * -format_address (address) +format_address_none (address) + long unsigned int address; +{ + return ""; +} + +static const char * +format_address_std (address) long unsigned int address; { const char *address_string; - if (output_address_fmt_string == NULL) - address_string = ""; - else - { - sprintf (address_fmt_buffer, output_address_fmt_string, address); - address_string = address_fmt_buffer; - } + sprintf (address_fmt_buffer, output_address_fmt_string, address); + address_string = address_fmt_buffer; + return address_string; +} + +static const char * +format_address_label (address) + long unsigned int address; +{ + const char *address_string; + assert (output_address_fmt_string != NULL); + + sprintf (address_fmt_buffer, output_address_fmt_string, + address, address + pseudo_offset); + address_string = address_fmt_buffer; return address_string; } @@ -1300,6 +1335,63 @@ get_lcm () return l_c_m; } +/* If S is a valid pre-POSIX offset specification with an optional leading '+' + return the offset it denotes. Otherwise, return -1. */ + +long int +parse_old_offset (const char *s) +{ + int radix; + char *suffix; + long offset; + + if (*s == '\0') + return -1; + + /* Skip over any leading '+'. */ + 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', it's + hexadecimal, else octal. */ + if (index (s, '.') != NULL) + radix = 10; + else + { + if (strlen (s) >= 2 && s[0] == '0' && s[1] == 'x') + radix = 16; + else + radix = 8; + } + offset = strtoul (s, &suffix, radix); + if (suffix == s || errno != 0) + return -1; + if (*suffix == '.') + ++suffix; + switch (*suffix) + { + case 'b': + BKM_SCALE (offset, 512, -1); + ++suffix; + break; + + case 'B': + BKM_SCALE (offset, 1024, -1); + ++suffix; + break; + + default: + /* empty */ + break; + } + + if (*suffix != '\0') + return -1; + else + return offset; +} + /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the formatted block to standard output, and repeat until the specified maximum number of bytes has been read or until all input has been @@ -1525,6 +1617,10 @@ main (argc, argv) int width_specified = 0; int err; + /* The old-style `pseudo starting address' to be printed in parentheses + after any true address. */ + long int pseudo_start; + program_name = argv[0]; err = 0; @@ -1551,10 +1647,11 @@ main (argc, argv) spec = (struct tspec *) xmalloc (n_specs_allocated * sizeof (struct tspec)); output_address_fmt_string = "%07o"; + format_address = format_address_std; address_pad_len = 7; flag_dump_strings = 0; - while ((c = getopt_long (argc, argv, "abcdfhilos::xw::A:j:N:t:v", + while ((c = getopt_long (argc, argv, "abcCdfhilos::xw::A:j:N:t:v", long_options, (int *) 0)) != EOF) { @@ -1567,18 +1664,22 @@ main (argc, argv) { case 'd': output_address_fmt_string = "%07d"; + format_address = format_address_std; address_pad_len = 7; break; case 'o': output_address_fmt_string = "%07o"; + format_address = format_address_std; address_pad_len = 7; break; case 'x': output_address_fmt_string = "%06x"; + format_address = format_address_std; address_pad_len = 6; break; case 'n': output_address_fmt_string = NULL; + format_address = format_address_none; address_pad_len = 0; break; default: @@ -1624,6 +1725,10 @@ main (argc, argv) abbreviate_duplicate_blocks = 0; break; + case 'C': + flag_compatibility = 1; + break; + /* The next several cases map the old, pre-POSIX format specification options to the corresponding POSIX format specs. GNU od accepts any combination of old- and @@ -1674,6 +1779,103 @@ main (argc, argv) if (flag_dump_strings && n_specs > 0) error (2, 0, "no type may be specified when dumping strings"); + n_files = argc - optind; + + /* If the --compatible option was used, there may be from 0 to 3 + remaining command line arguments: + [file] [offset [pseudo_start]] + The offset and pseudo_start have the same syntax + FIXME: elaborate */ + + if (flag_compatibility) + { + long int offset; + int usage_error = 0; + + if (n_files == 1) + { + if ((offset = parse_old_offset (argv[optind])) >= 0) + { + n_bytes_to_skip = offset; + --n_files; + ++argv; + } + } + else if (n_files == 2) + { + long int o1, o2; + if ((o1 = parse_old_offset (argv[optind])) >= 0 + && (o2 = parse_old_offset (argv[optind + 1])) >= 0) + { + n_bytes_to_skip = o1; + flag_pseudo_start = 1; + pseudo_start = o2; + argv += 2; + n_files -= 2; + } + else if ((o2 = parse_old_offset (argv[optind + 1])) >= 0) + { + n_bytes_to_skip = o2; + --n_files; + argv[optind + 1] = argv[optind]; + ++argv; + } + else + { + usage_error = 1; + error (0, 0, + "invalid second operand in compatibility mode `%s'", + argv[optind + 1]); + usage (); + } + } + else if (n_files == 3) + { + long int o1, o2; + if ((o1 = parse_old_offset (argv[optind + 1])) >= 0 + && (o2 = parse_old_offset (argv[optind + 2])) >= 0) + { + n_bytes_to_skip = o1; + flag_pseudo_start = 1; + pseudo_start = o2; + argv[optind + 2] = argv[optind]; + argv += 2; + n_files -= 2; + } + else + { + error (0, 0, + "in compatibility mode the last 2 arguments must be offsets"); + usage (); + } + } + else + { + error (0, 0, + "in compatibility mode there may be no more than 3 arguments"); + usage (); + } + + if (flag_pseudo_start) + { + static char buf[10]; + + if (output_address_fmt_string == NULL) + { + output_address_fmt_string = "(%07o)"; + format_address = format_address_std; + } + else + { + sprintf (buf, "%s (%s)", + output_address_fmt_string, + output_address_fmt_string); + output_address_fmt_string = buf; + format_address = format_address_label; + } + } + } + assert (address_pad_len <= MAX_ADDRESS_LENGTH); for (i = 0; i < address_pad_len; i++) address_pad[i] = ' '; @@ -1687,7 +1889,6 @@ main (argc, argv) n_specs = 1; } - n_files = argc - optind; if (n_files > 0) file_list = (char const *const *) &argv[optind]; else @@ -1702,6 +1903,8 @@ main (argc, argv) err |= skip (n_bytes_to_skip); + pseudo_offset = (flag_pseudo_start ? pseudo_start - n_bytes_to_skip : 0); + /* Compute output block length. */ l_c_m = get_lcm (); |