home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2269 < prev    next >
Internet Message Format  |  1990-12-28  |  47KB

  1. From: netnews@netcom.UUCP (USENET Administration)
  2. Newsgroups: alt.sources
  3. Subject: Public Domain Korn Shell - Part.04 of 7
  4. Message-ID: <18609@netcom.UUCP>
  5. Date: 12 Dec 90 11:37:20 GMT
  6.  
  7. #!/bin/sh
  8. # This is part 04 of ksh-pd
  9. # ============= src/tree.c ==============
  10. if test ! -d 'src'; then
  11.     echo 'x - creating directory src'
  12.     mkdir 'src'
  13. fi
  14. if test -f 'src/tree.c' -a X"$1" != X"-c"; then
  15.     echo 'x - skipping src/tree.c (File already exists)'
  16. else
  17. echo 'x - extracting src/tree.c (Text)'
  18. sed 's/^X//' << 'SHAR_EOF' > 'src/tree.c' &&
  19. X/*
  20. X * command tree climbing
  21. X */
  22. X
  23. Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/tree.c,v 3.1 88/11/03 09:18:05 egisin Exp $";
  24. X
  25. X#include <stddef.h>
  26. X#include <string.h>
  27. X#include <stdio.h>
  28. X#include <errno.h>
  29. X#include <setjmp.h>
  30. X#include <varargs.h>
  31. X#include "sh.h"
  32. X#include "tree.h"
  33. X
  34. X#define    FSTRING    (FILE*)NULL
  35. X
  36. Xstatic    int    tputc ARGS((int c, FILE *f));
  37. Xstatic    void    tputC ARGS((int c, FILE *f));
  38. Xstatic    void    tputS ARGS((char *wp, FILE *f));
  39. X
  40. X/*
  41. X * print a command tree
  42. X */
  43. X
  44. Xvoid
  45. Xptree(t, f)
  46. X    register struct op *t;
  47. X    register FILE *f;
  48. X{
  49. X    register char **w;
  50. X    struct ioword **ioact;
  51. X    struct op *t1;
  52. X
  53. X Chain:
  54. X    if (t == NULL)
  55. X        return;
  56. X    switch (t->type) {
  57. X      case TCOM:
  58. X        for (w = t->vars; *w != NULL; )
  59. X            fptreef(f, "%S ", *w++);
  60. X        for (w = t->args; *w != NULL; )
  61. X            fptreef(f, "%S ", *w++);
  62. X        break;
  63. X      case TEXEC:
  64. X        t = t->left;
  65. X        goto Chain;
  66. X      case TPAREN:
  67. X        fptreef(f, "(%T)", t->left);
  68. X        break;
  69. X      case TPIPE:
  70. X        fptreef(f, "%T | ", t->left);
  71. X        t = t->right;
  72. X        goto Chain;
  73. X      case TLIST:
  74. X        fptreef(f, "%T%;", t->left);
  75. X        t = t->right;
  76. X        goto Chain;
  77. X      case TOR:
  78. X      case TAND:
  79. X        fptreef(f, "%T %s %T",
  80. X            t->left, (t->type==TOR) ? "||" : "&&", t->right);
  81. X        break;
  82. X      case TFOR:
  83. X        fptreef(f, "for %s ", t->str);
  84. X        if (t->vars != NULL) {
  85. X            fptreef(f, "in ");
  86. X            for (w = t->vars; *w; )
  87. X                fptreef(f, "%S ", *w++);
  88. X            fptreef(f, "%;");
  89. X        }
  90. X        fptreef(f, "do %T%;done ", t->left);
  91. X        break;
  92. X      case TCASE:
  93. X        fptreef(f, "case %S in%;", t->str);
  94. X        for (t1 = t->left; t1 != NULL; t1 = t1->right) {
  95. X            fptreef(f, "(");
  96. X            for (w = t1->vars; *w != NULL; w++)
  97. X                fptreef(f, "%S%c", *w, (w[1] != NULL) ? '|' : ')');
  98. X            fptreef(f, " %T;;%;", t1->left);
  99. X        }
  100. X        fptreef(f, "esac ");
  101. X        break;
  102. X      case TIF:
  103. X        fptreef(f, "if %T%;", t->left);
  104. X        t = t->right;
  105. X        if (t->left != NULL)
  106. X            fptreef(f, "then %T%;", t->left);
  107. X        if (t->right != NULL)
  108. X            fptreef(f, "else %T%;", t->right);
  109. X        fptreef(f, "fi ");
  110. X        break;
  111. X      case TWHILE:
  112. X      case TUNTIL:
  113. X        fptreef(f, "%s %T%;do %T%;done ",
  114. X            (t->type==TWHILE) ? "while" : "until",
  115. X            t->left, t->right);
  116. X        break;
  117. X      case TBRACE:
  118. X        fptreef(f, "{%;%T%;} ", t->left);
  119. X        break;
  120. X      case TASYNC:
  121. X        fptreef(f, "%T &", t->left);
  122. X        break;
  123. X      case TFUNCT:
  124. X        fptreef(f, "function %s %T", t->str, t->left);
  125. X        break;
  126. X      case TTIME:
  127. X        fptreef(f, "time %T", t->left);
  128. X        break;
  129. X      default:
  130. X        fptreef(f, "<botch>");
  131. X        break;
  132. X    }
  133. X    if ((ioact = t->ioact) != NULL)
  134. X        while (*ioact != NULL)
  135. X            pioact(f, *ioact++);
  136. X}
  137. X
  138. Xpioact(f, iop)
  139. X    register FILE *f;
  140. X    register struct ioword *iop;
  141. X{
  142. X    fptreef(f, "%c><%S ", '0' + iop->unit, iop->name); /* todo: fix */
  143. X}
  144. X
  145. X
  146. X/*
  147. X * variants of fputc, fputs for ptreef and snptreef
  148. X */
  149. X
  150. Xstatic    char   *snpf_s;        /* snptreef string */
  151. Xstatic    int    snpf_n;        /* snptreef length */
  152. X
  153. Xstatic int
  154. Xtputc(c, f)
  155. X    int c;
  156. X    register FILE *f;
  157. X{
  158. X    if (f != NULL)
  159. X        putc(c, f);
  160. X    else
  161. X        if (--snpf_n >= 0)
  162. X            *snpf_s++ = c;
  163. X    return c;
  164. X}
  165. X
  166. Xstatic void
  167. XtputC(c, f)
  168. X    register int c;
  169. X    register FILE *f;
  170. X{
  171. X    if ((c&0x60) == 0) {        /* C0|C1 */
  172. X        tputc((c&0x80) ? '$' : '^', f);
  173. X        tputc((c&0x7F|0x40), f);
  174. X    } else if ((c&0x7F) == 0x7F) {    /* DEL */
  175. X        tputc((c&0x80) ? '$' : '^', f);
  176. X        tputc('?', f);
  177. X    } else
  178. X        tputc(c, f);
  179. X}
  180. X
  181. Xstatic void
  182. XtputS(wp, f)
  183. X    register char *wp;
  184. X    register FILE *f;
  185. X{
  186. X    register int c;
  187. X
  188. X    while (1)
  189. X        switch ((c = *wp++)) {
  190. X          case EOS:
  191. X            return;
  192. X          case CHAR:
  193. X            tputC(*wp++, f);
  194. X            break;
  195. X          case QCHAR:
  196. X            tputc('\\', f);
  197. X            tputC(*wp++, f);
  198. X            break;
  199. X          case OQUOTE:
  200. X          case CQUOTE:
  201. X            tputc('"', f);
  202. X            break;
  203. X          case OSUBST:
  204. X            tputc('$', f);
  205. X            tputc('{', f);
  206. X            while ((c = *wp++) != 0)
  207. X                tputc(c, f);
  208. X            if (*wp != CSUBST)
  209. X                tputC(*wp++, f);
  210. X            break;
  211. X          case CSUBST:
  212. X            tputc('}', f);
  213. X            break;
  214. X          case COMSUB:
  215. X            tputc('$', f);
  216. X            tputc('(', f);
  217. X            while (*wp != 0)
  218. X                tputC(*wp++, f);
  219. X            tputc(')', f);
  220. X            break;
  221. X        }
  222. X}
  223. X
  224. X/* TODO: use varargs properly */
  225. X
  226. X/* VARARGS */ int
  227. Xfptreef(f, va_alist) va_dcl
  228. X    register FILE *f;
  229. X{
  230. X    va_list va;
  231. X    char *fmt;
  232. X
  233. X    va_start(va);
  234. X    fmt = va_arg(va, char *);
  235. X    vfptreef(f, fmt, va);
  236. X    va_end(va);
  237. X    return 0;
  238. X}
  239. X
  240. X/* VARARGS */ int
  241. Xsnptreef(s, n, va_alist) va_dcl
  242. X    char *s;
  243. X    int n;
  244. X{
  245. X    va_list va;
  246. X    char *fmt;
  247. X
  248. X    snpf_s = s;
  249. X    snpf_n = n;
  250. X    va_start(va);
  251. X    fmt = va_arg(va, char *);
  252. X    vfptreef(FSTRING, fmt, va);
  253. X    tputc('\0', FSTRING);
  254. X    va_end(va);
  255. X    return 0;
  256. X}
  257. X
  258. Xvfptreef(f, fmt, va)
  259. X    register FILE *f;
  260. X    register char *fmt;
  261. X    register va_list va;
  262. X{
  263. X    register int c;
  264. X
  265. X    while ((c = *fmt++))
  266. X        if (c == '%') {
  267. X        register long n;
  268. X        register char *p;
  269. X        int neg;
  270. X
  271. X        switch ((c = *fmt++)) {
  272. X          case 'c':
  273. X            tputc(va_arg(va, int), f);
  274. X            break;
  275. X          case 's':
  276. X            p = va_arg(va, char *);
  277. X            while (*p)
  278. X                tputc(*p++, f);
  279. X            break;
  280. X          case 'S':    /* word */
  281. X            p = va_arg(va, char *);
  282. X            tputS(p, f);
  283. X            break;
  284. X          case 'd': case 'u': /* decimal */
  285. X            n = (c == 'd') ? va_arg(va, int) : va_arg(va, unsigned int);
  286. X            neg = c=='d' && n<0;
  287. X            p = ulton((neg) ? -n : n, 10);
  288. X            if (neg)
  289. X                *--p = '-';
  290. X            while (*p)
  291. X                tputc(*p++, f);
  292. X            break;
  293. X          case 'T':    /* format tree */
  294. X            ptree(va_arg(va, struct op *), f);
  295. X            break;
  296. X          case ';':    /* newline or ; */
  297. X            p = (f == FSTRING) ? "; " : "\n";
  298. X            while (*p)
  299. X                tputc(*p++, f);
  300. X            break;
  301. X          default:
  302. X            tputc(c, f);
  303. X            break;
  304. X        }
  305. X        } else
  306. X        tputc(c, f);
  307. X}
  308. X
  309. X/*
  310. X * copy tree (for function definition)
  311. X */
  312. X
  313. Xstatic    struct ioword **iocopy();
  314. X
  315. Xstruct op *
  316. Xtcopy(t, ap)
  317. X    register struct op *t;
  318. X    Area *ap;
  319. X{
  320. X    register struct op *r;
  321. X    register char **tw, **rw;
  322. X
  323. X    if (t == NULL)
  324. X        return NULL;
  325. X
  326. X    r = (struct op *) alloc(sizeof(struct op), ap);
  327. X
  328. X    r->type = t->type;
  329. X
  330. X    /* this will copy function and for identifiers quite accidently */
  331. X    r->str = (t->str == NULL) ? NULL : wdcopy(t->str, ap);
  332. X
  333. X    if (t->vars == NULL)
  334. X        r->vars = NULL;
  335. X    else {
  336. X        for (tw = t->vars; *tw++ != NULL; )
  337. X            ;
  338. X        rw = r->vars = (char **)
  339. X            alloc((int)(tw - t->vars) * sizeof(*tw), ap);
  340. X        for (tw = t->vars; *tw != NULL; )
  341. X            *rw++ = wdcopy(*tw++, ap);
  342. X        *rw = NULL;
  343. X    }
  344. X
  345. X    if (t->args == NULL)
  346. X        r->args = NULL;
  347. X    else {
  348. X        for (tw = t->args; *tw++ != NULL; )
  349. X            ;
  350. X        rw = r->args = (char **)
  351. X            alloc((int)(tw - t->args) * sizeof(*tw), ap);
  352. X        for (tw = t->args; *tw != NULL; )
  353. X            *rw++ = wdcopy(*tw++, ap);
  354. X        *rw = NULL;
  355. X    }
  356. X
  357. X    r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
  358. X
  359. X    r->left = tcopy(t->left, ap);
  360. X    r->right = tcopy(t->right, ap);
  361. X
  362. X    return r;
  363. X}
  364. X
  365. Xchar *
  366. Xwdcopy(wp, ap)
  367. X    char *wp;
  368. X    Area *ap;
  369. X{
  370. X    size_t len = wdscan(wp, EOS) - wp;
  371. X    return memcpy(alloc(len, ap), wp, len);
  372. X}
  373. X
  374. X/* return the position of prefix c in wp plus 1 */
  375. Xchar *
  376. Xwdscan(wp, c)
  377. X    register char *wp;
  378. X    register int c;
  379. X{
  380. X    register int nest = 0;
  381. X
  382. X    while (1)
  383. X        switch (*wp++) {
  384. X          case EOS:
  385. X            return wp;
  386. X          case CHAR:
  387. X          case QCHAR:
  388. X            wp++;
  389. X            break;
  390. X          case OQUOTE:
  391. X          case CQUOTE:
  392. X            break;
  393. X          case OSUBST:
  394. X            nest++;
  395. X            while (*wp++ != 0)
  396. X                ;
  397. X            if (*wp != CSUBST)
  398. X                wp++;
  399. X            break;
  400. X          case CSUBST:
  401. X            if (c == CSUBST && nest == 0)
  402. X                return wp;
  403. X            nest--;
  404. X            break;
  405. X          case COMSUB:
  406. X            while (*wp++ != 0)
  407. X                ;
  408. X            break;
  409. X        }
  410. X}
  411. X
  412. Xstatic    struct ioword **
  413. Xiocopy(iow, ap)
  414. X    register struct ioword **iow;
  415. X    Area *ap;
  416. X{
  417. X    register struct ioword **ior;
  418. X    register int i;
  419. X
  420. X    for (ior = iow; *ior++ != NULL; )
  421. X        ;
  422. X    ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap);
  423. X
  424. X    for (i = 0; iow[i] != NULL; i++) {
  425. X        register struct ioword *p, *q;
  426. X
  427. X        p = iow[i];
  428. X        q = (struct ioword *) alloc(sizeof(*p), ap);
  429. X        ior[i] = q;
  430. X        *q = *p;
  431. X        if (p->name != NULL)
  432. X            q->name = wdcopy(p->name, ap);
  433. X    }
  434. X    ior[i] = NULL;
  435. X
  436. X    return ior;
  437. X}
  438. X
  439. X/*
  440. X * free tree (for function definition)
  441. X */
  442. X
  443. Xstatic    void iofree();
  444. X
  445. Xvoid
  446. Xtfree(t, ap)
  447. X    register struct op *t;
  448. X    Area *ap;
  449. X{
  450. X    register char **w;
  451. X
  452. X    if (t == NULL)
  453. X        return;
  454. X
  455. X    if (t->str != NULL)
  456. X        afree((Void*)t->str, ap);
  457. X
  458. X    if (t->vars != NULL) {
  459. X        for (w = t->vars; *w != NULL; w++)
  460. X            afree((Void*)*w, ap);
  461. X        afree((Void*)t->vars, ap);
  462. X    }
  463. X
  464. X    if (t->args != NULL) {
  465. X        for (w = t->args; *w != NULL; w++)
  466. X            afree((Void*)*w, ap);
  467. X        afree((Void*)t->args, ap);
  468. X    }
  469. X
  470. X    if (t->ioact != NULL)
  471. X        iofree(t->ioact, ap);
  472. X
  473. X    tfree(t->left, ap);
  474. X    tfree(t->right, ap);
  475. X
  476. X    afree((Void*)t, ap);
  477. X}
  478. X
  479. Xstatic    void
  480. Xiofree(iow, ap)
  481. X    struct ioword **iow;
  482. X    Area *ap;
  483. X{
  484. X    register struct ioword **iop;
  485. X    register struct ioword *p;
  486. X
  487. X    for (iop = iow; (p = *iop++) != NULL; ) {
  488. X        if (p->name != NULL)
  489. X            afree((Void*)p->name, ap);
  490. X        afree((Void*)p, ap);
  491. X    }
  492. X}
  493. X
  494. SHAR_EOF
  495. true || echo 'restore of src/tree.c failed'
  496. fi
  497. # ============= src/exec.c ==============
  498. if test -f 'src/exec.c' -a X"$1" != X"-c"; then
  499.     echo 'x - skipping src/exec.c (File already exists)'
  500. else
  501. echo 'x - extracting src/exec.c (Text)'
  502. sed 's/^X//' << 'SHAR_EOF' > 'src/exec.c' &&
  503. X/*
  504. X * execute command tree
  505. X */
  506. X
  507. Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/exec.c,v 3.3 88/12/17 21:19:29 egisin Exp $";
  508. X
  509. X#include <stddef.h>
  510. X#include <stdio.h>
  511. X#include <string.h>
  512. X#include <errno.h>
  513. X#include <signal.h>
  514. X#include <setjmp.h>
  515. X#include <unistd.h>
  516. X#include <fcntl.h>
  517. X#include "sh.h"
  518. X#include "lex.h"
  519. X#include "tree.h"
  520. X#include "table.h"
  521. X
  522. Xstatic    int    comexec ARGS((struct op *t, char **vp, char **ap, int flags));
  523. Xstatic    void    iosetup ARGS((struct ioword *iop));
  524. Xstatic    void    echo ARGS((char **, char **));
  525. Xstatic    int    herein ARGS((char *name, int sub));
  526. X
  527. X/*
  528. X * execute command tree
  529. X */
  530. Xint
  531. Xexecute(t, flags)
  532. X    register struct op *t;
  533. X    Volatile int flags;    /* if XEXEC don't fork */
  534. X{
  535. X    int i;
  536. X    int Volatile rv = 0;
  537. X    int pv[2];
  538. X    register char **ap;
  539. X    char *s, *cp;
  540. X    struct ioword **iowp;
  541. X
  542. X    if (t == NULL)
  543. X        return 0;
  544. X
  545. X    if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
  546. X        return exchild(t, flags); /* run in sub-process */
  547. X
  548. X    newenv(E_EXEC);
  549. X    if (trap)
  550. X        runtraps();
  551. X    if (t->ioact != NULL || t->type == TPIPE) {
  552. X        e.savefd = alloc(sizeofN(short, NUFILE), ATEMP);
  553. X        for (i = 0; i < NUFILE; i++)
  554. X            e.savefd[i] = 0; /* not redirected */
  555. X    }
  556. X
  557. X    /* do redirection, to be restored in quitenv() */
  558. X    if (t->ioact != NULL)
  559. X        for (iowp = t->ioact; *iowp != NULL; iowp++) {
  560. X            if ((flags&XPIPEI) && (*iowp)->unit == 0 ||
  561. X                (flags&XPIPEO) && (*iowp)->unit == 1)
  562. X                errorf("attempt to redirect fd 0/1 in pipe\n");
  563. X            iosetup(*iowp);
  564. X        }
  565. X
  566. X    switch(t->type) {
  567. X      case TCOM:
  568. X        e.type = E_TCOM;
  569. X        rv = comexec(t, eval(t->vars, DOTILDE),
  570. X                 eval(t->args, DOBLANK|DOGLOB|DOTILDE), flags);
  571. X        break;
  572. X
  573. X      case TPAREN:
  574. X        rv = execute(t->left, flags|XFORK);
  575. X        break;
  576. X
  577. X      case TPIPE:
  578. X        flags |= XFORK;
  579. X        e.savefd[0] = savefd(0);
  580. X        e.savefd[1] = savefd(1);
  581. X        flags |= XPIPEO;
  582. X        (void) dup2(e.savefd[0], 0); /* stdin of first */
  583. X        while (t->type == TPIPE) {
  584. X            openpipe(pv);
  585. X            (void) dup2(pv[1], 1);    /* stdout of curr */
  586. X            exchild(t->left, flags);
  587. X            (void) dup2(pv[0], 0);    /* stdin of next */
  588. X            closepipe(pv);
  589. X            flags |= XPIPEI;
  590. X            t = t->right;
  591. X        }
  592. X        flags &= ~ XPIPEO;
  593. X        (void) dup2(e.savefd[1], 1); /* stdout of last */
  594. X        exchild(t, flags);
  595. X        (void) dup2(e.savefd[0], 0); /* close pipe in */
  596. X        rv = waitlast();
  597. X        break;
  598. X
  599. X      case TLIST:
  600. X        while (t->type == TLIST) {
  601. X            execute(t->left, 0);
  602. X            t = t->right;
  603. X        }
  604. X        rv = execute(t, 0);
  605. X        break;
  606. X
  607. X      case TASYNC:
  608. X        rv = execute(t->left, flags|XBGND|XFORK);
  609. X        break;
  610. X
  611. X      case TOR:
  612. X      case TAND:
  613. X        rv = execute(t->left, 0);
  614. X        if (t->right != NULL && (rv == 0) == (t->type == TAND))
  615. X            rv = execute(t->right, 0);
  616. X        break;
  617. X
  618. X      case TFOR:
  619. X        e.type = E_LOOP;
  620. X        ap = (t->vars != NULL) ?
  621. X            eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
  622. X        while ((i = setjmp(e.jbuf)))
  623. X            if (i == LBREAK)
  624. X                goto Break1;
  625. X        while (*ap != NULL) {
  626. X            setstr(global(t->str), *ap++);
  627. X            rv = execute(t->left, 0);
  628. X        }
  629. X      Break1:
  630. X        break;
  631. X
  632. X      case TWHILE:
  633. X      case TUNTIL:
  634. X        e.type = E_LOOP;
  635. X        while ((i = setjmp(e.jbuf)))
  636. X            if (i == LBREAK)
  637. X                goto Break2;
  638. X        while ((execute(t->left, 0) == 0) == (t->type == TWHILE))
  639. X            rv = execute(t->right, 0);
  640. X      Break2:
  641. X        break;
  642. X
  643. X      case TIF:
  644. X      case TELIF:
  645. X        if (t->right == NULL)
  646. X            break;    /* should be error */
  647. X        rv = execute(t->left, 0) == 0 ?
  648. X            execute(t->right->left, 0) :
  649. X            execute(t->right->right, 0);
  650. X        break;
  651. X
  652. X      case TCASE:
  653. X        cp = evalstr(t->str, 0);
  654. X        for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
  655. X            for (ap = t->vars; *ap; ap++)
  656. X            if ((s = evalstr(*ap, DOPAT)) && gmatch(cp, s))
  657. X                goto Found;
  658. X        break;
  659. X      Found:
  660. X        rv = execute(t->left, 0);
  661. X        break;
  662. X
  663. X      case TBRACE:
  664. X        rv = execute(t->left, 0);
  665. X        break;
  666. X
  667. X      case TFUNCT:
  668. X        rv = define(t->str, t->left);
  669. X        break;
  670. X
  671. X      case TTIME:
  672. X        rv = timex(t, flags);
  673. X        break;
  674. X
  675. X      case TEXEC:        /* an eval'd TCOM */
  676. X        s = t->args[0];
  677. X        ap = makenv();
  678. X#if _MINIX                /* no F_SETFD close-on-exec */
  679. X        for (i = 10; i < 20; i++)
  680. X            close(i);
  681. X#endif
  682. X        execve(t->str, t->args, ap);
  683. X        if (errno == ENOEXEC) {
  684. X            *t->args-- = t->str;
  685. X            *t->args = s;
  686. X            execve(SHELL, t->args, ap);
  687. X            errorf("No shell\n");
  688. X        }
  689. X        errorf("%s: %s\n", s, strerror(errno));
  690. X    }
  691. X
  692. X    quitenv();        /* restores IO */
  693. X    if (e.interactive) {    /* flush stdout, shlout */
  694. X        fflush(shf[1]);
  695. X        fflush(shf[2]);
  696. X    }
  697. X    if ((flags&XEXEC))
  698. X        exit(rv);    /* exit child */
  699. X    return rv;
  700. X}
  701. X
  702. X/*
  703. X * execute simple command
  704. X */
  705. X
  706. Xstatic int
  707. Xcomexec(t, vp, ap, flags)
  708. X    struct op *t;
  709. X    register char **ap, **vp;
  710. X    int flags;
  711. X{
  712. X    int i;
  713. X    int rv = 0;
  714. X    register char *cp;
  715. X    register struct tbl *tp = NULL;
  716. X    register struct block *l;
  717. X    static struct op texec = {TEXEC};
  718. X    extern int c_exec(), c_builtin();
  719. X
  720. X    if (flag[FXTRACE])
  721. X        echo(vp, ap);
  722. X
  723. X    /* create new variable/function block */
  724. X    l = alloc(sizeof(struct block), ATEMP);
  725. X    l->next = e.loc; e.loc = l;
  726. X    newblock();
  727. X
  728. X Doexec:
  729. X    if ((cp = *ap) == NULL)
  730. X        cp = ":";
  731. X    tp = findcom(cp, 1);
  732. X
  733. X    switch (tp->type) {
  734. X      case CSHELL:            /* shell built-in */
  735. X        while (tp->val.f == c_builtin) {
  736. X            if ((cp = *++ap) == NULL)
  737. X                break;
  738. X            tp = tsearch(&builtins, cp, hash(cp));
  739. X            if (tp == NULL)
  740. X                errorf("%s: not builtin\n", cp);
  741. X        }
  742. X        if (tp->val.f == c_exec) {
  743. X            if (*++ap == NULL) {
  744. X                e.savefd = NULL; /* don't restore redirection */
  745. X                break;
  746. X            }
  747. X            flags |= XEXEC;
  748. X            goto Doexec;
  749. X        }
  750. X        if ((tp->flag&TRACE))
  751. X            e.loc = l->next; /* no local block */
  752. X        i = (tp->flag&TRACE) ? 0 : LOCAL;
  753. X        while (*vp != NULL)
  754. X            (void) typeset(*vp++, i, 0);
  755. X        rv = (*tp->val.f)(ap);
  756. X        break;
  757. X
  758. X    case CFUNC:            /* function call */
  759. X        if (!(tp->flag&ISSET))
  760. X            errorf("%s: undefined function", cp);
  761. X        l->argv = ap;
  762. X        for (i = 0; *ap++ != NULL; i++)
  763. X            ;
  764. X        l->argc = i - 1;
  765. X        resetopts();
  766. X        while (*vp != NULL)
  767. X            (void) typeset(*vp++, LOCAL, 0);
  768. X        e.type = E_FUNC;
  769. X        if (setjmp(e.jbuf))
  770. X            rv = exstat; /* return # */
  771. X        else
  772. X            rv = execute(tp->val.t, 0);
  773. X        break;
  774. X
  775. X    case CEXEC:        /* executable command */
  776. X        if (!(tp->flag&ISSET)) {
  777. X            shellf("%s: not found\n", cp);
  778. X            rv = 1;
  779. X            break;
  780. X        }
  781. X
  782. X        /* set $_ to program's full path */
  783. X        setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
  784. X        while (*vp != NULL)
  785. X            (void) typeset(*vp++, LOCAL|EXPORT, 0);
  786. X
  787. X        if ((flags&XEXEC)) {
  788. X            j_exit();
  789. X            if (flag[FMONITOR] || !(flags&XBGND)) {
  790. X                signal(SIGINT, SIG_DFL);
  791. X                signal(SIGQUIT, SIG_DFL);
  792. X            }
  793. X        }
  794. X
  795. X        /* to fork we set up a TEXEC node and call execute */
  796. X        texec.left = t;    /* for tprint */
  797. X        texec.str = tp->val.s;
  798. X        texec.args = ap;
  799. X        rv = exchild(&texec, flags);
  800. X        break;
  801. X    }
  802. X    if (rv != 0 && flag[FERREXIT])
  803. X        leave(rv);
  804. X    return (exstat = rv);
  805. X}
  806. X
  807. Xint
  808. Xshcomexec(wp)
  809. X    register char **wp;
  810. X{
  811. X    register struct tbl *tp;
  812. X
  813. X    tp = tsearch(&builtins, *wp, hash(*wp));
  814. X    if (tp == NULL)
  815. X        errorf("%s: shcomexec botch\n", *wp);
  816. X    return (*tp->val.f)(wp);
  817. X}
  818. X
  819. X/*
  820. X * define function
  821. X */
  822. Xint
  823. Xdefine(name, t)
  824. X    char    *name;
  825. X    struct op *t;
  826. X{
  827. X    register struct block *l;
  828. X    register struct tbl *tp;
  829. X
  830. X    for (l = e.loc; l != NULL; l = l->next) {
  831. X        lastarea = &l->area;
  832. X        tp = tsearch(&l->funs, name, hash(name));
  833. X        if (tp != NULL && (tp->flag&DEFINED))
  834. X            break;
  835. X        if (l->next == NULL) {
  836. X            tp = tenter(&l->funs, name, hash(name));
  837. X            tp->flag = DEFINED|FUNCT;
  838. X            tp->type = CFUNC;
  839. X        }
  840. X    }
  841. X
  842. X    if ((tp->flag&ALLOC))
  843. X        tfree(tp->val.t, lastarea);
  844. X    tp->flag &= ~(ISSET|ALLOC);
  845. X
  846. X    if (t == NULL)        /* undefine */
  847. X        return 0;
  848. X
  849. X    tp->val.t = tcopy(t, lastarea);
  850. X    tp->flag |= (ISSET|ALLOC);
  851. X
  852. X    return 0;
  853. X}
  854. X
  855. X/*
  856. X * add builtin
  857. X */
  858. Xbuiltin(name, func)
  859. X    char *name;
  860. X    int (*func)();
  861. X{
  862. X    register struct tbl *tp;
  863. X    int flag = DEFINED;
  864. X
  865. X    if (*name == '=') {        /* sets keyword variables */
  866. X        name++;
  867. X        flag |= TRACE;    /* command does variable assignment */
  868. X    }
  869. X
  870. X    tp = tenter(&builtins, name, hash(name));
  871. X    tp->flag |= flag;
  872. X    tp->type = CSHELL;
  873. X    tp->val.f = func;
  874. X}
  875. X
  876. X/*
  877. X * find command
  878. X * either function, hashed command, or built-in (in that order)
  879. X */
  880. Xstruct tbl *
  881. Xfindcom(name, insert)
  882. X    char    *name;
  883. X    int    insert;            /* insert if not found */
  884. X{
  885. X    register struct block *l = e.loc;
  886. X    unsigned int h = hash(name);
  887. X    register struct    tbl *tp = NULL;
  888. X    static struct tbl temp;
  889. X
  890. X    if (strchr(name, '/') != NULL) {
  891. X        tp = &temp;
  892. X        tp->type = CEXEC;
  893. X        tp->flag = 0;    /* make ~ISSET */
  894. X        goto Search;
  895. X    }
  896. X    for (l = e.loc; l != NULL; l = l->next) {
  897. X        tp = tsearch(&l->funs, name, h);
  898. X        if (tp != NULL && (tp->flag&DEFINED))
  899. X            break;
  900. X    }
  901. X    if (tp == NULL)
  902. X        tp = tsearch(&commands, name, h);
  903. X    if (tp == NULL)
  904. X        tp = tsearch(&builtins, name, h);
  905. X    if (tp == NULL && insert) {
  906. X        tp = tenter(&commands, name, h);
  907. X        tp->type = CEXEC;
  908. X        tp->flag = DEFINED;
  909. X    }
  910. X  Search:
  911. X    if (tp->type == CEXEC && !(tp->flag&ISSET)) {
  912. X        if (!flag[FHASHALL]) {
  913. X            tp = &temp;
  914. X            tp->type = CEXEC;
  915. X            tp->flag = 0;    /* make ~ISSET */
  916. X        }
  917. X        name = search(name, path, 1);
  918. X        if (name != NULL) {
  919. X            tp->val.s = strsave(name,
  920. X                        (tp == &temp) ? ATEMP : APERM);
  921. X            tp->flag |= ISSET|ALLOC;
  922. X        }
  923. X    }
  924. X    return tp;
  925. X}
  926. X
  927. X/*
  928. X * flush executable commands with relative paths
  929. X */
  930. Xflushcom(all)
  931. X    int all;        /* just relative or all */
  932. X{
  933. X    register struct tbl *tp;
  934. X
  935. X    for (twalk(&commands); (tp = tnext()) != NULL; )
  936. X        if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
  937. X            if ((tp->flag&ALLOC))
  938. X                afree(tp->val.s, commands.areap);
  939. X            tp->flag = DEFINED; /* make ~ISSET */
  940. X        }
  941. X}
  942. X
  943. X/*
  944. X * search for command with PATH
  945. X */
  946. Xchar *
  947. Xsearch(name, path, mode)
  948. X    char *name, *path;
  949. X    int mode;        /* 0: readable; 1: executable */
  950. X{
  951. X    register int i;
  952. X    register char *sp, *tp;
  953. X
  954. X    if (strchr(name, '/'))
  955. X        return (eaccess(name, mode) == 0) ? name : NULL;
  956. X
  957. X    sp = path;
  958. X    do {
  959. X        tp = line;
  960. X        for (; *sp != '\0'; tp++)
  961. X            if ((*tp = *sp++) == ':')
  962. X                break;
  963. X        if (tp != line)
  964. X            *tp++ = '/';
  965. X        for (i = 0; (*tp++ = name[i++]) != '\0';)
  966. X            ;
  967. X        i = eaccess(line, mode);
  968. X        if (i == 0)
  969. X            return line;
  970. X        /* what should we do about EACCES? */
  971. X    } while (*sp != '\0');
  972. X    return NULL;
  973. X}
  974. X
  975. X/*
  976. X * set up redirection, saving old fd's in e.savefd
  977. X */
  978. Xstatic void
  979. Xiosetup(iop)
  980. X    register struct ioword *iop;
  981. X{
  982. X    register int u = -1;
  983. X    char *cp = iop->name;
  984. X    extern long lseek();
  985. X
  986. X    if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
  987. X        e.interactive = 0;
  988. X    e.savefd[iop->unit] = savefd(iop->unit);
  989. X
  990. X    if ((iop->flag&IOTYPE) != IOHERE)
  991. X        cp = evalstr(cp, DOTILDE);
  992. X
  993. X    switch (iop->flag&IOTYPE) {
  994. X      case IOREAD:
  995. X        u = open(cp, 0);
  996. X        break;
  997. X
  998. X      case IOCAT:
  999. X        if ((u = open(cp, 1)) >= 0) {
  1000. X            (void) lseek(u, (long)0, 2);
  1001. X            break;
  1002. X        }
  1003. X        /* FALLTHROUGH */
  1004. X      case IOWRITE:
  1005. X        u = creat(cp, 0666);
  1006. X        break;
  1007. X
  1008. X      case IORDWR:
  1009. X        u = open(cp, 2);
  1010. X        break;
  1011. X
  1012. X      case IOHERE:
  1013. X        u = herein(cp, iop->flag&IOEVAL);
  1014. X        /* cp may have wrong name */
  1015. X        break;
  1016. X
  1017. X      case IODUP:
  1018. X        if (*cp == '-')
  1019. X            close(iop->unit);
  1020. X        else
  1021. X        if (digit(*cp))
  1022. X            u = *cp - '0';
  1023. X        else
  1024. X            errorf("%s: illegal >& argument\n", cp);
  1025. X        break;
  1026. X    }
  1027. X    if (u < 0)
  1028. X        errorf("%s: cannot %s\n", cp,
  1029. X               (iop->flag&IOTYPE) == IOWRITE ? "create" : "open");
  1030. X    if (u != iop->unit) {
  1031. X        (void) dup2(u, iop->unit);
  1032. X        if (iop->flag != IODUP)
  1033. X            close(u);
  1034. X    }
  1035. X
  1036. X    fopenshf(iop->unit);
  1037. X}
  1038. X
  1039. X/*
  1040. X * open here document temp file.
  1041. X * if unquoted here, expand here temp file into second temp file.
  1042. X */
  1043. Xstatic int
  1044. Xherein(hname, sub)
  1045. X    char *hname;
  1046. X    int sub;
  1047. X{
  1048. X    int fd;
  1049. X    FILE * Volatile f = NULL;
  1050. X
  1051. X    f = fopen(hname, "r");
  1052. X    if (f == NULL)
  1053. X        return -1;
  1054. X    setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  1055. X
  1056. X    if (sub) {
  1057. X        char *cp;
  1058. X        struct source *s;
  1059. X        struct temp *h;
  1060. X
  1061. X        newenv(E_ERRH);
  1062. X        if (setjmp(e.jbuf)) {
  1063. X            if (f != NULL)
  1064. X                fclose(f);
  1065. X            quitenv();
  1066. X            return -1; /* todo: error()? */
  1067. X        }
  1068. X
  1069. X        /* set up yylex input from here file */
  1070. X        s = pushs(SFILE);
  1071. X        s->u.file = f;
  1072. X        source = s;
  1073. X        if (yylex(ONEWORD) != LWORD)
  1074. X            errorf("exec:herein error\n");
  1075. X        cp = evalstr(yylval.cp, 0);
  1076. X
  1077. X        /* write expanded input to another temp file */
  1078. X        h = maketemp(ATEMP);
  1079. X        h->next = e.temps; e.temps = h;
  1080. X        if (h == NULL)
  1081. X            error();
  1082. X        f = fopen(h->name, "w+");
  1083. X        if (f == NULL)
  1084. X            error();
  1085. X        setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  1086. X        fputs(cp, f);
  1087. X        rewind(f);
  1088. X
  1089. X        quitenv();
  1090. X    }
  1091. X    fd = dup(fileno(f));
  1092. X    fclose(f);
  1093. X    return fd;
  1094. X}
  1095. X
  1096. Xstatic void
  1097. Xecho(vp, ap)
  1098. X    register char **vp, **ap;
  1099. X{
  1100. X    shellf("+");
  1101. X    while (*vp != NULL)
  1102. X        shellf(" %s", *vp++);
  1103. X    while (*ap != NULL)
  1104. X        shellf(" %s", *ap++);
  1105. X    shellf("\n");
  1106. X}
  1107. X
  1108. SHAR_EOF
  1109. true || echo 'restore of src/exec.c failed'
  1110. fi
  1111. # ============= src/jobs.c ==============
  1112. if test -f 'src/jobs.c' -a X"$1" != X"-c"; then
  1113.     echo 'x - skipping src/jobs.c (File already exists)'
  1114. else
  1115. echo 'x - extracting src/jobs.c (Text)'
  1116. sed 's/^X//' << 'SHAR_EOF' > 'src/jobs.c' &&
  1117. X/*
  1118. X * Process and job control
  1119. X */
  1120. X
  1121. Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/jobs.c,v 3.4 88/12/14 19:49:17 egisin Exp $";
  1122. X
  1123. X/*
  1124. X * based on version by Ron Natalie, BRL
  1125. X *
  1126. X * TODO:
  1127. X *    change Proc table to Job table, with array of pids.
  1128. X *    make %+ be jobs, %- be jobs->next.
  1129. X *    do not JFREE members of pipeline.
  1130. X *    consider procs[] related critical sections.
  1131. X *    signal(SIGCHLD, j_sigchld) should be
  1132. X *    sigaction(SIGCHLD, sigchld, NULL),
  1133. X *    with sigchld.sa_flags = SA_RESTART.
  1134. X *    There is a simple work-around if there is no SA_RESTART.
  1135. X */
  1136. X
  1137. X#include <stddef.h>
  1138. X#include <string.h>
  1139. X#include <stdio.h>
  1140. X#include <errno.h>
  1141. X#include <unistd.h>
  1142. X#include <signal.h>
  1143. X#include <setjmp.h>
  1144. X#include <sys/types.h>
  1145. X#include <sys/times.h>
  1146. X#include <sys/wait.h>
  1147. X#if JOBS
  1148. X#if _BSD
  1149. X#include <sys/ioctl.h>
  1150. X#else
  1151. X#include "termios.h"
  1152. X#endif
  1153. X#endif
  1154. X#include "sh.h"
  1155. X#include "tree.h"
  1156. X
  1157. X#ifndef WIFCORED
  1158. X#define    WIFCORED(x)    (!!((x)&0x80)) /* non-standard */
  1159. X#endif
  1160. X
  1161. X/* as of P1003.1 Draft 12.3:
  1162. X *    pid_t getpgrp(void);        // Get process group id
  1163. X *    pid_t setsid(void);        // Create session and Set process group id
  1164. X *    int setpgid(pid_t pid, pid_t pgid); // Set process group id for job control
  1165. X */
  1166. X
  1167. X#if JOBS
  1168. X#if _BSD            /* _BSD 4.* */
  1169. X#define    setpgid(p, pg)    setpgrp(p, pg)
  1170. X#define    getpgid(p)    getpgrp(p)
  1171. X#define    tcsetpgrp(fd,p)    ioctl(fd, TIOCSPGRP, &(p))
  1172. X#else                /* POSIX-compatible */
  1173. X#define    getpgid(p)    getpgrp() /* 1003.1 stupidity */
  1174. X#define    killpg(p, s)    kill(-(p), s)
  1175. X#endif
  1176. X#endif
  1177. X
  1178. X#ifndef    SIGCHLD
  1179. X#define    SIGCHLD    SIGCLD
  1180. X#endif
  1181. X
  1182. Xtypedef struct Proc Proc;
  1183. Xstruct Proc {
  1184. X    Proc   *next;        /* `procs' list link */
  1185. X    int    job;        /* job number: %n */
  1186. X    short    Volatile state;    /* proc state */
  1187. X    short    Volatile notify; /* proc state has changed */
  1188. X    Proc   *prev;        /* prev member of pipeline */
  1189. X    pid_t    proc;        /* process id */
  1190. X    pid_t    pgrp;        /* process group if flag[FMONITOR] */
  1191. X    short    flags;        /* execute flags */
  1192. X    int    status;        /* wait status */
  1193. X    clock_t    utime, stime;    /* user/system time when JDONE */
  1194. X    char    com [48];    /* command */
  1195. X};
  1196. X
  1197. X/* proc states */
  1198. X#define    JFREE    0        /* unused proc */
  1199. X#define    JRUN    1        /* foreground */
  1200. X#define JEXIT    2        /* exit termination */
  1201. X#define    JSIGNAL    3        /* signal termination */
  1202. X#define    JSTOP    4        /* stopped */
  1203. X
  1204. Xstatic    Proc *procs = NULL;    /* job/process table */
  1205. X
  1206. Xclock_t    j_utime, j_stime;    /* user and system time for last job a-waited */
  1207. X#if JOBS
  1208. Xstatic    int    sm_default, sm_sigchld;    /* signal masks */
  1209. Xstatic    int    our_pgrp;        /* shell's pgrp */
  1210. X#endif
  1211. Xstatic    Proc   *j_lastj;        /* last proc created by exchild */
  1212. Xstatic    int    j_lastjob = 0;        /* last created job */
  1213. Xstatic    int    j_current = 0;        /* current job */
  1214. Xstatic    int    j_previous = 0;        /* previous job */
  1215. X
  1216. Xstatic    int    j_newjob ARGS((void));
  1217. Xstatic    void    j_print ARGS((Proc *j));
  1218. Xstatic    Proc   *j_search ARGS((int job));
  1219. Xstatic    int    j_waitj ARGS((Proc *j, int intr));
  1220. Xstatic    void    j_sigchld ARGS((int sig));
  1221. X    
  1222. X/* initialize job control */
  1223. Xvoid
  1224. Xj_init()
  1225. X{
  1226. X#if JOBS
  1227. X#ifdef NTTYDISC
  1228. X    int ldisc = NTTYDISC;    /* BSD brain damage */
  1229. X
  1230. X    if (ttyfd >= 0)
  1231. X        ioctl(ttyfd, TIOCSETD, &ldisc);
  1232. X#endif
  1233. X    our_pgrp = getpgid(0);
  1234. X    sm_default = 0;
  1235. X    sm_sigchld = sigmask(SIGCHLD);
  1236. X#endif
  1237. X}
  1238. X
  1239. X/* job cleanup before shell exit */
  1240. Xvoid
  1241. Xj_exit()
  1242. X{
  1243. X    register Proc *j;
  1244. X    int killed = 0;
  1245. X
  1246. X#if JOBS
  1247. X    /* kill stopped jobs */
  1248. X    for (j = procs; j != NULL; j = j->next)
  1249. X        if (j->state == JSTOP) {
  1250. X            killed ++;
  1251. X            killpg(j->pgrp, SIGHUP);
  1252. X            killpg(j->pgrp, SIGCONT);
  1253. X        }
  1254. X    if (killed)
  1255. X        sleep(1);
  1256. X#endif
  1257. X    j_notify();
  1258. X
  1259. X#if JOBS
  1260. X    if (flag[FMONITOR]) {
  1261. X        flag[FMONITOR] = 0;
  1262. X        j_change();
  1263. X    }
  1264. X#endif
  1265. X}
  1266. X
  1267. X#if JOBS
  1268. X/* turn job control on or off according to flag[FMONITOR] */
  1269. Xvoid
  1270. Xj_change()
  1271. X{
  1272. X    static handler_t old_tstp, old_ttin, old_ttou;
  1273. X
  1274. X    if (flag[FMONITOR]) {
  1275. X        if (ttyfd < 0) {
  1276. X            flag[FMONITOR] = 0;
  1277. X            shellf("job control requires tty\n");
  1278. X            return;
  1279. X        }
  1280. X        (void) signal(SIGCHLD, j_sigchld);
  1281. X        sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
  1282. X        old_tstp = signal(SIGTSTP, SIG_IGN);
  1283. X        sigtraps[SIGTSTP].sig_dfl = 1;
  1284. X        old_ttin = signal(SIGTTIN, SIG_IGN);
  1285. X        sigtraps[SIGTTIN].sig_dfl = 1;
  1286. X        old_ttou = signal(SIGTTOU, SIG_IGN);
  1287. X        sigtraps[SIGTTOU].sig_dfl = 1;
  1288. X        sigsetmask(sm_default);
  1289. X        tcsetpgrp(ttyfd, our_pgrp);
  1290. X    } else {
  1291. X        (void) signal(SIGCHLD, SIG_DFL);
  1292. X        (void) signal(SIGTSTP, old_tstp);
  1293. X        sigtraps[SIGTSTP].sig_dfl = 0;
  1294. X        (void) signal(SIGTTIN, old_ttin);
  1295. X        sigtraps[SIGTTIN].sig_dfl = 0;
  1296. X        (void) signal(SIGTTOU, old_ttou);
  1297. X        sigtraps[SIGTTOU].sig_dfl = 0;
  1298. X    }
  1299. X}
  1300. X#endif
  1301. X
  1302. X/* execute tree in child subprocess */
  1303. Xint
  1304. Xexchild(t, flags)
  1305. X    struct op *t;
  1306. X    int flags;
  1307. X{
  1308. X    register int i;
  1309. X    register Proc *j;
  1310. X    int rv = 0;
  1311. X
  1312. X    flags &= ~XFORK;
  1313. X    if ((flags&XEXEC))
  1314. X        return execute(t, flags);
  1315. X
  1316. X    /* get free Proc entry */
  1317. X    for (j = procs; j != NULL; j = j->next)
  1318. X        if (j->state == JFREE)
  1319. X            goto Found;
  1320. X    j = alloc(sizeof(Proc), APERM);
  1321. X    j->next = procs;
  1322. X    j->state = JFREE;
  1323. X    procs = j;
  1324. X  Found:
  1325. X
  1326. X    j->prev = ((flags&XPIPEI)) ? j_lastj : NULL;
  1327. X    j->proc = j->pgrp = 0;
  1328. X    j->flags = flags;
  1329. X    j->job = (flags&XPIPEI) ? j_lastjob : j_newjob();
  1330. X    snptreef(j->com, sizeof(j->com), "%T", t); /* save proc's command */
  1331. X    j->com[sizeof(j->com)-1] = '\0';
  1332. X    j->state = JRUN;
  1333. X
  1334. X    /* stdio buffer must be flushed and invalidated */
  1335. X    for (i = 0; i < NUFILE; i++)
  1336. X        flushshf(i);
  1337. X
  1338. X    /* create child process */
  1339. X    if ((i = fork()) < 0) {
  1340. X        /* todo: try a few times with exp-incr delay */
  1341. X        j->state = JFREE;
  1342. X        errorf("cannot fork - try again\n");
  1343. X    }
  1344. X    j->proc = (i != 0) ? i : getpid();
  1345. X
  1346. X#if JOBS
  1347. X    /* job control set up */
  1348. X    if (flag[FMONITOR] && !(flags&XXCOM)) {
  1349. X        j->pgrp = !(flags&XPIPEI) ? j->proc : j_lastj->pgrp;
  1350. X        /* do in both parent and child to avoid fork race condition */
  1351. X        if (!(flags&XBGND))
  1352. X            tcsetpgrp(ttyfd, j->pgrp); /* could be trouble */
  1353. X        setpgid(j->proc, j->pgrp);
  1354. X    }
  1355. X#endif
  1356. X    j_lastj = j;
  1357. X
  1358. X    if (i == 0) {        /* child */
  1359. X        e.oenv = NULL;
  1360. X        if (flag[FTALKING])
  1361. X            restoresigs();
  1362. X        if ((flags&XBGND) && !flag[FMONITOR]) {
  1363. X            signal(SIGINT, SIG_IGN);
  1364. X            signal(SIGQUIT, SIG_IGN);
  1365. X            if (flag[FTALKING])
  1366. X                signal(SIGTERM, SIG_DFL);
  1367. X            i = open("/dev/null", 0);
  1368. X            (void) dup2(i, 0);
  1369. X            close(i);
  1370. X        }
  1371. X        for (j = procs; j != NULL; j = j->next)
  1372. X            j->state = JFREE;
  1373. X        ttyfd = -1;
  1374. X        flag[FMONITOR] = flag[FTALKING] = 0;
  1375. X        cleartraps();
  1376. X        execute(t, flags|XEXEC); /* no return */
  1377. X        /* NOTREACHED */
  1378. X    }
  1379. X
  1380. X    /* shell (parent) stuff */
  1381. X    if ((flags&XBGND)) { /* async statement */
  1382. X        async = j->proc;
  1383. X        j_previous = j_current;
  1384. X        j_current = j->job;
  1385. X        if (flag[FTALKING])
  1386. X            j_print(j);
  1387. X    } else {        /* sync statement */
  1388. X        if (!(flags&XPIPE))
  1389. X            rv = j_waitj(j, 0);
  1390. X    }
  1391. X
  1392. X    return rv;
  1393. X}
  1394. X
  1395. X/* wait for last job: pipeline or $() sub-process */
  1396. Xint
  1397. Xwaitlast()
  1398. X{
  1399. X    return j_waitj(j_lastj, 0);
  1400. X}
  1401. X
  1402. X/* wait for job to complete or change state */
  1403. Xstatic int
  1404. Xj_waitj(aj, intr)
  1405. X    Proc *aj;
  1406. X    int intr;        /* interruptable */
  1407. X{
  1408. X    register Proc *j;
  1409. X    int rv = 1;
  1410. X    int ttysig = 0;
  1411. X
  1412. X#if JOBS
  1413. X    if (flag[FMONITOR])
  1414. X        sigsetmask(sm_sigchld);
  1415. X#endif
  1416. X    /* wait for all members of pipeline */
  1417. X    for (j = aj; j != NULL; j = j->prev) {
  1418. X        /* wait for job to finish, stop, or ^C of built-in wait */
  1419. X        while (j->state == JRUN) {
  1420. X#if JOBS
  1421. X            if (flag[FMONITOR])
  1422. X                sigpause(sm_default);
  1423. X            else
  1424. X#endif
  1425. X                j_sigchld(SIGCHLD);
  1426. X            if (sigtraps[SIGINT].set && intr)
  1427. X                goto Break;
  1428. X        }
  1429. X        if (j->state == JEXIT) { /* exit termination */
  1430. X            if (!(j->flags&XPIPEO))
  1431. X                rv = WEXITSTATUS(j->status);
  1432. X            j->notify = 0;
  1433. X        } else
  1434. X        if (j->state == JSIGNAL) { /* signalled to death */
  1435. X            if (!(j->flags&XPIPEO))
  1436. X                rv = 0x80 + WTERMSIG(j->status);
  1437. X            if (WTERMSIG(j->status) == SIGINT ||
  1438. X                WTERMSIG(j->status) == SIGPIPE && (j->flags&XPIPEO))
  1439. X                j->notify = 0;
  1440. X            if (WTERMSIG(j->status) == SIGINT ||
  1441. X                WTERMSIG(j->status) == SIGQUIT)
  1442. X                ttysig = 1;
  1443. X        } else
  1444. X#if JOBS
  1445. X        if (j->state == JSTOP)
  1446. X            if (WSTOPSIG(j->status) == SIGTSTP)
  1447. X                ttysig = 1;
  1448. X#else
  1449. X        ;
  1450. X#endif
  1451. X    }
  1452. X
  1453. X    /* compute total child time for time statement */
  1454. X    for (j = aj; j != NULL; j = j->prev)
  1455. X        j_utime += j->utime, j_stime += j->stime;
  1456. X
  1457. X    /* find new current job */
  1458. X#if JOBS
  1459. X    if (aj->state == JSTOP) {
  1460. X        j_previous = j_current;
  1461. X        j_current = aj->job;
  1462. X    } else {
  1463. X#else
  1464. X    if (1) {
  1465. X#endif
  1466. X        int hijob = 0;
  1467. X
  1468. X        /* todo: this needs to be done in j_notify */
  1469. X        /* todo: figure out what to do with j_previous */
  1470. X        j_current = 0;
  1471. X        for (j = procs; j != NULL; j = j->next)
  1472. X            if ((j->state == JRUN || j->state == JSTOP)
  1473. X                && j->job > hijob) {
  1474. X                hijob = j->job;
  1475. X                j_current = j->job;
  1476. X            }
  1477. X    }
  1478. X
  1479. X  Break:
  1480. X#if JOBS
  1481. X    if (flag[FMONITOR]) {
  1482. X        /* reset shell job control state */
  1483. X        sigsetmask(sm_default);
  1484. X        tcsetpgrp(ttyfd, our_pgrp);
  1485. X    }
  1486. X#endif
  1487. X    if (ttysig)
  1488. X        fputc('\n', shlout);
  1489. X    j_notify();
  1490. X
  1491. X    return rv;
  1492. X}
  1493. X
  1494. X/* SIGCHLD handler to reap children */
  1495. Xstatic void
  1496. Xj_sigchld(sig)
  1497. X    int sig;
  1498. X{
  1499. X    int errno_ = errno;
  1500. X    struct tms t0, t1;
  1501. X
  1502. X    (void) times(&t0);
  1503. X    do {
  1504. X        register Proc *j;
  1505. X        int pid, status;
  1506. X#if JOBS
  1507. X        if (flag[FMONITOR])
  1508. X            pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
  1509. X        else
  1510. X#endif
  1511. X            pid = wait(&status);
  1512. X        if (pid <= 0)    /* return if would block (0) ... */
  1513. X            break;    /* ... or no children or interrupted (-1) */
  1514. X        (void) times(&t1);
  1515. X
  1516. X        for (j = procs; j != NULL; j = j->next)
  1517. X            if (j->state != JFREE && pid == j->proc)
  1518. X                goto Found;
  1519. X        continue;
  1520. X
  1521. X      Found:
  1522. X        j->notify = 1;
  1523. X        j->status = status;
  1524. X#if JOBS
  1525. X        if (WIFSTOPPED(status))
  1526. X            j->state = JSTOP;
  1527. X        else
  1528. X#endif
  1529. X        if (WIFEXITED(status))
  1530. X            j->state = JEXIT;
  1531. X        else
  1532. X        if (WIFSIGNALED(status))
  1533. X            j->state = JSIGNAL;
  1534. X
  1535. X        /* compute child's time */
  1536. X        /* todo: what does a stopped job do? */
  1537. X        j->utime = t1.tms_cutime - t0.tms_cutime;
  1538. X        j->stime = t1.tms_cstime - t0.tms_cstime;
  1539. X        t0 = t1;
  1540. X#if JOBS
  1541. X    } while (flag[FMONITOR]);
  1542. X#else
  1543. X    } while (0);        /* only once if wait()ing */
  1544. X#endif
  1545. X
  1546. X    errno = errno_;
  1547. X}
  1548. X
  1549. X/* wait for child, interruptable */
  1550. Xint
  1551. Xwaitfor(job)
  1552. X    int job;
  1553. X{
  1554. X    register Proc *j;
  1555. X
  1556. X    if (job == 0 && j_current == 0)
  1557. X        errorf("no current job\n");
  1558. X    j = j_search((job == 0) ? j_current : job);
  1559. X    if (j == NULL)
  1560. X        errorf("no such job: %d\n", job);
  1561. X    if (flag[FTALKING])
  1562. X        j_print(j);
  1563. X    if (e.interactive) {    /* flush stdout, shlout */
  1564. X        fflush(shf[1]);
  1565. X        fflush(shf[2]);
  1566. X    }
  1567. X    return j_waitj(j, 1);
  1568. X}
  1569. X
  1570. X/* kill (built-in) a job */
  1571. Xvoid
  1572. Xj_kill(job, sig)
  1573. X    int job;
  1574. X    int sig;
  1575. X{
  1576. X    register Proc *j;
  1577. X
  1578. X    j = j_search(job);
  1579. X    if (j == NULL)
  1580. X        errorf("cannot find job\n");
  1581. X    if (j->pgrp == 0) {    /* !flag[FMONITOR] */
  1582. X        if (kill(j->proc, sig) < 0) /* todo: all member of pipeline */
  1583. X            errorf("kill: %s\n", strerror(errno));
  1584. X#if JOBS
  1585. X    } else {
  1586. X        if (sig == SIGTERM || sig == SIGHUP)
  1587. X            (void) killpg(j->pgrp, SIGCONT);
  1588. X        if (killpg(j->pgrp, sig) < 0)
  1589. X            errorf("killpg: %s\n", strerror(errno));
  1590. X#endif
  1591. X    }
  1592. X}
  1593. X
  1594. X#if JOBS
  1595. X
  1596. X/* fg and bg built-ins */
  1597. Xint
  1598. Xj_resume(job, bg)
  1599. X    int job;
  1600. X    int bg;
  1601. X{
  1602. X    register Proc *j; 
  1603. X    
  1604. X    j = j_search((job == 0) ? j_current : job);
  1605. X    if (j == NULL)
  1606. X        errorf("cannot find job\n", job);
  1607. X    if (j->pgrp == 0)
  1608. X        errorf("job not job-controlled\n");
  1609. X
  1610. X    j->state = JRUN;
  1611. X    j_print(j);
  1612. X    flushshf(2);
  1613. X
  1614. X    if (!bg)
  1615. X          tcsetpgrp(ttyfd, j->pgrp); /* attach shell to job */
  1616. X    if (killpg(j->pgrp, SIGCONT) < 0)
  1617. X        errorf("cannot continue job %%%d\n", job);
  1618. X    if (!bg)
  1619. X        return j_waitj(j, 0);
  1620. X    return 0;
  1621. X}
  1622. X
  1623. X#endif
  1624. X
  1625. X/* list jobs for jobs built-in */
  1626. Xvoid
  1627. Xj_jobs()
  1628. X{
  1629. X    register Proc *j; 
  1630. X
  1631. X    for (j = procs; j != NULL; j = j->next)
  1632. X        if (j->state != JFREE)
  1633. X            j_print(j);
  1634. X}
  1635. X
  1636. X/* list jobs for top-level notification */
  1637. Xvoid
  1638. Xj_notify()
  1639. X{
  1640. X    register Proc *j; 
  1641. X
  1642. X    for (j = procs; j != NULL; j = j->next) {
  1643. X        if (j->state == JEXIT && !flag[FTALKING])
  1644. X            j->notify = 0;
  1645. X        if (j->state != JFREE && j->notify)
  1646. X            j_print(j);
  1647. X        if (j->state == JEXIT || j->state == JSIGNAL)
  1648. X            j->state = JFREE;
  1649. X        j->notify = 0;
  1650. X    }
  1651. X}
  1652. X
  1653. Xstatic void
  1654. Xj_print(j)
  1655. X    register Proc *j;
  1656. X{
  1657. X    char buf [64], *s = buf;
  1658. X
  1659. X    switch (j->state) {
  1660. X      case JRUN:
  1661. X        s = "Running";
  1662. X        break;
  1663. X
  1664. X#if JOBS
  1665. X      case JSTOP:
  1666. X        strcpy(buf, "Stopped ");
  1667. X        s = strchr(sigtraps[WSTOPSIG(j->status)].mess, '(');
  1668. X        if (s != NULL)
  1669. X            strcat(buf, s);
  1670. X        s = buf;
  1671. X        break;
  1672. X#endif
  1673. X
  1674. X      case JEXIT: {
  1675. X        int rv;
  1676. X        rv = WEXITSTATUS(j->status);
  1677. X        sprintf(buf, "Done (%d)", rv);
  1678. X        if (rv == 0)
  1679. X            *strchr(buf, '(') = 0;
  1680. X        j->state = JFREE;
  1681. X        } break;
  1682. X
  1683. X      case JSIGNAL: {
  1684. X        int sig = WTERMSIG(j->status);
  1685. X        char *n = sigtraps[sig].mess;
  1686. X        if (n != NULL)
  1687. X            sprintf(buf, "%s", n);
  1688. X        else
  1689. X            sprintf(buf, "Signal %d", sig);
  1690. X        if (WIFCORED(j->status))
  1691. X            strcat(buf, " - core dumped");
  1692. X        j->state = JFREE;
  1693. X        } break;
  1694. X
  1695. X      default:
  1696. X        s = "Hideous job state";
  1697. X        j->state = JFREE;
  1698. X        break;
  1699. X    }
  1700. X    shellf("%%%-2d%c %5d %-20s %s%s\n", j->job,
  1701. X           (j_current==j->job) ? '+' : (j_previous==j->job) ? '-' : ' ',
  1702. X           j->proc, s, j->com, (j->flags&XPIPEO) ? "|" : "");
  1703. X}
  1704. X
  1705. X/* convert % sequence to job number */
  1706. Xint
  1707. Xj_lookup(cp)
  1708. X    char *cp;
  1709. X{
  1710. X    register Proc *j;
  1711. X    int len, job = 0;
  1712. X
  1713. X    if (*cp == '%')        /* leading % is optional */
  1714. X        cp++;
  1715. X    switch (*cp) {
  1716. X      case '\0':
  1717. X      case '+':
  1718. X        job = j_current;
  1719. X        break;
  1720. X
  1721. X      case '-':
  1722. X        job = j_previous;
  1723. X        break;
  1724. X
  1725. X      case '0': case '1': case '2': case '3': case '4':
  1726. X      case '5': case '6': case '7': case '8': case '9': 
  1727. X        job = atoi(cp);
  1728. X        break;
  1729. X
  1730. X      case '?':        /* %?string */
  1731. X        for (j = procs; j != NULL; j = j->next)
  1732. X            if (j->state != JFREE && strstr(j->com, cp+1) != NULL)
  1733. X                job = j->job;
  1734. X        break;
  1735. X
  1736. X      default:        /* %string */
  1737. X        len = strlen(cp);
  1738. X        for (j = procs; j != NULL; j = j->next)
  1739. X            if (j->state != JFREE && strncmp(cp, j->com, len) == 0)
  1740. X                job = j->job;
  1741. X        break;
  1742. X    }
  1743. X    if (job == 0)
  1744. X        errorf("%s: no such job\n", cp);
  1745. X    return job;
  1746. X}
  1747. X
  1748. X/* are any stopped jobs ? */
  1749. X#if JOBS
  1750. Xint
  1751. Xj_stopped()
  1752. X{
  1753. X    register Proc *j; 
  1754. X
  1755. X    for (j = procs; j != NULL; j = j->next)
  1756. X        if (j->state == JSTOP)
  1757. X            return 1;
  1758. X    return 0;
  1759. X}
  1760. X#endif
  1761. X
  1762. X/* create new job number */
  1763. Xstatic int
  1764. Xj_newjob()
  1765. X{
  1766. X    register Proc *j; 
  1767. X    register int max = 0;
  1768. X    
  1769. X    j_lastjob ++;
  1770. X    for (j = procs; j != NULL; j = j->next)
  1771. X        if (j->state != JFREE && j->job)
  1772. X            if (j->job > max)
  1773. X                max = j->job;
  1774. X    if (j_lastjob > max)
  1775. X        j_lastjob = max + 1;
  1776. X    return j_lastjob;
  1777. X}
  1778. X
  1779. X/* search for job by job number */
  1780. Xstatic Proc *
  1781. Xj_search(job)
  1782. X    int job;
  1783. X{
  1784. X    register Proc *j;
  1785. X
  1786. X    for (j = procs; j != NULL; j = j->next)
  1787. X        if (j->state != JFREE && job == j->job && !(j->flags&XPIPEO))
  1788. X            return j;
  1789. X    return NULL;
  1790. X}
  1791. X
  1792. SHAR_EOF
  1793. true || echo 'restore of src/jobs.c failed'
  1794. fi
  1795. # ============= src/c_sh.c ==============
  1796. if test -f 'src/c_sh.c' -a X"$1" != X"-c"; then
  1797.     echo 'x - skipping src/c_sh.c (File already exists)'
  1798. else
  1799. echo 'x - extracting src/c_sh.c (Text)'
  1800. sed 's/^X//' << 'SHAR_EOF' > 'src/c_sh.c' &&
  1801. X/*
  1802. X * built-in Bourne commands
  1803. X */
  1804. X
  1805. Xstatic char *RCSid = "Id: /u/egisin/sh/src/RCS/c_sh.c,v 3.1 88/11/03 09:14:31 egisin Exp $";
  1806. X
  1807. X#include <stddef.h>
  1808. X#include <stdio.h>
  1809. X#include <string.h>
  1810. X#include <errno.h>
  1811. X#include <signal.h>
  1812. X#include <setjmp.h>
  1813. X#include <sys/times.h>
  1814. X#include <unistd.h>        /* getcwd */
  1815. X#include "sh.h"
  1816. X#include "lex.h"
  1817. X#include "tree.h"
  1818. X#include "table.h"
  1819. X
  1820. Xstatic    char *clocktos();
  1821. X
  1822. Xint
  1823. Xc_label(wp)
  1824. X    char **wp;
  1825. X{
  1826. X    return 0;
  1827. X}
  1828. X
  1829. X/* todo: add symlink hacks */
  1830. Xint
  1831. Xc_cd(wp)
  1832. X    register char **wp;
  1833. X{
  1834. X    char path [PATH];
  1835. X    register char *cp;
  1836. X    register struct tbl *vp;
  1837. X
  1838. X    if ((cp = wp[1]) == NULL && (cp = strval(global("HOME"))) == NULL)
  1839. X        errorf("no home directory");
  1840. X    if (strcmp(cp, "-") == 0) {
  1841. X        cp = strval(global("OLDPWD"));
  1842. X        shellf("%s\n", cp);
  1843. X    }
  1844. X    if (chdir(cp) < 0)
  1845. X        errorf("%s: bad directory\n", cp);
  1846. X    flushcom(0);
  1847. X
  1848. X    /* maintain $PWD and $OLDPWD */
  1849. X    vp = global("PWD");
  1850. X    cp = strval(vp);
  1851. X    if (cp != null)
  1852. X        setstr(global("OLDPWD"), cp);
  1853. X    cp = getcwd(path, (size_t)PATH);
  1854. X    if (cp == NULL)
  1855. X        unset(vp);
  1856. X    else
  1857. X        setstr(vp, cp);
  1858. X
  1859. X    return 0;
  1860. X}
  1861. X
  1862. Xint
  1863. Xc_shift(wp)
  1864. X    register char **wp;
  1865. X{
  1866. X    register struct block *l = e.loc;
  1867. X    register int n;
  1868. X
  1869. X    n = wp[1] ? evaluate(wp[1]) : 1;
  1870. X    if (l->argc < n) {
  1871. X        errorf("nothing to shift\n");
  1872. X        return (1);
  1873. X    }
  1874. X    l->argv[n] = l->argv[0];
  1875. X    l->argv += n;
  1876. X    l->argc -= n;
  1877. X    return 0;
  1878. X}
  1879. X
  1880. Xint
  1881. Xc_umask(wp)
  1882. X    register char **wp;
  1883. X{
  1884. X    register int i;
  1885. X    register char *cp;
  1886. X
  1887. X    if ((cp = wp[1]) == NULL) {
  1888. X        i = umask(0);
  1889. X        umask(i);
  1890. X        printf("%#3.3o\n", i);    /* should this be shell output? */
  1891. X    } else {
  1892. X        for (i = 0; *cp>='0' && *cp<='7'; cp++)
  1893. X            i = i*8 + (*cp-'0');
  1894. X        umask(i);
  1895. X    }
  1896. X    return 0;
  1897. X}
  1898. X
  1899. Xint
  1900. Xc_dot(wp)
  1901. X    char **wp;
  1902. X{
  1903. X    char *file, *cp;
  1904. X
  1905. X    if ((cp = wp[1]) == NULL)
  1906. X        return 0;
  1907. X    file = search(cp, path, 0);
  1908. X    if (file == NULL)
  1909. X        errorf("%s: not found\n", cp);
  1910. X    if (include(file))
  1911. X        return exstat;
  1912. X    return -1;
  1913. X}
  1914. X
  1915. Xint
  1916. Xc_wait(wp)
  1917. X    char **wp;
  1918. X{
  1919. X    register char *cp;
  1920. X
  1921. X    wp++;
  1922. X    cp = *wp;
  1923. X    if (cp == NULL) cp = "%";
  1924. X    /* todo: print status ? */
  1925. X    return waitfor(j_lookup(cp));
  1926. X}
  1927. X
  1928. Xint
  1929. Xc_read(wp)
  1930. X    register char **wp;
  1931. X{
  1932. X    register int c = 0;
  1933. X    FILE *f = stdin;
  1934. X    int expand = 1;
  1935. X    register char *cp;
  1936. X
  1937. X    for (wp++; (cp = *wp) != NULL && *cp++ == '-'; wp++) {
  1938. X        while (*cp) switch (*cp++) {
  1939. X          case 'e':
  1940. X            expand = 1;
  1941. X            break;
  1942. X          case 'r':
  1943. X            expand = 0;
  1944. X            break;
  1945. X          case 'u':
  1946. X            if (!digit(*cp) || (f = shf[*cp++-'0']) == NULL)
  1947. X                errorf("bad -u argument\n");
  1948. X            break;
  1949. X        }
  1950. X    }
  1951. X
  1952. X    if (*wp == NULL)
  1953. X        errorf("missing name\n");
  1954. X    if ((cp = strchr(*wp, '?')) != NULL) {
  1955. X        *cp = 0;
  1956. X        if (flag[FTALKING]) {
  1957. X            shellf("%s ", cp+1);
  1958. X            fflush(shlout);
  1959. X        }
  1960. X    }
  1961. X
  1962. X    for (; *wp != NULL; wp++) {
  1963. X        for (cp = line; cp <= line+LINE; ) {
  1964. X            if (c == '\n')
  1965. X                break;
  1966. X            c = getc(f);
  1967. X            if (c == EOF)
  1968. X                return 1;
  1969. X            if (expand && c == '\\') {
  1970. X                c = getc(f);
  1971. X                if (c == '\n')
  1972. X                    c = 0;
  1973. X                else
  1974. X                    *cp++ = c;
  1975. X                continue;
  1976. X            }
  1977. X            if (c == '\n' || wp[1] && ctype(c, C_IFS))
  1978. X                break;
  1979. X            *cp++ = c;
  1980. X        }
  1981. X        *cp = 0;
  1982. X        setstr(global(*wp), line);
  1983. X    }
  1984. X    return 0;
  1985. X}
  1986. X
  1987. Xint
  1988. Xc_eval(wp)
  1989. X    register char **wp;
  1990. X{
  1991. X    register struct source *s;
  1992. X
  1993. X    s = pushs(SWORDS);
  1994. X    s->u.strv = wp+1;
  1995. X    return shell(s);
  1996. X}
  1997. X
  1998. Xvoid setsig ARGS((struct trap *p, handler_t f));
  1999. X
  2000. Xint
  2001. Xc_trap(wp)
  2002. X    register char **wp;
  2003. X{
  2004. X    int i;
  2005. X    char *s;
  2006. X    register struct trap *p;
  2007. X
  2008. X    wp++;
  2009. X    if (*wp == NULL) {
  2010. X        for (p = sigtraps, i = SIGNALS; --i >= 0; p++) {
  2011. X            if (p->trap != NULL)
  2012. X                shellf("%s: %s\n", p->name, p->trap);
  2013. X        }
  2014. X        return 0;
  2015. X    }
  2016. X
  2017. X    s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */
  2018. X    if (s != NULL && s[0] == '-' && s[1] == '\0')
  2019. X        s = NULL;
  2020. X
  2021. X    /* set/clear traps */
  2022. X    while (*wp != NULL) {
  2023. X        p = gettrap(*wp++);
  2024. X        if (p == NULL)
  2025. X            errorf("trap: bad signal %s\n", wp[-1]);
  2026. X        if (p->trap != NULL)
  2027. X            afree((Void*)p->trap, APERM);
  2028. X        p->trap = NULL;
  2029. X        if (s != NULL) {
  2030. X            if (strlen(s) != 0) {
  2031. X                p->trap = strsave(s, APERM);
  2032. X                setsig(p, trapsig);
  2033. X            } else
  2034. X                setsig(p, (handler_t)SIG_IGN);
  2035. X        } else
  2036. X            /* todo: restore to orginal value */
  2037. X            setsig(p,
  2038. X               (p->signal==SIGINT || p->signal==SIGQUIT) && flag[FTALKING]
  2039. X               ? (handler_t)SIG_IGN : (handler_t)SIG_DFL);
  2040. X    }
  2041. X    return 0;
  2042. X}
  2043. X
  2044. Xvoid
  2045. Xsetsig(p, f)
  2046. X    register struct trap *p;
  2047. X    void (*f)();
  2048. X{
  2049. X    if (p->signal == 0)
  2050. X        return;
  2051. X    if (signal(p->signal, SIG_IGN) != SIG_IGN || p->ourtrap) {
  2052. X        p->ourtrap = 1;
  2053. X        signal(p->signal, f);
  2054. X    }
  2055. X}
  2056. X
  2057. Xint
  2058. Xc_return(wp)
  2059. X    char **wp;
  2060. X{
  2061. X    wp++;
  2062. X    if (*wp != NULL)
  2063. X        exstat = getn(*wp);
  2064. X    quitenv();        /* pop E_TCOM */
  2065. X    while (e.type == E_LOOP || e.type == E_EXEC)
  2066. X        quitenv();
  2067. X    if (e.type == E_FUNC)
  2068. X        longjmp(e.jbuf, 1);
  2069. X    leave(exstat);
  2070. X}
  2071. X
  2072. Xint
  2073. Xc_brkcont(wp)
  2074. X    register char **wp;
  2075. X{
  2076. X    int quit;
  2077. X
  2078. X    quit = wp[1] == NULL ? 1 : getn(wp[1]);
  2079. X    quitenv();        /* pop E_TCOM */
  2080. X    while (e.type == E_LOOP || e.type == E_EXEC) {
  2081. X        if (e.type == E_LOOP && --quit <= 0)
  2082. X            longjmp(e.jbuf, (*wp[0] == 'b') ? LBREAK : LCONTIN);
  2083. X        quitenv();
  2084. X    }
  2085. X    errorf("cannot %s\n", wp[0]);
  2086. X}
  2087. X
  2088. Xint
  2089. Xc_exit(wp)
  2090. X    char **wp;
  2091. X{
  2092. X    register char *cp;
  2093. X
  2094. X    e.oenv = NULL;
  2095. X    if ((cp = wp[1]) != NULL)
  2096. X        exstat = getn(cp);
  2097. X#if JOBS
  2098. X    if (flag[FMONITOR] && j_stopped()) /* todo: only once */
  2099. X        errorf("There are stopped jobs\n");
  2100. X#endif
  2101. X    leave(exstat);
  2102. X}
  2103. X
  2104. Xint
  2105. Xc_set(wp)
  2106. X    register char **wp;
  2107. X{
  2108. X    struct block *l = e.loc;
  2109. X    register struct tbl *vp, **p;
  2110. X    register char **owp = wp;
  2111. X    register char *cp;
  2112. X    int old_fmonitor = flag[FMONITOR];
  2113. X
  2114. X    if ((cp = *++wp) == NULL) {
  2115. X        static char * Const args [] = {"set", "-", NULL};
  2116. X        extern int c_typeset ARGS((char **args));
  2117. X        return c_typeset(args);
  2118. X    }
  2119. X    
  2120. X    for (; (cp = *wp) != NULL && (*cp == '-' || *cp == '+');) {
  2121. X        int i, n = *cp++ == '-'; /* set or clear flag */
  2122. X        wp++;
  2123. X        if (*cp == '\0') {
  2124. X            if (n)
  2125. X                flag[FXTRACE] = flag[FVERBOSE] = 0;
  2126. X            break;
  2127. X        }
  2128. X        if (*cp == '-')
  2129. X            goto setargs;
  2130. X        for (; *cp != '\0'; cp++)
  2131. X            if (*cp == 'o') {
  2132. X                if (*wp == NULL) {
  2133. X                    printoptions();
  2134. X                    return 0;
  2135. X                }
  2136. X                i = option(*wp++);
  2137. X                if (i == 0)
  2138. X                    shellf("%s: unknown option\n", *--wp);
  2139. X                flag[i] = n;
  2140. X            } else if (*cp>='a' && *cp<='z')
  2141. X                flag[FLAG(*cp)] = n;
  2142. X            else
  2143. X                errorf("%c: bad flag\n", *cp);
  2144. X        if (flag[FTALKING])
  2145. X            flag[FERREXIT] = 0;
  2146. X    }
  2147. X
  2148. X#if JOBS
  2149. X    if (old_fmonitor != flag[FMONITOR])
  2150. X        j_change();
  2151. X#endif
  2152. X
  2153. X    /* set $# and $* */
  2154. X    if (*wp != NULL) {
  2155. X      setargs:
  2156. X        owp = --wp;
  2157. X        wp[0] = l->argv[0]; /* save $0 */
  2158. X        while (*++wp != NULL)
  2159. X            *wp = strsave(*wp, &l->area);
  2160. X        l->argc = wp - owp - 1;
  2161. X        l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
  2162. X        for (wp = l->argv; (*wp++ = *owp++) != NULL; )
  2163. X            ;
  2164. X        resetopts();
  2165. X    }
  2166. X    return 0;
  2167. X}
  2168. X
  2169. Xint
  2170. Xc_unset(wp)
  2171. X    register char **wp;
  2172. X{
  2173. X    register char *id;
  2174. X    int flagf = 0;
  2175. X
  2176. X    for (wp++; (id = *wp) != NULL && *id == '-'; wp++)
  2177. X        if (*++id == 'f')
  2178. X            flagf++;
  2179. X    for (; (id = *wp) != NULL; wp++)
  2180. X        if (!flagf) {    /* unset variable */
  2181. X            unset(local(id));
  2182. X        } else {    /* unset function */
  2183. X            register struct tbl *tp;
  2184. X            tp = tsearch(&e.loc->funs, id, hash(id));
  2185. X            if (tp != NULL)
  2186. X                define(tp, (struct op *)NULL);
  2187. X        }
  2188. X    return 0;
  2189. X}
  2190. X
  2191. Xint
  2192. Xc_ulimit(wp)
  2193. X    register char **wp;
  2194. X{
  2195. X    extern int do_ulimit();
  2196. X
  2197. X    return do_ulimit(wp[1], wp[2]);
  2198. X}
  2199. X
  2200. Xint
  2201. Xc_times(wp)
  2202. X    char **wp;
  2203. X{
  2204. X    struct tms all;
  2205. X
  2206. X    (void) times(&all);
  2207. X    printf("Shell: ");
  2208. X    printf("%8s user ", clocktos(all.tms_utime));
  2209. X    printf("%8s system\n", clocktos(all.tms_stime));
  2210. X    printf("Kids:  ");
  2211. X    printf("%8s user ", clocktos(all.tms_cutime));
  2212. X    printf("%8s system\n", clocktos(all.tms_cstime));
  2213. X
  2214. X    return 0;
  2215. X}
  2216. X
  2217. X/*
  2218. X * time pipeline (really a statement, not a built-in comman)
  2219. X */
  2220. Xint
  2221. Xtimex(t, f)
  2222. X    struct op *t;
  2223. X    int f;
  2224. X{
  2225. X    int rv;
  2226. X    struct tms t0, t1;
  2227. X    clock_t t0t, t1t;
  2228. X    extern clock_t j_utime, j_stime; /* computed by j_wait */
  2229. X
  2230. X    j_utime = j_stime = 0;
  2231. X    t0t = times(&t0);
  2232. X    rv = execute(t->left, f);
  2233. X    t1t = times(&t1);
  2234. X
  2235. X    shellf("%8s real ", clocktos(t1t - t0t));
  2236. X    shellf("%8s user ",
  2237. X           clocktos(t1.tms_utime - t0.tms_utime + j_utime));
  2238. X    shellf("%8s system ",
  2239. X           clocktos(t1.tms_stime - t0.tms_stime + j_stime));
  2240. X    shellf("\n");
  2241. X
  2242. X    return rv;
  2243. X}
  2244. X
  2245. Xstatic char *
  2246. Xclocktos(t)
  2247. X    clock_t t;
  2248. X{
  2249. X    static char temp[20];
  2250. X    register int i;
  2251. X    register char *cp = temp + sizeof(temp);
  2252. X
  2253. X#if CLK_TCK != 100        /* convert to 1/100'ths */
  2254. X    t = (t < 1000000000/CLK_TCK) ?
  2255. X        (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
  2256. X#endif
  2257. X
  2258. X    *--cp = '\0';
  2259. X    *--cp = 's';
  2260. X    for (i = -2; i <= 0 || t > 0; i++) {
  2261. X        if (i == 0)
  2262. X            *--cp = '.';
  2263. X        *--cp = '0' + (char)(t%10);
  2264. X        t /= 10;
  2265. X    }
  2266. X    return cp;
  2267. X}
  2268. X
  2269. X/* dummy function, special case in comexec() */
  2270. Xint
  2271. Xc_exec(wp)
  2272. X    char ** wp;
  2273. X{
  2274. X    return 0;
  2275. X}
  2276. X
  2277. X/* dummy function, special case in comexec() */
  2278. Xint
  2279. Xc_builtin(wp)
  2280. X    char ** wp;
  2281. X{
  2282. X    return 0;
  2283. X}
  2284. X
  2285. Xextern    int c_test();        /* in test.c */
  2286. X
  2287. XConst struct builtin shbuiltins [] = {
  2288. X    {"=:", c_label},
  2289. X    {"=.", c_dot},
  2290. X    {"[", c_test},
  2291. X    {"=cd", c_cd},
  2292. X    {"builtin", c_builtin},
  2293. X    {"=exec", c_exec},
  2294. X    {"=shift", c_shift},
  2295. X    {"wait", c_wait},
  2296. X    {"read", c_read},
  2297. X    {"=eval", c_eval},
  2298. X    {"trap", c_trap},
  2299. X    {"break", c_brkcont},
  2300. X    {"continue", c_brkcont},
  2301. X    {"exit", c_exit},
  2302. X    {"=return", c_return},
  2303. X    {"=set", c_set},
  2304. X    {"=unset", c_unset},
  2305. X    {"umask", c_umask},
  2306. X    {"test", c_test},
  2307. X    {"times", c_times},
  2308. X    {"ulimit", c_ulimit},
  2309. X    {NULL, NULL}
  2310. X};
  2311. X
  2312. SHAR_EOF
  2313. true || echo 'restore of src/c_sh.c failed'
  2314. fi
  2315. true || echo 'restore of src/c_ksh.c failed'
  2316. echo End of part 4, continue with part 5
  2317. exit 0
  2318.