exec.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
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 redirec… | |
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'] = flagse… | |
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 s… | |
203 * Xbang complement condition | |
204 * Xcase(pat, value){...} exec code on match, leave (valu… | |
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 compo… | |
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, assig… | |
220 * Xmark mark stack | |
221 * Xmatch(pat, str) match pattern, set status | |
222 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between … | |
223 * wait for both | |
224 * Xpipefd[type]{... Xreturn} connect {} to pipe (input o… | |
225 * depending on type), push /dev… | |
226 * Xpopm(value) pop value from stack | |
227 * Xrdwr(file)[fd] open file for reading and writ… | |
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 … | |
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 wo… | |
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:… | |
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 concatenatio… | |
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->loca… | |
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 bloc… | |
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 } |