xref: /plan9/sys/src/cmd/xd.c (revision 4db25db672e11d72a878263ef7c92def5c56957b)
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