Skip to content

Commit

Permalink
Update.
Browse files Browse the repository at this point in the history
  • Loading branch information
arthur-manske committed Apr 9, 2024
1 parent 25badbb commit 54d33ae
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 62 deletions.
2 changes: 1 addition & 1 deletion makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.POSIX:

CC := c99
CFLAGS := -O0 -s -D_POSIX_C_SOURCE=200809L
CFLAGS := -O0 -D_POSIX_C_SOURCE=200809L -s

SRC = src
OBJ = obj
Expand Down
11 changes: 7 additions & 4 deletions man/xd.1
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
xd \- Display a hexdump table of files

.SH SYNOPSIS
xd [\fI-D\fR|\fI-O\fR][\fI-L text\fR][\fI-K text\fR][\fI-R when\fR][\fI-bd\fR][\fI-c cols\fR][\fI-g size\fR][\fI-o file\fR][\fI-pu\fR] [\fIfile...\fR]
xd [\fI-D\fR|\fI-O\fR][\fI-L text\fR][\fI-K text\fR][\fI-R when\fR][\fI-b|-o\fR][\fI-d\fR][\fI-c cols\fR][\fI-g size\fR][\fI-p\fR][\fI-t type\fR][\fIu\fR] [\fIfile...\fR]
.br
xd \fI-i\fR [\fI-c cols\fR][\fI-n name\fR][\fI-o file\fR][\fI-u\fR] [\fIfile...\fR]
xd \fI-i\fR [\fI-c cols\fR][\fI-n name\fR][\fI-u\fR] [\fIfile...\fR]
.br
xd \fI-?\fR

Expand Down Expand Up @@ -52,12 +52,15 @@ Outputs C headers (changes the default columns size to twelve and ignores group
.B \-n name
Specify a variable name to be used with \fI-i\fR option.
.TP
.B \-o file
Specify a output file to be used instead of standard output.
.B \-o
Use octal count.
.TP
.B \-p
Displays in plain dump format (change the default columns to thirty, changes the default group size to zero, disables file offsets, disables the colorizing and disables the exibition of the file contents ASCII representation).
.TP
.B \-t type
Dumps in the specified base. Type may be: h or x (hexadecimal), o (octal), d (decimal) and b (binary).
.TP
.B \-u
Use upper case hexadecimal letters.

Expand Down
142 changes: 85 additions & 57 deletions src/xd.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,45 @@
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>

#define __XD_USAGE__ \
"Usage: %s [-D|-O][-L text][-K text][-R when][-bd][-c cols][-g size][-o file][-pu] [file...]\n" \
" %s -i [-c columns][-n name][-o file][-u] [file...]\n" \
" %s -?\n" \
"Displays a hexdump of the specified file(s) or standard input.\n" \
"This utility is not a part of POSIX® specification.\n" \
"Special options:\n" \
"\t-?: Displays this message and then exits.\n" \
"General options:\n" \
"\t-D: Disables the printing of offsets.\n" \
"\t-L text: Specifies the dump separator. A space is added before it.\n" \
"\t-K text: Specifies the offset separator.\n" \
"\t-O: Enables the printing of offsets (default).\n" \
"\t-R when: Specifies when to color output. When may be: never, always or auto.\n" \
"\t-b: Performs a binary dump (implies -c6 and -g1).\n" \
"\t-c cols: Specifies how many columns to use on dump (defaults to 16).\n" \
"\t-d: Counts the offset in decimal, not hexadecimal.\n" \
"\t-g size: Specifies a group size for the dumped bytes (defaults to 2).\n" \
"\t-i: Outputs C headers (implies -c12).\n" \
"\t-n name: Specifies a name for the variable with the option -i.\n" \
"\t-o file: Specifies a output file instead of standard output.\n" \
"\t-p: Displays in plain dump format (implies -D, -c30 and -g0).\n" \
"\t-u: Use upper case hex letters.\n" \
"Manual entry shall be avaliable with: `man 1 xd`.\n" \
#define __XD_USAGE__ \
"Usage: %s [-D|-O][-L text][-K text][-R when][-b][-d|-o][-c cols][-g size][-p][-t type][-u] [file...]\n" \
" %s -i [-b][-c columns][-n name][-u] [file...]\n" \
" %s -?\n" \
"Displays a hexdump of the specified file(s) or standard input.\n" \
"This utility is not a part of POSIX® specification.\n" \
"Special options:\n" \
"\t-?: Displays this message and then exits.\n" \
"General options:\n" \
"\t-D: Disables the printing of offsets.\n" \
"\t-L text: Specifies the dump separator. A space is added before it.\n" \
"\t-K text: Specifies the offset separator.\n" \
"\t-O: Enables the printing of offsets (default).\n" \
"\t-R when: Specifies when to color output. When may be: never, always or auto.\n" \
"\t-b: Performs a binary dump (implies -c6 and -g1).\n" \
"\t-c cols: Specifies how many columns to use on dump (defaults to 16).\n" \
"\t-d: Counts the offset in decimal, not hexadecimal.\n" \
"\t-g size: Specifies a group size for the dumped bytes (defaults to 2).\n" \
"\t-i: Outputs C headers (implies -c12).\n" \
"\t-n name: Specifies a name for the variable with the option -i.\n" \
"\t-o: Counts the offset in octal, not in hexadecimal.\n" \
"\t-p: Displays in plain dump format (implies -D, -c30 and -g0).\n" \
"\t-t type: Performs a dump of specified type: b(binary), x or h (hexadecimal), d(decimal) or o(octal).\n" \
"\t-u: Use upper case hex letters.\n" \
"Manual entry shall be avaliable with: `man 1 xd`.\n" \
"Copyright (©) @Arthur de Souza Manske, 2024. All rights reserved.\n"

#define HEXDFL_FORCE_COLUMNS (0x01)
#define HEXDFL_FORCE_WORDSIZE (0x02)
#define HEXDFL_COLORED (0x04)
#define HEXDFL_PLAIN (0x08)
#define HEXDFL_BINDUMP (0x10)
#define HEXDFL_DECCOUNT (0x20)
#define HEXDFL_BINARY_DUMP (0x10)
#define HEXDFL_DECIMAL_COUNT (0x20)
#define HEXDFL_C (0x40)
#define HEXDFL_UPPER (0x80)
#define HEXDFL_NOCOLOR (0x100)
Expand All @@ -50,6 +52,10 @@
#define HEXDFL_MASK_COLOR (HEXDFL_COLORED | HEXDFL_NOCOLOR)
#define HEXPFL_BYTE (0x800)

#define HEXDFL_OCTAL_COUNT (0x1000)
#define HEXDFL_OCTAL_DUMP (0x2000)
#define HEXDFL_DECIMAL_DUMP (0x4000)

struct hexdumping {
uint16_t hex_flags;
int hex_columns, hex_wordsize;
Expand All @@ -73,14 +79,16 @@ int hexprint(FILE *stream, unsigned char ch, uint16_t flags)
}
}

