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