156 lines
4.2 KiB
C
156 lines
4.2 KiB
C
/* hexdump.c - Dump file content in hexadecimal format to stdout
|
|
*
|
|
* Copyright 2021 Moritz Röhrich <moritz@ildefons.de>
|
|
*
|
|
* No standard
|
|
*
|
|
* TODO:
|
|
* - Implement format strings (see man (1) hexdump)
|
|
|
|
USE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN))
|
|
USE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN))
|
|
|
|
config HEXDUMP
|
|
bool "hexdump"
|
|
default n
|
|
help
|
|
usage: hexdump [-bcCdovx] [-n LEN] [-s SKIP] [FILE...]
|
|
|
|
Dump file(s) in hexadecimal format.
|
|
|
|
-n LEN Show LEN bytes of output
|
|
-s SKIP Skip bytes of input
|
|
-v Verbose (don't combine identical lines)
|
|
|
|
Display type:
|
|
-b One byte octal -c One byte character -C Canonical (hex + ASCII)
|
|
-d Two byte decimal -o Two byte octal -x Two byte hexadecimal (default)
|
|
|
|
config HD
|
|
bool "hd"
|
|
default HEXDUMP
|
|
help
|
|
usage: hd [FILE...]
|
|
|
|
Display file(s) in cannonical hex+ASCII format.
|
|
*/
|
|
|
|
#define FOR_hexdump
|
|
#include "toys.h"
|
|
|
|
GLOBALS(
|
|
long s, n;
|
|
|
|
long long len, pos, ppos;
|
|
const char *fmt;
|
|
unsigned int fn, bc; // file number and byte count
|
|
char linebuf[16]; // line buffer - serves double duty for sqeezing repeat
|
|
// lines and for accumulating full lines accross file
|
|
// boundaries if necessesary.
|
|
)
|
|
|
|
const char *make_printable(unsigned char byte) {
|
|
switch (byte) {
|
|
case '\0': return "\\0";
|
|
case '\a': return "\\a";
|
|
case '\b': return "\\b";
|
|
case '\t': return "\\t";
|
|
case '\n': return "\\n";
|
|
case '\v': return "\\v";
|
|
case '\f': return "\\f";
|
|
default: return "??"; // for all unprintable bytes
|
|
}
|
|
}
|
|
|
|
void do_hexdump(int fd, char *name)
|
|
{
|
|
unsigned short block, adv, i;
|
|
int sl, fs; // skip line, file size
|
|
|
|
TT.fn++; // keep track of how many files have been printed.
|
|
// skipp ahead, if necessary skip entire files:
|
|
if (FLAG(s) && (TT.s-TT.pos>0)) {
|
|
fs = xlseek(fd, 0L, SEEK_END);
|
|
|
|
if (fs < TT.s) {
|
|
TT.pos += fs;
|
|
TT.ppos += fs;
|
|
} else {
|
|
xlseek(fd, TT.s-TT.pos, SEEK_SET);
|
|
TT.ppos = TT.s;
|
|
TT.pos = TT.s;
|
|
}
|
|
}
|
|
|
|
for (sl = 0;
|
|
0 < (TT.len = readall(fd, toybuf,
|
|
(TT.n && TT.s+TT.n-TT.pos<16-(TT.bc%16))
|
|
? TT.s+TT.n-TT.pos : 16-(TT.bc%16)));
|
|
TT.pos += TT.len) {
|
|
// This block compares the data read from file to the last line printed.
|
|
// If they don't match a new line is printed, else the line is skipped.
|
|
// If a * has already been printed to indicate a skipped line, printing the
|
|
// * is also skipped.
|
|
for (i = 0; i < 16 && i < TT.len; i++){
|
|
if (FLAG(v) || TT.len < 16 || toybuf[i] != TT.linebuf[i]) goto newline;
|
|
}
|
|
if (sl == 0) {
|
|
printf("*\n");
|
|
sl = 1;
|
|
}
|
|
TT.ppos += TT.len;
|
|
continue;
|
|
|
|
newline:
|
|
strncpy(TT.linebuf+(TT.bc%16), toybuf, TT.len);
|
|
TT.bc = TT.bc % 16 + TT.len;
|
|
sl = 0;
|
|
if (TT.pos + TT.bc == TT.s+TT.n || TT.fn == toys.optc || TT.bc == 16) {
|
|
if (!FLAG(C) && !FLAG(c)) {
|
|
printf("%07llx", TT.ppos);
|
|
adv = FLAG(b) ? 1 : 2;
|
|
for (i = 0; i < TT.bc; i += adv) {
|
|
block = (FLAG(b) || i == TT.bc-1)
|
|
? TT.linebuf[i] : (TT.linebuf[i] | TT.linebuf[i+1] << 8);
|
|
printf(TT.fmt, block);
|
|
}
|
|
} else if (FLAG(C)) {
|
|
printf("%08llx", TT.ppos);
|
|
for (i = 0; i < 16; i++) {
|
|
if (!(i % 8)) putchar(' ');
|
|
if (i < TT.bc) printf(" %02x", TT.linebuf[i]);
|
|
else printf(" ");
|
|
}
|
|
printf(" |");
|
|
for (i = 0; i < TT.bc; i++) {
|
|
if (TT.linebuf[i] < ' ' || TT.linebuf[i] > '~') putchar('.');
|
|
else putchar(TT.linebuf[i]);
|
|
}
|
|
putchar('|');
|
|
} else {
|
|
printf("%07llx", TT.ppos);
|
|
for (i = 0; i < TT.bc; i++) {
|
|
if (TT.linebuf[i] >= ' ' && TT.linebuf[i] <= '~')
|
|
printf("%4c", TT.linebuf[i]);
|
|
else printf("%4s", make_printable(TT.linebuf[i]));
|
|
}
|
|
}
|
|
putchar('\n');
|
|
TT.ppos += TT.bc;
|
|
}
|
|
}
|
|
|
|
if (TT.len < 0) perror_exit("read");
|
|
}
|
|
|
|
void hexdump_main(void)
|
|
{
|
|
if FLAG(b) TT.fmt = " %03o";
|
|
else if FLAG(d) TT.fmt = " %05d";
|
|
else if FLAG(o) TT.fmt = " %06o";
|
|
else TT.fmt = " %04x";
|
|
|
|
loopfiles(toys.optargs, do_hexdump);
|
|
FLAG(C) ? printf("%08llx\n", TT.pos) : printf("%07llx\n", TT.pos);
|
|
}
|