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
Xsimple(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 *
searchpath(char * w)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
exitnext(void)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
doredir(Redir * rp)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
execexec(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
execfunc(Var * func)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
execcd(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
execexit(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
execflag(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
execshift(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
octal(char * s)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
execeval(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
execdot(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
execwhatis(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
execwait(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
mapfd(int fd)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