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