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