commit 2dd0aa249c9bac4e5c616d1f386dc4271fdbab46
parent 1128baa58acaff32e4538d5878b916fba091c574
Author: Toby Goodwin <toby@paccrat.org>
Date: Sat, 17 Mar 2018 18:36:15 +0000
Merge branch 'master' into ifnot
Diffstat:
M | builtins.c | | | 259 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
M | main.c | | | 16 | ++++++++++------ |
M | rc.1 | | | 30 | ++++++++++++++++++++++++++++++ |
M | rc.h | | | 5 | ++++- |
M | trip.rc | | | 8 | ++++++++ |
5 files changed, 216 insertions(+), 102 deletions(-)
diff --git a/builtins.c b/builtins.c
@@ -20,8 +20,8 @@
#include "rlimit.h"
#include "sigmsgs.h"
-static void b_break(char **), b_cd(char **), b_continue(char **), b_eval(char **), b_exit(char **),
- b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **),
+static void b_break(char **), b_cd(char **), b_continue(char **), b_eval(char **), b_flag(char **),
+ b_exit(char **), b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **),
b_wait(char **), b_whatis(char **);
#if HAVE_SETRLIMIT
@@ -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/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/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
@@ -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;
diff --git a/trip.rc b/trip.rc
@@ -707,3 +707,11 @@ if (~ $status 0) {
# exercise "if not"
submatch 'if (false) echo foo; if not echo bar' 'bar' 'if not 1'
submatch 'if (false) echo foo; echo qux; if not echo bar' 'rc: `if not'' must follow `if''' 'if not 2'
+
+# 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'