xref: /plan9-contrib/sys/src/cmd/xd.c (revision a1e175a14cc0a444823b3090c7dc9d55076f6121)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier 
5*a1e175a1SDavid du Colombier enum {
6*a1e175a1SDavid du Colombier 	Nsee = 4*4,  /* process this many bytes at a time; see swizz */
7*a1e175a1SDavid du Colombier };
8*a1e175a1SDavid du Colombier 
9*a1e175a1SDavid du Colombier uchar		odata[Nsee];
10*a1e175a1SDavid du Colombier uchar		data[2*Nsee];
113e12c5d1SDavid du Colombier int		ndata;
124db25db6SDavid du Colombier int		nread;
134db25db6SDavid du Colombier ulong		addr;
143e12c5d1SDavid du Colombier int		repeats;
153e12c5d1SDavid du Colombier int		swizzle;
163e12c5d1SDavid du Colombier int		flush;
173e12c5d1SDavid du Colombier int		abase=2;
18*a1e175a1SDavid du Colombier 
193e12c5d1SDavid du Colombier int		xd(char *, int);
20af2e6ba6SDavid du Colombier void		xprint(char *, ...);
213e12c5d1SDavid du Colombier void		initarg(void), swizz(void);
22*a1e175a1SDavid du Colombier 
233e12c5d1SDavid du Colombier enum{
244db25db6SDavid du Colombier 	Narg=10,
254db25db6SDavid du Colombier 
264db25db6SDavid du Colombier 	TNone=0,
274db25db6SDavid du Colombier 	TAscii,
284db25db6SDavid du Colombier 	TRune,
293e12c5d1SDavid du Colombier };
303e12c5d1SDavid du Colombier typedef struct Arg Arg;
313e12c5d1SDavid du Colombier typedef void fmtfn(char *);
323e12c5d1SDavid du Colombier struct Arg
333e12c5d1SDavid du Colombier {
344db25db6SDavid du Colombier 	int	chartype;	/* TNone, TAscii, TRunes */
35219b2ee8SDavid du Colombier 	int	loglen;		/* 0==1, 1==2, 2==4, 3==8 */
363e12c5d1SDavid du Colombier 	int	base;		/* 0==8, 1==10, 2==16 */
373e12c5d1SDavid du Colombier 	fmtfn	*fn;		/* function to call with data */
383e12c5d1SDavid du Colombier 	char	*afmt;		/* format to use to print address */
393e12c5d1SDavid du Colombier 	char	*fmt;		/* format to use to print data */
403e12c5d1SDavid du Colombier }arg[Narg];
413e12c5d1SDavid du Colombier int	narg;
423e12c5d1SDavid du Colombier 
434db25db6SDavid du Colombier fmtfn	fmt0, fmt1, fmt2, fmt3, fmtc, fmtr;
44219b2ee8SDavid du Colombier fmtfn *fmt[4] = {
453e12c5d1SDavid du Colombier 	fmt0,
463e12c5d1SDavid du Colombier 	fmt1,
47219b2ee8SDavid du Colombier 	fmt2,
48219b2ee8SDavid du Colombier 	fmt3
493e12c5d1SDavid du Colombier };
503e12c5d1SDavid du Colombier 
51219b2ee8SDavid du Colombier char *dfmt[4][3] = {
523e12c5d1SDavid du Colombier 	" %.3uo",	" %.3ud",	" %.2ux",
533e12c5d1SDavid du Colombier 	" %.6uo",	" %.5ud",	" %.4ux",
543e12c5d1SDavid du Colombier 	" %.11luo",	" %.10lud",	" %.8lux",
55219b2ee8SDavid du Colombier 	" %.22lluo",	" %.20llud",	" %.16llux",
563e12c5d1SDavid du Colombier };
573e12c5d1SDavid du Colombier 
583e12c5d1SDavid du Colombier char *cfmt[3][3] = {
593e12c5d1SDavid du Colombier 	"   %c",	"   %c", 	"  %c",
603e12c5d1SDavid du Colombier 	" %.3s",	" %.3s",	" %.2s",
613e12c5d1SDavid du Colombier 	" %.3uo",	" %.3ud",	" %.2ux",
623e12c5d1SDavid du Colombier };
633e12c5d1SDavid du Colombier 
644db25db6SDavid du Colombier char *rfmt[1][1] = {
654db25db6SDavid du Colombier 	" %2.2C",
664db25db6SDavid du Colombier };
674db25db6SDavid du Colombier 
683e12c5d1SDavid du Colombier char *afmt[2][3] = {
693e12c5d1SDavid du Colombier 	"%.7luo ",	"%.7lud ",	"%.7lux ",
703e12c5d1SDavid du Colombier 	"%7luo ",	"%7lud ",	"%7lux ",
713e12c5d1SDavid du Colombier };
723e12c5d1SDavid du Colombier 
733e12c5d1SDavid du Colombier Biobuf	bin;
743e12c5d1SDavid du Colombier Biobuf	bout;
753e12c5d1SDavid du Colombier 
763e12c5d1SDavid du Colombier void
main(int argc,char * argv[])773e12c5d1SDavid du Colombier main(int argc, char *argv[])
783e12c5d1SDavid du Colombier {
793e12c5d1SDavid du Colombier 	int i, err;
803e12c5d1SDavid du Colombier 	Arg *ap;
813e12c5d1SDavid du Colombier 
823e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
833e12c5d1SDavid du Colombier 	err = 0;
84219b2ee8SDavid du Colombier 	ap = 0;
853e12c5d1SDavid du Colombier 	while(argc>1 && argv[1][0]=='-' && argv[1][1]){
863e12c5d1SDavid du Colombier 		--argc;
873e12c5d1SDavid du Colombier 		argv++;
883e12c5d1SDavid du Colombier 		argv[0]++;
893e12c5d1SDavid du Colombier 		if(argv[0][0] == 'r'){
903e12c5d1SDavid du Colombier 			repeats = 1;
913e12c5d1SDavid du Colombier 			if(argv[0][1])
923e12c5d1SDavid du Colombier 				goto Usage;
933e12c5d1SDavid du Colombier 			continue;
943e12c5d1SDavid du Colombier 		}
953e12c5d1SDavid du Colombier 		if(argv[0][0] == 's'){
963e12c5d1SDavid du Colombier 			swizzle = 1;
973e12c5d1SDavid du Colombier 			if(argv[0][1])
983e12c5d1SDavid du Colombier 				goto Usage;
993e12c5d1SDavid du Colombier 			continue;
1003e12c5d1SDavid du Colombier 		}
1013e12c5d1SDavid du Colombier 		if(argv[0][0] == 'u'){
1023e12c5d1SDavid du Colombier 			flush = 1;
1033e12c5d1SDavid du Colombier 			if(argv[0][1])
1043e12c5d1SDavid du Colombier 				goto Usage;
1053e12c5d1SDavid du Colombier 			continue;
1063e12c5d1SDavid du Colombier 		}
1073e12c5d1SDavid du Colombier 		if(argv[0][0] == 'a'){
1083e12c5d1SDavid du Colombier 			argv[0]++;
1093e12c5d1SDavid du Colombier 			switch(argv[0][0]){
1103e12c5d1SDavid du Colombier 			case 'o':
1113e12c5d1SDavid du Colombier 				abase = 0;
1123e12c5d1SDavid du Colombier 				break;
1133e12c5d1SDavid du Colombier 			case 'd':
1143e12c5d1SDavid du Colombier 				abase = 1;
1153e12c5d1SDavid du Colombier 				break;
1163e12c5d1SDavid du Colombier 			case 'x':
1173e12c5d1SDavid du Colombier 				abase = 2;
1183e12c5d1SDavid du Colombier 				break;
1193e12c5d1SDavid du Colombier 			default:
1203e12c5d1SDavid du Colombier 				goto Usage;
1213e12c5d1SDavid du Colombier 			}
1223e12c5d1SDavid du Colombier 			if(argv[0][1])
1233e12c5d1SDavid du Colombier 				goto Usage;
1243e12c5d1SDavid du Colombier 			continue;
1253e12c5d1SDavid du Colombier 		}
1263e12c5d1SDavid du Colombier 		ap = &arg[narg];
1273e12c5d1SDavid du Colombier 		initarg();
1283e12c5d1SDavid du Colombier 		while(argv[0][0]){
1293e12c5d1SDavid du Colombier 			switch(argv[0][0]){
1303e12c5d1SDavid du Colombier 			case 'c':
1314db25db6SDavid du Colombier 				ap->chartype = TAscii;
1324db25db6SDavid du Colombier 				ap->loglen = 0;
1334db25db6SDavid du Colombier 				if(argv[0][1] || argv[0][-1]!='-')
1344db25db6SDavid du Colombier 					goto Usage;
1354db25db6SDavid du Colombier 				break;
1364db25db6SDavid du Colombier 			case 'R':
1374db25db6SDavid du Colombier 				ap->chartype = TRune;
1383e12c5d1SDavid du Colombier 				ap->loglen = 0;
1393e12c5d1SDavid du Colombier 				if(argv[0][1] || argv[0][-1]!='-')
1403e12c5d1SDavid du Colombier 					goto Usage;
1413e12c5d1SDavid du Colombier 				break;
1423e12c5d1SDavid du Colombier 			case 'o':
1433e12c5d1SDavid du Colombier 				ap->base = 0;
1443e12c5d1SDavid du Colombier 				break;
1453e12c5d1SDavid du Colombier 			case 'd':
1463e12c5d1SDavid du Colombier 				ap->base = 1;
1473e12c5d1SDavid du Colombier 				break;
1483e12c5d1SDavid du Colombier 			case 'x':
1493e12c5d1SDavid du Colombier 				ap->base = 2;
1503e12c5d1SDavid du Colombier 				break;
1513e12c5d1SDavid du Colombier 			case 'b':
1523e12c5d1SDavid du Colombier 			case '1':
1533e12c5d1SDavid du Colombier 				ap->loglen = 0;
1543e12c5d1SDavid du Colombier 				break;
1553e12c5d1SDavid du Colombier 			case 'w':
1563e12c5d1SDavid du Colombier 			case '2':
1573e12c5d1SDavid du Colombier 				ap->loglen = 1;
1583e12c5d1SDavid du Colombier 				break;
1593e12c5d1SDavid du Colombier 			case 'l':
1603e12c5d1SDavid du Colombier 			case '4':
1613e12c5d1SDavid du Colombier 				ap->loglen = 2;
1623e12c5d1SDavid du Colombier 				break;
163219b2ee8SDavid du Colombier 			case 'v':
164219b2ee8SDavid du Colombier 			case '8':
165219b2ee8SDavid du Colombier 				ap->loglen = 3;
166219b2ee8SDavid du Colombier 				break;
1673e12c5d1SDavid du Colombier 			default:
1683e12c5d1SDavid du Colombier 			Usage:
169219b2ee8SDavid du Colombier    fprint(2, "usage: xd [-u] [-r] [-s] [-a{odx}] [-c|{b1w2l4v8}{odx}] ... file ...\n");
1703e12c5d1SDavid du Colombier 				exits("usage");
1713e12c5d1SDavid du Colombier 			}
1723e12c5d1SDavid du Colombier 			argv[0]++;
1733e12c5d1SDavid du Colombier 		}
1744db25db6SDavid du Colombier 		if(ap->chartype == TRune)
1754db25db6SDavid du Colombier 			ap->fn = fmtr;
1764db25db6SDavid du Colombier 		else if(ap->chartype == TAscii)
1773e12c5d1SDavid du Colombier 			ap->fn = fmtc;
1783e12c5d1SDavid du Colombier 		else
1793e12c5d1SDavid du Colombier 			ap->fn = fmt[ap->loglen];
1803e12c5d1SDavid du Colombier 		ap->fmt = dfmt[ap->loglen][ap->base];
1813e12c5d1SDavid du Colombier 		ap->afmt = afmt[ap>arg][abase];
1823e12c5d1SDavid du Colombier 	}
1833e12c5d1SDavid du Colombier 	if(narg == 0)
1843e12c5d1SDavid du Colombier 		initarg();
1853e12c5d1SDavid du Colombier 	if(argc == 1)
1863e12c5d1SDavid du Colombier 		err = xd(0, 0);
1873e12c5d1SDavid du Colombier 	else if(argc == 2)
1883e12c5d1SDavid du Colombier 		err = xd(argv[1], 0);
1893e12c5d1SDavid du Colombier 	else for(i=1; i<argc; i++)
1903e12c5d1SDavid du Colombier 		err |= xd(argv[i], 1);
1913e12c5d1SDavid du Colombier 	exits(err? "error" : 0);
1923e12c5d1SDavid du Colombier }
1933e12c5d1SDavid du Colombier 
1943e12c5d1SDavid du Colombier void
initarg(void)1953e12c5d1SDavid du Colombier initarg(void)
1963e12c5d1SDavid du Colombier {
1973e12c5d1SDavid du Colombier 	Arg *ap;
1983e12c5d1SDavid du Colombier 
1993e12c5d1SDavid du Colombier 	ap = &arg[narg++];
2003e12c5d1SDavid du Colombier 	if(narg >= Narg){
2013e12c5d1SDavid du Colombier 		fprint(2, "xd: too many formats (max %d)\n", Narg);
2023e12c5d1SDavid du Colombier 		exits("usage");
2033e12c5d1SDavid du Colombier 	}
2044db25db6SDavid du Colombier 	ap->chartype = TNone;
2053e12c5d1SDavid du Colombier 	ap->loglen = 2;
2063e12c5d1SDavid du Colombier 	ap->base = 2;
2073e12c5d1SDavid du Colombier 	ap->fn = fmt2;
2083e12c5d1SDavid du Colombier 	ap->fmt = dfmt[ap->loglen][ap->base];
2093e12c5d1SDavid du Colombier 	ap->afmt = afmt[narg>1][abase];
2103e12c5d1SDavid du Colombier }
2113e12c5d1SDavid du Colombier 
212*a1e175a1SDavid du Colombier /*
213*a1e175a1SDavid du Colombier  * format the first ndata bytes in data[] (at most Nsee bytes).
214*a1e175a1SDavid du Colombier  * increment addr to account for them.
215*a1e175a1SDavid du Colombier  */
216*a1e175a1SDavid du Colombier void
fmtdata(void)217*a1e175a1SDavid du Colombier fmtdata(void)
218*a1e175a1SDavid du Colombier {
219*a1e175a1SDavid du Colombier 	Arg *ap;
220*a1e175a1SDavid du Colombier 
221*a1e175a1SDavid du Colombier 	for(ap=arg; ap<&arg[narg]; ap++){
222*a1e175a1SDavid du Colombier 		xprint(ap->afmt, addr);
223*a1e175a1SDavid du Colombier 		(*ap->fn)(ap->fmt);
224*a1e175a1SDavid du Colombier 		xprint("\n", 0);
225*a1e175a1SDavid du Colombier 		if(flush)
226*a1e175a1SDavid du Colombier 			Bflush(&bout);
227*a1e175a1SDavid du Colombier 	}
228*a1e175a1SDavid du Colombier 	addr += ndata;
229*a1e175a1SDavid du Colombier 	if(ndata<Nsee){			/* short read? print fragment */
230*a1e175a1SDavid du Colombier 		xprint(afmt[0][abase], addr);
231*a1e175a1SDavid du Colombier 		xprint("\n", 0);
232*a1e175a1SDavid du Colombier 		if(flush)
233*a1e175a1SDavid du Colombier 			Bflush(&bout);
234*a1e175a1SDavid du Colombier 	}
235*a1e175a1SDavid du Colombier }
236*a1e175a1SDavid du Colombier 
2373e12c5d1SDavid du Colombier int
xd(char * name,int title)2383e12c5d1SDavid du Colombier xd(char *name, int title)
2393e12c5d1SDavid du Colombier {
240*a1e175a1SDavid du Colombier 	int fd, star, nleft, doprint;
241219b2ee8SDavid du Colombier 	Biobuf *bp;
2423e12c5d1SDavid du Colombier 
2433e12c5d1SDavid du Colombier 	fd = 0;
244219b2ee8SDavid du Colombier 	if(name){
245219b2ee8SDavid du Colombier 		bp = Bopen(name, OREAD);
246219b2ee8SDavid du Colombier 		if(bp == 0){
2473e12c5d1SDavid du Colombier 			fprint(2, "xd: can't open %s\n", name);
2483e12c5d1SDavid du Colombier 			return 1;
2493e12c5d1SDavid du Colombier 		}
250219b2ee8SDavid du Colombier 	}else{
251219b2ee8SDavid du Colombier 		bp = &bin;
252219b2ee8SDavid du Colombier 		Binit(bp, fd, OREAD);
253219b2ee8SDavid du Colombier 	}
2543e12c5d1SDavid du Colombier 	if(title)
255af2e6ba6SDavid du Colombier 		xprint("%s\n", name);
2563e12c5d1SDavid du Colombier 	addr = 0;
2573e12c5d1SDavid du Colombier 	star = 0;
2584db25db6SDavid du Colombier 	nleft = 0;
259*a1e175a1SDavid du Colombier 	/* read 2*Nsee but see only Nsee so that runes are happy */
260*a1e175a1SDavid du Colombier 	while((ndata=Bread(bp, data + nleft, 2*Nsee - nleft)) >= 0){
2614db25db6SDavid du Colombier 		ndata += nleft;
2624db25db6SDavid du Colombier 		nleft = 0;
2634db25db6SDavid du Colombier 		nread = ndata;
264*a1e175a1SDavid du Colombier 		if(ndata>Nsee)
265*a1e175a1SDavid du Colombier 			ndata = Nsee;
266*a1e175a1SDavid du Colombier 		else if(ndata<Nsee)
267*a1e175a1SDavid du Colombier 			memset(data + ndata, '\0', Nsee - ndata);
2683e12c5d1SDavid du Colombier 		if(swizzle)
2693e12c5d1SDavid du Colombier 			swizz();
270*a1e175a1SDavid du Colombier 		doprint = 1;
271*a1e175a1SDavid du Colombier 		if(ndata==Nsee && repeats)
272*a1e175a1SDavid du Colombier 			if(addr>0 && memcmp(odata, data, Nsee) == 0){
273*a1e175a1SDavid du Colombier 				doprint = 0;
2743e12c5d1SDavid du Colombier 				if(star == 0){
2753e12c5d1SDavid du Colombier 					star++;
2763e12c5d1SDavid du Colombier 					xprint("*\n", 0);
2773e12c5d1SDavid du Colombier 				}
278*a1e175a1SDavid du Colombier 			} else {	/* not a repetition */
279*a1e175a1SDavid du Colombier 				memmove(odata, data, Nsee);
2803e12c5d1SDavid du Colombier 				star = 0;
2813e12c5d1SDavid du Colombier 			}
282*a1e175a1SDavid du Colombier 		if (doprint)
283*a1e175a1SDavid du Colombier 			fmtdata();	/* also increments addr */
284*a1e175a1SDavid du Colombier 		else
285*a1e175a1SDavid du Colombier 			addr += Nsee;
286*a1e175a1SDavid du Colombier 		if(ndata<Nsee)		/* short read? done */
2873e12c5d1SDavid du Colombier 			break;
288*a1e175a1SDavid du Colombier 		if(nread>Nsee){
289*a1e175a1SDavid du Colombier 			nleft = nread - Nsee;
290*a1e175a1SDavid du Colombier 			memmove(data, data + Nsee, nleft);
2914db25db6SDavid du Colombier 		}
2923e12c5d1SDavid du Colombier 	}
293219b2ee8SDavid du Colombier 	Bterm(bp);
2943e12c5d1SDavid du Colombier 	return 0;
2953e12c5d1SDavid du Colombier }
2963e12c5d1SDavid du Colombier 
2973e12c5d1SDavid du Colombier void
swizz(void)2983e12c5d1SDavid du Colombier swizz(void)
2993e12c5d1SDavid du Colombier {
3003e12c5d1SDavid du Colombier 	uchar *p, *q;
3013e12c5d1SDavid du Colombier 	int i;
302*a1e175a1SDavid du Colombier 	uchar swdata[Nsee];
3033e12c5d1SDavid du Colombier 
3043e12c5d1SDavid du Colombier 	p = data;
3053e12c5d1SDavid du Colombier 	q = swdata;
306*a1e175a1SDavid du Colombier 	for(i=0; i<Nsee; i++)
3073e12c5d1SDavid du Colombier 		*q++ = *p++;
3083e12c5d1SDavid du Colombier 	p = data;
3093e12c5d1SDavid du Colombier 	q = swdata;
3103e12c5d1SDavid du Colombier 	for(i=0; i<4; i++){
3113e12c5d1SDavid du Colombier 		p[0] = q[3];
3123e12c5d1SDavid du Colombier 		p[1] = q[2];
3133e12c5d1SDavid du Colombier 		p[2] = q[1];
3143e12c5d1SDavid du Colombier 		p[3] = q[0];
3153e12c5d1SDavid du Colombier 		p += 4;
3163e12c5d1SDavid du Colombier 		q += 4;
3173e12c5d1SDavid du Colombier 	}
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier void
fmt0(char * f)3213e12c5d1SDavid du Colombier fmt0(char *f)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	int i;
3243e12c5d1SDavid du Colombier 	for(i=0; i<ndata; i++)
3253e12c5d1SDavid du Colombier 		xprint(f, data[i]);
3263e12c5d1SDavid du Colombier }
3273e12c5d1SDavid du Colombier 
3283e12c5d1SDavid du Colombier void
fmt1(char * f)3293e12c5d1SDavid du Colombier fmt1(char *f)
3303e12c5d1SDavid du Colombier {
3313e12c5d1SDavid du Colombier 	int i;
3324db25db6SDavid du Colombier 	for(i=0; i<ndata; i+=sizeof(ushort))
3333e12c5d1SDavid du Colombier 		xprint(f, (data[i]<<8)|data[i+1]);
3343e12c5d1SDavid du Colombier }
3353e12c5d1SDavid du Colombier 
3363e12c5d1SDavid du Colombier void
fmt2(char * f)3373e12c5d1SDavid du Colombier fmt2(char *f)
3383e12c5d1SDavid du Colombier {
3393e12c5d1SDavid du Colombier 	int i;
3404db25db6SDavid du Colombier 	for(i=0; i<ndata; i+=sizeof(ulong))
3413e12c5d1SDavid du Colombier 		xprint(f, (data[i]<<24)|(data[i+1]<<16)|(data[i+2]<<8)|data[i+3]);
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3443e12c5d1SDavid du Colombier void
fmt3(char * f)345219b2ee8SDavid du Colombier fmt3(char *f)
346219b2ee8SDavid du Colombier {
347219b2ee8SDavid du Colombier 	int i;
3484db25db6SDavid du Colombier 	uvlong v;
3494db25db6SDavid du Colombier 
3504db25db6SDavid du Colombier 	for(i=0; i<ndata; i+=sizeof(uvlong)){
351219b2ee8SDavid du Colombier 		v = (data[i]<<24)|(data[i+1]<<16)|(data[i+2]<<8)|data[i+3];
352219b2ee8SDavid du Colombier 		v <<= 32;
353219b2ee8SDavid du Colombier 		v |= (data[i+4]<<24)|(data[i+1+4]<<16)|(data[i+2+4]<<8)|data[i+3+4];
354219b2ee8SDavid du Colombier 		if(Bprint(&bout, f, v)<0){
355219b2ee8SDavid du Colombier 			fprint(2, "xd: i/o error\n");
356219b2ee8SDavid du Colombier 			exits("i/o error");
357219b2ee8SDavid du Colombier 		}
358219b2ee8SDavid du Colombier 	}
359219b2ee8SDavid du Colombier }
360219b2ee8SDavid du Colombier 
361219b2ee8SDavid du Colombier void
onefmtc(uchar c)3624db25db6SDavid du Colombier onefmtc(uchar c)
3633e12c5d1SDavid du Colombier {
3644db25db6SDavid du Colombier 	switch(c){
3653e12c5d1SDavid du Colombier 	case '\t':
366af2e6ba6SDavid du Colombier 		xprint(cfmt[1][2], "\\t");
3673e12c5d1SDavid du Colombier 		break;
3683e12c5d1SDavid du Colombier 	case '\r':
369af2e6ba6SDavid du Colombier 		xprint(cfmt[1][2], "\\r");
3703e12c5d1SDavid du Colombier 		break;
3713e12c5d1SDavid du Colombier 	case '\n':
372af2e6ba6SDavid du Colombier 		xprint(cfmt[1][2], "\\n");
3733e12c5d1SDavid du Colombier 		break;
3743e12c5d1SDavid du Colombier 	case '\b':
375af2e6ba6SDavid du Colombier 		xprint(cfmt[1][2], "\\b");
3763e12c5d1SDavid du Colombier 		break;
3773e12c5d1SDavid du Colombier 	default:
3784db25db6SDavid du Colombier 		if(c>=0x7F || ' '>c)
3794db25db6SDavid du Colombier 			xprint(cfmt[2][2], c);
3803e12c5d1SDavid du Colombier 		else
3814db25db6SDavid du Colombier 			xprint(cfmt[0][2], c);
3823e12c5d1SDavid du Colombier 		break;
3833e12c5d1SDavid du Colombier 	}
3843e12c5d1SDavid du Colombier }
3853e12c5d1SDavid du Colombier 
3863e12c5d1SDavid du Colombier void
fmtc(char * f)3874db25db6SDavid du Colombier fmtc(char *f)
3884db25db6SDavid du Colombier {
3894db25db6SDavid du Colombier 	int i;
3904db25db6SDavid du Colombier 
3914db25db6SDavid du Colombier 	USED(f);
3924db25db6SDavid du Colombier 	for(i=0; i<ndata; i++)
3934db25db6SDavid du Colombier 		onefmtc(data[i]);
3944db25db6SDavid du Colombier }
3954db25db6SDavid du Colombier 
3964db25db6SDavid du Colombier void
fmtr(char * f)3974db25db6SDavid du Colombier fmtr(char *f)
3984db25db6SDavid du Colombier {
3994db25db6SDavid du Colombier 	int i, w, cw;
4004db25db6SDavid du Colombier 	Rune r;
4014db25db6SDavid du Colombier 	static int nstart;
4024db25db6SDavid du Colombier 
4034db25db6SDavid du Colombier 	USED(f);
4044db25db6SDavid du Colombier 	if(nstart)
4054db25db6SDavid du Colombier 		xprint("%*c", 3*nstart, ' ');
4064db25db6SDavid du Colombier 	for(i=nstart; i<ndata; )
4074db25db6SDavid du Colombier 		if(data[i] < Runeself)
4084db25db6SDavid du Colombier 			onefmtc(data[i++]);
4094db25db6SDavid du Colombier 		else{
4104db25db6SDavid du Colombier 			w = chartorune(&r, (char *)data+i);
4114db25db6SDavid du Colombier 			if(w == 1 || i + w>nread)
4124db25db6SDavid du Colombier 				onefmtc(data[i++]);
4134db25db6SDavid du Colombier 			else{
4144db25db6SDavid du Colombier 				cw = w;
4154db25db6SDavid du Colombier 				if(i + w>ndata)
4164db25db6SDavid du Colombier 					cw = ndata - i;
4174db25db6SDavid du Colombier 				xprint(rfmt[0][0], r);
4184db25db6SDavid du Colombier 				xprint("%*c", 3*cw-3, ' ');
4194db25db6SDavid du Colombier 				i += w;
4204db25db6SDavid du Colombier 			}
4214db25db6SDavid du Colombier 		}
4224db25db6SDavid du Colombier 	if(i > ndata)
4234db25db6SDavid du Colombier 		nstart = i - ndata;
4244db25db6SDavid du Colombier 	else
4254db25db6SDavid du Colombier 		nstart = 0;
4264db25db6SDavid du Colombier }
4274db25db6SDavid du Colombier 
4284db25db6SDavid du Colombier void
xprint(char * fmt,...)429af2e6ba6SDavid du Colombier xprint(char *fmt, ...)
4303e12c5d1SDavid du Colombier {
431af2e6ba6SDavid du Colombier 	va_list arglist;
432af2e6ba6SDavid du Colombier 
433af2e6ba6SDavid du Colombier 	va_start(arglist, fmt);
434af2e6ba6SDavid du Colombier 	if(Bvprint(&bout, fmt, arglist)<0){
4353e12c5d1SDavid du Colombier 		fprint(2, "xd: i/o error\n");
4363e12c5d1SDavid du Colombier 		exits("i/o error");
4373e12c5d1SDavid du Colombier 	}
438af2e6ba6SDavid du Colombier 	va_end(arglist);
4393e12c5d1SDavid du Colombier }
440