1 /* hexdump.c - Dump file content in hexadecimal format to stdout
2 *
3 * Copyright 2021 Moritz Röhrich <moritz@ildefons.de>
4 *
5 * No standard
6 *
7 * TODO:
8 * - Implement format strings (see man (1) hexdump)
9
10 USE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN))
11 USE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN))
12
13 config HEXDUMP
14 bool "hexdump"
15 default n
16 help
17 usage: hexdump [-bcCdovx] [-n LEN] [-s SKIP] [FILE...]
18
19 Dump file(s) in hexadecimal format.
20
21 -n LEN Show LEN bytes of output
22 -s SKIP Skip bytes of input
23 -v Verbose (don't combine identical lines)
24
25 Display type:
26 -b One byte octal -c One byte character -C Canonical (hex + ASCII)
27 -d Two byte decimal -o Two byte octal -x Two byte hexadecimal (default)
28
29 config HD
30 bool "hd"
31 default HEXDUMP
32 help
33 usage: hd [FILE...]
34
35 Display file(s) in cannonical hex+ASCII format.
36 */
37
38 #define FOR_hexdump
39 #include "toys.h"
40
GLOBALS(long s,n;long long len,pos,ppos;const char * fmt;unsigned int fn,bc;char linebuf[16];)41 GLOBALS(
42 long s, n;
43
44 long long len, pos, ppos;
45 const char *fmt;
46 unsigned int fn, bc; // file number and byte count
47 char linebuf[16]; // line buffer - serves double duty for sqeezing repeat
48 // lines and for accumulating full lines accross file
49 // boundaries if necessesary.
50 )
51
52 const char *make_printable(unsigned char byte) {
53 switch (byte) {
54 case '\0': return "\\0";
55 case '\a': return "\\a";
56 case '\b': return "\\b";
57 case '\t': return "\\t";
58 case '\n': return "\\n";
59 case '\v': return "\\v";
60 case '\f': return "\\f";
61 default: return "??"; // for all unprintable bytes
62 }
63 }
64
do_hexdump(int fd,char * name)65 void do_hexdump(int fd, char *name)
66 {
67 unsigned short block, adv, i;
68 int sl, fs; // skip line, file size
69
70 TT.fn++; // keep track of how many files have been printed.
71 // skipp ahead, if necessary skip entire files:
72 if (FLAG(s) && (TT.s-TT.pos>0)) {
73 fs = xlseek(fd, 0L, SEEK_END);
74
75 if (fs < TT.s) {
76 TT.pos += fs;
77 TT.ppos += fs;
78 } else {
79 xlseek(fd, TT.s-TT.pos, SEEK_SET);
80 TT.ppos = TT.s;
81 TT.pos = TT.s;
82 }
83 }
84
85 for (sl = 0;
86 0 < (TT.len = readall(fd, toybuf,
87 (TT.n && TT.s+TT.n-TT.pos<16-(TT.bc%16))
88 ? TT.s+TT.n-TT.pos : 16-(TT.bc%16)));
89 TT.pos += TT.len) {
90 // This block compares the data read from file to the last line printed.
91 // If they don't match a new line is printed, else the line is skipped.
92 // If a * has already been printed to indicate a skipped line, printing the
93 // * is also skipped.
94 for (i = 0; i < 16 && i < TT.len; i++){
95 if (FLAG(v) || TT.len < 16 || toybuf[i] != TT.linebuf[i]) goto newline;
96 }
97 if (sl == 0) {
98 printf("*\n");
99 sl = 1;
100 }
101 TT.ppos += TT.len;
102 continue;
103
104 newline:
105 strncpy(TT.linebuf+(TT.bc%16), toybuf, TT.len);
106 TT.bc = TT.bc % 16 + TT.len;
107 sl = 0;
108 if (TT.pos + TT.bc == TT.s+TT.n || TT.fn == toys.optc || TT.bc == 16) {
109 if (!FLAG(C) && !FLAG(c)) {
110 printf("%07llx", TT.ppos);
111 adv = FLAG(b) ? 1 : 2;
112 for (i = 0; i < TT.bc; i += adv) {
113 block = (FLAG(b) || i == TT.bc-1)
114 ? TT.linebuf[i] : (TT.linebuf[i] | TT.linebuf[i+1] << 8);
115 printf(TT.fmt, block);
116 }
117 } else if (FLAG(C)) {
118 printf("%08llx", TT.ppos);
119 for (i = 0; i < 16; i++) {
120 if (!(i % 8)) putchar(' ');
121 if (i < TT.bc) printf(" %02x", TT.linebuf[i]);
122 else printf(" ");
123 }
124 printf(" |");
125 for (i = 0; i < TT.bc; i++) {
126 if (TT.linebuf[i] < ' ' || TT.linebuf[i] > '~') putchar('.');
127 else putchar(TT.linebuf[i]);
128 }
129 putchar('|');
130 } else {
131 printf("%07llx", TT.ppos);
132 for (i = 0; i < TT.bc; i++) {
133 if (TT.linebuf[i] >= ' ' && TT.linebuf[i] <= '~')
134 printf("%4c", TT.linebuf[i]);
135 else printf("%4s", make_printable(TT.linebuf[i]));
136 }
137 }
138 putchar('\n');
139 TT.ppos += TT.bc;
140 }
141 }
142
143 if (TT.len < 0) perror_exit("read");
144 }
145
hexdump_main(void)146 void hexdump_main(void)
147 {
148 if FLAG(b) TT.fmt = " %03o";
149 else if FLAG(d) TT.fmt = " %05d";
150 else if FLAG(o) TT.fmt = " %06o";
151 else TT.fmt = " %04x";
152
153 loopfiles(toys.optargs, do_hexdump);
154 FLAG(C) ? printf("%08llx\n", TT.pos) : printf("%07llx\n", TT.pos);
155 }
156