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