xref: /plan9-contrib/sys/src/cmd/acid/builtin.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <mach.h>
6 #include <regexp.h>
7 #define Extern extern
8 #include "acid.h"
9 #include "y.tab.h"
10 
11 void	cvtatof(Node*, Node*);
12 void	cvtatoi(Node*, Node*);
13 void	cvtitoa(Node*, Node*);
14 void	bprint(Node*, Node*);
15 void	funcbound(Node*, Node*);
16 void	printto(Node*, Node*);
17 void	getfile(Node*, Node*);
18 void	fmt(Node*, Node*);
19 void	pcfile(Node*, Node*);
20 void	pcline(Node*, Node*);
21 void	setproc(Node*, Node*);
22 void	strace(Node*, Node*);
23 void	follow(Node*, Node*);
24 void	reason(Node*, Node*);
25 void	newproc(Node*, Node*);
26 void	startstop(Node*, Node*);
27 void	match(Node*, Node*);
28 void	status(Node*, Node*);
29 void	kill(Node*,Node*);
30 void	waitstop(Node*, Node*);
31 void	stop(Node*, Node*);
32 void	start(Node*, Node*);
33 void	filepc(Node*, Node*);
34 void	doerror(Node*, Node*);
35 void	rc(Node*, Node*);
36 void	doaccess(Node*, Node*);
37 void	map(Node*, Node*);
38 void	readfile(Node*, Node*);
39 void	interpret(Node*, Node*);
40 void	include(Node*, Node*);
41 void	regexp(Node*, Node*);
42 
43 typedef struct Btab Btab;
44 struct Btab
45 {
46 	char	*name;
47 	void	(*fn)(Node*, Node*);
48 } tab[] =
49 {
50 	"atof",		cvtatof,
51 	"atoi",		cvtatoi,
52 	"error",	doerror,
53 	"file",		getfile,
54 	"readfile",	readfile,
55 	"access",	doaccess,
56 	"filepc",	filepc,
57 	"fnbound",	funcbound,
58 	"fmt",		fmt,
59 	"follow",	follow,
60 	"itoa",		cvtitoa,
61 	"kill",		kill,
62 	"match",	match,
63 	"newproc",	newproc,
64 	"pcfile",	pcfile,
65 	"pcline",	pcline,
66 	"print",	bprint,
67 	"printto",	printto,
68 	"rc",		rc,
69 	"reason",	reason,
70 	"setproc",	setproc,
71 	"start",	start,
72 	"startstop",	startstop,
73 	"status",	status,
74 	"stop",		stop,
75 	"strace",	strace,
76 	"waitstop",	waitstop,
77 	"map",		map,
78 	"interpret",	interpret,
79 	"include",	include,
80 	"regexp",	regexp,
81 	0
82 };
83 
84 void
85 mkprint(Lsym *s)
86 {
87 	prnt = malloc(sizeof(Node));
88 	memset(prnt, 0, sizeof(Node));
89 	prnt->op = OCALL;
90 	prnt->left = malloc(sizeof(Node));
91 	memset(prnt->left, 0, sizeof(Node));
92 	prnt->left->sym = s;
93 }
94 
95 void
96 installbuiltin(void)
97 {
98 	Btab *b;
99 	Lsym *s;
100 
101 	b = tab;
102 	while(b->name) {
103 		s = look(b->name);
104 		if(s == 0)
105 			s = enter(b->name, Tid);
106 
107 		s->builtin = b->fn;
108 		if(b->fn == bprint)
109 			mkprint(s);
110 		b++;
111 	}
112 }
113 
114 void
115 match(Node *r, Node *args)
116 {
117 	int i;
118 	List *f;
119 	Node *av[Maxarg];
120 	Node resi, resl;
121 
122 	na = 0;
123 	flatten(av, args);
124 	if(na != 2)
125 		error("match(obj, list): arg count");
126 
127 	expr(av[1], &resl);
128 	if(resl.type != TLIST)
129 		error("match(obj, list): need list");
130 	expr(av[0], &resi);
131 
132 	r->op = OCONST;
133 	r->type = TINT;
134 	r->fmt = 'D';
135 	r->ival = -1;
136 
137 	i = 0;
138 	for(f = resl.l; f; f = f->next) {
139 		if(resi.type == f->type) {
140 			switch(resi.type) {
141 			case TINT:
142 				if(resi.ival == f->ival) {
143 					r->ival = i;
144 					return;
145 				}
146 				break;
147 			case TFLOAT:
148 				if(resi.fval == f->fval) {
149 					r->ival = i;
150 					return;
151 				}
152 				break;
153 			case TSTRING:
154 				if(scmp(resi.string, f->string)) {
155 					r->ival = i;
156 					return;
157 				}
158 				break;
159 			case TLIST:
160 				error("match(obj, list): not defined for list");
161 			}
162 		}
163 		i++;
164 	}
165 }
166 
167 void
168 newproc(Node *r, Node *args)
169 {
170 	int i;
171 	Node res;
172 	char *p, *e;
173 	char *argv[Maxarg], buf[Strsize];
174 
175 	i = 1;
176 	argv[0] = aout;
177 
178 	if(args) {
179 		expr(args, &res);
180 		if(res.type != TSTRING)
181 			error("newproc(): arg not string");
182 		if(res.string->len >= sizeof(buf))
183 			error("newproc(): too many arguments");
184 		memmove(buf, res.string->string, res.string->len);
185 		buf[res.string->len] = '\0';
186 		p = buf;
187 		e = buf+res.string->len;
188 		for(;;) {
189 			while(p < e && (*p == '\t' || *p == ' '))
190 				*p++ = '\0';
191 			if(p >= e)
192 				break;
193 			argv[i++] = p;
194 			if(i >= Maxarg)
195 				error("newproc: too many arguments");
196 			while(p < e && *p != '\t' && *p != ' ')
197 				p++;
198 		}
199 	}
200 	argv[i] = 0;
201 	r->op = OCONST;
202 	r->type = TINT;
203 	r->fmt = 'D';
204 	r->ival = nproc(argv);
205 }
206 
207 void
208 startstop(Node *r, Node *args)
209 {
210 	Node res;
211 
212 	USED(r);
213 	if(args == 0)
214 		error("startstop(pid): no pid");
215 	expr(args, &res);
216 	if(res.type != TINT)
217 		error("startstop(pid): arg type");
218 
219 	msg(res.ival, "startstop");
220 	notes(res.ival);
221 	dostop(res.ival);
222 }
223 
224 void
225 waitstop(Node *r, Node *args)
226 {
227 	Node res;
228 
229 	USED(r);
230 	if(args == 0)
231 		error("waitstop(pid): no pid");
232 	expr(args, &res);
233 	if(res.type != TINT)
234 		error("waitstop(pid): arg type");
235 
236 	Bflush(bout);
237 	msg(res.ival, "waitstop");
238 	notes(res.ival);
239 	dostop(res.ival);
240 }
241 
242 void
243 start(Node *r, Node *args)
244 {
245 	Node res;
246 
247 	USED(r);
248 	if(args == 0)
249 		error("start(pid): no pid");
250 	expr(args, &res);
251 	if(res.type != TINT)
252 		error("start(pid): arg type");
253 
254 	msg(res.ival, "start");
255 }
256 
257 void
258 stop(Node *r, Node *args)
259 {
260 	Node res;
261 
262 	USED(r);
263 	if(args == 0)
264 		error("stop(pid): no pid");
265 	expr(args, &res);
266 	if(res.type != TINT)
267 		error("stop(pid): arg type");
268 
269 	Bflush(bout);
270 	msg(res.ival, "stop");
271 	notes(res.ival);
272 	dostop(res.ival);
273 }
274 
275 void
276 kill(Node *r, Node *args)
277 {
278 	Node res;
279 
280 	USED(r);
281 	if(args == 0)
282 		error("kill(pid): no pid");
283 	expr(args, &res);
284 	if(res.type != TINT)
285 		error("kill(pid): arg type");
286 
287 	msg(res.ival, "kill");
288 	deinstall(res.ival);
289 }
290 
291 void
292 status(Node *r, Node *args)
293 {
294 	Node res;
295 	char *p;
296 
297 	USED(r);
298 	if(args == 0)
299 		error("status(pid): no pid");
300 	expr(args, &res);
301 	if(res.type != TINT)
302 		error("status(pid): arg type");
303 
304 	p = getstatus(res.ival);
305 	r->string = strnode(p);
306 	r->op = OCONST;
307 	r->fmt = 's';
308 	r->type = TSTRING;
309 }
310 
311 void
312 reason(Node *r, Node *args)
313 {
314 	Node res;
315 
316 	if(args == 0)
317 		error("reason(cause): no cause");
318 	expr(args, &res);
319 	if(res.type != TINT)
320 		error("reason(cause): arg type");
321 
322 	r->op = OCONST;
323 	r->type = TSTRING;
324 	r->fmt = 's';
325 	r->string = strnode((*machdata->excep)(cormap, rget));
326 }
327 
328 void
329 follow(Node *r, Node *args)
330 {
331 	int n, i;
332 	Node res;
333 	ulong f[10];
334 	List **tail, *l;
335 
336 	if(args == 0)
337 		error("follow(addr): no addr");
338 	expr(args, &res);
339 	if(res.type != TINT)
340 		error("follow(addr): arg type");
341 
342 	n = (*machdata->foll)(cormap, res.ival, rget, f);
343 	if (n < 0)
344 		error("follow(addr): %r");
345 	tail = &r->l;
346 	for(i = 0; i < n; i++) {
347 		l = al(TINT);
348 		l->ival = f[i];
349 		l->fmt = 'X';
350 		*tail = l;
351 		tail = &l->next;
352 	}
353 }
354 
355 void
356 funcbound(Node *r, Node *args)
357 {
358 	int n;
359 	Node res;
360 	ulong bounds[2];
361 	List *l;
362 
363 	if(args == 0)
364 		error("fnbound(addr): no addr");
365 	expr(args, &res);
366 	if(res.type != TINT)
367 		error("fnbound(addr): arg type");
368 
369 	n = fnbound(res.ival, bounds);
370 	if (n != 0) {
371 		r->l = al(TINT);
372 		l = r->l;
373 		l->ival = bounds[0];
374 		l->fmt = 'X';
375 		l->next = al(TINT);
376 		l = l->next;
377 		l->ival = bounds[1];
378 		l->fmt = 'X';
379 	}
380 }
381 
382 void
383 setproc(Node *r, Node *args)
384 {
385 	Node res;
386 
387 	USED(r);
388 	if(args == 0)
389 		error("setproc(pid): no pid");
390 	expr(args, &res);
391 	if(res.type != TINT)
392 		error("setproc(pid): arg type");
393 
394 	sproc(res.ival);
395 }
396 
397 void
398 filepc(Node *r, Node *args)
399 {
400 	Node res;
401 	char *p, c;
402 
403 	if(args == 0)
404 		error("filepc(filename:line): arg count");
405 	expr(args, &res);
406 	if(res.type != TSTRING)
407 		error("filepc(filename:line): arg type");
408 
409 	p = strchr(res.string->string, ':');
410 	if(p == 0)
411 		error("filepc(filename:line): bad arg format");
412 
413 	c = *p;
414 	*p++ = '\0';
415 	r->ival = file2pc(res.string->string, atoi(p));
416 	p[-1] = c;
417 	if(r->ival == -1)
418 		error("filepc(filename:line): can't find address");
419 
420 	r->op = OCONST;
421 	r->type = TINT;
422 	r->fmt = 'D';
423 }
424 
425 void
426 interpret(Node *r, Node *args)
427 {
428 	Node res;
429 	int isave;
430 
431 	if(args == 0)
432 		error("interpret(string): arg count");
433 	expr(args, &res);
434 	if(res.type != TSTRING)
435 		error("interpret(string): arg type");
436 
437 	pushstr(&res);
438 
439 	isave = interactive;
440 	interactive = 0;
441 	r->ival = yyparse();
442 	interactive = isave;
443 	popio();
444 	r->op = OCONST;
445 	r->type = TINT;
446 	r->fmt = 'D';
447 }
448 
449 void
450 include(Node *r, Node *args)
451 {
452 	Node res;
453 	int isave;
454 
455 	if(args == 0)
456 		error("include(string): arg count");
457 	expr(args, &res);
458 	if(res.type != TSTRING)
459 		error("include(string): arg type");
460 
461 	pushfile(res.string->string);
462 
463 	isave = interactive;
464 	interactive = 0;
465 	r->ival = yyparse();
466 	interactive = isave;
467 	popio();
468 	r->op = OCONST;
469 	r->type = TINT;
470 	r->fmt = 'D';
471 }
472 
473 void
474 rc(Node *r, Node *args)
475 {
476 	Node res;
477 	int pid;
478 	char *p, *q, *argv[4];
479 	Waitmsg *w;
480 
481 	USED(r);
482 	if(args == 0)
483 		error("error(string): arg count");
484 	expr(args, &res);
485 	if(res.type != TSTRING)
486 		error("error(string): arg type");
487 
488 	argv[0] = "/bin/rc";
489 	argv[1] = "-c";
490 	argv[2] = res.string->string;
491 	argv[3] = 0;
492 
493 	pid = fork();
494 	switch(pid) {
495 	case -1:
496 		error("fork %r");
497 	case 0:
498 		exec("/bin/rc", argv);
499 		exits(0);
500 	default:
501 		w = waitfor(pid);
502 		break;
503 	}
504 	p = w->msg;
505 	q = strrchr(p, ':');
506 	if (q)
507 		p = q+1;
508 
509 	r->op = OCONST;
510 	r->type = TSTRING;
511 	r->string = strnode(p);
512 	free(w);
513 	r->fmt = 's';
514 }
515 
516 void
517 doerror(Node *r, Node *args)
518 {
519 	Node res;
520 
521 	USED(r);
522 	if(args == 0)
523 		error("error(string): arg count");
524 	expr(args, &res);
525 	if(res.type != TSTRING)
526 		error("error(string): arg type");
527 
528 	error(res.string->string);
529 }
530 
531 void
532 doaccess(Node *r, Node *args)
533 {
534 	Node res;
535 
536 	if(args == 0)
537 		error("access(filename): arg count");
538 	expr(args, &res);
539 	if(res.type != TSTRING)
540 		error("access(filename): arg type");
541 
542 	r->op = OCONST;
543 	r->type = TINT;
544 	r->ival = 0;
545 	if(access(res.string->string, 4) == 0)
546 		r->ival = 1;
547 }
548 
549 void
550 readfile(Node *r, Node *args)
551 {
552 	Node res;
553 	int n, fd;
554 	char *buf;
555 	Dir *db;
556 
557 	if(args == 0)
558 		error("readfile(filename): arg count");
559 	expr(args, &res);
560 	if(res.type != TSTRING)
561 		error("readfile(filename): arg type");
562 
563 	fd = open(res.string->string, OREAD);
564 	if(fd < 0)
565 		return;
566 
567 	db = dirfstat(fd);
568 	if(db == nil || db->length == 0)
569 		n = 8192;
570 	else
571 		n = db->length;
572 	free(db);
573 
574 	buf = malloc(n);
575 	n = read(fd, buf, n);
576 
577 	if(n > 0) {
578 		r->op = OCONST;
579 		r->type = TSTRING;
580 		r->string = strnodlen(buf, n);
581 		r->fmt = 's';
582 	}
583 	free(buf);
584 	close(fd);
585 }
586 
587 void
588 getfile(Node *r, Node *args)
589 {
590 	int n;
591 	char *p;
592 	Node res;
593 	String *s;
594 	Biobuf *bp;
595 	List **l, *new;
596 
597 	if(args == 0)
598 		error("file(filename): arg count");
599 	expr(args, &res);
600 	if(res.type != TSTRING)
601 		error("file(filename): arg type");
602 
603 	r->op = OCONST;
604 	r->type = TLIST;
605 	r->l = 0;
606 
607 	p = res.string->string;
608 	bp = Bopen(p, OREAD);
609 	if(bp == 0)
610 		return;
611 
612 	l = &r->l;
613 	for(;;) {
614 		p = Brdline(bp, '\n');
615 		n = Blinelen(bp);
616 		if(p == 0) {
617 			if(n == 0)
618 				break;
619 			s = strnodlen(0, n);
620 			Bread(bp, s->string, n);
621 		}
622 		else
623 			s = strnodlen(p, n-1);
624 
625 		new = al(TSTRING);
626 		new->string = s;
627 		new->fmt = 's';
628 		*l = new;
629 		l = &new->next;
630 	}
631 	Bterm(bp);
632 }
633 
634 void
635 cvtatof(Node *r, Node *args)
636 {
637 	Node res;
638 
639 	if(args == 0)
640 		error("atof(string): arg count");
641 	expr(args, &res);
642 	if(res.type != TSTRING)
643 		error("atof(string): arg type");
644 
645 	r->op = OCONST;
646 	r->type = TFLOAT;
647 	r->fval = atof(res.string->string);
648 	r->fmt = 'f';
649 }
650 
651 void
652 cvtatoi(Node *r, Node *args)
653 {
654 	Node res;
655 
656 	if(args == 0)
657 		error("atoi(string): arg count");
658 	expr(args, &res);
659 	if(res.type != TSTRING)
660 		error("atoi(string): arg type");
661 
662 	r->op = OCONST;
663 	r->type = TINT;
664 	r->ival = strtoul(res.string->string, 0, 0);
665 	r->fmt = 'D';
666 }
667 
668 void
669 cvtitoa(Node *r, Node *args)
670 {
671 	Node res;
672 	Node *av[Maxarg];
673 	int ival;
674 	char buf[128], *fmt;
675 
676 	if(args == 0)
677 err:
678 		error("itoa(number [, printformat]): arg count");
679 	na = 0;
680 	flatten(av, args);
681 	if(na == 0 || na > 2)
682 		goto err;
683 	expr(av[0], &res);
684 	if(res.type != TINT)
685 		error("itoa(integer): arg type");
686 	ival = (int)res.ival;
687 	fmt = "%d";
688 	if(na == 2){
689 		expr(av[1], &res);
690 		if(res.type != TSTRING)
691 			error("itoa(integer, string): arg type");
692 		fmt = res.string->string;
693 	}
694 
695 	sprint(buf, fmt, ival);
696 	r->op = OCONST;
697 	r->type = TSTRING;
698 	r->string = strnode(buf);
699 	r->fmt = 's';
700 }
701 
702 List*
703 mapent(Map *m)
704 {
705 	int i;
706 	List *l, *n, **t, *h;
707 
708 	h = 0;
709 	t = &h;
710 	for(i = 0; i < m->nsegs; i++) {
711 		if(m->seg[i].inuse == 0)
712 			continue;
713 		l = al(TSTRING);
714 		n = al(TLIST);
715 		n->l = l;
716 		*t = n;
717 		t = &n->next;
718 		l->string = strnode(m->seg[i].name);
719 		l->fmt = 's';
720 		l->next = al(TINT);
721 		l = l->next;
722 		l->ival = m->seg[i].b;
723 		l->fmt = 'X';
724 		l->next = al(TINT);
725 		l = l->next;
726 		l->ival = m->seg[i].e;
727 		l->fmt = 'X';
728 		l->next = al(TINT);
729 		l = l->next;
730 		l->ival = m->seg[i].f;
731 		l->fmt = 'X';
732 	}
733 	return h;
734 }
735 
736 void
737 map(Node *r, Node *args)
738 {
739 	int i;
740 	Map *m;
741 	List *l;
742 	char *ent;
743 	Node *av[Maxarg], res;
744 
745 	na = 0;
746 	flatten(av, args);
747 
748 	if(na != 0) {
749 		expr(av[0], &res);
750 		if(res.type != TLIST)
751 			error("map(list): map needs a list");
752 		if(listlen(res.l) != 4)
753 			error("map(list): list must have 4 entries");
754 
755 		l = res.l;
756 		if(l->type != TSTRING)
757 			error("map name must be a string");
758 		ent = l->string->string;
759 		m = symmap;
760 		i = findseg(m, ent);
761 		if(i < 0) {
762 			m = cormap;
763 			i = findseg(m, ent);
764 		}
765 		if(i < 0)
766 			error("%s is not a map entry", ent);
767 		l = l->next;
768 		if(l->type != TINT)
769 			error("map entry not int");
770 		m->seg[i].b = l->ival;
771 		if (strcmp(ent, "text") == 0)
772 			textseg(l->ival, &fhdr);
773 		l = l->next;
774 		if(l->type != TINT)
775 			error("map entry not int");
776 		m->seg[i].e = l->ival;
777 		l = l->next;
778 		if(l->type != TINT)
779 			error("map entry not int");
780 		m->seg[i].f = l->ival;
781 	}
782 
783 	r->type = TLIST;
784 	r->l = 0;
785 	if(symmap)
786 		r->l = mapent(symmap);
787 	if(cormap) {
788 		if(r->l == 0)
789 			r->l = mapent(cormap);
790 		else {
791 			for(l = r->l; l->next; l = l->next)
792 				;
793 			l->next = mapent(cormap);
794 		}
795 	}
796 }
797 
798 void
799 flatten(Node **av, Node *n)
800 {
801 	if(n == 0)
802 		return;
803 
804 	switch(n->op) {
805 	case OLIST:
806 		flatten(av, n->left);
807 		flatten(av, n->right);
808 		break;
809 	default:
810 		av[na++] = n;
811 		if(na >= Maxarg)
812 			error("too many function arguments");
813 		break;
814 	}
815 }
816 
817 void
818 strace(Node *r, Node *args)
819 {
820 	Node *av[Maxarg], *n, res;
821 	ulong pc, sp;
822 
823 	na = 0;
824 	flatten(av, args);
825 	if(na != 3)
826 		error("strace(pc, sp, link): arg count");
827 
828 	n = av[0];
829 	expr(n, &res);
830 	if(res.type != TINT)
831 		error("strace(pc, sp, link): pc bad type");
832 	pc = res.ival;
833 
834 	n = av[1];
835 	expr(n, &res);
836 	if(res.type != TINT)
837 		error("strace(pc, sp, link): sp bad type");
838 	sp = res.ival;
839 
840 	n = av[2];
841 	expr(n, &res);
842 	if(res.type != TINT)
843 		error("strace(pc, sp, link): link bad type");
844 
845 	tracelist = 0;
846 	if ((*machdata->ctrace)(cormap, pc, sp, res.ival, trlist) <= 0)
847 		error("no stack frame");
848 	r->type = TLIST;
849 	r->l = tracelist;
850 }
851 
852 void
853 regerror(char *msg)
854 {
855 	error(msg);
856 }
857 
858 void
859 regexp(Node *r, Node *args)
860 {
861 	Node res;
862 	Reprog *rp;
863 	Node *av[Maxarg];
864 
865 	na = 0;
866 	flatten(av, args);
867 	if(na != 2)
868 		error("regexp(pattern, string): arg count");
869 	expr(av[0], &res);
870 	if(res.type != TSTRING)
871 		error("regexp(pattern, string): pattern must be string");
872 	rp = regcomp(res.string->string);
873 	if(rp == 0)
874 		return;
875 
876 	expr(av[1], &res);
877 	if(res.type != TSTRING)
878 		error("regexp(pattern, string): bad string");
879 
880 	r->fmt = 'D';
881 	r->type = TINT;
882 	r->ival = regexec(rp, res.string->string, 0, 0);
883 	free(rp);
884 }
885 
886 char vfmt[] = "aBbcCdDfFgGiIoOqQrRsuUVxXYZ";
887 
888 void
889 fmt(Node *r, Node *args)
890 {
891 	Node res;
892 	Node *av[Maxarg];
893 
894 	na = 0;
895 	flatten(av, args);
896 	if(na != 2)
897 		error("fmt(obj, fmt): arg count");
898 	expr(av[1], &res);
899 	if(res.type != TINT || strchr(vfmt, res.ival) == 0)
900 		error("fmt(obj, fmt): bad format '%c'", (char)res.ival);
901 	expr(av[0], r);
902 	r->fmt = res.ival;
903 }
904 
905 void
906 patom(char type, Store *res)
907 {
908 	int i;
909 	char buf[512];
910 	extern char *typenames[];
911 
912 	switch(res->fmt) {
913 	case 'c':
914 		Bprint(bout, "%c", (int)res->ival);
915 		break;
916 	case 'C':
917 		if(res->ival < ' ' || res->ival >= 0x7f)
918 			Bprint(bout, "%3d", (int)res->ival&0xff);
919 		else
920 			Bprint(bout, "%3c", (int)res->ival);
921 		break;
922 	case 'r':
923 		Bprint(bout, "%C", (int)res->ival);
924 		break;
925 	case 'B':
926 		memset(buf, '0', 34);
927 		buf[1] = 'b';
928 		for(i = 0; i < 32; i++) {
929 			if(res->ival & (1<<i))
930 				buf[33-i] = '1';
931 		}
932 		buf[35] = '\0';
933 		Bprint(bout, "%s", buf);
934 		break;
935 	case 'b':
936 		Bprint(bout, "%#.2x", (int)res->ival&0xff);
937 		break;
938 	case 'X':
939 		Bprint(bout, "%.8lux", (ulong)res->ival);
940 		break;
941 	case 'x':
942 		Bprint(bout, "%.4lux", (ulong)res->ival&0xffff);
943 		break;
944 	case 'W':
945 		Bprint(bout, "%.16llux", res->ival);
946 		break;
947 	case 'D':
948 		Bprint(bout, "%d", (int)res->ival);
949 		break;
950 	case 'd':
951 		Bprint(bout, "%d", (ushort)res->ival);
952 		break;
953 	case 'u':
954 		Bprint(bout, "%d", (int)res->ival&0xffff);
955 		break;
956 	case 'U':
957 		Bprint(bout, "%lud", (ulong)res->ival);
958 		break;
959 	case 'Z':
960 		Bprint(bout, "%llud", res->ival);
961 		break;
962 	case 'V':
963 		Bprint(bout, "%lld", res->ival);
964 		break;
965 	case 'Y':
966 		Bprint(bout, "%.16llux", res->ival);
967 		break;
968 	case 'o':
969 		Bprint(bout, "0%.11uo", (int)res->ival&0xffff);
970 		break;
971 	case 'O':
972 		Bprint(bout, "0%.6uo", (int)res->ival);
973 		break;
974 	case 'q':
975 		Bprint(bout, "0%.11o", (short)(res->ival&0xffff));
976 		break;
977 	case 'Q':
978 		Bprint(bout, "0%.6o", (int)res->ival);
979 		break;
980 	case 'f':
981 	case 'F':
982 		if(type != TFLOAT)
983 			Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
984 		else
985 			Bprint(bout, "%g", res->fval);
986 		break;
987 	case 's':
988 	case 'g':
989 	case 'G':
990 		if(type != TSTRING)
991 			Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
992 		else
993 			Bwrite(bout, res->string->string, res->string->len);
994 		break;
995 	case 'R':
996 		if(type != TSTRING)
997 			Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
998 		else
999 			Bprint(bout, "%S", (Rune*)res->string->string);
1000 		break;
1001 	case 'a':
1002 	case 'A':
1003 		symoff(buf, sizeof(buf), res->ival, CANY);
1004 		Bprint(bout, "%s", buf);
1005 		break;
1006 	case 'I':
1007 	case 'i':
1008 		if(type != TINT)
1009 			Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
1010 		else {
1011 			if (symmap == nil || (*machdata->das)(symmap, res->ival, res->fmt, buf, sizeof(buf)) < 0)
1012 				Bprint(bout, "no instruction");
1013 			else
1014 				Bprint(bout, "%s", buf);
1015 		}
1016 		break;
1017 	}
1018 }
1019 
1020 void
1021 blprint(List *l)
1022 {
1023 	Bprint(bout, "{");
1024 	while(l) {
1025 		switch(l->type) {
1026 		default:
1027 			patom(l->type, &l->Store);
1028 			break;
1029 		case TSTRING:
1030 			Bputc(bout, '"');
1031 			patom(l->type, &l->Store);
1032 			Bputc(bout, '"');
1033 			break;
1034 		case TLIST:
1035 			blprint(l->l);
1036 			break;
1037 		case TCODE:
1038 			pcode(l->cc, 0);
1039 			break;
1040 		}
1041 		l = l->next;
1042 		if(l)
1043 			Bprint(bout, ", ");
1044 	}
1045 	Bprint(bout, "}");
1046 }
1047 
1048 int
1049 comx(Node res)
1050 {
1051 	Lsym *sl;
1052 	Node *n, xx;
1053 
1054 	if(res.fmt != 'a' && res.fmt != 'A')
1055 		return 0;
1056 
1057 	if(res.comt == 0 || res.comt->base == 0)
1058 		return 0;
1059 
1060 	sl = res.comt->base;
1061 	if(sl->proc) {
1062 		res.left = ZN;
1063 		res.right = ZN;
1064 		n = an(ONAME, ZN, ZN);
1065 		n->sym = sl;
1066 		n = an(OCALL, n, &res);
1067 			n->left->sym = sl;
1068 		expr(n, &xx);
1069 		return 1;
1070 	}
1071 	print("(%s)", sl->name);
1072 	return 0;
1073 }
1074 
1075 void
1076 bprint(Node *r, Node *args)
1077 {
1078 	int i, nas;
1079 	Node res, *av[Maxarg];
1080 
1081 	USED(r);
1082 	na = 0;
1083 	flatten(av, args);
1084 	nas = na;
1085 	for(i = 0; i < nas; i++) {
1086 		expr(av[i], &res);
1087 		switch(res.type) {
1088 		default:
1089 			if(comx(res))
1090 				break;
1091 			patom(res.type, &res.Store);
1092 			break;
1093 		case TCODE:
1094 			pcode(res.cc, 0);
1095 			break;
1096 		case TLIST:
1097 			blprint(res.l);
1098 			break;
1099 		}
1100 	}
1101 	if(ret == 0)
1102 		Bputc(bout, '\n');
1103 }
1104 
1105 void
1106 printto(Node *r, Node *args)
1107 {
1108 	int fd;
1109 	Biobuf *b;
1110 	int i, nas;
1111 	Node res, *av[Maxarg];
1112 
1113 	USED(r);
1114 	na = 0;
1115 	flatten(av, args);
1116 	nas = na;
1117 
1118 	expr(av[0], &res);
1119 	if(res.type != TSTRING)
1120 		error("printto(string, ...): need string");
1121 
1122 	fd = create(res.string->string, OWRITE, 0666);
1123 	if(fd < 0)
1124 		fd = open(res.string->string, OWRITE);
1125 	if(fd < 0)
1126 		error("printto: open %s: %r", res.string->string);
1127 
1128 	b = gmalloc(sizeof(Biobuf));
1129 	Binit(b, fd, OWRITE);
1130 
1131 	Bflush(bout);
1132 	io[iop++] = bout;
1133 	bout = b;
1134 
1135 	for(i = 1; i < nas; i++) {
1136 		expr(av[i], &res);
1137 		switch(res.type) {
1138 		default:
1139 			if(comx(res))
1140 				break;
1141 			patom(res.type, &res.Store);
1142 			break;
1143 		case TLIST:
1144 			blprint(res.l);
1145 			break;
1146 		}
1147 	}
1148 	if(ret == 0)
1149 		Bputc(bout, '\n');
1150 
1151 	Bterm(b);
1152 	close(fd);
1153 	free(b);
1154 	bout = io[--iop];
1155 }
1156 
1157 void
1158 pcfile(Node *r, Node *args)
1159 {
1160 	Node res;
1161 	char *p, buf[128];
1162 
1163 	if(args == 0)
1164 		error("pcfile(addr): arg count");
1165 	expr(args, &res);
1166 	if(res.type != TINT)
1167 		error("pcfile(addr): arg type");
1168 
1169 	r->type = TSTRING;
1170 	r->fmt = 's';
1171 	if(fileline(buf, sizeof(buf), res.ival) == 0) {
1172 		r->string = strnode("?file?");
1173 		return;
1174 	}
1175 	p = strrchr(buf, ':');
1176 	if(p == 0)
1177 		error("pcfile(addr): funny file %s", buf);
1178 	*p = '\0';
1179 	r->string = strnode(buf);
1180 }
1181 
1182 void
1183 pcline(Node *r, Node *args)
1184 {
1185 	Node res;
1186 	char *p, buf[128];
1187 
1188 	if(args == 0)
1189 		error("pcline(addr): arg count");
1190 	expr(args, &res);
1191 	if(res.type != TINT)
1192 		error("pcline(addr): arg type");
1193 
1194 	r->type = TINT;
1195 	r->fmt = 'D';
1196 	if(fileline(buf, sizeof(buf), res.ival) == 0) {
1197 		r->ival = 0;
1198 		return;
1199 	}
1200 
1201 	p = strrchr(buf, ':');
1202 	if(p == 0)
1203 		error("pcline(addr): funny file %s", buf);
1204 	r->ival = atoi(p+1);
1205 }
1206