7 * Start executing the given code at the given pc with the given redirection
12 start(code *c, int pc, var *local)
14 struct thread *p = new(struct thread);
16 p->code = codecopy(c);
17 p->line = runq?runq->line:0;
20 p->redir = p->startredir = runq?runq->redir:nil;
26 p->lineno = runq ? runq->lineno : 1;
32 Newword(char *wd, word *next)
45 panic("pushword but no argv!", 0);
46 w = Newword(wd, runq->argv->words);
47 runq->argv->words = w;
52 newword(char *wd, word *next)
54 return Newword(estrdup(wd), next);
59 return Pushword(estrdup(wd));
67 panic("popword but no argv!", 0);
68 p = runq->argv->words;
70 panic("popword but no word!", 0);
71 runq->argv->words = p->next;
100 list *p = runq->argv;
102 panic("poplist but no argv", 0);
104 runq->argv = p->next;
112 for(n = 0;w;n++) w = w->next;
117 pushredir(int type, int from, int to)
119 redir * rp = new(redir);
123 rp->next = runq->redir;
135 runq->redir = rp->next;
136 rp->next = runq->startredir;
137 for(rr = &runq->redir; *rr != rp->next; rr = &((*rr)->next))
143 newvar(char *name, var *next)
146 v->name = estrdup(name);
155 * get command line flags, initialize keywords & traps.
156 * get values from environment.
157 * set $pid, $cflag, $*
158 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
159 * start interpreting code
163 main(int argc, char *argv[])
166 char num[12], *rcmain;
168 argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
170 usage("[file [arg ...]]");
175 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
176 rcmain = flag['m']?flag['m'][0]:Rcmain;
181 inttoascii(num, mypid = getpid());
182 setvar("pid", newword(num, (word *)0));
183 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
185 setvar("rcname", newword(argv[0], (word *)0));
187 bootstrap[i++].i = 1;
188 bootstrap[i++].f = Xmark;
189 bootstrap[i++].f = Xword;
190 bootstrap[i++].s="*";
191 bootstrap[i++].f = Xassign;
192 bootstrap[i++].f = Xmark;
193 bootstrap[i++].f = Xmark;
194 bootstrap[i++].f = Xword;
195 bootstrap[i++].s="*";
196 bootstrap[i++].f = Xdol;
197 bootstrap[i++].f = Xword;
198 bootstrap[i++].s = rcmain;
199 bootstrap[i++].f = Xword;
200 bootstrap[i++].s=".";
201 bootstrap[i++].f = Xsimple;
202 bootstrap[i++].f = Xexit;
204 start(bootstrap, 1, (var *)0);
205 runq->cmdfile = strdup("rc");
207 /* prime bootstrap argv */
209 argv0 = estrdup(argv[0]);
210 for(i = argc-1;i!=0;--i) pushword(argv[i]);
217 (*runq->code[runq->pc-1].f)();
224 * Arguments on stack (...)
225 * Arguments in line [...]
226 * Code in line with jump around {...}
228 * Xappend(file)[fd] open file to append
229 * Xassign(name, val) assign val to name
230 * Xasync{... Xexit} make thread for {}, no wait
231 * Xbackq(split){... Xreturn} make thread for {}, push stdout
232 * Xbang complement condition
233 * Xcase(pat, value){...} exec code on match, leave (value) on
235 * Xclose[i] close file descriptor
236 * Xconc(left, right) concatenate, push results
237 * Xcount(name) push var count
238 * Xdelfn(name) delete function definition
239 * Xdeltraps(names) delete named traps
240 * Xdol(name) get variable value
241 * Xqw(list) quote list, push result
242 * Xdup[i j] dup file descriptor
243 * Xexit rc exits with status
244 * Xfalse{...} execute {} if false
245 * Xfn(name){... Xreturn} define function
246 * Xfor(var, list){... Xreturn} for loop
247 * Xglobs[string globsize] push globbing string
249 * Xlocal(name, val) create local variable, assign value
251 * Xmatch(pat, str) match pattern, set status
252 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
254 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
255 * depending on type), push /dev/fd/??
256 * Xpopm(value) pop value from stack
257 * Xrdwr(file)[fd] open file for reading and writing
258 * Xread(file)[fd] open file to read
259 * Xsettraps(names){... Xreturn} define trap functions
260 * Xshowtraps print trap list
261 * Xsimple(args) run command and wait
262 * Xreturn kill thread
263 * Xsubshell{... Xexit} execute {} in a subshell and wait
264 * Xtrue{...} execute {} if true
265 * Xunlocal delete local variable
266 * Xword[string] push string
267 * Xwrite(file)[fd] open file to write
268 * Xsrcline[line] set current line number
269 * Xsrcfile[file] set current file name
277 switch(count(runq->argv->words)){
279 Xerror1(">> requires singleton");
282 Xerror1(">> requires file");
287 file = runq->argv->words->word;
288 if((f = open(file, 1))<0 && (f = Creat(file))<0){
289 pfmt(err, "%s: ", file);
290 Xerror("can't open");
294 pushredir(ROPEN, f, runq->code[runq->pc].i);
308 setstatus(truestatus()?"false":"");
314 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
321 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
328 if(eflagok && !truestatus()) Xexit();
335 struct word *starval;
336 static int beenhere = 0;
337 if(getpid()==mypid && !beenhere){
338 trapreq = vlook("sigexit");
342 starval = vlook("*")->val;
343 start(trapreq->fn, trapreq->pc, (struct var *)0);
344 runq->local = newvar("*", runq->local);
345 runq->local->val = copywords(starval, (struct word *)0);
346 runq->local->changed = 1;
347 runq->redir = runq->startredir = 0;
357 if(truestatus()) runq->pc = runq->code[runq->pc].i;
360 int ifnot; /* dynamic if not flag */
368 runq->pc = runq->code[runq->pc].i;
374 runq->pc = runq->code[runq->pc].i;
394 switch(count(runq->argv->words)){
396 Xerror1("< requires singleton\n");
399 Xerror1("< requires file\n");
404 file = runq->argv->words->word;
405 if((f = open(file, 0))<0){
406 pfmt(err, "%s: ", file);
407 Xerror("can't open");
410 pushredir(ROPEN, f, runq->code[runq->pc].i);
421 switch(count(runq->argv->words)){
423 Xerror1("<> requires singleton\n");
426 Xerror1("<> requires file\n");
431 file = runq->argv->words->word;
432 if((f = open(file, ORDWR))<0){
433 pfmt(err, "%s: ", file);
434 Xerror("can't open");
437 pushredir(ROPEN, f, runq->code[runq->pc].i);
445 while(runq->redir!=runq->startredir)
452 struct redir *rp = runq->redir;
454 panic("turfredir null!", 0);
455 runq->redir = rp->next;
464 struct thread *p = runq;
466 while(p->argv) poplist();
477 if(truestatus()) runq->pc++;
478 else runq->pc = runq->code[runq->pc].i;
485 if(truestatus()) runq->pc++;
486 else runq->pc = runq->code[runq->pc].i;
498 pushword(runq->code[runq->pc++].s);
504 word *w = pushword(runq->code[runq->pc++].s);
505 w->glob = runq->code[runq->pc++].i;
513 switch(count(runq->argv->words)){
515 Xerror1("> requires singleton\n");
518 Xerror1("> requires file\n");
523 file = runq->argv->words->word;
524 if((f = Creat(file))<0){
525 pfmt(err, "%s: ", file);
526 Xerror("can't open");
529 pushredir(ROPEN, f, runq->code[runq->pc].i);
535 list2str(word *words)
540 for(ap = words;ap;ap = ap->next)
541 len+=1+strlen(ap->word);
542 value = emalloc(len+1);
544 for(ap = words;ap;ap = ap->next){
545 for(t = ap->word;*t;) *s++=*t++;
559 subject = list2str(runq->argv->words);
560 setstatus("no match");
561 for(p = runq->argv->next->words;p;p = p->next)
562 if(match(subject, p->word, '\0')){
577 s = list2str(runq->argv->next->words);
578 for(p = runq->argv->words;p;p = p->next){
579 if(match(s, p->word, '\0')){
588 runq->pc = runq->code[runq->pc].i;
593 conclist(word *lp, word *rp, word *tail)
599 ln = strlen(lp->word), rn = strlen(rp->word);
600 p = Newword(emalloc(ln+rn+1), (word *)0);
601 memmove(p->word, lp->word, ln);
602 memmove(p->word+ln, rp->word, rn+1);
603 if(lp->glob || rp->glob)
604 p->glob = Globsize(p->word);
605 *end = p, end = &p->next;
606 if(lp->next == 0 && rp->next == 0)
608 if(lp->next) lp = lp->next;
609 if(rp->next) rp = rp->next;
618 word *lp = runq->argv->words;
619 word *rp = runq->argv->next->words;
620 word *vp = runq->argv->next->next->words;
621 int lc = count(lp), rc = count(rp);
624 Xerror1("null list in concatenation");
627 if(lc!=1 && rc!=1 && lc!=rc){
628 Xerror1("mismatched list lengths in concatenation");
631 vp = conclist(lp, rp, vp);
635 runq->argv->words = vp;
653 if(count(runq->argv->words)!=1){
654 Xerror1("variable name not singleton!");
657 v = vlook(Str(runq->argv->words));
660 v->val = globlist(runq->argv->words);
662 runq->argv->words = 0;
666 * copy arglist a, adding the copy to the front of tail
670 copywords(word *a, word *tail)
673 for(end=&v;a;a = a->next,end=&(*end)->next)
674 *end = newword(a->word, 0);
685 if(count(runq->argv->words)!=1){
686 Xerror1("variable name not singleton!");
689 s = Str(runq->argv->words);
691 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
692 a = runq->argv->next->words;
694 a = copywords(vlook(s)->val, a);
696 star = vlook("*")->val;
697 if(star && 1<=n && n<=count(star)){
698 while(--n) star = star->next;
699 a = newword(star->word, a);
703 runq->argv->words = a;
712 a = runq->argv->words;
713 if(a && a->next == 0){
714 runq->argv->words = 0;
716 a->next = runq->argv->words;
717 runq->argv->words = a;
726 copynwords(word *a, word *tail, int n)
733 *end = newword(a->word, 0);
742 subwords(word *val, int len, word *sub, word *a)
748 a = subwords(val, len, sub->next, a);
752 while('0'<=*s && *s<='9')
758 while('0'<=*s && *s<='9')
763 if(n<1 || n>len || m<0)
769 return copynwords(val, a, m+1);
777 if(count(runq->argv->next->words)!=1){
778 Xerror1("variable name not singleton!");
781 s = Str(runq->argv->next->words);
782 a = runq->argv->next->next->words;
784 a = subwords(v, count(v), runq->argv->words, a);
787 runq->argv->words = a;
797 if(count(runq->argv->words)!=1){
798 Xerror1("variable name not singleton!");
801 s = Str(runq->argv->words);
803 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
806 inttoascii(num, count(a));
810 inttoascii(num, a && 1<=n && n<=count(a)?1:0);
819 if(count(runq->argv->words)!=1){
820 Xerror1("variable name must be singleton\n");
823 runq->local = newvar(Str(runq->argv->words), runq->local);
825 runq->local->val = globlist(runq->argv->words);
826 runq->local->changed = 1;
827 runq->argv->words = 0;
834 var *v = runq->local, *hid;
836 panic("Xunlocal: no locals!", 0);
837 runq->local = v->next;
838 hid = vlook(v->name);
863 end = runq->code[runq->pc].i;
864 for(a = globlist(runq->argv->words);a;a = a->next){
868 v->fn = codecopy(runq->code);
881 for(a = runq->argv->words;a;a = a->next){
892 concstatus(char *s, char *t)
894 static char v[NSTATUS+1];
896 strncpy(v, s, NSTATUS);
899 strncpy(v+n+1, t, NSTATUS-n-1);
908 char status[NSTATUS+1];
910 setstatus(concstatus(runq->status, getstatus()));
912 strncpy(status, getstatus(), NSTATUS);
913 status[NSTATUS]='\0';
914 Waitfor(runq->pid, 1);
916 setstatus(concstatus(getstatus(), status));
923 struct thread *p = runq;
928 if(flag['s'] && !truestatus())
929 pfmt(err, "status=%v\n", vlook("status")->val);
931 prompt = vlook("prompt")->val;
933 promptstr = prompt->word;
939 if(!p->iflag || p->eof && !Eintr()){
950 --p->pc; /* go back for next command */
954 ntrap = 0; /* avoid double-interrupts during blocked writes */
955 --p->pc; /* re-execute Xrdcmds after codebuf runs */
956 start(codebuf, 1, runq->local);
964 for(; p != nil; p = p->ret)
965 if(p->cmdfile != nil)
973 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
974 pfmt(err, "rc:%d: %s: %r\n", runq->line, s);
976 pfmt(err, "%s:%d: %s: %r\n", curfile(runq), runq->line, s);
979 while(!runq->iflag) Xreturn();
985 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
986 pfmt(err, "rc:%d: %s\n", runq->line, s);
988 pfmt(err, "%s:%d: %s\n", curfile(runq), runq->line, s);
991 while(!runq->iflag) Xreturn();
997 setvar("status", newword(s, (word *)0));
1003 var *status = vlook("status");
1004 return status->val?status->val->word:"";
1011 for(s = getstatus();*s;s++)
1012 if(*s!='|' && *s!='0')
1020 Unlink(runq->code[runq->pc++].s);
1026 if(runq->argv->words==0){
1028 runq->pc = runq->code[runq->pc].i;
1031 freelist(runq->local->val);
1032 runq->local->val = runq->argv->words;
1033 runq->local->changed = 1;
1034 runq->argv->words = runq->argv->words->next;
1035 runq->local->val->next = 0;
1043 globlist(runq->argv->words);
1049 runq->line = runq->code[runq->pc++].i;
1055 free(runq->cmdfile);
1056 runq->cmdfile = strdup(runq->code[runq->pc++].s);