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