xref: /aosp_15_r20/external/toybox/toys/pending/hexdump.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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