246 lines
4.9 KiB
C
246 lines
4.9 KiB
C
#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;
|
|
}
|