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 10USE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN)) 11USE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN)) 12 13config 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 29config 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 41GLOBALS( 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 52const 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 65void 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 104newline: 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 146void 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