home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-18 | 47.7 KB | 2,061 lines |
- Newsgroups: comp.sources.misc
- From: byron@archone.tamu.edu (Byron Rakitzis)
- Subject: v23i066: rc - A Plan 9 shell reimplementation, v1.2, Part06/06
- Message-ID: <1991Oct18.034533.2626@sparky.imd.sterling.com>
- X-Md4-Signature: 34f51e7a094aa424e830d9bdcf6f92e3
- Date: Fri, 18 Oct 1991 03:45:33 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
- Posting-number: Volume 23, Issue 66
- Archive-name: rc/part06
- Environment: UNIX
- Supersedes: rc: Volume 20, Issue 10-13
-
- #!/bin/sh
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file redir.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 6; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- if test ! -f _shar_wnt_.tmp; then
- echo 'x - still skipping redir.c'
- else
- echo 'x - continuing file redir.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'redir.c' &&
- X exit(1);
- X }
- X close(p[0]);
- X }
- X } else {
- X fname = glob(glom(r->r->u[2].p));
- X if (fname == NULL) {
- X fprint(2,"null filename in redirection\n");
- X exit(1);
- X }
- X if (fname->n != NULL) {
- X fprint(2,"multi-word filename in redirection\n");
- X exit(1);
- X }
- X switch (r->r->u[0].i) {
- X default:
- X fprint(2,"doredirs: this can't happen\n");
- X exit(1);
- X /* NOTREACHED */
- X case CREATE: case APPEND: case FROM:
- X fd = rc_open(fname->w, r->r->u[0].i);
- X break;
- X }
- X if (fd < 0) {
- X uerror(fname->w);
- X exit(1);
- X }
- X if (dup2(fd, r->r->u[1].i) < 0) {
- X uerror("dup");
- X exit(1);
- X }
- X close(fd);
- X }
- X break;
- X case rDUP:
- X if (r->r->u[2].i == -1)
- X close(r->r->u[1].i);
- X else if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) {
- X uerror("dup");
- X exit(1);
- X }
- X }
- X }
- X redirq = NULL;
- }
- SHAR_EOF
- echo 'File redir.c is complete' &&
- chmod 0644 redir.c ||
- echo 'restore of redir.c failed'
- Wc_c="`wc -c < 'redir.c'`"
- test 2480 -eq "$Wc_c" ||
- echo 'redir.c: original size 2480, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= redir.h ==============
- if test -f 'redir.h' -a X"$1" != X"-c"; then
- echo 'x - skipping redir.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting redir.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'redir.h' &&
- extern void doredirs(void);
- SHAR_EOF
- chmod 0644 redir.h ||
- echo 'restore of redir.h failed'
- Wc_c="`wc -c < 'redir.h'`"
- test 28 -eq "$Wc_c" ||
- echo 'redir.h: original size 28, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= status.c ==============
- if test -f 'status.c' -a X"$1" != X"-c"; then
- echo 'x - skipping status.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting status.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'status.c' &&
- /* status.c: functions for printing fancy status messages in rc */
- X
- #include "rc.h"
- #include "utils.h"
- #include "status.h"
- #include "nalloc.h"
- #include "walk.h"
- #include "sigmsgs.h"
- X
- /* status == the wait() value of the last command in the pipeline, or the last command */
- X
- static int statuses[512];
- static int pipelength = 1;
- X
- /*
- X Test to see if rc's status is true. According to td, status is true if and only if every
- X pipe-member has an exit status of zero.
- */
- X
- int istrue() {
- X int i;
- X
- X for (i = 0; i < pipelength; i++)
- X if (statuses[i] != 0)
- X return FALSE;
- X return TRUE;
- }
- X
- /*
- X Return the status as an integer. A status which has low-bits set is a signal number,
- X whereas a status with high bits set is a value set from exit().
- */
- X
- int getstatus() {
- X int s = statuses[0];
- X
- X return s & 0xff ? s & 0x7f : (s >> 8) & 0xff;
- }
- X
- void set(boolean code) {
- X setstatus((!code) << 8); /* exit status 1 == 0x100 */
- }
- X
- /* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */
- X
- void setpipestatus(int stats[], int num) {
- X int i;
- X
- X for (i = 0; i < (pipelength = num); i++) {
- X statprint(stats[i]);
- X statuses[i] = stats[i];
- X }
- }
- X
- /* set a simple status, as opposed to a pipeline */
- X
- void setstatus(int i) {
- X pipelength = 1;
- X statuses[0] = i;
- X statprint(i);
- }
- X
- /* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */
- X
- void statprint(int i) {
- X if (i & 0xff) {
- X char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f][1] : "");
- X
- X if (i & 0x80) {
- X if (*msg == '\0')
- X fprint(2,"core dumped\n");
- X else
- X fprint(2,"%s--core dumped\n",msg);
- X } else if (*msg != '\0')
- X fprint(2,"%s\n",msg);
- X }
- X
- X if (i != 0 && dashee && !cond)
- X rc_exit(getstatus());
- }
- X
- /* prepare a list to be passed back. Used whenever $status is dereferenced */
- X
- List *sgetstatus() {
- X List *r;
- X int i;
- X
- X for (r = NULL, i = 0; i < pipelength; i++) {
- X char buf[16];
- X List *q = nnew(List);
- X int s = statuses[i];
- X int t;
- X
- X q->n = r;
- X r = q;
- X
- X if ((t = s & 0x7f) != 0) {
- X if (t < NUMOFSIGNALS && *signals[t][0] != '\0')
- X sprint(buf, "%s", signals[t][0]);
- X else
- X sprint(buf,"-%d", t); /* unknown signals are negated */
- X if (s & 0x80)
- X strcat(buf, "+core");
- X } else {
- X sprint(buf, "%d", (s >> 8) & 0xff);
- X }
- X
- X r->w = ncpy(buf);
- X r->m = NULL;
- X }
- X
- X return r;
- }
- X
- void ssetstatus(char **av) {
- X int i, j, k, l;
- X boolean found;
- X
- X for (l = 0; av[l] != NULL; l++)
- X ; /* count up array length */
- X --l;
- X
- X for (i = 0; av[i] != NULL; i++) {
- X j = a2u(av[i]);
- X
- X if (j >= 0) {
- X statuses[l - i] = j << 8;
- X continue;
- X }
- X
- X found = FALSE;
- X for (k = 0; k < NUMOFSIGNALS; k++) {
- X if (streq(signals[k][0], av[i])) {
- X statuses[l - i] = k;
- X found = TRUE;
- X break;
- X } else {
- X int len = strlen(signals[k][0]);
- X if (strncmp(signals[k][0], av[i], len) == 0 && streq(av[i] + len, "+core")) {
- X statuses[l - i] = k + 0x80;
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X if (!found) {
- X fprint(2, "bad return value\n");
- X set(FALSE);
- X return;
- X }
- X }
- X pipelength = i;
- }
- SHAR_EOF
- chmod 0644 status.c ||
- echo 'restore of status.c failed'
- Wc_c="`wc -c < 'status.c'`"
- test 3078 -eq "$Wc_c" ||
- echo 'status.c: original size 3078, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= status.h ==============
- if test -f 'status.h' -a X"$1" != X"-c"; then
- echo 'x - skipping status.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting status.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'status.h' &&
- extern int istrue(void);
- extern int getstatus(void);
- extern void set(boolean);
- extern void setstatus(int);
- extern List *sgetstatus(void);
- extern void setpipestatus(int [], int);
- extern void statprint(int);
- extern void ssetstatus(char **);
- SHAR_EOF
- chmod 0644 status.h ||
- echo 'restore of status.h failed'
- Wc_c="`wc -c < 'status.h'`"
- test 239 -eq "$Wc_c" ||
- echo 'status.h: original size 239, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= stddef.h ==============
- if test -f 'stddef.h' -a X"$1" != X"-c"; then
- echo 'x - skipping stddef.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting stddef.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'stddef.h' &&
- /* stddef.h
- X This file provides a definition for size_t and align_t that
- X should work for your system. If it does not, it is up to you to
- X make it the right thing. The problem is that I cannot rely upon
- X <sys/params.h> to do the right thing on machines which don't
- X yet have ansi header files. Note that on many RISC machines,
- X align_t must be at least 32 bits wide, and sparc doubles are
- X aligned on 64 bit boundaries, but of course, rc does not use
- X doubles in its code, so the "typedef long ALIGN_T" is good
- X enough in the sparc's case. Also for performance reasons on a
- X VAX one would probably want align_t to be 32 bits wide.
- */
- typedef long ALIGN_T;
- typedef unsigned int SIZE_T;
- typedef short int MODE_T;
- typedef int PID_T;
- X
- #ifndef NULL
- #define NULL 0
- #endif
- SHAR_EOF
- chmod 0644 stddef.h ||
- echo 'restore of stddef.h failed'
- Wc_c="`wc -c < 'stddef.h'`"
- test 766 -eq "$Wc_c" ||
- echo 'stddef.h: original size 766, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= stdlib.h ==============
- if test -f 'stdlib.h' -a X"$1" != X"-c"; then
- echo 'x - skipping stdlib.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting stdlib.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'stdlib.h' &&
- /*
- X stdlib.h function prototypes as taken from Appendix B of K&R 2.
- X Unused functions are:
- X atof(), atoi(), atol(), strtod(), strtol(), strtoul(), rand(),
- X srand(), calloc(), abort(), atexit(), system(), getenv(), bsearch(),
- X abs(), labs(), div() and ldiv()
- */
- X
- extern void *malloc(SIZE_T);
- extern void *realloc(void *, SIZE_T);
- extern void free(void *);
- extern void exit(int);
- extern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *));
- SHAR_EOF
- chmod 0644 stdlib.h ||
- echo 'restore of stdlib.h failed'
- Wc_c="`wc -c < 'stdlib.h'`"
- test 462 -eq "$Wc_c" ||
- echo 'stdlib.h: original size 462, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= string.h ==============
- if test -f 'string.h' -a X"$1" != X"-c"; then
- echo 'x - skipping string.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting string.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'string.h' &&
- extern int strncmp(const char *, const char *, SIZE_T);
- extern int strcmp(const char *, const char *);
- extern SIZE_T strlen(const char *);
- extern char *strchr(const char *, int);
- extern char *strrchr(const char *, int);
- extern char *strcpy(char *, const char *);
- extern char *strncpy(char *, const char *, SIZE_T);
- extern char *strcat(char *, const char *);
- extern char *strncat(char *, const char *, SIZE_T);
- extern void *memcpy(void *, const void *, SIZE_T);
- X
- #define streq(x,y) (*(x) == *(y) && strcmp(x,y) == 0)
- SHAR_EOF
- chmod 0644 string.h ||
- echo 'restore of string.h failed'
- Wc_c="`wc -c < 'string.h'`"
- test 516 -eq "$Wc_c" ||
- echo 'string.h: original size 516, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= tree.c ==============
- if test -f 'tree.c' -a X"$1" != X"-c"; then
- echo 'x - skipping tree.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting tree.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'tree.c' &&
- /* tree.c: functions for manipulating parse-trees. (create, copy, delete) */
- X
- #include <stdarg.h>
- #include "rc.h"
- #include "tree.h"
- #include "utils.h"
- #include "nalloc.h"
- X
- /* make a new node, pass it back to yyparse. Used to generate the parsetree. */
- X
- Node *newnode(int /*enum nodetype*/ t,...) {
- X va_list ap;
- X Node *n;
- X
- X va_start(ap,t);
- X
- X switch (t) {
- X default:
- X fprint(2,"newnode: this can't happen\n");
- X exit(1);
- X /* NOTREACHED */
- X case rDUP:
- X n = nalloc(offsetof(Node, u[3]));
- X n->u[0].i = va_arg(ap, int);
- X n->u[1].i = va_arg(ap, int);
- X n->u[2].i = va_arg(ap, int);
- X break;
- X case rWORD: case QWORD:
- X n = nalloc(offsetof(Node, u[2]));
- X n->u[0].s = va_arg(ap, char *);
- X n->u[1].s = va_arg(ap, char *);
- X break;
- X case rBANG: case NOWAIT:
- X case rCOUNT: case rFLAT: case RMFN: case rSUBSHELL:
- X case VAR: case rCASE:
- X n = nalloc(offsetof(Node, u[1]));
- X n->u[0].p = va_arg(ap, Node *);
- X break;
- X case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
- X case rELSE: case EPILOG: case rIF: case NEWFN: case CBODY:
- X case rOROR: case PRE: case ARGS: case rSWITCH:
- X case MATCH: case VARSUB: case rWHILE: case LAPPEND:
- X n = nalloc(offsetof(Node, u[2]));
- X n->u[0].p = va_arg(ap, Node *);
- X n->u[1].p = va_arg(ap, Node *);
- X break;
- X case FORIN:
- X n = nalloc(offsetof(Node, u[3]));
- X n->u[0].p = va_arg(ap, Node *);
- X n->u[1].p = va_arg(ap, Node *);
- X n->u[2].p = va_arg(ap, Node *);
- X break;
- X case rPIPE:
- X n = nalloc(offsetof(Node, u[4]));
- X n->u[0].i = va_arg(ap, int);
- X n->u[1].i = va_arg(ap, int);
- X n->u[2].p = va_arg(ap, Node *);
- X n->u[3].p = va_arg(ap, Node *);
- X break;
- X case rREDIR:
- X case NMPIPE:
- X n = nalloc(offsetof(Node, u[3]));
- X n->u[0].i = va_arg(ap, int);
- X n->u[1].i = va_arg(ap, int);
- X n->u[2].p = va_arg(ap, Node *);
- X break;
- X }
- X n->type = t;
- X va_end(ap);
- X return n;
- }
- X
- /* copy a tree to malloc space. Used when storing the definition of a function */
- X
- Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) {
- X Node *n;
- X
- X if (s == NULL)
- X return NULL;
- X
- X switch (s->type) {
- X default:
- X fprint(2,"treecpy: this can't happen\n");
- X exit(1);
- X /* NOTREACHED */
- X case rDUP:
- X n = alloc(offsetof(Node, u[3]));
- X n->u[0].i = s->u[0].i;
- X n->u[1].i = s->u[1].i;
- X n->u[2].i = s->u[2].i;
- X break;
- X case rWORD: case QWORD:
- X n = alloc(offsetof(Node, u[2]));
- X n->u[0].s = ecpy(s->u[0].s);
- X if (s->u[1].s != NULL) {
- X SIZE_T i = strlen(s->u[0].s);
- X
- X n->u[1].s = alloc(i);
- X memcpy(n->u[1].s, s->u[1].s, i);
- X } else
- X n->u[1].s = NULL;
- X break;
- X case rBANG: case NOWAIT: case rCASE:
- X case rCOUNT: case rFLAT: case RMFN: case rSUBSHELL: case VAR:
- X n = alloc(offsetof(Node, u[1]));
- X n->u[0].p = treecpy(s->u[0].p, alloc);
- X break;
- X case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
- X case rELSE: case EPILOG: case rIF: case NEWFN: case CBODY:
- X case rOROR: case PRE: case ARGS: case rSWITCH:
- X case MATCH: case VARSUB: case rWHILE: case LAPPEND:
- X n = alloc(offsetof(Node, u[2]));
- X n->u[0].p = treecpy(s->u[0].p, alloc);
- X n->u[1].p = treecpy(s->u[1].p, alloc);
- X break;
- X case FORIN:
- X n = alloc(offsetof(Node, u[3]));
- X n->u[0].p = treecpy(s->u[0].p, alloc);
- X n->u[1].p = treecpy(s->u[1].p, alloc);
- X n->u[2].p = treecpy(s->u[2].p, alloc);
- X break;
- X case rPIPE:
- X n = alloc(offsetof(Node, u[4]));
- X n->u[0].i = s->u[0].i;
- X n->u[1].i = s->u[1].i;
- X n->u[2].p = treecpy(s->u[2].p, alloc);
- X n->u[3].p = treecpy(s->u[3].p, alloc);
- X break;
- X case rREDIR:
- X case NMPIPE:
- X n = alloc(offsetof(Node, u[3]));
- X n->u[0].i = s->u[0].i;
- X n->u[1].i = s->u[1].i;
- X n->u[2].p = treecpy(s->u[2].p, alloc);
- X break;
- X }
- X n->type = s->type;
- X return n;
- }
- X
- /* free a function definition that is no longer needed */
- X
- void treefree(Node *s) {
- X if (s == NULL)
- X return;
- X switch (s->type) {
- X case rDUP:
- X break;
- X case rWORD: case QWORD:
- X efree(s->u[0].s);
- X efree(s->u[1].s);
- X break;
- X case rBANG: case NOWAIT:
- X case rCOUNT: case rFLAT: case RMFN:
- X case rSUBSHELL: case VAR: case rCASE:
- X treefree(s->u[0].p);
- X efree(s->u[0].p);
- X break;
- X case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
- X case rELSE: case EPILOG: case rIF: case NEWFN:
- X case rOROR: case PRE: case ARGS: case CBODY:
- X case rSWITCH: case MATCH: case VARSUB: case rWHILE:
- X case LAPPEND:
- X treefree(s->u[1].p);
- X treefree(s->u[0].p);
- X efree(s->u[1].p);
- X efree(s->u[0].p);
- X break;
- X case FORIN:
- X treefree(s->u[2].p);
- X treefree(s->u[1].p);
- X treefree(s->u[0].p);
- X efree(s->u[2].p);
- X efree(s->u[1].p);
- X efree(s->u[0].p);
- X break;
- X case rPIPE:
- X treefree(s->u[2].p);
- X treefree(s->u[3].p);
- X efree(s->u[2].p);
- X efree(s->u[3].p);
- X break;
- X case rREDIR:
- X case NMPIPE:
- X treefree(s->u[2].p);
- X efree(s->u[2].p);
- X break;
- X default:
- X fprint(2,"treefree: this can't happen\n");
- X exit(1);
- X }
- }
- SHAR_EOF
- chmod 0644 tree.c ||
- echo 'restore of tree.c failed'
- Wc_c="`wc -c < 'tree.c'`"
- test 4722 -eq "$Wc_c" ||
- echo 'tree.c: original size 4722, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= tree.h ==============
- if test -f 'tree.h' -a X"$1" != X"-c"; then
- echo 'x - skipping tree.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting tree.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'tree.h' &&
- extern Node *newnode(int /*enum nodetype*/ t,...);
- extern Node *treecpy(Node *s, void *(*)(SIZE_T));
- extern void treefree(Node *s);
- SHAR_EOF
- chmod 0644 tree.h ||
- echo 'restore of tree.h failed'
- Wc_c="`wc -c < 'tree.h'`"
- test 132 -eq "$Wc_c" ||
- echo 'tree.h: original size 132, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= unistd.h ==============
- if test -f 'unistd.h' -a X"$1" != X"-c"; then
- echo 'x - skipping unistd.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting unistd.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'unistd.h' &&
- extern PID_T fork(void);
- extern PID_T getpid(void);
- extern int chdir(const char *);
- extern int close(int);
- extern int dup2(int, int);
- extern int execve(const char *, const char **, const char **);
- extern int execl(const char *, ...);
- extern int getegid(void);
- extern int geteuid(void);
- extern int getgroups(int, int *);
- extern int isatty(int);
- #ifndef SYSVR4 /* declares AND defines this in sys/stat.h!! */
- extern int mknod(const char *, int, int);
- #endif
- extern int pipe(int *);
- extern int read(int, void *, unsigned int);
- extern int setpgrp(int, PID_T);
- extern int unlink(const char *);
- extern int wait(int *);
- extern int write(int, const void *, unsigned int);
- X
- extern int optind;
- extern char *optarg;
- extern int errno;
- X
- extern char *getenv(const char *);
- SHAR_EOF
- chmod 0644 unistd.h ||
- echo 'restore of unistd.h failed'
- Wc_c="`wc -c < 'unistd.h'`"
- test 759 -eq "$Wc_c" ||
- echo 'unistd.h: original size 759, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= utils.c ==============
- if test -f 'utils.c' -a X"$1" != X"-c"; then
- echo 'x - skipping utils.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting utils.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'utils.c' &&
- /* utils.c: general utility functions like fprint, ealloc etc. */
- X
- #include <stdarg.h>
- #include <errno.h>
- #include "jbwrap.h"
- #include <signal.h>
- #include "rc.h"
- #include "utils.h"
- #include "nalloc.h"
- #include "status.h"
- #include "input.h"
- #include "except.h"
- #include "lex.h" /* import char nw[]; used by strprint to see if it needs to quote a word */
- #include "walk.h"
- #include "footobar.h"
- #include "glom.h"
- #include "hash.h"
- #include "wait.h"
- X
- static void dprint(va_list, char *, char *);
- static int n2u(char *, int);
- X
- /* exception handlers */
- X
- void pr_error(char *s) {
- X if (s != NULL) {
- X if (interactive)
- X fprint(2,"%s\n",s);
- X else
- X fprint(2,"line %d: %s\n", lineno - 1, s);
- X }
- }
- X
- void rc_error(char *s) {
- X pr_error(s);
- X set(FALSE);
- X redirq = NULL;
- X cond = FALSE; /* no longer inside conditional */
- X empty_fifoq();
- X rc_raise(ERROR);
- }
- X
- void sig(int s) {
- X signal(SIGINT, sig); /* some unices require re-signaling */
- X
- X if (errno == EINTR)
- X return; /* allow wait() to complete */
- X
- X fprint(2,"\n"); /* this is the newline you see when you hit ^C while typing a command */
- X redirq = NULL;
- X cond = FALSE;
- X empty_fifoq();
- X rc_raise(ERROR);
- }
- X
- /* our perror */
- X
- void uerror(char *s) {
- X extern int sys_nerr;
- X extern char *sys_errlist[];
- X
- X if (errno > sys_nerr)
- X return;
- X
- X if (s != NULL)
- X fprint(2,"%s: %s\n",s,sys_errlist[errno]);
- X else
- X fprint(2,"%s\n",sys_errlist[errno]);
- }
- X
- /* printing functions */
- X
- void fprint(int fd, char *f,...) {
- X va_list ap;
- X char str[FPRINT_SIZE];
- X
- X va_start(ap,f);
- X dprint(ap, str, f);
- X va_end(ap);
- X writeall(fd,str,strlen(str));
- }
- X
- char *sprint(char *b, char *f,...) {
- X va_list ap;
- X
- X va_start(ap, f);
- X dprint(ap, b, f);
- X va_end(ap);
- X return b;
- }
- X
- static void dprint(va_list ap, char *strbuf, char *f) {
- X int i;
- X
- X for (i = 0; *f != '\0'; f++) {
- X if (*f != '%') {
- X strbuf[i++] = *f;
- X continue; /* avoid an ugly extra level of indentation */
- X }
- X switch (*++f) {
- X case 'a': {
- X char **a = va_arg(ap, char **);
- X
- X if (*a == NULL)
- X break;
- X strcpy(strbuf + i, *a);
- X i += strlen(*a);
- X while (*++a != NULL) {
- X strbuf[i++] = ' ';
- X strcpy(strbuf + i, *a);
- X i += strlen(*a);
- X }
- X break;
- X }
- X case 'c':
- X strbuf[i++] = va_arg(ap, int);
- X break;
- X case 'd': case 'o': {
- X int v = va_arg(ap, int);
- X int j = 0;
- X int base = (*f == 'd' ? 10 : 8);
- X char num[16];
- X
- X if (v == 0)
- X num[j++] = '0';
- X while (v != 0) {
- X num[j++] = (v % base) + '0';
- X v /= base;
- X }
- X while (--j >= 0)
- X strbuf[i++] = num[j];
- X break;
- X }
- X case 's': {
- X char *s = va_arg(ap, char *);
- X while (*s != '\0')
- X strbuf[i++] = *s++;
- X break;
- X }
- X case 'l': {
- X List *s, *l = va_arg(ap, List *);
- X
- X if (l == NULL) {
- X strbuf[i++] = '(';
- X strbuf[i++] = ')';
- X break;
- X }
- X for (s = l; s != NULL; s = s->n) {
- X strcpy(strbuf + i, strprint(s->w, FALSE, TRUE));
- X while (strbuf[i] != '\0')
- X i++;
- X if (s->n != NULL)
- X strbuf[i++] = ' ';
- X }
- X break;
- X }
- X default: /* on format error, just print the bad format */
- X strbuf[i++] = '%';
- X /* FALLTHROUGH */
- X case '%':
- X strbuf[i++] = *f;
- X }
- X }
- X strbuf[i] = '\0';
- }
- X
- /* prints a string in rc-quoted form. e.g., a string with spaces in it must be quoted */
- X
- char *strprint(char *s, int quotable, int metaquote) { /* really boolean, but y.tab.c includes utils.h */
- X SIZE_T i,j;
- X char *t;
- X
- X if (*s == '\0')
- X return "''";
- X
- X for (i = 0; s[i] != '\0'; i++)
- X if (nw[(unsigned char) s[i]] == 1 || (metaquote && (s[i] == '*' || s[i] == '?' || s[i] == '[')))
- X quotable = TRUE;
- X
- X if (!quotable)
- X return s; /* If the string doesn't need quotes, return */
- X
- X for (i = j = 0; s[i] != '\0'; i++, j++)
- X if (s[i] == '\'')
- X j++;
- X
- X t = nalloc(j + 3);
- X
- X t[0] = '\'';
- X
- X for (j = 1, i = 0; s[i] != '\0'; i++, j++) {
- X t[j] = s[i];
- X if (s[i] == '\'')
- X t[++j] = '\'';
- X }
- X
- X t[j++] = '\'';
- X t[j] = '\0';
- X
- X return t;
- }
- X
- /* ascii -> unsigned conversion routines. -1 indicates conversion error. */
- X
- static int n2u(char *s, int base) {
- X int i;
- X
- X for (i = 0; *s != '\0'; s++) {
- X /* small hack with unsigned ints -- one compare for range test */
- X if (((unsigned int) *s) - '0' >= (unsigned int) base)
- X return -1;
- X i = (i * base) + (*s - '0');
- X }
- X return i;
- }
- X
- /* decimal -> uint */
- X
- int a2u(char *s) {
- X return n2u(s, 10);
- }
- X
- /* octal -> uint */
- X
- int o2u(char *s) {
- X return n2u(s, 8);
- }
- X
- /* memory allocation functions */
- X
- void *ealloc(SIZE_T n) {
- X void *p = malloc(n);
- X
- X if (p == NULL) {
- X uerror("malloc");
- X rc_exit(1);
- X }
- X
- X return p;
- }
- X
- void *erealloc(void *p, SIZE_T n) {
- X p = realloc(p, n);
- X
- X if (p == NULL) {
- X uerror("realloc");
- X rc_exit(1);
- X }
- X
- X return p;
- }
- X
- void efree(void *p) {
- X if (p != NULL)
- X free(p);
- }
- X
- /* useful functions */
- X
- /* The last word in portable ANSI: a strcmp wrapper for qsort */
- X
- int starstrcmp(const void *s1, const void *s2) {
- X return strcmp(*(char **)s1, *(char **)s2);
- }
- X
- /* tests to see if pathname begins with "/", "./", or "../" */
- X
- int isabsolute(char *path) {
- X return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
- }
- X
- /* write a given buffer allowing for partial writes from write(2) */
- X
- void writeall(int fd, char *buf, SIZE_T remain) {
- X int i;
- X
- X for (i = 0; remain > 0; buf += i, remain -= i)
- X if ((i = write(fd, buf, remain)) <= 0)
- X return; /* abort silently on errors in write() */
- }
- X
- /* clear out z bytes from character string s */
- X
- void clear(char *s, SIZE_T z) {
- X while (z != 0)
- X s[--z] = 0;
- }
- X
- /* zero out the fifo queue, removing the fifos from /tmp as you go (also prints errors arising from signals) */
- X
- void empty_fifoq() {
- X int sp;
- X
- X while (fifoq != NULL) {
- X rc_wait4(fifoq->pid, &sp);
- X statprint(sp);
- X unlink(fifoq->name);
- X fifoq = fifoq->n;
- X }
- }
- X
- SIZE_T strarraylen(char **a) {
- X SIZE_T i;
- X
- X for (i = 0; *a != NULL; a++)
- X i += strlen(*a) + 1;
- X
- X return i;
- }
- SHAR_EOF
- chmod 0644 utils.c ||
- echo 'restore of utils.c failed'
- Wc_c="`wc -c < 'utils.c'`"
- test 5782 -eq "$Wc_c" ||
- echo 'utils.c: original size 5782, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= utils.h ==============
- if test -f 'utils.h' -a X"$1" != X"-c"; then
- echo 'x - skipping utils.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting utils.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'utils.h' &&
- extern char *strprint(char *, int, int);
- extern char *sprint(char *, char *,...);
- extern int isabsolute(char *); /* not boolean because y.tab.c includes utils.h */
- extern int a2u(char *);
- extern int o2u(char *);
- extern int starstrcmp(const void *, const void *);
- extern void *ealloc(SIZE_T);
- extern void *erealloc(void *, SIZE_T);
- extern void efree(void *);
- extern void fprint(int, char *,...);
- extern void empty_fifoq(void);
- extern void pr_error(char *);
- extern void rc_error(char *);
- extern void rc_exit(int); /* prototyped here, but defined in fn.c */
- extern void sig(int);
- extern void clear(char *, SIZE_T);
- extern void uerror(char *);
- extern void writeall(int, char *, SIZE_T);
- extern SIZE_T strarraylen(char **);
- X
- /* memory allocation abbreviations */
- #define enew(x) ((x *) ealloc(sizeof(x)))
- #define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1),x)
- X
- #define FPRINT_SIZE 16384
- SHAR_EOF
- chmod 0644 utils.h ||
- echo 'restore of utils.h failed'
- Wc_c="`wc -c < 'utils.h'`"
- test 884 -eq "$Wc_c" ||
- echo 'utils.h: original size 884, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= var.c ==============
- if test -f 'var.c' -a X"$1" != X"-c"; then
- echo 'x - skipping var.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting var.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'var.c' &&
- /* var.c: provide "public" functions for adding and removing variables from the symbol table */
- X
- #include "rc.h"
- #include "utils.h"
- #include "hash.h"
- #include "list.h"
- #include "footobar.h"
- #include "nalloc.h"
- #include "status.h"
- #include "glom.h"
- #include "wait.h"
- X
- #ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
- extern void rl_reset_terminal(char *);
- #endif
- X
- static void colonassign(char *, List *, boolean);
- static void listassign(char *, List *, boolean);
- static int hasalias(char *);
- X
- static char *const aliases[] = {
- X "home", "HOME", "path", "PATH", "cdpath", "CDPATH"
- };
- X
- /* assign a variable in List form to a name, stacking if appropriate */
- X
- void varassign(char *name, List *def, boolean stack) {
- X Variable *new;
- X List *newdef = listcpy(def); /* important to do the listcpy first; get_var_place() frees old values */
- X
- X new = get_var_place(name, stack);
- X new->def = newdef;
- X new->extdef = NULL;
- X
- #ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
- X if (interactive && streq(name, "TERM") || streq(name, "TERMCAP"))
- X rl_reset_terminal(NULL);
- #endif
- }
- X
- /* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
- X
- boolean varassign_string(char *extdef) {
- X char *name = get_name(extdef);
- X Variable *new;
- X int i;
- X static boolean aliasset[arraysize(aliases)] = {
- X FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
- X };
- X
- X if (name == NULL)
- X return FALSE; /* add it to bozo env */
- X
- X i = hasalias(name);
- X if (i >= 0) {
- X aliasset[i] = TRUE;
- X if ((i & 1 == 0) && aliasset[i^1])
- X return TRUE; /* don't alias variables that are already set in upper case */
- X }
- X new = get_var_place(name, FALSE);
- X new->def = NULL;
- X new->extdef = ealloc(strlen(extdef) + 1);
- X strcpy(new->extdef, extdef);
- X if (hasalias(name) != -1)
- X alias(name, varlookup(name), FALSE);
- X return TRUE;
- }
- X
- /*
- X Return a List based on a name lookup. If the list is in external (string) form,
- X convert it to internal (List) form. Treat $n (n is an integer) specially as $*(n).
- X Also check to see if $status is being dereferenced. (we lazily evaluate the List
- X associated with $status)
- */
- X
- List *varlookup(char *name) {
- X Variable *look;
- X List *ret, *l;
- X int sub;
- X
- X if (streq(name, "status"))
- X return sgetstatus();
- X if (streq(name, "apids"))
- X return sgetapids();
- X
- X if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
- X for (l = varlookup("*"); l != NULL && sub != 0; --sub)
- X l = l->n;
- X if (l == NULL)
- X return NULL;
- X ret = nnew(List);
- X ret->w = l->w;
- X ret->m = NULL;
- X ret->n = NULL;
- X return ret;
- X }
- X
- X look = lookup_var(name);
- X
- X if (look == NULL)
- X return NULL; /* not found */
- X if (look->def != NULL)
- X return look->def;
- X if (look->extdef == NULL)
- X return NULL; /* variable was set to null, e.g., a=() echo foo */
- X
- X ret = parse_var(name, look->extdef);
- X
- X if (ret == NULL) {
- X look->extdef = NULL;
- X return NULL;
- X }
- X return look->def = ret;
- }
- X
- /* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */
- X
- char *varlookup_string(char *name) {
- X Variable *look;
- X
- X look = lookup_var(name);
- X
- X if (look == NULL)
- X return NULL;
- X if (look->extdef != NULL)
- X return look->extdef;
- X if (look->def == NULL)
- X return NULL;
- X return look->extdef = list2str(name, look->def);
- }
- X
- /* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
- X
- void varrm(char *name, boolean stack) {
- X int i = hasalias(name);
- X
- X if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
- X varassign("*", varlookup("0"), FALSE);
- X return;
- X }
- X
- X delete_var(name, stack);
- X if (i != -1)
- X delete_var(aliases[i^1], stack);
- }
- X
- /* assign a value (List) to a variable, using array "a" as input. Used to assign $* */
- X
- void starassign(char *dollarzero, char **a, boolean stack) {
- X List *s, *var;
- X
- X var = nnew(List);
- X var->w = dollarzero;
- X
- X if (*a == NULL) {
- X var->n = NULL;
- X varassign("*", var, stack);
- X return;
- X }
- X
- X var->n = s = nnew(List);
- X
- X while (1) {
- X s->w = *a++;
- X if (*a == NULL) {
- X s->n = NULL;
- X break;
- X } else {
- X s->n = nnew(List);
- X s = s->n;
- X }
- X }
- X varassign("*", var, stack);
- }
- X
- /* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */
- X
- static void colonassign(char *name, List *def, boolean stack) {
- X char *colondef;
- X List dud;
- X SIZE_T deflen;
- X List *r;
- X
- X if (def == NULL) {
- X varassign(name, NULL, stack);
- X return;
- X }
- X
- X deflen = listlen(def) + 1; /* one for the null terminator */
- X
- X colondef = nalloc(deflen);
- X strcpy(colondef, def->w);
- X
- X for (r = def->n; r != NULL; r = r->n) {
- X strcat(colondef, ":");
- X strcat(colondef, r->w);
- X }
- X
- X dud.w = colondef;
- X dud.n = NULL;
- X varassign(name, &dud, stack);
- }
- X
- /* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */
- X
- static void listassign(char *name, List *def, boolean stack) {
- X List *val, *r;
- X char *v, *w;
- X
- X if (def == NULL) {
- X varassign(name, NULL, stack);
- X return;
- X }
- X
- X v = def->w;
- X
- X r = val = enew(List);
- X
- X while((w = strchr(v,':')) != NULL) {
- X *w = '\0';
- X r->w = ecpy(v);
- X *w = ':';
- X v = w + 1;
- X r->n = enew(List);
- X r = r->n;
- X }
- X r->w = ecpy(v);
- X r->n = NULL;
- X
- X varassign(name, val, stack);
- }
- X
- /* check to see if a particular variable is aliased; return -1 on failure, or the index */
- X
- static int hasalias(char *name) {
- X int i;
- X
- X for (i = 0; i < arraysize(aliases); i++)
- X if (streq(name, aliases[i]))
- X return i;
- X return -1;
- }
- X
- /* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */
- X
- void alias(char *name, List *s, boolean stack) {
- X int i = hasalias(name);
- X static void (*vectors[])(char *, List *, boolean) = {
- X varassign, varassign, colonassign, listassign, colonassign, listassign
- X };
- X
- X if (i != -1)
- X vectors[i](aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
- }
- X
- void prettyprint_var(int fd, char *name, List *s) {
- X static char *keywords[] = {
- X "if", "in", "fn", "for", "else", "switch", "while", "case"
- X };
- X char buf[10], *newname = NULL;
- X int i;
- X
- X if (s == NULL) {
- X fprint(fd, "%s=()\n", strprint(name, FALSE, FALSE));
- X return;
- X }
- X
- X if (streq(name, "*")) {
- X s = s->n;
- X if (s == NULL)
- X return; /* Don't print $0, and if $* is not set, skip it */
- X }
- X
- X for (i = 0; i < arraysize(keywords); i++)
- X if (streq(keywords[i], name)) {
- X newname = buf;
- X newname[0] = '\'';
- X strcpy(newname + 1, name);
- X strcat(newname, "\'");
- X break;
- X }
- X
- X fprint(fd, s->n == NULL ? "%s=%l\n" : "%s=(%l)\n", newname == NULL ? strprint(name, FALSE, FALSE) : newname, s);
- }
- SHAR_EOF
- chmod 0644 var.c ||
- echo 'restore of var.c failed'
- Wc_c="`wc -c < 'var.c'`"
- test 6567 -eq "$Wc_c" ||
- echo 'var.c: original size 6567, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= version.c ==============
- if test -f 'version.c' -a X"$1" != X"-c"; then
- echo 'x - skipping version.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting version.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'version.c' &&
- static char *
- #ifdef __STDC__
- X volatile const /* a little ANSI joke... */
- #endif
- X id = "@(#) rc version 1.2, 9/22/91.";
- SHAR_EOF
- chmod 0644 version.c ||
- echo 'restore of version.c failed'
- Wc_c="`wc -c < 'version.c'`"
- test 127 -eq "$Wc_c" ||
- echo 'version.c: original size 127, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= wait.c ==============
- if test -f 'wait.c' -a X"$1" != X"-c"; then
- echo 'x - skipping wait.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting wait.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'wait.c' &&
- #include <errno.h>
- #include "rc.h"
- #include "utils.h"
- #include "nalloc.h"
- #include "wait.h"
- X
- typedef struct Pid Pid;
- X
- static struct Pid {
- X int p;
- X int stat;
- X boolean alive;
- X Pid *n;
- } *plist = NULL;
- X
- int rc_fork() {
- X Pid *new = enew(Pid);
- X int pid = fork();
- X
- X switch (pid) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X return 0;
- X default:
- X new->p = pid;
- X new->alive = TRUE;
- X new->n = plist;
- X plist = new;
- X return pid;
- X }
- }
- X
- int rc_wait4(int pid, int *stat) {
- X Pid *r, *prev;
- X int ret;
- X
- X /* first look for a child which may already have exited */
- X
- again: for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n)
- X if (r->p == pid)
- X break;
- X
- X if (r == NULL) {
- X errno = ECHILD; /* no children */
- X uerror("wait");
- X *stat = 0x100; /* exit(1) */
- X return -1;
- X }
- X
- X if (r->alive) {
- X while (pid != (ret = wait(stat))) {
- X Pid *q;
- X
- X if (ret < 0) /* if rc is interrupted, a signal handler may have already */
- X goto again; /* wait()ed while the main rc was in limbo, so try again */
- X
- X for (q = plist; q != NULL; q = q->n)
- X if (q->p == ret) {
- X q->alive = FALSE;
- X q->stat = *stat;
- X break;
- X }
- X }
- X } else
- X *stat = r->stat;
- X
- X if (prev == NULL)
- X plist = r->n; /* remove element from head of list */
- X else
- X prev->n = r->n;
- X efree(r);
- X
- X return pid;
- }
- X
- List *sgetapids() {
- X List *r;
- X Pid *p;
- X
- X for (r = NULL, p = plist; p != NULL; p = p->n) {
- X char buf[16];
- X List *q;
- X
- X if (!p->alive)
- X continue;
- X
- X sprint(buf, "%d", p->p);
- X q = nnew(List);
- X q->w = ncpy(buf);
- X q->m = NULL;
- X q->n = r;
- X r = q;
- X }
- X
- X return r;
- }
- X
- void waitforall(int *stat) {
- X while (plist != NULL)
- X rc_wait4(plist->p, stat);
- }
- SHAR_EOF
- chmod 0644 wait.c ||
- echo 'restore of wait.c failed'
- Wc_c="`wc -c < 'wait.c'`"
- test 1660 -eq "$Wc_c" ||
- echo 'wait.c: original size 1660, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= wait.h ==============
- if test -f 'wait.h' -a X"$1" != X"-c"; then
- echo 'x - skipping wait.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting wait.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'wait.h' &&
- extern int rc_fork(void);
- extern int rc_wait4(int, int *);
- extern List *sgetapids(void);
- extern void waitforall(int *);
- SHAR_EOF
- chmod 0644 wait.h ||
- echo 'restore of wait.h failed'
- Wc_c="`wc -c < 'wait.h'`"
- test 120 -eq "$Wc_c" ||
- echo 'wait.h: original size 120, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= walk.c ==============
- if test -f 'walk.c' -a X"$1" != X"-c"; then
- echo 'x - skipping walk.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting walk.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'walk.c' &&
- /* walk.c: walks the parse tree. */
- X
- #include "jbwrap.h"
- #include <signal.h>
- #include "rc.h"
- #include "utils.h"
- #include "status.h"
- #include "exec.h"
- #include "walk.h"
- #include "glom.h"
- #include "hash.h"
- #include "glob.h"
- #include "lex.h"
- #include "open.h"
- #include "except.h"
- #include "wait.h"
- X
- boolean cond = FALSE;
- X
- static boolean isallpre(Node *);
- static boolean dofork(void);
- static void dopipe(Node *);
- X
- /* Tail-recursive version of walk() */
- X
- #define WALK(x,y) { n = x; parent = y; goto top; }
- X
- /* walk the parse-tree. "obvious". */
- X
- boolean walk(Node *n, boolean parent) {
- top: if (n == NULL) {
- X if (!parent)
- X exit(0);
- X set(TRUE);
- X return TRUE;
- X }
- X
- X switch (n->type) {
- X case ARGS: case BACKQ: case CONCAT: case rCOUNT:
- X case rFLAT: case LAPPEND: case rREDIR: case VAR:
- X case VARSUB: case rWORD: case QWORD:
- X exec(glob(glom(n)), parent); /* simple command */
- X break;
- X case BODY:
- X walk(n->u[0].p, TRUE);
- X WALK(n->u[1].p, TRUE);
- X break;
- X case NOWAIT: {
- X int pid;
- X char apid[8];
- X
- X if ((pid = rc_fork()) == 0) {
- X setsigdefaults();
- #if defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP)
- X signal(SIGTTOU, SIG_IGN); /* Berkeleyized version: put it in a new pgroup. */
- X signal(SIGTTIN, SIG_IGN);
- X signal(SIGTSTP, SIG_IGN);
- X setpgrp(0, getpid());
- #else
- X signal(SIGINT, SIG_IGN); /* traditional backgrounding procedure: ignore SIGINT */
- #endif
- X dup2(rc_open("/dev/null", FROM), 0);
- X walk(n->u[0].p, FALSE);
- X exit(getstatus());
- X }
- X
- X if (interactive)
- X fprint(2,"%d\n",pid);
- X varassign("apid", word(sprint(apid,"%d",pid), NULL), FALSE);
- X redirq = NULL; /* kill pre-redir queue */
- X fifoq = NULL;
- X break;
- X }
- X case rANDAND: {
- X boolean oldcond = cond;
- X
- X cond = TRUE;
- X if (walk(n->u[0].p, TRUE)) {
- X cond = oldcond;
- X WALK(n->u[1].p, TRUE);
- X } else
- X cond = oldcond;
- X break;
- X }
- X case rOROR: {
- X boolean oldcond = cond;
- X
- X cond = TRUE;
- X if (!walk(n->u[0].p, TRUE)) {
- X cond = oldcond;
- X WALK(n->u[1].p, TRUE);
- X } else
- X cond = oldcond;
- X break;
- X }
- X case rBANG:
- X set(!walk(n->u[0].p, TRUE));
- X break;
- X case rIF: {
- X boolean oldcond = cond;
- X Node *true_cmd = n->u[1].p, *false_cmd = NULL;
- X
- X if (true_cmd != NULL && true_cmd->type == rELSE) {
- X false_cmd = true_cmd->u[1].p;
- X true_cmd = true_cmd->u[0].p;
- X }
- X cond = TRUE;
- X if (!walk(n->u[0].p, TRUE))
- X true_cmd = false_cmd; /* run the else clause */
- X cond = oldcond;
- X WALK(true_cmd, TRUE);
- X break;
- X }
- X case rWHILE: {
- X jbwrap j;
- X boolean oldcond = cond;
- X Estack e1,e2;
- X
- X cond = TRUE;
- X
- X if (!walk(n->u[0].p, TRUE)) { /* prevent spurious breaks inside test */
- X cond = oldcond;
- X break;
- X }
- X
- X if (setjmp(j.j))
- X break;
- X
- X except(BREAK, &j, &e1);
- X do {
- X cond = oldcond;
- X except(ARENA, NULL, &e2);
- X walk(n->u[1].p, TRUE);
- X unexcept(); /* ARENA */
- X cond = TRUE;
- X } while (walk(n->u[0].p, TRUE));
- X cond = oldcond;
- X unexcept(); /* BREAK */
- X break;
- X }
- X case FORIN: {
- X List *l;
- X jbwrap j;
- X Estack e1,e2;
- X
- X if (setjmp(j.j))
- X break;
- X
- X except(BREAK, &j, &e1);
- X for (l = glob(glom(n->u[1].p)); l != NULL; l = l->n) {
- X assign(glom(n->u[0].p), word(l->w, NULL), FALSE);
- X except(ARENA, NULL, &e2);
- X walk(n->u[2].p, TRUE);
- X unexcept(); /* ARENA */
- X }
- X unexcept(); /* BREAK */
- X break;
- X }
- X case rSUBSHELL:
- X if (dofork()) {
- X setsigdefaults();
- X walk(n->u[0].p, TRUE);
- X rc_exit(getstatus());
- X }
- X break;
- X case ASSIGN:
- X if (n->u[0].p == NULL)
- X rc_error("null variable name");
- X assign(glom(n->u[0].p), glob(glom(n->u[1].p)), FALSE);
- X set(TRUE);
- X break;
- X case rPIPE:
- X dopipe(n);
- X break;
- X case NEWFN: {
- X List *l = glom(n->u[0].p);
- X
- X if (l == NULL)
- X rc_error("null function name");
- X while (l != NULL) {
- X if (dashex)
- X prettyprint_fn(2, l->w, n->u[1].p);
- X fnassign(l->w, n->u[1].p);
- X l = l->n;
- X }
- X set(TRUE);
- X break;
- X }
- X case RMFN: {
- X List *l = glom(n->u[0].p);
- X
- X while (l != NULL) {
- X if (dashex)
- X fprint(2, "fn %s\n", strprint(l->w, FALSE, FALSE));
- X fnrm(l->w);
- X l = l->n;
- X }
- X set(TRUE);
- X break;
- X }
- X case rDUP:
- X break; /* Null command */
- X case MATCH: {
- X List *a = glob(glom(n->u[0].p)), *b = glom(n->u[1].p);
- X
- X if (dashex)
- X fprint(2, (a != NULL && a->n != NULL) ? "~ (%l) %l\n" : "~ %l %l\n", a, b);
- X set(lmatch(a,b));
- X break;
- X }
- X case rSWITCH: {
- X List *v = glom(n->u[0].p);
- X
- X while (1) {
- X do {
- X n = n->u[1].p;
- X if (n == NULL)
- X return istrue();
- X } while (n->u[0].p == NULL || n->u[0].p->type != rCASE);
- X if (lmatch(v, glom(n->u[0].p->u[0].p))) {
- 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)
- X walk(n->u[0].p, TRUE);
- X break;
- X }
- X }
- X break;
- X }
- X case PRE: {
- X List *v;
- X
- X if (n->u[0].p->type == rREDIR) {
- X qredir(n->u[0].p);
- X walk(n->u[1].p, TRUE);
- X break;
- X } else if (n->u[0].p->type == ASSIGN) {
- X if (isallpre(n->u[1].p)) {
- X walk(n->u[0].p, TRUE);
- X walk(n->u[1].p, TRUE);
- X break;
- X } else {
- X Estack e;
- X
- X v = glom(n->u[0].p->u[0].p);
- X assign(v, glob(glom(n->u[0].p->u[1].p)), TRUE);
- X except(VARSTACK, v->w, &e);
- X walk(n->u[1].p, TRUE);
- X varrm(v->w, TRUE);
- X unexcept(); /* VARSTACK */
- X }
- X } else
- X rc_error("walk: node other than assign or redir in PRE. help!");
- X break;
- X }
- X case BRACE:
- X if (n->u[1].p == NULL) {
- X WALK(n->u[0].p, TRUE);
- X } else if (dofork()) {
- X setsigdefaults();
- X walk(n->u[1].p, TRUE); /* Do redirections */
- X redirq = NULL; /* Reset redirection queue */
- X walk(n->u[0].p, TRUE); /* Do commands */
- X rc_exit(getstatus());
- X /* NOTREACHED */
- X }
- X break;
- X case EPILOG:
- X qredir(n->u[0].p);
- X if (n->u[1].p != NULL) {
- X WALK(n->u[1].p, TRUE); /* Do more redirections. */
- X } else {
- X doredirs(); /* Okay, we hit the bottom. */
- X }
- X break;
- X case NMPIPE:
- X rc_error("named pipes cannot be executed as commands");
- X /* NOTREACHED */
- X default:
- X rc_error("walk: unknown node; this can't happen");
- X /* NOTREACHED */
- X }
- X return istrue();
- }
- X
- /* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
- X
- static boolean isallpre(Node *n) {
- X if (n == NULL)
- X return TRUE;
- X
- X switch (n->type) {
- X case PRE:
- X return isallpre(n->u[1].p);
- X case rREDIR: case ASSIGN: case rDUP:
- X return TRUE;
- X default:
- X return FALSE;
- X }
- }
- X
- /*
- X A code-saver. Forks, child returns (for further processing in walk()), and the parent
- X waits for the child to finish, setting $status appropriately.
- */
- X
- static boolean dofork() {
- X int pid, sp;
- X
- X if ((pid = rc_fork()) == 0)
- X return TRUE;
- X
- X redirq = NULL; /* clear out the pre-redirection queue in the parent */
- X fifoq = NULL;
- X rc_wait4(pid, &sp);
- X setstatus(sp);
- X return FALSE;
- }
- X
- static void dopipe(Node *n) {
- X int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2];
- X boolean intr;
- X void (*handler)(int);
- X Node *r;
- X
- X fd_prev = fd_out = 1;
- X
- X for (r = n, i = 0; r != NULL && r->type == rPIPE; r = r->u[2].p, i++) {
- X if (i > 500) /* the only hard-wired limit in rc? */
- X rc_error("pipe too long");
- X
- X if (pipe(p) < 0) {
- X uerror("pipe");
- X rc_error(NULL);
- X }
- X
- X if ((pid = rc_fork()) == 0) {
- X setsigdefaults();
- X redirq = NULL; /* clear preredir queue */
- X fifoq = NULL;
- X dup2(p[0],r->u[1].i);
- X if (fd_prev != 1) {
- X dup2(fd_prev, fd_out);
- X close(fd_prev);
- X }
- X close(p[0]);
- X close(p[1]);
- X walk(r->u[3].p, FALSE);
- X exit(getstatus());
- X }
- X
- X if (fd_prev != 1)
- X close(fd_prev); /* parent must close all pipe fd's */
- X pids[i] = pid;
- X fd_prev = p[1];
- X fd_out = r->u[0].i;
- X close(p[0]);
- X }
- X
- X if ((pid = rc_fork()) == 0) {
- X setsigdefaults();
- X dup2(fd_prev, fd_out);
- X close(fd_prev);
- X walk(r, FALSE);
- X exit(getstatus());
- X /* NOTREACHED */
- X }
- X
- X redirq = NULL; /* clear preredir queue */
- X fifoq = NULL;
- X close(fd_prev);
- X pids[i++] = pid;
- X
- X /* collect statuses */
- X
- X intr = FALSE;
- X
- X if ((handler = signal(SIGINT, SIG_IGN)) == SIG_DFL)
- X signal(SIGINT, SIG_DFL); /* don't ignore interrupts in noninteractive mode */
- X
- X for (j = 0; j < i; j++) {
- X rc_wait4(pids[j], &sp);
- X stats[j] = sp;
- X intr |= (sp == SIGINT);
- X }
- X
- X setpipestatus(stats, i);
- X signal(SIGINT, handler);
- X if (intr) /* interrupted during pipe? let the signal handler deal with it */
- X rc_raise(ERROR);
- }
- SHAR_EOF
- chmod 0644 walk.c ||
- echo 'restore of walk.c failed'
- Wc_c="`wc -c < 'walk.c'`"
- test 8100 -eq "$Wc_c" ||
- echo 'walk.c: original size 8100, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= walk.h ==============
- if test -f 'walk.h' -a X"$1" != X"-c"; then
- echo 'x - skipping walk.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting walk.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'walk.h' &&
- extern boolean walk(Node *, boolean);
- extern boolean cond;
- SHAR_EOF
- chmod 0644 walk.h ||
- echo 'restore of walk.h failed'
- Wc_c="`wc -c < 'walk.h'`"
- test 59 -eq "$Wc_c" ||
- echo 'walk.h: original size 59, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= which.c ==============
- if test -f 'which.c' -a X"$1" != X"-c"; then
- echo 'x - skipping which.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting which.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'which.c' &&
- /* which.c: check to see if a file is executable.
- X
- X This function was originally written with Maarten Litmaath's which.c as
- X a template, but was changed in order to accomodate the possibility of
- X rc's running setuid or the possibility of executing files not in the
- X primary group. Much of this file has been re-vamped by Paul Haahr.
- X I re-re-vamped the functions that Paul supplied to correct minor bugs
- X and to strip out unneeded functionality.
- */
- X
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/param.h>
- #include <errno.h>
- #include "rc.h"
- #include "hash.h"
- #include "utils.h"
- #include "builtins.h"
- X
- #define X_USR 0100
- #define X_GRP 0010
- #define X_OTH 0001
- #define X_ALL (X_USR|X_GRP|X_OTH)
- X
- extern int stat(const char *, struct stat *);
- X
- static boolean initialized = FALSE;
- static int uid, gid;
- X
- #ifdef NGROUPS
- static int ngroups, gidset[NGROUPS];
- X
- /* determine whether gid lies in gidset */
- X
- static int ingidset(int gid) {
- X int i;
- X for (i = 0; i < ngroups; i++)
- X if (gid == gidset[i])
- X return 1;
- X return 0;
- }
- #endif
- X
- /*
- X A home-grown access/stat. Does the right thing for group-executable files.
- X Returns a boolean result instead of this -1 nonsense.
- */
- X
- static boolean rc_access(char *path, boolean verbose) {
- X struct stat st;
- X int mask;
- X
- X if (stat(path, &st) != 0) {
- X if (verbose) /* verbose flag only set for absolute pathname */
- X uerror(path);
- X return FALSE;
- X }
- X
- X if (uid == 0)
- X mask = X_ALL;
- X else if (uid == st.st_uid)
- X mask = X_USR;
- #ifdef NGROUPS
- X else if (gid == st.st_gid || ingidset(st.st_gid))
- #else
- X else if (gid == st.st_gid)
- #endif
- X mask = X_GRP;
- X else
- X mask = X_OTH;
- X
- X if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask))
- X return TRUE;
- X
- X errno = EACCES;
- X if (verbose)
- X uerror(path);
- X return FALSE;
- }
- X
- /* return a full pathname by searching $path, and by checking the status of the file */
- X
- char *which(char *name, boolean verbose) {
- X static char *test = NULL;
- X static int testlen = 0;
- X List *path;
- X int len;
- X
- X if (name == NULL) /* no filename? can happen with "> foo" as a command */
- X return NULL;
- X
- X if (!initialized) {
- X initialized = TRUE;
- X uid = geteuid();
- X gid = getegid();
- #ifdef NGROUPS
- X ngroups = getgroups(NGROUPS, gidset);
- #endif
- X }
- X
- X if (isabsolute(name)) /* absolute pathname? */
- X return rc_access(name, verbose) ? name : NULL;
- X
- X len = strlen(name);
- X for (path = varlookup("path"); path != NULL; path = path->n) {
- X int need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
- X if (testlen < need) {
- X efree(test);
- X test = ealloc(testlen = need);
- X }
- X if (*path->w == '\0') {
- X strcpy(test, name);
- X } else {
- X strcpy(test, path->w);
- X strcat(test, "/");
- X strcat(test, name);
- X }
- X if (rc_access(test, FALSE))
- X return test;
- X }
- X if (verbose)
- X fprint(2, "%s not found\n", name);
- X return NULL;
- }
- SHAR_EOF
- chmod 0644 which.c ||
- echo 'restore of which.c failed'
- Wc_c="`wc -c < 'which.c'`"
- test 2816 -eq "$Wc_c" ||
- echo 'which.c: original size 2816, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- rm -f _shar_seq_.tmp
- echo You have unpacked the last part
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-