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