xref: /inferno-os/utils/rcsh/simple.c (revision f1dcfd03b4648fd6c0221d14436b391cd368beac)
1 #include "rc.h"
2 
3 typedef struct Builtin	Builtin;
4 
5 struct Builtin
6 {
7 	char	*name;
8 	void	(*fnc)(void);
9 };
10 
11 int	exitnext(void);
12 void	execexec(void);
13 void	execfunc(Var *func);
14 void	execcd(void);
15 void	execwhatis(void);
16 void	execeval(void);
17 void	execexit(void);
18 void	execshift(void);
19 void	execwait(void);
20 void	execdot(void);
21 void	execflag(void);
22 
23 Builtin builtin[]={
24 	"cd",		execcd,
25 	"whatis",	execwhatis,
26 	"eval",		execeval,
27 	"exec",		execexec,	/* but with popword first */
28 	"exit",		execexit,
29 	"shift",	execshift,
30 	"wait",		execwait,
31 	".",		execdot,
32 	"flag",		execflag,
33 	0
34 };
35 
36 int	mapfd(int fd);
37 
38 void
39 Xsimple(void)
40 {
41 	Word *a;
42 	Thread *p=runq;
43 	Var *v;
44 	Builtin *bp;
45 	uint pid;
46 	char **argv;
47 
48 	globlist();
49 	a=runq->argv->words;
50 	if(a==0){
51 		Xerror("empty argument list");
52 		return;
53 	}
54 	if(flag['x'])
55 		pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
56 
57 	v=gvlook(a->word);
58 	if(v->fn)
59 		execfunc(v);
60 	else{
61 		if(strcmp(a->word, "builtin")==0){
62 			if(count(a)==1){
63 				pfmt(err, "builtin: empty argument list\n");
64 				setstatus("empty arg list");
65 				poplist();
66 				return;
67 			}
68 			a=a->next;
69 			popword();
70 		}
71 		for(bp=builtin;bp->name;bp++) {
72 			if(strcmp(a->word, bp->name)==0){
73 				(*bp->fnc)();
74 				return;
75 			}
76 		}
77 
78 		updenv();
79 		argv = procargv(0, 0, 0, 0, runq->argv->words);
80 		pid = proc(argv, mapfd(0), mapfd(1), mapfd(2));
81 		free(argv);
82 
83 		if(pid == 0)
84 			pfmt(err, "%s: %r\n", runq->argv->words->word);
85 		else
86 			waitfor(pid);
87 		poplist();
88 #ifdef XXX
89 		if(exitnext()){
90 			/* fork and wait is redundant */
91 			pushword("exec");
92 			execexec();
93 			Xexit();
94 		}
95 		else{
96 			flush(err);
97 			updenv();
98 			switch(pid=fork()){
99 			case -1:
100 				Xperror("try again");
101 				return;
102 			case 0:
103 				pushword("exec");
104 				execexec();
105 				Exit("can't exec");
106 			default:
107 				poplist();
108 				/* interrupts don't get us out */
109 				while(Waitfor(pid, 1) < 0)
110 					;
111 			}
112 		}
113 #endif
114 	}
115 }
116 
117 Word nullpath={ "", 0};
118 
119 Word *
120 searchpath(char *w)
121 {
122 	Word *path;
123 
124 	return &nullpath;
125 
126 	if(strncmp(w, "/", 1) == 0
127 	|| strncmp(w, "#", 1) == 0
128 	|| *w && w[1] == ':'
129 	|| strncmp(w, "./", 2) == 0
130 	|| strncmp(w, "../", 3) == 0
131 	|| (path=vlook("path")->val) == 0)
132 		path=&nullpath;
133 	return path;
134 }
135 
136 /*
137  * Search through the following code to see if we're just going to exit.
138  */
139 int
140 exitnext(void)
141 {
142 	Code *c=&runq->code[runq->pc];
143 
144 	while(c->f==Xpopredir)
145 		c++;
146 	return c->f==Xexit;
147 }
148 
149 #ifdef XXX
150 
151 void
152 doredir(Redir *rp)
153 {
154 	if(rp){
155 		doredir(rp->next);
156 		switch(rp->type){
157 		case ROPEN:
158 			if(rp->from!=rp->to){
159 				Dup(rp->from, rp->to);
160 				close(rp->from);
161 			}
162 			break;
163 		case RDUP: Dup(rp->from, rp->to); break;
164 		case RCLOSE: close(rp->from); break;
165 		}
166 	}
167 }
168 
169 
170 #endif
171 
172 void
173 execexec(void)
174 {
175 	popword();	/* "exec" */
176 	if(runq->argv->words==0){
177 		Xerror("empty argument list");
178 		return;
179 	}
180 	fatal("execexec not done yet");
181 /*
182 	doredir(runq->redir);
183 	Execute(runq->argv->words, searchpath(runq->argv->words->word));
184 */
185 
186 	poplist();
187 }
188 
189 void
190 execfunc(Var *func)
191 {
192 	Word *starval;
193 
194 	popword();
195 	starval=runq->argv->words;
196 	runq->argv->words=0;
197 	poplist();
198 	start(func->fn, func->pc, runq->local);
199 	runq->local=newvar(strdup("*"), runq->local);
200 	runq->local->val=starval;
201 	runq->local->changed=1;
202 }
203 
204 void
205 execcd(void)
206 {
207 	Word *a=runq->argv->words;
208 	Word *cdpath;
209 	char dir[512];
210 
211 	setstatus("can't cd");
212 	cdpath=vlook("cdpath")->val;
213 	switch(count(a)){
214 	default:
215 		pfmt(err, "Usage: cd [directory]\n");
216 		break;
217 	case 2:
218 		if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
219 		for(;cdpath;cdpath=cdpath->next){
220 			strcpy(dir, cdpath->word);
221 			if(dir[0]) strcat(dir, "/");
222 			strcat(dir, a->next->word);
223 			if(chdir(dir)>=0){
224 				if(strlen(cdpath->word)
225 				&& strcmp(cdpath->word, ".")!=0)
226 					pfmt(err, "%s\n", dir);
227 				setstatus("");
228 				break;
229 			}
230 		}
231 		if(cdpath==0) pfmt(err, "Can't cd %s\n", a->next->word);
232 		break;
233 	case 1:
234 		a=vlook("home")->val;
235 		if(count(a)>=1){
236 			if(chdir(a->word)>=0)
237 				setstatus("");
238 			else
239 				pfmt(err, "Can't cd %s\n", a->word);
240 		}
241 		else
242 			pfmt(err, "Can't cd -- $home empty\n");
243 		break;
244 	}
245 	poplist();
246 }
247 
248 void
249 execexit(void)
250 {
251 	switch(count(runq->argv->words)){
252 	default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
253 	case 2: setstatus(runq->argv->words->next->word);
254 	case 1:	Xexit();
255 	}
256 }
257 
258 void
259 execflag(void)
260 {
261 	char *letter, *val;
262 	switch(count(runq->argv->words)){
263 	case 2:
264 		setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
265 		break;
266 	case 3:
267 		letter=runq->argv->words->next->word;
268 		val=runq->argv->words->next->next->word;
269 		if(strlen(letter)==1){
270 			if(strcmp(val, "+")==0){
271 				flag[letter[0]]=1;
272 				break;
273 			}
274 			if(strcmp(val, "-")==0){
275 				flag[letter[0]]=0;
276 				break;
277 			}
278 		}
279 	default:
280 		Xerror("Usage: flag [letter] [+-]");
281 		return;
282 	}
283 	poplist();
284 }
285 
286 void
287 execshift(void)
288 {
289 	int n;
290 	Word *a;
291 	Var *star;
292 	switch(count(runq->argv->words)){
293 	default:
294 		pfmt(err, "Usage: shift [n]\n");
295 		setstatus("shift usage");
296 		poplist();
297 		return;
298 	case 2: n=atoi(runq->argv->words->next->word); break;
299 	case 1: n=1; break;
300 	}
301 	star=vlook("*");
302 	for(;n && star->val;--n){
303 		a=star->val->next;
304 		free(star->val->word);
305 		free(star->val);
306 		star->val=a;
307 		star->changed=1;
308 	}
309 	setstatus("");
310 	poplist();
311 }
312 
313 int
314 octal(char *s)
315 {
316 	int n=0;
317 	while(*s==' ' || *s=='\t' || *s=='\n') s++;
318 	while('0'<=*s && *s<='7') n=n*8+*s++-'0';
319 	return n;
320 }
321 
322 void
323 execeval(void)
324 {
325 	char *cmdline, *s, *t;
326 	int len=0;
327 	Word *ap;
328 
329 	if(count(runq->argv->words)<=1){
330 		Xerror("Usage: eval cmd ...");
331 		return;
332 	}
333 	eflagok=1;
334 	for(ap=runq->argv->words->next;ap;ap=ap->next)
335 		len+=1+strlen(ap->word);
336 	cmdline=malloc(len);
337 	s=cmdline;
338 	for(ap=runq->argv->words->next;ap;ap=ap->next){
339 		for(t=ap->word;*t;) *s++=*t++;
340 		*s++=' ';
341 	}
342 	s[-1]='\n';
343 	poplist();
344 	execcmds(opencore(cmdline, len));
345 	free(cmdline);
346 }
347 
348 void
349 execdot(void)
350 {
351 	int iflag=0;
352 	int fd;
353 	List *av;
354 	Thread *p=runq;
355 	char *zero;
356 	char file[512];
357 	Word *path;
358 	static int first=1;
359 	static Code dotcmds[14];
360 
361 	if(first) {
362 		dotcmds[0].i=1;
363 		dotcmds[1].f=Xmark;
364 		dotcmds[2].f=Xword;
365 		dotcmds[3].s="0";
366 		dotcmds[4].f=Xlocal;
367 		dotcmds[5].f=Xmark;
368 		dotcmds[6].f=Xword;
369 		dotcmds[7].s="*";
370 		dotcmds[8].f=Xlocal;
371 		dotcmds[9].f=Xrdcmds;
372 		dotcmds[10].f=Xunlocal;
373 		dotcmds[11].f=Xunlocal;
374 		dotcmds[12].f=Xreturn;
375 		first=0;
376 	} else
377 		eflagok=1;
378 	popword();
379 	if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
380 		iflag=1;
381 		popword();
382 	}
383 	/* get input file */
384 	if(p->argv->words==0){
385 		Xerror("Usage: . [-i] file [arg ...]");
386 		return;
387 	}
388 	zero=strdup(p->argv->words->word);
389 	popword();
390 	strcpy(file, "**No file name**");
391 	fd = -1;
392 	if(strcmp(zero, "stdin$") == 0)
393 		fd = dup(0);
394 	else{
395 		for(path=searchpath(zero);path;path=path->next){
396 			strcpy(file, path->word);
397 			if(file[0])
398 				strcat(file, "/");
399 			strcat(file, zero);
400 			if((fd=open(file, 0))>=0)
401 				break;
402 		}
403 	}
404 	if(fd<0){
405 		Xperror(file);
406 		return;
407 	}
408 	/* set up for a new command loop */
409 	start(dotcmds, 1, 0);
410 	pushredir(RCLOSE, fd, 0);
411 	runq->cmdfile=zero;
412 	runq->cmdfd=openfd(fd);
413 	runq->iflag=iflag;
414 	runq->iflast=0;
415 	/* push $* value */
416 	pushlist();
417 	runq->argv->words=p->argv->words;
418 	/* free caller's copy of $* */
419 	av=p->argv;
420 	p->argv=av->next;
421 	free(av);
422 	/* push $0 value */
423 	pushlist();
424 	pushword(zero);
425 	ndot++;
426 }
427 
428 void
429 execwhatis(void)
430 {	/* mildly wrong -- should fork before writing */
431 	Word *a, *b, *path;
432 	Var *v;
433 	Builtin *bp;
434 	char file[512];
435 	Io out[1];
436 	int found, sep;
437 
438 	a=runq->argv->words->next;
439 	if(a==0){
440 		Xerror("Usage: whatis name ...");
441 		return;
442 	}
443 	setstatus("");
444 	out->fd=mapfd(1);
445 	out->bufp=out->buf;
446 	out->ebuf=&out->buf[NBUF];
447 	out->strp=0;
448 	for(;a;a=a->next){
449 		v=vlook(a->word);
450 		if(v->val){
451 			pfmt(out, "%s=", a->word);
452 			if(v->val->next==0)
453 				pfmt(out, "%q\n", v->val->word);
454 			else{
455 				sep='(';
456 				for(b=v->val;b && b->word;b=b->next){
457 					pfmt(out, "%c%q", sep, b->word);
458 					sep=' ';
459 				}
460 				pfmt(out, ")\n");
461 			}
462 			found=1;
463 		}
464 		else
465 			found=0;
466 		v=gvlook(a->word);
467 		if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
468 		else{
469 			for(bp=builtin;bp->name;bp++)
470 				if(strcmp(a->word, bp->name)==0){
471 					pfmt(out, "builtin %s\n", a->word);
472 					break;
473 				}
474 			if(!bp->name){
475 				for(path=searchpath(a->word);path;path=path->next){
476 					strcpy(file, path->word);
477 					if(file[0]) strcat(file, "/");
478 					strcat(file, a->word);
479 #ifdef XXX
480 					if(Executable(file)){
481 						pfmt(out, "%s\n", file);
482 						break;
483 					}
484 #endif
485 				}
486 				if(!path && !found){
487 					pfmt(err, "%s: not found\n", a->word);
488 					setstatus("not found");
489 				}
490 			}
491 		}
492 	}
493 	poplist();
494 	flush(err);
495 }
496 
497 void
498 execwait(void)
499 {
500 	fprint(2, "wait: not done yet");
501 
502 #ifdef XXX
503 	switch(count(runq->argv->words)){
504 	default: Xerror("Usage: wait [pid]"); return;
505 	case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
506 	case 1: Waitfor(-1, 0); break;
507 	}
508 	poplist();
509 #endif
510 }
511 
512 int
513 mapfd(int fd)
514 {
515 	Redir *rp;
516 	for(rp=runq->redir;rp;rp=rp->next){
517 		switch(rp->type){
518 		case RCLOSE:
519 			if(rp->from==fd) fd=-1;
520 			break;
521 		case RDUP:
522 		case ROPEN:
523 			if(rp->to==fd) fd=rp->from;
524 			break;
525 		}
526 	}
527 	return fd;
528 }
529