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