if (flags & HEXPFL_BYTE && flags & HEXDFL_BINDUMP) {
if (flags & HEXPFL_BYTE && flags & HEXDFL_BINARY_DUMP) {
for (int8_t i = 7; i >= 0; --i, ++ret)
fputc(ch & (1 << i) ? '1' : '0', stream);

return ret;
}

if (flags & HEXDFL_UPPER) format[5] = 'X';
if (flags & HEXDFL_UPPER) format = "%02hhX";
if (flags & HEXDFL_DECIMAL_DUMP) format = "%03hhu";
if (flags & HEXDFL_OCTAL_DUMP) format = "%03hho";

if (!(flags & HEXPFL_BYTE)) {
if (ch < 32 || ch > 127) ch = '.';
Expand Down Expand Up @@ -113,18 +121,17 @@ int chexdump(FILE *restrict stream, int source, unsigned char *restrict buf, siz

while ((readbytes = read(source, buf, bufsiz)) > 0) {
for (i = 0; i < readbytes; ++i, ++totalbytes) {
char *format = "0x%02hhx";
if (hexfl->hex_flags & HEXDFL_UPPER) format = "0x%02hhX";

if (totalbytes != 0 && (totalbytes % hexfl->hex_columns) == 0) {
fputc('\n', stream);
if (hexfl->hex_filename) fputc('\t', stream);
} else if (totalbytes != 0) {
fputs(", ", stream);
}

if (hexfl->hex_flags & HEXDFL_UPPER) {
fprintf(stream, "0x%02hhX", buf[i]);
} else {
fprintf(stream, "0x%02hhx", buf[i]);
}

fprintf(stream, format, buf[i]);
}
}

Expand All @@ -145,12 +152,15 @@ int hexdump(FILE *restrict stream, int source, unsigned char *restrict buf, size
int dumplen = 0, digits = 2;
int used_digits = 0, used_spaces = 0;

if (hexfl->hex_flags & HEXDFL_BINDUMP) digits = 8;
off_t initial_offset = 0;

if (hexfl->hex_flags & HEXDFL_BINARY_DUMP) digits = 8;
if (hexfl->hex_flags & HEXDFL_DECIMAL_DUMP || hexfl->hex_flags & HEXDFL_OCTAL_DUMP) digits = 3;

if (!(hexfl->hex_flags & HEXDFL_FORCE_COLUMNS)) {
if (hexfl->hex_flags & HEXDFL_C) {
hexfl->hex_columns = 12;
} else if (hexfl->hex_flags & HEXDFL_BINDUMP) {
} else if (hexfl->hex_flags & HEXDFL_BINARY_DUMP) {
hexfl->hex_columns = 6;
} else if (hexfl->hex_flags & HEXDFL_PLAIN) {
hexfl->hex_columns = 30;
Expand All @@ -163,7 +173,7 @@ int hexdump(FILE *restrict stream, int source, unsigned char *restrict buf, size
if (!(hexfl->hex_flags & HEXDFL_FORCE_WORDSIZE)) {
if (hexfl->hex_flags & HEXDFL_PLAIN) {
hexfl->hex_wordsize = INT_MAX;
} else if (hexfl->hex_flags & HEXDFL_BINDUMP) {
} else if (hexfl->hex_flags & HEXDFL_BINARY_DUMP) {
hexfl->hex_wordsize = 1;
} else {
hexfl->hex_wordsize = 2;
Expand All @@ -179,11 +189,13 @@ int hexdump(FILE *restrict stream, int source, unsigned char *restrict buf, size
while (i < readbytes) {
k = used_digits = used_spaces = 0;
if (!(hexfl->hex_flags & HEXDFL_NOCOUNT)) {
char *format = "%010zx%s";
if (hexfl->hex_flags & HEXDFL_DECCOUNT) {
format[4] = 'd'; /* format specifier type to decimal */
static char *format = "%010zx%s";
if (hexfl->hex_flags & HEXDFL_DECIMAL_COUNT) {
format = "%010zd%s";
} else if (hexfl->hex_flags & HEXDFL_OCTAL_COUNT) {
format = "%010zo%s";
} else if (hexfl->hex_flags & HEXDFL_UPPER) {
format[4] = 'X'; /* format specifier type to upper hexadecimal */
format = "%010zX%s";
}

fprintf(stream, format, totalbytes, hexfl->hex_off_separator);
Expand All @@ -195,18 +207,20 @@ int hexdump(FILE *restrict stream, int source, unsigned char *restrict buf, size
fputc(' ', stream);
}

for (ssize_t j = 0; j < hexfl->hex_wordsize && k < hexfl->hex_columns && i < readbytes; ++i, ++k, ++j, ++totalbytes)
for (ssize_t j = 0; j < hexfl->hex_wordsize && k < hexfl->hex_columns && i < readbytes; ++i, ++k, ++j, ++totalbytes)
used_digits += hexprint(stream, buf[i], hexfl->hex_flags | HEXPFL_BYTE);
}

if (!(hexfl->hex_flags & HEXDFL_PLAIN)) {
fprintf(stream, "%*s", dumplen - used_digits - used_spaces, "");
fputs(hexfl->hex_dump_separator, stream);
for (k = i - k; k < i; ++k)

for (k = i - k; k < i; ++k)
hexprint(stream, buf[k], hexfl->hex_flags);
}

fputc('\n', stream);
initial_offset = totalbytes;
}
}

Expand Down Expand Up @@ -240,20 +254,20 @@ int main(int argc, char **argv)

setvbuf(stdout, outbuf, _IOFBF, outbufsiz);
opterr = 0;
while ((ch = getopt(argc, argv, ":DK:L:OR:bc:dig:n:o:prs:u")) != -1) {
while ((ch = getopt(argc, argv, ":DK:L:OR:bc:dig:n:oprt:u")) != -1) {
switch (ch) {
case '?':
if (optopt == '?') {
dprintf(STDOUT_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0], argv[0]);
dprintf(STDOUT_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0]);
return EXIT_SUCCESS;
}

dprintf(STDERR_FILENO, "%s: Illegal option: %c.\n", argv[0], optopt);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0], argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0]);
return EXIT_FAILURE;
case ':':
dprintf(STDERR_FILENO, "%s: Missing option argument: %c.\n", argv[0], optopt);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0], argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0]);
return EXIT_FAILURE;
case 'K': hexfl->hex_off_separator = optarg; break;
case 'L': hexfl->hex_dump_separator = optarg; break;
Expand All @@ -271,27 +285,27 @@ int main(int argc, char **argv)
}

break;
case 'b': hexfl->hex_flags |= HEXDFL_BINDUMP; break;
case 'b': hexfl->hex_flags |= HEXDFL_BINARY_DUMP; break;
case 'c':
hexfl->hex_columns = (uint32_t) strtoull(optarg, NULL, 0);
hexfl->hex_flags |= HEXDFL_FORCE_COLUMNS;
if (hexfl->hex_columns == 0 && *optarg != '0') {
dprintf(STDERR_FILENO, "%s: Illegal option argument, expected integer number.\n", argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0], argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0]);
return EXIT_FAILURE;
}

if (hexfl->hex_columns == 0) hexfl->hex_columns = INT_MAX;

break;
case 'd': hexfl->hex_flags |= HEXDFL_DECCOUNT; break;
case 'd': hexfl->hex_flags |= HEXDFL_DECIMAL_COUNT; break;
case 'i': hexfl->hex_flags |= HEXDFL_C; hexfl->hex_flags &= ~HEXDFL_PLAIN; break;
case 'g':
hexfl->hex_wordsize = (uint32_t) strtoull(optarg, NULL, 0);
hexfl->hex_flags |= HEXDFL_FORCE_WORDSIZE;
if (hexfl->hex_wordsize == 0 && *optarg != '0') {
dprintf(STDERR_FILENO, "%s: Illegal option argument, expected integer number.\n", argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0], argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0]);
return EXIT_FAILURE;
}

