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