summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2017-02-23 08:58:39 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2017-02-23 09:15:06 -0800
commit23e64facf9f74133c6bacedeec56ad782ae69b65 (patch)
tree19822ecfb5af4b2f867dd02a2a29319ade9fcb13
parent5114b3a2047a9bcdb72fddf35e70201c16eb39a3 (diff)
downloademacs-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.c230
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 */