CC = c99
CPPFLAGS = -I.
CCCMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS)
-RCOBJS = builtins.o except.o exec.o fn.o footobar.o glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o nalloc.o open.o y.tab.o print.o redir.o signal.o status.o tree.o utils.o var.o wait.o walk.o which.o sigmsgs.o
+RCOBJS = builtins.o except.o exec.o fn.o footobar.o glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o nalloc.o open.o y.tab.o redir.o signal.o status.o tree.o utils.o var.o wait.o walk.o which.o sigmsgs.o
all: rc
/* builtins.c: the collection of rc's builtin commands */
/*
- NOTE: rc's builtins do not call "rc_error" because they are
- commands, and rc errors usually arise from syntax errors. e.g.,
- you probably don't want interpretation of a shell script to stop
- because of a bad umask.
+ NOTE: rc's builtins do not call "rc_error" because they are
+ commands, and rc errors usually arise from syntax errors. e.g.,
+ you probably don't want interpretation of a shell script to stop
+ because of a bad umask.
*/
#include "rc.h"
static void b_break(char **), b_cd(char **), b_eval(char **), b_exit(char **),
- b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **),
- b_wait(char **), b_limit(char **), b_echo(char **);
+ b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **),
+ b_wait(char **), b_limit(char **), b_echo(char **);
static struct {
- builtin_t *p;
- char *name;
+ builtin_t *p;
+ char *name;
} builtins[] = {
- { b_break, "break" },
- { b_builtin, "builtin" },
- { b_cd, "cd" },
- { b_echo, "echo" },
- { b_eval, "eval" },
- { b_exec, "exec" },
- { b_exit, "exit" },
- { b_limit, "limit" },
- { b_newpgrp, "newpgrp" },
- { b_return, "return" },
- { b_shift, "shift" },
- { b_umask, "umask" },
- { b_wait, "wait" },
- { b_dot, "." },
+ { b_break, "break" },
+ { b_builtin, "builtin" },
+ { b_cd, "cd" },
+ { b_echo, "echo" },
+ { b_eval, "eval" },
+ { b_exec, "exec" },
+ { b_exit, "exit" },
+ { b_limit, "limit" },
+ { b_newpgrp, "newpgrp" },
+ { b_return, "return" },
+ { b_shift, "shift" },
+ { b_umask, "umask" },
+ { b_wait, "wait" },
+ { b_dot, "." },
};
extern builtin_t *isbuiltin(char *s) {
- int i;
- for (i = 0; i < arraysize(builtins); i++)
- if (streq(builtins[i].name, s))
- return builtins[i].p;
- return NULL;
+ int i;
+ for (i = 0; i < arraysize(builtins); i++)
+ if (streq(builtins[i].name, s))
+ return builtins[i].p;
+ return NULL;
}
/* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */
extern void funcall(char **av) {
- Jbwrap j;
- Estack e1, e2;
- Edata jreturn, star;
- if (sigsetjmp(j.j, 1))
- return;
- starassign(*av, av+1, true);
- jreturn.jb = &j;
- star.name = "*";
- except(eReturn, jreturn, &e1);
- except(eVarstack, star, &e2);
- walk(treecpy(fnlookup(*av), nalloc), true);
- varrm("*", true);
- unexcept(); /* eVarstack */
- unexcept(); /* eReturn */
+ Jbwrap j;
+ Estack e1, e2;
+ Edata jreturn, star;
+ if (sigsetjmp(j.j, 1))
+ return;
+ starassign(*av, av+1, true);
+ jreturn.jb = &j;
+ star.name = "*";
+ except(eReturn, jreturn, &e1);
+ except(eVarstack, star, &e2);
+ walk(treecpy(fnlookup(*av), nalloc), true);
+ varrm("*", true);
+ unexcept(); /* eVarstack */
+ unexcept(); /* eReturn */
}
static void arg_count(char *name) {
- fprint(2, RC "too many arguments to %s\n", name);
- set(false);
+ fprintf(stderr, RC "too many arguments to %s\n", name);
+ set(false);
}
static void badnum(char *num) {
- fprint(2, RC "`%s' is a bad number\n", num);
- set(false);
+ fprintf(stderr, RC "`%s' is a bad number\n", num);
+ set(false);
}
/* a dummy command. (exec() performs "exec" simply by not forking) */
/* echo -n omits a newline. echo -- -n echos '-n' */
static void b_echo(char **av) {
- char *format = "%A\n";
- if (*++av != NULL) {
- if (streq(*av, "-n"))
- format = "%A", av++;
- else if (streq(*av, "--"))
- av++;
- }
- fprint(1, format, av);
- set(true);
+ char *format = "%A\n";
+ if (*++av != NULL) {
+ if (streq(*av, "-n"))
+ format = "%A", av++;
+ else if (streq(*av, "--"))
+ av++;
+ }
+ fprintf(stdout, format, av);
+ set(true);
}
/* cd. traverse $cdpath if the directory given is not an absolute pathname */
static void b_cd(char **av) {
- List *s, nil;
- char *path = NULL;
- size_t t, pathlen = 0;
- if (*++av == NULL) {
- s = varlookup("home");
- *av = (s == NULL) ? "/" : s->w;
- } else if (av[1] != NULL) {
- arg_count("cd");
- return;
- }
- if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */
- if (chdir(*av) < 0) {
- set(false);
- uerror(*av);
- } else
- set(true);
- } else {
- s = varlookup("cdpath");
- if (s == NULL) {
- s = &nil;
- nil.w = "";
- nil.n = NULL;
- }
- do {
- if (s != &nil && *s->w != '\0') {
- t = strlen(*av) + strlen(s->w) + 2;
- if (t > pathlen)
- path = nalloc(pathlen = t);
- strcpy(path, s->w);
- if (!streq(s->w, "/")) /* "//" is special to POSIX */
- strcat(path, "/");
- strcat(path, *av);
- } else {
- pathlen = 0;
- path = *av;
- }
- if (chdir(path) >= 0) {
- set(true);
- if (interactive && *s->w != '\0' && !streq(s->w, "."))
- fprint(1, "%s\n", path);
- return;
- }
- s = s->n;
- } while (s != NULL);
- fprint(2, "couldn't cd to %s\n", *av);
- set(false);
- }
+ List *s, nil;
+ char *path = NULL;
+ size_t t, pathlen = 0;
+ if (*++av == NULL) {
+ s = varlookup("home");
+ *av = (s == NULL) ? "/" : s->w;
+ } else if (av[1] != NULL) {
+ arg_count("cd");
+ return;
+ }
+ if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */
+ if (chdir(*av) < 0) {
+ set(false);
+ uerror(*av);
+ } else
+ set(true);
+ } else {
+ s = varlookup("cdpath");
+ if (s == NULL) {
+ s = &nil;
+ nil.w = "";
+ nil.n = NULL;
+ }
+ do {
+ if (s != &nil && *s->w != '\0') {
+ t = strlen(*av) + strlen(s->w) + 2;
+ if (t > pathlen)
+ path = nalloc(pathlen = t);
+ strcpy(path, s->w);
+ if (!streq(s->w, "/")) /* "//" is special to POSIX */
+ strcat(path, "/");
+ strcat(path, *av);
+ } else {
+ pathlen = 0;
+ path = *av;
+ }
+ if (chdir(path) >= 0) {
+ set(true);
+ if (interactive && *s->w != '\0' && !streq(s->w, "."))
+ fprintf(stdout, "%s\n", path);
+ return;
+ }
+ s = s->n;
+ } while (s != NULL);
+ fprintf(stderr, "couldn't cd to %s\n", *av);
+ set(false);
+ }
}
static void b_umask(char **av) {
- int i;
- if (*++av == NULL) {
- set(true);
- i = umask(0);
- umask(i);
- fprint(1, "0%o\n", i);
- } else if (av[1] == NULL) {
- i = o2u(*av);
- if ((unsigned int) i > 0777) {
- fprint(2, "bad umask\n");
- set(false);
- } else {
- umask(i);
- set(true);
- }
- } else {
- arg_count("umask");
- return;
- }
+ int i;
+ if (*++av == NULL) {
+ set(true);
+ i = umask(0);
+ umask(i);
+ fprintf(stdout, "0%o\n", i); // OCTAL
+ } else if (av[1] == NULL) {
+ i = o2u(*av);
+ if ((unsigned int) i > 0777) {
+ fprintf(stderr, "bad umask\n");
+ set(false);
+ } else {
+ umask(i);
+ set(true);
+ }
+ } else {
+ arg_count("umask");
+ return;
+ }
}
static void b_exit(char **av) {
- if (*++av != NULL)
- ssetstatus(av);
- rc_exit(getstatus());
+ if (*++av != NULL)
+ ssetstatus(av);
+ rc_exit(getstatus());
}
/* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */
static void b_return(char **av) {
- if (*++av != NULL)
- ssetstatus(av);
- rc_raise(eReturn);
+ if (*++av != NULL)
+ ssetstatus(av);
+ rc_raise(eReturn);
}
/* raise a "break" exception for breaking out of for and while loops */
static void b_break(char **av) {
- if (av[1] != NULL) {
- arg_count("break");
- return;
- }
- rc_raise(eBreak);
+ if (av[1] != NULL) {
+ arg_count("break");
+ return;
+ }
+ rc_raise(eBreak);
}
/* shift $* n places (default 1) */
static void b_shift(char **av) {
- int shift = (av[1] == NULL ? 1 : a2u(av[1]));
- List *s, *dollarzero;
- if (av[1] != NULL && av[2] != NULL) {
- arg_count("shift");
- return;
- }
- if (shift < 0) {
- badnum(av[1]);
- return;
- }
- s = varlookup("*")->n;
- dollarzero = varlookup("0");
- while (s != NULL && shift != 0) {
- s = s->n;
- --shift;
- }
- if (s == NULL && shift != 0) {
- fprint(2, "cannot shift\n");
- set(false);
- } else {
- varassign("*", append(dollarzero, s), false);
- set(true);
- }
+ int shift = (av[1] == NULL ? 1 : a2u(av[1]));
+ List *s, *dollarzero;
+ if (av[1] != NULL && av[2] != NULL) {
+ arg_count("shift");
+ return;
+ }
+ if (shift < 0) {
+ badnum(av[1]);
+ return;
+ }
+ s = varlookup("*")->n;
+ dollarzero = varlookup("0");
+ while (s != NULL && shift != 0) {
+ s = s->n;
+ --shift;
+ }
+ if (s == NULL && shift != 0) {
+ fprintf(stderr, "cannot shift\n");
+ set(false);
+ } else {
+ varassign("*", append(dollarzero, s), false);
+ set(true);
+ }
}
/* dud function */
/* wait for a given process, or all outstanding processes */
static void b_wait(char **av) {
- int status;
- pid_t pid;
- if (av[1] == NULL) {
- waitforall();
- return;
- }
- if (av[2] != NULL) {
- arg_count("wait");
- return;
- }
- if ((pid = a2u(av[1])) < 0) {
- badnum(av[1]);
- return;
- }
- if (rc_wait4(pid, &status, false) > 0)
- setstatus(pid, status);
- else
- set(false);
- sigchk();
+ int status;
+ pid_t pid;
+ if (av[1] == NULL) {
+ waitforall();
+ return;
+ }
+ if (av[2] != NULL) {
+ arg_count("wait");
+ return;
+ }
+ if ((pid = a2u(av[1])) < 0) {
+ badnum(av[1]);
+ return;
+ }
+ if (rc_wait4(pid, &status, false) > 0)
+ setstatus(pid, status);
+ else
+ set(false);
+ sigchk();
}
/*
is defined as a variable, function or pathname.
*/
-#define not(b) ((b)^true)
-#define show(b) (not(eff|vee|pee|bee|ess)|(b))
+#define not(b) ((b)^true)
+#define show(b) (not(eff|vee|pee|bee|ess)|(b))
/* push a string to be eval'ed onto the input stack. evaluate it */
static void b_eval(char **av) {
- bool i = interactive;
- if (av[1] == NULL)
- return;
- interactive = false;
- pushstring(av + 1, i); /* don't reset line numbers on noninteractive eval */
- doit(true);
- interactive = i;
+ bool i = interactive;
+ if (av[1] == NULL)
+ return;
+ interactive = false;
+ pushstring(av + 1, i); /* don't reset line numbers on noninteractive eval */
+ doit(true);
+ interactive = i;
}
/*
*/
extern void b_dot(char **av) {
- int fd;
- bool old_i = interactive, i = false;
- Estack e;
- Edata star;
- av++;
- if (*av == NULL)
- return;
- if (streq(*av, "-i")) {
- av++;
- i = true;
- }
- if (*av == NULL)
- return;
- fd = rc_open(*av, rFrom);
- if (fd < 0) {
- uerror(*av);
- set(false);
- return;
- }
- starassign(*av, av+1, true);
- interactive = i;
- pushfd(fd);
- star.name = "*";
- except(eVarstack, star, &e);
- doit(true);
- varrm("*", true);
- unexcept(); /* eVarstack */
- interactive = old_i;
+ int fd;
+ bool old_i = interactive, i = false;
+ Estack e;
+ Edata star;
+ av++;
+ if (*av == NULL)
+ return;
+ if (streq(*av, "-i")) {
+ av++;
+ i = true;
+ }
+ if (*av == NULL)
+ return;
+ fd = rc_open(*av, rFrom);
+ if (fd < 0) {
+ uerror(*av);
+ set(false);
+ return;
+ }
+ starassign(*av, av+1, true);
+ interactive = i;
+ pushfd(fd);
+ star.name = "*";
+ except(eVarstack, star, &e);
+ doit(true);
+ varrm("*", true);
+ unexcept(); /* eVarstack */
+ interactive = old_i;
}
/* put rc into a new pgrp. Used on the NeXT where the Terminal program is broken (sigh) */
static void b_newpgrp(char **av) {
- if (av[1] != NULL) {
- arg_count("newpgrp");
- return;
- }
- setpgid(rc_pid, rc_pid); /* XXX check return value */
- tcsetpgrp(2, rc_pid); /* XXX check return value */
+ if (av[1] != NULL) {
+ arg_count("newpgrp");
+ return;
+ }
+ setpgid(rc_pid, rc_pid); /* XXX check return value */
+ tcsetpgrp(2, rc_pid); /* XXX check return value */
}
/* Berkeley limit support was cleaned up by Paul Haahr. */
static const struct Suffix
- kbsuf = { NULL, 1024, "k" },
- mbsuf = { &kbsuf, 1024*1024, "m" },
- gbsuf = { &mbsuf, 1024*1024*1024, "g" },
- stsuf = { NULL, 1, "s" },
- mtsuf = { &stsuf, 60, "m" },
- htsuf = { &mtsuf, 60*60, "h" };
-#define SIZESUF &gbsuf
-#define TIMESUF &htsuf
-#define NOSUF ((struct Suffix *) NULL) /* for RLIMIT_NOFILE on SunOS 4.1 */
+ kbsuf = { NULL, 1024, "k" },
+ mbsuf = { &kbsuf, 1024*1024, "m" },
+ gbsuf = { &mbsuf, 1024*1024*1024, "g" },
+ stsuf = { NULL, 1, "s" },
+ mtsuf = { &stsuf, 60, "m" },
+ htsuf = { &mtsuf, 60*60, "h" };
+#define SIZESUF &gbsuf
+#define TIMESUF &htsuf
+#define NOSUF ((struct Suffix *) NULL) /* for RLIMIT_NOFILE on SunOS 4.1 */
static const struct Limit limits[] = {
- { "cputime", RLIMIT_CPU, TIMESUF },
- { "filesize", RLIMIT_FSIZE, SIZESUF },
- { "datasize", RLIMIT_DATA, SIZESUF },
- { "stacksize", RLIMIT_STACK, SIZESUF },
- { "coredumpsize", RLIMIT_CORE, SIZESUF },
+ { "cputime", RLIMIT_CPU, TIMESUF },
+ { "filesize", RLIMIT_FSIZE, SIZESUF },
+ { "datasize", RLIMIT_DATA, SIZESUF },
+ { "stacksize", RLIMIT_STACK, SIZESUF },
+ { "coredumpsize", RLIMIT_CORE, SIZESUF },
#ifdef RLIMIT_NOFILE /* SUSv2, but not universal */
- { "descriptors", RLIMIT_NOFILE, NOSUF },
+ { "descriptors", RLIMIT_NOFILE, NOSUF },
#endif
#ifdef RLIMIT_AS /* SUSv2, but not universal */
- { "memoryuse", RLIMIT_AS, SIZESUF },
+ { "memoryuse", RLIMIT_AS, SIZESUF },
#endif
#if defined(RLIMIT_VMEM) && !defined(RLIMIT_AS) /* old name for AS */
- { "memoryuse", RLIMIT_VMEM, SIZESUF },
+ { "memoryuse", RLIMIT_VMEM, SIZESUF },
#endif
#ifdef RLIMIT_RSS
- { "memoryrss", RLIMIT_RSS, SIZESUF },
+ { "memoryrss", RLIMIT_RSS, SIZESUF },
#endif
#ifdef RLIMIT_NPROC
- { "maxproc", RLIMIT_NPROC, NOSUF },
+ { "maxproc", RLIMIT_NPROC, NOSUF },
#endif
#ifdef RLIMIT_MEMLOCK
- { "memorylocked", RLIMIT_MEMLOCK, SIZESUF },
+ { "memorylocked", RLIMIT_MEMLOCK, SIZESUF },
#endif
#ifdef RLIMIT_LOCKS
- { "filelocks", RLIMIT_LOCKS, NOSUF },
+ { "filelocks", RLIMIT_LOCKS, NOSUF },
#endif
- { NULL, 0, NULL }
+ { NULL, 0, NULL }
};
static void printlimit(const struct Limit *limit, bool hard) {
- struct rlimit rlim;
- rlim_t lim;
- getrlimit(limit->flag, &rlim);
- if (hard)
- lim = rlim.rlim_max;
- else
- lim = rlim.rlim_cur;
- if (lim == RLIM_INFINITY)
- fprint(1, "%s \tunlimited\n", limit->name);
- else {
- const struct Suffix *suf;
- for (suf = limit->suffix; suf != NULL; suf = suf->next)
- if (lim % suf->amount == 0 && (lim != 0 || suf->amount > 1)) {
- lim /= suf->amount;
- break;
- }
- fprint(1, "%s \t%ld%s\n", limit->name, (long)lim, (suf == NULL || lim == 0) ? "" : suf->name);
- }
+ struct rlimit rlim;
+ rlim_t lim;
+ getrlimit(limit->flag, &rlim);
+ if (hard)
+ lim = rlim.rlim_max;
+ else
+ lim = rlim.rlim_cur;
+ if (lim == RLIM_INFINITY)
+ fprintf(stdout, "%s \tunlimited\n", limit->name);
+ else {
+ const struct Suffix *suf;
+ for (suf = limit->suffix; suf != NULL; suf = suf->next)
+ if (lim % suf->amount == 0 && (lim != 0 || suf->amount > 1)) {
+ lim /= suf->amount;
+ break;
+ }
+ fprintf(stdout, "%s \t%ld%s\n", limit->name, (long)lim, (suf == NULL || lim == 0) ? "" : suf->name);
+ }
}
static bool parselimit(const struct Limit *resource, rlim_t *limit, char *s) {
- char *t;
- int len = strlen(s);
- const struct Suffix *suf = resource->suffix;
-
- *limit = 1;
- if (streq(s, "unlimited")) {
- *limit = RLIM_INFINITY;
- return true;
- }
- if (suf == TIMESUF && (t = strchr(s, ':')) != NULL) {
- int min, sec;
- *t++ = '\0';
- min = a2u(s); sec = a2u(t);
- if (min == -1 || sec == -1) return false;
- *limit = 60 * min + sec;
- } else {
- int n;
- for (; suf != NULL; suf = suf->next)
- if (streq(suf->name, s + len - strlen(suf->name))) {
- s[len - strlen(suf->name)] = '\0';
- *limit *= suf->amount;
- break;
- }
- n = a2u(s);
- if (n == -1) return false;
- *limit *= n;
- }
- return true;
+ char *t;
+ int len = strlen(s);
+ const struct Suffix *suf = resource->suffix;
+
+ *limit = 1;
+ if (streq(s, "unlimited")) {
+ *limit = RLIM_INFINITY;
+ return true;
+ }
+ if (suf == TIMESUF && (t = strchr(s, ':')) != NULL) {
+ int min, sec;
+ *t++ = '\0';
+ min = a2u(s); sec = a2u(t);
+ if (min == -1 || sec == -1) return false;
+ *limit = 60 * min + sec;
+ } else {
+ int n;
+ for (; suf != NULL; suf = suf->next)
+ if (streq(suf->name, s + len - strlen(suf->name))) {
+ s[len - strlen(suf->name)] = '\0';
+ *limit *= suf->amount;
+ break;
+ }
+ n = a2u(s);
+ if (n == -1) return false;
+ *limit *= n;
+ }
+ return true;
}
static void b_limit(char **av) {
- const struct Limit *lp = limits;
- bool hard = false;
- if (*++av != NULL && streq(*av, "-h")) {
- av++;
- hard = true;
- }
- if (*av == NULL) {
- for (; lp->name != NULL; lp++)
- printlimit(lp, hard);
- return;
- }
- for (;; lp++) {
- if (lp->name == NULL) {
- fprint(2, "no such limit\n");
- set(false);
- return;
- }
- if (streq(*av, lp->name))
- break;
- }
- if (*++av == NULL)
- printlimit(lp, hard);
- else {
- struct rlimit rlim;
- rlim_t pl;
- getrlimit(lp->flag, &rlim);
- if (!parselimit(lp, &pl, *av)) {
- fprint(2, "bad limit\n");
- set(false);
- return;
- }
- if (hard)
- rlim.rlim_max = pl;
- else
- rlim.rlim_cur = pl;
- if (setrlimit(lp->flag, &rlim) == -1) {
- uerror("setrlimit");
- set(false);
- } else
- set(true);
- }
+ const struct Limit *lp = limits;
+ bool hard = false;
+ if (*++av != NULL && streq(*av, "-h")) {
+ av++;
+ hard = true;
+ }
+ if (*av == NULL) {
+ for (; lp->name != NULL; lp++)
+ printlimit(lp, hard);
+ return;
+ }
+ for (;; lp++) {
+ if (lp->name == NULL) {
+ fprintf(stderr, "no such limit\n");
+ set(false);
+ return;
+ }
+ if (streq(*av, lp->name))
+ break;
+ }
+ if (*++av == NULL)
+ printlimit(lp, hard);
+ else {
+ struct rlimit rlim;
+ rlim_t pl;
+ getrlimit(lp->flag, &rlim);
+ if (!parselimit(lp, &pl, *av)) {
+ fprintf(stderr, "bad limit\n");
+ set(false);
+ return;
+ }
+ if (hard)
+ rlim.rlim_max = pl;
+ else
+ rlim.rlim_cur = pl;
+ if (setrlimit(lp->flag, &rlim) == -1) {
+ uerror("setrlimit");
+ set(false);
+ } else
+ set(true);
+ }
}
/* add an exception to the input stack. */
extern void except(ecodes e, Edata data, Estack *ex) {
- ex->prev = estack;
- estack = ex;
- estack->e = e;
- estack->data = data;
- if (e == eError || e == eBreak || e == eReturn)
- estack->interactive = interactive;
+ ex->prev = estack;
+ estack = ex;
+ estack->e = e;
+ estack->data = data;
+ if (e == eError || e == eBreak || e == eReturn)
+ estack->interactive = interactive;
}
/* remove an exception, restore last interactive value */
extern void unexcept() {
- switch (estack->e) {
- default:
- break;
- case eError:
- interactive = estack->interactive;
- break;
- case eArena:
- restoreblock(estack->data.b);
- break;
- case eFifo:
- unlink(estack->data.name);
- break;
- case eFd:
- close(estack->data.fd);
- break;
- }
- estack = estack->prev;
+ switch (estack->e) {
+ default:
+ break;
+ case eError:
+ interactive = estack->interactive;
+ break;
+ case eArena:
+ restoreblock(estack->data.b);
+ break;
+ case eFifo:
+ unlink(estack->data.name);
+ break;
+ case eFd:
+ close(estack->data.fd);
+ break;
+ }
+ estack = estack->prev;
}
/*
*/
extern void rc_raise(ecodes e) {
- if (e == eError && rc_pid != getpid())
- exit(1); /* child processes exit on an error/signal */
- for (; estack != NULL; estack = estack->prev)
- if (estack->e != e) {
- if (e == eBreak && estack->e != eArena)
- rc_error("break outside of loop");
- else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */
- rc_error("return outside of function");
- switch (estack->e) {
- default:
- break;
- case eVarstack:
- varrm(estack->data.name, true);
- break;
- case eArena:
- restoreblock(estack->data.b);
- break;
- case eFifo:
- unlink(estack->data.name);
- break;
- case eFd:
- close(estack->data.fd);
- break;
- }
- } else {
- if (e == eError && !estack->interactive) {
- popinput();
- } else {
- Jbwrap *j = estack->data.jb;
+ if (e == eError && rc_pid != getpid())
+ exit(1); /* child processes exit on an error/signal */
+ for (; estack != NULL; estack = estack->prev)
+ if (estack->e != e) {
+ if (e == eBreak && estack->e != eArena)
+ rc_error("break outside of loop");
+ else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */
+ rc_error("return outside of function");
+ switch (estack->e) {
+ default:
+ break;
+ case eVarstack:
+ varrm(estack->data.name, true);
+ break;
+ case eArena:
+ restoreblock(estack->data.b);
+ break;
+ case eFifo:
+ unlink(estack->data.name);
+ break;
+ case eFd:
+ close(estack->data.fd);
+ break;
+ }
+ } else {
+ if (e == eError && !estack->interactive) {
+ popinput();
+ } else {
+ Jbwrap *j = estack->data.jb;
- interactive = estack->interactive;
- estack = estack->prev;
- siglongjmp(j->j, 1);
- }
- }
- rc_exit(1); /* top of exception stack */
+ interactive = estack->interactive;
+ estack = estack->prev;
+ siglongjmp(j->j, 1);
+ }
+ }
+ rc_exit(1); /* top of exception stack */
}
extern bool outstanding_cmdarg() {
- return estack->e == eFifo || estack->e == eFd;
+ return estack->e == eFifo || estack->e == eFd;
}
extern void pop_cmdarg(bool remove) {
- for (; estack != NULL; estack = estack->prev)
- switch (estack->e) {
- case eFifo:
- if (remove)
- unlink(estack->data.name);
- break;
- case eFd:
- if (remove)
- close(estack->data.fd);
- break;
- default:
- return;
- }
+ for (; estack != NULL; estack = estack->prev)
+ switch (estack->e) {
+ case eFifo:
+ if (remove)
+ unlink(estack->data.name);
+ break;
+ case eFd:
+ if (remove)
+ close(estack->data.fd);
+ break;
+ default:
+ return;
+ }
}
/* exception handlers */
extern void rc_error(char *s) {
- pr_error(s, -1);
- set(false);
- redirq = NULL;
- cond = false; /* no longer inside conditional */
- rc_raise(eError);
+ pr_error(s, -1);
+ set(false);
+ redirq = NULL;
+ cond = false; /* no longer inside conditional */
+ rc_raise(eError);
}
extern void sigint(int s) {
- if (s != SIGINT)
- panic("s != SIGINT in sigint catcher");
- /* this is the newline you see when you hit ^C while typing a command */
- if (interactive && nl_on_intr)
- fprint(2, "\n");
- nl_on_intr = true;
- redirq = NULL;
- cond = false;
- rc_raise(eError);
+ if (s != SIGINT)
+ panic("s != SIGINT in sigint catcher");
+ /* this is the newline you see when you hit ^C while typing a command */
+ if (interactive && nl_on_intr)
+ fprintf(stderr, "\n");
+ nl_on_intr = true;
+ redirq = NULL;
+ cond = false;
+ rc_raise(eError);
}
*/
extern void exec(List *s, bool parent) {
- char **av, **ev = NULL;
- int stat;
- pid_t pid;
- builtin_t *b;
- char *path = NULL;
- bool didfork, returning, saw_exec, saw_builtin;
- av = list2array(s, false);
- saw_builtin = saw_exec = false;
- do {
- if (*av == NULL || isabsolute(*av))
- b = NULL;
- else if (!saw_builtin && fnlookup(*av) != NULL)
- b = funcall;
- else
- b = isbuiltin(*av);
+ char **av, **ev = NULL;
+ int stat;
+ pid_t pid;
+ builtin_t *b;
+ char *path = NULL;
+ bool didfork, returning, saw_exec, saw_builtin;
+ av = list2array(s, false);
+ saw_builtin = saw_exec = false;
+ do {
+ if (*av == NULL || isabsolute(*av))
+ b = NULL;
+ else if (!saw_builtin && fnlookup(*av) != NULL)
+ b = funcall;
+ else
+ b = isbuiltin(*av);
- /*
- a builtin applies only to the immmediately following
- command, e.g., builtin exec echo hi
- */
- saw_builtin = false;
+ /*
+ a builtin applies only to the immmediately following
+ command, e.g., builtin exec echo hi
+ */
+ saw_builtin = false;
- if (b == b_exec) {
- av++;
- saw_exec = true;
- parent = false;
- } else if (b == b_builtin) {
- av++;
- saw_builtin = true;
- }
- } while (b == b_exec || b == b_builtin);
- if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
- doredirs();
- return;
- }
- /* force an exit on exec with any rc_error, but not for null commands as above */
- if (saw_exec)
- rc_pid = -1;
- if (b == NULL) {
- path = which(*av, true);
- if (path == NULL && *av != NULL) { /* perform null commands for redirections */
- set(false);
- redirq = NULL;
- if (parent)
- return;
- rc_exit(1);
- }
- ev = makeenv(); /* environment only needs to be built for execve() */
- }
- /*
- If parent & the redirq is nonnull, builtin or not it has to fork.
- If the fifoq is nonnull, then it must be emptied at the end so we
- must fork no matter what.
- */
- if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) {
- pid = rc_fork();
- didfork = true;
- } else {
- pid = 0;
- didfork = false;
- }
- returning = (!didfork && parent);
- switch (pid) {
- case -1:
- uerror("fork");
- rc_error(NULL);
- /* NOTREACHED */
- case 0:
- if (!returning)
- setsigdefaults(false);
- pop_cmdarg(false);
- doredirs();
+ if (b == b_exec) {
+ av++;
+ saw_exec = true;
+ parent = false;
+ } else if (b == b_builtin) {
+ av++;
+ saw_builtin = true;
+ }
+ } while (b == b_exec || b == b_builtin);
+ if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
+ doredirs();
+ return;
+ }
+ /* force an exit on exec with any rc_error, but not for null commands as above */
+ if (saw_exec)
+ rc_pid = -1;
+ if (b == NULL) {
+ path = which(*av, true);
+ if (path == NULL && *av != NULL) { /* perform null commands for redirections */
+ set(false);
+ redirq = NULL;
+ if (parent)
+ return;
+ rc_exit(1);
+ }
+ ev = makeenv(); /* environment only needs to be built for execve() */
+ }
+ /*
+ If parent & the redirq is nonnull, builtin or not it has to fork.
+ If the fifoq is nonnull, then it must be emptied at the end so we
+ must fork no matter what.
+ */
+ if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) {
+ pid = rc_fork();
+ didfork = true;
+ } else {
+ pid = 0;
+ didfork = false;
+ }
+ returning = (!didfork && parent);
+ switch (pid) {
+ case -1:
+ uerror("fork");
+ rc_error(NULL);
+ /* NOTREACHED */
+ case 0:
+ if (!returning)
+ setsigdefaults(false);
+ pop_cmdarg(false);
+ doredirs();
- /* null commands performed for redirections */
- if (*av == NULL || b != NULL) {
- if (b != NULL)
- (*b)(av);
- if (returning)
- return;
- rc_exit(getstatus());
- }
- execve(path, (char * const *) av, (char * const *) ev);
+ /* null commands performed for redirections */
+ if (*av == NULL || b != NULL) {
+ if (b != NULL)
+ (*b)(av);
+ if (returning)
+ return;
+ rc_exit(getstatus());
+ }
+ execve(path, (char * const *) av, (char * const *) ev);
#ifdef DEFAULTINTERP
- if (errno == ENOEXEC) {
- *av = path;
- *--av = DEFAULTINTERP;
- execve(*av, (char * const *) av, (char * const *) ev);
- }
+ if (errno == ENOEXEC) {
+ *av = path;
+ *--av = DEFAULTINTERP;
+ execve(*av, (char * const *) av, (char * const *) ev);
+ }
#endif
- uerror(*av);
- rc_exit(1);
- /* NOTREACHED */
- default:
- redirq = NULL;
- rc_wait4(pid, &stat, true);
- setstatus(-1, stat);
- /*
- There is a very good reason for having this weird
- nl_on_intr variable: when rc and its child both
- process a SIGINT, (i.e., the child has a SIGINT
- catcher installed) then you don't want rc to print
- a newline when the child finally exits. Here's an
- example: ed, <type ^C>, <type "q">. rc does not
- and should not print a newline before the next
- prompt, even though there's a SIGINT in its signal
- vector.
- */
- if (WIFEXITED(stat))
- nl_on_intr = false;
- sigchk();
- nl_on_intr = true;
- pop_cmdarg(true);
- }
+ uerror(*av);
+ rc_exit(1);
+ /* NOTREACHED */
+ default:
+ redirq = NULL;
+ rc_wait4(pid, &stat, true);
+ setstatus(-1, stat);
+ /*
+ There is a very good reason for having this weird
+ nl_on_intr variable: when rc and its child both
+ process a SIGINT, (i.e., the child has a SIGINT
+ catcher installed) then you don't want rc to print
+ a newline when the child finally exits. Here's an
+ example: ed, <type ^C>, <type "q">. rc does not
+ and should not print a newline before the next
+ prompt, even though there's a SIGINT in its signal
+ vector.
+ */
+ if (WIFEXITED(stat))
+ nl_on_intr = false;
+ sigchk();
+ nl_on_intr = true;
+ pop_cmdarg(true);
+ }
}
*/
extern void inithandler() {
- int i;
- null.type = nBody;
- null.u[0].p = null.u[1].p = NULL;
- for (i = 1; i < NSIG; i++)
- if (sighandlers[i] == SIG_IGN)
- fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */
- if (interactive || sighandlers[SIGINT] != SIG_IGN) {
- def_sigint = sigint;
- fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */
- }
-
- if (interactive || sighandlers[SIGQUIT] != SIG_IGN) {
- def_sigquit = dud_handler;
- fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */
- }
-
- if (interactive) {
- def_sigterm = dud_handler;
- fnrm("sigterm"); /* ditto for SIGTERM */
- }
+ int i;
+ null.type = nBody;
+ null.u[0].p = null.u[1].p = NULL;
+ for (i = 1; i < NSIG; i++)
+ if (sighandlers[i] == SIG_IGN)
+ fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */
+ if (interactive || sighandlers[SIGINT] != SIG_IGN) {
+ def_sigint = sigint;
+ fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */
+ }
+
+ if (interactive || sighandlers[SIGQUIT] != SIG_IGN) {
+ def_sigquit = dud_handler;
+ fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */
+ }
+
+ if (interactive) {
+ def_sigterm = dud_handler;
+ fnrm("sigterm"); /* ditto for SIGTERM */
+ }
}
/* only run this in a child process! resets signals to their default values */
extern void setsigdefaults(bool sysvbackground) {
- int i;
- /*
- General housekeeping: setsigdefaults happens after fork(),
- so it's a convenient place to clean up open file descriptors.
- (history file, scripts, etc.)
- */
- closefds();
- /*
- Restore signals to SIG_DFL, paying close attention to
- a few quirks: SIGINT, SIGQUIT and are treated specially
- depending on whether we are doing v7-style backgrounding
- or not; the default action for SIGINT, SIGQUIT and SIGTERM
- must be set to the appropriate action; finally, care must
- be taken not to set to SIG_DFL any signals which are being
- ignored.
- */
- for (i = 1; i < NSIG; i++)
- if (sighandlers[i] != SIG_IGN) {
- handlers[i] = NULL;
- switch (i) {
- case SIGINT:
- if (sysvbackground) {
- def_sigint = SIG_IGN;
- fnassign("sigint", NULL); /* ignore */
- } else {
- def_sigint = SIG_DFL;
- goto sigcommon;
- }
- break;
- case SIGQUIT:
- if (sysvbackground) {
- def_sigquit = SIG_IGN;
- fnassign("sigquit", NULL); /* ignore */
- } else {
- def_sigquit = SIG_DFL;
- goto sigcommon;
- }
- break;
- case SIGTERM:
- def_sigterm = SIG_DFL;
- /* FALLTHROUGH */
- sigcommon:
- default:
- if (sighandlers[i] != SIG_DFL) {
- rc_signal(i, SIG_DFL);
- delete_fn(signals[i].name);
- }
- }
- }
- delete_fn("sigexit");
- runexit = false; /* No sigexit on subshells */
+ int i;
+ /*
+ General housekeeping: setsigdefaults happens after fork(),
+ so it's a convenient place to clean up open file descriptors.
+ (history file, scripts, etc.)
+ */
+ closefds();
+ /*
+ Restore signals to SIG_DFL, paying close attention to
+ a few quirks: SIGINT, SIGQUIT and are treated specially
+ depending on whether we are doing v7-style backgrounding
+ or not; the default action for SIGINT, SIGQUIT and SIGTERM
+ must be set to the appropriate action; finally, care must
+ be taken not to set to SIG_DFL any signals which are being
+ ignored.
+ */
+ for (i = 1; i < NSIG; i++)
+ if (sighandlers[i] != SIG_IGN) {
+ handlers[i] = NULL;
+ switch (i) {
+ case SIGINT:
+ if (sysvbackground) {
+ def_sigint = SIG_IGN;
+ fnassign("sigint", NULL); /* ignore */
+ } else {
+ def_sigint = SIG_DFL;
+ goto sigcommon;
+ }
+ break;
+ case SIGQUIT:
+ if (sysvbackground) {
+ def_sigquit = SIG_IGN;
+ fnassign("sigquit", NULL); /* ignore */
+ } else {
+ def_sigquit = SIG_DFL;
+ goto sigcommon;
+ }
+ break;
+ case SIGTERM:
+ def_sigterm = SIG_DFL;
+ /* FALLTHROUGH */
+ sigcommon:
+ default:
+ if (sighandlers[i] != SIG_DFL) {
+ rc_signal(i, SIG_DFL);
+ delete_fn(signals[i].name);
+ }
+ }
+ }
+ delete_fn("sigexit");
+ runexit = false; /* No sigexit on subshells */
}
/* rc's exit. if runexit is set, run the sigexit function. */
extern void rc_exit(int stat) {
- if (runexit) {
- char *sig[2];
- sig[0] = "sigexit";
- sig[1] = NULL;
- runexit = false;
- funcall(sig);
- stat = getstatus();
- }
- exit(stat);
+ if (runexit) {
+ char *sig[2];
+ sig[0] = "sigexit";
+ sig[1] = NULL;
+ runexit = false;
+ funcall(sig);
+ stat = getstatus();
+ }
+ exit(stat);
}
/* The signal handler for all functions. calls walk() */
static void fn_handler(int s) {
- char *sig[2];
- int olderrno;
- if (s < 1 || s >= NSIG)
- panic("unknown signal");
- olderrno = errno;
- sig[0] = signals[s].name;
- sig[1] = NULL;
- funcall(sig);
- errno = olderrno;
+ char *sig[2];
+ int olderrno;
+ if (s < 1 || s >= NSIG)
+ panic("unknown signal");
+ olderrno = errno;
+ sig[0] = signals[s].name;
+ sig[1] = NULL;
+ funcall(sig);
+ errno = olderrno;
}
/* A dud signal handler for SIGQUIT and SIGTERM */
*/
extern void fnassign(char *name, Node *def) {
- if (!name) return;
- Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */
- rc_Function *new = get_fn_place(name);
- int i;
- new->def = newdef;
- new->extdef = NULL;
- if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */
- if (streq(name, "sigexit"))
- runexit = true;
- for (i = 1; i < NSIG; i++) /* zero is a bogus signal */
- if (streq(signals[i].name, name)) {
- handlers[i] = newdef;
- if (def == NULL)
- rc_signal(i, SIG_IGN);
- else
- rc_signal(i, fn_handler);
- break;
- }
- }
+ if (!name) return;
+ Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */
+ rc_Function *new = get_fn_place(name);
+ int i;
+ new->def = newdef;
+ new->extdef = NULL;
+ if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */
+ if (streq(name, "sigexit"))
+ runexit = true;
+ for (i = 1; i < NSIG; i++) /* zero is a bogus signal */
+ if (streq(signals[i].name, name)) {
+ handlers[i] = newdef;
+ if (def == NULL)
+ rc_signal(i, SIG_IGN);
+ else
+ rc_signal(i, fn_handler);
+ break;
+ }
+ }
}
/* Assign a function from the environment. Store just the external representation */
extern void fnassign_string(char *extdef) {
- char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
- rc_Function *new;
- if (name == NULL)
- return;
- new = get_fn_place(name);
- new->def = NULL;
- new->extdef = ecpy(extdef);
+ char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
+ rc_Function *new;
+ if (name == NULL)
+ return;
+ new = get_fn_place(name);
+ new->def = NULL;
+ new->extdef = ecpy(extdef);
}
/* Return a function in Node form, evaluating an entry from the environment if necessary */
extern Node *fnlookup(char *name) {
- rc_Function *look = lookup_fn(name);
- Node *ret;
- if (look == NULL)
- return NULL; /* not found */
- if (look->def != NULL)
- return look->def;
- if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
- return &null;
- ret = parse_fn(look->extdef);
- if (ret == NULL) {
- efree(look->extdef);
- look->extdef = NULL;
- return &null;
- } else {
- return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */
- }
+ rc_Function *look = lookup_fn(name);
+ Node *ret;
+ if (look == NULL)
+ return NULL; /* not found */
+ if (look->def != NULL)
+ return look->def;
+ if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
+ return &null;
+ ret = parse_fn(look->extdef);
+ if (ret == NULL) {
+ efree(look->extdef);
+ look->extdef = NULL;
+ return &null;
+ } else {
+ return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */
+ }
}
/* Return a function in string form (used by makeenv) */
extern char *fnlookup_string(char *name) {
- rc_Function *look = lookup_fn(name);
+ rc_Function *look = lookup_fn(name);
- if (look == NULL)
- return NULL;
- if (look->extdef != NULL)
- return look->extdef;
- return look->extdef = mprint("fn_%F={%T}", name, look->def);
+ if (look == NULL)
+ return NULL;
+ if (look->extdef != NULL)
+ return look->extdef;
+ return look->extdef = mprint("fn_%F={%T}", name, look->def);
}
/*
*/
extern void fnrm(char *name) {
- int i;
- for (i = 1; i < NSIG; i++)
- if (signals[i].name && streq(signals[i].name, name)) {
- handlers[i] = NULL;
- switch (i) {
- case SIGINT:
- rc_signal(i, def_sigint);
- break;
- case SIGQUIT:
- rc_signal(i, def_sigquit);
- break;
- case SIGTERM:
- rc_signal(i, def_sigterm);
- break;
- default:
- rc_signal(i, SIG_DFL);
- }
- }
- if (streq(name, "sigexit"))
- runexit = false;
- delete_fn(name);
+ int i;
+ for (i = 1; i < NSIG; i++)
+ if (signals[i].name && streq(signals[i].name, name)) {
+ handlers[i] = NULL;
+ switch (i) {
+ case SIGINT:
+ rc_signal(i, def_sigint);
+ break;
+ case SIGQUIT:
+ rc_signal(i, def_sigquit);
+ break;
+ case SIGTERM:
+ rc_signal(i, def_sigterm);
+ break;
+ default:
+ rc_signal(i, SIG_DFL);
+ }
+ }
+ if (streq(name, "sigexit"))
+ runexit = false;
+ delete_fn(name);
}
extern void whatare_all_signals() {
- int i;
- for (i = 1; i < NSIG; i++)
- if (signals[i].name && *signals[i].name) {
- if (sighandlers[i] == SIG_IGN)
- fprint(1, "fn %s {}\n", signals[i].name);
- else if (sighandlers[i] == fn_handler)
- fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]);
- else
- fprint(1, "fn %s\n", signals[i].name);
- }
+ int i;
+ for (i = 1; i < NSIG; i++)
+ if (signals[i].name && *signals[i].name) {
+ if (sighandlers[i] == SIG_IGN)
+ fprint(1, "fn %s {}\n", signals[i].name);
+ else if (sighandlers[i] == fn_handler)
+ fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]);
+ else
+ fprint(1, "fn %s\n", signals[i].name);
+ }
}
extern void prettyprint_fn(int fd, char *name, Node *n) {
- fprint(fd, "fn %S {%T}\n", name, n);
+ fprint(fd, "fn %S {%T}\n", name, n);
}
#if PROTECT_ENV
static bool Fconv(Format *f, int ignore) {
- unsigned const char *s = va_arg(f->args, unsigned const char *);
- int c;
-
- while ((c = *s++) != '\0')
- if (dnw[c] || c == '*' || (c == '_' && *s == '_'))
- fmtprint(f, "__%02x", c);
- else
- fmtputc(f, c);
- return false;
+ unsigned const char *s = va_arg(f->args, unsigned const char *);
+ int c;
+
+ while ((c = *s++) != '\0')
+ if (dnw[c] || c == '*' || (c == '_' && *s == '_'))
+ fmtprint(f, "__%02x", c);
+ else
+ fmtputc(f, c);
+ return false;
}
#endif
/* convert a redirection to a printable form */
static bool Dconv(Format *f, int ignore) {
- const char *name = "?";
- int n = va_arg(f->args, int);
- switch (n) {
- case rCreate: name = ">"; break;
- case rAppend: name = ">>"; break;
- case rFrom: name = "<"; break;
- case rHeredoc: name = "<<"; break;
- case rHerestring: name = "<<<"; break;
- }
- fmtcat(f, name);
- return false;
+ const char *name = "?";
+ int n = va_arg(f->args, int);
+ switch (n) {
+ case rCreate: name = ">"; break;
+ case rAppend: name = ">>"; break;
+ case rFrom: name = "<"; break;
+ case rHeredoc: name = "<<"; break;
+ case rHerestring: name = "<<<"; break;
+ }
+ fmtcat(f, name);
+ return false;
}
/* defaultfd -- return the default fd for a given redirection operation */
static int defaultfd(int op) {
- return (op == rCreate || op == rAppend) ? 1 : 0;
+ return (op == rCreate || op == rAppend) ? 1 : 0;
}
/* convert a function in Node * form into something rc can parse (and humans can read?) */
static bool Tconv(Format *f, int ignore) {
- bool dollar = f->flags & FMT_altform;
- Node *n = va_arg(f->args, Node *);
-
- if (n == NULL) {
- fmtprint(f, "()");
- return false;
- }
- switch (n->type) {
- case nBang: fmtprint(f, "!%T", n->u[0].p); break;
- case nCase: fmtprint(f, "case %T", n->u[0].p); break;
- case nNowait: fmtprint(f, "%T&", n->u[0].p); break;
- case nRmfn: fmtprint(f, "fn %T", n->u[0].p); break;
- case nSubshell: fmtprint(f, "@ %T", n->u[0].p); break;
- case nAndalso: fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p); break;
- case nAssign: fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p); break;
- case nConcat: fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p); break;
- case nElse: fmtprint(f, "{%T}else %T", n->u[0].p, n->u[1].p); break;
- case nNewfn: fmtprint(f, "fn %T {%T}", n->u[0].p, n->u[1].p); break;
- case nIf: fmtprint(f, "if(%T)%T", n->u[0].p, n->u[1].p); break;
- case nOrelse: fmtprint(f, "%T||%T", n->u[0].p, n->u[1].p); break;
- case nArgs: fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); break;
- case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break;
- case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break;
- case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break;
- case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
- case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break;
- case nWord:
- fmtprint(f, n->u[2].i && quotep(n->u[0].s, dollar) ?
- "%#S" : "%S", n->u[0].s);
- break;
- case nLappend: {
- static bool inlist;
- if (!inlist) {
- inlist = true;
- fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p);
- inlist = false;
- } else {
- fmtprint(f, "%T %T", n->u[0].p, n->u[1].p);
- }
- break;
- }
- case nCount: case nFlat: case nVar: {
- char *lp = "", *rp = "";
- Node *n0 = n->u[0].p;
-
- if (n0->type != nWord)
- lp = "(", rp = ")";
-
- switch (n->type) {
- default: panic("this can't happen"); break;
- case nCount: fmtprint(f, "$#%s%#T%s", lp, n0, rp); break;
- case nFlat: fmtprint(f, "$^%s%#T%s", lp, n0, rp); break;
- case nVar: fmtprint(f, "$%s%#T%s", lp, n0, rp); break;
- }
- break;
- }
- case nDup:
- if (n->u[2].i != -1)
- fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
- else
- fmtprint(f, "%D[%d=]", n->u[0].i, n->u[1].i);
- break;
- case nBackq: {
- Node *n0 = n->u[0].p, *n00;
- if (n0 != NULL && n0->type == nVar
- && (n00 = n0->u[0].p) != NULL && n00->type == nWord && streq(n00->u[0].s, "ifs"))
- fmtprint(f, "`");
- else
- fmtprint(f, "``%T", n0);
- fmtprint(f, "{%T}", n->u[1].p);
- break;
- }
- case nCbody:
- case nBody: {
- Node *n0 = n->u[0].p;
- if (n0 != NULL)
- fmtprint(f, "%T", n->u[0].p);
- if (n->u[1].p != NULL) {
- if (n0 != NULL && n0->type != nNowait)
- fmtprint(f, ";");
- fmtprint(f, "%T", n->u[1].p);
- }
- break;
- }
- case nBrace:
- fmtprint(f, "{%T}", n->u[0].p);
- if (n->u[1].p != NULL)
- fmtprint(f, "%T", n->u[1].p);
- break;
- case nEpilog:
- case nPre:
- fmtprint(f, "%T", n->u[0].p);
- if (n->u[1].p != NULL)
- fmtprint(f, " %T", n->u[1].p);
- break;
- case nPipe: {
- int ofd = n->u[0].i, ifd = n->u[1].i;
- fmtprint(f, "%T|", n->u[2].p);
- if (ifd != 0)
- fmtprint(f, "[%d=%d]", ofd, ifd);
- else if (ofd != 1)
- fmtprint(f, "[%d]", ofd);
- fmtprint(f, "%T", n->u[3].p);
- break;
- }
- case nRedir: {
- int op = n->u[0].i;
- fmtprint(f, "%D", op);
- if (n->u[1].i != defaultfd(op))
- fmtprint(f, "[%d]", n->u[1].i);
- fmtprint(f, "%T", n->u[2].p);
- break;
- }
- case nNmpipe: {
- int op = n->u[0].i;
- fmtprint(f, "%D", op);
- if (n->u[1].i != defaultfd(op))
- fmtprint(f, "[%d]", n->u[1].i);
- fmtprint(f, "{%T}", n->u[2].p);
- break;
- }
- }
- return false;
+ bool dollar = f->flags & FMT_altform;
+ Node *n = va_arg(f->args, Node *);
+
+ if (n == NULL) {
+ fmtprint(f, "()");
+ return false;
+ }
+ switch (n->type) {
+ case nBang: fmtprint(f, "!%T", n->u[0].p); break;
+ case nCase: fmtprint(f, "case %T", n->u[0].p); break;
+ case nNowait: fmtprint(f, "%T&", n->u[0].p); break;
+ case nRmfn: fmtprint(f, "fn %T", n->u[0].p); break;
+ case nSubshell: fmtprint(f, "@ %T", n->u[0].p); break;
+ case nAndalso: fmtprint(f, "%T&&%T", n->u[0].p, n->u[1].p); break;
+ case nAssign: fmtprint(f, "%T=%T", n->u[0].p, n->u[1].p); break;
+ case nConcat: fmtprint(f, "%T^%T", n->u[0].p, n->u[1].p); break;
+ case nElse: fmtprint(f, "{%T}else %T", n->u[0].p, n->u[1].p); break;
+ case nNewfn: fmtprint(f, "fn %T {%T}", n->u[0].p, n->u[1].p); break;
+ case nIf: fmtprint(f, "if(%T)%T", n->u[0].p, n->u[1].p); break;
+ case nOrelse: fmtprint(f, "%T||%T", n->u[0].p, n->u[1].p); break;
+ case nArgs: fmtprint(f, "%T %T", n->u[0].p, n->u[1].p); break;
+ case nSwitch: fmtprint(f, "switch(%T){%T}", n->u[0].p, n->u[1].p); break;
+ case nMatch: fmtprint(f, "~ %T %T", n->u[0].p, n->u[1].p); break;
+ case nWhile: fmtprint(f, "while(%T)%T", n->u[0].p, n->u[1].p); break;
+ case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
+ case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break;
+ case nWord:
+ fmtprint(f, n->u[2].i && quotep(n->u[0].s, dollar) ?
+ "%#S" : "%S", n->u[0].s);
+ break;
+ case nLappend: {
+ static bool inlist;
+ if (!inlist) {
+ inlist = true;
+ fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p);
+ inlist = false;
+ } else {
+ fmtprint(f, "%T %T", n->u[0].p, n->u[1].p);
+ }
+ break;
+ }
+ case nCount: case nFlat: case nVar: {
+ char *lp = "", *rp = "";
+ Node *n0 = n->u[0].p;
+
+ if (n0->type != nWord)
+ lp = "(", rp = ")";
+
+ switch (n->type) {
+ default: panic("this can't happen"); break;
+ case nCount: fmtprint(f, "$#%s%#T%s", lp, n0, rp); break;
+ case nFlat: fmtprint(f, "$^%s%#T%s", lp, n0, rp); break;
+ case nVar: fmtprint(f, "$%s%#T%s", lp, n0, rp); break;
+ }
+ break;
+ }
+ case nDup:
+ if (n->u[2].i != -1)
+ fmtprint(f, "%D[%d=%d]", n->u[0].i, n->u[1].i, n->u[2].i);
+ else
+ fmtprint(f, "%D[%d=]", n->u[0].i, n->u[1].i);
+ break;
+ case nBackq: {
+ Node *n0 = n->u[0].p, *n00;
+ if (n0 != NULL && n0->type == nVar
+ && (n00 = n0->u[0].p) != NULL && n00->type == nWord && streq(n00->u[0].s, "ifs"))
+ fmtprint(f, "`");
+ else
+ fmtprint(f, "``%T", n0);
+ fmtprint(f, "{%T}", n->u[1].p);
+ break;
+ }
+ case nCbody:
+ case nBody: {
+ Node *n0 = n->u[0].p;
+ if (n0 != NULL)
+ fmtprint(f, "%T", n->u[0].p);
+ if (n->u[1].p != NULL) {
+ if (n0 != NULL && n0->type != nNowait)
+ fmtprint(f, ";");
+ fmtprint(f, "%T", n->u[1].p);
+ }
+ break;
+ }
+ case nBrace:
+ fmtprint(f, "{%T}", n->u[0].p);
+ if (n->u[1].p != NULL)
+ fmtprint(f, "%T", n->u[1].p);
+ break;
+ case nEpilog:
+ case nPre:
+ fmtprint(f, "%T", n->u[0].p);
+ if (n->u[1].p != NULL)
+ fmtprint(f, " %T", n->u[1].p);
+ break;
+ case nPipe: {
+ int ofd = n->u[0].i, ifd = n->u[1].i;
+ fmtprint(f, "%T|", n->u[2].p);
+ if (ifd != 0)
+ fmtprint(f, "[%d=%d]", ofd, ifd);
+ else if (ofd != 1)
+ fmtprint(f, "[%d]", ofd);
+ fmtprint(f, "%T", n->u[3].p);
+ break;
+ }
+ case nRedir: {
+ int op = n->u[0].i;
+ fmtprint(f, "%D", op);
+ if (n->u[1].i != defaultfd(op))
+ fmtprint(f, "[%d]", n->u[1].i);
+ fmtprint(f, "%T", n->u[2].p);
+ break;
+ }
+ case nNmpipe: {
+ int op = n->u[0].i;
+ fmtprint(f, "%D", op);
+ if (n->u[1].i != defaultfd(op))
+ fmtprint(f, "[%d]", n->u[1].i);
+ fmtprint(f, "{%T}", n->u[2].p);
+ break;
+ }
+ }
+ return false;
}
/* convert a List to an array, for execve() */
extern char **list2array(List *s, bool print) {
- char **argv, **av;
-
- if (print)
- fprint(2, "%L\n", s, " ");
- /*
- Allocate 3 extra spots (2 for the fake execve & 1 for defaulting to
- sh) and hide these from exec().
- */
- argv = av = (char **) nalloc((listnel(s) + 4) * sizeof *av) + 3;
- while (s != NULL) {
- *av++ = s->w;
- s = s->n;
- }
- *av = NULL;
- return argv;
+ char **argv, **av;
+
+ if (print)
+ fprint(2, "%L\n", s, " ");
+ /*
+ Allocate 3 extra spots (2 for the fake execve & 1 for defaulting to
+ sh) and hide these from exec().
+ */
+ argv = av = (char **) nalloc((listnel(s) + 4) * sizeof *av) + 3;
+ while (s != NULL) {
+ *av++ = s->w;
+ s = s->n;
+ }
+ *av = NULL;
+ return argv;
}
/* figure out the name of a variable given an environment string. */
extern char *get_name(char *s) {
- char *eq = strchr(s, '=');
- char *r, *result;
- int c;
-
- if (eq == NULL)
- return NULL;
- r = result = nalloc(eq - s + 1);
- while (1)
- switch (c = *s++) {
- case '=':
- *r++ = '\0';
- return result;
+ char *eq = strchr(s, '=');
+ char *r, *result;
+ int c;
+
+ if (eq == NULL)
+ return NULL;
+ r = result = nalloc(eq - s + 1);
+ while (1)
+ switch (c = *s++) {
+ case '=':
+ *r++ = '\0';
+ return result;
#if PROTECT_ENV
- case '_':
- if (*s == '_') {
- static const char hexchar[] = "0123456789abcdef";
- char *h1 = strchr(hexchar, s[1]);
- char *h2 = strchr(hexchar, s[2]);
- if (h1 != NULL && h2 != NULL) {
- *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar);
- s += 3;
- break;
- }
- }
- /* FALLTHROUGH */
+ case '_':
+ if (*s == '_') {
+ static const char hexchar[] = "0123456789abcdef";
+ char *h1 = strchr(hexchar, s[1]);
+ char *h2 = strchr(hexchar, s[2]);
+ if (h1 != NULL && h2 != NULL) {
+ *r++ = ((h1 - hexchar) << 4) | (h2 - hexchar);
+ s += 3;
+ break;
+ }
+ }
+ /* FALLTHROUGH */
#endif
- default:
- *r++ = c;
- break;
- }
+ default:
+ *r++ = c;
+ break;
+ }
}
/* interpret a variable from environment. ^A separates list elements;
by anything other than ^A or ^B is preserved. */
extern List *parse_var(char *extdef) {
- char *begin, *end, *from, *to;
- int len;
- List *first, *last, *new;
-
- first = last = NULL;
- begin = strchr(extdef, '=');
- assert(begin); /* guaranteed by initenv() */
- while (*begin) {
- ++begin;
- end = begin;
- len = 0;
- while (*end != ENV_SEP && *end != '\0') {
- if (*end == ENV_ESC) {
- ++end;
- if (*end != ENV_SEP && *end != ENV_ESC) --end;
- }
- ++end; ++len;
- }
- new = enew(List);
- if (last)
- last->n = new;
- else
- first = new;
- last = new;
- new->w = ealloc(len + 1);
- new->m = NULL;
- new->n = NULL;
- to = new->w;
- for (from = begin; from < end; ++from) {
- if (*from == ENV_ESC) {
- ++from;
- if (*from != ENV_SEP && *from != ENV_ESC)
- --from;
- }
- *to = *from;
- ++to;
- }
- *to = '\0';
- begin = end;
- }
- return first;
+ char *begin, *end, *from, *to;
+ int len;
+ List *first, *last, *new;
+
+ first = last = NULL;
+ begin = strchr(extdef, '=');
+ assert(begin); /* guaranteed by initenv() */
+ while (*begin) {
+ ++begin;
+ end = begin;
+ len = 0;
+ while (*end != ENV_SEP && *end != '\0') {
+ if (*end == ENV_ESC) {
+ ++end;
+ if (*end != ENV_SEP && *end != ENV_ESC) --end;
+ }
+ ++end; ++len;
+ }
+ new = enew(List);
+ if (last)
+ last->n = new;
+ else
+ first = new;
+ last = new;
+ new->w = ealloc(len + 1);
+ new->m = NULL;
+ new->n = NULL;
+ to = new->w;
+ for (from = begin; from < end; ++from) {
+ if (*from == ENV_ESC) {
+ ++from;
+ if (*from != ENV_SEP && *from != ENV_ESC)
+ --from;
+ }
+ *to = *from;
+ ++to;
+ }
+ *to = '\0';
+ begin = end;
+ }
+ return first;
}
/* get an environment entry for a function and have rc parse it. */
#define PREFIX "fn x"
#define PRELEN conststrlen(PREFIX)
extern Node *parse_fn(char *extdef) {
- Node *def;
- char *s, old[PRELEN];
- if ((s = strchr(extdef, '=')) == NULL)
- return NULL;
- memcpy(old, s -= (PRELEN-1), PRELEN);
- memcpy(s, PREFIX, PRELEN);
- def = parseline(s);
- memcpy(s, old, PRELEN);
- return (def == NULL || def->type != nNewfn) ? NULL : def->u[1].p;
+ Node *def;
+ char *s, old[PRELEN];
+ if ((s = strchr(extdef, '=')) == NULL)
+ return NULL;
+ memcpy(old, s -= (PRELEN-1), PRELEN);
+ memcpy(s, PREFIX, PRELEN);
+ def = parseline(s);
+ memcpy(s, old, PRELEN);
+ return (def == NULL || def->type != nNewfn) ? NULL : def->u[1].p;
}
static bool Aconv(Format *f, int ignore) {
- char **a = va_arg(f->args, char **);
- if (*a != NULL) {
- fmtcat(f, *a);
- while (*++a != NULL)
- fmtprint(f, " %s", *a);
- }
- return false;
+ char **a = va_arg(f->args, char **);
+ if (*a != NULL) {
+ fmtcat(f, *a);
+ while (*++a != NULL)
+ fmtprint(f, " %s", *a);
+ }
+ return false;
}
/* %L -- print a list */
static bool Lconv(Format *f, int ignore) {
- bool plain;
- char *sep;
- List *l, *n;
-
- plain = f->flags & FMT_leftside;
- l = va_arg(f->args, List *);
- sep = va_arg(f->args, char *);
- if (l == NULL && (f->flags & FMT_leftside) == 0)
- fmtprint(f, "()");
- else {
- for (; l != NULL; l = n) {
- n = l->n;
- fmtprint(f, plain ? "%s" : "%-S", l->w);
- if (n != NULL) fmtputc(f, *sep);
- }
- }
- return false;
+ bool plain;
+ char *sep;
+ List *l, *n;
+
+ plain = f->flags & FMT_leftside;
+ l = va_arg(f->args, List *);
+ sep = va_arg(f->args, char *);
+ if (l == NULL && (f->flags & FMT_leftside) == 0)
+ fmtprint(f, "()");
+ else {
+ for (; l != NULL; l = n) {
+ n = l->n;
+ fmtprint(f, plain ? "%s" : "%-S", l->w);
+ if (n != NULL) fmtputc(f, *sep);
+ }
+ }
+ return false;
}
/* %W -- print a list for exporting */
static bool Wconv(Format *f, int ignore) {
- List *l, *n;
-
- l = va_arg(f->args, List *);
- for (; l != NULL; l = n) {
- char c, *s;
-
- for (s = l->w; (c = *s) != '\0'; ++s) {
- if (c == ENV_SEP || c == ENV_ESC)
- fmtputc(f, ENV_ESC);
- fmtputc(f, c);
- }
- n = l->n;
- if (n != NULL) fmtputc(f, ENV_SEP);
- }
- return false;
+ List *l, *n;
+
+ l = va_arg(f->args, List *);
+ for (; l != NULL; l = n) {
+ char c, *s;
+
+ for (s = l->w; (c = *s) != '\0'; ++s) {
+ if (c == ENV_SEP || c == ENV_ESC)
+ fmtputc(f, ENV_ESC);
+ fmtputc(f, c);
+ }
+ n = l->n;
+ if (n != NULL) fmtputc(f, ENV_SEP);
+ }
+ return false;
}
-#define ISMETA(c) (c == '*' || c == '?' || c == '[')
+#define ISMETA(c) (c == '*' || c == '?' || c == '[')
static bool Sconv(Format *f, int ignore) {
- int c;
- unsigned char *s = va_arg(f->args, unsigned char *), *t = s;
- bool quoted = (f->flags & FMT_altform) != 0; /* '#' */
- bool metaquote = (f->flags & FMT_leftside) != 0; /* '-' */
- if (*s == '\0') {
- fmtprint(f, "''");
- return false;
- }
- if (!quoted) {
- while ((c = *t++) != '\0')
- if (nw[c] == 1 || (metaquote && ISMETA(c)))
- goto quoteit;
- fmtprint(f, "%s", s);
- return false;
- }
+ int c;
+ unsigned char *s = va_arg(f->args, unsigned char *), *t = s;
+ bool quoted = (f->flags & FMT_altform) != 0; /* '#' */
+ bool metaquote = (f->flags & FMT_leftside) != 0; /* '-' */
+ if (*s == '\0') {
+ fmtprint(f, "''");
+ return false;
+ }
+ if (!quoted) {
+ while ((c = *t++) != '\0')
+ if (nw[c] == 1 || (metaquote && ISMETA(c)))
+ goto quoteit;
+ fmtprint(f, "%s", s);
+ return false;
+ }
quoteit:
- fmtputc(f, '\'');
- while ((c = *s++) != '\0') {
- fmtputc(f, c);
- if (c == '\'')
- fmtputc(f, '\'');
-
- }
- fmtputc(f, '\'');
- return false;
+ fmtputc(f, '\'');
+ while ((c = *s++) != '\0') {
+ fmtputc(f, c);
+ if (c == '\'')
+ fmtputc(f, '\'');
+
+ }
+ fmtputc(f, '\'');
+ return false;
}
void initprint(void) {
- fmtinstall('A', Aconv);
- fmtinstall('L', Lconv);
- fmtinstall('S', Sconv);
- fmtinstall('T', Tconv);
- fmtinstall('D', Dconv);
- fmtinstall('W', Wconv);
-#if PROTECT_ENV
- fmtinstall('F', Fconv);
-#else
- fmtinstall('F', fmtinstall('s', NULL));
-#endif
+ fmtinstall('A', Aconv);
+ fmtinstall('L', Lconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('T', Tconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('W', Wconv);
+ fmtinstall('F', Fconv);
+ fmtinstall('F', fmtinstall('s', NULL));
}
*/
extern bool lmatch(List *s, List *p) {
- List *q;
- if (s == NULL) {
- if (p == NULL) /* null matches null */
- return true;
- for (; p != NULL; p = p->n) /* one or more stars match null */
- if (strspn(p->w, "*") == strlen(p->w) &&
- p->m != NULL && strlen(p->m) == strlen(p->w))
- return true;
- return false;
- }
- for (; s != NULL; s = s->n)
- for (q = p; q != NULL; q = q->n)
- if (match(q->w, q->m, s->w))
- return true;
- return false;
+ List *q;
+ if (s == NULL) {
+ if (p == NULL) /* null matches null */
+ return true;
+ for (; p != NULL; p = p->n) /* one or more stars match null */
+ if (strspn(p->w, "*") == strlen(p->w) &&
+ p->m != NULL && strlen(p->m) == strlen(p->w))
+ return true;
+ return false;
+ }
+ for (; s != NULL; s = s->n)
+ for (q = p; q != NULL; q = q->n)
+ if (match(q->w, q->m, s->w))
+ return true;
+ return false;
}
/*
*/
extern List *glob(List *s) {
- List *top, *r;
- bool meta;
- for (r = s, meta = false; r != NULL; r = r->n)
- if (r->m != NULL)
- meta = true;
- if (!meta)
- return s; /* don't copy lists with no metacharacters in them */
- for (top = r = NULL; s != NULL; s = s->n) {
- if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
- if (top == NULL)
- top = r = nnew(List);
- else
- r = r->n = nnew(List);
- r->w = s->w;
- } else {
- if (top == NULL)
- top = r = sort(doglob(s->w, s->m));
- else
- r->n = sort(doglob(s->w, s->m));
- while (r->n != NULL)
- r = r->n;
- }
- }
- r->n = NULL;
- return top;
+ List *top, *r;
+ bool meta;
+ for (r = s, meta = false; r != NULL; r = r->n)
+ if (r->m != NULL)
+ meta = true;
+ if (!meta)
+ return s; /* don't copy lists with no metacharacters in them */
+ for (top = r = NULL; s != NULL; s = s->n) {
+ if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
+ if (top == NULL)
+ top = r = nnew(List);
+ else
+ r = r->n = nnew(List);
+ r->w = s->w;
+ } else {
+ if (top == NULL)
+ top = r = sort(doglob(s->w, s->m));
+ else
+ r->n = sort(doglob(s->w, s->m));
+ while (r->n != NULL)
+ r = r->n;
+ }
+ }
+ r->n = NULL;
+ return top;
}
/* Matches a pattern p against the contents of directory d */
static List *dmatch(char *d, char *p, char *m) {
- bool matched;
- List *top, *r;
- static DIR *dirp;
- static struct dirent *dp;
- static struct stat s;
- int i;
-
- /*
- return a match if there are no metacharacters; allows globbing through
- directories with no read permission. make sure the file exists, though.
- */
- matched = true;
- if (m != NULL)
- for (i = 0; p[i] != '\0'; i++)
- if (m[i]) {
- matched = false;
- break;
- }
-
- if (matched) {
- char *path = nprint("%s/%s", d, p);
- if (lstat(path, &s) < 0)
- return NULL;
- r = nnew(List);
- r->w = ncpy(p);
- r->m = NULL;
- r->n = NULL;
- return r;
- }
-
- top = r = NULL;
- if (*d == '\0') d = "/";
- if ((dirp = opendir(d)) == NULL)
- return NULL;
- /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
- if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR) {
- closedir(dirp);
- return NULL;
- }
- while ((dp = readdir(dirp)) != NULL)
- if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
- matched = true;
- if (top == NULL)
- top = r = nnew(List);
- else
- r = r->n = nnew(List);
- r->w = ncpy(dp->d_name);
- r->m = NULL;
- }
- closedir(dirp);
- if (!matched)
- return NULL;
- r->n = NULL;
- return top;
+ bool matched;
+ List *top, *r;
+ static DIR *dirp;
+ static struct dirent *dp;
+ static struct stat s;
+ int i;
+
+ /*
+ return a match if there are no metacharacters; allows globbing through
+ directories with no read permission. make sure the file exists, though.
+ */
+ matched = true;
+ if (m != NULL)
+ for (i = 0; p[i] != '\0'; i++)
+ if (m[i]) {
+ matched = false;
+ break;
+ }
+
+ if (matched) {
+ char *path = nprint("%s/%s", d, p);
+ if (lstat(path, &s) < 0)
+ return NULL;
+ r = nnew(List);
+ r->w = ncpy(p);
+ r->m = NULL;
+ r->n = NULL;
+ return r;
+ }
+
+ top = r = NULL;
+ if (*d == '\0') d = "/";
+ if ((dirp = opendir(d)) == NULL)
+ return NULL;
+ /* opendir succeeds on regular files on some systems, so the stat() call is necessary (sigh) */
+ if (stat(d, &s) < 0 || (s.st_mode & S_IFMT) != S_IFDIR) {
+ closedir(dirp);
+ return NULL;
+ }
+ while ((dp = readdir(dirp)) != NULL)
+ if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
+ matched = true;
+ if (top == NULL)
+ top = r = nnew(List);
+ else
+ r = r->n = nnew(List);
+ r->w = ncpy(dp->d_name);
+ r->m = NULL;
+ }
+ closedir(dirp);
+ if (!matched)
+ return NULL;
+ r->n = NULL;
+ return top;
}
/*
*/
static List *lglob(List *s, char *p, char *m, size_t slashcount) {
- List *q, *r, *top, foo;
- static struct {
- List l;
- size_t size;
- } slash;
- if (slashcount+1 > slash.size) {
- slash.size = 2*(slashcount+1);
- slash.l.w = erealloc(slash.l.w, slash.size);
- }
- slash.l.w[slashcount] = '\0';
- while (slashcount > 0)
- slash.l.w[--slashcount] = '/';
- for (top = r = NULL; s != NULL; s = s->n) {
- q = dmatch(s->w, p, m);
- if (q != NULL) {
- foo.w = s->w;
- foo.m = NULL;
- foo.n = NULL;
- if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
- q = concat(&slash.l, q); /* dir/name with slash */
- q = concat(&foo, q);
- if (r == NULL)
- top = r = q;
- else
- r->n = q;
- while (r->n != NULL)
- r = r->n;
- }
- }
- return top;
+ List *q, *r, *top, foo;
+ static struct {
+ List l;
+ size_t size;
+ } slash;
+ if (slashcount+1 > slash.size) {
+ slash.size = 2*(slashcount+1);
+ slash.l.w = erealloc(slash.l.w, slash.size);
+ }
+ slash.l.w[slashcount] = '\0';
+ while (slashcount > 0)
+ slash.l.w[--slashcount] = '/';
+ for (top = r = NULL; s != NULL; s = s->n) {
+ q = dmatch(s->w, p, m);
+ if (q != NULL) {
+ foo.w = s->w;
+ foo.m = NULL;
+ foo.n = NULL;
+ if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
+ q = concat(&slash.l, q); /* dir/name with slash */
+ q = concat(&foo, q);
+ if (r == NULL)
+ top = r = q;
+ else
+ r->n = q;
+ while (r->n != NULL)
+ r = r->n;
+ }
+ }
+ return top;
}
/*
*/
static List *doglob(char *w, char *m) {
- static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
- static size_t dsize = 0;
- char *d, *p, *md, *mp;
- size_t psize;
- char *s = w;
- List firstdir;
- List *matched;
- if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
- efree(dir); efree(pattern); efree(metadir); efree(metapattern);
- dir = ealloc(psize);
- pattern = ealloc(psize);
- metadir = ealloc(psize);
- metapattern = ealloc(psize);
- dsize = psize;
- }
- d = dir;
- p = pattern;
- md = metadir;
- mp = metapattern;
- while (*s != '/' && *s != '\0') {
- *d++ = *s++; /* get first directory component */
- *md++ = *m++;
- }
- *d = '\0';
- /*
- Special case: no slashes in the pattern, i.e., open the current directory.
- Remember that w cannot consist of slashes alone (the other way *s could be
- zero) since doglob gets called iff there's a metacharacter to be matched
- */
- if (*s == '\0') {
- matched = dmatch(".", dir, metadir);
- goto end;
- }
- if (*w == '/') {
- firstdir.w = dir;
- firstdir.m = metadir;
- firstdir.n = NULL;
- matched = &firstdir;
- } else {
- /*
- we must glob against current directory,
- since the first character is not a slash.
- */
- matched = dmatch(".", dir, metadir);
- }
- do {
- size_t slashcount;
- sigchk();
- for (slashcount = 0; *s == '/'; s++, m++)
- slashcount++; /* skip slashes */
- while (*s != '/' && *s != '\0')
- *p++ = *s++, *mp++ = *m++; /* get pattern */
- *p = '\0';
- matched = lglob(matched, pattern, metapattern, slashcount);
- p = pattern, mp = metapattern;
- } while (*s != '\0');
-end: if (matched == NULL) {
- matched = nnew(List);
- matched->w = w;
- matched->m = NULL;
- matched->n = NULL;
- }
- return matched;
+ static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
+ static size_t dsize = 0;
+ char *d, *p, *md, *mp;
+ size_t psize;
+ char *s = w;
+ List firstdir;
+ List *matched;
+ if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
+ efree(dir); efree(pattern); efree(metadir); efree(metapattern);
+ dir = ealloc(psize);
+ pattern = ealloc(psize);
+ metadir = ealloc(psize);
+ metapattern = ealloc(psize);
+ dsize = psize;
+ }
+ d = dir;
+ p = pattern;
+ md = metadir;
+ mp = metapattern;
+ while (*s != '/' && *s != '\0') {
+ *d++ = *s++; /* get first directory component */
+ *md++ = *m++;
+ }
+ *d = '\0';
+ /*
+ Special case: no slashes in the pattern, i.e., open the current directory.
+ Remember that w cannot consist of slashes alone (the other way *s could be
+ zero) since doglob gets called iff there's a metacharacter to be matched
+ */
+ if (*s == '\0') {
+ matched = dmatch(".", dir, metadir);
+ goto end;
+ }
+ if (*w == '/') {
+ firstdir.w = dir;
+ firstdir.m = metadir;
+ firstdir.n = NULL;
+ matched = &firstdir;
+ } else {
+ /*
+ we must glob against current directory,
+ since the first character is not a slash.
+ */
+ matched = dmatch(".", dir, metadir);
+ }
+ do {
+ size_t slashcount;
+ sigchk();
+ for (slashcount = 0; *s == '/'; s++, m++)
+ slashcount++; /* skip slashes */
+ while (*s != '/' && *s != '\0')
+ *p++ = *s++, *mp++ = *m++; /* get pattern */
+ *p = '\0';
+ matched = lglob(matched, pattern, metapattern, slashcount);
+ p = pattern, mp = metapattern;
+ } while (*s != '\0');
+end: if (matched == NULL) {
+ matched = nnew(List);
+ matched->w = w;
+ matched->m = NULL;
+ matched->n = NULL;
+ }
+ return matched;
}
static List *sort(List *s) {
- size_t nel = listnel(s);
- if (nel > 1) {
- char **a;
- List *t;
- qsort(a = list2array(s, false), nel, sizeof(char *), starstrcmp);
- for (t = s; t != NULL; t = t->n)
- t->w = *a++;
- }
- return s;
+ size_t nel = listnel(s);
+ if (nel > 1) {
+ char **a;
+ List *t;
+ qsort(a = list2array(s, false), nel, sizeof(char *), starstrcmp);
+ for (t = s; t != NULL; t = t->n)
+ t->w = *a++;
+ }
+ return s;
}
Rq *redirq = NULL;
extern List *word(char *w, char *m) {
- List *s = NULL;
- if (w != NULL) {
- s = nnew(List);
- s->w = w;
- s->m = m;
- s->n = NULL;
- }
- return s;
+ List *s = NULL;
+ if (w != NULL) {
+ s = nnew(List);
+ s->w = w;
+ s->m = m;
+ s->n = NULL;
+ }
+ return s;
}
/*
*/
extern List *append(List *s1, List *s2) {
- List *r, *top;
- if (s1 == NULL)
- return s2;
- if (s2 == NULL)
- return s1;
- for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
- r->w = s1->w;
- r->m = s1->m;
- if ((s1 = s1->n) == NULL)
- break;
- }
- r->n = s2;
- return top;
+ List *r, *top;
+ if (s1 == NULL)
+ return s2;
+ if (s2 == NULL)
+ return s1;
+ for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
+ r->w = s1->w;
+ r->m = s1->m;
+ if ((s1 = s1->n) == NULL)
+ break;
+ }
+ r->n = s2;
+ return top;
}
extern List *concat(List *s1, List *s2) {
- int n1, n2;
- List *r, *top;
- if (s1 == NULL)
- return s2;
- if (s2 == NULL)
- return s1;
- if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1)
- rc_error("bad concatenation");
- for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
- size_t x = strlen(s1->w);
- size_t y = strlen(s2->w);
- size_t z = x + y + 1;
- r->w = nalloc(z);
- strcpy(r->w, s1->w);
- strcat(r->w, s2->w);
- if (s1->m == NULL && s2->m == NULL) {
- r->m = NULL;
- } else {
- r->m = nalloc(z);
- if (s1->m == NULL)
- memzero(r->m, x);
- else
- memcpy(r->m, s1->m, x);
- if (s2->m == NULL)
- memzero(&r->m[x], y);
- else
- memcpy(&r->m[x], s2->m, y);
- r->m[z] = 0;
- }
- if (n1 > 1)
- s1 = s1->n;
- if (n2 > 1)
- s2 = s2->n;
- if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1))
- break;
- }
- r->n = NULL;
- return top;
+ int n1, n2;
+ List *r, *top;
+ if (s1 == NULL)
+ return s2;
+ if (s2 == NULL)
+ return s1;
+ if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1)
+ rc_error("bad concatenation");
+ for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
+ size_t x = strlen(s1->w);
+ size_t y = strlen(s2->w);
+ size_t z = x + y + 1;
+ r->w = nalloc(z);
+ strcpy(r->w, s1->w);
+ strcat(r->w, s2->w);
+ if (s1->m == NULL && s2->m == NULL) {
+ r->m = NULL;
+ } else {
+ r->m = nalloc(z);
+ if (s1->m == NULL)
+ memzero(r->m, x);
+ else
+ memcpy(r->m, s1->m, x);
+ if (s2->m == NULL)
+ memzero(&r->m[x], y);
+ else
+ memcpy(&r->m[x], s2->m, y);
+ r->m[z] = 0;
+ }
+ if (n1 > 1)
+ s1 = s1->n;
+ if (n2 > 1)
+ s2 = s2->n;
+ if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1))
+ break;
+ }
+ r->n = NULL;
+ return top;
}
extern List *varsub(List *var, List *subs) {
- List *r, *top;
- int n = listnel(var);
- for (top = r = NULL; subs != NULL; subs = subs->n) {
- int i = a2u(subs->w);
- if (i < 1)
- rc_error("bad subscript");
- if (i <= n) {
- List *sub = var;
- while (--i)
- sub = sub->n; /* loop until sub == var(i) */
- if (top == NULL)
- top = r = nnew(List);
- else
- r = r->n = nnew(List);
- r->w = sub->w;
- r->m = sub->m;
- }
- }
- if (top != NULL)
- r->n = NULL;
- return top;
+ List *r, *top;
+ int n = listnel(var);
+ for (top = r = NULL; subs != NULL; subs = subs->n) {
+ int i = a2u(subs->w);
+ if (i < 1)
+ rc_error("bad subscript");
+ if (i <= n) {
+ List *sub = var;
+ while (--i)
+ sub = sub->n; /* loop until sub == var(i) */
+ if (top == NULL)
+ top = r = nnew(List);
+ else
+ r = r->n = nnew(List);
+ r->w = sub->w;
+ r->m = sub->m;
+ }
+ }
+ if (top != NULL)
+ r->n = NULL;
+ return top;
}
extern List *flatten(List *s) {
- List *r;
- size_t step;
- char *f;
- if (s == NULL || s->n == NULL)
- return s;
- r = nnew(List);
- f = r->w = nalloc(listlen(s) + 1);
- r->m = NULL; /* flattened lists come from variables, so no meta */
- r->n = NULL;
- strcpy(f, s->w);
- f += strlen(s->w);
- do {
- *f++ = ' ';
- s = s->n;
- step = strlen(s->w);
- memcpy(f, s->w, step);
- f += step;
- } while (s->n != NULL);
- *f = '\0';
- return r;
+ List *r;
+ size_t step;
+ char *f;
+ if (s == NULL || s->n == NULL)
+ return s;
+ r = nnew(List);
+ f = r->w = nalloc(listlen(s) + 1);
+ r->m = NULL; /* flattened lists come from variables, so no meta */
+ r->n = NULL;
+ strcpy(f, s->w);
+ f += strlen(s->w);
+ do {
+ *f++ = ' ';
+ s = s->n;
+ step = strlen(s->w);
+ memcpy(f, s->w, step);
+ f += step;
+ } while (s->n != NULL);
+ *f = '\0';
+ return r;
}
static List *count(List *l) {
- List *s = nnew(List);
- s->w = nprint("%d", listnel(l));
- s->n = NULL;
- s->m = NULL;
- return s;
+ List *s = nnew(List);
+ s->w = nprint("%d", listnel(l));
+ s->n = NULL;
+ s->m = NULL;
+ return s;
}
extern void assign(List *s1, List *s2, bool stack) {
- List *val = s2;
- if (s1 == NULL)
- rc_error("null variable name");
- if (s1->n != NULL)
- rc_error("multi-word variable name");
- if (*s1->w == '\0')
- rc_error("zero-length variable name");
- if (a2u(s1->w) != -1)
- rc_error("numeric variable name");
- if (strchr(s1->w, '=') != NULL)
- rc_error("'=' in variable name");
- if (*s1->w == '*' && s1->w[1] == '\0')
- val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
- if (s2 != NULL || stack) {
- varassign(s1->w, val, stack);
- alias(s1->w, varlookup(s1->w), stack);
- } else {
- varrm(s1->w, stack);
- }
+ List *val = s2;
+ if (s1 == NULL)
+ rc_error("null variable name");
+ if (s1->n != NULL)
+ rc_error("multi-word variable name");
+ if (*s1->w == '\0')
+ rc_error("zero-length variable name");
+ if (a2u(s1->w) != -1)
+ rc_error("numeric variable name");
+ if (strchr(s1->w, '=') != NULL)
+ rc_error("'=' in variable name");
+ if (*s1->w == '*' && s1->w[1] == '\0')
+ val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
+ if (s2 != NULL || stack) {
+ varassign(s1->w, val, stack);
+ alias(s1->w, varlookup(s1->w), stack);
+ } else {
+ varrm(s1->w, stack);
+ }
}
/*
who could not stand the incompetence of my own backquote implementation.
*/
-#define BUFSIZE ((size_t) 1000)
+#define BUFSIZE ((size_t) 1000)
static List *bqinput(List *ifs, int fd) {
- char *end, *bufend, *s;
- List *r, *top, *prev;
- size_t remain, bufsize;
- char isifs[256];
- int n, state; /* a simple FSA is used to read in data */
+ char *end, *bufend, *s;
+ List *r, *top, *prev;
+ size_t remain, bufsize;
+ char isifs[256];
+ int n, state; /* a simple FSA is used to read in data */
- memzero(isifs, sizeof isifs);
- for (isifs['\0'] = true; ifs != NULL; ifs = ifs->n)
- for (s = ifs->w; *s != '\0'; s++)
- isifs[*(unsigned char *)s] = true;
- remain = bufsize = BUFSIZE;
- top = r = nnew(List);
- r->w = end = nalloc(bufsize + 1);
- r->m = NULL;
- state = 0;
- prev = NULL;
+ memzero(isifs, sizeof isifs);
+ for (isifs['\0'] = true; ifs != NULL; ifs = ifs->n)
+ for (s = ifs->w; *s != '\0'; s++)
+ isifs[*(unsigned char *)s] = true;
+ remain = bufsize = BUFSIZE;
+ top = r = nnew(List);
+ r->w = end = nalloc(bufsize + 1);
+ r->m = NULL;
+ state = 0;
+ prev = NULL;
- while (1) {
- if (remain == 0) { /* is the string bigger than the buffer? */
- size_t m = end - r->w;
- char *buf;
- while (bufsize < m + BUFSIZE)
- bufsize *= 2;
- buf = nalloc(bufsize + 1);
- memcpy(buf, r->w, m);
- r->w = buf;
- end = &buf[m];
- remain = bufsize - m;
- }
- if ((n = read(fd, end, remain)) <= 0) {
- if (n == 0)
- /* break */ break;
- else if (errno == EINTR)
- return NULL; /* interrupted, wait for subproc */
- else {
- uerror("backquote read");
- rc_error(NULL);
- }
- }
- remain -= n;
- for (bufend = &end[n]; end < bufend; end++)
- if (state == 0) {
- if (!isifs[*(unsigned char *)end]) {
- state = 1;
- r->w = end;
- r->m = NULL;
- }
- } else {
- if (isifs[*(unsigned char *)end]) {
- state = 0;
- *end = '\0';
- prev = r;
- r = r->n = nnew(List);
- r->w = end+1;
- r->m = NULL;
- }
- }
- }
- if (state == 1) { /* terminate last string */
- *end = '\0';
- r->n = NULL;
- } else {
- if (prev == NULL) /* no input at all? */
- top = NULL;
- else
- prev->n = NULL; /* else terminate list */
- }
- return top;
+ while (1) {
+ if (remain == 0) { /* is the string bigger than the buffer? */
+ size_t m = end - r->w;
+ char *buf;
+ while (bufsize < m + BUFSIZE)
+ bufsize *= 2;
+ buf = nalloc(bufsize + 1);
+ memcpy(buf, r->w, m);
+ r->w = buf;
+ end = &buf[m];
+ remain = bufsize - m;
+ }
+ if ((n = read(fd, end, remain)) <= 0) {
+ if (n == 0)
+ /* break */ break;
+ else if (errno == EINTR)
+ return NULL; /* interrupted, wait for subproc */
+ else {
+ uerror("backquote read");
+ rc_error(NULL);
+ }
+ }
+ remain -= n;
+ for (bufend = &end[n]; end < bufend; end++)
+ if (state == 0) {
+ if (!isifs[*(unsigned char *)end]) {
+ state = 1;
+ r->w = end;
+ r->m = NULL;
+ }
+ } else {
+ if (isifs[*(unsigned char *)end]) {
+ state = 0;
+ *end = '\0';
+ prev = r;
+ r = r->n = nnew(List);
+ r->w = end+1;
+ r->m = NULL;
+ }
+ }
+ }
+ if (state == 1) { /* terminate last string */
+ *end = '\0';
+ r->n = NULL;
+ } else {
+ if (prev == NULL) /* no input at all? */
+ top = NULL;
+ else
+ prev->n = NULL; /* else terminate list */
+ }
+ return top;
}
static List *backq(Node *ifs, Node *n) {
- int p[2], sp;
- pid_t pid;
- List *bq;
- if (n == NULL)
- return NULL;
- if (pipe(p) < 0) {
- uerror("pipe");
- rc_error(NULL);
- }
- if ((pid = rc_fork()) == 0) {
- mvfd(p[1], 1);
- close(p[0]);
- redirq = NULL;
- walk(n, false);
- exit(getstatus());
- }
- close(p[1]);
- bq = bqinput(glom(ifs), p[0]);
- close(p[0]);
- rc_wait4(pid, &sp, true);
- statprint(-1, sp);
- varassign("bqstatus", word(strstatus(sp), NULL), false);
- sigchk();
- return bq;
+ int p[2], sp;
+ pid_t pid;
+ List *bq;
+ if (n == NULL)
+ return NULL;
+ if (pipe(p) < 0) {
+ uerror("pipe");
+ rc_error(NULL);
+ }
+ if ((pid = rc_fork()) == 0) {
+ mvfd(p[1], 1);
+ close(p[0]);
+ redirq = NULL;
+ walk(n, false);
+ exit(getstatus());
+ }
+ close(p[1]);
+ bq = bqinput(glom(ifs), p[0]);
+ close(p[0]);
+ rc_wait4(pid, &sp, true);
+ statprint(-1, sp);
+ varassign("bqstatus", word(strstatus(sp), NULL), false);
+ sigchk();
+ return bq;
}
extern void qredir(Node *n) {
- Rq *next;
- if (redirq == NULL) {
- next = redirq = nnew(Rq);
- } else {
- for (next = redirq; next->n != NULL; next = next->n)
- ;
- next->n = nnew(Rq);
- next = next->n;
- }
- next->r = n;
- next->n = NULL;
+ Rq *next;
+ if (redirq == NULL) {
+ next = redirq = nnew(Rq);
+ } else {
+ for (next = redirq; next->n != NULL; next = next->n)
+ ;
+ next->n = nnew(Rq);
+ next = next->n;
+ }
+ next->r = n;
+ next->n = NULL;
}
static List *mkcmdarg(Node *n) {
- int fd;
- char *name;
- Edata efifo;
- Estack *e = enew(Estack);
- List *ret = nnew(List);
- static int fifonumber = 0;
+ int fd;
+ char *name;
+ Edata efifo;
+ Estack *e = enew(Estack);
+ List *ret = nnew(List);
+ static int fifonumber = 0;
- name = nprint("/tmp/rc%d.%d", getpid(), fifonumber++);
- if (mkfifo(name, 0666) < 0) {
- uerror("mkfifo");
- return NULL;
- }
- if (rc_fork() == 0) {
- setsigdefaults(false);
- fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */
- if (fd < 0) {
- uerror("open");
- exit(1);
- }
- if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */
- exit(1);
- redirq = NULL;
- walk(n->u[2].p, false);
- exit(getstatus());
- }
- efifo.name = name;
- except(eFifo, efifo, e);
- ret->w = name;
- ret->m = NULL;
- ret->n = NULL;
- return ret;
+ name = nprint("/tmp/rc%d.%d", getpid(), fifonumber++);
+ if (mkfifo(name, 0666) < 0) {
+ uerror("mkfifo");
+ return NULL;
+ }
+ if (rc_fork() == 0) {
+ setsigdefaults(false);
+ fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */
+ if (fd < 0) {
+ uerror("open");
+ exit(1);
+ }
+ if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */
+ exit(1);
+ redirq = NULL;
+ walk(n->u[2].p, false);
+ exit(getstatus());
+ }
+ efifo.name = name;
+ except(eFifo, efifo, e);
+ ret->w = name;
+ ret->m = NULL;
+ ret->n = NULL;
+ return ret;
}
extern List *glom(Node *n) {
- List *v, *head, *tail;
- Node *words;
- if (n == NULL)
- return NULL;
- switch (n->type) {
- case nArgs:
- case nLappend:
- words = n->u[0].p;
- tail = NULL;
- while (words != NULL && (words->type == nArgs || words->type == nLappend)) {
- if (words->u[1].p != NULL && words->u[1].p->type != nWord)
- break;
- head = glom(words->u[1].p);
- if (head != NULL) {
- head->n = tail;
- tail = head;
- }
- words = words->u[0].p;
- }
- v = append(glom(words), tail); /* force left to right evaluation */
- return append(v, glom(n->u[1].p));
- case nBackq:
- return backq(n->u[0].p, n->u[1].p);
- case nConcat:
- head = glom(n->u[0].p); /* force left-to-right evaluation */
- return concat(head, glom(n->u[1].p));
- case nDup:
- case nRedir:
- qredir(n);
- return NULL;
- case nWord:
- return word(n->u[0].s, n->u[1].s);
- case nNmpipe:
- return mkcmdarg(n);
- default:
- /*
- The next four operations depend on the left-child of glom
- to be a variable name. Therefore the variable is looked up
- here.
- */
- if ((v = glom(n->u[0].p)) == NULL)
- rc_error("null variable name");
- if (v->n != NULL)
- rc_error("multi-word variable name");
- if (*v->w == '\0')
- rc_error("zero-length variable name");
- v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w);
- switch (n->type) {
- default:
- panic("unexpected node in glom");
- exit(1);
- /* NOTREACHED */
- case nCount:
- return count(v);
- case nFlat:
- return flatten(v);
- case nVar:
- return v;
- case nVarsub:
- return varsub(v, glom(n->u[1].p));
- }
- }
+ List *v, *head, *tail;
+ Node *words;
+ if (n == NULL)
+ return NULL;
+ switch (n->type) {
+ case nArgs:
+ case nLappend:
+ words = n->u[0].p;
+ tail = NULL;
+ while (words != NULL && (words->type == nArgs || words->type == nLappend)) {
+ if (words->u[1].p != NULL && words->u[1].p->type != nWord)
+ break;
+ head = glom(words->u[1].p);
+ if (head != NULL) {
+ head->n = tail;
+ tail = head;
+ }
+ words = words->u[0].p;
+ }
+ v = append(glom(words), tail); /* force left to right evaluation */
+ return append(v, glom(n->u[1].p));
+ case nBackq:
+ return backq(n->u[0].p, n->u[1].p);
+ case nConcat:
+ head = glom(n->u[0].p); /* force left-to-right evaluation */
+ return concat(head, glom(n->u[1].p));
+ case nDup:
+ case nRedir:
+ qredir(n);
+ return NULL;
+ case nWord:
+ return word(n->u[0].s, n->u[1].s);
+ case nNmpipe:
+ return mkcmdarg(n);
+ default:
+ /*
+ The next four operations depend on the left-child of glom
+ to be a variable name. Therefore the variable is looked up
+ here.
+ */
+ if ((v = glom(n->u[0].p)) == NULL)
+ rc_error("null variable name");
+ if (v->n != NULL)
+ rc_error("multi-word variable name");
+ if (*v->w == '\0')
+ rc_error("zero-length variable name");
+ v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w);
+ switch (n->type) {
+ default:
+ panic("unexpected node in glom");
+ exit(1);
+ /* NOTREACHED */
+ case nCount:
+ return count(v);
+ case nFlat:
+ return flatten(v);
+ case nVar:
+ return v;
+ case nVarsub:
+ return varsub(v, glom(n->u[1].p));
+ }
+ }
}
#define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
extern void inithash() {
- Htab *fpp, *vpp;
- int i;
- fp = ealloc(sizeof(Htab) * HASHSIZE);
- vp = ealloc(sizeof(Htab) * HASHSIZE);
- fused = vused = 0;
- fsize = vsize = HASHSIZE;
- for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++)
- vpp->name = fpp->name = NULL;
+ Htab *fpp, *vpp;
+ int i;
+ fp = ealloc(sizeof(Htab) * HASHSIZE);
+ vp = ealloc(sizeof(Htab) * HASHSIZE);
+ fused = vused = 0;
+ fsize = vsize = HASHSIZE;
+ for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++)
+ vpp->name = fpp->name = NULL;
}
#define ADV() {if ((c = *s++) == '\0') break;}
/* hash function courtesy of paul haahr */
static int hash(char *s, int size) {
- int c, n = 0;
- while (1) {
- ADV();
- n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
- ADV();
- n ^= (c << 14) + (c << 7) + (c << 4) + c;
- ADV();
- n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
- ADV();
- n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
- }
- if (n < 0)
- n = ~n;
- return n & (size - 1); /* need power of 2 size */
+ int c, n = 0;
+ while (1) {
+ ADV();
+ n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
+ ADV();
+ n ^= (c << 14) + (c << 7) + (c << 4) + c;
+ ADV();
+ n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
+ ADV();
+ n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
+ }
+ if (n < 0)
+ n = ~n;
+ return n & (size - 1); /* need power of 2 size */
}
static bool rehash(Htab *ht) {
- int i, j, size;
- int newsize, newused;
- Htab *newhtab;
- if (ht == fp) {
- if (fsize > 2 * fused)
- return false;
- size = fsize;
- } else {
- if (vsize > 2 * vused)
- return false;
- size = vsize;
- }
- newsize = 2 * size;
- newhtab = ealloc(newsize * sizeof(Htab));
- for (i = 0; i < newsize; i++)
- newhtab[i].name = NULL;
- for (i = newused = 0; i < size; i++)
- if (ht[i].name != NULL && ht[i].name != dead) {
- newused++;
- j = hash(ht[i].name, newsize);
- while (newhtab[j].name != NULL) {
- j++;
- j &= (newsize - 1);
- }
- newhtab[j].name = ht[i].name;
- newhtab[j].p = ht[i].p;
- }
- if (ht == fp) {
- fused = newused;
- fp = newhtab;
- fsize = newsize;
- } else {
- vused = newused;
- vp = newhtab;
- vsize = newsize;
- }
- efree(ht);
- return true;
+ int i, j, size;
+ int newsize, newused;
+ Htab *newhtab;
+ if (ht == fp) {
+ if (fsize > 2 * fused)
+ return false;
+ size = fsize;
+ } else {
+ if (vsize > 2 * vused)
+ return false;
+ size = vsize;
+ }
+ newsize = 2 * size;
+ newhtab = ealloc(newsize * sizeof(Htab));
+ for (i = 0; i < newsize; i++)
+ newhtab[i].name = NULL;
+ for (i = newused = 0; i < size; i++)
+ if (ht[i].name != NULL && ht[i].name != dead) {
+ newused++;
+ j = hash(ht[i].name, newsize);
+ while (newhtab[j].name != NULL) {
+ j++;
+ j &= (newsize - 1);
+ }
+ newhtab[j].name = ht[i].name;
+ newhtab[j].p = ht[i].p;
+ }
+ if (ht == fp) {
+ fused = newused;
+ fp = newhtab;
+ fsize = newsize;
+ } else {
+ vused = newused;
+ vp = newhtab;
+ vsize = newsize;
+ }
+ efree(ht);
+ return true;
}
#define varfind(s) find(s, vp, vsize)
#define fnfind(s) find(s, fp, fsize)
static int find(char *s, Htab *ht, int size) {
- int h = hash(s, size);
- while (ht[h].name != NULL && !streq(ht[h].name, s)) {
- h++;
- h &= size - 1;
- }
- return h;
+ int h = hash(s, size);
+ while (ht[h].name != NULL && !streq(ht[h].name, s)) {
+ h++;
+ h &= size - 1;
+ }
+ return h;
}
extern void *lookup(char *s, Htab *ht) {
- int h = find(s, ht, ht == fp ? fsize : vsize);
- return (ht[h].name == NULL) ? NULL : ht[h].p;
+ int h = find(s, ht, ht == fp ? fsize : vsize);
+ return (ht[h].name == NULL) ? NULL : ht[h].p;
}
extern rc_Function *get_fn_place(char *s) {
- int h = fnfind(s);
- env_dirty = true;
- if (fp[h].name == NULL) {
- if (rehash(fp))
- h = fnfind(s);
- fused++;
- fp[h].name = ecpy(s);
- fp[h].p = enew(rc_Function);
- } else
- free_fn(fp[h].p);
- return fp[h].p;
+ int h = fnfind(s);
+ env_dirty = true;
+ if (fp[h].name == NULL) {
+ if (rehash(fp))
+ h = fnfind(s);
+ fused++;
+ fp[h].name = ecpy(s);
+ fp[h].p = enew(rc_Function);
+ } else
+ free_fn(fp[h].p);
+ return fp[h].p;
}
extern Variable *get_var_place(char *s, bool stack) {
- Variable *new;
- int h = varfind(s);
+ Variable *new;
+ int h = varfind(s);
- env_dirty = true;
+ env_dirty = true;
- if (vp[h].name == NULL) {
- if (rehash(vp))
- h = varfind(s);
- vused++;
- vp[h].name = ecpy(s);
- vp[h].p = enew(Variable);
- ((Variable *)vp[h].p)->n = NULL;
- return vp[h].p;
- } else {
- if (stack) { /* increase the stack by 1 */
- new = enew(Variable);
- new->n = vp[h].p;
- return vp[h].p = new;
- } else { /* trample the top of the stack */
- new = vp[h].p;
- efree(new->extdef);
- listfree(new->def);
- return new;
- }
- }
+ if (vp[h].name == NULL) {
+ if (rehash(vp))
+ h = varfind(s);
+ vused++;
+ vp[h].name = ecpy(s);
+ vp[h].p = enew(Variable);
+ ((Variable *)vp[h].p)->n = NULL;
+ return vp[h].p;
+ } else {
+ if (stack) { /* increase the stack by 1 */
+ new = enew(Variable);
+ new->n = vp[h].p;
+ return vp[h].p = new;
+ } else { /* trample the top of the stack */
+ new = vp[h].p;
+ efree(new->extdef);
+ listfree(new->def);
+ return new;
+ }
+ }
}
extern void delete_fn(char *s) {
- int h = fnfind(s);
- if (fp[h].name == NULL)
- return; /* not found */
- env_dirty = true;
- free_fn(fp[h].p);
- efree(fp[h].p);
- efree(fp[h].name);
- if (fp[(h+1)&(fsize-1)].name == NULL) {
- --fused;
- fp[h].name = NULL;
- } else {
- fp[h].name = dead;
- }
+ int h = fnfind(s);
+ if (fp[h].name == NULL)
+ return; /* not found */
+ env_dirty = true;
+ free_fn(fp[h].p);
+ efree(fp[h].p);
+ efree(fp[h].name);
+ if (fp[(h+1)&(fsize-1)].name == NULL) {
+ --fused;
+ fp[h].name = NULL;
+ } else {
+ fp[h].name = dead;
+ }
}
extern void delete_var(char *s, bool stack) {
- int h = varfind(s);
- Variable *v;
- if (vp[h].name == NULL)
- return; /* not found */
- env_dirty = true;
- v = vp[h].p;
- efree(v->extdef);
- listfree(v->def);
- if (v->n != NULL) { /* This is the top of a stack */
- if (stack) { /* pop */
- vp[h].p = v->n;
- efree(v);
- } else { /* else just empty */
- v->extdef = NULL;
- v->def = NULL;
- }
- } else { /* needs to be removed from the hash table */
- efree(v);
- efree(vp[h].name);
- if (vp[(h+1)&(vsize-1)].name == NULL) {
- --vused;
- vp[h].name = NULL;
- } else {
- vp[h].name = dead;
- }
- }
+ int h = varfind(s);
+ Variable *v;
+ if (vp[h].name == NULL)
+ return; /* not found */
+ env_dirty = true;
+ v = vp[h].p;
+ efree(v->extdef);
+ listfree(v->def);
+ if (v->n != NULL) { /* This is the top of a stack */
+ if (stack) { /* pop */
+ vp[h].p = v->n;
+ efree(v);
+ } else { /* else just empty */
+ v->extdef = NULL;
+ v->def = NULL;
+ }
+ } else { /* needs to be removed from the hash table */
+ efree(v);
+ efree(vp[h].name);
+ if (vp[(h+1)&(vsize-1)].name == NULL) {
+ --vused;
+ vp[h].name = NULL;
+ } else {
+ vp[h].name = dead;
+ }
+ }
}
static void free_fn(rc_Function *f) {
- treefree(f->def);
- efree(f->extdef);
+ treefree(f->def);
+ efree(f->extdef);
}
extern void initenv(char **envp) {
- int n;
- for (n = 0; envp[n] != NULL; n++)
- ;
- n++; /* one for the null terminator */
- if (n < HASHSIZE)
- n = HASHSIZE;
- env = ealloc((envsize = 2 * n) * sizeof (char *));
- for (; *envp != NULL; envp++)
- if (strncmp(*envp, "fn_", conststrlen("fn_")) == 0) {
- fnassign_string(*envp);
- } else {
- if (!varassign_string(*envp)) /* add to bozo env */
- env[bozosize++] = *envp;
- }
+ int n;
+ for (n = 0; envp[n] != NULL; n++)
+ ;
+ n++; /* one for the null terminator */
+ if (n < HASHSIZE)
+ n = HASHSIZE;
+ env = ealloc((envsize = 2 * n) * sizeof (char *));
+ for (; *envp != NULL; envp++)
+ if (strncmp(*envp, "fn_", conststrlen("fn_")) == 0) {
+ fnassign_string(*envp);
+ } else {
+ if (!varassign_string(*envp)) /* add to bozo env */
+ env[bozosize++] = *envp;
+ }
}
static char *neverexport[] = {
- "apid", "apids", "bqstatus", "cdpath", "home",
- "ifs", "path", "pid", "status", "*"
+ "apid", "apids", "bqstatus", "cdpath", "home",
+ "ifs", "path", "pid", "status", "*"
};
/* for a few variables that have default values, we export them only
if they've been explicitly set; maybeexport[n].flag is true if this
has occurred. */
struct nameflag {
- char *name;
- bool flag;
+ char *name;
+ bool flag;
};
static struct nameflag maybeexport[] = {
- { "prompt", false },
- { "version", false }
+ { "prompt", false },
+ { "version", false }
};
void set_exportable(char *s, bool b) {
- int i;
- for (i = 0; i < arraysize(maybeexport); ++i)
- if (maybeexport[i].flag != b && streq(s, maybeexport[i].name))
- maybeexport[i].flag = b;
+ int i;
+ for (i = 0; i < arraysize(maybeexport); ++i)
+ if (maybeexport[i].flag != b && streq(s, maybeexport[i].name))
+ maybeexport[i].flag = b;
}
static bool var_exportable(char *s) {
- int i;
- for (i = 0; i < arraysize(neverexport); i++)
- if (streq(s, neverexport[i]))
- return false;
- for (i = 0; i < arraysize(maybeexport); i++)
- if (maybeexport[i].flag == false && streq(s, maybeexport[i].name))
- return false;
- return true;
+ int i;
+ for (i = 0; i < arraysize(neverexport); i++)
+ if (streq(s, neverexport[i]))
+ return false;
+ for (i = 0; i < arraysize(maybeexport); i++)
+ if (maybeexport[i].flag == false && streq(s, maybeexport[i].name))
+ return false;
+ return true;
}
static bool fn_exportable(char *s) {
- int i;
- if (strncmp(s, "sig", conststrlen("sig")) == 0) { /* small speed hack */
- for (i = 0; i < NSIG; i++)
- if (streq(s, signals[i].name))
- return false;
- if (streq(s, "sigexit"))
- return false;
- }
- return true;
+ int i;
+ if (strncmp(s, "sig", conststrlen("sig")) == 0) { /* small speed hack */
+ for (i = 0; i < NSIG; i++)
+ if (streq(s, signals[i].name))
+ return false;
+ if (streq(s, "sigexit"))
+ return false;
+ }
+ return true;
}
extern char **makeenv() {
- int ep, i;
- char *v;
- if (!env_dirty)
- return env;
- env_dirty = false;
- ep = bozosize;
- if (vsize + fsize + 1 + bozosize > envsize) {
- envsize = 2 * (bozosize + vsize + fsize + 1);
- env = erealloc(env, envsize * sizeof(char *));
- }
- for (i = 0; i < vsize; i++) {
- if (vp[i].name == NULL || vp[i].name == dead || !var_exportable(vp[i].name))
- continue;
- v = varlookup_string(vp[i].name);
- if (v != NULL)
- env[ep++] = v;
- }
- for (i = 0; i < fsize; i++) {
- if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name))
- continue;
- env[ep++] = fnlookup_string(fp[i].name);
- }
- env[ep] = NULL;
- qsort(env, (size_t) ep, sizeof(char *), starstrcmp);
- return env;
+ int ep, i;
+ char *v;
+ if (!env_dirty)
+ return env;
+ env_dirty = false;
+ ep = bozosize;
+ if (vsize + fsize + 1 + bozosize > envsize) {
+ envsize = 2 * (bozosize + vsize + fsize + 1);
+ env = erealloc(env, envsize * sizeof(char *));
+ }
+ for (i = 0; i < vsize; i++) {
+ if (vp[i].name == NULL || vp[i].name == dead || !var_exportable(vp[i].name))
+ continue;
+ v = varlookup_string(vp[i].name);
+ if (v != NULL)
+ env[ep++] = v;
+ }
+ for (i = 0; i < fsize; i++) {
+ if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name))
+ continue;
+ env[ep++] = fnlookup_string(fp[i].name);
+ }
+ env[ep] = NULL;
+ qsort(env, (size_t) ep, sizeof(char *), starstrcmp);
+ return env;
}
extern void whatare_all_vars(bool showfn, bool showvar) {
- int i;
- List *s;
- if (showvar)
- for (i = 0; i < vsize; i++)
- if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
- prettyprint_var(1, vp[i].name, s);
- if (showfn)
- for (i = 0; i < fsize; i++)
- if (fp[i].name != NULL && fp[i].name != dead)
- prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
+ int i;
+ List *s;
+ if (showvar)
+ for (i = 0; i < vsize; i++)
+ if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
+ prettyprint_var(1, vp[i].name, s);
+ if (showfn)
+ for (i = 0; i < fsize; i++)
+ if (fp[i].name != NULL && fp[i].name != dead)
+ prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
}
#include "rc.h"
struct Hq {
- Node *doc;
- char *name;
- Hq *n;
- bool quoted;
+ Node *doc;
+ char *name;
+ Hq *n;
+ bool quoted;
} *hq;
static bool dead = false;
*/
static char *readheredoc(char *eof) {
- int c;
- char *t, *buf, *bufend;
- unsigned char *s;
- size_t bufsize;
- t = buf = nalloc(bufsize = 512);
- bufend = &buf[bufsize];
- dead = false;
-#define RESIZE(extra) { \
- char *nbuf; \
- bufsize = bufsize * 2 + extra; \
- nbuf = nalloc(bufsize); \
- memcpy(nbuf, buf, (size_t) (t - buf)); \
- t = nbuf + (t - buf); \
- buf = nbuf; \
- bufend = &buf[bufsize]; \
- }
- for (;;) {
- nextline();
- for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
- ;
- if (*s == '\0' && (c == '\n' || c == EOF)) {
- *t++ = '\0';
- return buf;
- }
- if (s != (unsigned char *) eof) {
- size_t len = s - (unsigned char *) eof;
- if (t + len >= bufend)
- RESIZE(len);
- memcpy(t, eof, len);
- t += len;
- }
- for (;; c = gchar()) {
- if (c == EOF) {
- yyerror("heredoc incomplete");
- dead = true;
- return NULL;
- }
- if (t + 1 >= bufend)
- RESIZE(0);
- *t++ = c;
- if (c == '\n')
- break;
- }
- }
+ int c;
+ char *t, *buf, *bufend;
+ unsigned char *s;
+ size_t bufsize;
+ t = buf = nalloc(bufsize = 512);
+ bufend = &buf[bufsize];
+ dead = false;
+#define RESIZE(extra) { \
+ char *nbuf; \
+ bufsize = bufsize * 2 + extra; \
+ nbuf = nalloc(bufsize); \
+ memcpy(nbuf, buf, (size_t) (t - buf)); \
+ t = nbuf + (t - buf); \
+ buf = nbuf; \
+ bufend = &buf[bufsize]; \
+ }
+ for (;;) {
+ nextline();
+ for (s = (unsigned char *) eof; (c = gchar()) == *s; s++)
+ ;
+ if (*s == '\0' && (c == '\n' || c == EOF)) {
+ *t++ = '\0';
+ return buf;
+ }
+ if (s != (unsigned char *) eof) {
+ size_t len = s - (unsigned char *) eof;
+ if (t + len >= bufend)
+ RESIZE(len);
+ memcpy(t, eof, len);
+ t += len;
+ }
+ for (;; c = gchar()) {
+ if (c == EOF) {
+ yyerror("heredoc incomplete");
+ dead = true;
+ return NULL;
+ }
+ if (t + 1 >= bufend)
+ RESIZE(0);
+ *t++ = c;
+ if (c == '\n')
+ break;
+ }
+ }
}
/* parseheredoc -- turn a heredoc with variable references into a node chain */
static Node *parseheredoc(char *s) {
- int c = *s;
- Node *result = NULL;
- while (true) {
- Node *node;
- switch (c) {
- default: {
- char *begin = s;
- while ((c = *s++) != '\0' && c != '$')
- ;
- *--s = '\0';
- node = mk(nWord, begin, NULL);
- break;
- }
- case '$': {
- char *begin = ++s, *var;
- c = *s++;
- if (c == '$') {
- node = mk(nWord, "$", NULL);
- c = *s;
- } else {
- size_t len = 0;
- do
- len++;
- while (!dnw[c = *(unsigned char *) s++]);
- if (c == '^')
- c = *s;
- else
- s--;
- var = nalloc(len + 1);
- var[len] = '\0';
- memcpy(var, begin, len);
- node = mk(nFlat, mk(nWord, var, NULL));
- }
- break;
- }
- case '\0':
- return result;
- }
- result = (result == NULL) ? node : mk(nConcat, result, node);
- }
+ int c = *s;
+ Node *result = NULL;
+ while (true) {
+ Node *node;
+ switch (c) {
+ default: {
+ char *begin = s;
+ while ((c = *s++) != '\0' && c != '$')
+ ;
+ *--s = '\0';
+ node = mk(nWord, begin, NULL);
+ break;
+ }
+ case '$': {
+ char *begin = ++s, *var;
+ c = *s++;
+ if (c == '$') {
+ node = mk(nWord, "$", NULL);
+ c = *s;
+ } else {
+ size_t len = 0;
+ do
+ len++;
+ while (!dnw[c = *(unsigned char *) s++]);
+ if (c == '^')
+ c = *s;
+ else
+ s--;
+ var = nalloc(len + 1);
+ var[len] = '\0';
+ memcpy(var, begin, len);
+ node = mk(nFlat, mk(nWord, var, NULL));
+ }
+ break;
+ }
+ case '\0':
+ return result;
+ }
+ result = (result == NULL) ? node : mk(nConcat, result, node);
+ }
}
/* read in heredocs when yyparse hits a newline. called from yyparse */
extern int heredoc(int end) {
- Hq *here;
- if ((here = hq) != NULL) {
- hq = NULL;
- if (end) {
- yyerror("heredoc incomplete");
- return false;
- }
- do {
- Node *n = here->doc;
- char *s = readheredoc(here->name);
- if (dead)
- return false;
- n->u[2].p = here->quoted ? mk(nWord, s, NULL, false) : parseheredoc(s);
- n->u[0].i = rHerestring;
- } while ((here = here->n) != NULL);
- }
- return true;
+ Hq *here;
+ if ((here = hq) != NULL) {
+ hq = NULL;
+ if (end) {
+ yyerror("heredoc incomplete");
+ return false;
+ }
+ do {
+ Node *n = here->doc;
+ char *s = readheredoc(here->name);
+ if (dead)
+ return false;
+ n->u[2].p = here->quoted ? mk(nWord, s, NULL, false) : parseheredoc(s);
+ n->u[0].i = rHerestring;
+ } while ((here = here->n) != NULL);
+ }
+ return true;
}
/* queue pending heredocs into a queue. called from yyparse */
extern int qdoc(Node *name, Node *n) {
- Hq *new, **prev;
- if (name->type != nWord) {
- yyerror("eof-marker not a single literal word");
- skiptonl();
- return false;
- }
- for (prev = &hq; (new = *prev) != NULL; prev = &new->n)
- ;
- *prev = new = nnew(Hq);
- new->name = name->u[0].s;
- new->quoted = name->u[2].i;
- new->doc = n;
- new->n = NULL;
- return true;
+ Hq *new, **prev;
+ if (name->type != nWord) {
+ yyerror("eof-marker not a single literal word");
+ skiptonl();
+ return false;
+ }
+ for (prev = &hq; (new = *prev) != NULL; prev = &new->n)
+ ;
+ *prev = new = nnew(Hq);
+ new->name = name->u[0].s;
+ new->quoted = name->u[2].i;
+ new->doc = n;
+ new->n = NULL;
+ return true;
}
enum { UNGETSIZE = 2 };
typedef enum inputtype {
- iFd, iString, iEdit
+ iFd, iString, iEdit
} inputtype;
typedef struct Input {
- bool saved;
- inputtype t;
- int fd, index, read, ungetcount, lineno, last;
- char *ibuf;
- void *cookie;
- int ungetbuf[UNGETSIZE];
- int (*gchar)(void);
+ bool saved;
+ inputtype t;
+ int fd, index, read, ungetcount, lineno, last;
+ char *ibuf;
+ void *cookie;
+ int ungetbuf[UNGETSIZE];
+ int (*gchar)(void);
} Input;
#define BUFSIZE ((size_t) 256)
static char *prompt, *prompt2;
extern void ugchar(int c) {
- assert(istack->ungetcount < UNGETSIZE);
- istack->ungetbuf[istack->ungetcount++] = c;
+ assert(istack->ungetcount < UNGETSIZE);
+ istack->ungetbuf[istack->ungetcount++] = c;
}
extern int gchar() {
- int c;
+ int c;
- if (istack->ungetcount)
- return lastchar = istack->ungetbuf[--istack->ungetcount];
+ if (istack->ungetcount)
+ return lastchar = istack->ungetbuf[--istack->ungetcount];
- while ((c = (*istack->gchar)()) == '\0')
- pr_error("warning: null character ignored", 0);
+ while ((c = (*istack->gchar)()) == '\0')
+ pr_error("warning: null character ignored", 0);
- return c;
+ return c;
}
/* get the next character from a string. */
static int stringgchar() {
- return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]);
+ return lastchar = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]);
}
/* write last command out to a file if interactive && $history is set */
static void history() {
- List *hist;
- size_t a;
-
- if (!interactive || (hist = varlookup("history")) == NULL)
- return;
-
- for (a = 0; a < chars_in; a++) {
- char c = inbuf[a];
-
- /* skip empty lines and comments */
- if (c == '#' || c == '\n')
- break;
-
- /* line matches [ \t]*[^#\n] so it's ok to write out */
- if (c != ' ' && c != '\t') {
- char *name = hist->w;
- int fd = rc_open(name, rAppend);
- if (fd < 0)
- uerror(name);
- else {
- writeall(fd, inbuf, chars_in);
- close(fd);
- }
- break;
- }
- }
+ List *hist;
+ size_t a;
+
+ if (!interactive || (hist = varlookup("history")) == NULL)
+ return;
+
+ for (a = 0; a < chars_in; a++) {
+ char c = inbuf[a];
+
+ /* skip empty lines and comments */
+ if (c == '#' || c == '\n')
+ break;
+
+ /* line matches [ \t]*[^#\n] so it's ok to write out */
+ if (c != ' ' && c != '\t') {
+ char *name = hist->w;
+ int fd = rc_open(name, rAppend);
+ if (fd < 0)
+ uerror(name);
+ else {
+ writeall(fd, inbuf, chars_in);
+ close(fd);
+ }
+ break;
+ }
+ }
}
/* read a character from a file descriptor */
static int fdgchar() {
- if (chars_out >= chars_in) { /* replenish empty buffer */
- ssize_t r;
- do {
- r = read(istack->fd, inbuf, BUFSIZE);
- sigchk();
- if (r == -1)
- switch (errno) {
- case EAGAIN:
- if (!makeblocking(istack->fd))
- panic("not O_NONBLOCK");
- errno = EINTR;
- break;
- case EIO:
- if (makesamepgrp(istack->fd))
- errno = EINTR;
- else
- errno = EIO;
- break;
- }
- } while (r < 0 && errno == EINTR);
- if (r < 0) {
- uerror("read");
- rc_raise(eError);
- }
- chars_in = (size_t) r;
- if (chars_in == 0)
- return lastchar = EOF;
- chars_out = 0;
- history();
- }
-
- return lastchar = inbuf[chars_out++];
+ if (chars_out >= chars_in) { /* replenish empty buffer */
+ ssize_t r;
+ do {
+ r = read(istack->fd, inbuf, BUFSIZE);
+ sigchk();
+ if (r == -1)
+ switch (errno) {
+ case EAGAIN:
+ if (!makeblocking(istack->fd))
+ panic("not O_NONBLOCK");
+ errno = EINTR;
+ break;
+ case EIO:
+ if (makesamepgrp(istack->fd))
+ errno = EINTR;
+ else
+ errno = EIO;
+ break;
+ }
+ } while (r < 0 && errno == EINTR);
+ if (r < 0) {
+ uerror("read");
+ rc_raise(eError);
+ }
+ chars_in = (size_t) r;
+ if (chars_in == 0)
+ return lastchar = EOF;
+ chars_out = 0;
+ history();
+ }
+
+ return lastchar = inbuf[chars_out++];
}
/* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
extern void initinput() {
- istack = itop = ealloc(istacksize = 256 * sizeof (Input));
- istack->ungetcount = 0;
- ugchar(EOF);
+ istack = itop = ealloc(istacksize = 256 * sizeof (Input));
+ istack->ungetcount = 0;
+ ugchar(EOF);
}
/* push an input source onto the stack. set up a new input buffer, and set gchar() */
static void pushcommon() {
- size_t idiff;
- istack->index = chars_out;
- istack->read = chars_in;
- istack->ibuf = inbuf;
- istack->lineno = lineno;
- istack->saved = save_lineno;
- istack->last = lastchar;
- istack++;
- idiff = istack - itop;
- if (idiff >= istacksize / sizeof (Input)) {
- itop = erealloc(itop, istacksize *= 2);
- istack = itop + idiff;
- }
- chars_out = 0;
- chars_in = 0;
- istack->ungetcount = 0;
+ size_t idiff;
+ istack->index = chars_out;
+ istack->read = chars_in;
+ istack->ibuf = inbuf;
+ istack->lineno = lineno;
+ istack->saved = save_lineno;
+ istack->last = lastchar;
+ istack++;
+ idiff = istack - itop;
+ if (idiff >= istacksize / sizeof (Input)) {
+ itop = erealloc(itop, istacksize *= 2);
+ istack = itop + idiff;
+ }
+ chars_out = 0;
+ chars_in = 0;
+ istack->ungetcount = 0;
}
extern void pushfd(int fd) {
- pushcommon();
- save_lineno = true;
- istack->fd = fd;
- lineno = 1;
- istack->t = iFd;
- istack->gchar = fdgchar;
- inbuf = ealloc(BUFSIZE);
+ pushcommon();
+ save_lineno = true;
+ istack->fd = fd;
+ lineno = 1;
+ istack->t = iFd;
+ istack->gchar = fdgchar;
+ inbuf = ealloc(BUFSIZE);
}
extern void pushstring(char **a, bool save) {
- pushcommon();
- istack->t = iString;
- save_lineno = save;
- inbuf = mprint("%A", a);
- istack->gchar = stringgchar;
- if (save_lineno)
- lineno = 1;
- else
- --lineno;
+ pushcommon();
+ istack->t = iString;
+ save_lineno = save;
+ inbuf = mprint("%A", a);
+ istack->gchar = stringgchar;
+ if (save_lineno)
+ lineno = 1;
+ else
+ --lineno;
}
/* remove an input source from the stack. restore associated variables etc. */
extern void popinput() {
- if (istack->t == iFd || istack->t == iEdit)
- close(istack->fd);
- efree(inbuf);
- --istack;
- lastchar = istack->last;
- inbuf = istack->ibuf;
- chars_out = istack->index;
- chars_in = istack->read;
- if (save_lineno)
- lineno = istack->lineno;
- else
- lineno++;
- save_lineno = istack->saved;
+ if (istack->t == iFd || istack->t == iEdit)
+ close(istack->fd);
+ efree(inbuf);
+ --istack;
+ lastchar = istack->last;
+ inbuf = istack->ibuf;
+ chars_out = istack->index;
+ chars_in = istack->read;
+ if (save_lineno)
+ lineno = istack->lineno;
+ else
+ lineno++;
+ save_lineno = istack->saved;
}
/* flush input characters up to newline. Used by scanerror() */
extern void skiptonl() {
- int c;
- if (lastchar == '\n' || lastchar == EOF)
- return;
- while ((c = gchar()) != '\n' && c != EOF)
- ; /* skip to newline */
- if (c == EOF)
- ugchar(c);
+ int c;
+ if (lastchar == '\n' || lastchar == EOF)
+ return;
+ while ((c = gchar()) != '\n' && c != EOF)
+ ; /* skip to newline */
+ if (c == EOF)
+ ugchar(c);
}
/* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
extern Node *doit(bool clobberexecit) {
- bool eof;
- bool execit;
- Jbwrap j;
- Estack e1;
- Edata jerror;
-
- execit = clobberexecit;
- sigsetjmp(j.j, 1);
- jerror.jb = &j;
- except(eError, jerror, &e1);
- for (eof = false; !eof;) {
- Edata block;
- Estack e2;
-
- block.b = newblock();
- except(eArena, block, &e2);
- sigchk();
-
- if (interactive) {
- List *s;
- if (fnlookup("prompt") != NULL) {
- static bool died = false;
- static char *arglist[] = { "prompt", NULL };
-
- if (!died) {
- died = true;
- funcall(arglist);
- }
- died = false;
- }
- s = varlookup("prompt");
- if (s != NULL) {
- prompt = s->w;
- if (s->n != NULL)
- prompt2 = s->n->w;
- else
- prompt2 = "";
- } else {
- prompt = prompt2 = "";
- }
- if (istack->t == iFd)
- fprint(2, "%s", prompt);
- }
- inityy();
- if (yyparse() == 1 && execit)
- rc_raise(eError);
- eof = (lastchar == EOF); /* "lastchar" can be clobbered during a walk() */
- if (parsetree != NULL && execit)
- walk(parsetree, true);
- unexcept(); /* eArena */
- }
- popinput();
- unexcept(); /* eError */
- return parsetree;
+ bool eof;
+ bool execit;
+ Jbwrap j;
+ Estack e1;
+ Edata jerror;
+
+ execit = clobberexecit;
+ sigsetjmp(j.j, 1);
+ jerror.jb = &j;
+ except(eError, jerror, &e1);
+ for (eof = false; !eof;) {
+ Edata block;
+ Estack e2;
+
+ block.b = newblock();
+ except(eArena, block, &e2);
+ sigchk();
+
+ if (interactive) {
+ List *s;
+ if (fnlookup("prompt") != NULL) {
+ static bool died = false;
+ static char *arglist[] = { "prompt", NULL };
+
+ if (!died) {
+ died = true;
+ funcall(arglist);
+ }
+ died = false;
+ }
+ s = varlookup("prompt");
+ if (s != NULL) {
+ prompt = s->w;
+ if (s->n != NULL)
+ prompt2 = s->n->w;
+ else
+ prompt2 = "";
+ } else {
+ prompt = prompt2 = "";
+ }
+ if (istack->t == iFd)
+ fprintf(stderr, "%s", prompt);
+ }
+ inityy();
+ if (yyparse() == 1 && execit)
+ rc_raise(eError);
+ eof = (lastchar == EOF); /* "lastchar" can be clobbered during a walk() */
+ if (parsetree != NULL && execit)
+ walk(parsetree, true);
+ unexcept(); /* eArena */
+ }
+ popinput();
+ unexcept(); /* eError */
+ return parsetree;
}
/* parse a function imported from the environment */
extern Node *parseline(char *extdef) {
- bool i = interactive;
- char *in[2];
- Node *fun;
- in[0] = extdef;
- in[1] = NULL;
- interactive = false;
- pushstring(in, true);
- fun = doit(false);
- interactive = i;
- return fun;
+ bool i = interactive;
+ char *in[2];
+ Node *fun;
+ in[0] = extdef;
+ in[1] = NULL;
+ interactive = false;
+ pushstring(in, true);
+ fun = doit(false);
+ interactive = i;
+ return fun;
}
/* close file descriptors after a fork() */
extern void closefds() {
- Input *i;
- for (i = istack; i != itop; --i) /* close open scripts */
- if (i->t == iFd && i->fd > 2) {
- close(i->fd);
- i->fd = -1;
- }
+ Input *i;
+ for (i = istack; i != itop; --i) /* close open scripts */
+ if (i->t == iFd && i->fd > 2) {
+ close(i->fd);
+ i->fd = -1;
+ }
}
/* print (or set) prompt(2) */
extern void nextline() {
- lineno++;
- if (interactive) {
- if (istack->t == iFd)
- fprint(2, "%s", prompt2);
- }
+ lineno++;
+ if (interactive) {
+ if (istack->t == iFd)
+ fprintf(stderr, "%s", prompt2);
+ }
}
#include "y.tab.h"
/*
- Special characters (i.e., "non-word") in rc:
- \t \n # ; & | ^ $ = ~ ` ' { } @ ! ( ) < > \
+ Special characters (i.e., "non-word") in rc:
+ \t \n # ; & | ^ $ = ~ ` ' { } @ ! ( ) < > \
- The lexical analyzer is fairly straightforward. The only really
- unclean part concerns backslash continuation and "double
- backslashes". A backslash followed by a newline is treated as a
- space, otherwise backslash is not a special character (i.e.,
- it can be part of a word). This introduces a host of unwanted
- special cases. In our case, \ cannot be a word character, since
- we wish to read in all word characters in a tight loop.
+ The lexical analyzer is fairly straightforward. The only really
+ unclean part concerns backslash continuation and "double
+ backslashes". A backslash followed by a newline is treated as a
+ space, otherwise backslash is not a special character (i.e.,
+ it can be part of a word). This introduces a host of unwanted
+ special cases. In our case, \ cannot be a word character, since
+ we wish to read in all word characters in a tight loop.
- Note: to save the trouble of declaring these arrays with trues
- and falses, I am assuming that false = 0, true = 1. (and so is
- it declared in rc.h)
+ Note: to save the trouble of declaring these arrays with trues
+ and falses, I am assuming that false = 0, true = 1. (and so is
+ it declared in rc.h)
*/
-#define BUFSIZE ((size_t) 1000) /* malloc hates power of 2 buffers? */
-#define BUFMAX (8 * BUFSIZE) /* How big the buffer can get before we re-allocate the
- space at BUFSIZE again. Premature optimization? Maybe.
- */
+#define BUFSIZE ((size_t) 1000) /* malloc hates power of 2 buffers? */
+#define BUFMAX (8 * BUFSIZE) /* How big the buffer can get before we re-allocate the
+ space at BUFSIZE again. Premature optimization? Maybe.
+ */
typedef enum wordstates {
- NW, RW, KW /* "nonword", "realword", "keyword" */
+ NW, RW, KW /* "nonword", "realword", "keyword" */
} wordstates;
static void getpair(int);
/* lookup table for non-word characters */
const char nw[] = {
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* lookup table for non-word characters in variable names */
const char dnw[] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
/* lookup table for quotable characters: nw + glob metachars */
const char q[] = {
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static size_t bufsize = BUFSIZE;
#define checkfreecaret {if (w != NW) { w = NW; ugchar(c); return '^'; }}
enum filedescriptors {
- UNSET = -9, CLOSED = -1
+ UNSET = -9, CLOSED = -1
};
/* does this string require quoting? */
extern bool quotep(char *s, bool dollar) {
- unsigned char c;
- const char *meta;
+ unsigned char c;
+ const char *meta;
- meta = dollar ? dnw : q;
- while ((c = *s++))
- if (meta[c])
- return true;
- return false;
+ meta = dollar ? dnw : q;
+ while ((c = *s++))
+ if (meta[c])
+ return true;
+ return false;
}
extern int yylex() {
- static bool dollar = false;
- bool saw_meta = false;
- int c;
- size_t i; /* The purpose of all these local assignments is to */
- const char *meta; /* allow optimizing compilers like gcc to load these */
- char *buf = realbuf; /* values into registers. On a sparc this is a */
- YYSTYPE *y = &yylval; /* win, in code size *and* execution time */
- if (errset) {
- errset = false;
- return '\n';
- }
- /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
- meta = (dollar ? dnw : nw);
- if (newline) {
- --lineno; /* slight space optimization; nextline() always increments lineno */
- nextline();
- newline = false;
- }
-top: while ((c = gchar()) == ' ' || c == '\t')
- w = NW;
- if (c != '(') dollar = false;
- if (c == EOF)
- return END;
- if (!meta[(unsigned char) c]) { /* it's a word or keyword. */
- checkfreecaret;
- w = RW;
- i = 0;
- read: do {
- buf[i++] = c;
- if (c == '?' || c == '[' || c == '*')
- saw_meta = true;
- if (i >= bufsize)
- buf = realbuf = erealloc(buf, bufsize *= 2);
- } while ((c = gchar()) != EOF && !meta[(unsigned char) c]);
- while (c == '\\') {
- if ((c = gchar()) == '\n') {
- nextline();
- c = ' '; /* Pretend a space was read */
- break;
- } else {
- bs: if (meta != dnw) { /* all words but varnames may have a bslash */
- buf[i++] = '\\';
- if (i >= bufsize)
- buf = realbuf = erealloc(buf, bufsize *= 2);
- if (!meta[(unsigned char) c])
- goto read;
- } else {
- ugchar(c);
- c = '\\';
- break;
- }
- }
- }
- ugchar(c);
- buf[i] = '\0';
- w = KW;
- if (i == 2) {
- if (*buf == 'i' && buf[1] == 'f') return IF;
- if (*buf == 'f' && buf[1] == 'n') return FN;
- if (*buf == 'i' && buf[1] == 'n') return IN;
- }
- if (streq(buf, "for")) return FOR;
- if (streq(buf, "else")) return ELSE;
- if (streq(buf, "switch")) return SWITCH;
- if (streq(buf, "while")) return WHILE;
- if (streq(buf, "case")) return CASE;
- w = RW;
- y->word.w = ncpy(buf);
- if (saw_meta) {
- char *r, *s;
+ static bool dollar = false;
+ bool saw_meta = false;
+ int c;
+ size_t i; /* The purpose of all these local assignments is to */
+ const char *meta; /* allow optimizing compilers like gcc to load these */
+ char *buf = realbuf; /* values into registers. On a sparc this is a */
+ YYSTYPE *y = &yylval; /* win, in code size *and* execution time */
+ if (errset) {
+ errset = false;
+ return '\n';
+ }
+ /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
+ meta = (dollar ? dnw : nw);
+ if (newline) {
+ --lineno; /* slight space optimization; nextline() always increments lineno */
+ nextline();
+ newline = false;
+ }
+top: while ((c = gchar()) == ' ' || c == '\t')
+ w = NW;
+ if (c != '(') dollar = false;
+ if (c == EOF)
+ return END;
+ if (!meta[(unsigned char) c]) { /* it's a word or keyword. */
+ checkfreecaret;
+ w = RW;
+ i = 0;
+ read: do {
+ buf[i++] = c;
+ if (c == '?' || c == '[' || c == '*')
+ saw_meta = true;
+ if (i >= bufsize)
+ buf = realbuf = erealloc(buf, bufsize *= 2);
+ } while ((c = gchar()) != EOF && !meta[(unsigned char) c]);
+ while (c == '\\') {
+ if ((c = gchar()) == '\n') {
+ nextline();
+ c = ' '; /* Pretend a space was read */
+ break;
+ } else {
+ bs: if (meta != dnw) { /* all words but varnames may have a bslash */
+ buf[i++] = '\\';
+ if (i >= bufsize)
+ buf = realbuf = erealloc(buf, bufsize *= 2);
+ if (!meta[(unsigned char) c])
+ goto read;
+ } else {
+ ugchar(c);
+ c = '\\';
+ break;
+ }
+ }
+ }
+ ugchar(c);
+ buf[i] = '\0';
+ w = KW;
+ if (i == 2) {
+ if (*buf == 'i' && buf[1] == 'f') return IF;
+ if (*buf == 'f' && buf[1] == 'n') return FN;
+ if (*buf == 'i' && buf[1] == 'n') return IN;
+ }
+ if (streq(buf, "for")) return FOR;
+ if (streq(buf, "else")) return ELSE;
+ if (streq(buf, "switch")) return SWITCH;
+ if (streq(buf, "while")) return WHILE;
+ if (streq(buf, "case")) return CASE;
+ w = RW;
+ y->word.w = ncpy(buf);
+ if (saw_meta) {
+ char *r, *s;
- y->word.m = nalloc(strlen(buf) + 1);
- for (r = buf, s = y->word.m; *r != '\0'; r++, s++)
- *s = (*r == '?' || *r == '[' || *r == '*');
- } else {
- y->word.m = NULL;
- }
- y->word.q = false;
- return WORD;
- }
- if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
- checkfreecaret;
- if (c == '!' || c == '@' || c == '~')
- w = KW;
- }
- switch (c) {
- case '!':
- return BANG;
- case '@':
- return SUBSHELL;
- case '~':
- return TWIDDLE;
- case '`':
- c = gchar();
- if (c == '`')
- return BACKBACK;
- ugchar(c);
- return '`';
- case '$':
- dollar = true;
- c = gchar();
- if (c == '#')
- return COUNT;
- if (c == '^' || c == '"')
- return FLAT;
- ugchar(c);
- return '$';
- case '\'':
- w = RW;
- i = 0;
- /* double ' to quote it, like this: 'how''s it going?' */
- while ((c = gchar()) != '\'' || (c = gchar()) == '\'') {
- buf[i++] = c;
- if (c == '\n')
- nextline();
- if (c == EOF) {
- w = NW;
- scanerror("eof in quoted string");
- return HUH;
- }
- if (i >= bufsize)
- buf = realbuf = erealloc(buf, bufsize *= 2);
- }
- ugchar(c);
- buf[i] = '\0';
- y->word.w = ncpy(buf);
- y->word.m = NULL;
- y->word.q = true;
- return WORD;
- case '\\':
- if ((c = gchar()) == '\n') {
- nextline();
- goto top; /* Pretend it was just another space. */
- }
- ugchar(c);
- c = '\\';
- checkfreecaret;
- c = gchar();
- i = 0;
- goto bs;
- case '(':
- if (w == RW) /* SUB's happen only after real words, not keywords, so if () and while () work */
- c = SUB;
- w = NW;
- return c;
- case '#':
- while ((c = gchar()) != '\n') /* skip comment until newline */
- if (c == EOF)
- return END;
- /* FALLTHROUGH */
- case '\n':
- lineno++;
- newline = true;
- /* FALLTHROUGH */
- case ';':
- case '^':
- case ')':
- case '=':
- case '{': case '}':
- w = NW;
- return c;
- case '&':
- w = NW;
- c = gchar();
- if (c == '&')
- return ANDAND;
- ugchar(c);
- return '&';
- case '|':
- w = NW;
- c = gchar();
- if (c == '|')
- return OROR;
- getpair(c);
- if (errset)
- return HUH;
- if ((y->pipe.left = fd_left) == UNSET)
- y->pipe.left = 1; /* default to fd 1 */
- if ((y->pipe.right = fd_right) == UNSET)
- y->pipe.right = 0; /* default to fd 0 */
- if (y->pipe.right == CLOSED) {
- scanerror("expected digit after '='"); /* can't close a pipe */
- return HUH;
- }
- return PIPE;
- case '>':
- c = gchar();
- if (c == '>') {
- c = gchar();
- y->redir.type = rAppend;
- } else
- y->redir.type = rCreate;
- y->redir.fd = 1;
- goto common;
- case '<':
- c = gchar();
- if (c == '<') {
- c = gchar();
- if (c == '<') {
- c = gchar();
- y->redir.type = rHerestring;
- } else {
- y->redir.type = rHeredoc;
- }
- } else
- y->redir.type = rFrom;
- y->redir.fd = 0;
- common:
- w = NW;
- getpair(c);
- if (errset)
- return HUH;
- if (fd_right == UNSET) { /* redirection, not dup */
- if (fd_left != UNSET) {
- y->redir.fd = fd_left;
- return SREDIR;
- }
- return (y->redir.type == rFrom || y->redir.type == rCreate) ? REDIR : SREDIR;
- } else { /* dup; recast yylval */
- y->dup.type = y->redir.type;
- y->dup.left = fd_left;
- y->dup.right = fd_right;
- return DUP;
- }
- default:
- w = NW;
- return c; /* don't know what it is, let yacc barf on it */
- }
+ y->word.m = nalloc(strlen(buf) + 1);
+ for (r = buf, s = y->word.m; *r != '\0'; r++, s++)
+ *s = (*r == '?' || *r == '[' || *r == '*');
+ } else {
+ y->word.m = NULL;
+ }
+ y->word.q = false;
+ return WORD;
+ }
+ if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
+ checkfreecaret;
+ if (c == '!' || c == '@' || c == '~')
+ w = KW;
+ }
+ switch (c) {
+ case '!':
+ return BANG;
+ case '@':
+ return SUBSHELL;
+ case '~':
+ return TWIDDLE;
+ case '`':
+ c = gchar();
+ if (c == '`')
+ return BACKBACK;
+ ugchar(c);
+ return '`';
+ case '$':
+ dollar = true;
+ c = gchar();
+ if (c == '#')
+ return COUNT;
+ if (c == '^' || c == '"')
+ return FLAT;
+ ugchar(c);
+ return '$';
+ case '\'':
+ w = RW;
+ i = 0;
+ /* double ' to quote it, like this: 'how''s it going?' */
+ while ((c = gchar()) != '\'' || (c = gchar()) == '\'') {
+ buf[i++] = c;
+ if (c == '\n')
+ nextline();
+ if (c == EOF) {
+ w = NW;
+ scanerror("eof in quoted string");
+ return HUH;
+ }
+ if (i >= bufsize)
+ buf = realbuf = erealloc(buf, bufsize *= 2);
+ }
+ ugchar(c);
+ buf[i] = '\0';
+ y->word.w = ncpy(buf);
+ y->word.m = NULL;
+ y->word.q = true;
+ return WORD;
+ case '\\':
+ if ((c = gchar()) == '\n') {
+ nextline();
+ goto top; /* Pretend it was just another space. */
+ }
+ ugchar(c);
+ c = '\\';
+ checkfreecaret;
+ c = gchar();
+ i = 0;
+ goto bs;
+ case '(':
+ if (w == RW) /* SUB's happen only after real words, not keywords, so if () and while () work */
+ c = SUB;
+ w = NW;
+ return c;
+ case '#':
+ while ((c = gchar()) != '\n') /* skip comment until newline */
+ if (c == EOF)
+ return END;
+ /* FALLTHROUGH */
+ case '\n':
+ lineno++;
+ newline = true;
+ /* FALLTHROUGH */
+ case ';':
+ case '^':
+ case ')':
+ case '=':
+ case '{': case '}':
+ w = NW;
+ return c;
+ case '&':
+ w = NW;
+ c = gchar();
+ if (c == '&')
+ return ANDAND;
+ ugchar(c);
+ return '&';
+ case '|':
+ w = NW;
+ c = gchar();
+ if (c == '|')
+ return OROR;
+ getpair(c);
+ if (errset)
+ return HUH;
+ if ((y->pipe.left = fd_left) == UNSET)
+ y->pipe.left = 1; /* default to fd 1 */
+ if ((y->pipe.right = fd_right) == UNSET)
+ y->pipe.right = 0; /* default to fd 0 */
+ if (y->pipe.right == CLOSED) {
+ scanerror("expected digit after '='"); /* can't close a pipe */
+ return HUH;
+ }
+ return PIPE;
+ case '>':
+ c = gchar();
+ if (c == '>') {
+ c = gchar();
+ y->redir.type = rAppend;
+ } else
+ y->redir.type = rCreate;
+ y->redir.fd = 1;
+ goto common;
+ case '<':
+ c = gchar();
+ if (c == '<') {
+ c = gchar();
+ if (c == '<') {
+ c = gchar();
+ y->redir.type = rHerestring;
+ } else {
+ y->redir.type = rHeredoc;
+ }
+ } else
+ y->redir.type = rFrom;
+ y->redir.fd = 0;
+ common:
+ w = NW;
+ getpair(c);
+ if (errset)
+ return HUH;
+ if (fd_right == UNSET) { /* redirection, not dup */
+ if (fd_left != UNSET) {
+ y->redir.fd = fd_left;
+ return SREDIR;
+ }
+ return (y->redir.type == rFrom || y->redir.type == rCreate) ? REDIR : SREDIR;
+ } else { /* dup; recast yylval */
+ y->dup.type = y->redir.type;
+ y->dup.left = fd_left;
+ y->dup.right = fd_right;
+ return DUP;
+ }
+ default:
+ w = NW;
+ return c; /* don't know what it is, let yacc barf on it */
+ }
}
extern void yyerror(const char *s) {
- char *tok;
- if (prerror) { /* don't print "syntax error" if there's a more informative scanerror */
- prerror = false;
- return;
- }
- if (!interactive) {
- if (w != NW)
- tok = realbuf;
- else if (lastchar == EOF)
- tok = "eof";
- else if (lastchar == '\n')
- tok = "end of line";
- else
- tok = nprint((lastchar < 32 || lastchar > 126) ? "(decimal %d)" : "'%c'", lastchar);
- fprint(2, "rc: line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok);
- } else
- fprint(2, "rc: %s\n", s);
+ char *tok;
+ if (prerror) { /* don't print "syntax error" if there's a more informative scanerror */
+ prerror = false;
+ return;
+ }
+ if (!interactive) {
+ if (w != NW)
+ tok = realbuf;
+ else if (lastchar == EOF)
+ tok = "eof";
+ else if (lastchar == '\n')
+ tok = "end of line";
+ else
+ tok = nprint((lastchar < 32 || lastchar > 126) ? "(decimal %d)" : "'%c'", lastchar);
+ fprintf(stderr, "rc: line %d: %s near %s\n", lineno - (lastchar == '\n'), s, tok);
+ } else
+ fprintf(stderr, "rc: %s\n", s);
}
extern void scanerror(char *s) {
- skiptonl(); /* flush up to newline */
- yyerror(s);
- errset = prerror = true;
+ skiptonl(); /* flush up to newline */
+ yyerror(s);
+ errset = prerror = true;
}
extern void inityy() {
- newline = false;
- w = NW;
- hq = NULL;
- /* return memory to the system if the buffer got too large */
- if (bufsize > BUFMAX && realbuf != NULL) {
- efree(realbuf);
- bufsize = BUFSIZE;
- realbuf = ealloc(bufsize);
- } else if (realbuf == NULL)
- realbuf = ealloc(bufsize);
+ newline = false;
+ w = NW;
+ hq = NULL;
+ /* return memory to the system if the buffer got too large */
+ if (bufsize > BUFMAX && realbuf != NULL) {
+ efree(realbuf);
+ bufsize = BUFSIZE;
+ realbuf = ealloc(bufsize);
+ } else if (realbuf == NULL)
+ realbuf = ealloc(bufsize);
}
/*
*/
static void getpair(int c) {
- int n;
- fd_left = fd_right = UNSET;
- if (c != '[') {
- ugchar(c);
- return;
- }
- if ((unsigned int) (n = gchar() - '0') > 9) {
- scanerror("expected digit after '['");
- return;
- }
- while ((unsigned int) (c = gchar() - '0') <= 9)
- n = n * 10 + c;
- fd_left = n;
- c += '0';
- switch (c) {
- default:
- scanerror("expected '=' or ']' after digit");
- return;
- case ']':
- return;
- case '=':
- if ((unsigned int) (n = gchar() - '0') > 9) {
- if (n != ']' - '0') {
- scanerror("expected digit or ']' after '='");
- return;
- }
- fd_right = CLOSED;
- } else {
- while ((unsigned int) (c = gchar() - '0') <= 9)
- n = n * 10 + c;
- if (c != ']' - '0') {
- scanerror("expected ']' after digit");
- return;
- }
- fd_right = n;
- }
- }
+ int n;
+ fd_left = fd_right = UNSET;
+ if (c != '[') {
+ ugchar(c);
+ return;
+ }
+ if ((unsigned int) (n = gchar() - '0') > 9) {
+ scanerror("expected digit after '['");
+ return;
+ }
+ while ((unsigned int) (c = gchar() - '0') <= 9)
+ n = n * 10 + c;
+ fd_left = n;
+ c += '0';
+ switch (c) {
+ default:
+ scanerror("expected '=' or ']' after digit");
+ return;
+ case ']':
+ return;
+ case '=':
+ if ((unsigned int) (n = gchar() - '0') > 9) {
+ if (n != ']' - '0') {
+ scanerror("expected digit or ']' after '='");
+ return;
+ }
+ fd_right = CLOSED;
+ } else {
+ while ((unsigned int) (c = gchar() - '0') <= 9)
+ n = n * 10 + c;
+ if (c != ']' - '0') {
+ scanerror("expected ']' after digit");
+ return;
+ }
+ fd_right = n;
+ }
+ }
}
/* free a list from malloc space */
extern void listfree(List *p) {
- while (p != NULL) {
- List *n = p->n;
- efree(p->w);
- efree(p);
- p = n;
- }
+ while (p != NULL) {
+ List *n = p->n;
+ efree(p->w);
+ efree(p);
+ p = n;
+ }
}
/* Copy list into malloc space (for storing a variable) */
extern List *listcpy(List *s, void *(*alloc)(size_t)) {
- List *top, *r;
- for (top = r = NULL; s != NULL; s = s->n) {
- if (top == NULL)
- r = top = (*alloc)(sizeof (List));
- else
- r = r->n = (*alloc)(sizeof (List));
- r->w = (*alloc)(strlen(s->w) + 1);
- strcpy(r->w, s->w);
- r->m = NULL;
- }
- if (r != NULL)
- r->n = NULL;
- return top;
+ List *top, *r;
+ for (top = r = NULL; s != NULL; s = s->n) {
+ if (top == NULL)
+ r = top = (*alloc)(sizeof (List));
+ else
+ r = r->n = (*alloc)(sizeof (List));
+ r->w = (*alloc)(strlen(s->w) + 1);
+ strcpy(r->w, s->w);
+ r->m = NULL;
+ }
+ if (r != NULL)
+ r->n = NULL;
+ return top;
}
/* Length of list */
extern size_t listlen(List *s) {
- size_t size;
- for (size = 0; s != NULL; s = s->n)
- size += strlen(s->w) + 1;
- return size;
+ size_t size;
+ for (size = 0; s != NULL; s = s->n)
+ size += strlen(s->w) + 1;
+ return size;
}
/* Number of elements in list */
extern int listnel(List *s) {
- int nel;
- for (nel = 0; s != NULL; s = s->n)
- nel++;
- return nel;
+ int nel;
+ for (nel = 0; s != NULL; s = s->n)
+ nel++;
+ return nel;
}
#include "rc.h"
char* ARGV0;
-bool interactive;
+bool dashee, dasheye, dashen, dashpee, interactive;
pid_t rc_pid;
+static bool dashEYE, dashell, dashoh;
+
static void assigndefault(char *,...);
static void checkfd(int, enum redirtype);
void usage(void) {
- printf("Usage: %s [OPTION...] [FILE [ARG...]]\n", ARGV0);
+ printf("Usage: %s [OPTION...] [FILE [ARG...]]\n", ARGV0);
}
extern int main(int argc, char *argv[], char *envp[]) {
- char *dollarzero, *null[1];
- initprint();
- ARGV0 = dollarzero = argv[0];
- rc_pid = getpid();
+ char *dashsee[2], *dollarzero, *null[1];
+ initprint();
+ dashsee[0] = dashsee[1] = NULL;
+ dollarzero = argv[0];
+ rc_pid = getpid();
+ dashell = (*argv[0] == '-'); /* login shell, per unix tradition */
+
+ OPTBEGIN {
+ case 'e': dashee = true; break;
+ case 'l': dashell = true; break;
+ case 'n': dashen = true; break;
+ case 'o': dashoh = true; break;
+ case 'p': dashpee = true; break;
+ case 'i':
+ dasheye = true;
+ interactive = true;
+ break;
+ case 'I':
+ dashEYE = true;
+ interactive = false;
+ break;
+ case 'c':
+ dashsee[0] = EOPTARG(usage());
+ break;
+ } OPTEND;
+
+ /* use isatty() iff neither -i nor -I is set, and iff the input is not from a script or -c flags */
+ if (!dasheye && !dashEYE && dashsee[0] == NULL && (*argv == NULL))
+ interactive = isatty(0);
+ if (!dashoh) {
+ checkfd(0, rFrom);
+ checkfd(1, rCreate);
+ checkfd(2, rCreate);
+ }
+ initsignal();
+ inithash();
+ initparse();
+ assigndefault("ifs", " ", "\t", "\n", (void *)0);
+#ifdef DEFAULTPATH
+ assigndefault("path", DEFAULTPATH, (void *)0);
+#endif
+ assigndefault("pid", nprint("%d", rc_pid), (void *)0);
+ assigndefault("prompt", "; ", "", (void *)0);
+ assigndefault("version", VERSION, "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $", (void *)0);
+ initenv(envp);
+ initinput();
+ null[0] = NULL;
+ starassign(dollarzero, null, false); /* assign $0 to $* */
+ inithandler();
+
+ if (dashell) {
+ char *rcrc;
+ int fd;
+
+ rcrc = concat(varlookup("home"), word("/.rcrc", NULL))->w;
+ fd = rc_open(rcrc, rFrom);
+ if (fd == -1) {
+ if (errno != ENOENT)
+ uerror(rcrc);
+ } else {
+ bool push_interactive;
- /* use isatty() iff neither -i nor -I is set, and iff the input is not from a script or -c flags */
- interactive = isatty(0);
- checkfd(0, rFrom);
- checkfd(1, rCreate);
- checkfd(2, rCreate);
-
- initsignal();
- inithash();
- initparse();
- assigndefault("ifs", " ", "\t", "\n", (void *)0);
- assigndefault("path", DEFAULTPATH, (void *)0);
- assigndefault("pid", nprint("%d", rc_pid), (void *)0);
- assigndefault("prompt", "; ", "", (void *)0);
- assigndefault("version", VERSION, "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $", (void *)0);
- initenv(envp);
- initinput();
- null[0] = NULL;
- starassign(dollarzero, null, false); /* assign $0 to $* */
- inithandler();
+ pushfd(fd);
+ push_interactive = interactive;
+ interactive = false;
+ doit(true);
+ interactive = push_interactive;
+ close(fd);
+ }
+ }
- pushfd(0); // Read stdin
- doit(true);
- rc_exit(getstatus());
- return 0; /* Never really reached. */
+ if (dashsee[0] != NULL) { /* input from -c or -s? */
+ if (*argv != NULL)
+ starassign(dollarzero, argv, false);
+ pushstring(dashsee, true);
+ } else if (*argv != NULL) { /* else from a file? */
+ b_dot(--argv);
+ rc_exit(getstatus());
+ } else { /* else stdin */
+ pushfd(0);
+ }
+ dasheye = false;
+ doit(true);
+ rc_exit(getstatus());
+ return 0; /* Never really reached. */
}
static void assigndefault(char *name,...) {
- va_list ap;
- List *l;
- char *v;
- va_start(ap, name);
- for (l = NULL; (v = va_arg(ap, char *)) != NULL;)
- l = append(l, word(v, NULL));
- varassign(name, l, false);
- set_exportable(name, false);
- if (streq(name, "path"))
- alias(name, l, false);
- va_end(ap);
+ va_list ap;
+ List *l;
+ char *v;
+ va_start(ap, name);
+ for (l = NULL; (v = va_arg(ap, char *)) != NULL;)
+ l = append(l, word(v, NULL));
+ varassign(name, l, false);
+ set_exportable(name, false);
+ if (streq(name, "path"))
+ alias(name, l, false);
+ va_end(ap);
}
/* open an fd on /dev/null if it is inherited closed */
static void checkfd(int fd, enum redirtype r) {
- int new = rc_open("/dev/null", r);
- if (new != fd && new != -1)
- close(new);
+ int new = rc_open("/dev/null", r);
+ if (new != fd && new != -1)
+ close(new);
}
/* match() matches a single pattern against a single string. */
extern bool match(char *p, char *m, char *s) {
- int i, j;
- if (m == NULL)
- return streq(p, s);
- i = 0;
- while (1) {
- if (p[i] == '\0')
- return *s == '\0';
- else if (m[i]) {
- switch (p[i++]) {
- case '?':
- if (*s++ == '\0')
- return false;
- break;
- case '*':
- while (p[i] == '*' && m[i] == 1) /* collapse multiple stars */
- i++;
- if (p[i] == '\0') /* star at end of pattern? */
- return true;
- while (*s != '\0')
- if (match(p + i, m + i, s++))
- return true;
- return false;
- case '[':
- if (*s == '\0')
- return false;
- switch (j = rangematch(p + i, *s)) {
- default:
- i += j;
- break;
- case RANGE_FAIL:
- return false;
- case RANGE_ERROR:
- if (*s != '[')
- return false;
- }
- s++;
- break;
- default:
- panic("bad metacharacter in match");
- /* NOTREACHED */
- return false; /* hush up gcc -Wall */
- }
- } else if (p[i++] != *s++)
- return false;
- }
+ int i, j;
+ if (m == NULL)
+ return streq(p, s);
+ i = 0;
+ while (1) {
+ if (p[i] == '\0')
+ return *s == '\0';
+ else if (m[i]) {
+ switch (p[i++]) {
+ case '?':
+ if (*s++ == '\0')
+ return false;
+ break;
+ case '*':
+ while (p[i] == '*' && m[i] == 1) /* collapse multiple stars */
+ i++;
+ if (p[i] == '\0') /* star at end of pattern? */
+ return true;
+ while (*s != '\0')
+ if (match(p + i, m + i, s++))
+ return true;
+ return false;
+ case '[':
+ if (*s == '\0')
+ return false;
+ switch (j = rangematch(p + i, *s)) {
+ default:
+ i += j;
+ break;
+ case RANGE_FAIL:
+ return false;
+ case RANGE_ERROR:
+ if (*s != '[')
+ return false;
+ }
+ s++;
+ break;
+ default:
+ panic("bad metacharacter in match");
+ /* NOTREACHED */
+ return false; /* hush up gcc -Wall */
+ }
+ } else if (p[i++] != *s++)
+ return false;
+ }
}
/*
From the ed(1) man pages (on ranges):
- The `-' is treated as an ordinary character if it occurs first
- (or first after an initial ^) or last in the string.
+ The `-' is treated as an ordinary character if it occurs first
+ (or first after an initial ^) or last in the string.
- The right square bracket does not terminate the enclosed string
- if it is the first character (after an initial `^', if any), in
- the bracketed string.
+ The right square bracket does not terminate the enclosed string
+ if it is the first character (after an initial `^', if any), in
+ the bracketed string.
rangematch() matches a single character against a class, and returns
an integer offset to the end of the range on success, or -1 on
*/
static int rangematch(char *p, char c) {
- char *orig = p;
- bool neg = (*p == '~');
- bool matched = false;
- if (neg)
- p++;
- if (*p == ']') {
- p++;
- matched = (c == ']');
- }
- for (; *p != ']'; p++) {
- if (*p == '\0')
- return RANGE_ERROR; /* bad syntax */
- if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */
- if (c >= *p)
- matched |= (c <= p[2]);
- p += 2;
- } else {
- matched |= (*p == c);
- }
- }
- if (matched ^ neg)
- return p - orig + 1; /* skip the right-bracket */
- else
- return RANGE_FAIL;
+ char *orig = p;
+ bool neg = (*p == '~');
+ bool matched = false;
+ if (neg)
+ p++;
+ if (*p == ']') {
+ p++;
+ matched = (c == ']');
+ }
+ for (; *p != ']'; p++) {
+ if (*p == '\0')
+ return RANGE_ERROR; /* bad syntax */
+ if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */
+ if (c >= *p)
+ matched |= (c <= p[2]);
+ p += 2;
+ } else {
+ matched |= (*p == c);
+ }
+ }
+ if (matched ^ neg)
+ return p - orig + 1; /* skip the right-bracket */
+ else
+ return RANGE_FAIL;
}
static struct signaming signamings[] = {
#ifdef SIGABRT
- { SIGABRT, "sigabrt", "abort"},
+ { SIGABRT, "sigabrt", "abort"},
#endif
#ifdef SIGALRM
- { SIGALRM, "sigalrm", "alarm clock"},
+ { SIGALRM, "sigalrm", "alarm clock"},
#endif
#ifdef SIGBREAK
- { SIGBREAK, "sigbreak", "break"},
+ { SIGBREAK, "sigbreak", "break"},
#endif
#ifdef SIGBUS
- { SIGBUS, "sigbus", "bus error"},
+ { SIGBUS, "sigbus", "bus error"},
#endif
#ifdef SIGCANCEL
- { SIGCANCEL, "sigcancel", "thread cancellation"},
+ { SIGCANCEL, "sigcancel", "thread cancellation"},
#endif
#ifdef SIGCHLD
- { SIGCHLD, "sigchld", "child stop or exit"},
+ { SIGCHLD, "sigchld", "child stop or exit"},
#endif
#ifdef SIGCLD
- { SIGCLD, "sigcld", "child stop or exit"},
+ { SIGCLD, "sigcld", "child stop or exit"},
#endif
#ifdef SIGCONT
- { SIGCONT, "sigcont", "continue"},
+ { SIGCONT, "sigcont", "continue"},
#endif
#ifdef SIGDIL
- { SIGDIL, "sigdil", "dil signal"},
+ { SIGDIL, "sigdil", "dil signal"},
#endif
#ifdef SIGEMT
- { SIGEMT, "sigemt", "emt instruction"},
+ { SIGEMT, "sigemt", "emt instruction"},
#endif
#ifdef SIGFPE
- { SIGFPE, "sigfpe", "floating point error"},
+ { SIGFPE, "sigfpe", "floating point error"},
#endif
#ifdef SIGFREEZE
- { SIGFREEZE, "sigfreeze", "cpr freeze"},
+ { SIGFREEZE, "sigfreeze", "cpr freeze"},
#endif
#ifdef SIGHUP
- { SIGHUP, "sighup", "hangup"},
+ { SIGHUP, "sighup", "hangup"},
#endif
#ifdef SIGILL
- { SIGILL, "sigill", "illegal instruction"},
+ { SIGILL, "sigill", "illegal instruction"},
#endif
/* We don't want a default message for SIGINT. */
#ifdef SIGINT
- { SIGINT, "sigint", ""},
+ { SIGINT, "sigint", ""},
#endif
#ifdef SIGIO
- { SIGIO, "sigio", "socket i/o possible"},
+ { SIGIO, "sigio", "socket i/o possible"},
#endif
#ifdef SIGIOT
- { SIGIOT, "sigiot", "iot instruction"},
+ { SIGIOT, "sigiot", "iot instruction"},
#endif
#ifdef SIGKILL
- { SIGKILL, "sigkill", "killed"},
+ { SIGKILL, "sigkill", "killed"},
#endif
#ifdef SIGLOST
- { SIGLOST, "siglost", "resource lost"},
+ { SIGLOST, "siglost", "resource lost"},
#endif
#ifdef SIGLWP
- { SIGLWP, "siglwp", "thread library signal"},
+ { SIGLWP, "siglwp", "thread library signal"},
#endif
/* By default, SIGPIPEs are silent. */
#ifdef SIGPIPE
- { SIGPIPE, "sigpipe", ""},
+ { SIGPIPE, "sigpipe", ""},
#endif
#ifdef SIGPOLL
- { SIGPOLL, "sigpoll", "pollable event occurred"},
+ { SIGPOLL, "sigpoll", "pollable event occurred"},
#endif
#ifdef SIGPROF
- { SIGPROF, "sigprof", "profiling timer alarm"},
+ { SIGPROF, "sigprof", "profiling timer alarm"},
#endif
#ifdef SIGPWR
- { SIGPWR, "sigpwr", "power-fail restart"},
+ { SIGPWR, "sigpwr", "power-fail restart"},
#endif
#ifdef SIGQUIT
- { SIGQUIT, "sigquit", "quit"},
+ { SIGQUIT, "sigquit", "quit"},
#endif
#ifdef SIGSEGV
- { SIGSEGV, "sigsegv", "segmentation violation"},
+ { SIGSEGV, "sigsegv", "segmentation violation"},
#endif
#ifdef SIGSTKFLT
- { SIGSTKFLT, "sigstkflt", "stack fault"},
+ { SIGSTKFLT, "sigstkflt", "stack fault"},
#endif
#ifdef SIGSTOP
- { SIGSTOP, "sigstop", "stopped by program"},
+ { SIGSTOP, "sigstop", "stopped by program"},
#endif
#ifdef SIGSYS
- { SIGSYS, "sigsys", "invalid argument to system call"},
+ { SIGSYS, "sigsys", "invalid argument to system call"},
#endif
#ifdef SIGTERM
- { SIGTERM, "sigterm", "terminated"},
+ { SIGTERM, "sigterm", "terminated"},
#endif
#ifdef SIGTHAW
- { SIGTHAW, "sigthaw", "cpr thaw"},
+ { SIGTHAW, "sigthaw", "cpr thaw"},
#endif
#ifdef SIGTRAP
- { SIGTRAP, "sigtrap", "trace trap"},
+ { SIGTRAP, "sigtrap", "trace trap"},
#endif
#ifdef SIGTSTP
- { SIGTSTP, "sigtstp", "stopped"},
+ { SIGTSTP, "sigtstp", "stopped"},
#endif
#ifdef SIGTTIN
- { SIGTTIN, "sigttin", "background tty read"},
+ { SIGTTIN, "sigttin", "background tty read"},
#endif
#ifdef SIGTTOU
- { SIGTTOU, "sigttou", "background tty write"},
+ { SIGTTOU, "sigttou", "background tty write"},
#endif
#ifdef SIGURG
- { SIGURG, "sigurg", "urgent condition on i/o channel"},
+ { SIGURG, "sigurg", "urgent condition on i/o channel"},
#endif
#ifdef SIGUSR1
- { SIGUSR1, "sigusr1", "user defined signal 1"},
+ { SIGUSR1, "sigusr1", "user defined signal 1"},
#endif
#ifdef SIGUSR2
- { SIGUSR2, "sigusr2", "user defined signal 2"},
+ { SIGUSR2, "sigusr2", "user defined signal 2"},
#endif
#ifdef SIGVTALRM
- { SIGVTALRM, "sigvtalrm", "virtual timer alarm"},
+ { SIGVTALRM, "sigvtalrm", "virtual timer alarm"},
#endif
#ifdef SIGWAITING
- { SIGWAITING, "sigwaiting", "lwps blocked"},
+ { SIGWAITING, "sigwaiting", "lwps blocked"},
#endif
#ifdef SIGWINCH
- { SIGWINCH, "sigwinch", "window size change"},
+ { SIGWINCH, "sigwinch", "window size change"},
#endif
#ifdef SIGWINDOW
- { SIGWINDOW, "sigwindow", "window size change"},
+ { SIGWINDOW, "sigwindow", "window size change"},
#endif
#ifdef SIGXCPU
- { SIGXCPU, "sigxcpu", "exceeded cpu time limit"},
+ { SIGXCPU, "sigxcpu", "exceeded cpu time limit"},
#endif
#ifdef SIGXFSZ
- { SIGXFSZ, "sigxfsz", "exceeded file size limit"},
+ { SIGXFSZ, "sigxfsz", "exceeded file size limit"},
#endif
#ifdef SIGSAK
- { SIGSAK, "sigsak", "secure attention key"},
+ { SIGSAK, "sigsak", "secure attention key"},
#endif
#ifdef SIGSOUND
- { SIGSOUND, "sigsound", "hft sound sequence completed"},
+ { SIGSOUND, "sigsound", "hft sound sequence completed"},
#endif
#ifdef SIGRETRACT
- { SIGRETRACT, "sigretract", "hft monitor mode retracted"},
+ { SIGRETRACT, "sigretract", "hft monitor mode retracted"},
#endif
#ifdef SIGKAP
- { SIGKAP, "sigkap", "keep alive poll"},
+ { SIGKAP, "sigkap", "keep alive poll"},
#endif
#ifdef SIGGRANT
- { SIGGRANT, "siggrant", "hft monitor mode granted"},
+ { SIGGRANT, "siggrant", "hft monitor mode granted"},
#endif
#ifdef SIGALRM1
- { SIGALRM1, "sigalrm1", "m:n condition alarm"},
+ { SIGALRM1, "sigalrm1", "m:n condition alarm"},
#endif
#ifdef SIGVIRT
- { SIGVIRT, "sigvirt", "virtual time alarm"},
+ { SIGVIRT, "sigvirt", "virtual time alarm"},
#endif
#ifdef SIGPRE
- { SIGPRE, "sigpre", "programming error"},
+ { SIGPRE, "sigpre", "programming error"},
#endif
#ifdef SIGMIGRATE
- { SIGMIGRATE, "sigmigrate", "migrate process"},
+ { SIGMIGRATE, "sigmigrate", "migrate process"},
#endif
#ifdef SIGDANGER
- { SIGDANGER, "sigdanger", "system crash imminent"},
+ { SIGDANGER, "sigdanger", "system crash imminent"},
#endif
#ifdef SIGMSG
- { SIGMSG, "sigmsg", "hft input data pending"},
+ { SIGMSG, "sigmsg", "hft input data pending"},
#endif
#ifdef SIGINFO
- { SIGINFO, "siginfo", "information request"},
+ { SIGINFO, "siginfo", "information request"},
#endif
{ 0, 0, 0}
};
FILE *outf;
for (snp = signamings; snp->signo; ++snp)
- if (snp->signo > maxsig)
- maxsig = snp->signo;
+ if (snp->signo > maxsig)
+ maxsig = snp->signo;
outf = fopen("sigmsgs.h", "w");
if (!outf) barf("could not open sigmsgs.h for writing");
/* yes, we could avoid the quadratic searching with an aux array. fap. */
for (s = 1; s <= maxsig; ++s) {
for (snp = signamings; snp->signo && snp->signo != s; ++snp)
- /* */;
- if (snp->signo)
- fprintf(outf, "\t{\"%s\",\t\"%s\"},\n",
- snp->signame, snp->sigmsg);
- else
- fprintf(outf, "\t{\"sigunknown%d\",\t\"unknown signal %d\"},\n",
- s, s);
+ /* */;
+ if (snp->signo)
+ fprintf(outf, "\t{\"%s\",\t\"%s\"},\n",
+ snp->signame, snp->sigmsg);
+ else
+ fprintf(outf, "\t{\"sigunknown%d\",\t\"unknown signal %d\"},\n",
+ s, s);
}
fprintf(outf, "};\n");
if (fclose(outf) == EOF) barf("could not fclose sigmsgs.c after writing");
#include <unistd.h>
int main(void) {
- int cstatus, pstatus;
- pid_t pid;
-
- for (cstatus = 0; cstatus < 2; ++cstatus) {
- switch (pid = fork()) {
- case -1:
- perror("fork");
- return 1;
- case 0:
- _exit(cstatus);
- default:
- if (wait(&pstatus) != pid) {
- perror("wait");
- return 1;
- }
- printf("#define STATUS%d %d\n", cstatus, pstatus);
- }
- }
- return 0;
+ int cstatus, pstatus;
+ pid_t pid;
+
+ for (cstatus = 0; cstatus < 2; ++cstatus) {
+ switch (pid = fork()) {
+ case -1:
+ perror("fork");
+ return 1;
+ case 0:
+ _exit(cstatus);
+ default:
+ if (wait(&pstatus) != pid) {
+ perror("wait");
+ return 1;
+ }
+ printf("#define STATUS%d %d\n", cstatus, pstatus);
+ }
+ }
+ return 0;
}
#include "rc.h"
static struct Block {
- size_t used, size;
- char *mem;
- Block *n;
+ size_t used, size;
+ char *mem;
+ Block *n;
} *fl, *ul;
/* alignto() works only with power of 2 blocks and assumes 2's complement arithmetic */
/* Allocate a block from the free list or malloc one if none in the fl fit */
static void getblock(size_t n) {
- Block *r, *p;
- for (r = fl, p = NULL; r != NULL; p = r, r = r->n)
- if (n <= r->size)
- break; /* look for a block which fits the request */
- if (r != NULL) { /* if one is found, take it off the free list */
- if (p != NULL)
- p->n = r->n;
- else
- fl = r->n;
- } else { /* else allocate a new block */
- r = enew(Block);
- r->mem = ealloc(r->size = alignto(n, BLOCKSIZE));
- }
- r->used = 0;
- r->n = ul;
- ul = r;
+ Block *r, *p;
+ for (r = fl, p = NULL; r != NULL; p = r, r = r->n)
+ if (n <= r->size)
+ break; /* look for a block which fits the request */
+ if (r != NULL) { /* if one is found, take it off the free list */
+ if (p != NULL)
+ p->n = r->n;
+ else
+ fl = r->n;
+ } else { /* else allocate a new block */
+ r = enew(Block);
+ r->mem = ealloc(r->size = alignto(n, BLOCKSIZE));
+ }
+ r->used = 0;
+ r->n = ul;
+ ul = r;
}
/*
*/
extern void *nalloc(size_t n) {
- size_t base;
- Block *ulp;
- n = alignto(n, sizeof(align_t));
- ulp = ul;
- if (ulp != NULL && n + (base = ulp->used) < ulp->size) {
- ulp->used = base + n;
- return &ulp->mem[base];
- } else {
- getblock(n);
- assert(ul->used == 0);
- (ulp = ul)->used = n;
- return &ulp->mem[0];
- }
+ size_t base;
+ Block *ulp;
+ n = alignto(n, sizeof(long));
+ ulp = ul;
+ if (ulp != NULL && n + (base = ulp->used) < ulp->size) {
+ ulp->used = base + n;
+ return &ulp->mem[base];
+ } else {
+ getblock(n);
+ assert(ul->used == 0);
+ (ulp = ul)->used = n;
+ return &ulp->mem[0];
+ }
}
/*
#define MAXMEM 500000
extern void nfree() {
- size_t count;
- Block *r;
- if (ul == NULL)
- return;
- for (r = ul; r->n != NULL; r = r->n)
- ; /* get to end of used list */
- r->n = fl; /* tack free list onto it */
- fl = ul; /* and make it the free list */
- ul = NULL; /* finally, zero out the used list */
- for (r = fl, count = r->size; r->n != NULL; r = r->n, count += r->size) {
- if (count >= MAXMEM) {
- Block *tmp = r;
- r = r->n;
- tmp->n = NULL; /* terminate the free list */
- while (r != NULL) { /* free memory off the tail of the free list */
- tmp = r->n;
- efree(r->mem);
- efree(r);
- r = tmp;
- }
- return;
- }
- }
+ size_t count;
+ Block *r;
+ if (ul == NULL)
+ return;
+ for (r = ul; r->n != NULL; r = r->n)
+ ; /* get to end of used list */
+ r->n = fl; /* tack free list onto it */
+ fl = ul; /* and make it the free list */
+ ul = NULL; /* finally, zero out the used list */
+ for (r = fl, count = r->size; r->n != NULL; r = r->n, count += r->size) {
+ if (count >= MAXMEM) {
+ Block *tmp = r;
+ r = r->n;
+ tmp->n = NULL; /* terminate the free list */
+ while (r != NULL) { /* free memory off the tail of the free list */
+ tmp = r->n;
+ efree(r->mem);
+ efree(r);
+ r = tmp;
+ }
+ return;
+ }
+ }
}
/*
*/
extern Block *newblock() {
- Block *old = ul;
- ul = NULL;
- return old;
+ Block *old = ul;
+ ul = NULL;
+ return old;
}
/* "Restores" an arena to its saved value. */
extern void restoreblock(Block *old) {
- nfree();
- ul = old;
+ nfree();
+ ul = old;
}
/* generic memory allocation functions */
extern void *ealloc(size_t n) {
- void *p;
-
- assert(n);
- p = malloc(n);
- if (p == NULL) {
- uerror("malloc");
- rc_exit(1);
- }
- return p;
+ void *p;
+
+ assert(n);
+ p = malloc(n);
+ if (p == NULL) {
+ uerror("malloc");
+ rc_exit(1);
+ }
+ return p;
}
extern void *erealloc(void *p, size_t n) {
- if (p == NULL) /* erealloc() has POSIX realloc() semantics */
- return ealloc(n);
- if ((p = realloc(p, n)) == NULL) {
- uerror("realloc");
- rc_exit(1);
- }
- return p;
+ if (p == NULL) /* erealloc() has POSIX realloc() semantics */
+ return ealloc(n);
+ if ((p = realloc(p, n)) == NULL) {
+ uerror("realloc");
+ rc_exit(1);
+ }
+ return p;
}
extern void efree(void *p) {
- if (p != NULL)
- free(p);
+ if (p != NULL)
+ free(p);
}
Opens a file with the necessary flags. Assumes the following
declaration for redirtype:
- enum redirtype {
- rFrom, rCreate, rAppend, rHeredoc, rHerestring
- };
+ enum redirtype {
+ rFrom, rCreate, rAppend, rHeredoc, rHerestring
+ };
*/
static const int mode_masks[] = {
- /* rFrom */ O_RDONLY,
- /* rCreate */ O_TRUNC | O_CREAT | O_WRONLY,
- /* rAppend */ O_APPEND | O_CREAT | O_WRONLY
+ /* rFrom */ O_RDONLY,
+ /* rCreate */ O_TRUNC | O_CREAT | O_WRONLY,
+ /* rAppend */ O_APPEND | O_CREAT | O_WRONLY
};
extern int rc_open(const char *name, redirtype m) {
- if ((unsigned) m >= arraysize(mode_masks))
- panic("bad mode passed to rc_open");
- return open(name, mode_masks[m], 0666);
+ if ((unsigned) m >= arraysize(mode_masks))
+ panic("bad mode passed to rc_open");
+ return open(name, mode_masks[m], 0666);
}
/* make a file descriptor blocking. return value indicates whether
the desciptor was previously set to non-blocking. */
extern bool makeblocking(int fd) {
- int flags;
-
- if ((flags = fcntl(fd, F_GETFL)) == -1) {
- uerror("fcntl");
- rc_error(NULL);
- }
- if (! (flags & O_NONBLOCK))
- return false;
- flags &= ~O_NONBLOCK;
- if (fcntl(fd, F_SETFL, (long) flags) == -1) {
- uerror("fcntl");
- rc_error(NULL);
- }
- return true;
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL)) == -1) {
+ uerror("fcntl");
+ rc_error(NULL);
+ }
+ if (! (flags & O_NONBLOCK))
+ return false;
+ flags &= ~O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, (long) flags) == -1) {
+ uerror("fcntl");
+ rc_error(NULL);
+ }
+ return true;
}
/* make a file descriptor the same pgrp as us. Returns true if
it changes anything. */
extern bool makesamepgrp(int fd) {
- pid_t grp;
+ pid_t grp;
- grp = getpgrp();
+ grp = getpgrp();
- if (tcgetpgrp(fd) == grp)
- return false;
+ if (tcgetpgrp(fd) == grp)
+ return false;
- if (tcsetpgrp(fd, grp) < 0) {
- uerror("tcsetgrp");
- return false;
- }
- return true;
+ if (tcsetpgrp(fd, grp) < 0) {
+ uerror("tcsetgrp");
+ return false;
+ }
+ return true;
}
+++ /dev/null
-/* print.c -- formatted printing routines (Paul Haahr, 12/91) */
-
-#include "rc.h"
-
-#define PRINT_ALLOCSIZE ((size_t)64)
-#define SPRINT_BUFSIZ ((size_t)1024)
-
-#define MAXCONV 256
-
-/*
- * conversion functions
- * true return -> flag changes only, not a conversion
- */
-
-#define Flag(name, flag) \
-static bool name(Format *format, int ignore) { \
- format->flags |= flag; \
- return true; \
-}
-
-Flag(uconv, FMT_unsigned)
-Flag(rc_lconv, FMT_long)
-Flag(altconv, FMT_altform)
-Flag(leftconv, FMT_leftside)
-Flag(dotconv, FMT_f2set)
-
-static bool digitconv(Format *format, int c) {
- if (format->flags & FMT_f2set)
- format->f2 = 10 * format->f2 + c - '0';
- else {
- format->flags |= FMT_f1set;
- format->f1 = 10 * format->f1 + c - '0';
- }
- return true;
-}
-
-static bool zeroconv(Format *format, int ignore) {
- if (format->flags & (FMT_f1set | FMT_f2set))
- return digitconv(format, '0');
- format->flags |= FMT_zeropad;
- return true;
-}
-
-static void pad(Format *format, size_t len, int c) {
- while (len-- != 0)
- fmtputc(format, c);
-}
-
-static bool sconv(Format *format, int ignore) {
- char *s = va_arg(format->args, char *);
- if ((format->flags & FMT_f1set) == 0)
- fmtcat(format, s);
- else {
- size_t len = strlen(s), width = format->f1 - len;
- if (format->flags & FMT_leftside) {
- fmtappend(format, s, len);
- pad(format, width, ' ');
- } else {
- pad(format, width, ' ');
- fmtappend(format, s, len);
- }
- }
- return false;
-}
-
-static char *rc_utoa(unsigned long u, char *t, unsigned int radix, const char *digit) {
- if (u >= radix) {
- t = rc_utoa(u / radix, t, radix, digit);
- u %= radix;
- }
- *t++ = digit[u];
- return t;
-}
-
-static void intconv(Format *format, unsigned int radix, int upper, const char *altform) {
- static const char * const table[] = {
- "0123456789abcdefghijklmnopqrstuvwxyz",
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- };
- char padchar;
- size_t len, pre, zeroes, padding, width;
- long n, flags;
- unsigned long u;
- char number[64], prefix[20];
-
- if (radix > 36)
- return;
-
- flags = format->flags;
-
- if (flags & FMT_long)
- n = va_arg(format->args, long);
- else
- n = va_arg(format->args, int);
-
- pre = 0;
- if ((flags & FMT_unsigned) || n >= 0)
- u = n;
- else {
- prefix[pre++] = '-';
- u = -n;
- }
-
- if (flags & FMT_altform)
- while (*altform != '\0')
- prefix[pre++] = *altform++;
-
- len = rc_utoa(u, number, radix, table[upper]) - number;
- if ((flags & FMT_f2set) && (size_t) format->f2 > len)
- zeroes = format->f2 - len;
- else
- zeroes = 0;
-
- width = pre + zeroes + len;
- if ((flags & FMT_f1set) && (size_t) format->f1 > width) {
- padding = format->f1 - width;
- } else
- padding = 0;
-
- padchar = ' ';
- if (padding > 0 && flags & FMT_zeropad) {
- padchar = '0';
- if ((flags & FMT_leftside) == 0) {
- zeroes += padding;
- padding = 0;
- }
- }
-
-
- if ((flags & FMT_leftside) == 0)
- pad(format, padding, padchar);
- fmtappend(format, prefix, pre);
- pad(format, zeroes, '0');
- fmtappend(format, number, len);
- if (flags & FMT_leftside)
- pad(format, padding, padchar);
-}
-
-static bool cconv(Format *format, int ignore) {
- fmtputc(format, va_arg(format->args, int));
- return false;
-}
-
-static bool dconv(Format *format, int ignore) {
- intconv(format, 10, 0, "");
- return false;
-}
-
-static bool oconv(Format *format, int ignore) {
- intconv(format, 8, 0, "0");
- return false;
-}
-
-static bool xconv(Format *format, int ignore) {
- intconv(format, 16, 0, "0x");
- return false;
-}
-
-static bool pctconv(Format *format, int ignore) {
- fmtputc(format, '%');
- return false;
-}
-
-static bool badconv(Format *ignore, int ign0re) {
- panic("bad conversion character in printfmt");
- /* NOTREACHED */
- return false; /* hush up gcc -Wall */
-}
-
-
-/*
- * conversion table management
- */
-
-static Conv fmttab[MAXCONV];
-
-static void inittab(void) {
- int i;
- for (i = 0; i < MAXCONV; i++)
- fmttab[i] = badconv;
-
- fmttab['s'] = sconv;
- fmttab['c'] = cconv;
- fmttab['d'] = dconv;
- fmttab['o'] = oconv;
- fmttab['x'] = xconv;
- fmttab['%'] = pctconv;
-
- fmttab['u'] = uconv;
- fmttab['l'] = rc_lconv;
- fmttab['#'] = altconv;
- fmttab['-'] = leftconv;
- fmttab['.'] = dotconv;
-
- fmttab['0'] = zeroconv;
- for (i = '1'; i <= '9'; i++)
- fmttab[i] = digitconv;
-}
-
-extern bool (*fmtinstall(int c, bool (*f)(Format *, int)))(Format *, int) {
-/*Conv fmtinstall(int c, Conv f) {*/
- Conv oldf;
- if (fmttab[0] == NULL)
- inittab();
- c &= MAXCONV - 1;
- oldf = fmttab[c];
- if (f != NULL)
- fmttab[c] = f;
- return oldf;
-}
-
-
-/*
- * functions for inserting strings in the format buffer
- */
-
-extern void fmtappend(Format *format, const char *s, size_t len) {
- while (format->buf + len > format->bufend) {
- size_t split = format->bufend - format->buf;
- memcpy(format->buf, s, split);
- format->buf += split;
- s += split;
- len -= split;
- (*format->grow)(format, len);
- }
- memcpy(format->buf, s, len);
- format->buf += len;
-}
-
-extern void fmtcat(Format *format, const char *s) {
- fmtappend(format, s, strlen(s));
-}
-
-/*
- * printfmt -- the driver routine
- */
-
-extern int printfmt(Format *format, const char *fmt) {
- unsigned const char *s = (unsigned const char *) fmt;
-
- if (fmttab[0] == NULL)
- inittab();
-
- for (;;) {
- int c = *s++;
- switch (c) {
- case '%':
- format->flags = format->f1 = format->f2 = 0;
- do
- c = *s++;
- while ((*fmttab[c])(format, c));
- break;
- case '\0':
- return format->buf - format->bufbegin + format->flushed;
- default:
- fmtputc(format, c);
- break;
- }
- }
-}
-
-
-/*
- * the public entry points
- */
-
-extern int fmtprint(Format *format, const char *fmt,...) {
- int n = -format->flushed;
- va_list ap, saveargs;
-
- va_start(ap, fmt);
- va_copy(saveargs, format->args);
- va_copy(format->args, ap);
- n += printfmt(format, fmt);
- va_end(format->args);
- va_copy(format->args, saveargs);
-
- return n + format->flushed;
-}
-
-static void fprint_flush(Format *format, size_t ignore) {
- size_t n = format->buf - format->bufbegin;
- char *buf = format->bufbegin;
-
- format->flushed += n;
- format->buf = format->bufbegin;
- writeall(format->u.n, buf, n);
-}
-
-extern int fprint(int fd, const char *fmt,...) {
- char buf[1024];
- Format format;
- va_list ap;
-
- format.buf = buf;
- format.bufbegin = buf;
- format.bufend = buf + sizeof buf;
- format.grow = fprint_flush;
- format.flushed = 0;
- format.u.n = fd;
-
- va_start(ap, fmt);
- va_copy(format.args, ap);
- printfmt(&format, fmt);
- va_end(format.args);
-
- fprint_flush(&format, 0);
- return format.flushed;
-}
-
-static void memprint_grow(Format *format, size_t more) {
- char *buf;
- size_t len = format->bufend - format->bufbegin + 1;
- size_t used = format->buf - format->bufbegin;
-
- len = (len >= more)
- ? len * 2
- : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1);
- if (format->u.n)
- buf = erealloc(format->bufbegin, len);
- else {
- buf = nalloc(len);
- memcpy(buf, format->bufbegin, used);
- }
- format->buf = buf + used;
- format->bufbegin = buf;
- format->bufend = buf + len - 1;
-}
-
-static char *memprint(Format *format, const char *fmt, char *buf, size_t len) {
- format->buf = buf;
- format->bufbegin = buf;
- format->bufend = buf + len - 1;
- format->grow = memprint_grow;
- format->flushed = 0;
- printfmt(format, fmt);
- *format->buf = '\0';
- return format->bufbegin;
-}
-
-extern char *mprint(const char *fmt,...) {
- Format format;
- char *result;
- va_list ap;
-
- format.u.n = 1;
- va_start(ap, fmt);
- va_copy(format.args, ap);
- result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
- va_end(format.args);
- return result;
-}
-
-extern char *nprint(const char *fmt,...) {
- Format format;
- char *result;
- va_list ap;
-
- format.u.n = 0;
- va_start(ap, fmt);
- va_copy(format.args, ap);
- result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
- va_end(format.args);
- return result;
-}
-
-extern void writeall(int fd, char *buf, size_t remain) {
- int i;
-
- for (i = 0; remain > 0; buf += i, remain -= i)
- if ((i = write(fd, buf, remain)) <= 0)
- break; /* abort silently on errors in write() */
- sigchk();
-}
*/
extern void doredirs() {
- List *fname;
- int fd, p[2];
- Rq *r;
- for (r = redirq; r != NULL; r = r->n) {
- switch(r->r->type) {
- default:
- panic("unexpected node in doredirs");
- /* NOTREACHED */
- case nRedir:
- if (r->r->u[0].i == rHerestring) {
- fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */
- if (pipe(p) < 0) {
- uerror("pipe");
- rc_error(NULL);
- }
- if (rc_fork() == 0) { /* child writes to pipe */
- setsigdefaults(false);
- close(p[0]);
- if (fname != NULL)
- writeall(p[1], fname->w, strlen(fname->w));
- exit(0);
- } else {
- close(p[1]);
- if (mvfd(p[0], r->r->u[1].i) < 0)
- rc_error(NULL);
- }
- } else {
- fname = glob(glom(r->r->u[2].p));
- if (fname == NULL)
- rc_error("null filename in redirection");
- if (fname->n != NULL)
- rc_error("multi-word filename in redirection");
- switch (r->r->u[0].i) {
- default:
- panic("unexpected node in doredirs");
- /* NOTREACHED */
- case rCreate: case rAppend: case rFrom:
- fd = rc_open(fname->w, r->r->u[0].i);
- break;
- }
- if (fd < 0) {
- uerror(fname->w);
- rc_error(NULL);
- }
- if (mvfd(fd, r->r->u[1].i) < 0)
- rc_error(NULL);
- }
- break;
- case nDup:
- if (r->r->u[2].i == -1)
- close(r->r->u[1].i);
- else if (r->r->u[2].i != r->r->u[1].i) {
- if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) {
- uerror("dup2");
- rc_error(NULL);
- }
- }
- }
- }
- redirq = NULL;
+ List *fname;
+ int fd, p[2];
+ Rq *r;
+ for (r = redirq; r != NULL; r = r->n) {
+ switch(r->r->type) {
+ default:
+ panic("unexpected node in doredirs");
+ /* NOTREACHED */
+ case nRedir:
+ if (r->r->u[0].i == rHerestring) {
+ fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */
+ if (pipe(p) < 0) {
+ uerror("pipe");
+ rc_error(NULL);
+ }
+ if (rc_fork() == 0) { /* child writes to pipe */
+ setsigdefaults(false);
+ close(p[0]);
+ if (fname != NULL)
+ writeall(p[1], fname->w, strlen(fname->w));
+ exit(0);
+ } else {
+ close(p[1]);
+ if (mvfd(p[0], r->r->u[1].i) < 0)
+ rc_error(NULL);
+ }
+ } else {
+ fname = glob(glom(r->r->u[2].p));
+ if (fname == NULL)
+ rc_error("null filename in redirection");
+ if (fname->n != NULL)
+ rc_error("multi-word filename in redirection");
+ switch (r->r->u[0].i) {
+ default:
+ panic("unexpected node in doredirs");
+ /* NOTREACHED */
+ case rCreate: case rAppend: case rFrom:
+ fd = rc_open(fname->w, r->r->u[0].i);
+ break;
+ }
+ if (fd < 0) {
+ uerror(fname->w);
+ rc_error(NULL);
+ }
+ if (mvfd(fd, r->r->u[1].i) < 0)
+ rc_error(NULL);
+ }
+ break;
+ case nDup:
+ if (r->r->u[2].i == -1)
+ close(r->r->u[1].i);
+ else if (r->r->u[2].i != r->r->u[1].i) {
+ if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) {
+ uerror("dup2");
+ rc_error(NULL);
+ }
+ }
+ }
+ }
+ redirq = NULL;
}
#include "rc.h"
void (*sys_signal(int signum, void (*handler)(int)))(int) {
- struct sigaction new, old;
+ struct sigaction new, old;
- new.sa_handler = handler;
- new.sa_flags = 0; /* clear SA_RESTART */
- sigfillset(&new.sa_mask);
- sigaction(signum, &new, &old);
- return old.sa_handler;
+ new.sa_handler = handler;
+ new.sa_flags = 0; /* clear SA_RESTART */
+ sigfillset(&new.sa_mask);
+ sigaction(signum, &new, &old);
+ return old.sa_handler;
}
void (*sighandlers[NSIG])(int);
static volatile sig_atomic_t sigcount, caught[NSIG];
extern void catcher(int s) {
- if (caught[s] == 0) {
- sigcount++;
- caught[s] = 1;
- }
- sys_signal(s, catcher);
+ if (caught[s] == 0) {
+ sigcount++;
+ caught[s] = 1;
+ }
+ sys_signal(s, catcher);
}
extern void sigchk() {
- void (*h)(int);
- int s, i;
+ void (*h)(int);
+ int s, i;
- if (sigcount == 0)
- return; /* ho hum; life as usual */
- if (forked)
- exit(1); /* exit unconditionally on a signal in a child process */
- for (i = 0, s = -1; i < NSIG; i++)
- if (caught[i] != 0) {
- s = i;
- --sigcount;
- caught[s] = 0;
- break;
- }
- if (s == -1)
- panic("all-zero sig vector with nonzero sigcount");
- if ((h = sighandlers[s]) == SIG_DFL)
- panic("caught signal set to SIG_DFL");
- if (h == SIG_IGN)
- panic("caught signal set to SIG_IGN");
- (*h)(s);
+ if (sigcount == 0)
+ return; /* ho hum; life as usual */
+ if (forked)
+ exit(1); /* exit unconditionally on a signal in a child process */
+ for (i = 0, s = -1; i < NSIG; i++)
+ if (caught[i] != 0) {
+ s = i;
+ --sigcount;
+ caught[s] = 0;
+ break;
+ }
+ if (s == -1)
+ panic("all-zero sig vector with nonzero sigcount");
+ if ((h = sighandlers[s]) == SIG_DFL)
+ panic("caught signal set to SIG_DFL");
+ if (h == SIG_IGN)
+ panic("caught signal set to SIG_IGN");
+ (*h)(s);
}
extern void (*rc_signal(int s, void (*h)(int)))(int) {
- void (*old)(int);
- sigchk();
- old = sighandlers[s];
- sighandlers[s] = h;
- if (h == SIG_DFL || h == SIG_IGN)
- sys_signal(s, h);
- else
- sys_signal(s, catcher);
- return old;
+ void (*old)(int);
+ sigchk();
+ old = sighandlers[s];
+ sighandlers[s] = h;
+ if (h == SIG_DFL || h == SIG_IGN)
+ sys_signal(s, h);
+ else
+ sys_signal(s, catcher);
+ return old;
}
extern void initsignal() {
- void (*h)(int);
- int i;
+ void (*h)(int);
+ int i;
- for (i = 1; i < NSIG; i++) {
+ for (i = 1; i < NSIG; i++) {
#ifdef SIGKILL
- if (i == SIGKILL) continue;
+ if (i == SIGKILL) continue;
#endif
#ifdef SIGSTOP
- if (i == SIGSTOP) continue;
+ if (i == SIGSTOP) continue;
#endif
- h = sys_signal(i, SIG_IGN);
- if (h != SIG_IGN && h != SIG_ERR)
- sys_signal(i, h);
- sighandlers[i] = h;
- }
+ h = sys_signal(i, SIG_IGN);
+ if (h != SIG_IGN && h != SIG_ERR)
+ sys_signal(i, h);
+ sighandlers[i] = h;
+ }
}
*/
extern int istrue() {
- int i;
- for (i = 0; i < pipelength; i++)
- if (statuses[i] != 0)
- return false;
- return true;
+ int i;
+ for (i = 0; i < pipelength; i++)
+ if (statuses[i] != 0)
+ return false;
+ return true;
}
/*
*/
extern int getstatus() {
- int s;
- if (pipelength > 1)
- return !istrue();
- s = statuses[0];
- if (WIFSIGNALED(s))
- return 1;
- return WEXITSTATUS(s);
+ int s;
+ if (pipelength > 1)
+ return !istrue();
+ s = statuses[0];
+ if (WIFSIGNALED(s))
+ return 1;
+ return WEXITSTATUS(s);
}
extern void set(bool code) {
- setstatus(-1, code ? STATUS0 : STATUS1);
+ setstatus(-1, code ? STATUS0 : STATUS1);
}
/* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */
extern void setpipestatus(int stats[], int num) {
- int i;
- for (i = 0; i < (pipelength = num); i++) {
- statprint(-1, stats[i]);
- statuses[i] = stats[i];
- }
+ int i;
+ for (i = 0; i < (pipelength = num); i++) {
+ statprint(-1, stats[i]);
+ statuses[i] = stats[i];
+ }
}
/* set a simple status, as opposed to a pipeline */
extern void setstatus(pid_t pid, int i) {
- pipelength = 1;
- statuses[0] = i;
- statprint(pid, i);
+ pipelength = 1;
+ statuses[0] = i;
+ statprint(pid, i);
}
/* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */
extern void statprint(pid_t pid, int i) {
- if (WIFSIGNALED(i)) {
- int t = WTERMSIG(i);
- char *msg = ((t > 0) && (t < NSIG) ? signals[WTERMSIG(i)].msg : "");
- if (pid != -1)
- fprint(2, "%ld: ", (long)pid);
- if (myWIFDUMPED(i)) {
- if (*msg == '\0')
- fprint(2, "core dumped\n");
- else
- fprint(2, "%s--core dumped\n", msg);
- } else if (*msg != '\0')
- fprint(2, "%s\n", msg);
- }
+ if (WIFSIGNALED(i)) {
+ int t = WTERMSIG(i);
+ char *msg = ((t > 0) && (t < NSIG) ? signals[WTERMSIG(i)].msg : "");
+ if (pid != -1)
+ fprintf(stderr, "%ld: ", (long)pid);
+ if (myWIFDUMPED(i)) {
+ if (*msg == '\0')
+ fprintf(stderr, "core dumped\n");
+ else
+ fprintf(stderr, "%s--core dumped\n", msg);
+ } else if (*msg != '\0')
+ fprintf(stderr, "%s\n", msg);
+ }
}
/* prepare a list to be passed back. Used whenever $status is dereferenced */
extern List *sgetstatus() {
- List *r = NULL;
- int i;
-
- for (i = 0; i < pipelength; i++) {
- List *q = nnew(List);
- q->w = strstatus(statuses[i]);
- q->m = NULL;
- q->n = r;
- r = q;
- }
-
- return r;
+ List *r = NULL;
+ int i;
+
+ for (i = 0; i < pipelength; i++) {
+ List *q = nnew(List);
+ q->w = strstatus(statuses[i]);
+ q->m = NULL;
+ q->n = r;
+ r = q;
+ }
+
+ return r;
}
/* return status as a string (used above and for bqstatus) */
extern char *strstatus(int s) {
- if (WIFSIGNALED(s)) {
- int t = WTERMSIG(s);
- const char *core = myWIFDUMPED(s) ? "+core" : "";
- if ((t > 0) && (t < NSIG) && *signals[t].name != '\0')
- return nprint("%s%s", signals[t].name, core);
- else
- return nprint("-%d%s", t, core); /* unknown signals are negated */
- } else
- return nprint("%d", WEXITSTATUS(s));
+ if (WIFSIGNALED(s)) {
+ int t = WTERMSIG(s);
+ const char *core = myWIFDUMPED(s) ? "+core" : "";
+ if ((t > 0) && (t < NSIG) && *signals[t].name != '\0')
+ return nprint("%s%s", signals[t].name, core);
+ else
+ return nprint("-%d%s", t, core); /* unknown signals are negated */
+ } else
+ return nprint("%d", WEXITSTATUS(s));
}
extern void ssetstatus(char **av) {
- int i, j, k, l;
- bool found;
- for (l = 0; av[l] != NULL; l++)
- ; /* count up array length */
- --l;
- for (i = 0; av[i] != NULL; i++) {
- j = a2u(av[i]);
- if (j >= 0) {
- statuses[l - i] = j << 8;
- continue;
- }
- found = false;
- for (k = 0; k < NSIG; k++) {
- if (streq(signals[k].name, av[i])) {
- statuses[l - i] = k;
- found = true;
- break;
- }
- else {
- size_t len = strlen(signals[k].name);
- if (strncmp(signals[k].name, av[i], len) == 0 && streq(av[i] + len, "+core")) {
- statuses[l - i] = k + 0x80;
- found = true;
- break;
- }
- }
- }
- if (!found) {
- fprint(2, "bad status\n");
- set(false);
- return;
- }
- }
- pipelength = i;
+ int i, j, k, l;
+ bool found;
+ for (l = 0; av[l] != NULL; l++)
+ ; /* count up array length */
+ --l;
+ for (i = 0; av[i] != NULL; i++) {
+ j = a2u(av[i]);
+ if (j >= 0) {
+ statuses[l - i] = j << 8;
+ continue;
+ }
+ found = false;
+ for (k = 0; k < NSIG; k++) {
+ if (streq(signals[k].name, av[i])) {
+ statuses[l - i] = k;
+ found = true;
+ break;
+ }
+ else {
+ size_t len = strlen(signals[k].name);
+ if (strncmp(signals[k].name, av[i], len) == 0 && streq(av[i] + len, "+core")) {
+ statuses[l - i] = k + 0x80;
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ fprintf(stderr, "bad status\n");
+ set(false);
+ return;
+ }
+ }
+ pipelength = i;
}
/* make a new node, pass it back to yyparse. Used to generate the parsetree. */
extern Node *mk(int /*nodetype*/ t,...) {
- va_list ap;
- Node *n;
- va_start(ap, t);
- switch (t) {
- default:
- panic("unexpected node in mk");
- /* NOTREACHED */
- case nDup:
- n = nalloc(offsetof(Node, u[3]));
- n->u[0].i = va_arg(ap, int);
- n->u[1].i = va_arg(ap, int);
- n->u[2].i = va_arg(ap, int);
- break;
- case nWord:
- n = nalloc(offsetof(Node, u[3]));
- n->u[0].s = va_arg(ap, char *);
- n->u[1].s = va_arg(ap, char *);
- n->u[2].i = va_arg(ap, int);
- break;
- case nBang: case nNowait:
- case nCount: case nFlat: case nRmfn: case nSubshell:
- case nVar: case nCase:
- n = nalloc(offsetof(Node, u[1]));
- n->u[0].p = va_arg(ap, Node *);
- break;
- case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
- case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
- case nOrelse: case nPre: case nArgs: case nSwitch:
- case nMatch: case nVarsub: case nWhile: case nLappend:
- n = nalloc(offsetof(Node, u[2]));
- n->u[0].p = va_arg(ap, Node *);
- n->u[1].p = va_arg(ap, Node *);
- break;
- case nForin:
- n = nalloc(offsetof(Node, u[3]));
- n->u[0].p = va_arg(ap, Node *);
- n->u[1].p = va_arg(ap, Node *);
- n->u[2].p = va_arg(ap, Node *);
- break;
- case nPipe:
- n = nalloc(offsetof(Node, u[4]));
- n->u[0].i = va_arg(ap, int);
- n->u[1].i = va_arg(ap, int);
- n->u[2].p = va_arg(ap, Node *);
- n->u[3].p = va_arg(ap, Node *);
- break;
- case nRedir:
- case nNmpipe:
- n = nalloc(offsetof(Node, u[3]));
- n->u[0].i = va_arg(ap, int);
- n->u[1].i = va_arg(ap, int);
- n->u[2].p = va_arg(ap, Node *);
- break;
- }
- n->type = t;
- va_end(ap);
- return n;
+ va_list ap;
+ Node *n;
+ va_start(ap, t);
+ switch (t) {
+ default:
+ panic("unexpected node in mk");
+ /* NOTREACHED */
+ case nDup:
+ n = nalloc(offsetof(Node, u[3]));
+ n->u[0].i = va_arg(ap, int);
+ n->u[1].i = va_arg(ap, int);
+ n->u[2].i = va_arg(ap, int);
+ break;
+ case nWord:
+ n = nalloc(offsetof(Node, u[3]));
+ n->u[0].s = va_arg(ap, char *);
+ n->u[1].s = va_arg(ap, char *);
+ n->u[2].i = va_arg(ap, int);
+ break;
+ case nBang: case nNowait:
+ case nCount: case nFlat: case nRmfn: case nSubshell:
+ case nVar: case nCase:
+ n = nalloc(offsetof(Node, u[1]));
+ n->u[0].p = va_arg(ap, Node *);
+ break;
+ case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
+ case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
+ case nOrelse: case nPre: case nArgs: case nSwitch:
+ case nMatch: case nVarsub: case nWhile: case nLappend:
+ n = nalloc(offsetof(Node, u[2]));
+ n->u[0].p = va_arg(ap, Node *);
+ n->u[1].p = va_arg(ap, Node *);
+ break;
+ case nForin:
+ n = nalloc(offsetof(Node, u[3]));
+ n->u[0].p = va_arg(ap, Node *);
+ n->u[1].p = va_arg(ap, Node *);
+ n->u[2].p = va_arg(ap, Node *);
+ break;
+ case nPipe:
+ n = nalloc(offsetof(Node, u[4]));
+ n->u[0].i = va_arg(ap, int);
+ n->u[1].i = va_arg(ap, int);
+ n->u[2].p = va_arg(ap, Node *);
+ n->u[3].p = va_arg(ap, Node *);
+ break;
+ case nRedir:
+ case nNmpipe:
+ n = nalloc(offsetof(Node, u[3]));
+ n->u[0].i = va_arg(ap, int);
+ n->u[1].i = va_arg(ap, int);
+ n->u[2].p = va_arg(ap, Node *);
+ break;
+ }
+ n->type = t;
+ va_end(ap);
+ return n;
}
/* copy a tree to malloc space. Used when storing the definition of a function */
extern Node *treecpy(Node *s, void *(*alloc)(size_t)) {
- Node *n;
- if (s == NULL)
- return NULL;
- switch (s->type) {
- default:
- panic("unexpected node in treecpy");
- /* NOTREACHED */
- case nDup:
- n = (*alloc)(offsetof(Node, u[3]));
- n->u[0].i = s->u[0].i;
- n->u[1].i = s->u[1].i;
- n->u[2].i = s->u[2].i;
- break;
- case nWord:
- n = (*alloc)(offsetof(Node, u[3]));
- n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s);
- if (s->u[1].s != NULL) {
- size_t i = strlen(s->u[0].s);
- n->u[1].s = (*alloc)(i);
- memcpy(n->u[1].s, s->u[1].s, i);
- } else
- n->u[1].s = NULL;
- n->u[2].i = s->u[2].i;
- break;
- case nBang: case nNowait: case nCase:
- case nCount: case nFlat: case nRmfn: case nSubshell: case nVar:
- n = (*alloc)(offsetof(Node, u[1]));
- n->u[0].p = treecpy(s->u[0].p, alloc);
- break;
- case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
- case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
- case nOrelse: case nPre: case nArgs: case nSwitch:
- case nMatch: case nVarsub: case nWhile: case nLappend:
- n = (*alloc)(offsetof(Node, u[2]));
- n->u[0].p = treecpy(s->u[0].p, alloc);
- n->u[1].p = treecpy(s->u[1].p, alloc);
- break;
- case nForin:
- n = (*alloc)(offsetof(Node, u[3]));
- n->u[0].p = treecpy(s->u[0].p, alloc);
- n->u[1].p = treecpy(s->u[1].p, alloc);
- n->u[2].p = treecpy(s->u[2].p, alloc);
- break;
- case nPipe:
- n = (*alloc)(offsetof(Node, u[4]));
- n->u[0].i = s->u[0].i;
- n->u[1].i = s->u[1].i;
- n->u[2].p = treecpy(s->u[2].p, alloc);
- n->u[3].p = treecpy(s->u[3].p, alloc);
- break;
- case nRedir:
- case nNmpipe:
- n = (*alloc)(offsetof(Node, u[3]));
- n->u[0].i = s->u[0].i;
- n->u[1].i = s->u[1].i;
- n->u[2].p = treecpy(s->u[2].p, alloc);
- break;
- }
- n->type = s->type;
- return n;
+ Node *n;
+ if (s == NULL)
+ return NULL;
+ switch (s->type) {
+ default:
+ panic("unexpected node in treecpy");
+ /* NOTREACHED */
+ case nDup:
+ n = (*alloc)(offsetof(Node, u[3]));
+ n->u[0].i = s->u[0].i;
+ n->u[1].i = s->u[1].i;
+ n->u[2].i = s->u[2].i;
+ break;
+ case nWord:
+ n = (*alloc)(offsetof(Node, u[3]));
+ n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s);
+ if (s->u[1].s != NULL) {
+ size_t i = strlen(s->u[0].s);
+ n->u[1].s = (*alloc)(i);
+ memcpy(n->u[1].s, s->u[1].s, i);
+ } else
+ n->u[1].s = NULL;
+ n->u[2].i = s->u[2].i;
+ break;
+ case nBang: case nNowait: case nCase:
+ case nCount: case nFlat: case nRmfn: case nSubshell: case nVar:
+ n = (*alloc)(offsetof(Node, u[1]));
+ n->u[0].p = treecpy(s->u[0].p, alloc);
+ break;
+ case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
+ case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
+ case nOrelse: case nPre: case nArgs: case nSwitch:
+ case nMatch: case nVarsub: case nWhile: case nLappend:
+ n = (*alloc)(offsetof(Node, u[2]));
+ n->u[0].p = treecpy(s->u[0].p, alloc);
+ n->u[1].p = treecpy(s->u[1].p, alloc);
+ break;
+ case nForin:
+ n = (*alloc)(offsetof(Node, u[3]));
+ n->u[0].p = treecpy(s->u[0].p, alloc);
+ n->u[1].p = treecpy(s->u[1].p, alloc);
+ n->u[2].p = treecpy(s->u[2].p, alloc);
+ break;
+ case nPipe:
+ n = (*alloc)(offsetof(Node, u[4]));
+ n->u[0].i = s->u[0].i;
+ n->u[1].i = s->u[1].i;
+ n->u[2].p = treecpy(s->u[2].p, alloc);
+ n->u[3].p = treecpy(s->u[3].p, alloc);
+ break;
+ case nRedir:
+ case nNmpipe:
+ n = (*alloc)(offsetof(Node, u[3]));
+ n->u[0].i = s->u[0].i;
+ n->u[1].i = s->u[1].i;
+ n->u[2].p = treecpy(s->u[2].p, alloc);
+ break;
+ }
+ n->type = s->type;
+ return n;
}
/* free a function definition that is no longer needed */
extern void treefree(Node *s) {
- if (s == NULL)
- return;
- switch (s->type) {
- default:
- panic("unexpected node in treefree");
- /* NOTREACHED */
- case nDup:
- break;
- case nWord:
- efree(s->u[0].s);
- efree(s->u[1].s);
- break;
- case nBang: case nNowait:
- case nCount: case nFlat: case nRmfn:
- case nSubshell: case nVar: case nCase:
- treefree(s->u[0].p);
- break;
- case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
- case nElse: case nEpilog: case nIf: case nNewfn:
- case nOrelse: case nPre: case nArgs: case nCbody:
- case nSwitch: case nMatch: case nVarsub: case nWhile:
- case nLappend:
- treefree(s->u[1].p);
- treefree(s->u[0].p);
- break;
- case nForin:
- treefree(s->u[2].p);
- treefree(s->u[1].p);
- treefree(s->u[0].p);
- break;
- case nPipe:
- treefree(s->u[2].p);
- treefree(s->u[3].p);
- break;
- case nRedir:
- case nNmpipe:
- treefree(s->u[2].p);
- }
- efree(s);
+ if (s == NULL)
+ return;
+ switch (s->type) {
+ default:
+ panic("unexpected node in treefree");
+ /* NOTREACHED */
+ case nDup:
+ break;
+ case nWord:
+ efree(s->u[0].s);
+ efree(s->u[1].s);
+ break;
+ case nBang: case nNowait:
+ case nCount: case nFlat: case nRmfn:
+ case nSubshell: case nVar: case nCase:
+ treefree(s->u[0].p);
+ break;
+ case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
+ case nElse: case nEpilog: case nIf: case nNewfn:
+ case nOrelse: case nPre: case nArgs: case nCbody:
+ case nSwitch: case nMatch: case nVarsub: case nWhile:
+ case nLappend:
+ treefree(s->u[1].p);
+ treefree(s->u[0].p);
+ break;
+ case nForin:
+ treefree(s->u[2].p);
+ treefree(s->u[1].p);
+ treefree(s->u[0].p);
+ break;
+ case nPipe:
+ treefree(s->u[2].p);
+ treefree(s->u[3].p);
+ break;
+ case nRedir:
+ case nNmpipe:
+ treefree(s->u[2].p);
+ }
+ efree(s);
}
/* print error with line number on noninteractive shells (i.e., scripts) */
extern void pr_error(char *s, int offset) {
- if (s != NULL) {
- if (interactive)
- fprint(2, RC "%s\n", s);
- else
- fprint(2, RC "line %d: %s\n", lineno + offset, s);
- }
+ if (s != NULL) {
+ if (interactive)
+ fprintf(stderr, RC "%s\n", s);
+ else
+ fprintf(stderr, RC "line %d: %s\n", lineno + offset, s);
+ }
}
/* our perror */
extern void uerror(char *s) {
- char *err;
+ char *err;
- err = strerror(errno);
- if (!err) err = "unknown error";
+ err = strerror(errno);
+ if (!err) err = "unknown error";
- if (s)
- fprint(2, RC "%s: %s\n", s, err);
- else
- fprint(2, RC "%s\n", err);
+ if (s)
+ fprintf(stderr, RC "%s: %s\n", s, err);
+ else
+ fprintf(stderr, RC "%s\n", err);
}
/* Die horribly. This should never get called. Please let me know if it does. */
#define PANICMSG "rc panic: "
extern void panic(char *s) {
- write(2, PANICMSG, conststrlen(PANICMSG));
- write(2, s, strlen(s));
- write(2, "!\n", 2);
- exit(1);
+ write(2, PANICMSG, conststrlen(PANICMSG));
+ write(2, s, strlen(s));
+ write(2, "!\n", 2);
+ exit(1);
}
/* ascii -> unsigned conversion routines. -1 indicates conversion error. */
extern int n2u(char *s, unsigned int base) {
- unsigned int i;
- for (i = 0; *s != '\0'; s++) {
- unsigned int j = (unsigned int) *s - '0';
- if (j >= base) /* small hack with unsigned ints -- one compare for range test */
- return -1;
- i = i * base + j;
- }
- return (int) i;
+ unsigned int i;
+ for (i = 0; *s != '\0'; s++) {
+ unsigned int j = (unsigned int) *s - '0';
+ if (j >= base) /* small hack with unsigned ints -- one compare for range test */
+ return -1;
+ i = i * base + j;
+ }
+ return (int) i;
}
/* The last word in portable ANSI: a strcmp wrapper for qsort */
extern int starstrcmp(const void *s1, const void *s2) {
- return strcmp(*(char * const *)s1, *(char * const *)s2);
+ return strcmp(*(char * const *)s1, *(char * const *)s2);
}
/* tests to see if pathname begins with "/", "./", or "../" */
extern bool isabsolute(char *path) {
- return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
+ return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
}
/* duplicate a fd and close the old one only if necessary */
extern int mvfd(int i, int j) {
- if (i != j) {
- int s = dup2(i, j);
- close(i);
- return s;
- }
- return 0;
+ if (i != j) {
+ int s = dup2(i, j);
+ close(i);
+ return s;
+ }
+ return 0;
}
static int hasalias(char *);
static char *const aliases[] = {
- "home", "HOME", "path", "PATH", "cdpath", "CDPATH"
+ "home", "HOME", "path", "PATH", "cdpath", "CDPATH"
};
/* assign a variable in List form to a name, stacking if appropriate */
extern void varassign(char *name, List *def, bool stack) {
- Variable *new;
- List *newdef = listcpy(def, ealloc); /* important to do the listcpy first; get_var_place() frees old values */
- new = get_var_place(name, stack);
- new->def = newdef;
- new->extdef = NULL;
- set_exportable(name, true);
+ Variable *new;
+ List *newdef = listcpy(def, ealloc); /* important to do the listcpy first; get_var_place() frees old values */
+ new = get_var_place(name, stack);
+ new->def = newdef;
+ new->extdef = NULL;
+ set_exportable(name, true);
}
/* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
extern bool varassign_string(char *extdef) {
- static bool aliasset[arraysize(aliases)] = {
- false, false, false, false, false, false
- };
- char *name = get_name(extdef);
- Variable *new;
- int i;
- if (name == NULL)
- return false; /* add it to bozo env */
- if ((i = hasalias(name)) != -1) {
- aliasset[i] = true;
- i ^= 1; /* set i to the "opposite" case subscript and */
- if (i&1 && aliasset[i]) /* don't alias variables that are already set in upper case */
- return true;
- }
- new = get_var_place(name, false);
- new->def = NULL;
- new->extdef = ealloc(strlen(extdef) + 1);
- strcpy(new->extdef, extdef);
- if (i != -1)
- alias(name, varlookup(name), false);
- set_exportable(name, true);
- return true;
+ static bool aliasset[arraysize(aliases)] = {
+ false, false, false, false, false, false
+ };
+ char *name = get_name(extdef);
+ Variable *new;
+ int i;
+ if (name == NULL)
+ return false; /* add it to bozo env */
+ if ((i = hasalias(name)) != -1) {
+ aliasset[i] = true;
+ i ^= 1; /* set i to the "opposite" case subscript and */
+ if (i&1 && aliasset[i]) /* don't alias variables that are already set in upper case */
+ return true;
+ }
+ new = get_var_place(name, false);
+ new->def = NULL;
+ new->extdef = ealloc(strlen(extdef) + 1);
+ strcpy(new->extdef, extdef);
+ if (i != -1)
+ alias(name, varlookup(name), false);
+ set_exportable(name, true);
+ return true;
}
/*
*/
extern List *varlookup(char *name) {
- Variable *look;
- List *ret, *l;
- int sub;
- if (streq(name, "apids"))
- return sgetapids();
- if (streq(name, "status"))
- return sgetstatus();
- if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
- for (l = varlookup("*"); l != NULL && sub != 0; --sub)
- l = l->n;
- if (l == NULL)
- return NULL;
- ret = nnew(List);
- ret->w = l->w;
- ret->m = NULL;
- ret->n = NULL;
- return ret;
- }
- look = lookup_var(name);
- if (look == NULL)
- return NULL; /* not found */
- if (look->def != NULL)
- return look->def;
- if (look->extdef == NULL)
- return NULL; /* variable was set to null, e.g., a=() echo foo */
- ret = parse_var(look->extdef);
- if (ret == NULL) {
- look->extdef = NULL;
- return NULL;
- }
- return look->def = ret;
+ Variable *look;
+ List *ret, *l;
+ int sub;
+ if (streq(name, "apids"))
+ return sgetapids();
+ if (streq(name, "status"))
+ return sgetstatus();
+ if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
+ for (l = varlookup("*"); l != NULL && sub != 0; --sub)
+ l = l->n;
+ if (l == NULL)
+ return NULL;
+ ret = nnew(List);
+ ret->w = l->w;
+ ret->m = NULL;
+ ret->n = NULL;
+ return ret;
+ }
+ look = lookup_var(name);
+ if (look == NULL)
+ return NULL; /* not found */
+ if (look->def != NULL)
+ return look->def;
+ if (look->extdef == NULL)
+ return NULL; /* variable was set to null, e.g., a=() echo foo */
+ ret = parse_var(look->extdef);
+ if (ret == NULL) {
+ look->extdef = NULL;
+ return NULL;
+ }
+ return look->def = ret;
}
/* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */
extern char *varlookup_string(char *name) {
- Variable *look;
- look = lookup_var(name);
- if (look == NULL)
- return NULL;
- if (look->extdef != NULL)
- return look->extdef;
- if (look->def == NULL)
- return NULL;
- return look->extdef = mprint("%F=%W", name, look->def);
+ Variable *look;
+ look = lookup_var(name);
+ if (look == NULL)
+ return NULL;
+ if (look->extdef != NULL)
+ return look->extdef;
+ if (look->def == NULL)
+ return NULL;
+ return look->extdef = mprint("%F=%W", name, look->def);
}
/* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
extern void varrm(char *name, bool stack) {
- int i = hasalias(name);
- if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
- varassign("*", varlookup("0"), false);
- return;
- }
- delete_var(name, stack);
- if (i != -1)
- delete_var(aliases[i^1], stack);
+ int i = hasalias(name);
+ if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
+ varassign("*", varlookup("0"), false);
+ return;
+ }
+ delete_var(name, stack);
+ if (i != -1)
+ delete_var(aliases[i^1], stack);
}
/* assign a value (List) to a variable, using array "a" as input. Used to assign $* */
extern void starassign(char *dollarzero, char **a, bool stack) {
- List *s, *var;
- var = nnew(List);
- var->w = dollarzero;
- if (*a == NULL) {
- var->n = NULL;
- varassign("*", var, stack);
- return;
- }
- var->n = s = nnew(List);
- while (1) {
- s->w = *a++;
- if (*a == NULL) {
- s->n = NULL;
- break;
- } else
- s = s->n = nnew(List);
- }
- varassign("*", var, stack);
+ List *s, *var;
+ var = nnew(List);
+ var->w = dollarzero;
+ if (*a == NULL) {
+ var->n = NULL;
+ varassign("*", var, stack);
+ return;
+ }
+ var->n = s = nnew(List);
+ while (1) {
+ s->w = *a++;
+ if (*a == NULL) {
+ s->n = NULL;
+ break;
+ } else
+ s = s->n = nnew(List);
+ }
+ varassign("*", var, stack);
}
/* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */
static void colonassign(char *name, List *def, bool stack) {
- List dud;
- if (def == NULL) {
- varassign(name, NULL, stack);
- return;
- }
- dud.w = nprint("%-L", def, ":");
- dud.n = NULL;
- varassign(name, &dud, stack);
+ List dud;
+ if (def == NULL) {
+ varassign(name, NULL, stack);
+ return;
+ }
+ dud.w = nprint("%-L", def, ":");
+ dud.n = NULL;
+ varassign(name, &dud, stack);
}
/* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */
static void listassign(char *name, List *def, bool stack) {
- List *val, *r;
- char *v, *w;
- if (def == NULL) {
- varassign(name, NULL, stack);
- return;
- }
- v = def->w;
- r = val = nnew(List);
- while ((w = strchr(v, ':')) != NULL) {
- *w = '\0';
- r->w = ncpy(v);
- *w = ':';
- v = w + 1;
- r = r->n = nnew(List);
- }
- r->w = ncpy(v);
- r->n = NULL;
- varassign(name, val, stack);
+ List *val, *r;
+ char *v, *w;
+ if (def == NULL) {
+ varassign(name, NULL, stack);
+ return;
+ }
+ v = def->w;
+ r = val = nnew(List);
+ while ((w = strchr(v, ':')) != NULL) {
+ *w = '\0';
+ r->w = ncpy(v);
+ *w = ':';
+ v = w + 1;
+ r = r->n = nnew(List);
+ }
+ r->w = ncpy(v);
+ r->n = NULL;
+ varassign(name, val, stack);
}
/* check to see if a particular variable is aliased; return -1 on failure, or the index */
static int hasalias(char *name) {
- int i;
- for (i = 0; i < arraysize(aliases); i++)
- if (streq(name, aliases[i]))
- return i;
- return -1;
+ int i;
+ for (i = 0; i < arraysize(aliases); i++)
+ if (streq(name, aliases[i]))
+ return i;
+ return -1;
}
/* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */
extern void alias(char *name, List *s, bool stack) {
- static void (*vectors[])(char *, List *, bool) = {
- varassign, varassign, colonassign, listassign, colonassign, listassign
- };
- int i = hasalias(name);
- if (i != -1)
- (*vectors[i])(aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
+ static void (*vectors[])(char *, List *, bool) = {
+ varassign, varassign, colonassign, listassign, colonassign, listassign
+ };
+ int i = hasalias(name);
+ if (i != -1)
+ (*vectors[i])(aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
}
extern void prettyprint_var(int fd, char *name, List *s) {
- int i;
- static const char * const keywords[] = {
- "if", "in", "fn", "for", "else", "switch", "while", "case"
- };
- if (s == NULL) {
- fprint(fd, "%S=()\n", name);
- return;
- }
- if (streq(name, "*")) {
- s = s->n;
- if (s == NULL)
- return; /* Don't print $0, and if $* is not set, skip it */
- }
- for (i = 0; i < arraysize(keywords); i++)
- if (streq(keywords[i], name)) {
- fprint(fd, "%#S=", name);
- goto value;
- }
- fprint(fd, "%S=", name);
+ int i;
+ static const char * const keywords[] = {
+ "if", "in", "fn", "for", "else", "switch", "while", "case"
+ };
+ if (s == NULL) {
+ fprint(fd, "%S=()\n", name);
+ return;
+ }
+ if (streq(name, "*")) {
+ s = s->n;
+ if (s == NULL)
+ return; /* Don't print $0, and if $* is not set, skip it */
+ }
+ for (i = 0; i < arraysize(keywords); i++)
+ if (streq(keywords[i], name)) {
+ fprint(fd, "%#S=", name);
+ goto value;
+ }
+ fprint(fd, "%S=", name);
value:
- fprint(fd, s->n == NULL ? "%L\n" : "(%L)\n", s, " ");
+ fprint(fd, s->n == NULL ? "%L\n" : "(%L)\n", s, " ");
}
typedef struct Pid Pid;
static struct Pid {
- pid_t pid;
- int stat;
- bool alive;
- Pid *n;
+ pid_t pid;
+ int stat;
+ bool alive;
+ Pid *n;
} *plist = NULL;
extern pid_t rc_fork() {
- Pid *new;
- struct Pid *p, *q;
- pid_t pid = fork();
+ Pid *new;
+ struct Pid *p, *q;
+ pid_t pid = fork();
- switch (pid) {
- case -1:
- uerror("fork");
- rc_error(NULL);
- /* NOTREACHED */
- case 0:
- forked = true;
- sigchk();
- p = plist; q = 0;
- while (p) {
- if (q) efree(q);
- q = p;
- p = p->n;
- }
- if (q) efree(q);
- plist = 0;
- return 0;
- default:
- new = enew(Pid);
- new->pid = pid;
- new->alive = true;
- new->n = plist;
- plist = new;
- return pid;
- }
+ switch (pid) {
+ case -1:
+ uerror("fork");
+ rc_error(NULL);
+ /* NOTREACHED */
+ case 0:
+ forked = true;
+ sigchk();
+ p = plist; q = 0;
+ while (p) {
+ if (q) efree(q);
+ q = p;
+ p = p->n;
+ }
+ if (q) efree(q);
+ plist = 0;
+ return 0;
+ default:
+ new = enew(Pid);
+ new->pid = pid;
+ new->alive = true;
+ new->n = plist;
+ plist = new;
+ return pid;
+ }
}
extern pid_t rc_wait4(pid_t pid, int *stat, bool nointr) {
- Pid *r, *prev;
+ Pid *r, *prev;
- /* Find the child on the list. */
- for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n)
- if (r->pid == pid)
- break;
+ /* Find the child on the list. */
+ for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n)
+ if (r->pid == pid)
+ break;
- /* Uh-oh, not there. */
- if (r == NULL) {
- errno = ECHILD; /* no children */
- uerror("wait");
- *stat = 0x100; /* exit(1) */
- return -1;
- }
+ /* Uh-oh, not there. */
+ if (r == NULL) {
+ errno = ECHILD; /* no children */
+ uerror("wait");
+ *stat = 0x100; /* exit(1) */
+ return -1;
+ }
- /* If it's still alive, wait() for it. */
- while (r->alive) {
- int ret;
- Pid *q;
+ /* If it's still alive, wait() for it. */
+ while (r->alive) {
+ int ret;
+ Pid *q;
- ret = wait(stat);
+ ret = wait(stat);
- if (ret < 0) {
- if (errno == ECHILD)
- panic("lost child");
- if (nointr)
- continue;
- else
- return ret;
- }
+ if (ret < 0) {
+ if (errno == ECHILD)
+ panic("lost child");
+ if (nointr)
+ continue;
+ else
+ return ret;
+ }
- for (q = plist; q != NULL; q = q->n)
- if (q->pid == ret) {
- q->alive = false;
- q->stat = *stat;
- break;
- }
- }
- *stat = r->stat;
- if (prev == NULL)
- plist = r->n; /* remove element from head of list */
- else
- prev->n = r->n;
- efree(r);
- return pid;
+ for (q = plist; q != NULL; q = q->n)
+ if (q->pid == ret) {
+ q->alive = false;
+ q->stat = *stat;
+ break;
+ }
+ }
+ *stat = r->stat;
+ if (prev == NULL)
+ plist = r->n; /* remove element from head of list */
+ else
+ prev->n = r->n;
+ efree(r);
+ return pid;
}
extern List *sgetapids() {
- List *r;
- Pid *p;
- for (r = NULL, p = plist; p != NULL; p = p->n) {
- List *q;
- if (!p->alive)
- continue;
- q = nnew(List);
- q->w = nprint("%d", p->pid);
- q->m = NULL;
- q->n = r;
- r = q;
- }
- return r;
+ List *r;
+ Pid *p;
+ for (r = NULL, p = plist; p != NULL; p = p->n) {
+ List *q;
+ if (!p->alive)
+ continue;
+ q = nnew(List);
+ q->w = nprint("%d", p->pid);
+ q->m = NULL;
+ q->n = r;
+ r = q;
+ }
+ return r;
}
extern void waitforall() {
- int stat;
+ int stat;
- while (plist != NULL) {
- pid_t pid = rc_wait4(plist->pid, &stat, false);
- if (pid > 0)
- setstatus(pid, stat);
- else {
- set(false);
- if (errno == EINTR)
- return;
- }
- sigchk();
- }
+ while (plist != NULL) {
+ pid_t pid = rc_wait4(plist->pid, &stat, false);
+ if (pid > 0)
+ setstatus(pid, stat);
+ else {
+ set(false);
+ if (errno == EINTR)
+ return;
+ }
+ sigchk();
+ }
}
/* walk the parse-tree. "obvious". */
extern bool walk(Node *n, bool parent) {
-top: sigchk();
- if (n == NULL) {
- if (!parent)
- exit(0);
- set(true);
- return true;
- }
- switch (n->type) {
- case nArgs: case nBackq: case nConcat: case nCount:
- case nFlat: case nLappend: case nRedir: case nVar:
- case nVarsub: case nWord:
- exec(glob(glom(n)), parent); /* simple command */
- break;
- case nBody:
- walk(n->u[0].p, true);
- WALK(n->u[1].p, parent);
- /* WALK doesn't fall through */
- case nNowait: {
- int pid;
- if ((pid = rc_fork()) == 0) {
+top: sigchk();
+ if (n == NULL) {
+ if (!parent)
+ exit(0);
+ set(true);
+ return true;
+ }
+ switch (n->type) {
+ case nArgs: case nBackq: case nConcat: case nCount:
+ case nFlat: case nLappend: case nRedir: case nVar:
+ case nVarsub: case nWord:
+ exec(glob(glom(n)), parent); /* simple command */
+ break;
+ case nBody:
+ walk(n->u[0].p, true);
+ WALK(n->u[1].p, parent);
+ /* WALK doesn't fall through */
+ case nNowait: {
+ int pid;
+ if ((pid = rc_fork()) == 0) {
#if defined(RC_JOB) && defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP)
- setsigdefaults(false);
- rc_signal(SIGTTOU, SIG_IGN); /* Berkeleyized version: put it in a new pgroup. */
- rc_signal(SIGTTIN, SIG_IGN);
- rc_signal(SIGTSTP, SIG_IGN);
- setpgid(0, getpid());
+ setsigdefaults(false);
+ rc_signal(SIGTTOU, SIG_IGN); /* Berkeleyized version: put it in a new pgroup. */
+ rc_signal(SIGTTIN, SIG_IGN);
+ rc_signal(SIGTSTP, SIG_IGN);
+ setpgid(0, getpid());
#else
- setsigdefaults(true); /* ignore SIGINT, SIGQUIT, SIGTERM */
+ setsigdefaults(true); /* ignore SIGINT, SIGQUIT, SIGTERM */
#endif
- mvfd(rc_open("/dev/null", rFrom), 0);
- walk(n->u[0].p, false);
- exit(getstatus());
- }
- if (interactive)
- fprint(2, "%d\n", pid);
- varassign("apid", word(nprint("%d", pid), NULL), false);
- redirq = NULL; /* kill pre-redir queue */
- break;
- }
- case nAndalso: {
- bool oldcond = cond;
- cond = true;
- if (walk(n->u[0].p, true)) {
- cond = oldcond;
- WALK(n->u[1].p, parent);
- } else
- cond = oldcond;
- break;
- }
- case nOrelse: {
- bool oldcond = cond;
- cond = true;
- if (!walk(n->u[0].p, true)) {
- cond = oldcond;
- WALK(n->u[1].p, parent);
- } else
- cond = oldcond;
- break;
- }
- case nBang:
- set(!walk(n->u[0].p, true));
- break;
- case nIf: {
- bool oldcond = cond;
- Node *true_cmd = n->u[1].p, *false_cmd = NULL;
- if (true_cmd != NULL && true_cmd->type == nElse) {
- false_cmd = true_cmd->u[1].p;
- true_cmd = true_cmd->u[0].p;
- }
- cond = true;
- if (!walk(n->u[0].p, true))
- true_cmd = false_cmd; /* run the else clause */
- cond = oldcond;
- WALK(true_cmd, parent);
- }
- case nWhile: {
- Jbwrap j;
- Edata jbreak;
- Estack e1, e2;
- bool testtrue, oldcond = cond;
- cond = true;
- if (!walk(n->u[0].p, true)) { /* prevent spurious breaks inside test */
- cond = oldcond;
- break;
- }
- if (sigsetjmp(j.j, 1))
- break;
- jbreak.jb = &j;
- except(eBreak, jbreak, &e1);
- do {
- Edata block;
- block.b = newblock();
- cond = oldcond;
- except(eArena, block, &e2);
- walk(n->u[1].p, true);
- testtrue = walk(n->u[0].p, true);
- unexcept(); /* eArena */
- cond = true;
- } while (testtrue);
- cond = oldcond;
- unexcept(); /* eBreak */
- break;
- }
- case nForin: {
- List *l, *var = glom(n->u[0].p);
- Jbwrap j;
- Estack e1, e2;
- Edata jbreak;
- if (sigsetjmp(j.j, 1))
- break;
- jbreak.jb = &j;
- except(eBreak, jbreak, &e1);
- for (l = listcpy(glob(glom(n->u[1].p)), nalloc); l != NULL; l = l->n) {
- Edata block;
- assign(var, word(l->w, NULL), false);
- block.b = newblock();
- except(eArena, block, &e2);
- walk(n->u[2].p, true);
- unexcept(); /* eArena */
- }
- unexcept(); /* eBreak */
- break;
- }
- case nSubshell:
- if (dofork(true)) {
- setsigdefaults(false);
- walk(n->u[0].p, false);
- rc_exit(getstatus());
- }
- break;
- case nAssign:
- if (n->u[0].p == NULL)
- rc_error("null variable name");
- assign(glom(n->u[0].p), glob(glom(n->u[1].p)), false);
- set(true);
- break;
- case nPipe:
- dopipe(n);
- break;
- case nNewfn: {
- List *l = glom(n->u[0].p);
- if (l == NULL)
- rc_error("null function name");
- while (l != NULL) {
- fnassign(l->w, n->u[1].p);
- l = l->n;
- }
- set(true);
- break;
- }
- case nRmfn: {
- List *l = glom(n->u[0].p);
- while (l != NULL) {
- fnrm(l->w);
- l = l->n;
- }
- set(true);
- break;
- }
- case nDup:
- redirq = NULL;
- break; /* Null command */
- case nMatch: {
- List *a = glob(glom(n->u[0].p)), *b = glom(n->u[1].p);
- set(lmatch(a, b));
- break;
- }
- case nSwitch: {
- List *v = glom(n->u[0].p);
- while (1) {
- do {
- n = n->u[1].p;
- if (n == NULL)
- return istrue();
- } while (n->u[0].p == NULL || n->u[0].p->type != nCase);
- if (lmatch(v, glom(n->u[0].p->u[0].p))) {
- for (n = n->u[1].p; n != NULL && (n->u[0].p == NULL || n->u[0].p->type != nCase); n = n->u[1].p)
- walk(n->u[0].p, true);
- break;
- }
- }
- break;
- }
- case nPre: {
- List *v;
- if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) {
- if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */
- break;
- setsigdefaults(false);
- qredir(n->u[0].p);
- if (!haspreredir(n->u[1].p))
- doredirs(); /* no more preredirs, empty queue */
- walk(n->u[1].p, false);
- rc_exit(getstatus());
- /* NOTREACHED */
- } else if (n->u[0].p->type == nAssign) {
- if (isallpre(n->u[1].p)) {
- walk(n->u[0].p, true);
- WALK(n->u[1].p, parent);
- } else {
- Estack e;
- Edata var;
- v = glom(n->u[0].p->u[0].p);
- assign(v, glob(glom(n->u[0].p->u[1].p)), true);
- var.name = v->w;
- except(eVarstack, var, &e);
- walk(n->u[1].p, parent);
- varrm(v->w, true);
- unexcept(); /* eVarstack */
- }
- } else
- panic("unexpected node in preredir section of walk");
- break;
- }
- case nBrace:
- if (n->u[1].p == NULL) {
- WALK(n->u[0].p, parent);
- } else if (dofork(parent)) {
- setsigdefaults(false);
- walk(n->u[1].p, true); /* Do redirections */
- redirq = NULL; /* Reset redirection queue */
- walk(n->u[0].p, false); /* Do commands */
- rc_exit(getstatus());
- /* NOTREACHED */
- }
- break;
- case nEpilog:
- qredir(n->u[0].p);
- if (n->u[1].p != NULL) {
- WALK(n->u[1].p, parent); /* Do more redirections. */
- } else {
- doredirs(); /* Okay, we hit the bottom. */
- }
- break;
- case nNmpipe:
- rc_error("named pipes cannot be executed as commands");
- /* NOTREACHED */
- default:
- panic("unknown node in walk");
- /* NOTREACHED */
- }
- return istrue();
+ mvfd(rc_open("/dev/null", rFrom), 0);
+ walk(n->u[0].p, false);
+ exit(getstatus());
+ }
+ if (interactive)
+ fprintf(stderr, "%d\n", pid);
+ varassign("apid", word(nprint("%d", pid), NULL), false);
+ redirq = NULL; /* kill pre-redir queue */
+ break;
+ }
+ case nAndalso: {
+ bool oldcond = cond;
+ cond = true;
+ if (walk(n->u[0].p, true)) {
+ cond = oldcond;
+ WALK(n->u[1].p, parent);
+ } else
+ cond = oldcond;
+ break;
+ }
+ case nOrelse: {
+ bool oldcond = cond;
+ cond = true;
+ if (!walk(n->u[0].p, true)) {
+ cond = oldcond;
+ WALK(n->u[1].p, parent);
+ } else
+ cond = oldcond;
+ break;
+ }
+ case nBang:
+ set(!walk(n->u[0].p, true));
+ break;
+ case nIf: {
+ bool oldcond = cond;
+ Node *true_cmd = n->u[1].p, *false_cmd = NULL;
+ if (true_cmd != NULL && true_cmd->type == nElse) {
+ false_cmd = true_cmd->u[1].p;
+ true_cmd = true_cmd->u[0].p;
+ }
+ cond = true;
+ if (!walk(n->u[0].p, true))
+ true_cmd = false_cmd; /* run the else clause */
+ cond = oldcond;
+ WALK(true_cmd, parent);
+ }
+ case nWhile: {
+ Jbwrap j;
+ Edata jbreak;
+ Estack e1, e2;
+ bool testtrue, oldcond = cond;
+ cond = true;
+ if (!walk(n->u[0].p, true)) { /* prevent spurious breaks inside test */
+ cond = oldcond;
+ break;
+ }
+ if (sigsetjmp(j.j, 1))
+ break;
+ jbreak.jb = &j;
+ except(eBreak, jbreak, &e1);
+ do {
+ Edata block;
+ block.b = newblock();
+ cond = oldcond;
+ except(eArena, block, &e2);
+ walk(n->u[1].p, true);
+ testtrue = walk(n->u[0].p, true);
+ unexcept(); /* eArena */
+ cond = true;
+ } while (testtrue);
+ cond = oldcond;
+ unexcept(); /* eBreak */
+ break;
+ }
+ case nForin: {
+ List *l, *var = glom(n->u[0].p);
+ Jbwrap j;
+ Estack e1, e2;
+ Edata jbreak;
+ if (sigsetjmp(j.j, 1))
+ break;
+ jbreak.jb = &j;
+ except(eBreak, jbreak, &e1);
+ for (l = listcpy(glob(glom(n->u[1].p)), nalloc); l != NULL; l = l->n) {
+ Edata block;
+ assign(var, word(l->w, NULL), false);
+ block.b = newblock();
+ except(eArena, block, &e2);
+ walk(n->u[2].p, true);
+ unexcept(); /* eArena */
+ }
+ unexcept(); /* eBreak */
+ break;
+ }
+ case nSubshell:
+ if (dofork(true)) {
+ setsigdefaults(false);
+ walk(n->u[0].p, false);
+ rc_exit(getstatus());
+ }
+ break;
+ case nAssign:
+ if (n->u[0].p == NULL)
+ rc_error("null variable name");
+ assign(glom(n->u[0].p), glob(glom(n->u[1].p)), false);
+ set(true);
+ break;
+ case nPipe:
+ dopipe(n);
+ break;
+ case nNewfn: {
+ List *l = glom(n->u[0].p);
+ if (l == NULL)
+ rc_error("null function name");
+ while (l != NULL) {
+ fnassign(l->w, n->u[1].p);
+ l = l->n;
+ }
+ set(true);
+ break;
+ }
+ case nRmfn: {
+ List *l = glom(n->u[0].p);
+ while (l != NULL) {
+ fnrm(l->w);
+ l = l->n;
+ }
+ set(true);
+ break;
+ }
+ case nDup:
+ redirq = NULL;
+ break; /* Null command */
+ case nMatch: {
+ List *a = glob(glom(n->u[0].p)), *b = glom(n->u[1].p);
+ set(lmatch(a, b));
+ break;
+ }
+ case nSwitch: {
+ List *v = glom(n->u[0].p);
+ while (1) {
+ do {
+ n = n->u[1].p;
+ if (n == NULL)
+ return istrue();
+ } while (n->u[0].p == NULL || n->u[0].p->type != nCase);
+ if (lmatch(v, glom(n->u[0].p->u[0].p))) {
+ for (n = n->u[1].p; n != NULL && (n->u[0].p == NULL || n->u[0].p->type != nCase); n = n->u[1].p)
+ walk(n->u[0].p, true);
+ break;
+ }
+ }
+ break;
+ }
+ case nPre: {
+ List *v;
+ if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) {
+ if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */
+ break;
+ setsigdefaults(false);
+ qredir(n->u[0].p);
+ if (!haspreredir(n->u[1].p))
+ doredirs(); /* no more preredirs, empty queue */
+ walk(n->u[1].p, false);
+ rc_exit(getstatus());
+ /* NOTREACHED */
+ } else if (n->u[0].p->type == nAssign) {
+ if (isallpre(n->u[1].p)) {
+ walk(n->u[0].p, true);
+ WALK(n->u[1].p, parent);
+ } else {
+ Estack e;
+ Edata var;
+ v = glom(n->u[0].p->u[0].p);
+ assign(v, glob(glom(n->u[0].p->u[1].p)), true);
+ var.name = v->w;
+ except(eVarstack, var, &e);
+ walk(n->u[1].p, parent);
+ varrm(v->w, true);
+ unexcept(); /* eVarstack */
+ }
+ } else
+ panic("unexpected node in preredir section of walk");
+ break;
+ }
+ case nBrace:
+ if (n->u[1].p == NULL) {
+ WALK(n->u[0].p, parent);
+ } else if (dofork(parent)) {
+ setsigdefaults(false);
+ walk(n->u[1].p, true); /* Do redirections */
+ redirq = NULL; /* Reset redirection queue */
+ walk(n->u[0].p, false); /* Do commands */
+ rc_exit(getstatus());
+ /* NOTREACHED */
+ }
+ break;
+ case nEpilog:
+ qredir(n->u[0].p);
+ if (n->u[1].p != NULL) {
+ WALK(n->u[1].p, parent); /* Do more redirections. */
+ } else {
+ doredirs(); /* Okay, we hit the bottom. */
+ }
+ break;
+ case nNmpipe:
+ rc_error("named pipes cannot be executed as commands");
+ /* NOTREACHED */
+ default:
+ panic("unknown node in walk");
+ /* NOTREACHED */
+ }
+ return istrue();
}
/* checks to see whether there are any pre-redirections left in the tree */
static bool haspreredir(Node *n) {
- while (n != NULL && n->type == nPre) {
- if (n->u[0].p->type == nDup || n->u[0].p->type == nRedir)
- return true;
- n = n->u[1].p;
- }
- return false;
+ while (n != NULL && n->type == nPre) {
+ if (n->u[0].p->type == nDup || n->u[0].p->type == nRedir)
+ return true;
+ n = n->u[1].p;
+ }
+ return false;
}
/* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
static bool isallpre(Node *n) {
- while (n != NULL && n->type == nPre)
- n = n->u[1].p;
- return n == NULL || n->type == nRedir || n->type == nAssign || n->type == nDup;
+ while (n != NULL && n->type == nPre)
+ n = n->u[1].p;
+ return n == NULL || n->type == nRedir || n->type == nAssign || n->type == nDup;
}
/*
*/
static bool dofork(bool parent) {
- int pid, sp;
+ int pid, sp;
- if (!parent || (pid = rc_fork()) == 0)
- return true;
- redirq = NULL; /* clear out the pre-redirection queue in the parent */
- rc_wait4(pid, &sp, true);
- setstatus(-1, sp);
- sigchk();
- return false;
+ if (!parent || (pid = rc_fork()) == 0)
+ return true;
+ redirq = NULL; /* clear out the pre-redirection queue in the parent */
+ rc_wait4(pid, &sp, true);
+ setstatus(-1, sp);
+ sigchk();
+ return false;
}
static void dopipe(Node *n) {
- int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2];
- bool intr;
- Node *r;
+ int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2];
+ bool intr;
+ Node *r;
- fd_prev = fd_out = 1;
- for (r = n, i = 0; r != NULL && r->type == nPipe; r = r->u[2].p, i++) {
- if (i > 500) /* the only hard-wired limit in rc? */
- rc_error("pipe too long");
- if (pipe(p) < 0) {
- uerror("pipe");
- rc_error(NULL);
- }
- if ((pid = rc_fork()) == 0) {
- setsigdefaults(false);
- redirq = NULL; /* clear preredir queue */
- mvfd(p[0], r->u[1].i);
- if (fd_prev != 1)
- mvfd(fd_prev, fd_out);
- close(p[1]);
- walk(r->u[3].p, false);
- exit(getstatus());
- }
- if (fd_prev != 1)
- close(fd_prev); /* parent must close all pipe fd's */
- pids[i] = pid;
- fd_prev = p[1];
- fd_out = r->u[0].i;
- close(p[0]);
- }
- if ((pid = rc_fork()) == 0) {
- setsigdefaults(false);
- mvfd(fd_prev, fd_out);
- walk(r, false);
- exit(getstatus());
- /* NOTREACHED */
- }
- redirq = NULL; /* clear preredir queue */
- close(fd_prev);
- pids[i++] = pid;
+ fd_prev = fd_out = 1;
+ for (r = n, i = 0; r != NULL && r->type == nPipe; r = r->u[2].p, i++) {
+ if (i > 500) /* the only hard-wired limit in rc? */
+ rc_error("pipe too long");
+ if (pipe(p) < 0) {
+ uerror("pipe");
+ rc_error(NULL);
+ }
+ if ((pid = rc_fork()) == 0) {
+ setsigdefaults(false);
+ redirq = NULL; /* clear preredir queue */
+ mvfd(p[0], r->u[1].i);
+ if (fd_prev != 1)
+ mvfd(fd_prev, fd_out);
+ close(p[1]);
+ walk(r->u[3].p, false);
+ exit(getstatus());
+ }
+ if (fd_prev != 1)
+ close(fd_prev); /* parent must close all pipe fd's */
+ pids[i] = pid;
+ fd_prev = p[1];
+ fd_out = r->u[0].i;
+ close(p[0]);
+ }
+ if ((pid = rc_fork()) == 0) {
+ setsigdefaults(false);
+ mvfd(fd_prev, fd_out);
+ walk(r, false);
+ exit(getstatus());
+ /* NOTREACHED */
+ }
+ redirq = NULL; /* clear preredir queue */
+ close(fd_prev);
+ pids[i++] = pid;
- /* collect statuses */
+ /* collect statuses */
- intr = false;
- for (j = 0; j < i; j++) {
- rc_wait4(pids[j], &sp, true);
- stats[j] = sp;
- intr |= (sp == SIGINT);
- }
- setpipestatus(stats, i);
- sigchk();
+ intr = false;
+ for (j = 0; j < i; j++) {
+ rc_wait4(pids[j], &sp, true);
+ stats[j] = sp;
+ intr |= (sp == SIGINT);
+ }
+ setpipestatus(stats, i);
+ sigchk();
}
/* determine whether gid lies in gidset */
static int ingidset(gid_t g) {
- int i;
- for (i = 0; i < ngroups; ++i)
- if (g == gidset[i])
- return 1;
- return 0;
+ int i;
+ for (i = 0; i < ngroups; ++i)
+ if (g == gidset[i])
+ return 1;
+ return 0;
}
/*
*/
static bool rc_access(char *path, bool verbose) {
- struct stat st;
- int mask;
- if (stat(path, &st) != 0) {
- if (verbose) /* verbose flag only set for absolute pathname */
- uerror(path);
- return false;
- }
- if (uid == 0)
- mask = X_ALL;
- else if (uid == st.st_uid)
- mask = X_USR;
- else if (gid == st.st_gid || ingidset(st.st_gid))
- mask = X_GRP;
- else
- mask = X_OTH;
- if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask))
- return true;
- errno = EACCES;
- if (verbose)
- uerror(path);
- return false;
+ struct stat st;
+ int mask;
+ if (stat(path, &st) != 0) {
+ if (verbose) /* verbose flag only set for absolute pathname */
+ uerror(path);
+ return false;
+ }
+ if (uid == 0)
+ mask = X_ALL;
+ else if (uid == st.st_uid)
+ mask = X_USR;
+ else if (gid == st.st_gid || ingidset(st.st_gid))
+ mask = X_GRP;
+ else
+ mask = X_OTH;
+ if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask))
+ return true;
+ errno = EACCES;
+ if (verbose)
+ uerror(path);
+ return false;
}
/* replace non-printing characters with question marks in a freshly
* allocated string */
static char *protect(char *in) {
- int l = strlen(in);
- char *out = ealloc(l + 1);
- int i;
+ int l = strlen(in);
+ char *out = ealloc(l + 1);
+ int i;
- for (i = 0; i < l; ++i)
- out[i] = isprint(in[i]) ? in[i] : '?';
- out[i] = '\0';
- return out;
+ for (i = 0; i < l; ++i)
+ out[i] = isprint(in[i]) ? in[i] : '?';
+ out[i] = '\0';
+ return out;
}
-
+
/* return a full pathname by searching $path, and by checking the status of the file */
extern char *which(char *name, bool verbose) {
- static char *test = NULL;
- static size_t testlen = 0;
- List *path;
- int len;
- if (name == NULL) /* no filename? can happen with "> foo" as a command */
- return NULL;
- if (!initialized) {
- initialized = true;
- uid = geteuid();
- gid = getegid();
- ngroups = getgroups(0, (gid_t *)0);
- if (ngroups < 0) {
- uerror("getgroups");
- rc_exit(1);
- }
- if (ngroups) {
- gidset = ealloc(ngroups * sizeof(gid_t));
- getgroups(ngroups, gidset);
- }
- }
- if (isabsolute(name)) /* absolute pathname? */
- return rc_access(name, verbose) ? name : NULL;
- len = strlen(name);
- for (path = varlookup("path"); path != NULL; path = path->n) {
- size_t need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
- if (testlen < need) {
- efree(test);
- test = ealloc(testlen = need);
- }
- if (*path->w == '\0') {
- strcpy(test, name);
- } else {
- strcpy(test, path->w);
- if (!streq(test, "/")) /* "//" is special to POSIX */
- strcat(test, "/");
- strcat(test, name);
- }
- if (rc_access(test, false))
- return test;
- }
- if (verbose) {
- char *n = protect(name);
- fprint(2, RC "cannot find `%s'\n", n);
- efree(n);
- }
- return NULL;
+ static char *test = NULL;
+ static size_t testlen = 0;
+ List *path;
+ int len;
+ if (name == NULL) /* no filename? can happen with "> foo" as a command */
+ return NULL;
+ if (!initialized) {
+ initialized = true;
+ uid = geteuid();
+ gid = getegid();
+ ngroups = getgroups(0, (gid_t *)0);
+ if (ngroups < 0) {
+ uerror("getgroups");
+ rc_exit(1);
+ }
+ if (ngroups) {
+ gidset = ealloc(ngroups * sizeof(gid_t));
+ getgroups(ngroups, gidset);
+ }
+ }
+ if (isabsolute(name)) /* absolute pathname? */
+ return rc_access(name, verbose) ? name : NULL;
+ len = strlen(name);
+ for (path = varlookup("path"); path != NULL; path = path->n) {
+ size_t need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
+ if (testlen < need) {
+ efree(test);
+ test = ealloc(testlen = need);
+ }
+ if (*path->w == '\0') {
+ strcpy(test, name);
+ } else {
+ strcpy(test, path->w);
+ if (!streq(test, "/")) /* "//" is special to POSIX */
+ strcat(test, "/");
+ strcat(test, name);
+ }
+ if (rc_access(test, false))
+ return test;
+ }
+ if (verbose) {
+ char *n = protect(name);
+ fprintf(stderr, RC "cannot find `%s'\n", n);
+ efree(n);
+ }
+ return NULL;
}