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