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