home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume23 / rc / part06 < prev    next >
Encoding:
Text File  |  1991-10-18  |  47.7 KB  |  2,061 lines

  1. Newsgroups: comp.sources.misc
  2. From: byron@archone.tamu.edu (Byron Rakitzis)
  3. Subject:  v23i066:  rc - A Plan 9 shell reimplementation, v1.2, Part06/06
  4. Message-ID: <1991Oct18.034533.2626@sparky.imd.sterling.com>
  5. X-Md4-Signature: 34f51e7a094aa424e830d9bdcf6f92e3
  6. Date: Fri, 18 Oct 1991 03:45:33 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
  10. Posting-number: Volume 23, Issue 66
  11. Archive-name: rc/part06
  12. Environment: UNIX
  13. Supersedes: rc: Volume 20, Issue 10-13
  14.  
  15. #!/bin/sh
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file redir.c continued
  18. #
  19. if test ! -r _shar_seq_.tmp; then
  20.     echo 'Please unpack part 1 first!'
  21.     exit 1
  22. fi
  23. (read Scheck
  24.  if test "$Scheck" != 6; then
  25.     echo Please unpack part "$Scheck" next!
  26.     exit 1
  27.  else
  28.     exit 0
  29.  fi
  30. ) < _shar_seq_.tmp || exit 1
  31. if test ! -f _shar_wnt_.tmp; then
  32.     echo 'x - still skipping redir.c'
  33. else
  34. echo 'x - continuing file redir.c'
  35. sed 's/^X//' << 'SHAR_EOF' >> 'redir.c' &&
  36. X                        exit(1);
  37. X                    }
  38. X                    close(p[0]);
  39. X                }
  40. X            } else {
  41. X                fname = glob(glom(r->r->u[2].p));
  42. X                if (fname == NULL) {
  43. X                    fprint(2,"null filename in redirection\n");
  44. X                    exit(1);
  45. X                }
  46. X                if (fname->n != NULL) {
  47. X                    fprint(2,"multi-word filename in redirection\n");
  48. X                    exit(1);
  49. X                }
  50. X                switch (r->r->u[0].i) {
  51. X                default:
  52. X                    fprint(2,"doredirs: this can't happen\n");
  53. X                    exit(1);
  54. X                    /* NOTREACHED */
  55. X                case CREATE: case APPEND: case FROM:
  56. X                    fd = rc_open(fname->w, r->r->u[0].i);
  57. X                    break;
  58. X                }
  59. X                if (fd < 0) {
  60. X                    uerror(fname->w);
  61. X                    exit(1);
  62. X                }
  63. X                if (dup2(fd, r->r->u[1].i) < 0) {
  64. X                    uerror("dup");
  65. X                    exit(1);
  66. X                }
  67. X                close(fd);
  68. X            }
  69. X            break;
  70. X        case rDUP:
  71. X            if (r->r->u[2].i == -1)
  72. X                close(r->r->u[1].i);
  73. X            else if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) {
  74. X                uerror("dup");
  75. X                exit(1);
  76. X            }
  77. X        }
  78. X    }
  79. X    redirq = NULL;
  80. }
  81. SHAR_EOF
  82. echo 'File redir.c is complete' &&
  83. chmod 0644 redir.c ||
  84. echo 'restore of redir.c failed'
  85. Wc_c="`wc -c < 'redir.c'`"
  86. test 2480 -eq "$Wc_c" ||
  87.     echo 'redir.c: original size 2480, current size' "$Wc_c"
  88. rm -f _shar_wnt_.tmp
  89. fi
  90. # ============= redir.h ==============
  91. if test -f 'redir.h' -a X"$1" != X"-c"; then
  92.     echo 'x - skipping redir.h (File already exists)'
  93.     rm -f _shar_wnt_.tmp
  94. else
  95. > _shar_wnt_.tmp
  96. echo 'x - extracting redir.h (Text)'
  97. sed 's/^X//' << 'SHAR_EOF' > 'redir.h' &&
  98. extern void doredirs(void);
  99. SHAR_EOF
  100. chmod 0644 redir.h ||
  101. echo 'restore of redir.h failed'
  102. Wc_c="`wc -c < 'redir.h'`"
  103. test 28 -eq "$Wc_c" ||
  104.     echo 'redir.h: original size 28, current size' "$Wc_c"
  105. rm -f _shar_wnt_.tmp
  106. fi
  107. # ============= status.c ==============
  108. if test -f 'status.c' -a X"$1" != X"-c"; then
  109.     echo 'x - skipping status.c (File already exists)'
  110.     rm -f _shar_wnt_.tmp
  111. else
  112. > _shar_wnt_.tmp
  113. echo 'x - extracting status.c (Text)'
  114. sed 's/^X//' << 'SHAR_EOF' > 'status.c' &&
  115. /* status.c: functions for printing fancy status messages in rc */
  116. X
  117. #include "rc.h"
  118. #include "utils.h"
  119. #include "status.h"
  120. #include "nalloc.h"
  121. #include "walk.h"
  122. #include "sigmsgs.h"
  123. X
  124. /* status == the wait() value of the last command in the pipeline, or the last command */
  125. X
  126. static int statuses[512];
  127. static int pipelength = 1;
  128. X
  129. /*
  130. X   Test to see if rc's status is true. According to td, status is true if and only if every
  131. X   pipe-member has an exit status of zero.
  132. */
  133. X
  134. int istrue() {
  135. X    int i;
  136. X
  137. X    for (i = 0; i < pipelength; i++)
  138. X        if (statuses[i] != 0)
  139. X            return FALSE;
  140. X    return TRUE;
  141. }
  142. X
  143. /*
  144. X   Return the status as an integer. A status which has low-bits set is a signal number,
  145. X   whereas a status with high bits set is a value set from exit().
  146. */
  147. X
  148. int getstatus() {
  149. X    int s = statuses[0];
  150. X
  151. X    return s & 0xff ? s & 0x7f : (s >> 8) & 0xff;
  152. }
  153. X
  154. void set(boolean code) {
  155. X    setstatus((!code) << 8); /* exit status 1 == 0x100 */
  156. }
  157. X
  158. /* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */
  159. X
  160. void setpipestatus(int stats[], int num) {
  161. X    int i;
  162. X
  163. X    for (i = 0; i < (pipelength = num); i++) {
  164. X        statprint(stats[i]);
  165. X        statuses[i] = stats[i];
  166. X    }
  167. }
  168. X
  169. /* set a simple status, as opposed to a pipeline */
  170. X
  171. void setstatus(int i) {
  172. X    pipelength = 1;
  173. X    statuses[0] = i;
  174. X    statprint(i);
  175. }
  176. X
  177. /* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */
  178. X
  179. void statprint(int i) {
  180. X    if (i & 0xff) {
  181. X        char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f][1] : "");
  182. X
  183. X        if (i & 0x80) {
  184. X            if (*msg == '\0')
  185. X                fprint(2,"core dumped\n");
  186. X            else
  187. X                fprint(2,"%s--core dumped\n",msg);
  188. X        } else if (*msg != '\0')
  189. X            fprint(2,"%s\n",msg);
  190. X    }
  191. X
  192. X    if (i != 0 && dashee && !cond)
  193. X        rc_exit(getstatus());
  194. }
  195. X
  196. /* prepare a list to be passed back. Used whenever $status is dereferenced */
  197. X
  198. List *sgetstatus() {
  199. X    List *r;
  200. X    int i;
  201. X
  202. X    for (r = NULL, i = 0; i < pipelength; i++) {
  203. X        char buf[16];
  204. X        List *q = nnew(List);
  205. X        int s = statuses[i];
  206. X        int t;
  207. X
  208. X        q->n = r;
  209. X        r = q;
  210. X
  211. X        if ((t = s & 0x7f) != 0) {
  212. X            if (t < NUMOFSIGNALS && *signals[t][0] != '\0')
  213. X                sprint(buf, "%s", signals[t][0]);
  214. X            else
  215. X                sprint(buf,"-%d", t); /* unknown signals are negated */
  216. X            if (s & 0x80)
  217. X                strcat(buf, "+core");
  218. X        } else {
  219. X            sprint(buf, "%d", (s >> 8) & 0xff);
  220. X        }
  221. X
  222. X        r->w = ncpy(buf);
  223. X        r->m = NULL;
  224. X    }
  225. X
  226. X    return r;
  227. }
  228. X
  229. void ssetstatus(char **av) {
  230. X    int i, j, k, l;
  231. X    boolean found;
  232. X
  233. X    for (l = 0; av[l] != NULL; l++)
  234. X        ; /* count up array length */
  235. X    --l;
  236. X
  237. X    for (i = 0; av[i] != NULL; i++) {
  238. X        j = a2u(av[i]);
  239. X
  240. X        if (j >= 0) {
  241. X            statuses[l - i] = j << 8;
  242. X            continue;
  243. X        }
  244. X
  245. X        found = FALSE;
  246. X        for (k = 0; k < NUMOFSIGNALS; k++) {
  247. X            if (streq(signals[k][0], av[i])) {
  248. X                statuses[l - i] = k;
  249. X                found = TRUE;
  250. X                break;
  251. X            } else {
  252. X                int len = strlen(signals[k][0]);
  253. X                if (strncmp(signals[k][0], av[i], len) == 0 && streq(av[i] + len, "+core")) {
  254. X                    statuses[l - i] = k + 0x80;
  255. X                    found = TRUE;
  256. X                    break;
  257. X                }
  258. X            }
  259. X        }
  260. X        if (!found) {
  261. X            fprint(2, "bad return value\n");
  262. X            set(FALSE);
  263. X            return;
  264. X        }
  265. X    }
  266. X    pipelength = i;
  267. }
  268. SHAR_EOF
  269. chmod 0644 status.c ||
  270. echo 'restore of status.c failed'
  271. Wc_c="`wc -c < 'status.c'`"
  272. test 3078 -eq "$Wc_c" ||
  273.     echo 'status.c: original size 3078, current size' "$Wc_c"
  274. rm -f _shar_wnt_.tmp
  275. fi
  276. # ============= status.h ==============
  277. if test -f 'status.h' -a X"$1" != X"-c"; then
  278.     echo 'x - skipping status.h (File already exists)'
  279.     rm -f _shar_wnt_.tmp
  280. else
  281. > _shar_wnt_.tmp
  282. echo 'x - extracting status.h (Text)'
  283. sed 's/^X//' << 'SHAR_EOF' > 'status.h' &&
  284. extern int istrue(void);
  285. extern int getstatus(void);
  286. extern void set(boolean);
  287. extern void setstatus(int);
  288. extern List *sgetstatus(void);
  289. extern void setpipestatus(int [], int);
  290. extern void statprint(int);
  291. extern void ssetstatus(char **);
  292. SHAR_EOF
  293. chmod 0644 status.h ||
  294. echo 'restore of status.h failed'
  295. Wc_c="`wc -c < 'status.h'`"
  296. test 239 -eq "$Wc_c" ||
  297.     echo 'status.h: original size 239, current size' "$Wc_c"
  298. rm -f _shar_wnt_.tmp
  299. fi
  300. # ============= stddef.h ==============
  301. if test -f 'stddef.h' -a X"$1" != X"-c"; then
  302.     echo 'x - skipping stddef.h (File already exists)'
  303.     rm -f _shar_wnt_.tmp
  304. else
  305. > _shar_wnt_.tmp
  306. echo 'x - extracting stddef.h (Text)'
  307. sed 's/^X//' << 'SHAR_EOF' > 'stddef.h' &&
  308. /* stddef.h
  309. X    This file provides a definition for size_t and align_t that
  310. X    should work for your system. If it does not, it is up to you to
  311. X    make it the right thing. The problem is that I cannot rely upon
  312. X    <sys/params.h> to do the right thing on machines which don't
  313. X    yet have ansi header files. Note that on many RISC machines,
  314. X    align_t must be at least 32 bits wide, and sparc doubles are
  315. X    aligned on 64 bit boundaries, but of course, rc does not use
  316. X    doubles in its code, so the "typedef long ALIGN_T" is good
  317. X    enough in the sparc's case. Also for performance reasons on a
  318. X    VAX one would probably want align_t to be 32 bits wide.
  319. */
  320. typedef long ALIGN_T;
  321. typedef unsigned int SIZE_T;
  322. typedef short int MODE_T;
  323. typedef int PID_T;
  324. X
  325. #ifndef NULL
  326. #define NULL 0
  327. #endif
  328. SHAR_EOF
  329. chmod 0644 stddef.h ||
  330. echo 'restore of stddef.h failed'
  331. Wc_c="`wc -c < 'stddef.h'`"
  332. test 766 -eq "$Wc_c" ||
  333.     echo 'stddef.h: original size 766, current size' "$Wc_c"
  334. rm -f _shar_wnt_.tmp
  335. fi
  336. # ============= stdlib.h ==============
  337. if test -f 'stdlib.h' -a X"$1" != X"-c"; then
  338.     echo 'x - skipping stdlib.h (File already exists)'
  339.     rm -f _shar_wnt_.tmp
  340. else
  341. > _shar_wnt_.tmp
  342. echo 'x - extracting stdlib.h (Text)'
  343. sed 's/^X//' << 'SHAR_EOF' > 'stdlib.h' &&
  344. /*
  345. X   stdlib.h function prototypes as taken from Appendix B of K&R 2.
  346. X   Unused functions are:
  347. X    atof(), atoi(), atol(), strtod(), strtol(), strtoul(), rand(),
  348. X    srand(), calloc(), abort(), atexit(), system(), getenv(), bsearch(),
  349. X    abs(), labs(), div() and ldiv()
  350. */
  351. X
  352. extern void *malloc(SIZE_T);
  353. extern void *realloc(void *, SIZE_T);
  354. extern void free(void *);
  355. extern void exit(int);
  356. extern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *));
  357. SHAR_EOF
  358. chmod 0644 stdlib.h ||
  359. echo 'restore of stdlib.h failed'
  360. Wc_c="`wc -c < 'stdlib.h'`"
  361. test 462 -eq "$Wc_c" ||
  362.     echo 'stdlib.h: original size 462, current size' "$Wc_c"
  363. rm -f _shar_wnt_.tmp
  364. fi
  365. # ============= string.h ==============
  366. if test -f 'string.h' -a X"$1" != X"-c"; then
  367.     echo 'x - skipping string.h (File already exists)'
  368.     rm -f _shar_wnt_.tmp
  369. else
  370. > _shar_wnt_.tmp
  371. echo 'x - extracting string.h (Text)'
  372. sed 's/^X//' << 'SHAR_EOF' > 'string.h' &&
  373. extern int strncmp(const char *, const char *, SIZE_T);
  374. extern int strcmp(const char *, const char *);
  375. extern SIZE_T strlen(const char *);
  376. extern char *strchr(const char *, int);
  377. extern char *strrchr(const char *, int);
  378. extern char *strcpy(char *, const char *);
  379. extern char *strncpy(char *, const char *, SIZE_T);
  380. extern char *strcat(char *, const char *);
  381. extern char *strncat(char *, const char *, SIZE_T);
  382. extern void *memcpy(void *, const void *, SIZE_T);
  383. X
  384. #define streq(x,y) (*(x) == *(y) && strcmp(x,y) == 0)
  385. SHAR_EOF
  386. chmod 0644 string.h ||
  387. echo 'restore of string.h failed'
  388. Wc_c="`wc -c < 'string.h'`"
  389. test 516 -eq "$Wc_c" ||
  390.     echo 'string.h: original size 516, current size' "$Wc_c"
  391. rm -f _shar_wnt_.tmp
  392. fi
  393. # ============= tree.c ==============
  394. if test -f 'tree.c' -a X"$1" != X"-c"; then
  395.     echo 'x - skipping tree.c (File already exists)'
  396.     rm -f _shar_wnt_.tmp
  397. else
  398. > _shar_wnt_.tmp
  399. echo 'x - extracting tree.c (Text)'
  400. sed 's/^X//' << 'SHAR_EOF' > 'tree.c' &&
  401. /* tree.c: functions for manipulating parse-trees. (create, copy, delete) */
  402. X
  403. #include <stdarg.h>
  404. #include "rc.h"
  405. #include "tree.h"
  406. #include "utils.h"
  407. #include "nalloc.h"
  408. X
  409. /* make a new node, pass it back to yyparse. Used to generate the parsetree. */
  410. X
  411. Node *newnode(int /*enum nodetype*/ t,...) {
  412. X    va_list ap;
  413. X    Node *n;
  414. X
  415. X    va_start(ap,t);
  416. X
  417. X    switch (t) {
  418. X    default:
  419. X        fprint(2,"newnode: this can't happen\n");
  420. X        exit(1);
  421. X        /* NOTREACHED */
  422. X    case rDUP:
  423. X        n = nalloc(offsetof(Node, u[3]));
  424. X        n->u[0].i = va_arg(ap, int);
  425. X        n->u[1].i = va_arg(ap, int);
  426. X        n->u[2].i = va_arg(ap, int);
  427. X        break;
  428. X    case rWORD: case QWORD:
  429. X        n = nalloc(offsetof(Node, u[2]));
  430. X        n->u[0].s = va_arg(ap, char *);
  431. X        n->u[1].s = va_arg(ap, char *);
  432. X        break;
  433. X    case rBANG: case NOWAIT:
  434. X    case rCOUNT: case rFLAT: case RMFN: case rSUBSHELL:
  435. X    case VAR: case rCASE:
  436. X        n = nalloc(offsetof(Node, u[1]));
  437. X        n->u[0].p = va_arg(ap, Node *);
  438. X        break;
  439. X    case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
  440. X    case rELSE: case EPILOG: case rIF: case NEWFN: case CBODY:
  441. X    case rOROR: case PRE: case ARGS: case rSWITCH:
  442. X    case MATCH: case VARSUB: case rWHILE: case LAPPEND:
  443. X        n = nalloc(offsetof(Node, u[2]));
  444. X        n->u[0].p = va_arg(ap, Node *);
  445. X        n->u[1].p = va_arg(ap, Node *);
  446. X        break;
  447. X    case FORIN:
  448. X        n = nalloc(offsetof(Node, u[3]));
  449. X        n->u[0].p = va_arg(ap, Node *);
  450. X        n->u[1].p = va_arg(ap, Node *);
  451. X        n->u[2].p = va_arg(ap, Node *);
  452. X        break;
  453. X    case rPIPE:
  454. X        n = nalloc(offsetof(Node, u[4]));
  455. X        n->u[0].i = va_arg(ap, int);
  456. X        n->u[1].i = va_arg(ap, int);
  457. X        n->u[2].p = va_arg(ap, Node *);
  458. X        n->u[3].p = va_arg(ap, Node *);
  459. X        break;
  460. X    case rREDIR:
  461. X    case NMPIPE:
  462. X        n = nalloc(offsetof(Node, u[3]));
  463. X        n->u[0].i = va_arg(ap, int);
  464. X        n->u[1].i = va_arg(ap, int);
  465. X        n->u[2].p = va_arg(ap, Node *);
  466. X        break;
  467. X     }
  468. X    n->type = t;
  469. X    va_end(ap);
  470. X    return n;
  471. }
  472. X
  473. /* copy a tree to malloc space. Used when storing the definition of a function */
  474. X
  475. Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) {
  476. X    Node *n;
  477. X
  478. X    if (s == NULL)
  479. X        return NULL;
  480. X
  481. X    switch (s->type) {
  482. X    default:
  483. X        fprint(2,"treecpy: this can't happen\n");
  484. X        exit(1);
  485. X        /* NOTREACHED */
  486. X    case rDUP:
  487. X        n = alloc(offsetof(Node, u[3]));
  488. X        n->u[0].i = s->u[0].i;
  489. X        n->u[1].i = s->u[1].i;
  490. X        n->u[2].i = s->u[2].i;
  491. X        break;
  492. X    case rWORD: case QWORD:
  493. X        n = alloc(offsetof(Node, u[2]));
  494. X        n->u[0].s = ecpy(s->u[0].s);
  495. X        if (s->u[1].s != NULL) {
  496. X            SIZE_T i = strlen(s->u[0].s);
  497. X
  498. X            n->u[1].s = alloc(i);
  499. X            memcpy(n->u[1].s, s->u[1].s, i);
  500. X        } else
  501. X            n->u[1].s = NULL;
  502. X        break;
  503. X    case rBANG: case NOWAIT: case rCASE:
  504. X    case rCOUNT: case rFLAT: case RMFN: case rSUBSHELL: case VAR:
  505. X        n = alloc(offsetof(Node, u[1]));
  506. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  507. X        break;
  508. X    case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
  509. X    case rELSE: case EPILOG: case rIF: case NEWFN: case CBODY:
  510. X    case rOROR: case PRE: case ARGS: case rSWITCH:
  511. X    case MATCH: case VARSUB: case rWHILE: case LAPPEND:
  512. X        n = alloc(offsetof(Node, u[2]));
  513. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  514. X        n->u[1].p = treecpy(s->u[1].p, alloc);
  515. X        break;
  516. X    case FORIN:
  517. X        n = alloc(offsetof(Node, u[3]));
  518. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  519. X        n->u[1].p = treecpy(s->u[1].p, alloc);
  520. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  521. X        break;
  522. X    case rPIPE:
  523. X        n = alloc(offsetof(Node, u[4]));
  524. X        n->u[0].i = s->u[0].i;
  525. X        n->u[1].i = s->u[1].i;
  526. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  527. X        n->u[3].p = treecpy(s->u[3].p, alloc);
  528. X        break;
  529. X    case rREDIR:
  530. X    case NMPIPE:
  531. X        n = alloc(offsetof(Node, u[3]));
  532. X        n->u[0].i = s->u[0].i;
  533. X        n->u[1].i = s->u[1].i;
  534. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  535. X        break;
  536. X    }
  537. X    n->type = s->type;
  538. X    return n;
  539. }
  540. X
  541. /* free a function definition that is no longer needed */
  542. X
  543. void treefree(Node *s) {
  544. X    if (s == NULL)
  545. X        return;
  546. X    switch (s->type) {
  547. X    case rDUP:
  548. X        break;
  549. X    case rWORD: case QWORD:
  550. X        efree(s->u[0].s);
  551. X        efree(s->u[1].s);
  552. X        break;
  553. X    case rBANG: case NOWAIT:
  554. X    case rCOUNT: case rFLAT: case RMFN:
  555. X    case rSUBSHELL: case VAR: case rCASE:
  556. X        treefree(s->u[0].p);
  557. X        efree(s->u[0].p);
  558. X        break;
  559. X    case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
  560. X    case rELSE: case EPILOG: case rIF: case NEWFN:
  561. X    case rOROR: case PRE: case ARGS: case CBODY:
  562. X    case rSWITCH: case MATCH:  case VARSUB: case rWHILE:
  563. X    case LAPPEND:
  564. X        treefree(s->u[1].p);
  565. X        treefree(s->u[0].p);
  566. X        efree(s->u[1].p);
  567. X        efree(s->u[0].p);
  568. X        break;
  569. X    case FORIN:
  570. X        treefree(s->u[2].p);
  571. X        treefree(s->u[1].p);
  572. X        treefree(s->u[0].p);
  573. X        efree(s->u[2].p);
  574. X        efree(s->u[1].p);
  575. X        efree(s->u[0].p);
  576. X        break;
  577. X    case rPIPE:
  578. X        treefree(s->u[2].p);
  579. X        treefree(s->u[3].p);
  580. X        efree(s->u[2].p);
  581. X        efree(s->u[3].p);
  582. X        break;
  583. X    case rREDIR:
  584. X    case NMPIPE:
  585. X        treefree(s->u[2].p);
  586. X        efree(s->u[2].p);
  587. X        break;
  588. X    default:
  589. X        fprint(2,"treefree: this can't happen\n");
  590. X        exit(1);
  591. X    }
  592. }
  593. SHAR_EOF
  594. chmod 0644 tree.c ||
  595. echo 'restore of tree.c failed'
  596. Wc_c="`wc -c < 'tree.c'`"
  597. test 4722 -eq "$Wc_c" ||
  598.     echo 'tree.c: original size 4722, current size' "$Wc_c"
  599. rm -f _shar_wnt_.tmp
  600. fi
  601. # ============= tree.h ==============
  602. if test -f 'tree.h' -a X"$1" != X"-c"; then
  603.     echo 'x - skipping tree.h (File already exists)'
  604.     rm -f _shar_wnt_.tmp
  605. else
  606. > _shar_wnt_.tmp
  607. echo 'x - extracting tree.h (Text)'
  608. sed 's/^X//' << 'SHAR_EOF' > 'tree.h' &&
  609. extern Node *newnode(int /*enum nodetype*/ t,...);
  610. extern Node *treecpy(Node *s, void *(*)(SIZE_T));
  611. extern void treefree(Node *s);
  612. SHAR_EOF
  613. chmod 0644 tree.h ||
  614. echo 'restore of tree.h failed'
  615. Wc_c="`wc -c < 'tree.h'`"
  616. test 132 -eq "$Wc_c" ||
  617.     echo 'tree.h: original size 132, current size' "$Wc_c"
  618. rm -f _shar_wnt_.tmp
  619. fi
  620. # ============= unistd.h ==============
  621. if test -f 'unistd.h' -a X"$1" != X"-c"; then
  622.     echo 'x - skipping unistd.h (File already exists)'
  623.     rm -f _shar_wnt_.tmp
  624. else
  625. > _shar_wnt_.tmp
  626. echo 'x - extracting unistd.h (Text)'
  627. sed 's/^X//' << 'SHAR_EOF' > 'unistd.h' &&
  628. extern PID_T fork(void);
  629. extern PID_T getpid(void);
  630. extern int chdir(const char *);
  631. extern int close(int);
  632. extern int dup2(int, int);
  633. extern int execve(const char *, const char **, const char **);
  634. extern int execl(const char *, ...);
  635. extern int getegid(void);
  636. extern int geteuid(void);
  637. extern int getgroups(int, int *);
  638. extern int isatty(int);
  639. #ifndef SYSVR4 /* declares AND defines this in sys/stat.h!! */
  640. extern int mknod(const char *, int, int);
  641. #endif
  642. extern int pipe(int *);
  643. extern int read(int, void *, unsigned int);
  644. extern int setpgrp(int, PID_T);
  645. extern int unlink(const char *);
  646. extern int wait(int *);
  647. extern int write(int, const void *, unsigned int);
  648. X
  649. extern int optind;
  650. extern char *optarg;
  651. extern int errno;
  652. X
  653. extern char *getenv(const char *);
  654. SHAR_EOF
  655. chmod 0644 unistd.h ||
  656. echo 'restore of unistd.h failed'
  657. Wc_c="`wc -c < 'unistd.h'`"
  658. test 759 -eq "$Wc_c" ||
  659.     echo 'unistd.h: original size 759, current size' "$Wc_c"
  660. rm -f _shar_wnt_.tmp
  661. fi
  662. # ============= utils.c ==============
  663. if test -f 'utils.c' -a X"$1" != X"-c"; then
  664.     echo 'x - skipping utils.c (File already exists)'
  665.     rm -f _shar_wnt_.tmp
  666. else
  667. > _shar_wnt_.tmp
  668. echo 'x - extracting utils.c (Text)'
  669. sed 's/^X//' << 'SHAR_EOF' > 'utils.c' &&
  670. /* utils.c: general utility functions like fprint, ealloc etc. */
  671. X
  672. #include <stdarg.h>
  673. #include <errno.h>
  674. #include "jbwrap.h"
  675. #include <signal.h>
  676. #include "rc.h"
  677. #include "utils.h"
  678. #include "nalloc.h"
  679. #include "status.h"
  680. #include "input.h"
  681. #include "except.h"
  682. #include "lex.h"    /* import char nw[]; used by strprint to see if it needs to quote a word */
  683. #include "walk.h"
  684. #include "footobar.h"
  685. #include "glom.h"
  686. #include "hash.h"
  687. #include "wait.h"
  688. X
  689. static void dprint(va_list, char *, char *);
  690. static int n2u(char *, int);
  691. X
  692. /* exception handlers */
  693. X
  694. void pr_error(char *s) {
  695. X    if (s != NULL) {
  696. X        if (interactive)
  697. X            fprint(2,"%s\n",s);
  698. X        else
  699. X            fprint(2,"line %d: %s\n", lineno - 1, s);
  700. X    }
  701. }
  702. X
  703. void rc_error(char *s) {
  704. X    pr_error(s);
  705. X    set(FALSE);
  706. X    redirq = NULL;
  707. X    cond = FALSE; /* no longer inside conditional */
  708. X    empty_fifoq();
  709. X    rc_raise(ERROR);
  710. }
  711. X
  712. void sig(int s) {
  713. X    signal(SIGINT, sig); /* some unices require re-signaling */
  714. X
  715. X    if (errno == EINTR)
  716. X        return; /* allow wait() to complete */
  717. X
  718. X    fprint(2,"\n"); /* this is the newline you see when you hit ^C while typing a command */
  719. X    redirq = NULL;
  720. X    cond = FALSE;
  721. X    empty_fifoq();
  722. X    rc_raise(ERROR);
  723. }
  724. X
  725. /* our perror */
  726. X
  727. void uerror(char *s) {
  728. X    extern int sys_nerr;
  729. X    extern char *sys_errlist[];
  730. X
  731. X    if (errno > sys_nerr)
  732. X        return;
  733. X
  734. X    if (s != NULL)
  735. X        fprint(2,"%s: %s\n",s,sys_errlist[errno]);
  736. X    else
  737. X        fprint(2,"%s\n",sys_errlist[errno]);
  738. }
  739. X
  740. /* printing functions */
  741. X
  742. void fprint(int fd, char *f,...) {
  743. X        va_list ap;
  744. X    char str[FPRINT_SIZE];
  745. X
  746. X    va_start(ap,f);
  747. X    dprint(ap, str, f);
  748. X    va_end(ap);
  749. X    writeall(fd,str,strlen(str));
  750. }
  751. X
  752. char *sprint(char *b, char *f,...) {
  753. X    va_list ap;
  754. X
  755. X    va_start(ap, f);
  756. X    dprint(ap, b, f);
  757. X    va_end(ap);
  758. X    return b;
  759. }
  760. X
  761. static void dprint(va_list ap, char *strbuf, char *f) {
  762. X    int i;
  763. X
  764. X    for (i = 0; *f != '\0'; f++) {
  765. X        if (*f != '%') {
  766. X            strbuf[i++] = *f;
  767. X            continue; /* avoid an ugly extra level of indentation */
  768. X        }
  769. X        switch (*++f) {
  770. X        case 'a': {
  771. X            char **a = va_arg(ap, char **);
  772. X
  773. X            if (*a == NULL)
  774. X                break;
  775. X            strcpy(strbuf + i, *a);
  776. X            i += strlen(*a);
  777. X            while (*++a != NULL) {
  778. X                strbuf[i++] = ' ';
  779. X                strcpy(strbuf + i, *a);
  780. X                i += strlen(*a);
  781. X            }
  782. X            break;
  783. X        }
  784. X        case 'c':
  785. X            strbuf[i++] = va_arg(ap, int);
  786. X            break;
  787. X        case 'd': case 'o': {
  788. X            int v = va_arg(ap, int);
  789. X            int j = 0;
  790. X            int base = (*f == 'd' ? 10 : 8);
  791. X            char num[16];
  792. X
  793. X            if (v == 0)
  794. X                num[j++] = '0';
  795. X            while (v != 0) {
  796. X                num[j++] = (v % base) + '0';
  797. X                v /= base;
  798. X            }
  799. X            while (--j >= 0)
  800. X                strbuf[i++] = num[j];
  801. X            break;
  802. X        }
  803. X        case 's': {
  804. X            char *s = va_arg(ap, char *);
  805. X            while (*s != '\0')
  806. X                strbuf[i++] = *s++;
  807. X                break;
  808. X        }
  809. X        case 'l': {
  810. X            List *s, *l = va_arg(ap, List *);
  811. X
  812. X            if (l == NULL) {
  813. X                strbuf[i++] = '(';
  814. X                strbuf[i++] = ')';
  815. X                break;
  816. X            }
  817. X            for (s = l; s != NULL; s = s->n) {
  818. X                strcpy(strbuf + i, strprint(s->w, FALSE, TRUE));
  819. X                while (strbuf[i] != '\0')
  820. X                    i++;
  821. X                if (s->n != NULL)
  822. X                    strbuf[i++] = ' ';
  823. X            }
  824. X            break;
  825. X        }
  826. X        default: /* on format error, just print the bad format */
  827. X            strbuf[i++] = '%';
  828. X            /* FALLTHROUGH */
  829. X        case '%':
  830. X            strbuf[i++] = *f;
  831. X        }
  832. X    }
  833. X    strbuf[i] = '\0';
  834. }
  835. X
  836. /* prints a string in rc-quoted form. e.g., a string with spaces in it must be quoted */
  837. X
  838. char *strprint(char *s, int quotable, int metaquote) { /* really boolean, but y.tab.c includes utils.h */
  839. X    SIZE_T i,j;
  840. X    char *t;
  841. X
  842. X    if (*s == '\0')
  843. X        return "''";
  844. X
  845. X    for (i = 0; s[i] != '\0'; i++)
  846. X        if (nw[(unsigned char) s[i]] == 1 || (metaquote && (s[i] == '*' || s[i] == '?' || s[i] == '[')))
  847. X            quotable = TRUE;
  848. X
  849. X    if (!quotable)
  850. X        return s; /* If the string doesn't need quotes, return */
  851. X
  852. X    for (i = j = 0; s[i] != '\0'; i++, j++)
  853. X        if (s[i] == '\'')
  854. X            j++;
  855. X
  856. X    t = nalloc(j + 3);
  857. X
  858. X    t[0] = '\'';
  859. X
  860. X    for (j = 1, i = 0; s[i] != '\0'; i++, j++) {
  861. X        t[j] = s[i];
  862. X        if (s[i] == '\'')
  863. X            t[++j] = '\'';
  864. X    }
  865. X
  866. X    t[j++] = '\'';
  867. X    t[j] = '\0';
  868. X
  869. X    return t;
  870. }
  871. X
  872. /* ascii -> unsigned conversion routines. -1 indicates conversion error. */
  873. X
  874. static int n2u(char *s, int base) {
  875. X    int i;
  876. X
  877. X    for (i = 0; *s != '\0'; s++) {
  878. X        /* small hack with unsigned ints -- one compare for range test */
  879. X        if (((unsigned int) *s) - '0' >= (unsigned int) base)
  880. X            return -1;
  881. X        i = (i * base) + (*s - '0');
  882. X    }
  883. X    return i;
  884. }
  885. X
  886. /* decimal -> uint */
  887. X
  888. int a2u(char *s) {
  889. X    return n2u(s, 10);
  890. }
  891. X
  892. /* octal -> uint */
  893. X
  894. int o2u(char *s) {
  895. X    return n2u(s, 8);
  896. }
  897. X
  898. /* memory allocation functions */
  899. X
  900. void *ealloc(SIZE_T n) {
  901. X    void *p = malloc(n);
  902. X
  903. X    if (p == NULL) {
  904. X        uerror("malloc");
  905. X        rc_exit(1);
  906. X    }
  907. X
  908. X    return p;
  909. }
  910. X
  911. void *erealloc(void *p, SIZE_T n) {
  912. X    p = realloc(p, n);
  913. X
  914. X    if (p == NULL) {
  915. X        uerror("realloc");
  916. X        rc_exit(1);
  917. X    }
  918. X
  919. X    return p;
  920. }
  921. X
  922. void efree(void *p) {
  923. X    if (p != NULL)
  924. X        free(p);
  925. }
  926. X
  927. /* useful functions */
  928. X
  929. /* The last word in portable ANSI: a strcmp wrapper for qsort */
  930. X
  931. int starstrcmp(const void *s1, const void *s2) {
  932. X    return strcmp(*(char **)s1, *(char **)s2);
  933. }
  934. X
  935. /* tests to see if pathname begins with "/", "./", or "../" */
  936. X
  937. int isabsolute(char *path) {
  938. X    return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
  939. }
  940. X
  941. /* write a given buffer allowing for partial writes from write(2) */
  942. X
  943. void writeall(int fd, char *buf, SIZE_T remain) {
  944. X    int i;
  945. X
  946. X    for (i = 0; remain > 0; buf += i, remain -= i)
  947. X        if ((i = write(fd, buf, remain)) <= 0)
  948. X            return; /* abort silently on errors in write() */
  949. }
  950. X
  951. /* clear out z bytes from character string s */
  952. X
  953. void clear(char *s, SIZE_T z) {
  954. X    while (z != 0)
  955. X        s[--z] = 0;
  956. }
  957. X
  958. /* zero out the fifo queue, removing the fifos from /tmp as you go (also prints errors arising from signals) */
  959. X
  960. void empty_fifoq() {
  961. X    int sp;
  962. X
  963. X    while (fifoq != NULL) {
  964. X        rc_wait4(fifoq->pid, &sp);
  965. X        statprint(sp);
  966. X        unlink(fifoq->name);
  967. X        fifoq = fifoq->n;
  968. X    }
  969. }
  970. X
  971. SIZE_T strarraylen(char **a) {
  972. X    SIZE_T i;
  973. X
  974. X    for (i = 0; *a != NULL; a++)
  975. X        i += strlen(*a) + 1;
  976. X
  977. X    return i;
  978. }
  979. SHAR_EOF
  980. chmod 0644 utils.c ||
  981. echo 'restore of utils.c failed'
  982. Wc_c="`wc -c < 'utils.c'`"
  983. test 5782 -eq "$Wc_c" ||
  984.     echo 'utils.c: original size 5782, current size' "$Wc_c"
  985. rm -f _shar_wnt_.tmp
  986. fi
  987. # ============= utils.h ==============
  988. if test -f 'utils.h' -a X"$1" != X"-c"; then
  989.     echo 'x - skipping utils.h (File already exists)'
  990.     rm -f _shar_wnt_.tmp
  991. else
  992. > _shar_wnt_.tmp
  993. echo 'x - extracting utils.h (Text)'
  994. sed 's/^X//' << 'SHAR_EOF' > 'utils.h' &&
  995. extern char *strprint(char *, int, int);
  996. extern char *sprint(char *, char *,...);
  997. extern int isabsolute(char *); /* not boolean because y.tab.c includes utils.h */
  998. extern int a2u(char *);
  999. extern int o2u(char *);
  1000. extern int starstrcmp(const void *, const void *);
  1001. extern void *ealloc(SIZE_T);
  1002. extern void *erealloc(void *, SIZE_T);
  1003. extern void efree(void *);
  1004. extern void fprint(int, char *,...);
  1005. extern void empty_fifoq(void);
  1006. extern void pr_error(char *);
  1007. extern void rc_error(char *);
  1008. extern void rc_exit(int); /* prototyped here, but defined in fn.c */
  1009. extern void sig(int);
  1010. extern void clear(char *, SIZE_T);
  1011. extern void uerror(char *);
  1012. extern void writeall(int, char *, SIZE_T);
  1013. extern SIZE_T strarraylen(char **);
  1014. X
  1015. /* memory allocation abbreviations */
  1016. #define enew(x) ((x *) ealloc(sizeof(x)))
  1017. #define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1),x)
  1018. X
  1019. #define FPRINT_SIZE 16384
  1020. SHAR_EOF
  1021. chmod 0644 utils.h ||
  1022. echo 'restore of utils.h failed'
  1023. Wc_c="`wc -c < 'utils.h'`"
  1024. test 884 -eq "$Wc_c" ||
  1025.     echo 'utils.h: original size 884, current size' "$Wc_c"
  1026. rm -f _shar_wnt_.tmp
  1027. fi
  1028. # ============= var.c ==============
  1029. if test -f 'var.c' -a X"$1" != X"-c"; then
  1030.     echo 'x - skipping var.c (File already exists)'
  1031.     rm -f _shar_wnt_.tmp
  1032. else
  1033. > _shar_wnt_.tmp
  1034. echo 'x - extracting var.c (Text)'
  1035. sed 's/^X//' << 'SHAR_EOF' > 'var.c' &&
  1036. /* var.c: provide "public" functions for adding and removing variables from the symbol table */
  1037. X
  1038. #include "rc.h"
  1039. #include "utils.h"
  1040. #include "hash.h"
  1041. #include "list.h"
  1042. #include "footobar.h"
  1043. #include "nalloc.h"
  1044. #include "status.h"
  1045. #include "glom.h"
  1046. #include "wait.h"
  1047. X
  1048. #ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
  1049. extern void rl_reset_terminal(char *);
  1050. #endif
  1051. X
  1052. static void colonassign(char *, List *, boolean);
  1053. static void listassign(char *, List *, boolean);
  1054. static int hasalias(char *);
  1055. X
  1056. static char *const aliases[] = {
  1057. X    "home", "HOME", "path", "PATH", "cdpath", "CDPATH"
  1058. };
  1059. X
  1060. /* assign a variable in List form to a name, stacking if appropriate */
  1061. X
  1062. void varassign(char *name, List *def, boolean stack) {
  1063. X    Variable *new;
  1064. X    List *newdef = listcpy(def); /* important to do the listcpy first; get_var_place() frees old values */
  1065. X
  1066. X    new = get_var_place(name, stack);
  1067. X    new->def = newdef;
  1068. X    new->extdef = NULL;
  1069. X
  1070. #ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
  1071. X    if (interactive && streq(name, "TERM") || streq(name, "TERMCAP"))
  1072. X        rl_reset_terminal(NULL);
  1073. #endif
  1074. }
  1075. X
  1076. /* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
  1077. X
  1078. boolean varassign_string(char *extdef) {
  1079. X    char *name = get_name(extdef);
  1080. X    Variable *new;
  1081. X    int i;
  1082. X    static boolean aliasset[arraysize(aliases)] = {
  1083. X        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
  1084. X    };
  1085. X
  1086. X    if (name == NULL)
  1087. X        return FALSE; /* add it to bozo env */
  1088. X
  1089. X    i = hasalias(name);
  1090. X    if (i >= 0) {
  1091. X        aliasset[i] = TRUE;
  1092. X        if ((i & 1 == 0) && aliasset[i^1])
  1093. X            return TRUE; /* don't alias variables that are already set in upper case */
  1094. X    }
  1095. X    new = get_var_place(name, FALSE);
  1096. X    new->def = NULL;
  1097. X    new->extdef = ealloc(strlen(extdef) + 1);
  1098. X    strcpy(new->extdef, extdef);
  1099. X    if (hasalias(name) != -1)
  1100. X        alias(name, varlookup(name), FALSE);
  1101. X    return TRUE;
  1102. }
  1103. X
  1104. /*
  1105. X   Return a List based on a name lookup. If the list is in external (string) form,
  1106. X   convert it to internal (List) form. Treat $n (n is an integer) specially as $*(n).
  1107. X   Also check to see if $status is being dereferenced. (we lazily evaluate the List
  1108. X   associated with $status)
  1109. */
  1110. X
  1111. List *varlookup(char *name) {
  1112. X    Variable *look;
  1113. X    List *ret, *l;
  1114. X    int sub;
  1115. X
  1116. X    if (streq(name, "status"))
  1117. X        return sgetstatus();
  1118. X    if (streq(name, "apids"))
  1119. X        return sgetapids();
  1120. X
  1121. X    if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
  1122. X        for (l = varlookup("*"); l != NULL && sub != 0; --sub)
  1123. X            l = l->n;
  1124. X        if (l == NULL)
  1125. X            return NULL;
  1126. X        ret = nnew(List);
  1127. X        ret->w = l->w;
  1128. X        ret->m = NULL;
  1129. X        ret->n = NULL;
  1130. X        return ret;
  1131. X    }
  1132. X
  1133. X    look = lookup_var(name);
  1134. X
  1135. X    if (look == NULL)
  1136. X        return NULL; /* not found */
  1137. X    if (look->def != NULL)
  1138. X        return look->def;
  1139. X    if (look->extdef == NULL)
  1140. X        return NULL; /* variable was set to null, e.g., a=() echo foo */
  1141. X
  1142. X    ret = parse_var(name, look->extdef);
  1143. X
  1144. X    if (ret == NULL) {
  1145. X        look->extdef = NULL;
  1146. X        return NULL;
  1147. X    }
  1148. X    return look->def = ret;
  1149. }
  1150. X
  1151. /* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */
  1152. X
  1153. char *varlookup_string(char *name) {
  1154. X    Variable *look;
  1155. X
  1156. X    look = lookup_var(name);
  1157. X
  1158. X    if (look == NULL)
  1159. X        return NULL;
  1160. X    if (look->extdef != NULL)
  1161. X        return look->extdef;
  1162. X    if (look->def == NULL)
  1163. X        return NULL;
  1164. X    return look->extdef = list2str(name, look->def);
  1165. }
  1166. X
  1167. /* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
  1168. X
  1169. void varrm(char *name, boolean stack) {
  1170. X    int i = hasalias(name);
  1171. X
  1172. X    if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
  1173. X        varassign("*", varlookup("0"), FALSE);
  1174. X        return;
  1175. X    }
  1176. X
  1177. X    delete_var(name, stack);
  1178. X    if (i != -1)
  1179. X        delete_var(aliases[i^1], stack);
  1180. }
  1181. X
  1182. /* assign a value (List) to a variable, using array "a" as input. Used to assign $* */
  1183. X
  1184. void starassign(char *dollarzero, char **a, boolean stack) {
  1185. X    List *s, *var;
  1186. X
  1187. X    var = nnew(List);
  1188. X    var->w = dollarzero;
  1189. X
  1190. X    if (*a == NULL) {
  1191. X        var->n = NULL;
  1192. X        varassign("*", var, stack);
  1193. X        return;
  1194. X    }
  1195. X
  1196. X    var->n = s = nnew(List);
  1197. X
  1198. X    while (1) {
  1199. X        s->w = *a++;
  1200. X        if (*a == NULL) {
  1201. X            s->n = NULL;
  1202. X            break;
  1203. X        } else {
  1204. X            s->n = nnew(List);
  1205. X            s = s->n;
  1206. X        }
  1207. X    }
  1208. X    varassign("*", var, stack);
  1209. }
  1210. X
  1211. /* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */
  1212. X
  1213. static void colonassign(char *name, List *def, boolean stack) {
  1214. X    char *colondef;
  1215. X    List dud;
  1216. X    SIZE_T deflen;
  1217. X    List *r;
  1218. X
  1219. X    if (def == NULL) {
  1220. X        varassign(name, NULL, stack);
  1221. X        return;
  1222. X    }
  1223. X
  1224. X    deflen = listlen(def) + 1; /* one for the null terminator */
  1225. X
  1226. X    colondef = nalloc(deflen);
  1227. X    strcpy(colondef, def->w);
  1228. X
  1229. X    for (r = def->n; r != NULL; r = r->n) {
  1230. X        strcat(colondef, ":");
  1231. X        strcat(colondef, r->w);
  1232. X    }
  1233. X
  1234. X    dud.w = colondef;
  1235. X    dud.n = NULL;
  1236. X    varassign(name, &dud, stack);
  1237. }
  1238. X
  1239. /* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */
  1240. X
  1241. static void listassign(char *name, List *def, boolean stack) {
  1242. X    List *val, *r;
  1243. X    char *v, *w;
  1244. X
  1245. X    if (def == NULL) {
  1246. X        varassign(name, NULL, stack);
  1247. X        return;
  1248. X    }
  1249. X
  1250. X    v = def->w;
  1251. X
  1252. X    r = val = enew(List);
  1253. X
  1254. X    while((w = strchr(v,':')) != NULL) {
  1255. X        *w = '\0';
  1256. X        r->w = ecpy(v);
  1257. X        *w = ':';
  1258. X        v = w + 1;
  1259. X        r->n = enew(List);
  1260. X        r = r->n;
  1261. X    }
  1262. X    r->w = ecpy(v);
  1263. X    r->n = NULL;
  1264. X
  1265. X    varassign(name, val, stack);
  1266. }
  1267. X
  1268. /* check to see if a particular variable is aliased; return -1 on failure, or the index */
  1269. X
  1270. static int hasalias(char *name) {
  1271. X    int i;
  1272. X
  1273. X    for (i = 0; i < arraysize(aliases); i++)
  1274. X        if (streq(name, aliases[i]))
  1275. X            return i;
  1276. X    return -1;
  1277. }
  1278. X
  1279. /* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */
  1280. X
  1281. void alias(char *name, List *s, boolean stack) {
  1282. X    int i = hasalias(name);
  1283. X    static void (*vectors[])(char *, List *, boolean) = {
  1284. X        varassign, varassign, colonassign, listassign, colonassign, listassign
  1285. X    };
  1286. X
  1287. X    if (i != -1)
  1288. X        vectors[i](aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
  1289. }
  1290. X
  1291. void prettyprint_var(int fd, char *name, List *s) {
  1292. X    static char *keywords[] = {
  1293. X        "if", "in", "fn", "for", "else", "switch", "while", "case"
  1294. X    };
  1295. X    char buf[10], *newname = NULL;
  1296. X    int i;
  1297. X
  1298. X    if (s == NULL) {
  1299. X        fprint(fd, "%s=()\n", strprint(name, FALSE, FALSE));
  1300. X        return;
  1301. X    }
  1302. X
  1303. X    if (streq(name, "*")) {
  1304. X        s = s->n;
  1305. X        if (s == NULL)
  1306. X            return; /* Don't print $0, and if $* is not set, skip it */
  1307. X    }
  1308. X
  1309. X    for (i = 0; i < arraysize(keywords); i++)
  1310. X        if (streq(keywords[i], name)) {
  1311. X            newname = buf;
  1312. X            newname[0] = '\'';
  1313. X            strcpy(newname + 1, name);
  1314. X            strcat(newname, "\'");
  1315. X            break;
  1316. X        }
  1317. X
  1318. X    fprint(fd, s->n == NULL ? "%s=%l\n" : "%s=(%l)\n", newname == NULL ? strprint(name, FALSE, FALSE) : newname, s);
  1319. }
  1320. SHAR_EOF
  1321. chmod 0644 var.c ||
  1322. echo 'restore of var.c failed'
  1323. Wc_c="`wc -c < 'var.c'`"
  1324. test 6567 -eq "$Wc_c" ||
  1325.     echo 'var.c: original size 6567, current size' "$Wc_c"
  1326. rm -f _shar_wnt_.tmp
  1327. fi
  1328. # ============= version.c ==============
  1329. if test -f 'version.c' -a X"$1" != X"-c"; then
  1330.     echo 'x - skipping version.c (File already exists)'
  1331.     rm -f _shar_wnt_.tmp
  1332. else
  1333. > _shar_wnt_.tmp
  1334. echo 'x - extracting version.c (Text)'
  1335. sed 's/^X//' << 'SHAR_EOF' > 'version.c' &&
  1336. static char *
  1337. #ifdef __STDC__
  1338. X          volatile const     /* a little ANSI joke... */
  1339. #endif
  1340. X                id = "@(#) rc version 1.2, 9/22/91.";
  1341. SHAR_EOF
  1342. chmod 0644 version.c ||
  1343. echo 'restore of version.c failed'
  1344. Wc_c="`wc -c < 'version.c'`"
  1345. test 127 -eq "$Wc_c" ||
  1346.     echo 'version.c: original size 127, current size' "$Wc_c"
  1347. rm -f _shar_wnt_.tmp
  1348. fi
  1349. # ============= wait.c ==============
  1350. if test -f 'wait.c' -a X"$1" != X"-c"; then
  1351.     echo 'x - skipping wait.c (File already exists)'
  1352.     rm -f _shar_wnt_.tmp
  1353. else
  1354. > _shar_wnt_.tmp
  1355. echo 'x - extracting wait.c (Text)'
  1356. sed 's/^X//' << 'SHAR_EOF' > 'wait.c' &&
  1357. #include <errno.h>
  1358. #include "rc.h"
  1359. #include "utils.h"
  1360. #include "nalloc.h"
  1361. #include "wait.h"
  1362. X
  1363. typedef struct Pid Pid;
  1364. X
  1365. static struct Pid {
  1366. X    int p;
  1367. X    int stat;
  1368. X    boolean alive;
  1369. X    Pid *n;
  1370. } *plist = NULL;
  1371. X
  1372. int rc_fork() {
  1373. X    Pid *new = enew(Pid);
  1374. X    int pid = fork();
  1375. X
  1376. X    switch (pid) {
  1377. X    case -1:
  1378. X        uerror("fork");
  1379. X        rc_error(NULL);
  1380. X        /* NOTREACHED */
  1381. X    case 0:
  1382. X        return 0;
  1383. X    default:
  1384. X        new->p = pid;
  1385. X        new->alive = TRUE;
  1386. X        new->n = plist;
  1387. X        plist = new;
  1388. X        return pid;
  1389. X    }
  1390. }
  1391. X
  1392. int rc_wait4(int pid, int *stat) {
  1393. X    Pid *r, *prev;
  1394. X    int ret;
  1395. X
  1396. X    /* first look for a child which may already have exited */
  1397. X
  1398. again:    for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n)
  1399. X        if (r->p == pid)
  1400. X            break;
  1401. X
  1402. X    if (r == NULL) {
  1403. X        errno = ECHILD; /* no children */
  1404. X        uerror("wait");
  1405. X        *stat = 0x100; /* exit(1) */
  1406. X        return -1;
  1407. X    }
  1408. X
  1409. X    if (r->alive) {
  1410. X        while (pid != (ret = wait(stat))) {
  1411. X            Pid *q;
  1412. X
  1413. X            if (ret < 0)        /* if rc is interrupted, a signal handler may have already */
  1414. X                goto again;    /* wait()ed while the main rc was in limbo, so try again   */
  1415. X
  1416. X            for (q = plist; q != NULL; q = q->n)
  1417. X                if (q->p == ret) {
  1418. X                    q->alive = FALSE;
  1419. X                    q->stat = *stat;
  1420. X                    break;
  1421. X                }
  1422. X        }
  1423. X    } else
  1424. X        *stat = r->stat;
  1425. X
  1426. X    if (prev == NULL)
  1427. X        plist = r->n; /* remove element from head of list */
  1428. X    else
  1429. X        prev->n = r->n;
  1430. X    efree(r);
  1431. X
  1432. X    return pid;
  1433. }
  1434. X
  1435. List *sgetapids() {
  1436. X    List *r;
  1437. X    Pid *p;
  1438. X
  1439. X    for (r = NULL, p = plist; p != NULL; p = p->n) {
  1440. X        char buf[16];
  1441. X        List *q;
  1442. X
  1443. X        if (!p->alive)
  1444. X            continue;
  1445. X
  1446. X        sprint(buf, "%d", p->p);
  1447. X        q = nnew(List);
  1448. X        q->w = ncpy(buf);
  1449. X        q->m = NULL;
  1450. X        q->n = r;
  1451. X        r = q;
  1452. X    }
  1453. X
  1454. X    return r;
  1455. }
  1456. X
  1457. void waitforall(int *stat) {
  1458. X    while (plist != NULL)
  1459. X        rc_wait4(plist->p, stat);
  1460. }
  1461. SHAR_EOF
  1462. chmod 0644 wait.c ||
  1463. echo 'restore of wait.c failed'
  1464. Wc_c="`wc -c < 'wait.c'`"
  1465. test 1660 -eq "$Wc_c" ||
  1466.     echo 'wait.c: original size 1660, current size' "$Wc_c"
  1467. rm -f _shar_wnt_.tmp
  1468. fi
  1469. # ============= wait.h ==============
  1470. if test -f 'wait.h' -a X"$1" != X"-c"; then
  1471.     echo 'x - skipping wait.h (File already exists)'
  1472.     rm -f _shar_wnt_.tmp
  1473. else
  1474. > _shar_wnt_.tmp
  1475. echo 'x - extracting wait.h (Text)'
  1476. sed 's/^X//' << 'SHAR_EOF' > 'wait.h' &&
  1477. extern int rc_fork(void);
  1478. extern int rc_wait4(int, int *);
  1479. extern List *sgetapids(void);
  1480. extern void waitforall(int *);
  1481. SHAR_EOF
  1482. chmod 0644 wait.h ||
  1483. echo 'restore of wait.h failed'
  1484. Wc_c="`wc -c < 'wait.h'`"
  1485. test 120 -eq "$Wc_c" ||
  1486.     echo 'wait.h: original size 120, current size' "$Wc_c"
  1487. rm -f _shar_wnt_.tmp
  1488. fi
  1489. # ============= walk.c ==============
  1490. if test -f 'walk.c' -a X"$1" != X"-c"; then
  1491.     echo 'x - skipping walk.c (File already exists)'
  1492.     rm -f _shar_wnt_.tmp
  1493. else
  1494. > _shar_wnt_.tmp
  1495. echo 'x - extracting walk.c (Text)'
  1496. sed 's/^X//' << 'SHAR_EOF' > 'walk.c' &&
  1497. /* walk.c: walks the parse tree. */
  1498. X
  1499. #include "jbwrap.h"
  1500. #include <signal.h>
  1501. #include "rc.h"
  1502. #include "utils.h"
  1503. #include "status.h"
  1504. #include "exec.h"
  1505. #include "walk.h"
  1506. #include "glom.h"
  1507. #include "hash.h"
  1508. #include "glob.h"
  1509. #include "lex.h"
  1510. #include "open.h"
  1511. #include "except.h"
  1512. #include "wait.h"
  1513. X
  1514. boolean cond = FALSE;
  1515. X
  1516. static boolean isallpre(Node *);
  1517. static boolean dofork(void);
  1518. static void dopipe(Node *);
  1519. X
  1520. /* Tail-recursive version of walk() */
  1521. X
  1522. #define WALK(x,y) { n = x; parent = y; goto top; }
  1523. X
  1524. /* walk the parse-tree. "obvious". */
  1525. X
  1526. boolean walk(Node *n, boolean parent) {
  1527. top:    if (n == NULL) {
  1528. X        if (!parent)
  1529. X            exit(0);
  1530. X        set(TRUE);
  1531. X        return TRUE;
  1532. X    }
  1533. X
  1534. X    switch (n->type) {
  1535. X    case ARGS: case BACKQ: case CONCAT: case rCOUNT:
  1536. X    case rFLAT: case LAPPEND: case rREDIR: case VAR:
  1537. X    case VARSUB: case rWORD: case QWORD:
  1538. X        exec(glob(glom(n)), parent);    /* simple command */
  1539. X        break;
  1540. X    case BODY:
  1541. X        walk(n->u[0].p, TRUE);
  1542. X        WALK(n->u[1].p, TRUE);
  1543. X        break;
  1544. X    case NOWAIT: {
  1545. X        int pid;
  1546. X        char apid[8];
  1547. X
  1548. X        if ((pid = rc_fork()) == 0) {
  1549. X            setsigdefaults();
  1550. #if defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP)
  1551. X            signal(SIGTTOU, SIG_IGN);    /* Berkeleyized version: put it in a new pgroup. */
  1552. X            signal(SIGTTIN, SIG_IGN);
  1553. X            signal(SIGTSTP, SIG_IGN);
  1554. X            setpgrp(0, getpid());
  1555. #else
  1556. X            signal(SIGINT, SIG_IGN);    /* traditional backgrounding procedure: ignore SIGINT */
  1557. #endif
  1558. X            dup2(rc_open("/dev/null", FROM), 0);
  1559. X            walk(n->u[0].p, FALSE);
  1560. X            exit(getstatus());
  1561. X        }
  1562. X
  1563. X        if (interactive)
  1564. X            fprint(2,"%d\n",pid);
  1565. X        varassign("apid", word(sprint(apid,"%d",pid), NULL), FALSE);
  1566. X        redirq = NULL; /* kill pre-redir queue */
  1567. X        fifoq = NULL;
  1568. X        break;
  1569. X    }
  1570. X    case rANDAND: {
  1571. X        boolean oldcond = cond;
  1572. X
  1573. X        cond = TRUE;
  1574. X        if (walk(n->u[0].p, TRUE)) {
  1575. X            cond = oldcond;
  1576. X            WALK(n->u[1].p, TRUE);
  1577. X        } else
  1578. X            cond = oldcond;
  1579. X        break;
  1580. X    }
  1581. X    case rOROR: {
  1582. X        boolean oldcond = cond;
  1583. X
  1584. X        cond = TRUE;
  1585. X        if (!walk(n->u[0].p, TRUE)) {
  1586. X            cond = oldcond;
  1587. X            WALK(n->u[1].p, TRUE);
  1588. X        } else
  1589. X            cond = oldcond;
  1590. X        break;
  1591. X    }
  1592. X    case rBANG:
  1593. X        set(!walk(n->u[0].p, TRUE));
  1594. X        break;
  1595. X    case rIF: {
  1596. X        boolean oldcond = cond;
  1597. X        Node *true_cmd = n->u[1].p, *false_cmd = NULL;
  1598. X
  1599. X        if (true_cmd != NULL && true_cmd->type == rELSE) {
  1600. X            false_cmd = true_cmd->u[1].p;
  1601. X            true_cmd = true_cmd->u[0].p;
  1602. X        }
  1603. X        cond = TRUE;
  1604. X        if (!walk(n->u[0].p, TRUE))
  1605. X            true_cmd = false_cmd; /* run the else clause */
  1606. X        cond = oldcond;
  1607. X        WALK(true_cmd, TRUE);
  1608. X        break;
  1609. X    }
  1610. X    case rWHILE: {
  1611. X        jbwrap j;
  1612. X        boolean oldcond = cond;
  1613. X        Estack e1,e2;
  1614. X
  1615. X        cond = TRUE;
  1616. X
  1617. X        if (!walk(n->u[0].p, TRUE)) { /* prevent spurious breaks inside test */
  1618. X            cond = oldcond;
  1619. X            break;
  1620. X        }
  1621. X
  1622. X        if (setjmp(j.j))
  1623. X            break;
  1624. X
  1625. X        except(BREAK, &j, &e1);
  1626. X        do {
  1627. X            cond = oldcond;
  1628. X            except(ARENA, NULL, &e2);
  1629. X            walk(n->u[1].p, TRUE);
  1630. X            unexcept(); /* ARENA */
  1631. X            cond = TRUE;
  1632. X        } while (walk(n->u[0].p, TRUE));
  1633. X        cond = oldcond;
  1634. X        unexcept(); /* BREAK */
  1635. X        break;
  1636. X    }
  1637. X    case FORIN: {
  1638. X        List *l;
  1639. X        jbwrap j;
  1640. X        Estack e1,e2;
  1641. X
  1642. X        if (setjmp(j.j))
  1643. X            break;
  1644. X
  1645. X        except(BREAK, &j, &e1);
  1646. X        for (l = glob(glom(n->u[1].p)); l != NULL; l = l->n) {
  1647. X            assign(glom(n->u[0].p), word(l->w, NULL), FALSE);
  1648. X            except(ARENA, NULL, &e2);
  1649. X            walk(n->u[2].p, TRUE);
  1650. X            unexcept(); /* ARENA */
  1651. X        }
  1652. X        unexcept(); /* BREAK */
  1653. X        break;
  1654. X    }
  1655. X    case rSUBSHELL:
  1656. X        if (dofork()) {
  1657. X            setsigdefaults();
  1658. X            walk(n->u[0].p, TRUE);
  1659. X            rc_exit(getstatus());
  1660. X        }
  1661. X        break;
  1662. X    case ASSIGN:
  1663. X        if (n->u[0].p == NULL)
  1664. X            rc_error("null variable name");
  1665. X        assign(glom(n->u[0].p), glob(glom(n->u[1].p)), FALSE);
  1666. X        set(TRUE);
  1667. X        break;
  1668. X    case rPIPE:
  1669. X        dopipe(n);
  1670. X        break;
  1671. X    case NEWFN: {
  1672. X        List *l = glom(n->u[0].p);
  1673. X
  1674. X        if (l == NULL)
  1675. X            rc_error("null function name");
  1676. X        while (l != NULL) {
  1677. X            if (dashex)
  1678. X                prettyprint_fn(2, l->w, n->u[1].p);
  1679. X            fnassign(l->w, n->u[1].p);
  1680. X            l = l->n;
  1681. X        }
  1682. X        set(TRUE);
  1683. X        break;
  1684. X    }
  1685. X    case RMFN: {
  1686. X        List *l = glom(n->u[0].p);
  1687. X
  1688. X        while (l != NULL) {
  1689. X            if (dashex)
  1690. X                fprint(2, "fn %s\n", strprint(l->w, FALSE, FALSE));
  1691. X            fnrm(l->w);
  1692. X            l = l->n;
  1693. X        }
  1694. X        set(TRUE);
  1695. X        break;
  1696. X    }
  1697. X    case rDUP:
  1698. X        break; /* Null command */
  1699. X    case MATCH: {
  1700. X        List *a = glob(glom(n->u[0].p)), *b = glom(n->u[1].p);
  1701. X
  1702. X        if (dashex)
  1703. X            fprint(2, (a != NULL && a->n != NULL) ? "~ (%l) %l\n" : "~ %l %l\n", a, b);
  1704. X        set(lmatch(a,b));
  1705. X        break;
  1706. X    }
  1707. X    case rSWITCH: {
  1708. X        List *v = glom(n->u[0].p);
  1709. X
  1710. X        while (1) {
  1711. X            do {
  1712. X                n = n->u[1].p;
  1713. X                if (n == NULL)
  1714. X                    return istrue();
  1715. X            } while (n->u[0].p == NULL || n->u[0].p->type != rCASE);
  1716. X            if (lmatch(v, glom(n->u[0].p->u[0].p))) {
  1717. X                for (n = n->u[1].p; n != NULL && (n->u[0].p == NULL || n->u[0].p->type != rCASE); n = n->u[1].p)
  1718. X                    walk(n->u[0].p, TRUE);
  1719. X                break;
  1720. X            }
  1721. X        }
  1722. X        break;
  1723. X    }
  1724. X    case PRE: {
  1725. X        List *v;
  1726. X
  1727. X        if (n->u[0].p->type == rREDIR) {
  1728. X            qredir(n->u[0].p);
  1729. X            walk(n->u[1].p, TRUE);
  1730. X            break;
  1731. X        } else if (n->u[0].p->type == ASSIGN) {
  1732. X            if (isallpre(n->u[1].p)) {
  1733. X                walk(n->u[0].p, TRUE);
  1734. X                walk(n->u[1].p, TRUE);
  1735. X                break;
  1736. X            } else {
  1737. X                Estack e;
  1738. X                
  1739. X                v = glom(n->u[0].p->u[0].p);
  1740. X                assign(v, glob(glom(n->u[0].p->u[1].p)), TRUE);
  1741. X                except(VARSTACK, v->w, &e);
  1742. X                walk(n->u[1].p, TRUE);
  1743. X                varrm(v->w, TRUE);
  1744. X                unexcept(); /* VARSTACK */
  1745. X            }
  1746. X        } else
  1747. X            rc_error("walk: node other than assign or redir in PRE. help!");
  1748. X        break;
  1749. X    }
  1750. X    case BRACE:
  1751. X        if (n->u[1].p == NULL) {
  1752. X            WALK(n->u[0].p, TRUE);
  1753. X        } else if (dofork()) {
  1754. X            setsigdefaults();
  1755. X            walk(n->u[1].p, TRUE); /* Do redirections */
  1756. X            redirq = NULL;   /* Reset redirection queue */
  1757. X            walk(n->u[0].p, TRUE); /* Do commands */
  1758. X            rc_exit(getstatus());
  1759. X            /* NOTREACHED */
  1760. X        }
  1761. X        break;
  1762. X    case EPILOG:
  1763. X        qredir(n->u[0].p);
  1764. X        if (n->u[1].p != NULL) {
  1765. X            WALK(n->u[1].p, TRUE); /* Do more redirections. */
  1766. X        } else {
  1767. X            doredirs();    /* Okay, we hit the bottom. */
  1768. X        }
  1769. X        break;
  1770. X    case NMPIPE:
  1771. X        rc_error("named pipes cannot be executed as commands");
  1772. X        /* NOTREACHED */
  1773. X    default:
  1774. X        rc_error("walk: unknown node; this can't happen");
  1775. X        /* NOTREACHED */
  1776. X    }
  1777. X    return istrue();
  1778. }
  1779. X
  1780. /* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
  1781. X
  1782. static boolean isallpre(Node *n) {
  1783. X    if (n == NULL)
  1784. X        return TRUE;
  1785. X
  1786. X    switch (n->type) {
  1787. X    case PRE:
  1788. X        return isallpre(n->u[1].p);
  1789. X    case rREDIR: case ASSIGN: case rDUP:
  1790. X        return TRUE;
  1791. X    default:
  1792. X        return FALSE;
  1793. X    }
  1794. }
  1795. X
  1796. /*
  1797. X   A code-saver. Forks, child returns (for further processing in walk()), and the parent
  1798. X   waits for the child to finish, setting $status appropriately.
  1799. */
  1800. X
  1801. static boolean dofork() {
  1802. X    int pid, sp;
  1803. X
  1804. X    if ((pid = rc_fork()) == 0)
  1805. X        return TRUE;
  1806. X
  1807. X    redirq = NULL; /* clear out the pre-redirection queue in the parent */
  1808. X    fifoq = NULL;
  1809. X    rc_wait4(pid, &sp);
  1810. X    setstatus(sp);
  1811. X    return FALSE;
  1812. }
  1813. X
  1814. static void dopipe(Node *n) {
  1815. X    int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2];
  1816. X    boolean intr;
  1817. X    void (*handler)(int);
  1818. X    Node *r;
  1819. X
  1820. X    fd_prev = fd_out = 1;
  1821. X
  1822. X    for (r = n, i = 0; r != NULL && r->type == rPIPE; r = r->u[2].p, i++) {
  1823. X        if (i > 500) /* the only hard-wired limit in rc? */
  1824. X            rc_error("pipe too long");
  1825. X
  1826. X        if (pipe(p) < 0) {
  1827. X            uerror("pipe");
  1828. X            rc_error(NULL);
  1829. X        }
  1830. X
  1831. X        if ((pid = rc_fork()) == 0) {
  1832. X            setsigdefaults();
  1833. X            redirq = NULL; /* clear preredir queue */
  1834. X            fifoq = NULL;
  1835. X            dup2(p[0],r->u[1].i);
  1836. X            if (fd_prev != 1) {
  1837. X                dup2(fd_prev, fd_out);
  1838. X                close(fd_prev);
  1839. X            }
  1840. X            close(p[0]);
  1841. X            close(p[1]);
  1842. X            walk(r->u[3].p, FALSE);
  1843. X            exit(getstatus());
  1844. X        }
  1845. X
  1846. X        if (fd_prev != 1)
  1847. X            close(fd_prev); /* parent must close all pipe fd's */
  1848. X        pids[i] = pid;
  1849. X        fd_prev = p[1];
  1850. X        fd_out = r->u[0].i;
  1851. X        close(p[0]);
  1852. X    }
  1853. X
  1854. X    if ((pid = rc_fork()) == 0) {
  1855. X        setsigdefaults();
  1856. X        dup2(fd_prev, fd_out);
  1857. X        close(fd_prev);
  1858. X        walk(r, FALSE);
  1859. X        exit(getstatus());
  1860. X        /* NOTREACHED */
  1861. X    }
  1862. X
  1863. X    redirq = NULL; /* clear preredir queue */
  1864. X    fifoq = NULL;
  1865. X    close(fd_prev);
  1866. X    pids[i++] = pid;
  1867. X
  1868. X    /* collect statuses */
  1869. X
  1870. X    intr = FALSE;
  1871. X
  1872. X    if ((handler = signal(SIGINT, SIG_IGN)) == SIG_DFL)
  1873. X        signal(SIGINT, SIG_DFL); /* don't ignore interrupts in noninteractive mode */
  1874. X
  1875. X    for (j = 0; j < i; j++) {
  1876. X        rc_wait4(pids[j], &sp);
  1877. X        stats[j] = sp;
  1878. X        intr |= (sp == SIGINT);
  1879. X    }
  1880. X
  1881. X    setpipestatus(stats, i);
  1882. X    signal(SIGINT, handler);
  1883. X    if (intr) /* interrupted during pipe? let the signal handler deal with it */
  1884. X        rc_raise(ERROR);
  1885. }
  1886. SHAR_EOF
  1887. chmod 0644 walk.c ||
  1888. echo 'restore of walk.c failed'
  1889. Wc_c="`wc -c < 'walk.c'`"
  1890. test 8100 -eq "$Wc_c" ||
  1891.     echo 'walk.c: original size 8100, current size' "$Wc_c"
  1892. rm -f _shar_wnt_.tmp
  1893. fi
  1894. # ============= walk.h ==============
  1895. if test -f 'walk.h' -a X"$1" != X"-c"; then
  1896.     echo 'x - skipping walk.h (File already exists)'
  1897.     rm -f _shar_wnt_.tmp
  1898. else
  1899. > _shar_wnt_.tmp
  1900. echo 'x - extracting walk.h (Text)'
  1901. sed 's/^X//' << 'SHAR_EOF' > 'walk.h' &&
  1902. extern boolean walk(Node *, boolean);
  1903. extern boolean cond;
  1904. SHAR_EOF
  1905. chmod 0644 walk.h ||
  1906. echo 'restore of walk.h failed'
  1907. Wc_c="`wc -c < 'walk.h'`"
  1908. test 59 -eq "$Wc_c" ||
  1909.     echo 'walk.h: original size 59, current size' "$Wc_c"
  1910. rm -f _shar_wnt_.tmp
  1911. fi
  1912. # ============= which.c ==============
  1913. if test -f 'which.c' -a X"$1" != X"-c"; then
  1914.     echo 'x - skipping which.c (File already exists)'
  1915.     rm -f _shar_wnt_.tmp
  1916. else
  1917. > _shar_wnt_.tmp
  1918. echo 'x - extracting which.c (Text)'
  1919. sed 's/^X//' << 'SHAR_EOF' > 'which.c' &&
  1920. /* which.c: check to see if a file is executable.
  1921. X
  1922. X   This function was originally written with Maarten Litmaath's which.c as
  1923. X   a template, but was changed in order to accomodate the possibility of
  1924. X   rc's running setuid or the possibility of executing files not in the
  1925. X   primary group. Much of this file has been re-vamped by Paul Haahr.
  1926. X   I re-re-vamped the functions that Paul supplied to correct minor bugs
  1927. X   and to strip out unneeded functionality.
  1928. */
  1929. X
  1930. #include <sys/types.h>
  1931. #include <sys/stat.h>
  1932. #include <sys/param.h>
  1933. #include <errno.h>
  1934. #include "rc.h"
  1935. #include "hash.h"
  1936. #include "utils.h"
  1937. #include "builtins.h"
  1938. X
  1939. #define X_USR 0100
  1940. #define X_GRP 0010
  1941. #define X_OTH 0001
  1942. #define X_ALL (X_USR|X_GRP|X_OTH)
  1943. X
  1944. extern int stat(const char *, struct stat *);
  1945. X
  1946. static boolean initialized = FALSE;
  1947. static int uid, gid;
  1948. X
  1949. #ifdef NGROUPS
  1950. static int ngroups, gidset[NGROUPS];
  1951. X
  1952. /* determine whether gid lies in gidset */
  1953. X
  1954. static int ingidset(int gid) {
  1955. X    int i;
  1956. X    for (i = 0; i < ngroups; i++)
  1957. X        if (gid == gidset[i])
  1958. X            return 1;
  1959. X    return 0;
  1960. }
  1961. #endif
  1962. X
  1963. /*
  1964. X   A home-grown access/stat. Does the right thing for group-executable files.
  1965. X   Returns a boolean result instead of this -1 nonsense.
  1966. */
  1967. X
  1968. static boolean rc_access(char *path, boolean verbose) {
  1969. X    struct stat st;
  1970. X    int mask;
  1971. X
  1972. X    if (stat(path, &st) != 0) {
  1973. X        if (verbose) /* verbose flag only set for absolute pathname */
  1974. X            uerror(path);
  1975. X        return FALSE;
  1976. X    }
  1977. X
  1978. X    if (uid == 0)
  1979. X        mask = X_ALL;
  1980. X    else if (uid == st.st_uid)
  1981. X        mask = X_USR;
  1982. #ifdef NGROUPS
  1983. X    else if (gid == st.st_gid || ingidset(st.st_gid))
  1984. #else
  1985. X    else if (gid == st.st_gid)
  1986. #endif
  1987. X        mask = X_GRP;
  1988. X    else
  1989. X        mask = X_OTH;
  1990. X
  1991. X    if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask))
  1992. X        return TRUE;
  1993. X
  1994. X    errno = EACCES;
  1995. X    if (verbose)
  1996. X        uerror(path);
  1997. X    return FALSE;
  1998. }
  1999. X
  2000. /* return a full pathname by searching $path, and by checking the status of the file */
  2001. X
  2002. char *which(char *name, boolean verbose) {
  2003. X    static char *test = NULL;
  2004. X    static int testlen = 0;
  2005. X    List *path;
  2006. X    int len;
  2007. X
  2008. X    if (name == NULL)    /* no filename? can happen with "> foo" as a command */
  2009. X        return NULL;
  2010. X
  2011. X    if (!initialized) {
  2012. X        initialized = TRUE;
  2013. X        uid = geteuid();
  2014. X        gid = getegid();
  2015. #ifdef NGROUPS
  2016. X        ngroups = getgroups(NGROUPS, gidset);
  2017. #endif
  2018. X    }
  2019. X
  2020. X    if (isabsolute(name)) /* absolute pathname? */
  2021. X        return rc_access(name, verbose) ? name : NULL;
  2022. X
  2023. X    len = strlen(name);
  2024. X    for (path = varlookup("path"); path != NULL; path = path->n) {
  2025. X        int need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
  2026. X        if (testlen < need) {
  2027. X            efree(test);
  2028. X            test = ealloc(testlen = need);
  2029. X        }
  2030. X        if (*path->w == '\0') {
  2031. X            strcpy(test, name);
  2032. X        } else {
  2033. X            strcpy(test, path->w);
  2034. X            strcat(test, "/");
  2035. X            strcat(test, name);
  2036. X        }
  2037. X        if (rc_access(test, FALSE))
  2038. X            return test;
  2039. X    }
  2040. X    if (verbose)
  2041. X        fprint(2, "%s not found\n", name);
  2042. X    return NULL;
  2043. }
  2044. SHAR_EOF
  2045. chmod 0644 which.c ||
  2046. echo 'restore of which.c failed'
  2047. Wc_c="`wc -c < 'which.c'`"
  2048. test 2816 -eq "$Wc_c" ||
  2049.     echo 'which.c: original size 2816, current size' "$Wc_c"
  2050. rm -f _shar_wnt_.tmp
  2051. fi
  2052. rm -f _shar_seq_.tmp
  2053. echo You have unpacked the last part
  2054. exit 0
  2055. exit 0 # Just in case...
  2056. -- 
  2057. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2058. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2059. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2060. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2061.