home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-18 | 55.4 KB | 2,566 lines |
- Newsgroups: comp.sources.misc
- From: byron@archone.tamu.edu (Byron Rakitzis)
- Subject: v23i062: rc - A Plan 9 shell reimplementation, v1.2, Part02/06
- Message-ID: <1991Oct18.034306.2126@sparky.imd.sterling.com>
- X-Md4-Signature: e40b03bf1de892a0f76ae6f7a5d1c497
- Date: Fri, 18 Oct 1991 03:43:06 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
- Posting-number: Volume 23, Issue 62
- Archive-name: rc/part02
- Environment: UNIX
- Supersedes: rc: Volume 20, Issue 10-13
-
- #!/bin/sh
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file execve.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 2; 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 execve.c'
- else
- echo 'x - continuing file execve.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'execve.c' &&
- X
- /*
- X NOTE: this file depends on a hack in footobar.c which places two free spots before
- X av[][] so that execve does not have to call malloc.
- */
- X
- #include "rc.h"
- #include <errno.h>
- #include "lex.h"
- #include "open.h"
- X
- #define giveupif(x) { if (x) goto fail; }
- X
- int my_execve(const char *path, const char **av, const char **ev) {
- X int fd, len, fst, snd, end;
- X boolean noarg;
- X char pb[256]; /* arbitrary but generous limit */
- X
- X execve(path, av, ev);
- X
- X if (errno != ENOEXEC)
- X return -1;
- X
- X fd = rc_open(path, FROM);
- X
- X giveupif(fd < 0);
- X
- X len = read(fd, pb, sizeof pb);
- X close(fd);
- X
- X /*
- X This execve() rejects all scripts which don't begin with #!
- X This may have to be changed on some systems.
- X */
- X
- X giveupif(len <= 0 || pb[0] != '#' || pb[1] != '!');
- X
- X for (fst = 2; fst < len && (pb[fst] == ' ' || pb[fst] == '\t'); fst++)
- X ; /* skip leading whitespace */
- X
- X giveupif(fst == len);
- X
- X for (snd = fst; snd < len && pb[snd] != ' ' && pb[snd] != '\t' && pb[snd] != '\n'; snd++)
- X ; /* skip first arg */
- X
- X giveupif(snd == len);
- X
- X noarg = (pb[snd] == '\n');
- X
- X pb[snd++] = '\0'; /* null terminate the first arg */
- X
- X if (!noarg) {
- X while (snd < len && (pb[snd] == ' ' || pb[snd] == '\t'))
- X snd++; /* skip whitespace to second arg */
- X
- X giveupif(snd == len);
- X
- X noarg = (pb[snd] == '\n'); /* could have trailing whitespace after only one arg */
- X
- X if (!noarg) {
- X for (end = snd; end < len && pb[end] != ' ' && pb[end] != '\t' && pb[end] != '\n'; end++)
- X ; /* skip to the end of the second arg */
- X
- X giveupif(end == len);
- X
- X if (pb[end] == '\n') {
- X pb[end] = '\0'; /* null terminate the first arg */
- X } else { /* else check for a spurious third arg */
- X pb[end++] = '\0';
- X
- X while (end < len && (pb[end] == ' ' || pb[end] == '\t'))
- X end++;
- X
- X giveupif(end == len || pb[end] != '\n');
- X }
- X }
- X }
- X
- X *av = path;
- X
- X if (!noarg)
- X *--av = pb + snd;
- X *--av = pb + fst;
- X
- X execve(*av, av, ev);
- X return -1;
- X
- fail: errno = ENOEXEC;
- X return -1;
- }
- SHAR_EOF
- echo 'File execve.c is complete' &&
- chmod 0644 execve.c ||
- echo 'restore of execve.c failed'
- Wc_c="`wc -c < 'execve.c'`"
- test 2017 -eq "$Wc_c" ||
- echo 'execve.c: original size 2017, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= fn.c ==============
- if test -f 'fn.c' -a X"$1" != X"-c"; then
- echo 'x - skipping fn.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting fn.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'fn.c' &&
- /*
- X fn.c: functions for adding and deleting functions from the symbol table.
- X Support for signal handlers is also found here.
- */
- X
- #include "rc.h"
- #include <signal.h>
- #ifdef PROTECT_JOB
- #include <sys/ioctl.h>
- #endif
- #include "utils.h"
- #include "status.h"
- #include "tree.h"
- #include "hash.h"
- #include "footobar.h"
- #include "walk.h"
- #include "nalloc.h"
- #include "sigmsgs.h"
- #include "builtins.h"
- #include "input.h"
- X
- static void fn_handler(int);
- X
- static Node *handlers[NUMOFSIGNALS], null_function;
- static boolean runexit = FALSE;
- X
- /* set signals to default values for rc. this means that interactive shells ignore SIGQUIT, etc. */
- X
- void inithandler() {
- X if (interactive) {
- #ifdef PROTECT_JOB
- X if (dashell) {
- X extern int ioctl(int, long,...);
- X
- X setpgrp(rc_pid, rc_pid);
- X ioctl(2, TIOCSPGRP, &rc_pid);
- X }
- #endif
- X
- X signal(SIGINT, sig);
- X if (!dashdee) {
- X signal(SIGQUIT, SIG_IGN);
- X handlers[SIGQUIT] = &null_function;
- X signal(SIGTERM, SIG_IGN);
- X handlers[SIGTERM] = &null_function;
- X }
- X }
- X null_function.type = BODY;
- X null_function.u[0].p = null_function.u[1].p = NULL;
- }
- X
- /* only run this in a child process! resets signals to their default values */
- X
- void setsigdefaults() {
- X int i;
- X
- X /*
- X General housekeeping: (setsigdefaults happens after fork(), so it's a convenient
- X place to clean up)
- X */
- X
- X interactive = FALSE;
- X if (histstr != NULL) { /* Close an open history file */
- X close(histfd);
- X histstr = NULL; /* But prevent re-closing of the same file-descriptor */
- X }
- X
- X /* Restore signals to SIG_DFL */
- X
- X for (i = 1; i < NUMOFSIGNALS; i++) { /* signal 0 is never used (bogus) */
- X if (handlers[i] != NULL) {
- X handlers[i] = NULL;
- X signal(i, SIG_DFL);
- X }
- X }
- X signal(SIGINT, SIG_DFL); /* sigint is special because its handler is normally */
- X /* set to NULL, which doesn't get caught in the above loop */
- X runexit = FALSE; /* No sigexit on subshells */
- }
- X
- /* rc's exit. if runexit is set, run the sigexit function. */
- X
- void rc_exit(int stat) {
- X static char *sigexit[2] = { "sigexit", NULL };
- X
- X if (runexit) {
- X runexit = FALSE;
- X funcall(sigexit);
- X exit(getstatus());
- X } else {
- X exit(stat);
- X }
- }
- X
- /* the signal handler for all functions. calls walk() */
- X
- static void fn_handler(int s) {
- X if (s < 0 || s >= NUMOFSIGNALS)
- X rc_error("unknown signal!?");
- X
- X signal(s, fn_handler); /* sgi seems to require re-signalling */
- X walk(handlers[s], TRUE);
- }
- X
- /*
- X assign a function in Node form. Check to see if the function is also a signal, and set the
- X signal vectors appropriately.
- */
- X
- void fnassign(char *name, Node *def) {
- X Node *newdef = treecpy(def == NULL ? &null_function : def, ealloc); /* important to do the treecopy first */
- X Function *new = get_fn_place(name);
- X int i;
- X
- X new->def = newdef;
- X new->extdef = NULL;
- X
- X if (strncmp(name, "sig", sizeof "sig" - 3) == 0) { /* slight optimization */
- #ifdef NOSIGCLD /* System V machines treat SIGCLD very specially */
- X if (streq(name, "sigcld"))
- X rc_error("can't trap SIGCLD");
- #endif
- X if (streq(name, "sigexit"))
- X runexit = TRUE;
- X for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
- X if (streq(signals[i][0], name)) {
- X if (newdef != NULL) {
- X handlers[i] = newdef;
- X signal(i, fn_handler);
- X } else {
- X handlers[i] = &null_function;
- X signal(i, SIG_IGN);
- X }
- X break;
- X }
- X }
- }
- X
- /* assign a function from the environment. store just the external representation */
- X
- void fnassign_string(char *extdef) {
- X char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
- X Function *new;
- X
- X if (name == NULL)
- X return;
- X
- X new = get_fn_place(name);
- X new->def = NULL;
- X new->extdef = ecpy(extdef);
- }
- X
- /* return a function in Node form, evaluating an entry from the environment if necessary */
- X
- Node *fnlookup(char *name) {
- X Function *look = lookup_fn(name);
- X Node *ret;
- X
- X if (look == NULL)
- X return NULL; /* not found */
- X if (look->def != NULL)
- X return look->def;
- X if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
- X return &null_function;
- X
- X ret = parse_fn(name, look->extdef);
- X
- X if (ret == NULL) {
- X efree(look->extdef);
- X look->extdef = NULL;
- X return &null_function;
- X } else {
- X return look->def = treecpy(ret, ealloc); /* Need to take it out of talloc space */
- X }
- }
- X
- /* return a function in string form (used by makeenv) */
- X
- char *fnlookup_string(char *name) {
- X Function *look = lookup_fn(name);
- X
- X if (look == NULL)
- X return NULL;
- X if (look->extdef != NULL)
- X return look->extdef;
- X return look->extdef = fun2str(name, look->def);
- }
- X
- /*
- X remove a function from the symbol table. If it also defines a signal handler, restore the signal handler
- X to its default value.
- */
- X
- void fnrm(char *name) {
- X int i;
- X
- X for (i = 1; i < NUMOFSIGNALS; i++) /* signal 0 unused */
- X if (streq(signals[i][0], name)) {
- X handlers[i] = NULL;
- X if (i == SIGINT)
- X signal(i, sig); /* restore default signal handler for rc */
- X else if ((i == SIGQUIT || i == SIGTERM) && !dashdee) {
- X handlers[i] = &null_function;
- X signal(i, SIG_IGN); /* ditto */
- X } else {
- X signal(i, SIG_DFL);
- X }
- X }
- X
- X if (streq(name, "sigexit"))
- X runexit = FALSE;
- X
- X delete_fn(name);
- }
- X
- void whatare_all_signals() {
- X int i;
- X
- X for (i = 1; i < NUMOFSIGNALS; i++)
- X if (*signals[i][0] != '\0')
- X if (handlers[i] == NULL)
- X fprint(1, "fn %s\n", signals[i][0]);
- X else
- X fprint(1, "fn %s {%s}\n", strprint(signals[i][0], FALSE, FALSE), ptree(handlers[i]));
- }
- X
- void prettyprint_fn(int fd, char *name, Node *n) {
- X fprint(fd, "fn %s {%s}\n", strprint(name, FALSE, FALSE), ptree(n));
- }
- SHAR_EOF
- chmod 0644 fn.c ||
- echo 'restore of fn.c failed'
- Wc_c="`wc -c < 'fn.c'`"
- test 5485 -eq "$Wc_c" ||
- echo 'fn.c: original size 5485, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= footobar.c ==============
- if test -f 'footobar.c' -a X"$1" != X"-c"; then
- echo 'x - skipping footobar.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting footobar.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'footobar.c' &&
- /*
- X footobar.c: a collection of functions to convert internal representations of
- X variables and functions to external representations, and vice versa
- */
- X
- #include "rc.h"
- #include "utils.h"
- #include "lex.h"
- #include "footobar.h"
- #include "nalloc.h"
- #include "input.h"
- #include "list.h"
- X
- #define FSCHAR '\1'
- #define FSSTRING "\1"
- X
- static char *getenvw(char *, boolean);
- static void funcat(char *);
- static void strtree(Node *);
- X
- static char *fun;
- static SIZE_T funsize, funpos;
- X
- #ifdef PROTECT_ENV
- /* octalize -- protect an exported name from brain-dead shells */
- X
- static char hexchar[] = "0123456789abcdef";
- X
- static char *octalize(char *name) {
- X int c;
- X static char namebuf[1000];
- X char *s = namebuf;
- X
- X while (1) {
- X c = *(unsigned char *) name++;
- X if (c == '\0') {
- X *s++ = '\0';
- X return namebuf;
- X }
- X if (!dnw[c] && c != '*') {
- X if (c != '_')
- X *s++ = c;
- X else if (*name != '_')
- X *s++ = c;
- X else
- X goto fallthrough;
- X } else {
- X fallthrough: *s++ = '_';
- X *s++ = '_';
- X *s++ = hexchar[(c >> 4) & 0xf];
- X *s++ = hexchar[c & 0xf];
- X }
- X }
- }
- #endif
- X
- /* a specialized strcat, used in strtree */
- X
- static void funcat(char *s) {
- X SIZE_T l = strlen(s);
- X char *new;
- X
- X if (l + funpos > funsize) {
- X new = nalloc(funsize *= 2);
- X memcpy(new, fun, funpos);
- X new[funpos] = 0;
- X fun = new;
- X }
- X strcpy(fun + funpos, s);
- X funpos += l;
- }
- X
- /* used to turn a function in Node * form into something we can export to the environment */
- X
- char *fun2str(char *name, Node *s) {
- #ifdef PROTECT_ENV
- X name = octalize(name);
- #endif
- X fun = nalloc(funsize = 512);
- X funpos = 0;
- X funcat("fn_");
- X funcat(name);
- X funcat("={");
- X strtree(s);
- X funcat("}");
- X return ecpy(fun); /* put into malloc space */
- }
- X
- /* ptree is used by whatis in order to print the definition of a function to the terminal */
- X
- char *ptree(Node *s) {
- X fun = nalloc(funsize = 512);
- X funpos = 0;
- X fun[0] = 0;
- X strtree(s);
- X return fun;
- }
- X
- /* save some code space by gathering this operation in a function */
- X
- static void catredir(int i) {
- X switch (i) {
- X case CREATE: funcat(">"); break;
- X case APPEND: funcat(">>"); break;
- X case HEREDOC: funcat("<<"); break;
- X case HERESTRING: funcat("<<<"); break;
- X case FROM: funcat("<"); break;
- X }
- }
- X
- /* convert a function in Node * form into something rc can parse (and humans can read?) */
- X
- static void strtree(Node *n) {
- X int defaultfd;
- X char b[16];
- X
- X if (n == NULL) {
- X funcat("()");
- X return;
- X }
- X
- X switch (n->type) {
- X case rDUP:
- X catredir(n->u[0].i);
- X if (n->u[2].i != -1)
- X sprint(b, "[%d=%d]", n->u[1].i, n->u[2].i);
- X else
- X sprint(b, "[%d=]", n->u[1].i);
- X funcat(b);
- X break;
- X case rWORD:
- X funcat(strprint(n->u[0].s, FALSE, FALSE));
- X break;
- X case QWORD:
- X funcat(strprint(n->u[0].s, TRUE, FALSE));
- X break;
- X case BACKQ:
- X if (n->u[0].p != NULL && n->u[0].p->type == VAR
- X && n->u[0].p->u[0].p != NULL && n->u[0].p->u[0].p->type == rWORD
- X && streq(n->u[0].p->u[0].p->u[0].s,"ifs")) {
- X funcat("`{");
- X } else {
- X funcat("``");
- X strtree(n->u[0].p);
- X funcat("{");
- X }
- X strtree(n->u[1].p);
- X funcat("}");
- X break;
- X case rBANG:
- X funcat("! ");
- X strtree(n->u[0].p);
- X break;
- X case rCASE:
- X funcat("case ");
- X strtree(n->u[0].p);
- X break;
- X case CBODY:
- X if (n->u[0].p != NULL) {
- X strtree(n->u[0].p);
- X funcat(";");
- X }
- X if (n->u[1].p != NULL)
- X strtree(n->u[1].p);
- X break;
- X case NOWAIT:
- X strtree(n->u[0].p);
- X funcat("&");
- X break;
- X case rCOUNT:
- X funcat("$#");
- X strtree(n->u[0].p);
- X break;
- X case rFLAT:
- X funcat("$^");
- X strtree(n->u[0].p);
- X break;
- X case RMFN:
- X funcat("fn ");
- X strtree(n->u[0].p);
- X break;
- X case rSUBSHELL:
- X funcat("@ ");
- X strtree(n->u[0].p);
- X break;
- X case VAR:
- X funcat("$");
- X strtree(n->u[0].p);
- X break;
- X case rANDAND:
- X strtree(n->u[0].p);
- X funcat("&&");
- X strtree(n->u[1].p);
- X break;
- X case ASSIGN:
- X strtree(n->u[0].p);
- X funcat("=");
- X strtree(n->u[1].p);
- X break;
- X case BODY:
- X if (n->u[1].p != NULL)
- X funcat("{");
- X strtree(n->u[0].p);
- X if (n->u[1].p != NULL) {
- X funcat(";");
- X strtree(n->u[1].p);
- X funcat("}");
- X }
- X break;
- X case BRACE:
- X funcat("{");
- X strtree(n->u[0].p);
- X funcat("}");
- X if (n->u[1].p != NULL)
- X strtree(n->u[1].p);
- X break;
- X case CONCAT:
- X strtree(n->u[0].p);
- X funcat("^");
- X strtree(n->u[1].p);
- X break;
- X case rELSE:
- X funcat("{");
- X strtree(n->u[0].p);
- X funcat("}else ");
- X strtree(n->u[1].p);
- X break;
- X case EPILOG:
- X case PRE:
- X strtree(n->u[0].p);
- X if (n->u[1].p != NULL) {
- X funcat(" ");
- X strtree(n->u[1].p);
- X }
- X break;
- X case NEWFN:
- X funcat("fn ");
- X strtree(n->u[0].p);
- X funcat(" {");
- X strtree(n->u[1].p);
- X funcat("}");
- X break;
- X case rIF:
- X funcat("if(");
- X strtree(n->u[0].p);
- X funcat(")");
- X strtree(n->u[1].p);
- X break;
- X case rOROR:
- X strtree(n->u[0].p);
- X funcat("||");
- X strtree(n->u[1].p);
- X break;
- X case ARGS:
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X break;
- X case rSWITCH:
- X funcat("switch(");
- X strtree(n->u[0].p);
- X funcat("){");
- X strtree(n->u[1].p);
- X funcat("}");
- X break;
- X case MATCH:
- X funcat("~ ");
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X break;
- X case VARSUB:
- X funcat("$");
- X strtree(n->u[0].p);
- X funcat("(");
- X strtree(n->u[1].p);
- X funcat(")");
- X break;
- X case rWHILE:
- X funcat("while(");
- X strtree(n->u[0].p);
- X funcat(")");
- X strtree(n->u[1].p);
- X break;
- X case LAPPEND:
- X funcat("(");
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X funcat(")");
- X break;
- X case FORIN:
- X funcat("for(");
- X strtree(n->u[0].p);
- X funcat(" in ");
- X strtree(n->u[1].p);
- X funcat(")");
- X strtree(n->u[2].p);
- X break;
- X case rPIPE:
- X funcat("{");
- X strtree(n->u[2].p);
- X if (n->u[0].i == 1) {
- X if (n->u[1].i == 0)
- X sprint(b, "}|{");
- X else
- X sprint(b, "}|[1=%d]{", n->u[1].p);
- X } else {
- X if (n->u[1].i == 0)
- X sprint(b, "}|[%d]{", n->u[0].p);
- X else
- X sprint(b, "}|[%d=%d]{", n->u[0].i, n->u[1].i);
- X }
- X funcat(b);
- X strtree(n->u[3].p);
- X funcat("}");
- X break;
- X case NMPIPE:
- X defaultfd = (n->u[0].i == CREATE || n->u[0].i == APPEND);
- X catredir(n->u[0].i);
- X if (n->u[1].i != defaultfd) {
- X sprint(b, "[%d]{", n->u[1].i);
- X funcat(b);
- X } else
- X funcat("{");
- X strtree(n->u[2].p);
- X funcat("}");
- X break;
- X case rREDIR:
- X defaultfd = (n->u[0].i == CREATE || n->u[0].i == APPEND);
- X catredir(n->u[0].i);
- X if (n->u[1].i != defaultfd) {
- X sprint(b, "[%d]", n->u[1].i);
- X funcat(b);
- X }
- X strtree(n->u[2].p);
- X break;
- X }
- }
- X
- /* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
- X
- char *list2str(char *name, List *s) {
- X SIZE_T size;
- X List *t;
- X char *w;
- X
- #ifdef PROTECT_ENV
- X name = octalize(name);
- #endif
- X size = strlen(name) + listlen(s);
- X
- X w = ealloc(size + 2);
- X t = s;
- X strcpy(w, name);
- X strcat(w, "=");
- X strcat(w, t->w);
- X for (s = s->n; s != NULL; s = s->n) {
- X strcat(w, FSSTRING);
- X strcat(w, s->w);
- X }
- X return w;
- }
- X
- /* convert a List to an array, for execve() */
- X
- char **list2array(List *s, boolean print) {
- X char **av;
- X int i;
- X
- X /* 4 == 1 for the null terminator + 2 for the fake execve() + 1 for defaulting to sh */
- X
- X av = nalloc((listnel(s) + 4) * sizeof (char *));
- X
- X av += 3; /* hide the two free spots from rc (two for #! emulation, one for defaulting to sh) */
- X
- X if (print)
- X fprint(2, "%l\n", s);
- X
- X for (i = 0; s != NULL; i++) {
- X av[i] = s->w;
- X s = s->n;
- X }
- X av[i] = NULL;
- X return av;
- }
- X
- /* figure out the name of a variable given an environment string. copy this into malloc space */
- X
- char *get_name(char *s) {
- X int c;
- X SIZE_T i;
- X char *r, *namebuf;
- #ifdef PROTECT_ENV
- X char *h1, *h2;
- #endif
- X
- X for (i = 0; s[i] != '\0' && s[i] != '='; i++)
- X ;
- X
- X if (s[i] == '\0')
- X return NULL;
- X
- X r = namebuf = ealloc(i + 1);
- X
- X while (1)
- X switch (c = *s++) {
- X case '=':
- X *r++ = '\0';
- X return namebuf;
- #ifdef PROTECT_ENV
- X case '_':
- X if (*s == '_' && (h1 = strchr(hexchar, s[1])) != NULL && (h2 = strchr(hexchar, s[2])) != NULL) {
- X *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar);
- X s += 3;
- X break;
- X }
- X /* FALLTHROUGH */
- #endif
- X default:
- X *r++ = c;
- X break;
- X }
- }
- X
- /* get the next word from a variable's value as represented in the environment. */
- X
- static char *getenvw(char *s, boolean saw_alpha) {
- X char *r;
- X SIZE_T i,j;
- X
- X for (i = j = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
- X ;
- X
- X if (i == 0)
- X if(s[i] == '\0' && !saw_alpha)
- X return NULL;
- X else {
- X r = enew(char);
- X *r = '\0';
- X return r;
- X }
- X
- X r = ealloc(i + j + 1);
- X
- X r[i + j] = '\0';
- X
- X while (i > 0) {
- X --i;
- X r[i + j] = s[i];
- X }
- X return r;
- }
- X
- /* take an environment entry for a variable (elements ^A separated) and turn it into a List */
- X
- List *parse_var(char *name, char *extdef) {
- X List *r, *top;
- X char *f;
- X boolean saw_alpha;
- X
- X top = r = enew(List);
- X extdef = strchr(extdef, '=') + 1;
- X
- X
- X if ((f = getenvw(extdef, FALSE)) == NULL)
- X return NULL;
- X
- X while (1) {
- X r->w = f;
- X r->m = NULL;
- X extdef += strlen(f);
- X if (*extdef == FSCHAR) {
- X extdef++;
- X saw_alpha = TRUE;
- X } else {
- X saw_alpha = FALSE;
- X }
- X if ((f = getenvw(extdef, saw_alpha)) == NULL) {
- X r->n = NULL;
- X break;
- X }
- X r = r->n = enew(List);
- X }
- X return top;
- }
- X
- /* get an environment entry for a function and have rc parse it. */
- X
- Node *parse_fn(char *name, char *extdef) {
- X Node *def;
- X int i;
- X char *s, old[4];
- X
- X s = strchr(extdef, '=');
- X
- X if (s == NULL)
- X return NULL;
- X
- X s -= 3;
- X
- X for (i = 0; i < 4; i++)
- X old[i] = s[i];
- X s[0] = 'f';
- X s[1] = 'n';
- X s[2] = ' ';
- X s[3] = 'x';
- X
- X def = parseline(s);
- X for (i = 0; i < 4; i++)
- X s[i] = old[i];
- X
- X if (def == NULL || def->type != NEWFN)
- X return NULL;
- X else
- X return def->u[1].p;
- }
- SHAR_EOF
- chmod 0644 footobar.c ||
- echo 'restore of footobar.c failed'
- Wc_c="`wc -c < 'footobar.c'`"
- test 9420 -eq "$Wc_c" ||
- echo 'footobar.c: original size 9420, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= footobar.h ==============
- if test -f 'footobar.h' -a X"$1" != X"-c"; then
- echo 'x - skipping footobar.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting footobar.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'footobar.h' &&
- extern char *fun2str(char *, Node *);
- extern char *ptree(Node *);
- extern char *list2str(char *, List *);
- extern char **list2array(List *, boolean);
- extern char *get_name(char *);
- extern List *parse_var(char *, char *);
- extern Node *parse_fn(char *, char *);
- SHAR_EOF
- chmod 0644 footobar.h ||
- echo 'restore of footobar.h failed'
- Wc_c="`wc -c < 'footobar.h'`"
- test 258 -eq "$Wc_c" ||
- echo 'footobar.h: original size 258, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= getopt.c ==============
- if test -f 'getopt.c' -a X"$1" != X"-c"; then
- echo 'x - skipping getopt.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting getopt.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'getopt.c' &&
- /* getopt routine courtesy of David Sanderson */
- #include "rc.h"
- #include "utils.h"
- #include "getopt.h"
- X
- int opterr = 1;
- int optind = 1;
- int optopt;
- char *optarg;
- X
- int getopt(int argc, char **argv, char *opts) {
- X static int sp = 1;
- X int c;
- X char *cp;
- X
- X if (optind == 0) /* reset getopt() */
- X optind = sp = 1;
- X
- X if (sp == 1)
- X if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') {
- X return -1;
- X } else if (strcmp(argv[optind], "--") == 0) {
- X optind++;
- X return -1;
- X }
- X optopt = c = argv[optind][sp];
- X if (c == ':' || (cp=strchr(opts, c)) == 0) {
- X fprint(2, "%s: illegal option -- %c\n", argv[0], c);
- X if (argv[optind][++sp] == '\0') {
- X optind++;
- X sp = 1;
- X }
- X return '?';
- X }
- X if (*++cp == ':') {
- X if(argv[optind][sp+1] != '\0') {
- X optarg = &argv[optind++][sp+1];
- X } else if(++optind >= argc) {
- X fprint(2, "%s: option requires an argument -- %c\n", argv[0], c);
- X sp = 1;
- X return '?';
- X } else
- X optarg = argv[optind++];
- X sp = 1;
- X } else {
- X if (argv[optind][++sp] == '\0') {
- X sp = 1;
- X optind++;
- X }
- X optarg = 0;
- X }
- X return c;
- }
- SHAR_EOF
- chmod 0644 getopt.c ||
- echo 'restore of getopt.c failed'
- Wc_c="`wc -c < 'getopt.c'`"
- test 1619 -eq "$Wc_c" ||
- echo 'getopt.c: original size 1619, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= getopt.h ==============
- if test -f 'getopt.h' -a X"$1" != X"-c"; then
- echo 'x - skipping getopt.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting getopt.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'getopt.h' &&
- extern int getopt(int, char **, char *);
- X
- extern int optind, opterr, optopt;
- extern char *optarg;
- SHAR_EOF
- chmod 0644 getopt.h ||
- echo 'restore of getopt.h failed'
- Wc_c="`wc -c < 'getopt.h'`"
- test 98 -eq "$Wc_c" ||
- echo 'getopt.h: original size 98, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= glob.c ==============
- if test -f 'glob.c' -a X"$1" != X"-c"; then
- echo 'x - skipping glob.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting glob.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'glob.c' &&
- /* glob.c: rc's (ugly) globber. This code is not elegant, but it works */
- X
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "rc.h"
- #include "glob.h"
- #include "glom.h"
- #include "nalloc.h"
- #include "utils.h"
- #include "match.h"
- #include "footobar.h"
- #include "list.h"
- #ifdef NODIRENT
- #include <sys/dir.h>
- #define dirent direct /* need to get the struct declaraction right */
- #else
- #include <dirent.h>
- #endif
- X
- static List *dmatch(char *, char *, char *);
- static List *doglob(char *, char *);
- static List *lglob(List *, char *, char *, SIZE_T);
- static List *sort(List *);
- X
- /*
- X matches a list of words s against a list of patterns p. Returns true iff
- X a pattern in p matches a word in s. null matches null, but otherwise null
- X patterns match nothing.
- */
- X
- boolean lmatch(List *s, List *p) {
- X List *q;
- X int i;
- X boolean okay;
- X
- X if (s == NULL) {
- X if (p == NULL) /* null matches null */
- X return TRUE;
- X for (; p != NULL; p = p->n) { /* one or more stars match null */
- X if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */
- X okay = TRUE;
- X for (i = 0; p->w[i] != '\0'; i++)
- X if (p->w[i] != '*' || p->m[i] != 1) {
- X okay = FALSE;
- X break;
- X }
- X if (okay)
- X return TRUE;
- X }
- X }
- X return FALSE;
- X }
- X
- X for (; s != NULL; s = s->n)
- X for (q = p; q != NULL; q = q->n)
- X if (match(q->w, q->m, s->w))
- X return TRUE;
- X return FALSE;
- }
- X
- /* Matches a pattern p against the contents of directory d */
- X
- static List *dmatch(char *d, char *p, char *m) {
- X boolean matched = FALSE;
- X List *top, *r;
- X DIR *dirp;
- X struct dirent *dp;
- X struct stat s;
- X /* prototypes for XXXdir functions. comment out if necessary */
- X extern DIR *opendir(const char *);
- X extern struct dirent *readdir(DIR *);
- X extern int closedir(DIR *);
- X
- X /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
- X if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR)
- X return NULL;
- X if ((dirp = opendir(d)) == NULL)
- X return NULL;
- X
- X top = r = NULL;
- X
- X while ((dp = readdir(dirp)) != NULL)
- X if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
- X matched = TRUE;
- X if (top == NULL)
- X top = r = nnew(List);
- X else
- X r = r->n = nnew(List);
- X r->w = ncpy(dp->d_name);
- X r->m = NULL;
- X }
- X
- X closedir(dirp);
- X
- X if (!matched)
- X return NULL;
- X
- X r->n = NULL;
- X return top;
- }
- X
- /*
- X lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*"
- X will return a list with all the files in /tmp, /usr, and /bin. NULL on no match.
- X slashcount indicates the number of slashes to stick between the directory and the
- X matched name. e.g., for matching ////tmp/////foo*
- */
- X
- static List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
- X List *q, *r, *top, foo;
- X static List slash;
- X static SIZE_T slashsize = 0;
- X
- X if (slashcount + 1 > slashsize) {
- X slash.w = ealloc(slashcount + 1);
- X slashsize = slashcount;
- X }
- X slash.w[slashcount] = '\0';
- X while (slashcount > 0)
- X slash.w[--slashcount] = '/';
- X
- X for (top = r = NULL; s != NULL; s = s->n) {
- X q = dmatch(s->w, p, m);
- X if (q != NULL) {
- X foo.w = s->w;
- X foo.m = NULL;
- X foo.n = NULL;
- X if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
- X q = concat(&slash, q); /* dir/name with slash */
- X q = concat(&foo, q);
- X if (r == NULL)
- X top = r = q;
- X else
- X r->n = q;
- X while (r->n != NULL)
- X r = r->n;
- X }
- X }
- X return top;
- }
- X
- /*
- X Doglob globs a pathname in pattern form against a unix path. Returns the original
- X pattern (cleaned of metacharacters) on failure, or the globbed string(s).
- */
- X
- static List *doglob(char *w, char *m) {
- X static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
- X static SIZE_T dsize = 0;
- X char *d, *p, *md, *mp;
- X SIZE_T psize;
- X char *s = w;
- X List firstdir;
- X List *matched;
- X int slashcount;
- X
- X if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
- X efree(dir); efree(pattern); efree(metadir); efree(metapattern);
- X dir = ealloc(psize);
- X pattern = ealloc(psize);
- X metadir = ealloc(psize);
- X metapattern = ealloc(psize);
- X dsize = psize;
- X }
- X
- X d = dir;
- X p = pattern;
- X md = metadir;
- X mp = metapattern;
- X
- X if (*s == '/') {
- X while (*s == '/')
- X *d++ = *s++, *md++ = *m++;
- X } else {
- X while (*s != '/' && *s != '\0')
- X *d++ = *s++, *md++ = *m++; /* get first directory component */
- X }
- X *d = '\0';
- X
- X /*
- X Special case: no slashes in the pattern, i.e., open the current directory.
- X Remember that w cannot consist of slashes alone (the other way *s could be
- X zero) since doglob gets called iff there's a metacharacter to be matched
- X */
- X if (*s == '\0') {
- X matched = dmatch(".", dir, metadir);
- X goto end;
- X }
- X
- X if (*w == '/') {
- X firstdir.w = dir;
- X firstdir.m = metadir;
- X firstdir.n = NULL;
- X matched = &firstdir;
- X } else {
- X /*
- X we must glob against current directory,
- X since the first character is not a slash.
- X */
- X matched = dmatch(".", dir, metadir);
- X }
- X
- X do {
- X for (slashcount = 0; *s == '/'; s++, m++)
- X slashcount++; /* skip slashes */
- X
- X while (*s != '/' && *s != '\0')
- X *p++ = *s++, *mp++ = *m++; /* get pattern */
- X *p = '\0';
- X
- X matched = lglob(matched, pattern, metapattern, slashcount);
- X
- X p = pattern, mp = metapattern;
- X } while (*s != '\0');
- X
- end: if (matched == NULL) {
- X matched = nnew(List);
- X matched->w = w;
- X matched->m = NULL;
- X matched->n = NULL;
- X }
- X return matched;
- }
- X
- /*
- X Globs a list; checks to see if each element in the list has a metacharacter. If it
- X does, it is globbed, and the output is sorted.
- */
- X
- List *glob(List *s) {
- X List *top, *r;
- X boolean meta;
- X
- X for (r = s, meta = FALSE; r != NULL; r = r->n)
- X if (r->m != NULL)
- X meta = TRUE;
- X
- X if (!meta)
- X return s; /* don't copy lists with no metacharacters in them */
- X
- X for (top = r = NULL; s != NULL; s = s->n) {
- X if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
- X if (top == NULL) {
- X top = r = nnew(List);
- X } else {
- X r->n = nnew(List);
- X r = r->n;
- X }
- X r->w = s->w;
- X } else {
- X if (top == NULL)
- X top = r = sort(doglob(s->w, s->m));
- X else
- X r->n = sort(doglob(s->w, s->m));
- X while (r->n != NULL)
- X r = r->n;
- X }
- X }
- X
- X r->n = NULL;
- X return top;
- }
- X
- static List *sort(List *s) {
- X SIZE_T nel = listnel(s);
- X
- X if (nel > 1) {
- X char **a;
- X List *t;
- X
- X qsort(a = list2array(s, FALSE), nel, sizeof(char *), starstrcmp);
- X
- X for (t = s; t != NULL; t = t->n)
- X t->w = *a++;
- X }
- X
- X return s;
- }
- SHAR_EOF
- chmod 0644 glob.c ||
- echo 'restore of glob.c failed'
- Wc_c="`wc -c < 'glob.c'`"
- test 6378 -eq "$Wc_c" ||
- echo 'glob.c: original size 6378, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= glob.h ==============
- if test -f 'glob.h' -a X"$1" != X"-c"; then
- echo 'x - skipping glob.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting glob.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'glob.h' &&
- extern boolean lmatch(List *, List *);
- extern List *glob(List *);
- SHAR_EOF
- chmod 0644 glob.h ||
- echo 'restore of glob.h failed'
- Wc_c="`wc -c < 'glob.h'`"
- test 66 -eq "$Wc_c" ||
- echo 'glob.h: original size 66, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= glom.c ==============
- if test -f 'glom.c' -a X"$1" != X"-c"; then
- echo 'x - skipping glom.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting glom.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'glom.c' &&
- /* glom.c: builds an argument list out of words, variables, etc. */
- X
- #include <sys/types.h>
- #include <sys/stat.h>
- #ifndef S_IFIFO
- #ifndef DEVFD
- #define NOCMDARG
- #endif
- #endif
- #include "rc.h"
- #include "utils.h"
- #include "nalloc.h"
- #include "glom.h"
- #include "hash.h"
- #include "walk.h"
- #include "status.h"
- #include "exec.h"
- #include "lex.h"
- #include "open.h"
- #include "list.h"
- #include "wait.h"
- X
- static List *backq(Node *, Node *);
- static List *bqinput(List *, int);
- static List *count(List *);
- static List *mkcmdarg(Node *);
- X
- Rq *redirq = NULL;
- Fq *fifoq = NULL;
- X
- List *word(char *w, char *m) {
- X List *s;
- X
- X if (w == NULL)
- X return NULL;
- X
- X s = nnew(List);
- X s->w = w;
- X s->m = m;
- X s->n = NULL;
- X return s;
- }
- X
- /*
- X Append list s2 to list s1 by copying s1 and making the new copy
- X point at s2.
- */
- X
- List *append(List *s1, List *s2) {
- X List *r, *top;
- X
- X if (s1 == NULL)
- X return s2;
- X if (s2 == NULL)
- X return s1;
- X
- X r = top = nnew(List);
- X while (1) {
- X r->w = s1->w;
- X r->m = s1->m;
- X if ((s1 = s1->n) == NULL)
- X break;
- X r = r->n = nnew(List);
- X }
- X
- X r->n = s2;
- X
- X return top;
- }
- X
- List *concat(List *s1, List *s2) {
- X int n1, n2;
- X SIZE_T y,z;
- X List *n, *s;
- X
- X if (s1 == NULL)
- X return s2;
- X if (s2 == NULL)
- X return s1;
- X
- X n1 = listnel(s1);
- X n2 = listnel(s2);
- X
- X if (n1 != n2 && n1 != 1 && n2 != 1)
- X rc_error("bad concatenation");
- X
- X n = s = nnew(List);
- X
- X while (1) {
- X z = strlen(s1->w) + strlen(s2->w) + 1;
- X n->w = nalloc(z);
- X strcpy(n->w,s1->w);
- X strcat(n->w,s2->w);
- X if (s1->m == NULL && s2->m == NULL) {
- X n->m = NULL;
- X } else {
- X n->m = nalloc(z);
- X y = strlen(s1->w);
- X if (s1->m == NULL)
- X clear(n->m, y);
- X else
- X memcpy(n->m, s1->m, y);
- X if (s2->m == NULL)
- X clear(n->m + y, strlen(s2->w));
- X else
- X memcpy(n->m + y, s2->m, strlen(s2->w));
- X n->m[z] = 0;
- X }
- X if (n1 > 1)
- X s1 = s1->n;
- X if (n2 > 1)
- X s2 = s2->n;
- X if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1)) {
- X n->n = NULL;
- X return s;
- X }
- X n->n = nnew(List);
- X n = n->n;
- X }
- }
- X
- List *varsub(List *v, List *subs) {
- X int i,j;
- X int n;
- X List *r,*s;
- X List *top,*cat;
- X
- X n = listnel(v);
- X
- X top = cat = NULL;
- X
- X for (s = subs; s != NULL; s = s->n) {
- X i = a2u(s->w);
- X if (i < 1)
- X rc_error("bad subscript");
- X if (i <= n) {
- X for (j = 1, r = v; j != i; j++, r = r->n)
- X ; /* loop until r == v(i) */
- X if (top == NULL) {
- X top = cat = nnew(List);
- X } else {
- X cat->n = nnew(List);
- X cat = cat->n;
- X }
- X cat->w = r->w;
- X cat->m = r->m;
- X }
- X }
- X
- X if (top == NULL)
- X return NULL;
- X
- X cat->n = NULL;
- X return top;
- }
- X
- List *flatten(List *s) {
- X List *r;
- X
- X if (s == NULL || s->n == NULL)
- X return s;
- X
- X r = nnew(List);
- X r->w = nalloc(listlen(s) + 1);
- X r->m = NULL; /* flattened lists come from variables, so no meta */
- X r->n = NULL;
- X
- X strcpy(r->w, s->w);
- X
- X do {
- X s = s->n;
- X strcat(r->w, " ");
- X strcat(r->w, s->w);
- X } while (s->n != NULL);
- X
- X return r;
- }
- X
- static List *count(List *l) {
- X List *s = nnew(List);
- X char buf[16];
- X
- X s->w = sprint(buf, "%d", listnel(l));
- X s->w = ncpy(s->w);
- X s->n = NULL;
- X s->m = NULL;
- X return s;
- }
- X
- void assign(List *s1, List *s2, boolean stack) {
- X List *val = s2;
- X
- X if (s1 == NULL)
- X rc_error("null variable name");
- X if (s1->n != NULL)
- X rc_error("multi-word variable name");
- X if (*s1->w == '\0')
- X rc_error("zero-length variable name");
- X if (a2u(s1->w) != -1)
- X rc_error("numeric variable name");
- X if (strchr(s1->w, '=') != NULL)
- X rc_error("'=' in variable name");
- X if (s1->w[0] == '*' && s1->w[1] == '\0')
- X val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
- X
- X
- X if (s2 != NULL || stack) {
- X if (dashex)
- X prettyprint_var(2, s1->w, val);
- X varassign(s1->w, val, stack);
- X alias(s1->w, val, stack);
- X } else {
- X if (dashex)
- X prettyprint_var(2, s1->w, NULL);
- X varrm(s1->w, stack);
- X }
- }
- X
- /*
- X The following two functions are by the courtesy of Paul Haahr,
- X who could not stand the incompetence of my own backquote implementation.
- */
- X
- #define BUFSIZE ((SIZE_T) 1000)
- X
- static List *bqinput(List *ifs, int fd) {
- X char *end, *bufend, *s;
- X List *r, *top, *prev;
- X SIZE_T remain, bufsize;
- X char isifs[256];
- X int n;
- X int state; /* a simple FSA is used to read in data */
- X
- X clear(isifs, sizeof isifs);
- X isifs['\0'] = 1;
- X for (r = ifs; r != NULL; r = r->n)
- X for (s = r->w; *s != '\0'; s++)
- X isifs[*(unsigned char *)s] = 1;
- X
- X remain = bufsize = BUFSIZE;
- X top = r = nnew(List);
- X r->w = end = nalloc(bufsize + 1);
- X r->m = NULL;
- X state = 0;
- X prev = NULL;
- X
- X while (1) {
- X if (remain == 0) { /* is the string bigger than the buffer? */
- X SIZE_T m = end - r->w;
- X char *buf;
- X
- X while (bufsize < m + BUFSIZE)
- X bufsize *= 2;
- X buf = nalloc(bufsize + 1);
- X memcpy(buf, r->w, m);
- X r->w = buf;
- X end = &buf[m];
- X remain = bufsize - m;
- X }
- X
- X n = read(fd, end, remain);
- X
- X if (n <= 0) {
- X if (n == -1) {
- X uerror("backquote read");
- X rc_error(NULL);
- X }
- X /* break */ break;
- X }
- X
- X remain -= n;
- X
- X for (bufend = &end[n]; end < bufend; end++)
- X switch (state) {
- X case 0:
- X if (!isifs[*(unsigned char *)end]) {
- X state = 1;
- X r->w = end;
- X }
- X break;
- X case 1:
- X if (isifs[*(unsigned char *)end]) {
- X state = 0;
- X *end = '\0';
- X prev = r;
- X r = r->n = nnew(List);
- X r->w = end+1;
- X r->m = NULL;
- X }
- X break;
- X }
- X }
- X
- X if (state == 1) { /* terminate last string */
- X *end = '\0';
- X r->n = NULL;
- X } else {
- X if (prev == NULL) /* no input at all? */
- X top = NULL;
- X else
- X prev->n = NULL; /* else terminate list */
- X }
- X
- X return top;
- }
- X
- static List *backq(Node *ifsnode, Node *n) {
- X int p[2], pid, sp;
- X List *result, *ifs;
- X
- X if (n == NULL)
- X return NULL;
- X
- X if (pipe(p) < 0) {
- X uerror("pipe");
- X rc_error(NULL);
- X }
- X
- X if ((pid = rc_fork()) == 0) {
- X setsigdefaults();
- X dup2(p[1],1);
- X close(p[0]);
- X close(p[1]);
- X redirq = NULL;
- X fifoq = NULL;
- X walk(n, FALSE);
- X exit(getstatus());
- X }
- X
- X ifs = glom(ifsnode);
- X close(p[1]);
- X result = bqinput(ifs, p[0]);
- X close(p[0]);
- X rc_wait4(pid, &sp);
- X statprint(sp);
- X return result;
- }
- X
- void qredir(Node *n) {
- X Rq *next;
- X
- X if (redirq == NULL) {
- X next = redirq = nnew(Rq);
- X } else {
- X for (next = redirq; next->n != NULL; next = next->n)
- X ;
- X next->n = nnew(Rq);
- X next = next->n;
- X }
- X
- X next->r = n;
- X next->n = NULL;
- }
- X
- #ifdef NOCMDARG
- static List *mkcmdarg(Node *n) {
- X rc_error("named pipes are not supported");
- X return NULL;
- }
- #else
- #ifndef DEVFD
- static List *mkcmdarg(Node *n) {
- X int fd, pid;
- X char *name, buf[32];
- X List *ret = nnew(List);
- X Fq *f = nnew(Fq);
- X static int fifonumber = 0;
- X
- X name = sprint(buf,"/tmp/rc%d.%d", getpid(), fifonumber++);
- X name = ncpy(name);
- X
- X if (mknod(name, S_IFIFO | 0644, 0) < 0) {
- X uerror("mknod");
- X return NULL;
- X }
- X
- X if ((pid = rc_fork()) == 0) {
- X setsigdefaults();
- X /* fd = rc_open(name, CREATE); */
- X fd = rc_open(name, (n->u[0].i != FROM) ? FROM : CREATE); /* stupid hack */
- X if (fd < 0) {
- X uerror("open");
- X exit(1);
- X }
- X if (dup2(fd, (n->u[0].i == FROM)) < 0) { /* same stupid hack */
- X uerror("dup2");
- X exit(1);
- X }
- X close(fd);
- X redirq = NULL;
- X fifoq = NULL;
- X walk(n->u[2].p, FALSE);
- X exit(getstatus());
- X }
- X
- X f->pid = pid;
- X f->name = name;
- X f->n = fifoq;
- X fifoq = f;
- X
- X ret->w = name;
- X ret->m = NULL;
- X ret->n = NULL;
- X
- X return ret;
- }
- #else
- static List *mkcmdarg(Node *n) {
- X char *name, buf[32];
- X List *ret = nnew(List);
- X int p[2];
- X
- X if (pipe(p) < 0) {
- X uerror("pipe");
- X return NULL;
- X }
- X
- X if (rc_fork() == 0) {
- X setsigdefaults();
- X
- X if (dup2(p[n->u[0].i == FROM], n->u[0].i == FROM) < 0) { /* stupid hack */
- X uerror("dup2");
- X exit(1);
- X }
- X close(p[n->u[0].i != FROM]);
- X
- X redirq = NULL;
- X walk(n->u[2].p, FALSE);
- X exit(getstatus());
- X }
- X
- X name = sprint(buf, "/dev/fd/%d", p[n->u[0].i != FROM]);
- X name = ncpy(name); /* ncpy evaluates the expression twice */
- X ret->w = name;
- X ret->m = NULL;
- X ret->n = NULL;
- X
- X close(p[n->u[0].i == FROM]);
- X
- X return ret;
- }
- #endif /* DEVFD */
- #endif /* !NOCMDARG */
- X
- List *glom(Node *n) {
- X Node *words;
- X List *v, *first, *last;
- X boolean dollarstar;
- X
- X if (n == NULL)
- X return NULL;
- X
- X switch (n->type) {
- X case ARGS:
- X case LAPPEND:
- X words = n->u[0].p;
- X last = NULL;
- X while (words != NULL && (words->type == ARGS || words->type == LAPPEND)) {
- X if (words->u[1].p != NULL && words->u[1].p->type != rWORD && words->u[1].p->type != QWORD)
- X break;
- X first = glom(words->u[1].p);
- X if (first != NULL) {
- X first->n = last;
- X last = first;
- X }
- X words = words->u[0].p;
- X }
- X v = append(glom(words), last); /* force left to right evaluation */
- X return append(v, glom(n->u[1].p));
- X case BACKQ:
- X return backq(n->u[0].p,n->u[1].p);
- X case CONCAT:
- X first = glom(n->u[0].p); /* force left-to-right evaluation */
- X return concat(first, glom(n->u[1].p));
- X case rDUP:
- X case rREDIR:
- X qredir(n);
- X return NULL;
- X case rWORD: case QWORD:
- X return word(n->u[0].s,n->u[1].s);
- X case NMPIPE:
- X return mkcmdarg(n);
- X default:
- X break;
- X }
- X
- X /*
- X the next three operations depend on the left-child of glom
- X to be a variable name. Therefore they are all treated here.
- X (previously each function looked up and checked the validity
- X of a variable name)
- X */
- X
- X v = glom(n->u[0].p);
- X if (v == NULL)
- X rc_error("null variable name");
- X if (v->n != NULL)
- X rc_error("multi-word variable name");
- X if (*v->w == '\0')
- X rc_error("zero-length variable name");
- X
- X dollarstar = (v->w[0] == '*' && v->w[1] == '\0');
- X v = varlookup(v->w);
- X if (dollarstar)
- X v = v->n;
- X
- X switch (n->type) {
- X default:
- X fprint(2,"glom: this can't happen\n");
- X exit(1);
- X /* NOTREACHED */
- X case rCOUNT:
- X return count(v);
- X case rFLAT:
- X return flatten(v);
- X case VAR:
- X return v;
- X case VARSUB:
- X return varsub(v, glom(n->u[1].p));
- X }
- X
- }
- SHAR_EOF
- chmod 0644 glom.c ||
- echo 'restore of glom.c failed'
- Wc_c="`wc -c < 'glom.c'`"
- test 9512 -eq "$Wc_c" ||
- echo 'glom.c: original size 9512, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= glom.h ==============
- if test -f 'glom.h' -a X"$1" != X"-c"; then
- echo 'x - skipping glom.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting glom.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'glom.h' &&
- extern void assign(List *, List *, boolean);
- extern void qredir(Node *);
- extern List *append(List *, List*);
- extern List *flatten(List *);
- extern List *glom(Node *);
- extern List *concat(List *, List *);
- extern List *varsub(List *, List *);
- extern List *word(char *, char *);
- X
- struct Fq {
- X int pid;
- X char *name;
- X Fq *n;
- };
- SHAR_EOF
- chmod 0644 glom.h ||
- echo 'restore of glom.h failed'
- Wc_c="`wc -c < 'glom.h'`"
- test 322 -eq "$Wc_c" ||
- echo 'glom.h: original size 322, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= hash.c ==============
- if test -f 'hash.c' -a X"$1" != X"-c"; then
- echo 'x - skipping hash.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting hash.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'hash.c' &&
- /* hash.c: hash table support for functions and variables. */
- X
- /*
- X functions and variables are cached in both internal and external
- X form for performance. Thus a variable which is never "dereferenced"
- X with a $ is passed on to rc's children untouched. This is not so
- X important for variables, but is a big win for functions, where a call
- X to yyparse() is involved.
- */
- X
- #include "rc.h"
- #include "utils.h"
- #include "hash.h"
- #include "list.h"
- #include "tree.h"
- #include "footobar.h"
- #include "sigmsgs.h"
- X
- static boolean var_exportable(char *);
- static boolean fn_exportable(char *);
- static int hash(char *, int);
- static int find(char *, Htab *, int);
- static void free_fn(Function *);
- X
- Htab *fp;
- Htab *vp;
- static int fused, fsize, vused, vsize;
- static char **env;
- static int bozosize;
- static int envsize;
- static boolean env_dirty = TRUE;
- static char *dead = "";
- X
- #define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
- X
- void inithash() {
- X int i;
- X Htab *fpp, *vpp;
- X
- X fp = ealloc(sizeof(Htab) * HASHSIZE);
- X vp = ealloc(sizeof(Htab) * HASHSIZE);
- X fused = vused = 0;
- X fsize = vsize = HASHSIZE;
- X
- X for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++)
- X vpp->name = fpp->name = NULL;
- }
- X
- #define ADV() {if ((c = *s++) == '\0') break;}
- X
- /* hash function courtesy of paul haahr */
- X
- static int hash(char *s, int size) {
- X int n = 0;
- X int c;
- X
- X while (1) {
- X ADV();
- X n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
- X ADV();
- X n ^= (c << 14) + (c << 7) + (c << 4) + c;
- X ADV();
- X n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
- X ADV();
- X n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
- X }
- X
- X if (n < 0)
- X n = ~n;
- X
- X return n & (size - 1); /* need power of 2 size */
- }
- X
- static boolean rehash(Htab *ht) {
- X int i,j,size;
- X int newsize,newused;
- X Htab *newhtab;
- X
- X if (ht == fp) {
- X if (fsize > 2 * fused)
- X return FALSE;
- X size = fsize;
- X } else {
- X if (vsize > 2 * vused)
- X return FALSE;
- X size = vsize;
- X }
- X
- X
- X newsize = 2 * size;
- X newhtab = ealloc(newsize * sizeof(Htab));
- X for (i = 0; i < newsize; i++)
- X newhtab[i].name = NULL;
- X
- X for (i = newused = 0; i < size; i++)
- X if (ht[i].name != NULL && ht[i].name != dead) {
- X newused++;
- X j = hash(ht[i].name, newsize);
- X while (newhtab[j].name != NULL) {
- X j++;
- X j &= (newsize - 1);
- X }
- X newhtab[j].name = ht[i].name;
- X newhtab[j].p = ht[i].p;
- X }
- X
- X if (ht == fp) {
- X fused = newused;
- X fp = newhtab;
- X fsize = newsize;
- X } else {
- X vused = newused;
- X vp = newhtab;
- X vsize = newsize;
- X }
- X
- X efree(ht);
- X return TRUE;
- }
- X
- #define varfind(s) find(s,vp,vsize)
- #define fnfind(s) find(s,fp,fsize)
- X
- static int find(char *s, Htab *ht, int size) {
- X int h = hash(s, size);
- X
- X while (ht[h].name != NULL && !streq(ht[h].name,s)) {
- X h++;
- X h &= size - 1;
- X }
- X
- X return h;
- }
- X
- void *lookup(char *s, Htab *ht) {
- X int h = find(s, ht, ht == fp ? fsize : vsize);
- X
- X return (ht[h].name == NULL) ? NULL : ht[h].p;
- }
- X
- Function *get_fn_place(char *s) {
- X int h = fnfind(s);
- X
- X env_dirty = TRUE;
- X
- X if (fp[h].name == NULL) {
- X if (rehash(fp))
- X h = fnfind(s);
- X fused++;
- X fp[h].name = ecpy(s);
- X fp[h].p = enew(Function);
- X } else
- X free_fn(fp[h].p);
- X
- X return fp[h].p;
- }
- X
- Variable *get_var_place(char *s, boolean stack) {
- X Variable *new;
- X int h = varfind(s);
- X
- X env_dirty = TRUE;
- X
- X if (vp[h].name == NULL) {
- X if (rehash(vp))
- X h = varfind(s);
- X vused++;
- X vp[h].name = ecpy(s);
- X vp[h].p = enew(Variable);
- X ((Variable *)vp[h].p)->n = NULL;
- X return vp[h].p;
- X } else {
- X if (stack) { /* increase the stack by 1 */
- X new = enew(Variable);
- X new->n = vp[h].p;
- X return vp[h].p = new;
- X } else { /* trample the top of the stack */
- X new = vp[h].p;
- X efree(new->extdef);
- X listfree(new->def);
- X return new;
- X }
- X }
- }
- X
- void delete_fn(char *s) {
- X int h = fnfind(s);
- X
- X if (fp[h].name == NULL)
- X return; /* not found */
- X
- X env_dirty = TRUE;
- X
- X free_fn(fp[h].p);
- X efree(fp[h].p);
- X efree(fp[h].name);
- X if (fp[(h+1)&(fsize-1)].name == NULL) {
- X --fused;
- X fp[h].name = NULL;
- X } else {
- X fp[h].name = dead;
- X }
- }
- X
- void delete_var(char *s, boolean stack) {
- X int h = varfind(s);
- X Variable *v;
- X
- X if (vp[h].name == NULL)
- X return; /* not found */
- X
- X env_dirty = TRUE;
- X
- X v = vp[h].p;
- X efree(v->extdef);
- X listfree(v->def);
- X
- X if (v->n != NULL) { /* This is the top of a stack */
- X if (stack) { /* pop */
- X vp[h].p = v->n;
- X efree(v);
- X } else { /* else just empty */
- X v->extdef = NULL;
- X v->def = NULL;
- X }
- X } else { /* needs to be removed from the hash table */
- X efree(v);
- X efree(vp[h].name);
- X if (vp[(h+1)&(vsize-1)].name == NULL) {
- X --vused;
- X vp[h].name = NULL;
- X } else {
- X vp[h].name = dead;
- X }
- X }
- }
- X
- static void free_fn(Function *f) {
- X treefree(f->def);
- X efree(f->extdef);
- }
- X
- void initenv(char **envp) {
- X int n;
- X
- X for (n = 0; envp[n] != NULL; n++)
- X ;
- X n++; /* one for the null terminator */
- X
- X if (n < HASHSIZE)
- X n = HASHSIZE;
- X
- X env = ealloc((envsize = 2 * n) * sizeof (char *));
- X
- X for (; *envp != NULL; envp++)
- X if (strncmp(*envp, "fn_", sizeof("fn_") - 1) == 0)
- X fnassign_string(*envp);
- X else
- X if (!varassign_string(*envp)) /* add to bozo env */
- X env[bozosize++] = *envp;
- }
- X
- static boolean var_exportable(char *s) {
- X int i;
- X static char *notforexport[] = {
- X "apid", "pid", "apids", "*", "ifs"
- X };
- X
- X for (i = 0; i < arraysize(notforexport); i++)
- X if (streq(s,notforexport[i]))
- X return FALSE;
- X
- X return TRUE;
- }
- X
- static boolean fn_exportable(char *s) {
- X int i;
- X
- X if (strncmp(s,"sig",3) == 0) { /* small speed hack */
- X for (i = 0; i < NUMOFSIGNALS; i++)
- X if (streq(s, signals[i][0]))
- X return FALSE;
- X
- X if (streq(s, "sigexit"))
- X return FALSE;
- X }
- X
- X return TRUE;
- }
- X
- char **makeenv() {
- X int ep, i;
- X char *v;
- X
- X if (!env_dirty)
- X return env;
- X
- X env_dirty = FALSE;
- X ep = bozosize;
- X
- X if (vsize + fsize + 1 + bozosize > envsize) {
- X envsize = 2 * (bozosize + vsize + fsize + 1);
- X env = erealloc(env, envsize * sizeof(char *));
- X }
- X
- X for (i = 0; i < vsize; i++) {
- X if (vp[i].name == NULL || vp[i].name == dead || !var_exportable(vp[i].name))
- X continue;
- X v = varlookup_string(vp[i].name);
- X if (v != NULL)
- X env[ep++] = v;
- X }
- X for (i = 0; i < fsize; i++) {
- X if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name))
- X continue;
- X env[ep++] = fnlookup_string(fp[i].name);
- X }
- X env[ep] = NULL;
- X qsort(env, ep, sizeof(char *), starstrcmp);
- X return env;
- }
- X
- void whatare_all_vars() {
- X int i;
- X List *s;
- X
- X for (i = 0; i < vsize; i++)
- X if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
- X prettyprint_var(1, vp[i].name, s);
- X
- X for (i = 0; i < fsize; i++)
- X if (fp[i].name != NULL)
- X prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
- }
- X
- /* fake getenv() for readline() follows: */
- X
- #ifdef READLINE
- char *getenv(const char *name) {
- X List *s;
- X
- X if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL)
- X return NULL;
- X
- X return s->w;
- }
- #endif
- X
- SHAR_EOF
- chmod 0644 hash.c ||
- echo 'restore of hash.c failed'
- Wc_c="`wc -c < 'hash.c'`"
- test 6760 -eq "$Wc_c" ||
- echo 'hash.c: original size 6760, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= hash.h ==============
- if test -f 'hash.h' -a X"$1" != X"-c"; then
- echo 'x - skipping hash.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting hash.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'hash.h' &&
- typedef struct Function {
- X Node *def;
- X char *extdef;
- } Function;
- X
- typedef struct Variable {
- X List *def;
- X char *extdef;
- X struct Variable *n;
- } Variable;
- X
- typedef struct Htab {
- X char *name;
- X void *p;
- } Htab;
- X
- extern Htab *fp, *vp;
- X
- #define lookup_fn(s) ((Function *) lookup(s,fp))
- #define lookup_var(s) ((Variable *) lookup(s,vp))
- X
- extern void *lookup(char *, Htab *);
- extern Function *get_fn_place(char *);
- extern List *varlookup(char *);
- extern Node *fnlookup(char *);
- extern Variable *get_var_place(char *, boolean);
- extern boolean varassign_string(char *);
- extern char **makeenv(void);
- extern char *fnlookup_string(char *);
- extern char *varlookup_string(char *);
- extern void alias(char *, List *, boolean);
- extern void starassign(char *, char **, boolean);
- extern void delete_fn(char *);
- extern void delete_var(char *, boolean);
- extern void fnassign(char *, Node *);
- extern void fnassign_string(char *);
- extern void fnrm(char *);
- extern void initenv(char **);
- extern void inithash(void);
- extern void setsigdefaults(void);
- extern void inithandler(void);
- extern void varassign(char *, List *, boolean);
- extern void varrm(char *, boolean);
- extern void whatare_all_vars(void);
- extern void whatare_all_signals(void);
- extern void prettyprint_var(int, char *, List *);
- extern void prettyprint_fn(int, char *, Node *);
- SHAR_EOF
- chmod 0644 hash.h ||
- echo 'restore of hash.h failed'
- Wc_c="`wc -c < 'hash.h'`"
- test 1313 -eq "$Wc_c" ||
- echo 'hash.h: original size 1313, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= heredoc.c ==============
- if test -f 'heredoc.c' -a X"$1" != X"-c"; then
- echo 'x - skipping heredoc.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting heredoc.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'heredoc.c' &&
- /* heredoc.c: heredoc slurping is done here */
- X
- #include "rc.h"
- #include "lex.h"
- #include "utils.h"
- #include "nalloc.h"
- #include "heredoc.h"
- #include "tree.h"
- #include "input.h"
- #include "hash.h"
- #include "glom.h"
- X
- struct Hq {
- X Node *doc;
- X char *name;
- X Hq *n;
- X boolean quoted;
- } *hq;
- X
- static boolean dead = FALSE;
- X
- /*
- X * read in a heredocument. A clever trick: skip over any partially matched end-of-file
- X * marker storing only the number of characters matched. If the whole marker is matched,
- X * return from readheredoc(). If only part of the marker is matched, copy that part into
- X * the heredocument.
- X *
- X * BUG: if the eof string contains a newline, the state can get confused, and the
- X * heredoc may continue past where it should. on the other hand, /bin/sh seems to
- X * never get out of its readheredoc() when the heredoc string contains a newline
- X */
- X
- static char *readheredoc(char *eof) {
- X int c;
- X char *t, *buf, *bufend;
- X unsigned char *s;
- X SIZE_T bufsize;
- X
- X t = buf = nalloc(bufsize = 512);
- X bufend = &buf[bufsize];
- X dead = FALSE;
- X
- #define RESIZE(extra) { \
- X char *nbuf; \
- X bufsize = bufsize * 2 + extra; \
- X nbuf = nalloc(bufsize); \
- X memcpy(nbuf, buf, t - buf); \
- X t = nbuf + (t - buf); \
- X buf = nbuf; \
- X bufend = &buf[bufsize]; \
- X }
- X
- X for (;;) {
- X print_prompt2();
- X for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
- X ;
- X if (*s == '\0' && (c == '\n' || c == EOF)) {
- X *t++ = '\0';
- X return buf;
- X }
- X if (s != (unsigned char *) eof) {
- X SIZE_T len = s - (unsigned char *) eof;
- X if (t + len >= bufend)
- X RESIZE(len);
- X memcpy(t, eof, len);
- X t += len;
- X }
- X for (;; c = gchar()) {
- X if (c == EOF) {
- X yyerror("EOF inside heredoc");
- X dead = TRUE;
- X return NULL;
- X }
- X if (t + 1 >= bufend)
- X RESIZE(0);
- X *t++ = c;
- X if (c == '\n')
- X break;
- X }
- X }
- }
- X
- /* parseheredoc -- turn a heredoc with variable references into a node chain */
- X
- static Node *parseheredoc(char *s) {
- X int c = *s;
- X Node *result = NULL;
- X
- X while (TRUE) {
- X Node *node;
- X
- X switch (c) {
- X default: {
- X char *begin = s;
- X while ((c = *s++) != '\0' && c != '$')
- X ;
- X *--s = '\0';
- X node = newnode(QWORD, begin, NULL);
- X break;
- X }
- X case '$': {
- X char *begin = ++s, *var;
- X c = *s++;
- X if (c == '$') {
- X node = newnode(QWORD, "$", NULL);
- X c = *s;
- X } else {
- X int len = 0;
- X do
- X len++;
- X while (!dnw[c = *(unsigned char *) s++]);
- X if (c == '^')
- X c = *s;
- X else
- X s--;
- X var = nalloc(len + 1);
- X var[len] = '\0';
- X memcpy(var, begin, len);
- X node = newnode(rFLAT, newnode(rWORD, var, NULL));
- X }
- X break;
- X }
- X case '\0':
- X return result;
- X }
- X
- X result = (result == NULL) ? node : newnode(CONCAT, result, node);
- X }
- }
- X
- /* read in heredocs when yyparse hits a newline. called from yyparse */
- X
- int heredoc(int end) {
- X Hq *here;
- X
- X if ((here = hq) != NULL) {
- X hq = NULL;
- X if (end) {
- X yyerror("EOF on command line with heredoc");
- X return FALSE;
- X }
- X do {
- X Node *n = here->doc;
- X char *s = readheredoc(here->name);
- X if (dead)
- X return FALSE;
- X n->u[2].p = here->quoted ? newnode(QWORD, s, NULL) : parseheredoc(s);
- X n->u[0].i = HERESTRING;
- X } while ((here = here->n) != NULL);
- X }
- X return TRUE;
- }
- X
- /* queue pending heredocs into a queue. called from yyparse */
- X
- int qdoc(Node *name, Node *n) {
- X Hq *new, **prev;
- X
- X if (name->type != rWORD && name->type != QWORD) {
- X yyerror("eof-marker must be a single literal word");
- X flushu();
- X return FALSE;
- X }
- X
- X for (prev = &hq; (new = *prev) != NULL; prev = &new->n)
- X ;
- X *prev = new = nnew(Hq);
- X
- X new->name = name->u[0].s;
- X new->quoted = (name->type == QWORD);
- X new->doc = n;
- X new->n = NULL;
- X return TRUE;
- }
- SHAR_EOF
- chmod 0644 heredoc.c ||
- echo 'restore of heredoc.c failed'
- Wc_c="`wc -c < 'heredoc.c'`"
- test 3622 -eq "$Wc_c" ||
- echo 'heredoc.c: original size 3622, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= heredoc.h ==============
- if test -f 'heredoc.h' -a X"$1" != X"-c"; then
- echo 'x - skipping heredoc.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting heredoc.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'heredoc.h' &&
- extern int heredoc(int);
- extern int qdoc(Node *, Node *);
- X
- typedef struct Hq Hq;
- X
- extern Hq *hq;
- SHAR_EOF
- chmod 0644 heredoc.h ||
- echo 'restore of heredoc.h failed'
- Wc_c="`wc -c < 'heredoc.h'`"
- test 97 -eq "$Wc_c" ||
- echo 'heredoc.h: original size 97, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= hfix.awk ==============
- if test -f 'hfix.awk' -a X"$1" != X"-c"; then
- echo 'x - skipping hfix.awk (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting hfix.awk (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'hfix.awk' &&
- /^extern void b_exec\(char \*\*\), funcall\(char \*\*\), b_dot\(char \*\*\), b_builtin\(char \*\*\);$/ {
- SHAR_EOF
- true || echo 'restore of hfix.awk failed'
- fi
- echo 'End of part 2'
- echo 'File hfix.awk is continued in part 3'
- echo 3 > _shar_seq_.tmp
- 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.
-