ref: 87de3d34335e20fdb2ad2c471f89173aa6610193
dir: /sys/src/cmd/xd.c/
#include <u.h> #include <libc.h> #include <bio.h> unsigned char odata[16]; unsigned char data[16]; int ndata; unsigned long addr; int repeats; int le; /* little endian */ int flush; int abase=2; int xd(char *, int); void xprint(char *, ...); void initarg(void), swizz(void); enum{ Narg=10 }; typedef struct Arg Arg; typedef void fmtfn(char *); struct Arg { int ascii; /* 0==none, 1==ascii */ int loglen; /* 0==1, 1==2, 2==4, 3==8 */ int base; /* 0==8, 1==10, 2==16 */ fmtfn *fn; /* function to call with data */ char *afmt; /* format to use to print address */ char *fmt; /* format to use to print data */ }arg[Narg]; int narg; fmtfn fmt0, fmt1, fmt2, fmt3, fmtc; fmtfn *fmt[4] = { fmt0, fmt1, fmt2, fmt3 }; char *dfmt[4][3] = { " %.3uo", " %.3ud", " %.2ux", " %.6uo", " %.5ud", " %.4ux", " %.11luo", " %.10lud", " %.8lux", " %.22lluo", " %.20llud", " %.16llux", }; char *cfmt[3][3] = { " %c", " %c", " %c", " %.3s", " %.3s", " %.2s", " %.3uo", " %.3ud", " %.2ux", }; char *afmt[2][3] = { "%.7luo ", "%.7lud ", "%.7lux ", "%7luo ", "%7lud ", "%7lux ", }; Biobuf bin; Biobuf bout; int flushout(Biobufhdr *bp, void *v, long n) { Bflush(&bout); return read(bp->fid, v, n); } void main(int argc, char *argv[]) { int i, err; Arg *ap; Binit(&bout, 1, OWRITE); Blethal(&bout, nil); err = 0; ap = 0; while(argc>1 && argv[1][0]=='-' && argv[1][1]){ --argc; argv++; argv[0]++; if(argv[0][0] == 'r'){ repeats = 1; if(argv[0][1]) goto Usage; continue; } if(argv[0][0] == 's'){ le = 1; if(argv[0][1]) goto Usage; continue; } if(argv[0][0] == 'u'){ flush = 1; if(argv[0][1]) goto Usage; continue; } if(argv[0][0] == 'a'){ argv[0]++; switch(argv[0][0]){ case 'o': abase = 0; break; case 'd': abase = 1; break; case 'x': abase = 2; break; default: goto Usage; } if(argv[0][1]) goto Usage; continue; } ap = &arg[narg]; initarg(); while(argv[0][0]){ switch(argv[0][0]){ case 'c': ap->ascii = 1; ap->loglen = 0; if(argv[0][1] || argv[0][-1]!='-') goto Usage; break; case 'o': ap->base = 0; break; case 'd': ap->base = 1; break; case 'x': ap->base = 2; break; case 'b': case '1': ap->loglen = 0; break; case 'w': case '2': ap->loglen = 1; break; case 'l': case '4': ap->loglen = 2; break; case 'v': case '8': ap->loglen = 3; break; default: Usage: fprint(2, "usage: xd [-u] [-r] [-s] [-a{odx}] [-c|{b1w2l4v8}{odx}] ... file ...\n"); exits("usage"); } argv[0]++; } if(ap->ascii) ap->fn = fmtc; else ap->fn = fmt[ap->loglen]; ap->fmt = dfmt[ap->loglen][ap->base]; ap->afmt = afmt[ap>arg][abase]; } if(narg == 0) initarg(); if(argc == 1) err = xd(0, 0); else if(argc == 2) err = xd(argv[1], 0); else for(i=1; i<argc; i++) err |= xd(argv[i], 1); exits(err? "error" : 0); } void initarg(void) { Arg *ap; ap = &arg[narg++]; if(narg >= Narg){ fprint(2, "xd: too many formats (max %d)\n", Narg); exits("usage"); } ap->ascii = 0; ap->loglen = 2; ap->base = 2; ap->fn = fmt2; ap->fmt = dfmt[ap->loglen][ap->base]; ap->afmt = afmt[narg>1][abase]; } int xd(char *name, int title) { int fd; int i, star; Arg *ap; Biobuf *bp; fd = 0; if(name){ bp = Bopen(name, OREAD); if(bp == 0){ fprint(2, "xd: can't open %s\n", name); return 1; } }else{ bp = &bin; Binit(bp, fd, OREAD); } if(flush) Biofn(bp, flushout); Blethal(bp, nil); if(title) xprint("%s\n", name); addr = 0; star = 0; while((ndata=Bread(bp, data, 16)) >= 0){ if(ndata < 16) for(i=ndata; i<16; i++) data[i] = 0; if(ndata==16 && repeats){ if(addr>0 && data[0]==odata[0]){ for(i=1; i<16; i++) if(data[i] != odata[i]) break; if(i == 16){ addr += 16; if(star == 0){ star++; xprint("*\n", 0); } continue; } } for(i=0; i<16; i++) odata[i] = data[i]; star = 0; } for(ap=arg; ap<&arg[narg]; ap++){ xprint(ap->afmt, addr); (*ap->fn)(ap->fmt); xprint("\n", 0); } addr += ndata; if(ndata<16){ xprint(afmt[0][abase], addr); xprint("\n", 0); break; } } Bterm(bp); return 0; } void fmt0(char *f) { int i; for(i=0; i<ndata; i++) xprint(f, data[i]); } void fmt1(char *f) { int i; for(i=0; i<ndata; i+=sizeof(unsigned short)) xprint(f, le ? (data[i+1]<<8)|data[i] : (data[i]<<8)|data[i+1]); } void fmt2(char *f) { int i; for(i=0; i<ndata; i+=sizeof(unsigned long)) xprint(f, le ? (data[i+3]<<24)|(data[i+2]<<16)|(data[i+1]<<8)|data[i] : (data[i]<<24)|(data[i+1]<<16)|(data[i+2]<<8)|data[i+3]); } void fmt3(char *f) { int i; unsigned long long v; for(i=0; i<ndata; i+=sizeof(unsigned long long)){ if(le){ v = (data[i+3+4]<<24)|(data[i+2+4]<<16)|(data[i+1+4]<<8)|data[i+4]; v <<= 32; v |= (data[i+3]<<24)|(data[i+2]<<16)|(data[i+1]<<8)|data[i]; }else{ v = (data[i]<<24)|(data[i+1]<<16)|(data[i+2]<<8)|data[i+3]; v <<= 32; v |= (data[i+4]<<24)|(data[i+1+4]<<16)|(data[i+2+4]<<8)|data[i+3+4]; } if(Bprint(&bout, f, v)<0){ fprint(2, "xd: i/o error\n"); exits("i/o error"); } } } void fmtc(char *f) { int i; USED(f); for(i=0; i<ndata; i++) switch(data[i]){ case '\t': xprint(cfmt[1][2], "\\t"); break; case '\r': xprint(cfmt[1][2], "\\r"); break; case '\n': xprint(cfmt[1][2], "\\n"); break; case '\b': xprint(cfmt[1][2], "\\b"); break; default: if(data[i]>=0x7F || ' '>data[i]) xprint(cfmt[2][2], data[i]); else xprint(cfmt[0][2], data[i]); break; } } void xprint(char *fmt, ...) { va_list arglist; va_start(arglist, fmt); if(Bvprint(&bout, fmt, arglist)<0){ fprint(2, "xd: i/o error\n"); exits("i/o error"); } va_end(arglist); }