1 #include "rc.h"
2 #include "exec.h"
3 #include "io.h"
4 #include "fns.h"
5
6 char flagset[] = "<flag>"; /* anything non-nil will do */
7 char *flag[NFLAG];
8
9 /*
10 * Start executing the given code at the given pc with the given redirection
11 */
12 char *argv0;
13
14 void
start(code * c,int pc,var * local)15 start(code *c, int pc, var *local)
16 {
17 struct thread *p = new(struct thread);
18
19 p->code = codecopy(c);
20 p->pc = pc;
21 p->argv = 0;
22 p->redir = p->startredir = runq?runq->redir:0;
23 p->local = local;
24 p->cmdfile = 0;
25 p->cmdfd = 0;
26 p->eof = 0;
27 p->iflag = 0;
28 p->lineno = 1;
29 p->ret = runq;
30 runq = p;
31 }
32
33 word*
newword(char * wd,word * next)34 newword(char *wd, word *next)
35 {
36 word *p = new(word);
37 p->word = strdup(wd);
38 p->next = next;
39 return p;
40 }
41
42 void
pushword(char * wd)43 pushword(char *wd)
44 {
45 if(runq->argv==0)
46 panic("pushword but no argv!", 0);
47 runq->argv->words = newword(wd, runq->argv->words);
48 }
49
50 void
popword(void)51 popword(void)
52 {
53 word *p;
54 if(runq->argv==0)
55 panic("popword but no argv!", 0);
56 p = runq->argv->words;
57 if(p==0)
58 panic("popword but no word!", 0);
59 runq->argv->words = p->next;
60 efree(p->word);
61 efree((char *)p);
62 }
63
64 void
freelist(word * w)65 freelist(word *w)
66 {
67 word *nw;
68 while(w){
69 nw = w->next;
70 efree(w->word);
71 efree((char *)w);
72 w = nw;
73 }
74 }
75
76 void
pushlist(void)77 pushlist(void)
78 {
79 list *p = new(list);
80 p->next = runq->argv;
81 p->words = 0;
82 runq->argv = p;
83 }
84
85 void
poplist(void)86 poplist(void)
87 {
88 list *p = runq->argv;
89 if(p==0)
90 panic("poplist but no argv", 0);
91 freelist(p->words);
92 runq->argv = p->next;
93 efree((char *)p);
94 }
95
96 int
count(word * w)97 count(word *w)
98 {
99 int n;
100 for(n = 0;w;n++) w = w->next;
101 return n;
102 }
103
104 void
pushredir(int type,int from,int to)105 pushredir(int type, int from, int to)
106 {
107 redir * rp = new(redir);
108 rp->type = type;
109 rp->from = from;
110 rp->to = to;
111 rp->next = runq->redir;
112 runq->redir = rp;
113 }
114
115 void
shuffleredir(void)116 shuffleredir(void)
117 {
118 redir **rr, *rp;
119
120 rp = runq->redir;
121 if(rp==0)
122 return;
123 runq->redir = rp->next;
124 rp->next = runq->startredir;
125 for(rr = &runq->redir; *rr != rp->next; rr = &((*rr)->next))
126 ;
127 *rr = rp;
128 }
129
130 var*
newvar(char * name,var * next)131 newvar(char *name, var *next)
132 {
133 var *v = new(var);
134
135 assert(name != nil);
136 v->name = name;
137 v->val = 0;
138 v->fn = 0;
139 v->changed = 0;
140 v->fnchanged = 0;
141 v->next = next;
142 return v;
143 }
144
145 /* fabricate bootstrap code (*=(argv);. /rc/lib/rcmain $*; exit) */
146 static void
loadboot(code * base,int nel,char * rcmain)147 loadboot(code *base, int nel, char *rcmain)
148 {
149 code *bs;
150
151 bs = base;
152 bs++->i = 1; /* reference count */
153 bs++->f = Xmark; /* "* = $*" */
154 bs++->f = Xword;
155 bs++->s="*";
156 bs++->f = Xassign;
157 bs++->f = Xmark;
158 bs++->f = Xmark;
159 bs++->f = Xword;
160 bs++->s="*";
161 bs++->f = Xdol;
162 bs++->f = Xword;
163 bs++->s = rcmain; /* ". /rc/lib/rcmain $*" */
164 bs++->f = Xword;
165 bs++->s=".";
166 bs++->f = Xsimple;
167 bs++->f = Xexit; /* exit */
168 bs++->i = 0; /* not reached */
169 if (bs > base + nel)
170 panic("bootstrap array too small", 0);
171 }
172
173 void
usage(void)174 usage(void)
175 {
176 pfmt(err, "Usage: rc [-srdiIlxepvV] [-c arg] [-m command] "
177 "[file [arg ...]]\n");
178 Exit("bad flags");
179 }
180
181 /*
182 * get command line flags, initialize keywords & traps.
183 * get values from environment.
184 * set $pid, $cflag, $*
185 * fabricate bootstrap code and start it
186 * start interpreting code
187 */
188 void
main(int argc,char * argv[])189 main(int argc, char *argv[])
190 {
191 code bootstrap[17];
192 char num[12];
193 int i;
194
195 err = openfd(2);
196 ARGBEGIN {
197 case 'd': case 'e': case 'i': case 'l':
198 case 'p': case 'r': case 's': case 'v':
199 case 'x': case 'I': case 'V':
200 flag[ARGC()] = flagset;
201 break;
202 case 'c':
203 case 'm':
204 if (flag[ARGC()])
205 usage();
206 flag[ARGC()] = EARGF(usage());
207 break;
208 default:
209 usage();
210 break;
211 } ARGEND
212 if(argc < 0)
213 usage();
214 if(argv0 == nil)
215 argv0 = "rc";
216 if(argv0[0]=='-') /* login shell? */
217 flag['l'] = flagset;
218 if(flag['I'])
219 flag['i'] = 0;
220 else if(flag['i']==0 && argc==0 && Isatty(0))
221 flag['i'] = flagset; /* force interactive */
222
223 kinit();
224 Trapinit();
225 Vinit();
226 inttoascii(num, mypid = getpid());
227 setvar("pid", newword(num, (word *)0));
228 setvar("cflag", flag['c']? newword(flag['c'], (word *)0): (word *)0);
229 setvar("rcname", newword(argv0, (word *)0));
230
231 loadboot(bootstrap, nelem(bootstrap), (flag['m']? flag['m']: Rcmain));
232 start(bootstrap, 1, (var *)0);
233 /* prime bootstrap argv */
234 pushlist();
235 for(i = argc-1; i >= 0; --i)
236 pushword(argv[i]);
237 for(;;){
238 if(flag['r'])
239 pfnc(err, runq);
240 runq->pc++;
241 (*runq->code[runq->pc-1].f)();
242 if(ntrap)
243 dotrap();
244 }
245 }
246
247 /*
248 * Opcode routines
249 * Arguments on stack (...)
250 * Arguments in line [...]
251 * Code in line with jump around {...}
252 *
253 * Xappend(file)[fd] open file to append
254 * Xassign(name, val) assign val to name
255 * Xasync{... Xexit} make thread for {}, no wait
256 * Xbackq(split){... Xreturn} make thread for {}, push stdout
257 * Xbang complement condition
258 * Xcase(pat, value){...} exec code on match, leave (value) on
259 * stack
260 * Xclose[i] close file descriptor
261 * Xconc(left, right) concatenate, push results
262 * Xcount(name) push var count
263 * Xdelfn(name) delete function definition
264 * Xdelhere
265 * Xdol(name) get variable value
266 * Xdup[i j] dup file descriptor
267 * Xeflag
268 * Xerror
269 * Xexit rc exits with status
270 * Xfalse{...} execute {} if false
271 * Xfn(name){... Xreturn} define function
272 * Xfor(var, list){... Xreturn} for loop
273 * Xglob
274 * Xif
275 * Xifnot
276 * Xjump[addr] goto
277 * Xlocal(name, val) create local variable, assign value
278 * Xmark mark stack
279 * Xmatch(pat, str) match pattern, set status
280 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
281 * wait for both
282 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
283 * depending on type), push /dev/fd/??
284 * Xpipewait
285 * Xpopm(value) pop value from stack
286 * Xpopredir
287 * Xqdol(name) concatenate variable components
288 * Xrdcmds
289 * Xrdfn
290 * Xrdwr(file)[fd] open file for reading and writing
291 * Xread(file)[fd] open file to read
292 * Xreturn kill thread
293 * Xsimple(args) run command and wait
294 * Xsettrue
295 * Xsub
296 * Xsubshell{... Xexit} execute {} in a subshell and wait
297 * Xtrue{...} execute {} if true
298 * Xunlocal delete local variable
299 * Xwastrue
300 * Xword[string] push string
301 * Xwrite(file)[fd] open file to write
302 */
303
304 void
Xappend(void)305 Xappend(void)
306 {
307 char *file;
308 int f;
309 switch(count(runq->argv->words)){
310 default:
311 Xerror1(">> requires singleton");
312 return;
313 case 0:
314 Xerror1(">> requires file");
315 return;
316 case 1:
317 break;
318 }
319 file = runq->argv->words->word;
320 if((f = open(file, 1))<0 && (f = Creat(file))<0){
321 pfmt(err, "%s: ", file);
322 Xerror("can't open");
323 return;
324 }
325 seek(f, 0, 2);
326 pushredir(ROPEN, f, runq->code[runq->pc].i);
327 runq->pc++;
328 poplist();
329 }
330
331 void
Xsettrue(void)332 Xsettrue(void)
333 {
334 setstatus("");
335 }
336
337 void
Xbang(void)338 Xbang(void)
339 {
340 setstatus(truestatus()?"false":"");
341 }
342
343 void
Xclose(void)344 Xclose(void)
345 {
346 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
347 runq->pc++;
348 }
349
350 void
Xdup(void)351 Xdup(void)
352 {
353 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
354 runq->pc+=2;
355 }
356
357 void
Xeflag(void)358 Xeflag(void)
359 {
360 if(eflagok && !truestatus()) Xexit();
361 }
362
363 void
Xexit(void)364 Xexit(void)
365 {
366 struct var *trapreq;
367 struct word *starval;
368 static int beenhere = 0;
369 if(getpid()==mypid && !beenhere){
370 trapreq = vlook("sigexit");
371 if(trapreq->fn){
372 beenhere = 1;
373 --runq->pc;
374 starval = vlook("*")->val;
375 start(trapreq->fn, trapreq->pc, (struct var *)0);
376 runq->local = newvar(strdup("*"), runq->local);
377 runq->local->val = copywords(starval, (struct word *)0);
378 runq->local->changed = 1;
379 runq->redir = runq->startredir = 0;
380 return;
381 }
382 }
383 Exit(getstatus());
384 }
385
386 void
Xfalse(void)387 Xfalse(void)
388 {
389 if(truestatus()) runq->pc = runq->code[runq->pc].i;
390 else runq->pc++;
391 }
392 int ifnot; /* dynamic if not flag */
393
394 void
Xifnot(void)395 Xifnot(void)
396 {
397 if(ifnot)
398 runq->pc++;
399 else
400 runq->pc = runq->code[runq->pc].i;
401 }
402
403 void
Xjump(void)404 Xjump(void)
405 {
406 runq->pc = runq->code[runq->pc].i;
407 }
408
409 void
Xmark(void)410 Xmark(void)
411 {
412 pushlist();
413 }
414
415 void
Xpopm(void)416 Xpopm(void)
417 {
418 poplist();
419 }
420
421 void
Xread(void)422 Xread(void)
423 {
424 char *file;
425 int f;
426 switch(count(runq->argv->words)){
427 default:
428 Xerror1("< requires singleton\n");
429 return;
430 case 0:
431 Xerror1("< requires file\n");
432 return;
433 case 1:
434 break;
435 }
436 file = runq->argv->words->word;
437 if((f = open(file, 0))<0){
438 pfmt(err, "%s: ", file);
439 Xerror("can't open");
440 return;
441 }
442 pushredir(ROPEN, f, runq->code[runq->pc].i);
443 runq->pc++;
444 poplist();
445 }
446
447 void
Xrdwr(void)448 Xrdwr(void)
449 {
450 char *file;
451 int f;
452
453 switch(count(runq->argv->words)){
454 default:
455 Xerror1("<> requires singleton\n");
456 return;
457 case 0:
458 Xerror1("<> requires file\n");
459 return;
460 case 1:
461 break;
462 }
463 file = runq->argv->words->word;
464 if((f = open(file, ORDWR))<0){
465 pfmt(err, "%s: ", file);
466 Xerror("can't open");
467 return;
468 }
469 pushredir(ROPEN, f, runq->code[runq->pc].i);
470 runq->pc++;
471 poplist();
472 }
473
474 void
turfredir(void)475 turfredir(void)
476 {
477 while(runq->redir!=runq->startredir)
478 Xpopredir();
479 }
480
481 void
Xpopredir(void)482 Xpopredir(void)
483 {
484 struct redir *rp = runq->redir;
485 if(rp==0)
486 panic("turfredir null!", 0);
487 runq->redir = rp->next;
488 if(rp->type==ROPEN)
489 close(rp->from);
490 efree((char *)rp);
491 }
492
493 void
Xreturn(void)494 Xreturn(void)
495 {
496 struct thread *p = runq;
497 turfredir();
498 while(p->argv) poplist();
499 codefree(p->code);
500 runq = p->ret;
501 efree((char *)p);
502 if(runq==0)
503 Exit(getstatus());
504 }
505
506 void
Xtrue(void)507 Xtrue(void)
508 {
509 if(truestatus()) runq->pc++;
510 else runq->pc = runq->code[runq->pc].i;
511 }
512
513 void
Xif(void)514 Xif(void)
515 {
516 ifnot = 1;
517 if(truestatus()) runq->pc++;
518 else runq->pc = runq->code[runq->pc].i;
519 }
520
521 void
Xwastrue(void)522 Xwastrue(void)
523 {
524 ifnot = 0;
525 }
526
527 void
Xword(void)528 Xword(void)
529 {
530 pushword(runq->code[runq->pc++].s);
531 }
532
533 void
Xwrite(void)534 Xwrite(void)
535 {
536 char *file;
537 int f;
538 switch(count(runq->argv->words)){
539 default:
540 Xerror1("> requires singleton\n");
541 return;
542 case 0:
543 Xerror1("> requires file\n");
544 return;
545 case 1:
546 break;
547 }
548 file = runq->argv->words->word;
549 if((f = Creat(file))<0){
550 pfmt(err, "%s: ", file);
551 Xerror("can't open");
552 return;
553 }
554 pushredir(ROPEN, f, runq->code[runq->pc].i);
555 runq->pc++;
556 poplist();
557 }
558
559 char*
list2str(word * words)560 list2str(word *words)
561 {
562 char *value, *s, *t;
563 int len = 0;
564 word *ap;
565 for(ap = words;ap;ap = ap->next)
566 len+=1+strlen(ap->word);
567 value = emalloc(len+1);
568 s = value;
569 for(ap = words;ap;ap = ap->next){
570 for(t = ap->word;*t;) *s++=*t++;
571 *s++=' ';
572 }
573 if(s==value)
574 *s='\0';
575 else s[-1]='\0';
576 return value;
577 }
578
579 void
Xmatch(void)580 Xmatch(void)
581 {
582 word *p;
583 char *subject;
584 subject = list2str(runq->argv->words);
585 setstatus("no match");
586 for(p = runq->argv->next->words;p;p = p->next)
587 if(match(subject, p->word, '\0')){
588 setstatus("");
589 break;
590 }
591 efree(subject);
592 poplist();
593 poplist();
594 }
595
596 void
Xcase(void)597 Xcase(void)
598 {
599 word *p;
600 char *s;
601 int ok = 0;
602 s = list2str(runq->argv->next->words);
603 for(p = runq->argv->words;p;p = p->next){
604 if(match(s, p->word, '\0')){
605 ok = 1;
606 break;
607 }
608 }
609 efree(s);
610 if(ok)
611 runq->pc++;
612 else
613 runq->pc = runq->code[runq->pc].i;
614 poplist();
615 }
616
617 word*
conclist(word * lp,word * rp,word * tail)618 conclist(word *lp, word *rp, word *tail)
619 {
620 char *buf;
621 word *v;
622 if(lp->next || rp->next)
623 tail = conclist(lp->next==0? lp: lp->next,
624 rp->next==0? rp: rp->next, tail);
625 buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
626 strcpy(buf, lp->word);
627 strcat(buf, rp->word);
628 v = newword(buf, tail);
629 efree(buf);
630 return v;
631 }
632
633 void
Xconc(void)634 Xconc(void)
635 {
636 word *lp = runq->argv->words;
637 word *rp = runq->argv->next->words;
638 word *vp = runq->argv->next->next->words;
639 int lc = count(lp), rc = count(rp);
640 if(lc!=0 || rc!=0){
641 if(lc==0 || rc==0){
642 Xerror1("null list in concatenation");
643 return;
644 }
645 if(lc!=1 && rc!=1 && lc!=rc){
646 Xerror1("mismatched list lengths in concatenation");
647 return;
648 }
649 vp = conclist(lp, rp, vp);
650 }
651 poplist();
652 poplist();
653 runq->argv->words = vp;
654 }
655
656 void
Xassign(void)657 Xassign(void)
658 {
659 var *v;
660 if(count(runq->argv->words)!=1){
661 Xerror1("variable name not singleton!");
662 return;
663 }
664 deglob(runq->argv->words->word);
665 v = vlook(runq->argv->words->word);
666 poplist();
667 globlist();
668 freewords(v->val);
669 v->val = runq->argv->words;
670 v->changed = 1;
671 runq->argv->words = 0;
672 poplist();
673 }
674 /*
675 * copy arglist a, adding the copy to the front of tail
676 */
677
678 word*
copywords(word * a,word * tail)679 copywords(word *a, word *tail)
680 {
681 word *v = 0, **end;
682 for(end=&v;a;a = a->next,end=&(*end)->next)
683 *end = newword(a->word, 0);
684 *end = tail;
685 return v;
686 }
687
688 void
Xdol(void)689 Xdol(void)
690 {
691 word *a, *star;
692 char *s, *t;
693 int n;
694 if(count(runq->argv->words)!=1){
695 Xerror1("variable name not singleton!");
696 return;
697 }
698 s = runq->argv->words->word;
699 deglob(s);
700 n = 0;
701 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
702 a = runq->argv->next->words;
703 if(n==0 || *t)
704 a = copywords(vlook(s)->val, a);
705 else{
706 star = vlook("*")->val;
707 if(star && 1<=n && n<=count(star)){
708 while(--n) star = star->next;
709 a = newword(star->word, a);
710 }
711 }
712 poplist();
713 runq->argv->words = a;
714 }
715
716 void
Xqdol(void)717 Xqdol(void)
718 {
719 word *a, *p;
720 char *s;
721 int n;
722 if(count(runq->argv->words)!=1){
723 Xerror1("variable name not singleton!");
724 return;
725 }
726 s = runq->argv->words->word;
727 deglob(s);
728 a = vlook(s)->val;
729 poplist();
730 n = count(a);
731 if(n==0){
732 pushword("");
733 return;
734 }
735 for(p = a;p;p = p->next) n+=strlen(p->word);
736 s = emalloc(n);
737 if(a){
738 strcpy(s, a->word);
739 for(p = a->next;p;p = p->next){
740 strcat(s, " ");
741 strcat(s, p->word);
742 }
743 }
744 else
745 s[0]='\0';
746 pushword(s);
747 efree(s);
748 }
749
750 word*
copynwords(word * a,word * tail,int n)751 copynwords(word *a, word *tail, int n)
752 {
753 word *v, **end;
754
755 v = 0;
756 end = &v;
757 while(n-- > 0){
758 *end = newword(a->word, 0);
759 end = &(*end)->next;
760 a = a->next;
761 }
762 *end = tail;
763 return v;
764 }
765
766 word*
subwords(word * val,int len,word * sub,word * a)767 subwords(word *val, int len, word *sub, word *a)
768 {
769 int n, m;
770 char *s;
771 if(!sub)
772 return a;
773 a = subwords(val, len, sub->next, a);
774 s = sub->word;
775 deglob(s);
776 m = 0;
777 n = 0;
778 while('0'<=*s && *s<='9')
779 n = n*10+ *s++ -'0';
780 if(*s == '-'){
781 if(*++s == 0)
782 m = len - n;
783 else{
784 while('0'<=*s && *s<='9')
785 m = m*10+ *s++ -'0';
786 m -= n;
787 }
788 }
789 if(n<1 || n>len || m<0)
790 return a;
791 if(n+m>len)
792 m = len-n;
793 while(--n > 0)
794 val = val->next;
795 return copynwords(val, a, m+1);
796 }
797
798 void
Xsub(void)799 Xsub(void)
800 {
801 word *a, *v;
802 char *s;
803 if(count(runq->argv->next->words)!=1){
804 Xerror1("variable name not singleton!");
805 return;
806 }
807 s = runq->argv->next->words->word;
808 deglob(s);
809 a = runq->argv->next->next->words;
810 v = vlook(s)->val;
811 a = subwords(v, count(v), runq->argv->words, a);
812 poplist();
813 poplist();
814 runq->argv->words = a;
815 }
816
817 void
Xcount(void)818 Xcount(void)
819 {
820 word *a;
821 char *s, *t;
822 int n;
823 char num[12];
824 if(count(runq->argv->words)!=1){
825 Xerror1("variable name not singleton!");
826 return;
827 }
828 s = runq->argv->words->word;
829 deglob(s);
830 n = 0;
831 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
832 if(n==0 || *t){
833 a = vlook(s)->val;
834 inttoascii(num, count(a));
835 }
836 else{
837 a = vlook("*")->val;
838 inttoascii(num, a && 1<=n && n<=count(a)?1:0);
839 }
840 poplist();
841 pushword(num);
842 }
843
844 void
Xlocal(void)845 Xlocal(void)
846 {
847 if(count(runq->argv->words)!=1){
848 Xerror1("variable name must be singleton\n");
849 return;
850 }
851 deglob(runq->argv->words->word);
852 runq->local = newvar(strdup(runq->argv->words->word), runq->local);
853 poplist();
854 globlist();
855 runq->local->val = runq->argv->words;
856 runq->local->changed = 1;
857 runq->argv->words = 0;
858 poplist();
859 }
860
861 void
Xunlocal(void)862 Xunlocal(void)
863 {
864 var *v = runq->local, *hid;
865 if(v==0)
866 panic("Xunlocal: no locals!", 0);
867 runq->local = v->next;
868 hid = vlook(v->name);
869 hid->changed = 1;
870 efree(v->name);
871 freewords(v->val);
872 efree((char *)v);
873 }
874
875 void
freewords(word * w)876 freewords(word *w)
877 {
878 word *nw;
879 while(w){
880 efree(w->word);
881 nw = w->next;
882 efree((char *)w);
883 w = nw;
884 }
885 }
886
887 void
Xfn(void)888 Xfn(void)
889 {
890 var *v;
891 word *a;
892 int end;
893 end = runq->code[runq->pc].i;
894 globlist();
895 for(a = runq->argv->words;a;a = a->next){
896 v = gvlook(a->word);
897 if(v->fn)
898 codefree(v->fn);
899 v->fn = codecopy(runq->code);
900 v->pc = runq->pc+2;
901 v->fnchanged = 1;
902 }
903 runq->pc = end;
904 poplist();
905 }
906
907 void
Xdelfn(void)908 Xdelfn(void)
909 {
910 var *v;
911 word *a;
912 for(a = runq->argv->words;a;a = a->next){
913 v = gvlook(a->word);
914 if(v->fn)
915 codefree(v->fn);
916 v->fn = 0;
917 v->fnchanged = 1;
918 }
919 poplist();
920 }
921
922 char*
concstatus(char * s,char * t)923 concstatus(char *s, char *t)
924 {
925 static char v[NSTATUS+1];
926 int n = strlen(s);
927 strncpy(v, s, NSTATUS);
928 if(n<NSTATUS){
929 v[n]='|';
930 strncpy(v+n+1, t, NSTATUS-n-1);
931 }
932 v[NSTATUS]='\0';
933 return v;
934 }
935
936 void
Xpipewait(void)937 Xpipewait(void)
938 {
939 char status[NSTATUS+1];
940 if(runq->pid==-1)
941 setstatus(concstatus(runq->status, getstatus()));
942 else{
943 strncpy(status, getstatus(), NSTATUS);
944 status[NSTATUS]='\0';
945 Waitfor(runq->pid, 1);
946 runq->pid=-1;
947 setstatus(concstatus(getstatus(), status));
948 }
949 }
950
951 void
Xrdcmds(void)952 Xrdcmds(void)
953 {
954 struct thread *p = runq;
955 word *prompt;
956 flush(err);
957 nerror = 0;
958 if(flag['s'] && !truestatus())
959 pfmt(err, "status=%v\n", vlook("status")->val);
960 if(runq->iflag){
961 prompt = vlook("prompt")->val;
962 if(prompt)
963 promptstr = prompt->word;
964 else
965 promptstr="% ";
966 }
967 Noerror();
968 if(yyparse()){
969 if(!p->iflag || p->eof && !Eintr()){
970 if(p->cmdfile)
971 efree(p->cmdfile);
972 closeio(p->cmdfd);
973 Xreturn(); /* should this be omitted? */
974 }
975 else{
976 if(Eintr()){
977 pchr(err, '\n');
978 p->eof = 0;
979 }
980 --p->pc; /* go back for next command */
981 }
982 }
983 else{
984 ntrap = 0; /* avoid double-interrupts during blocked writes */
985 --p->pc; /* re-execute Xrdcmds after codebuf runs */
986 start(codebuf, 1, runq->local);
987 }
988 freenodes();
989 }
990
991 void
pargv0(io * f)992 pargv0(io *f)
993 {
994 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
995 pfmt(f, "rc: ");
996 else
997 pfmt(f, "rc (%s): ", argv0);
998 }
999
1000 void
hisfault(io * f)1001 hisfault(io *f)
1002 {
1003 thread *t;
1004
1005 for(t = runq; !t->cmdfile && t->ret != 0; t = t->ret)
1006 ;
1007 if(t->cmdfile && !t->iflag)
1008 pfmt(f, "%s:%d ", t->cmdfile, t->lineno);
1009 }
1010
1011 void
Xerror(char * s)1012 Xerror(char *s)
1013 {
1014 io *msg = openstr();
1015
1016 pargv0(msg);
1017 hisfault(msg); /* capture errstr before another sys call */
1018 pfmt(err, "%s%s: %r\n", (char *)msg->strp, s);
1019 closeio(msg);
1020 flush(err);
1021 setstatus("error");
1022 while(!runq->iflag) Xreturn();
1023 }
1024
1025 void
Xerror1(char * s)1026 Xerror1(char *s) /* omit errstr */
1027 {
1028 pargv0(err);
1029 hisfault(err);
1030 pfmt(err, "%s\n", s);
1031 flush(err);
1032 setstatus("error");
1033 while(!runq->iflag) Xreturn();
1034 }
1035
1036 void
setstatus(char * s)1037 setstatus(char *s)
1038 {
1039 setvar("status", newword(s, (word *)0));
1040 }
1041
1042 char*
getstatus(void)1043 getstatus(void)
1044 {
1045 var *status = vlook("status");
1046 return status->val?status->val->word:"";
1047 }
1048
1049 int
truestatus(void)1050 truestatus(void)
1051 {
1052 char *s;
1053 for(s = getstatus();*s;s++)
1054 if(*s!='|' && *s!='0')
1055 return 0;
1056 return 1;
1057 }
1058
1059 void
Xdelhere(void)1060 Xdelhere(void)
1061 {
1062 Unlink(runq->code[runq->pc++].s);
1063 }
1064
1065 void
Xfor(void)1066 Xfor(void)
1067 {
1068 if(runq->argv->words==0){
1069 poplist();
1070 runq->pc = runq->code[runq->pc].i;
1071 }
1072 else{
1073 freelist(runq->local->val);
1074 runq->local->val = runq->argv->words;
1075 runq->local->changed = 1;
1076 runq->argv->words = runq->argv->words->next;
1077 runq->local->val->next = 0;
1078 runq->pc++;
1079 }
1080 }
1081
1082 void
Xglob(void)1083 Xglob(void)
1084 {
1085 globlist();
1086 }
1087