summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS20
-rw-r--r--ChangeLog8
-rw-r--r--acinclude.m436
-rw-r--r--builtins.c255
-rw-r--r--config.h-dist204
-rw-r--r--configure.ac2
-rw-r--r--fn.c11
-rw-r--r--glom.c2
-rw-r--r--main.c16
-rw-r--r--parse.y17
-rw-r--r--rc.130
-rw-r--r--rc.h6
-rw-r--r--signal.c10
-rw-r--r--status.c6
-rw-r--r--testcld.c19
-rw-r--r--trip.rc18
16 files changed, 264 insertions, 396 deletions
diff --git a/AUTHORS b/AUTHORS
index ee7c64f..3b425aa 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -28,13 +28,13 @@ FTP or HTTP directory as the shell). Please read this paper bearing in
mind that it describes a program that was written at AT&T and that the
version of rc presented here differs in some respects.
-Toby would like to thank these people for their contributions since he took
-over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg,
-Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, Casper Ti. Vector, Chris
-Siebenmann, Christian Neukirchen, Dale Scheetz, Dan Moniz, David Luyer,
-David Swasey, Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell,
-Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jakub Wilk, Jeremy
-Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond
-Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve
-Simon, Thomas Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang
-Zekoll.
+Toby would like to thank these people for their contributions since he
+took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt
+Kleberg, Bert Münnich, Brynjulv Hauksson, Byron Rakitzis, Callum Gibson,
+Casper Ti. Vector, Chris Siebenmann, Dale Scheetz, Dan Moniz, David
+Luyer, David Swasey, Decklin Foster, Donn Cave, Erik Quanstrom, Gary
+Carvell, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jakub Wilk,
+Jeremy Fitzhardinge, Leah Neukirchen, Marc Moorcroft, Mark H Wilkinson,
+Mark K Gardner, Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz,
+Stefan Dalibor, Steve Simon, Thomas Nordin, Tom Culliton, Tom Tromey,
+Vincent Broman, Wolfgang Zekoll.
diff --git a/ChangeLog b/ChangeLog
index 5ba1cf3..f759e29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -903,3 +903,11 @@ Changes since rc-1.5b2
2015-05-13
Release: rc-1.7.4.
+
+[... needs completing]
+
+2018-03-05
+
+ Bug: the grammar disallowed local assignments and redirections in the true
+ branch of `if` when there was an `else` clause (thanks Dražen Borković and
+ Bert Münnich; github #31).
diff --git a/acinclude.m4 b/acinclude.m4
index 3f9ec93..19d0d50 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -128,42 +128,6 @@ AC_DEFUN([RC_TYPE_SIG_ATOMIC_T], [
])
-dnl Do we have SysV SIGCLD semantics? In other words, if we set the
-dnl action for SIGCLD to SIG_IGN does wait() always say ECHILD? Linux,
-dnl of course, is bizarre here. It basically implements the SysV
-dnl semantics, but if the parent calls wait() before the child calls
-dnl exit(), wait() returns with the PID of the child as normal. (Real
-dnl SysV waits for all children to exit, then returns with ECHILD.)
-dnl Anyway, this is why the `sleep(1)' is there.
-AC_DEFUN([RC_SYS_V_SIGCLD], [
- AC_CACHE_CHECK(for SysV SIGCLD semantics, rc_cv_sysv_sigcld,
- AC_TRY_RUN([
-#include <errno.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-int main(void) {
- int i;
- signal(SIGCLD, SIG_IGN);
- switch (fork()) {
- case -1:
- return 1;
- case 0:
- return 0;
- default:
- sleep(1);
- if (wait(&i) == -1 && errno == ECHILD) return 0;
- else return 1;
- }
-}
- ], rc_cv_sysv_sigcld=yes, rc_cv_sysv_sigcld=no, rc_cv_sysv_sigcld=yes))
- case "$rc_cv_sysv_sigcld" in
- yes) AC_DEFINE(HAVE_SYSV_SIGCLD, 1, [Has SysV SIGCLD]) ;;
- esac
-])
-
-
dnl Do we have /dev/fd or /proc/self/fd?
AC_DEFUN([RC_SYS_DEV_FD], [
AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd,
diff --git a/builtins.c b/builtins.c
index 477ff71..ff153cf 100644
--- a/builtins.c
+++ b/builtins.c
@@ -46,27 +46,28 @@ static struct {
{ b_eval, "eval" },
{ b_exec, "exec" },
{ b_exit, "exit" },
+ { b_flag, "flag" },
#if HAVE_SETRLIMIT
- { b_limit, "limit" },
+ { b_limit, "limit" },
#endif
- { b_newpgrp, "newpgrp" },
- { b_return, "return" },
- { b_shift, "shift" },
- { b_umask, "umask" },
- { b_wait, "wait" },
- { b_whatis, "whatis" },
- { b_dot, "." },
+ { b_newpgrp, "newpgrp" },
+ { b_return, "return" },
+ { b_shift, "shift" },
+ { b_umask, "umask" },
+ { b_wait, "wait" },
+ { b_whatis, "whatis" },
+ { b_dot, "." },
#ifdef ADDONS
- ADDONS
+ ADDONS
#endif
};
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. */
@@ -89,13 +90,13 @@ extern void funcall(char **av) {
}
static void arg_count(char *name) {
- fprint(2, RC "too many arguments to %s\n", name);
- set(FALSE);
+ fprint(2, 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);
+ fprint(2, RC "`%s' is a bad number\n", num);
+ set(FALSE);
}
/* a dummy command. (exec() performs "exec" simply by not forking) */
@@ -107,90 +108,90 @@ extern void b_exec(char **ignore) {
/* 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++;
+ }
+ fprint(1, format, av);
+ set(TRUE);
}
#endif
/* 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, "."))
+ fprint(1, "%s\n", path);
+ return;
+ }
+ s = s->n;
+ } while (s != NULL);
+ fprint(2, "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);
+ 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;
+ }
}
static void b_exit(char **av) {
@@ -199,6 +200,74 @@ static void b_exit(char **av) {
rc_exit(getstatus());
}
+static void b_flag(char **av) {
+ bool *flagp = NULL;
+ char f;
+ int mode = 3; /* 0 = reset (-), 1 = set (+), 2 = test */
+ const char *usage = "usage: flag f [ + | - ]\n";
+
+ if (*++av == NULL) {
+ fprint(2, RC "not enough arguments to flag\n");
+ set(FALSE);
+ return;
+ }
+ f = av[0][0];
+ if (f == '\0' || av[0][1] != '\0') goto flag_usage;
+ if (*++av == NULL) {
+ mode = 2;
+ } else if (av[0][0] == '+' && av[0][1] == '\0') {
+ mode = 1;
+ } else if (av[0][0] == '-' && av[0][1] == '\0') {
+ mode = 0;
+ }
+ if (mode == 3) goto flag_usage;
+ switch (f) {
+ case 'c':
+ if (mode != 2) goto flag_immutable;
+ set(dashsee[0] != NULL);
+ return;
+ case 'd':
+ if (mode != 2) goto flag_immutable;
+ flagp = &dashdee; break;
+ case 'e': flagp = &dashee; break;
+ case 'i': flagp = &interactive; break;
+ case 'l':
+ if (mode != 2) goto flag_immutable;
+ flagp = &dashell; break;
+ case 'n': flagp = &dashen; break;
+ case 'o':
+ if (mode != 2) goto flag_immutable;
+ flagp = &dashoh; break;
+ case 'p':
+ if (mode != 2) goto flag_immutable;
+ flagp = &dashpee; break;
+ case 's':
+ if (mode != 2) goto flag_immutable;
+ flagp = &dashess; break;
+ case 'v': flagp = &dashvee; break;
+ case 'x': flagp = &dashex; break;
+ }
+ if (flagp != NULL) {
+ if (mode == 2)
+ set(*flagp);
+ else {
+ *flagp = mode;
+ set(TRUE);
+ }
+ } else {
+ fprint(2, RC "unknown flag");
+ set(FALSE);
+ }
+ return;
+flag_immutable:
+ fprint(2, RC "flag immutable\n");
+ set(FALSE);
+ return;
+flag_usage:
+ fprint(2, usage);
+ set(FALSE);
+}
+
/* 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) {
diff --git a/config.h-dist b/config.h-dist
deleted file mode 100644
index 5be81eb..0000000
--- a/config.h-dist
+++ /dev/null
@@ -1,204 +0,0 @@
-/* Copy config.h-dist to config.h and edit config.h, don't edit this file */
-
-/*
- * Configuration parameters for rc. Suggested defaults are at the bottom
- * of this file (you should probably look at those first to see if your
- * system matches one of them; you can search for the beginning of the
- * defaults section by looking for the string "#ifndef CUSTOM"). If you
- * want to override the suggested defaults, define the macro CUSTOM.
-#define CUSTOM
- */
-
-/*
- * (Note that certain default settings redefine this macro)
- * DEFAULTPATH the default search path that rc uses when it is started
- * without either a $PATH or $path environment variable. You must pick
- * something sensible for your system if you don't like the path shown
- * below.
- */
-#define DEFAULTPATH "/usr/ucb", "/usr/bin", "/bin", "."
-
-/*
- * Define the macro NODIRENT if your system has <sys/dir.h> but not
- * <dirent.h>. (e.g., NeXT-OS and RISCos)
-#define NODIRENT
- */
-
-/*
- * Define the macro SVSIGS if your system has System V signal semantics,
- * i.e., if "slow" system calls are interrupted rather than resumed
- * after returning from an interrupt handler. (If you are not sure what
- * this means, see the man page for signal(2). In any case, it is probably
- * safe to leave this macro undefined.)
-#define SVSIGS
- */
-
-/*
- * Define the macro NOCMDARG if you do not have /dev/fd or fifos on your
- * system. You may also want to define this if you have broken fifos.
-#define NOCMDARG
- */
-
-/*
- * Define TMPDIR if you need to have rc create its fifos in a directory
- * other than /tmp. For example, if you have a Sun with /tmp mounted
- * as a ramdisk (type "tmpfs") then you cannot use fifos in /tmp (sigh).
-#define TMPDIR "/var/tmp"
- */
-
-/*
- * Define the macro DEVFD if your system supports /dev/fd.
-#define DEVFD
- */
-
-/*
- * Define the macro NOLIMITS if your system does not support Berkeley
- * limits.
-#define NOLIMITS
- */
-
-/*
- * Define the macro NOSIGCLD if your system uses SIGCLD in the System
- * V way. (e.g., sgi's Irix)
-#define NOSIGCLD
- */
-
-/*
- * Define the macro READLINE if you want rc to call GNU readline
- * instead of read(2) on interactive shells.
-#define READLINE
- */
-
-/*
- * Define the macro NOEXECVE if your Unix does not interpret #! in the
- * kernel, and uncomment the EXECVE variable in the Makefile.
-#define NOEXECVE
- */
-
-/*
- * If you want rc to default to some interpreter for files which don't
- * have a legal #! on the first line, define the macro DEFAULTINTERP.
-#define DEFAULTINTERP "/bin/sh"
- */
-
-/*
- * If your /bin/sh (or another program you care about) rejects environment
- * variables with special characters in them (such as ':' or '-'), rc can
- * put out ugly variable names using [_0-9a-zA-Z] that encode the real name;
- * define PROTECT_ENV for this hack. (Known offenders: every sh I have tried;
- * SunOS (silently discards), NeXT (aborts with error), SGI (aborts with
- * error), Ultrix (sh seems to work, sh5 aborts with error))
-#define PROTECT_ENV
- */
-
-/*
- * Define the macro NOECHO if you wish to omit rc's echo builtin from the
- * compile.
-#define NOECHO
- */
-
-/*
- * Define the NOJOB if you do *not* wish rc to perform backgrounding
- * as if it were a job-control shell; that is, if you do *not* wish
- * it to put a command spawned in the background into a new process
- * group. Since most systems support job control and since there are
- * many broken programs that do not behave correctly when backgrounded
- * in a v7 non-job-control fashion, rc by default performs a job-
- * control-like backgrounding.
-#define NOJOB
- */
-
-/* Beginning of defaults section: */
-
-#ifndef CUSTOM
-
-/*
- * Suggested settings for Sun, NeXT and sgi (machines here at TAMU):
- */
-
-#ifdef NeXT /* Used on NextOS 2.1 */
-#define NODIRENT
-#define PROTECT_ENV
-#define NOCMDARG
-#endif
-
-#ifdef sgi /* Used on Irix 3.3.[12] */
-#define SVSIGS
-#define NOSIGCLD
-#define PROTECT_ENV
-#undef DEFAULTPATH
-#define DEFAULTPATH "/usr/bsd", "/usr/sbin", "/usr/bin", "/bin", "."
-#endif
-
-#ifdef sun /* Used on SunOS 4.1.1 */
-#define PROTECT_ENV
-#undef DEFAULTPATH
-#define DEFAULTPATH "/usr/ucb", "/usr/bin", "."
-#endif
-
-/*
- * Suggested settings for HP300 running 4.3BSD-utah (DWS):
- */
-
-#if defined(hp300) && !defined(hpux)
-#define NODIRENT
-#define NOCMDARG
-#define DEFAULTINTERP "/bin/sh"
-#define PROTECT_ENV
-#endif
-
-/*
- * Suggested settings for Ultrix
- */
-
-#ifdef ultrix
-#define PROTECT_ENV
-#define DEFAULTINTERP "/bin/sh" /* so /bin/true can work */
-#endif
-
-/*
- * Suggested settings for RISCos 4.52
- */
-
-/*
- This doesn't work without interfering with other MIPS-based
- systems' configuration. Please do it by hand.
-*/
-
-#if defined(host_mips) && defined(MIPSEB) && defined(SYSTYPE_BSD43)
-#define NODIRENT
-#define PROTECT_ENV
-#endif
-
-/*
- * Suggested settings for AIX
- */
-
-#ifdef _AIX
-#define PROTECT_ENV
-#endif
-
-/*
- * Suggested settings for OSF/1 1.0
- */
-
-#ifdef OSF1
-#define PROTECT_ENV
-#endif
-
-/*
- * Suggested settings for Unicos XXX
- */
-
-#ifdef cray
-#define PROTECT_ENV
-#define NOLIMITS
-#define word _word
-#define DEFAULTINTERP "/bin/sh"
-#endif
-
-#endif /* CUSTOM */
-
-#ifndef TMPDIR
-#define TMPDIR "/tmp"
-#endif
diff --git a/configure.ac b/configure.ac
index 23ebf8a..c9d1cb4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,8 +63,6 @@ RC_TYPE_RLIM_T
RC_TYPE_SIG_ATOMIC_T
-RC_SYS_V_SIGCLD
-
dnl Does the kernel handle `#! /interpreter'?
AC_SYS_INTERPRETER
case "$ac_cv_sys_interpreter" in
diff --git a/fn.c b/fn.c
index 7d9e4f7..01652b4 100644
--- a/fn.c
+++ b/fn.c
@@ -29,10 +29,7 @@ extern void inithandler() {
null.type = nBody;
null.u[0].p = null.u[1].p = NULL;
for (i = 1; i < NUMOFSIGNALS; i++)
-#if HAVE_SYSV_SIGCLD
- if (i != SIGCLD)
-#endif
- if (sighandlers[i] == SIG_IGN)
+ if (i != SIGCHLD && sighandlers[i] == SIG_IGN)
fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */
if (interactive || sighandlers[SIGINT] != SIG_IGN) {
def_sigint = sigint;
@@ -151,10 +148,8 @@ extern void fnassign(char *name, Node *def) {
new->def = newdef;
new->extdef = NULL;
if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */
-#if HAVE_SYSV_SIGCLD /* System V machines treat SIGCLD very specially */
- if (streq(name, "sigcld"))
- rc_error("can't trap SIGCLD");
-#endif
+ if (streq(name, "sigchld") || streq(name, "sigcld"))
+ rc_error("can't trap SIGCHLD");
if (streq(name, "sigexit"))
runexit = TRUE;
for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
diff --git a/glom.c b/glom.c
index c44f0d5..7f90d9d 100644
--- a/glom.c
+++ b/glom.c
@@ -266,7 +266,7 @@ static List *backq(Node *ifs, Node *n) {
bq = bqinput(glom(ifs), p[0]);
close(p[0]);
rc_wait4(pid, &sp, TRUE);
- statprint(-1, sp);
+ setstatus(-1, sp);
varassign("bqstatus", word(strstatus(sp), NULL), FALSE);
sigchk();
return bq;
diff --git a/main.c b/main.c
index 9743a2c..c5dc5d5 100644
--- a/main.c
+++ b/main.c
@@ -6,17 +6,19 @@
#include "input.h"
-bool dashdee, dashee, dashvee, dashex, dasheye,
- dashen, dashpee, interactive;
+bool dashdee, dashee, dasheye, dashell, dashen;
+bool dashpee, dashoh, dashess, dashvee, dashex;
+bool interactive;
+static bool dashEYE;
+char *dashsee[2];
pid_t rc_pid;
-static bool dashEYE, dashell, dashoh, dashess;
static void assigndefault(char *,...);
static void checkfd(int, enum redirtype);
extern int main(int argc, char *argv[], char *envp[]) {
- char *dashsee[2], *dollarzero, *null[1];
+ char *dollarzero, *null[1];
int c;
initprint();
dashsee[0] = dashsee[1] = NULL;
@@ -67,8 +69,10 @@ extern int main(int argc, char *argv[], char *envp[]) {
}
quitopts:
argv += rc_optind;
- /* 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 && (dashess || *argv == NULL))
+ /* 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 &&
+ (dashess || *argv == NULL))
interactive = isatty(0);
if (!dashoh) {
checkfd(0, rFrom);
diff --git a/parse.y b/parse.y
index 276961a..55f7e80 100644
--- a/parse.y
+++ b/parse.y
@@ -17,7 +17,8 @@ Node *parsetree; /* not using yylval because bison declares it as an auto */
%token OROR PIPE REDIR SREDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH
%left '^' '='
-%left WHILE ')' ELSE
+%right ELSE TWIDDLE
+%left WHILE ')'
%left ANDAND OROR '\n'
%left BANG SUBSHELL
%left PIPE
@@ -43,7 +44,7 @@ Node *parsetree; /* not using yylval because bison declares it as an auto */
%type <keyword> keyword
%type <node> assign body brace case cbody cmd cmdsa cmdsan comword epilog
first line nlwords paren redir sword simple iftail word words
- arg args
+ arg args else
%start rc
@@ -96,8 +97,10 @@ cbody : cmd { $$ = mk(nCbody, $1, NULL); }
| case cbody { $$ = mk(nCbody, $1, $2); }
| cmdsan cbody { $$ = mk(nCbody, $1, $2); }
-iftail : cmd %prec ELSE
- | brace ELSE optnl cmd { $$ = mk(nElse,$1,$4); }
+iftail : cmd else { $$ = $2 != NULL ? mk(nElse, $1, $2) : $1; }
+
+else : /* empty */ %prec ELSE { $$ = NULL; }
+ | ELSE optnl cmd { $$ = $3; }
cmd : /* empty */ %prec WHILE { $$ = NULL; }
| simple
@@ -116,13 +119,13 @@ cmd : /* empty */ %prec WHILE { $$ = NULL; }
| BANG optcaret cmd { $$ = mk(nBang,$3); }
| SUBSHELL optcaret cmd { $$ = mk(nSubshell,$3); }
| FN words brace { $$ = mk(nNewfn,$2,$3); }
- | FN words { $$ = mk(nRmfn,$2); }
+ | FN words %prec ELSE { $$ = mk(nRmfn,$2); }
optcaret : /* empty */ %prec '^'
| '^'
-simple : first
- | first args { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); }
+simple : first %prec ELSE
+ | first args %prec ELSE { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); }
args : arg
| args arg { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); }
diff --git a/rc.1 b/rc.1
index 79e39ed..f4fa9c1 100644
--- a/rc.1
+++ b/rc.1
@@ -1717,6 +1717,36 @@ If no argument is given, the current value of
.Cr $status
is used.
.TP
+\fBflag\fR \fIf\fR [ \fB+\fR | \fB\-\fR ]
+Test, set (\fB+\fR), or reset (\fB\-\fR) command-line flag
+.IR f .
+For example, a script that requires ``exit if command fails'' semantics can say
+.Ds
+.Cr "flag e +"
+.De
+.TP
+\&
+Some flags cannot be set or reset using
+.BR flag ,
+but they can still be tested. These are
+.BR c ,
+.BR d ,
+.BR l ,
+.BR o ,
+.BR p ,
+and
+.BR s .
+As a special case,
+.Cr "flag i"
+operates on
+.BR rc 's
+internal
+.IR interactive
+flag, which may have been set by
+.Cr -i
+on the command line, or if standard input was a terminal; there is no
+.Cr "flag I" .
+.TP
\fBlimit \fR[\fB\-h\fR] [\fIresource \fR[\fIvalue\fR]]
Similar to the
.IR csh (1)
diff --git a/rc.h b/rc.h
index 7324ed8..82e7d84 100644
--- a/rc.h
+++ b/rc.h
@@ -170,7 +170,10 @@ enum {
/* main.c */
extern Rq *redirq;
-extern bool dashdee, dashee, dashvee, dashex, dasheye, dashen, dashpee, interactive;
+extern bool dashdee, dashee, dasheye, dashell, dashen;
+extern bool dashpee, dashoh, dashess, dashvee, dashex;
+extern bool interactive;
+extern char *dashsee[];
extern pid_t rc_pid;
extern int lineno;
@@ -347,7 +350,6 @@ extern void set(bool);
extern void setstatus(pid_t, int);
extern List *sgetstatus(void);
extern void setpipestatus(int [], int);
-extern void statprint(pid_t, int);
extern void ssetstatus(char **);
extern char *strstatus(int s);
diff --git a/signal.c b/signal.c
index 68dcc27..aa74922 100644
--- a/signal.c
+++ b/signal.c
@@ -83,14 +83,12 @@ extern void initsignal() {
void (*h)(int);
int i;
-#if HAVE_SYSV_SIGCLD
- /* Ensure that SIGCLD is not SIG_IGN. Solaris's rshd does this. :-( */
- h = sys_signal(SIGCLD, SIG_IGN);
+ /* Ensure that SIGCHLD is not SIG_IGN. Solaris's rshd does this. :-( */
+ h = sys_signal(SIGCHLD, SIG_IGN);
if (h != SIG_IGN && h != SIG_ERR)
- sys_signal(SIGCLD, h);
+ sys_signal(SIGCHLD, h);
else
- sys_signal(SIGCLD, SIG_DFL);
-#endif
+ sys_signal(SIGCHLD, SIG_DFL);
for (i = 1; i < NUMOFSIGNALS; i++) {
#ifdef SIGKILL
diff --git a/status.c b/status.c
index 5b37aa5..b4e6a05 100644
--- a/status.c
+++ b/status.c
@@ -7,6 +7,8 @@
/* status == the wait() value of the last command in the pipeline, or the last command */
+static void statprint(pid_t, int);
+
static int statuses[512];
static int pipelength = 1;
@@ -49,8 +51,8 @@ extern void set(bool code) {
extern void setpipestatus(int stats[], int num) {
int i;
for (i = 0; i < (pipelength = num); i++) {
- statprint(-1, stats[i]);
statuses[i] = stats[i];
+ statprint(-1, stats[i]);
}
}
@@ -64,7 +66,7 @@ extern void setstatus(pid_t pid, int 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) {
+static void statprint(pid_t pid, int i) {
if (WIFSIGNALED(i)) {
int t = WTERMSIG(i);
char *msg = ((t > 0) && (t < NUMOFSIGNALS) ? signals[WTERMSIG(i)].msg : "");
diff --git a/testcld.c b/testcld.c
deleted file mode 100644
index 83212e9..0000000
--- a/testcld.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <errno.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-int main(void) {
- int i;
- sigset(SIGCLD, SIG_IGN);
- switch (fork()) {
- case -1:
- return 1;
- case 0:
- return 0;
- default:
- sleep(1);
- if (wait(&i) == -1 && errno == ECHILD) return 0;
- else return 1;
- }
-}
diff --git a/trip.rc b/trip.rc
index 6a42350..bb5643f 100644
--- a/trip.rc
+++ b/trip.rc
@@ -690,3 +690,21 @@ if (! ~ $X YYY) {
A=``($nl){ $rc -c 'mkdir / >[2=1] | tr a-z A-Z' }
B=``($nl){ $rc -c '>[2=1] mkdir / | tr a-z A-Z' }
~ $A $B || fail counter intuitive redirection bug, $A '!=' $B
+
+# test for github issue #40
+$rc -ec 'false | false'
+if (~ $status 0) {
+ fail '"rc -e" exits with zero status when command in pipeline returns non-zero'
+}
+$rc -ec 'X=`{false}'
+if (~ $status 0) {
+ fail '"rc -e" exits with zero status when backquote command returns non-zero'
+}
+
+# exercise flag builtin
+submatch 'flag' 'rc: not enough arguments to flag' 'flag no args'
+submatch 'flag a b c' 'usage: flag f [ + | - ]' 'flag 3 args'
+submatch 'flag xx' 'usage: flag f [ + | - ]' 'flag wrong first arg'
+submatch 'flag x x' 'usage: flag f [ + | - ]' 'flag wrong second arg'
+submatch 'flag c && echo yes' yes 'flag c'
+submatch 'flag x +; flag x -' 'flag x -' 'setting x flag'