Skip to content

Instantly share code, notes, and snippets.

@maxrt101
Last active March 17, 2022 23:30
Show Gist options
  • Save maxrt101/8bb4760651453e66fa08c8ea71f494e4 to your computer and use it in GitHub Desktop.
Save maxrt101/8bb4760651453e66fa08c8ea71f494e4 to your computer and use it in GitHub Desktop.
Hexdump
/* hexdump.c by maxrt101 */
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#define VERSION "0.50"
#define FORMAT_HEX_UPPER "%02X"
#define FORMAT_HEX_LOWER "%02x"
enum mode {
MODE_DEFAULT,
MODE_BINARY,
MODE_PLAIN,
MODE_CARRAY
};
typedef struct {
FILE* fp;
char* data;
size_t size;
size_t count;
size_t start;
size_t end;
char* fmt;
int cols;
} state;
void die(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
exit(EXIT_FAILURE);
}
void state_init(state* s, const char* filename) {
if (!s) {
die("Error: filename is null");
}
s->fp = fopen(filename, "rb");
if (!s->fp) {
if (errno == 2) {
die("Error: no such file or directory");
} else {
die("Error: failed to open a file(errno=%d)", errno);
}
}
fseek(s->fp, 0, SEEK_END);
s->size = ftell(s->fp);
rewind(s->fp);
if (s->size <= 0) {
die("Error: file size <= 0");
}
s->data = (char*)malloc(s->size);
if (!s->data) {
die("Error: malloc failed (errno=%d)", errno);
}
if (fread(s->data, 1, s->size, s->fp) != s->size) {
free(s->data);
die("Error: couldn't read file (errno=%d)", errno);
}
s->count = 0;
s->cols = 16;
}
void state_cleanup(state* s) {
fclose(s->fp);
free(s->data);
}
void mode_default(state* s) {
int can_print = 1;
char* buf = (char*)malloc(s->cols);
while (can_print) {
memset(buf, '.', s->cols);
printf("%06zx |", s->count);
for (int i = 0; i < s->cols; i++) {
printf("%s", (i % (s->cols/2) == 0) ? " " : " ");
if (s->count < s->end) {
printf(s->fmt, (unsigned char)s->data[s->count]);
buf[s->count % s->cols] = s->data[s->count++];
} else {
printf(" ");
can_print = 0;
}
}
printf(" | ");
for (int i = 0; i < s->cols; i++) {
printf("%c", isprint(buf[i]) ? buf[i] : '.');
}
printf("\n");
}
free(buf);
}
void mode_plain(state* s) {
while (s->count < s->end) {
printf(s->fmt, (unsigned char)s->data[s->count++]);
if (s->count % s->cols == 0) {
printf("\n");
}
}
printf("\n");
}
void mode_binary(state* s) {
int can_print = 1;
char* buf = (char*)malloc(s->cols);
while (can_print) {
memset(buf, '.', s->cols);
printf("%06zx |", s->count);
for (int i = 0; i < s->cols; i++) {
printf(" ");
if (s->count < s->end) {
unsigned char b = s->data[s->count];
for (int i = 0; i < 8; i++) {
printf("%d", ((b >> i) & 0x1) ? 1 : 0);
}
buf[s->count % s->cols] = s->data[s->count++];
} else {
printf(" ");
can_print = 0;
}
}
printf(" | ");
for (int i = 0; i < s->cols; i++) {
if (isprint(buf[i])) {
printf("%c", buf[i]);
} else {
printf(".");
}
}
printf("\n");
}
free(buf);
}
void mode_carray(state* s) {
puts("unsigned char hex[] = {\n ");
while (s->count < s->end) {
printf("0x");
printf(s->fmt, (unsigned char)s->data[s->count]);
printf(", ");
s->count++;
if (s->count % 10 == 0) {
printf("\n ");
}
}
printf("\n};\n");
}
void set_cols(state* s, int cols, int default_cols) {
s->cols = cols ? cols : default_cols;
}
void usage(const char* prog_name) {
printf("Usage: %s FILE [OPTIONS]\n"
"Options:\n"
" -h Prints this message.\n"
" -v Print version string.\n"
" -b Binary mode.\n"
" -C C array mode.\n"
" -p Plain mode\n"
" -c cols Sets columns\n"
" -s off Offset from the beginning of the file.\n"
" -l len Length to read.\n"
" -U Uppercase hex formatting.\n"
" -L Lowercase hex formatting.\n", prog_name);
}
int main(int argc, char ** argv) {
char* filename = NULL;
char* fmt = FORMAT_HEX_UPPER;
enum mode mode = MODE_DEFAULT;
int start = 0, end = 0, cols = 0;
for (int i = 1; i < argc; i++) {
if (!strcmp("-h", argv[i])) {
usage(argv[0]);
return 0;
} else if (!strcmp("-v", argv[i])) {
printf("hexdump v%s by maxrt101\n", VERSION);
return 0;
} else if (!strcmp("-b", argv[i])) {
mode = MODE_BINARY;
} else if (!strcmp("-C", argv[i])) {
mode = MODE_CARRAY;
} else if (!strcmp("-p", argv[i])) {
mode = MODE_PLAIN;
} else if (!strcmp("-c", argv[i])) {
if (i+1 < argc) {
cols = atoi(argv[++i]);
} else {
usage(argv[0]);
}
} else if (!strcmp("-s", argv[i])) {
if (i+1 < argc) {
start = atoi(argv[++i]);
} else {
usage(argv[0]);
return 0;
}
} else if (!strcmp("-l", argv[i])) {
if (i+1 < argc) {
end = atoi(argv[++i]);
} else {
usage(argv[0]);
return 0;
}
} else if (!strcmp("-U", argv[i])) {
fmt = FORMAT_HEX_UPPER;
} else if (!strcmp("-L", argv[i])) {
fmt = FORMAT_HEX_LOWER;
} else {
filename = argv[i];
}
}
if (!filename) {
usage(argv[0]);
return 0;
}
state s;
state_init(&s, filename);
s.start = start;
s.end = end ? end : s.size;
s.fmt = fmt;
s.count = s.start;
switch (mode) {
case MODE_DEFAULT:
set_cols(&s, cols, 16);
mode_default(&s);
break;
case MODE_BINARY:
set_cols(&s, cols, 6);
mode_binary(&s);
break;
case MODE_CARRAY:
set_cols(&s, cols, 10);
mode_carray(&s);
break;
case MODE_PLAIN:
set_cols(&s, cols, 30);
mode_plain(&s);
break;
default:
printf("Unknown operation mode\n");
}
state_cleanup(&s);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment