summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2005-05-24 09:14:46 +0000
committerharti <harti@FreeBSD.org>2005-05-24 09:14:46 +0000
commit37b9e8f42f9e0fc810925827e20ad144c7b88871 (patch)
treeb703a63fab4a1142e2d14e45259737c6236b2bd7 /usr.bin
parenta2e5c5c0f415c2965a0e3e4cde46953caf61319e (diff)
downloadFreeBSD-src-37b9e8f42f9e0fc810925827e20ad144c7b88871.zip
FreeBSD-src-37b9e8f42f9e0fc810925827e20ad144c7b88871.tar.gz
Before doing any parsing parse the builtin shell specifications and
set the current shell to DEFSHELL. Put all these specifications into a list. Add user specified new shells to this list. If the user just selects one of the already know shells just pick the right one off the list. This let's one do something like: # Full specification of the user's shell. This also selects the shell. .SHELL: name=myshell path=/somewhere/foo echo=loud ... FOO != bar # use myshell here .SHELL: name=sh BAR != baz # use /bin/sh here .SHELL: name=myshell # no need for full spec here. # continue to use the user's special shell.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/make/job.c373
-rw-r--r--usr.bin/make/job.h2
-rw-r--r--usr.bin/make/main.c7
3 files changed, 204 insertions, 178 deletions
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c
index f0de17e..49497b3 100644
--- a/usr.bin/make/job.c
+++ b/usr.bin/make/job.c
@@ -278,6 +278,8 @@ TAILQ_HEAD(JobList, Job);
* anyway as is and if it causes an error, so be it.
*/
struct Shell {
+ TAILQ_ENTRY(Shell) link; /* link all shell descriptions */
+
/*
* the name of the shell. For Bourne and C shells, this is used
* only to find the shell description when used as the single
@@ -315,6 +317,7 @@ struct Shell {
ArgArray builtins;
char *meta;
};
+TAILQ_HEAD(Shells, Shell);
/*
* error handling variables
@@ -375,45 +378,40 @@ static int numCommands;
#define CSH_META "#=|^(){};&<>*?[]:$`\\@\n"
#define SH_META "#=|^(){};&<>*?[]:$`\\\n"
-static const char *const shells[][2] = {
+static const char *const shells_init[] = {
/*
* CSH description. The csh can do echo control by playing
* with the setting of the 'echo' shell variable. Sadly,
* however, it is unable to do error control nicely.
*/
- { "csh",
- "name=csh path='" PATH_DEFSHELLDIR "/csh' "
- "quiet='unset verbose' echo='set verbose' filter='unset verbose' "
- "hasErrCtl=N check='echo \"%s\"\n' ignore='csh -c \"%s || exit 0\"' "
- "echoFlag=v errFlag=e "
- "meta='" CSH_META "' builtins='" CSH_BUILTINS "'"
- },
+ "name=csh path='" PATH_DEFSHELLDIR "/csh' "
+ "quiet='unset verbose' echo='set verbose' filter='unset verbose' "
+ "hasErrCtl=N check='echo \"%s\"\n' ignore='csh -c \"%s || exit 0\"' "
+ "echoFlag=v errFlag=e "
+ "meta='" CSH_META "' builtins='" CSH_BUILTINS "'",
+
/*
* SH description. Echo control is also possible and, under
* sun UNIX anyway, one can even control error checking.
*/
- {
- "sh",
- "name=sh path='" PATH_DEFSHELLDIR "/sh' "
- "quiet='set -' echo='set -v' filter='set -' "
- "hasErrCtl=Y check='set -e' ignore='set +e' "
- "echoFlag=v errFlag=e "
- "meta='" SH_META "' builtins='" SH_BUILTINS "'"
- },
+ "name=sh path='" PATH_DEFSHELLDIR "/sh' "
+ "quiet='set -' echo='set -v' filter='set -' "
+ "hasErrCtl=Y check='set -e' ignore='set +e' "
+ "echoFlag=v errFlag=e "
+ "meta='" SH_META "' builtins='" SH_BUILTINS "'",
+
/*
* KSH description. The Korn shell has a superset of
* the Bourne shell's functionality. There are probably builtins
* missing here.
*/
- {
- "ksh",
- "name=ksh path='" PATH_DEFSHELLDIR "/ksh' "
- "quiet='set -' echo='set -v' filter='set -' "
- "hasErrCtl=Y check='set -e' ignore='set +e' "
- "echoFlag=v errFlag=e "
- "meta='" SH_META "' builtins='" SH_BUILTINS "'"
- },
- { NULL, NULL }
+ "name=ksh path='" PATH_DEFSHELLDIR "/ksh' "
+ "quiet='set -' echo='set -v' filter='set -' "
+ "hasErrCtl=Y check='set -e' ignore='set +e' "
+ "echoFlag=v errFlag=e "
+ "meta='" SH_META "' builtins='" SH_BUILTINS "'",
+
+ NULL
};
/*
@@ -423,6 +421,11 @@ static const char *const shells[][2] = {
static struct Shell *commandShell = NULL;
/*
+ * This is the list of all known shells.
+ */
+static struct Shells shells = TAILQ_HEAD_INITIALIZER(shells);
+
+/*
* The maximum number of jobs that may run. This is initialize from the
* -j argument for the leading make and from the FIFO for sub-makes.
*/
@@ -2581,12 +2584,138 @@ JobShellDump(const struct Shell *sh)
fprintf(stderr, "\n meta='%s'\n", sh->meta);
}
-static void
+/**
+ * Parse a shell specification line and return the new Shell structure.
+ * In case of an error a message is printed and NULL is returned.
+ */
+static struct Shell *
+JobParseShellSpec(const char *spec, Boolean *fullSpec)
+{
+ ArgArray aa;
+ struct Shell *sh;
+ char *eq;
+ char *keyw;
+ int arg;
+
+ *fullSpec = FALSE;
+
+ sh = emalloc(sizeof(*sh));
+ memset(sh, 0, sizeof(*sh));
+ ArgArray_Init(&sh->builtins);
+
+ /*
+ * Parse the specification by keyword but skip the first word
+ */
+ brk_string(&aa, spec, TRUE);
+
+ for (arg = 1; arg < aa.argc; arg++) {
+ /*
+ * Split keyword and value
+ */
+ keyw = aa.argv[arg];
+ if ((eq = strchr(keyw, '=')) == NULL) {
+ Parse_Error(PARSE_FATAL, "missing '=' in shell "
+ "specification keyword '%s'", keyw);
+ ArgArray_Done(&aa);
+ JobFreeShell(sh);
+ return (NULL);
+ }
+ *eq++ = '\0';
+
+ if (strcmp(keyw, "path") == 0) {
+ free(sh->path);
+ sh->path = estrdup(eq);
+ } else if (strcmp(keyw, "name") == 0) {
+ free(sh->name);
+ sh->name = estrdup(eq);
+ } else if (strcmp(keyw, "quiet") == 0) {
+ free(sh->echoOff);
+ sh->echoOff = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "echo") == 0) {
+ free(sh->echoOn);
+ sh->echoOn = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "filter") == 0) {
+ free(sh->noPrint);
+ sh->noPrint = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "echoFlag") == 0) {
+ free(sh->echo);
+ sh->echo = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "errFlag") == 0) {
+ free(sh->exit);
+ sh->exit = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "hasErrCtl") == 0) {
+ sh->hasErrCtl = (*eq == 'Y' || *eq == 'y' ||
+ *eq == 'T' || *eq == 't');
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "check") == 0) {
+ free(sh->errCheck);
+ sh->errCheck = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "ignore") == 0) {
+ free(sh->ignErr);
+ sh->ignErr = estrdup(eq);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "builtins") == 0) {
+ ArgArray_Done(&sh->builtins);
+ brk_string(&sh->builtins, eq, TRUE);
+ qsort(sh->builtins.argv + 1, sh->builtins.argc - 1,
+ sizeof(char *), sort_builtins);
+ *fullSpec = TRUE;
+ } else if (strcmp(keyw, "meta") == 0) {
+ free(sh->meta);
+ sh->meta = estrdup(eq);
+ *fullSpec = TRUE;
+ } else {
+ Parse_Error(PARSE_FATAL, "unknown keyword in shell "
+ "specification '%s'", keyw);
+ ArgArray_Done(&aa);
+ JobFreeShell(sh);
+ return (NULL);
+ }
+ }
+ ArgArray_Done(&aa);
+
+ /*
+ * Some checks (could be more)
+ */
+ if (*fullSpec) {
+ if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) {
+ Parse_Error(PARSE_FATAL, "Shell must have either both "
+ "echoOff and echoOn or none of them");
+ JobFreeShell(sh);
+ return (NULL);
+ }
+
+ if (sh->echoOn != NULL && sh->echoOff != NULL)
+ sh->hasEchoCtl = TRUE;
+ }
+
+ return (sh);
+}
+
+/**
+ * Parse the builtin shell specifications and put them into the shell
+ * list. Then select the default shell to be the current shell. This
+ * is called from main() before any parsing (including MAKEFLAGS and
+ * command line) is done.
+ */
+void
Shell_Init(void)
{
+ int i;
+ struct Shell *sh;
+ Boolean fullSpec;
- if (commandShell == NULL) {
- commandShell = JobMatchShell(shells[DEFSHELL][0]);
+ for (i = 0; shells_init[i] != NULL; i++) {
+ sh = JobParseShellSpec(shells_init[i], &fullSpec);
+ TAILQ_INSERT_TAIL(&shells, sh, link);
+ if (i == DEFSHELL)
+ commandShell = sh;
}
}
@@ -2667,8 +2796,6 @@ Job_Init(int maxproc)
targFmt = TARG_FMT;
}
- Shell_Init();
-
/*
* Catch the four signals that POSIX specifies if they aren't ignored.
* JobCatchSignal will just set global variables and hope someone
@@ -2787,116 +2914,6 @@ Job_Empty(void)
}
}
-static struct Shell *
-JobParseShellSpec(const char *spec, Boolean *fullSpec)
-{
- ArgArray aa;
- struct Shell *sh;
- char *eq;
- char *keyw;
- int arg;
-
- *fullSpec = FALSE;
-
- sh = emalloc(sizeof(*sh));
- memset(sh, 0, sizeof(*sh));
- ArgArray_Init(&sh->builtins);
-
- /*
- * Parse the specification by keyword but skip the first word
- */
- brk_string(&aa, spec, TRUE);
-
- for (arg = 1; arg < aa.argc; arg++) {
- /*
- * Split keyword and value
- */
- keyw = aa.argv[arg];
- if ((eq = strchr(keyw, '=')) == NULL) {
- Parse_Error(PARSE_FATAL, "missing '=' in shell "
- "specification keyword '%s'", keyw);
- ArgArray_Done(&aa);
- JobFreeShell(sh);
- return (NULL);
- }
- *eq++ = '\0';
-
- if (strcmp(keyw, "path") == 0) {
- free(sh->path);
- sh->path = estrdup(eq);
- } else if (strcmp(keyw, "name") == 0) {
- free(sh->name);
- sh->name = estrdup(eq);
- } else if (strcmp(keyw, "quiet") == 0) {
- free(sh->echoOff);
- sh->echoOff = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "echo") == 0) {
- free(sh->echoOn);
- sh->echoOn = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "filter") == 0) {
- free(sh->noPrint);
- sh->noPrint = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "echoFlag") == 0) {
- free(sh->echo);
- sh->echo = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "errFlag") == 0) {
- free(sh->exit);
- sh->exit = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "hasErrCtl") == 0) {
- sh->hasErrCtl = (*eq == 'Y' || *eq == 'y' ||
- *eq == 'T' || *eq == 't');
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "check") == 0) {
- free(sh->errCheck);
- sh->errCheck = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "ignore") == 0) {
- free(sh->ignErr);
- sh->ignErr = estrdup(eq);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "builtins") == 0) {
- ArgArray_Done(&sh->builtins);
- brk_string(&sh->builtins, eq, TRUE);
- qsort(sh->builtins.argv + 1, sh->builtins.argc - 1,
- sizeof(char *), sort_builtins);
- *fullSpec = TRUE;
- } else if (strcmp(keyw, "meta") == 0) {
- free(sh->meta);
- sh->meta = estrdup(eq);
- *fullSpec = TRUE;
- } else {
- Parse_Error(PARSE_FATAL, "unknown keyword in shell "
- "specification '%s'", keyw);
- ArgArray_Done(&aa);
- JobFreeShell(sh);
- return (NULL);
- }
- }
- ArgArray_Done(&aa);
-
- /*
- * Some checks (could be more)
- */
- if (*fullSpec) {
- if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) {
- Parse_Error(PARSE_FATAL, "Shell must have either both "
- "echoOff and echoOn or none of them");
- JobFreeShell(sh);
- return (NULL);
- }
-
- if (sh->echoOn != NULL && sh->echoOff != NULL)
- sh->hasEchoCtl = TRUE;
- }
-
- return (sh);
-}
-
/**
* Find a matching shell in 'shells' given its final component.
*
@@ -2908,12 +2925,11 @@ JobParseShellSpec(const char *spec, Boolean *fullSpec)
static struct Shell *
JobMatchShell(const char *name)
{
- u_int sh;
- Boolean fullSpec;
+ struct Shell *sh;
- for (sh = 0; shells[sh][0] != NULL; sh++)
- if (strcmp(shells[sh][0], name) == 0)
- return (JobParseShellSpec(shells[sh][1], &fullSpec));
+ TAILQ_FOREACH(sh, &shells, link)
+ if (strcmp(sh->name, name) == 0)
+ return (sh);
return (NULL);
}
@@ -3001,44 +3017,49 @@ Job_ParseShell(const char line[])
return (FALSE);
}
JobFreeShell(sh);
- sh = match;
+ commandShell = match;
- } else {
- /*
- * The user provided a path. If s/he gave nothing else
- * (fullSpec is FALSE), try and find a matching shell in the
- * ones we know of. Else we just take the specification at its
- * word and copy it to a new location. In either case, we need
- * to record the path the user gave for the shell.
- */
- if (sh->name == NULL) {
- /* get the base name as the name */
- if ((sh->name = strrchr(sh->path, '/')) == NULL) {
- sh->name = estrdup(sh->path);
- } else {
- sh->name = estrdup(sh->name + 1);
- }
+ return (TRUE);
+ }
+
+ /*
+ * The user provided a path. If s/he gave nothing else
+ * (fullSpec is FALSE), try and find a matching shell in the
+ * ones we know of. Else we just take the specification at its
+ * word and copy it to a new location. In either case, we need
+ * to record the path the user gave for the shell.
+ */
+ if (sh->name == NULL) {
+ /* get the base name as the name */
+ if ((sh->name = strrchr(sh->path, '/')) == NULL) {
+ sh->name = estrdup(sh->path);
+ } else {
+ sh->name = estrdup(sh->name + 1);
}
+ }
- if (!fullSpec) {
- if ((match = JobMatchShell(sh->name)) == NULL) {
- Parse_Error(PARSE_FATAL,
- "%s: no matching shell", sh->name);
- JobFreeShell(sh);
- return (FALSE);
- }
- free(match->path);
- match->path = sh->path;
- sh->path = NULL;
+ if (!fullSpec) {
+ if ((match = JobMatchShell(sh->name)) == NULL) {
+ Parse_Error(PARSE_FATAL,
+ "%s: no matching shell", sh->name);
JobFreeShell(sh);
- sh = match;
+ return (FALSE);
}
+
+ /* set the patch on the matching shell */
+ free(match->path);
+ match->path = sh->path;
+ sh->path = NULL;
+
+ JobFreeShell(sh);
+ commandShell = match;
+ return (TRUE);
}
+ TAILQ_INSERT_HEAD(&shells, sh, link);
+
/* set the new shell */
- JobFreeShell(commandShell);
commandShell = sh;
-
return (TRUE);
}
@@ -3230,8 +3251,6 @@ Cmd_Exec(const char *cmd, const char **error)
*error = NULL;
buf = Buf_Init(0);
- if (commandShell == NULL)
- Shell_Init();
/*
* Open a pipe for fetching its output
*/
@@ -3882,8 +3901,6 @@ Compat_Run(Lst *targs)
int error_cnt; /* Number of targets not remade due to errors */
LstNode *ln;
- Shell_Init(); /* Set up shell. */
-
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
signal(SIGINT, CompatCatchSig);
}
diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h
index 45518de..d479211 100644
--- a/usr.bin/make/job.h
+++ b/usr.bin/make/job.h
@@ -71,6 +71,8 @@ void Job_AbortAll(void);
void Proc_Init(void);
+void Shell_Init(void);
+
struct Buffer *Cmd_Exec(const char *, const char **);
void Compat_Run(struct Lst *);
diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c
index 1d65ffb..cbc2a30 100644
--- a/usr.bin/make/main.c
+++ b/usr.bin/make/main.c
@@ -785,6 +785,13 @@ main(int argc, char **argv)
* can be processed correctly */
Var_Init(environ); /* As well as the lists of variables for
* parsing arguments */
+
+ /*
+ * Initialize the Shell so that we have a shell for != assignments
+ * on the command line.
+ */
+ Shell_Init();
+
/*
* Initialize various variables.
* MAKE also gets this name, for compatibility
OpenPOWER on IntegriCloud