1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 enum {
6 Nsee = 4*4, /* process this many bytes at a time; see swizz */
7 };
8
9 uchar odata[Nsee];
10 uchar data[2*Nsee];
11 int ndata;
12 int nread;
13 ulong addr;
14 int repeats;
15 int swizzle;
16 int flush;
17 int abase=2;
18
19 int xd(char *, int);
20 void xprint(char *, ...);
21 void initarg(void), swizz(void);
22
23 enum{
24 Narg=10,
25
26 TNone=0,
27 TAscii,
28 TRune,
29 };
30 typedef struct Arg Arg;
31 typedef void fmtfn(char *);
32 struct Arg
33 {
34 int chartype; /* TNone, TAscii, TRunes */
35 int loglen; /* 0==1, 1==2, 2==4, 3==8 */
36 int base; /* 0==8, 1==10, 2==16 */
37 fmtfn *fn; /* function to call with data */
38 char *afmt; /* format to use to print address */
39 char *fmt; /* format to use to print data */
40 }arg[Narg];
41 int narg;
42
43 fmtfn fmt0, fmt1, fmt2, fmt3, fmtc, fmtr;
44 fmtfn *fmt[4] = {
45 fmt0,
46 fmt1,
47 fmt2,
48 fmt3
49 };
50
51 char *dfmt[4][3] = {
52 " %.3uo", " %.3ud", " %.2ux",
53 " %.6uo", " %.5ud", " %.4ux",
54 " %.11luo", " %.10lud", " %.8lux",
55 " %.22lluo", " %.20llud", " %.16llux",
56 };
57
58 char *cfmt[3][3] = {
59 " %c", " %c", " %c",
60 " %.3s", " %.3s", " %.2s",
61 " %.3uo", " %.3ud", " %.2ux",
62 };
63
64 char *rfmt[1][1] = {
65 " %2.2C",
66 };
67
68 char *afmt[2][3] = {
69 "%.7luo ", "%.7lud ", "%.7lux ",
70 "%7luo ", "%7lud ", "%7lux ",
71 };
72
73 Biobuf bin;
74 Biobuf bout;
75
76 void
main(int argc,char * argv[])77 main(int argc, char *argv[])
78 {
79 int i, err;
80 Arg *ap;
81
82 Binit(&bout, 1, OWRITE);
83 err = 0;
84 ap = 0;
85 while(argc>1 && argv[1][0]=='-' && argv[1][1]){
86 --argc;
87 argv++;
88 argv[0]++;
89 if(argv[0][0] == 'r'){
90 repeats = 1;
91 if(argv[0][1])
92 goto Usage;
93 continue;
94 }
95 if(argv[0][0] == 's'){
96 swizzle = 1;
97 if(argv[0][1])
98 goto Usage;
99 continue;
100 }
101 if(argv[0][0] == 'u'){
102 flush = 1;
103 if(argv[0][1])
104 goto Usage;
105 continue;
106 }
107 if(argv[0][0] == 'a'){
108 argv[0]++;
109 switch(argv[0][0]){
110 case 'o':
111 abase = 0;
112 break;
113 case 'd':
114 abase = 1;
115 break;
116 case 'x':
117 abase = 2;
118 break;
119 default:
120 goto Usage;
121 }
122 if(argv[0][1])
123 goto Usage;
124 continue;
125 }
126 ap = &arg[narg];
127 initarg();
128 while(argv[0][0]){
129 switch(argv[0][0]){
130 case 'c':
131 ap->chartype = TAscii;
132 ap->loglen = 0;
133 if(argv[0][1] || argv[0][-1]!='-')
134 goto Usage;
135 break;
136 case 'R':
137 ap->chartype = TRune;
138 ap->loglen = 0;
139 if(argv[0][1] || argv[0][-1]!='-')
140 goto Usage;
141 break;
142 case 'o':
143 ap->base = 0;
144 break;
145 case 'd':
146 ap->base = 1;
147 break;
148 case 'x':
149 ap->base = 2;
150 break;
151 case 'b':
152 case '1':
153 ap->loglen = 0;
154 break;
155 case 'w':
156 case '2':
157 ap->loglen = 1;
158 break;
159 case 'l':
160 case '4':
161 ap->loglen = 2;
162 break;
163 case 'v':
164 case '8':
165 ap->loglen = 3;
166 break;
167 default:
168 Usage:
169 fprint(2, "usage: xd [-u] [-r] [-s] [-a{odx}] [-c|{b1w2l4v8}{odx}] ... file ...\n");
170 exits("usage");
171 }
172 argv[0]++;
173 }
174 if(ap->chartype == TRune)
175 ap->fn = fmtr;
176 else if(ap->chartype == TAscii)
177 ap->fn = fmtc;
178 else
179 ap->fn = fmt[ap->loglen];
180 ap->fmt = dfmt[ap->loglen][ap->base];
181 ap->afmt = afmt[ap>arg][abase];
182 }
183 if(narg == 0)
184 initarg();
185 if(argc == 1)
186 err = xd(0, 0);
187 else if(argc == 2)
188 err = xd(argv[1], 0);
189 else for(i=1; i<argc; i++)
190 err |= xd(argv[i], 1);
191 exits(err? "error" : 0);
192 }
193
194 void
initarg(void)195 initarg(void)
196 {
197 Arg *ap;
198
199 ap = &arg[narg++];
200 if(narg >= Narg){
201 fprint(2, "xd: too many formats (max %d)\n", Narg);
202 exits("usage");
203 }
204 ap->chartype = TNone;
205 ap->loglen = 2;
206 ap->base = 2;
207 ap->fn = fmt2;
208 ap->fmt = dfmt[ap->loglen][ap->base];
209 ap->afmt = afmt[narg>1][abase];
210 }
211
212 /*
213 * format the first ndata bytes in data[] (at most Nsee bytes).
214 * increment addr to account for them.
215 */
216 void
fmtdata(void)217 fmtdata(void)
218 {
219 Arg *ap;
220
221 for(ap=arg; ap<&arg[narg]; ap++){
222 xprint(ap->afmt, addr);
223 (*ap->fn)(ap->fmt);
224 xprint("\n", 0);
225 if(flush)
226 Bflush(&bout);
227 }
228 addr += ndata;
229 if(ndata<Nsee){ /* short read? print fragment */
230 xprint(afmt[0][abase], addr);
231 xprint("\n", 0);
232 if(flush)
233 Bflush(&bout);
234 }
235 }
236
237 int
xd(char * name,int title)238 xd(char *name, int title)
239 {
240 int fd, star, nleft, doprint;
241 Biobuf *bp;
242
243 fd = 0;
244 if(name){
245 bp = Bopen(name, OREAD);
246 if(bp == 0){
247 fprint(2, "xd: can't open %s\n", name);
248 return 1;
249 }
250 }else{
251 bp = &bin;
252 Binit(bp, fd, OREAD);
253 }
254 if(title)
255 xprint("%s\n", name);
256 addr = 0;
257 star = 0;
258 nleft = 0;
259 /* read 2*Nsee but see only Nsee so that runes are happy */
260 while((ndata=Bread(bp, data + nleft, 2*Nsee - nleft)) >= 0){
261 ndata += nleft;
262 nleft = 0;
263 nread = ndata;
264 if(ndata>Nsee)
265 ndata = Nsee;
266 else if(ndata<Nsee)
267 memset(data + ndata, '\0', Nsee - ndata);
268 if(swizzle)
269 swizz();
270 doprint = 1;
271 if(ndata==Nsee && repeats)
272 if(addr>0 && memcmp(odata, data, Nsee) == 0){
273 doprint = 0;
274 if(star == 0){
275 star++;
276 xprint("*\n", 0);
277 }
278 } else { /* not a repetition */
279 memmove(odata, data, Nsee);
280 star = 0;
281 }
282 if (doprint)
283 fmtdata(); /* also increments addr */
284 else
285 addr += Nsee;
286 if(ndata<Nsee) /* short read? done */
287 break;
288 if(nread>Nsee){
289 nleft = nread - Nsee;
290 memmove(data, data + Nsee, nleft);
291 }
292 }
293 Bterm(bp);
294 return 0;
295 }
296
297 void
swizz(void)298 swizz(void)
299 {
300 uchar *p, *q;
301 int i;
302 uchar swdata[Nsee];
303
304 p = data;
305 q = swdata;
306 for(i=0; i<Nsee; i++)
307 *q++ = *p++;
308 p = data;
309 q = swdata;
310 for(i=0; i<4; i++){
311 p[0] = q[3];
312 p[1] = q[2];
313 p[2] = q[1];
314 p[3] = q[0];
315 p += 4;
316 q += 4;
317 }
318 }
319
320 void
fmt0(char * f)321 fmt0(char *f)
322 {
323 int i;
324 for(i=0; i<ndata; i++)
325 xprint(f, data[i]);
326 }
327
328 void
fmt1(char * f)329 fmt1(char *f)
330 {
331 int i;
332 for(i=0; i<ndata; i+=sizeof(ushort))
333 xprint(f, (data[i]<<8)|data[i+1]);
334 }
335
336 void
fmt2(char * f)337 fmt2(char *f)
338 {
339 int i;
340 for(i=0; i<ndata; i+=sizeof(ulong))
341 xprint(f, (data[i]<<24)|(data[i+1]<<16)|(data[i+2]<<8)|data[i+3]);
342 }
343
344 void
fmt3(char * f)345 fmt3(char *f)
346 {
347 int i;
348 uvlong v;
349
350 for(i=0; i<ndata; i+=sizeof(uvlong)){
351 v = (data[i]<<24)|(data[i+1]<<16)|(data[i+2]<<8)|data[i+3];
352 v <<= 32;
353 v |= (data[i+4]<<24)|(data[i+1+4]<<16)|(data[i+2+4]<<8)|data[i+3+4];
354 if(Bprint(&bout, f, v)<0){
355 fprint(2, "xd: i/o error\n");
356 exits("i/o error");
357 }
358 }
359 }
360
361 void
onefmtc(uchar c)362 onefmtc(uchar c)
363 {
364 switch(c){
365 case '\t':
366 xprint(cfmt[1][2], "\\t");
367 break;
368 case '\r':
369 xprint(cfmt[1][2], "\\r");
370 break;
371 case '\n':
372 xprint(cfmt[1][2], "\\n");
373 break;
374 case '\b':
375 xprint(cfmt[1][2], "\\b");
376 break;
377 default:
378 if(c>=0x7F || ' '>c)
379 xprint(cfmt[2][2], c);
380 else
381 xprint(cfmt[0][2], c);
382 break;
383 }
384 }
385
386 void
fmtc(char * f)387 fmtc(char *f)
388 {
389 int i;
390
391 USED(f);
392 for(i=0; i<ndata; i++)
393 onefmtc(data[i]);
394 }
395
396 void
fmtr(char * f)397 fmtr(char *f)
398 {
399 int i, w, cw;
400 Rune r;
401 static int nstart;
402
403 USED(f);
404 if(nstart)
405 xprint("%*c", 3*nstart, ' ');
406 for(i=nstart; i<ndata; )
407 if(data[i] < Runeself)
408 onefmtc(data[i++]);
409 else{
410 w = chartorune(&r, (char *)data+i);
411 if(w == 1 || i + w>nread)
412 onefmtc(data[i++]);
413 else{
414 cw = w;
415 if(i + w>ndata)
416 cw = ndata - i;
417 xprint(rfmt[0][0], r);
418 xprint("%*c", 3*cw-3, ' ');
419 i += w;
420 }
421 }
422 if(i > ndata)
423 nstart = i - ndata;
424 else
425 nstart = 0;
426 }
427
428 void
xprint(char * fmt,...)429 xprint(char *fmt, ...)
430 {
431 va_list arglist;
432
433 va_start(arglist, fmt);
434 if(Bvprint(&bout, fmt, arglist)<0){
435 fprint(2, "xd: i/o error\n");
436 exits("i/o error");
437 }
438 va_end(arglist);
439 }
440