exec.c 17 KB

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