diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2017-02-23 08:58:39 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2017-02-23 09:15:06 -0800 |
commit | 23e64facf9f74133c6bacedeec56ad782ae69b65 (patch) | |
tree | 19822ecfb5af4b2f867dd02a2a29319ade9fcb13 | |
parent | 5114b3a2047a9bcdb72fddf35e70201c16eb39a3 (diff) | |
download | emacs-23e64facf9f74133c6bacedeec56ad782ae69b65.tar.gz |
hexl: handle large files and I/O errors
* lib-src/hexl.c: Include inttypes.h, for PRIxMAX etc.
Do not include ctype.h, as the code no longer uses isdigit.
(DEFAULT_GROUPING, un_flag, iso_flag, group_by): Now local to ‘main’.
(DEFAULT_BASE, endian): Remove; was not really used.
(usage): Remove; now done by ‘main’, as that’s simpler.
(progname): Now static.
(output_error, hexchar): New functions.
(main): Use them. Simplify. Remove "-oct", "-big-endian", and
"-little-endian" options, as they did not work and were not used.
Use SET_BINARY only on stdin, and fopen with "rb" otherwise.
Use SET_BINARY only once on stdout.
Do not assume file offsets fit in ‘long’.
If an I/O error occurs, report it and exit with nonzero status.
-rw-r--r-- | lib-src/hexl.c | 230 |
1 files changed, 95 insertions, 135 deletions
diff --git a/lib-src/hexl.c b/lib-src/hexl.c index 2eef7b3a63d..2c7e8c44161 100644 --- a/lib-src/hexl.c +++ b/lib-src/hexl.c @@ -21,241 +21,201 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> #include <binary-io.h> -#define DEFAULT_GROUPING 0x01 -#define DEFAULT_BASE 16 +static char *progname; -int base = DEFAULT_BASE; -bool un_flag = false, iso_flag = false, endian = true; -int group_by = DEFAULT_GROUPING; -char *progname; +static _Noreturn void +output_error (void) +{ + fprintf (stderr, "%s: write error\n", progname); + exit (EXIT_FAILURE); +} -_Noreturn void usage (void); +static int +hexchar (int c) +{ + return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10); +} int main (int argc, char **argv) { - register long address; - char string[18]; - FILE *fp; - - progname = *argv++; --argc; + int status = EXIT_SUCCESS; + int DEFAULT_GROUPING = 0x01; + int group_by = DEFAULT_GROUPING; + bool un_flag = false, iso_flag = false; + progname = *argv++; /* ** -hex hex dump - ** -oct Octal dump ** -group-by-8-bits ** -group-by-16-bits ** -group-by-32-bits ** -group-by-64-bits ** -iso iso character set. - ** -big-endian Big Endian - ** -little-endian Little Endian ** -un || -de from hexl format to binary. ** -- End switch list. ** <filename> dump filename ** - (as filename == stdin) */ - while (*argv && *argv[0] == '-' && (*argv)[1]) + for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++) { /* A switch! */ if (!strcmp (*argv, "--")) { - --argc; argv++; + argv++; break; } else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de")) { un_flag = true; - --argc; argv++; + SET_BINARY (fileno (stdout)); } else if (!strcmp (*argv, "-hex")) - { - base = 16; - --argc; argv++; - } + /* Hex is the default and is only base supported. */; else if (!strcmp (*argv, "-iso")) - { - iso_flag = true; - --argc; argv++; - } - else if (!strcmp (*argv, "-oct")) - { - base = 8; - --argc; argv++; - } - else if (!strcmp (*argv, "-big-endian")) - { - endian = true; - --argc; argv++; - } - else if (!strcmp (*argv, "-little-endian")) - { - endian = false; - --argc; argv++; - } + iso_flag = true; else if (!strcmp (*argv, "-group-by-8-bits")) - { - group_by = 0x00; - --argc; argv++; - } + group_by = 0x00; else if (!strcmp (*argv, "-group-by-16-bits")) - { - group_by = 0x01; - --argc; argv++; - } + group_by = 0x01; else if (!strcmp (*argv, "-group-by-32-bits")) - { - group_by = 0x03; - --argc; argv++; - } + group_by = 0x03; else if (!strcmp (*argv, "-group-by-64-bits")) - { - group_by = 0x07; - endian = false; - --argc; argv++; - } + group_by = 0x07; else { fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname, *argv); - usage (); + fprintf (stderr, "usage: %s [-de] [-iso]\n", progname); + return EXIT_FAILURE; } } + char const *filename = *argv ? *argv++ : "-"; + do { - if (*argv == NULL) - fp = stdin; + FILE *fp; + + if (!strcmp (filename, "-")) + { + fp = stdin; + if (!un_flag) + SET_BINARY (fileno (stdin)); + } else { - char *filename = *argv++; - - if (!strcmp (filename, "-")) - fp = stdin; - else if ((fp = fopen (filename, "r")) == NULL) + fp = fopen (filename, un_flag ? "r" : "rb"); + if (!fp) { perror (filename); + status = EXIT_FAILURE; continue; } } if (un_flag) { - SET_BINARY (fileno (stdout)); - - for (;;) + for (int c; 0 <= (c = getc (fp)); ) { - int i, c = 0, d; - char buf[18]; - -#define hexchar(x) (isdigit (x) ? x - '0' : x - 'a' + 10) - - /* Skip 10 bytes. */ - if (fread (buf, 1, 10, fp) != 10) - break; + /* Skip address at start of line. */ + if (c != ' ') + continue; - for (i=0; i < 16; ++i) + for (int i = 0; i < 16; i++) { - if ((c = getc (fp)) == ' ' || c == EOF) + c = getc (fp); + if (c < 0 || c == ' ') break; - d = getc (fp); - c = hexchar (c) * 0x10 + hexchar (d); - putchar (c); - - if ((i&group_by) == group_by) - getc (fp); - } - - if (c == ' ') - { - while ((c = getc (fp)) != '\n' && c != EOF) - ; - - if (c == EOF) - break; - } - else - { - if (i < 16) + int hc = hexchar (c); + c = getc (fp); + if (c < 0) break; + putchar (hc * 0x10 + hexchar (c)); - /* Skip 18 bytes. */ - if (fread (buf, 1, 18, fp) != 18) - break; + if ((i & group_by) == group_by) + { + c = getc (fp); + if (c < 0) + break; + } } + + while (0 <= c && c != '\n') + c = getc (fp); + if (c < 0) + break; + if (ferror (stdout)) + output_error (); } } else { - SET_BINARY (fileno (fp)); - address = 0; + int c = 0; + char string[18]; string[0] = ' '; string[17] = '\0'; - for (;;) + for (uintmax_t address = 0; 0 <= c; address += 0x10) { - register int i, c = 0; - - for (i=0; i < 16; ++i) + int i; + for (i = 0; i < 16; i++) { - if ((c = getc (fp)) == EOF) + if (0 <= c) + c = getc (fp); + if (c < 0) { if (!i) break; fputs (" ", stdout); - string[i+1] = '\0'; + string[i + 1] = '\0'; } else { if (!i) - printf ("%08lx: ", address + 0ul); + printf ("%08"PRIxMAX": ", address); - if (iso_flag) - string[i+1] = - (c < 0x20 || (c >= 0x7F && c < 0xa0)) ? '.' :c; - else - string[i+1] = (c < 0x20 || c >= 0x7F) ? '.' : c; + string[i + 1] + = (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0)) + ? '.' : c); printf ("%02x", c + 0u); } - if ((i&group_by) == group_by) + if ((i & group_by) == group_by) putchar (' '); } if (i) puts (string); - if (c == EOF) - break; - - address += 0x10; - + if (ferror (stdout)) + output_error (); } } - if (fp != stdin) - fclose (fp); + bool trouble = ferror (fp) != 0; + trouble |= fp != stdin && fclose (fp) != 0; + if (trouble) + { + fprintf (stderr, "%s: read error\n", progname); + status = EXIT_FAILURE; + } - } while (*argv != NULL); - return EXIT_SUCCESS; -} + filename = *argv++; + } + while (filename); -void -usage (void) -{ - fprintf (stderr, "usage: %s [-de] [-iso]\n", progname); - exit (EXIT_FAILURE); + if (ferror (stdout) || fclose (stdout) != 0) + output_error (); + return status; } - - -/* hexl.c ends here */ |