Expand All @@ -308,17 +322,31 @@ int main(int argc, char **argv)
hexfl->hex_flags |= HEXDFL_AUTONAME;
break;
case 'o':
if ((fd = open(optarg, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR)) < 0) {
dprintf(STDERR_FILENO, "%s: '%s': Unable to output open file: %s (%d).\n", argv[0], optarg, strerror(errno), errno);
return EXIT_FAILURE;
}

dup2(fd, STDOUT_FILENO);
hexfl->hex_flags &= ~(HEXDFL_DECIMAL_COUNT);
hexfl->hex_flags |= HEXDFL_OCTAL_COUNT;
break;
case 'p':
hexfl->hex_flags &= ~(HEXDFL_C | HEXDFL_MASK_COLOR);
hexfl->hex_flags |= (HEXDFL_NOCOUNT | HEXDFL_PLAIN | HEXDFL_NOCOLOR);
hexfl->hex_off_separator = "";
break;
case 't':
if (optarg[1]) {
error:
dprintf(STDERR_FILENO, "%s: Illegal option argument.\n", argv[0]);
dprintf(STDERR_FILENO, __XD_USAGE__, argv[0], argv[0], argv[0]);
return EXIT_FAILURE;
}

switch (optarg[0]) {
case 'h':
case 'x': hexfl->hex_flags &= ~(HEXDFL_DECIMAL_DUMP | HEXDFL_OCTAL_DUMP | HEXDFL_BINARY_DUMP); break;
case 'b': hexfl->hex_flags &= ~(HEXDFL_DECIMAL_DUMP | HEXDFL_OCTAL_DUMP); hexfl->hex_flags |= HEXDFL_BINARY_DUMP; break;
case 'o': hexfl->hex_flags &= ~(HEXDFL_BINARY_DUMP | HEXDFL_DECIMAL_DUMP); hexfl->hex_flags |= HEXDFL_OCTAL_DUMP; break;
case 'd': hexfl->hex_flags &= ~(HEXDFL_BINARY_DUMP | HEXDFL_OCTAL_DUMP); hexfl->hex_flags |= HEXDFL_DECIMAL_DUMP; break;
default: goto error;
}

break;
case 'u': hexfl->hex_flags |= HEXDFL_UPPER; break;
}
Expand Down

0 comments on commit 54d33ae

Please sign in to comment.