10f66f451Sopenharmony_ci/* hexdump.c - Dump file content in hexadecimal format to stdout 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2021 Moritz Röhrich <moritz@ildefons.de> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * No standard 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * TODO: 80f66f451Sopenharmony_ci * - Implement format strings (see man (1) hexdump) 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ciUSE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN)) 110f66f451Sopenharmony_ciUSE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN)) 120f66f451Sopenharmony_ci 130f66f451Sopenharmony_ciconfig HEXDUMP 140f66f451Sopenharmony_ci bool "hexdump" 150f66f451Sopenharmony_ci default n 160f66f451Sopenharmony_ci help 170f66f451Sopenharmony_ci usage: hexdump [-bcCdovx] [-n LEN] [-s SKIP] [FILE...] 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci Dump file(s) in hexadecimal format. 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci -n LEN Show LEN bytes of output 220f66f451Sopenharmony_ci -s SKIP Skip bytes of input 230f66f451Sopenharmony_ci -v Verbose (don't combine identical lines) 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci Display type: 260f66f451Sopenharmony_ci -b One byte octal -c One byte character -C Canonical (hex + ASCII) 270f66f451Sopenharmony_ci -d Two byte decimal -o Two byte octal -x Two byte hexadecimal (default) 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_ciconfig HD 300f66f451Sopenharmony_ci bool "hd" 310f66f451Sopenharmony_ci default HEXDUMP 320f66f451Sopenharmony_ci help 330f66f451Sopenharmony_ci usage: hd [FILE...] 340f66f451Sopenharmony_ci 350f66f451Sopenharmony_ci Display file(s) in cannonical hex+ASCII format. 360f66f451Sopenharmony_ci*/ 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci#define FOR_hexdump 390f66f451Sopenharmony_ci#include "toys.h" 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ciGLOBALS( 420f66f451Sopenharmony_ci long s, n; 430f66f451Sopenharmony_ci 440f66f451Sopenharmony_ci long long len, pos, ppos; 450f66f451Sopenharmony_ci const char *fmt; 460f66f451Sopenharmony_ci unsigned int fn, bc; // file number and byte count 470f66f451Sopenharmony_ci char linebuf[16]; // line buffer - serves double duty for sqeezing repeat 480f66f451Sopenharmony_ci // lines and for accumulating full lines accross file 490f66f451Sopenharmony_ci // boundaries if necessesary. 500f66f451Sopenharmony_ci) 510f66f451Sopenharmony_ci 520f66f451Sopenharmony_ciconst char *make_printable(unsigned char byte) { 530f66f451Sopenharmony_ci switch (byte) { 540f66f451Sopenharmony_ci case '\0': return "\\0"; 550f66f451Sopenharmony_ci case '\a': return "\\a"; 560f66f451Sopenharmony_ci case '\b': return "\\b"; 570f66f451Sopenharmony_ci case '\t': return "\\t"; 580f66f451Sopenharmony_ci case '\n': return "\\n"; 590f66f451Sopenharmony_ci case '\v': return "\\v"; 600f66f451Sopenharmony_ci case '\f': return "\\f"; 610f66f451Sopenharmony_ci default: return "??"; // for all unprintable bytes 620f66f451Sopenharmony_ci } 630f66f451Sopenharmony_ci} 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_civoid do_hexdump(int fd, char *name) 660f66f451Sopenharmony_ci{ 670f66f451Sopenharmony_ci unsigned short block, adv, i; 680f66f451Sopenharmony_ci int sl, fs; // skip line, file size 690f66f451Sopenharmony_ci 700f66f451Sopenharmony_ci TT.fn++; // keep track of how many files have been printed. 710f66f451Sopenharmony_ci // skipp ahead, if necessary skip entire files: 720f66f451Sopenharmony_ci if (FLAG(s) && (TT.s-TT.pos>0)) { 730f66f451Sopenharmony_ci fs = xlseek(fd, 0L, SEEK_END); 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_ci if (fs < TT.s) { 760f66f451Sopenharmony_ci TT.pos += fs; 770f66f451Sopenharmony_ci TT.ppos += fs; 780f66f451Sopenharmony_ci } else { 790f66f451Sopenharmony_ci xlseek(fd, TT.s-TT.pos, SEEK_SET); 800f66f451Sopenharmony_ci TT.ppos = TT.s; 810f66f451Sopenharmony_ci TT.pos = TT.s; 820f66f451Sopenharmony_ci } 830f66f451Sopenharmony_ci } 840f66f451Sopenharmony_ci 850f66f451Sopenharmony_ci for (sl = 0; 860f66f451Sopenharmony_ci 0 < (TT.len = readall(fd, toybuf, 870f66f451Sopenharmony_ci (TT.n && TT.s+TT.n-TT.pos<16-(TT.bc%16)) 880f66f451Sopenharmony_ci ? TT.s+TT.n-TT.pos : 16-(TT.bc%16))); 890f66f451Sopenharmony_ci TT.pos += TT.len) { 900f66f451Sopenharmony_ci // This block compares the data read from file to the last line printed. 910f66f451Sopenharmony_ci // If they don't match a new line is printed, else the line is skipped. 920f66f451Sopenharmony_ci // If a * has already been printed to indicate a skipped line, printing the 930f66f451Sopenharmony_ci // * is also skipped. 940f66f451Sopenharmony_ci for (i = 0; i < 16 && i < TT.len; i++){ 950f66f451Sopenharmony_ci if (FLAG(v) || TT.len < 16 || toybuf[i] != TT.linebuf[i]) goto newline; 960f66f451Sopenharmony_ci } 970f66f451Sopenharmony_ci if (sl == 0) { 980f66f451Sopenharmony_ci printf("*\n"); 990f66f451Sopenharmony_ci sl = 1; 1000f66f451Sopenharmony_ci } 1010f66f451Sopenharmony_ci TT.ppos += TT.len; 1020f66f451Sopenharmony_ci continue; 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_cinewline: 1050f66f451Sopenharmony_ci strncpy(TT.linebuf+(TT.bc%16), toybuf, TT.len); 1060f66f451Sopenharmony_ci TT.bc = TT.bc % 16 + TT.len; 1070f66f451Sopenharmony_ci sl = 0; 1080f66f451Sopenharmony_ci if (TT.pos + TT.bc == TT.s+TT.n || TT.fn == toys.optc || TT.bc == 16) { 1090f66f451Sopenharmony_ci if (!FLAG(C) && !FLAG(c)) { 1100f66f451Sopenharmony_ci printf("%07llx", TT.ppos); 1110f66f451Sopenharmony_ci adv = FLAG(b) ? 1 : 2; 1120f66f451Sopenharmony_ci for (i = 0; i < TT.bc; i += adv) { 1130f66f451Sopenharmony_ci block = (FLAG(b) || i == TT.bc-1) 1140f66f451Sopenharmony_ci ? TT.linebuf[i] : (TT.linebuf[i] | TT.linebuf[i+1] << 8); 1150f66f451Sopenharmony_ci printf(TT.fmt, block); 1160f66f451Sopenharmony_ci } 1170f66f451Sopenharmony_ci } else if (FLAG(C)) { 1180f66f451Sopenharmony_ci printf("%08llx", TT.ppos); 1190f66f451Sopenharmony_ci for (i = 0; i < 16; i++) { 1200f66f451Sopenharmony_ci if (!(i % 8)) putchar(' '); 1210f66f451Sopenharmony_ci if (i < TT.bc) printf(" %02x", TT.linebuf[i]); 1220f66f451Sopenharmony_ci else printf(" "); 1230f66f451Sopenharmony_ci } 1240f66f451Sopenharmony_ci printf(" |"); 1250f66f451Sopenharmony_ci for (i = 0; i < TT.bc; i++) { 1260f66f451Sopenharmony_ci if (TT.linebuf[i] < ' ' || TT.linebuf[i] > '~') putchar('.'); 1270f66f451Sopenharmony_ci else putchar(TT.linebuf[i]); 1280f66f451Sopenharmony_ci } 1290f66f451Sopenharmony_ci putchar('|'); 1300f66f451Sopenharmony_ci } else { 1310f66f451Sopenharmony_ci printf("%07llx", TT.ppos); 1320f66f451Sopenharmony_ci for (i = 0; i < TT.bc; i++) { 1330f66f451Sopenharmony_ci if (TT.linebuf[i] >= ' ' && TT.linebuf[i] <= '~') 1340f66f451Sopenharmony_ci printf("%4c", TT.linebuf[i]); 1350f66f451Sopenharmony_ci else printf("%4s", make_printable(TT.linebuf[i])); 1360f66f451Sopenharmony_ci } 1370f66f451Sopenharmony_ci } 1380f66f451Sopenharmony_ci putchar('\n'); 1390f66f451Sopenharmony_ci TT.ppos += TT.bc; 1400f66f451Sopenharmony_ci } 1410f66f451Sopenharmony_ci } 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_ci if (TT.len < 0) perror_exit("read"); 1440f66f451Sopenharmony_ci} 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_civoid hexdump_main(void) 1470f66f451Sopenharmony_ci{ 1480f66f451Sopenharmony_ci if FLAG(b) TT.fmt = " %03o"; 1490f66f451Sopenharmony_ci else if FLAG(d) TT.fmt = " %05d"; 1500f66f451Sopenharmony_ci else if FLAG(o) TT.fmt = " %06o"; 1510f66f451Sopenharmony_ci else TT.fmt = " %04x"; 1520f66f451Sopenharmony_ci 1530f66f451Sopenharmony_ci loopfiles(toys.optargs, do_hexdump); 1540f66f451Sopenharmony_ci FLAG(C) ? printf("%08llx\n", TT.pos) : printf("%07llx\n", TT.pos); 1550f66f451Sopenharmony_ci} 156