diff options
Diffstat (limited to 'com32/modules/hexdump.c')
-rw-r--r-- | com32/modules/hexdump.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/com32/modules/hexdump.c b/com32/modules/hexdump.c new file mode 100644 index 0000000..bc2c70d --- /dev/null +++ b/com32/modules/hexdump.c @@ -0,0 +1,245 @@ +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <console.h> +#include <errno.h> +#include <syslinux/loadfile.h> + +/* Macros */ +#define ROWS_PER_PAGE 24 +#define COLS_PER_ROW 16 +#define BYTES_PER_PAGE (ROWS_PER_PAGE * COLS_PER_ROW) + +/* Functions declarations */ +static int usage(void); +static void eat_stdin(void); +static int do_page(void); +static void hexdump(const void *memory, size_t bytes); + +/* Objects */ +static const char *prog_name; +static int opt_page; +static int opt_no_buffer; +static int opt_extended_ascii; + +int main(int argc, char **argv) +{ + int rc; + const char *filename; + int i; + void *file_data; + size_t file_sz; + FILE *f; + size_t len; + const char *cur_pos; + + /* Assume failure */ + rc = EXIT_FAILURE; + + /* Determine the program name, as invoked */ + if (argc < 1 || !argv || !argv[0]) { + fprintf(stderr, "argc or argv failure!\n"); + goto err_prog_name; + } + prog_name = argv[0]; + + /* Process arguments */ + filename = NULL; + for (i = 1; i < argc; ++i) { + if (!argv[i]) { + fprintf(stderr, "argc and argv mismatch!\n"); + goto err_argv; + } + + if (!strncmp(argv[i], "--page", sizeof "--page") || + !strncmp(argv[i], "-p", sizeof "-p")) { + opt_page = 1; + continue; + } + + if (!strncmp(argv[i], "--no-buffer", sizeof "--no-buffer")) { + opt_no_buffer = 1; + continue; + } + + if (!strncmp(argv[i], "--extended-ascii", sizeof "--extended-ascii")) { + opt_extended_ascii = 1; + continue; + } + + if (!strncmp(argv[i], "--help", sizeof "--help") || + !strncmp(argv[i], "-h", sizeof "-h") || + !strncmp(argv[i], "-?", sizeof "-?")) + return usage(); + + /* Otherwise, interpret as a filename, but only accept one */ + if (filename) + return usage(); + filename = argv[i]; + } + if (!filename) + return usage(); + fprintf(stdout, "Dumping file: %s\n", filename); + + /* Either fetch the whole file, or just allocate a buffer */ + f = NULL; + if (opt_no_buffer) { + errno = 0; + if (loadfile(filename, &file_data, &file_sz)) { + fprintf(stderr, "Couldn't load file. Error: %d\n", errno); + goto err_file_data; + } + } else { + file_sz = BYTES_PER_PAGE; + file_data = malloc(file_sz); + if (!file_data) { + fprintf(stderr, "Couldn't allocate file data buffer\n"); + goto err_file_data; + } + errno = 0; + f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "Couldn't open file. Error: %d\n", errno); + goto err_f; + } + } + + /* Dump the data */ + len = BYTES_PER_PAGE; + cur_pos = file_data; + do { + if (f) { + /* Buffered */ + len = fread(file_data, 1, file_sz, f); + cur_pos = file_data; + } else { + /* Non-buffered */ + if (file_sz < len) + len = file_sz; + } + if (!len) + break; + + hexdump(cur_pos, len); + + /* Pause, if requested */ + if (opt_page) { + /* The user might choose to quit */ + if (do_page()) + break; + } + + /* Reduce file_sz for non-buffered mode */ + if (!f) + file_sz -= len; + } while (cur_pos += len); + + rc = EXIT_SUCCESS; + + if (f) + fclose(f); + err_f: + + free(file_data); + err_file_data: + + err_argv: + + err_prog_name: + + return rc; +} + +static int usage(void) +{ + static const char usage[] = + "Usage: %s [<option> [...]] <filename> [<option> [...]]\n" + "\n" + "Options: -p\n" + " --page . . . . . . . Pause output every 24 lines\n" + " --no-buffer . . . . Load the entire file before dumping\n" + " --extended-ascii . . Use extended ASCII chars in dump\n" + " -?\n" + " -h\n" + " --help . . . . . . Display this help\n"; + + fprintf(stderr, usage, prog_name); + return EXIT_FAILURE; +} + +static void eat_stdin(void) +{ + int i; + + while (1) { + i = fgetc(stdin); + if (i == EOF || i == '\n') + return; + } +} +static int do_page(void) +{ + int i; + + while (1) { + fprintf(stdout, "Continue? [Y|n]: "); + i = fgetc(stdin); + switch (i) { + case 'n': + case 'N': + eat_stdin(); + return 1; + + case EOF: + fprintf(stderr, "No response. Continuing...\n"); + /* Fall through to "yes" */ + + case 'y': + case 'Y': + eat_stdin(); + case '\n': + return 0; + + default: + fprintf(stderr, "Invalid choice\n"); + eat_stdin(); + } + } +} + +static void hexdump(const void *memory, size_t bytes) +{ + const unsigned char *p, *q; + int i; + + p = memory; + while (bytes) { + q = p; + printf("%p: ", (void *) p); + for (i = 0; i < 16 && bytes; ++i) { + printf("%02X ", *p); + ++p; + --bytes; + } + bytes += i; + while (i < 16) { + printf("XX "); + ++i; + } + printf("| "); + p = q; + for (i = 0; i < 16 && bytes; ++i) { + printf("%c", isprint(*p) && !isspace(*p) ? *p : ' '); + ++p; + --bytes; + } + while (i < 16) { + printf(" "); + ++i; + } + printf("\n"); + } + return; +} |