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