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