Fix quoting of the MAKEFLAGS environment variable by only quoting spaces

and tabs. This is still not correct for command line variable values
ending in a backslash because this would require a larger effort.
Document this limitation in the BUGS section of the man page. The
quoting is mostly compatible with that of gmake and smake.

Tested by:	Max Okumoto and Joerg Sonnenberger from DragonFly BSD
Reviewed by:	ru (man page, partly)
This commit is contained in:
Hartmut Brandt 2005-01-26 18:19:39 +00:00
parent fb3be370b0
commit b071ad2dca
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=140870
5 changed files with 146 additions and 11 deletions

View File

@ -144,14 +144,21 @@ static char *objdir; /* where we chdir'ed to */
static void
MFLAGS_append(char *flag, char *arg)
{
char *str;
Var_Append(MAKEFLAGS, flag, VAR_GLOBAL);
if (arg != NULL)
Var_Append(MAKEFLAGS, arg, VAR_GLOBAL);
if (arg != NULL) {
str = MAKEFLAGS_quote(arg);
Var_Append(MAKEFLAGS, str, VAR_GLOBAL);
free(str);
}
Var_Append("MFLAGS", flag, VAR_GLOBAL);
if (arg != NULL)
Var_Append("MFLAGS", arg, VAR_GLOBAL);
if (arg != NULL) {
str = MAKEFLAGS_quote(arg);
Var_Append("MFLAGS", str, VAR_GLOBAL);
free(str);
}
}
/*-
@ -340,7 +347,7 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) {
*/
for (argv += optind, argc -= optind; *argv; ++argv, --argc)
if (Parse_IsVar(*argv)) {
char *ptr = Var_Quote(*argv);
char *ptr = MAKEFLAGS_quote(*argv);
Var_Append(MAKEFLAGS, ptr, VAR_GLOBAL);
free(ptr);
@ -376,7 +383,7 @@ rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) {
* Only those that come from the various arguments.
*/
void
Main_ParseArgLine(char *line)
Main_ParseArgLine(char *line, int mflags)
{
char **argv; /* Manufactured argument vector */
int argc; /* Number of arguments in argv */
@ -388,7 +395,11 @@ Main_ParseArgLine(char *line)
if (!*line)
return;
argv = brk_string(line, &argc, TRUE);
if (mflags)
argv = MAKEFLAGS_break(line, &argc);
else
argv = brk_string(line, &argc, TRUE);
MainParseArgs(argc, argv);
}
@ -622,7 +633,7 @@ main(int argc, char **argv)
* (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
* in a different format).
*/
Main_ParseArgLine(getenv("MAKEFLAGS"));
Main_ParseArgLine(getenv("MAKEFLAGS"), 1);
MainParseArgs(argc, argv);

View File

@ -32,7 +32,7 @@
.\" @(#)make.1 8.8 (Berkeley) 6/13/95
.\" $FreeBSD$
.\"
.Dd December 2, 2004
.Dd January 26, 2005
.Dt MAKE 1
.Os
.Sh NAME
@ -590,6 +590,20 @@ environment variable made available for all programs which
executes; compare with the
.Ic .MAKEFLAGS
special target below.
.Pp
When passing macro definitions and flag arguments in the
.Ev MAKEFLAGS
environment variable,
space and tab characters are quoted by preceding them with a backslash.
When reading the
.Ev MAKEFLAGS
variable from the environment,
all sequences of a backslash and one of space or tab
are replaced just with their second character
without causing a word break.
Any other occurences of a backslash are retained.
Groups of unquoted space, tab and newline characters cause word
breaking.
.It Va MFLAGS
This variable is provided for backward compatibility and
contains all the options from the
@ -1467,3 +1481,12 @@ all:
...
\&.endfor
.Ed
.Pp
A trailing backslash in a variable value defined on the command line causes
the delimiting space in the
.Ev MAKEFLAGS
environment variable to be preceeded by that backslash.
That causes a submake to not treat that space as a word delimiter.
Fixing this requires a larger rewrite of the code handling command line
macros and assignments to
.Va .MAKEFLAGS .

View File

@ -62,7 +62,7 @@ int For_Eval(char *);
void For_Run(int);
/* main.c */
void Main_ParseArgLine(char *);
void Main_ParseArgLine(char *, int);
char *Cmd_Exec(char *, char **);
void Debug(const char *, ...);
void Error(const char *, ...);
@ -92,6 +92,8 @@ void Parse_MainName(Lst *);
void str_init(void);
char *str_concat(const char *, const char *, int);
char **brk_string(char *, int *, Boolean);
char *MAKEFLAGS_quote(const char *);
char **MAKEFLAGS_break(const char *, int *);
int Str_Match(const char *, const char *);
const char *Str_SYSVMatch(const char *, const char *, int *);
void Str_SYSVSubst(Buffer, const char *, const char *, int);

View File

@ -1033,7 +1033,7 @@ ParseDoDependency (char *line)
* set the initial character to a null-character so the loop to
* get sources won't get anything
*/
Main_ParseArgLine(line);
Main_ParseArgLine(line, 0);
*line = '\0';
} else if (specType == ExShell) {
if (Job_ParseShell(line) != SUCCESS) {

View File

@ -222,6 +222,105 @@ done: argv[argc] = NULL;
return (argv);
}
/*
* Quote a string for appending it to MAKEFLAGS. According to Posix the
* kind of quoting here is implementation-defined. This quoting must ensure
* that the parsing of MAKEFLAGS's contents in a sub-shell yields the same
* options, option arguments and macro definitions as in the calling make.
* We simply quote all blanks, which according to Posix are space and tab
* in the POSIX locale. Don't use isblank because in that case makes with
* different locale settings could not communicate. We must also quote
* backslashes obviously.
*/
char *
MAKEFLAGS_quote(const char *str)
{
char *ret, *q;
const char *p;
/* assume worst case - everything has to be quoted */
ret = emalloc(strlen(str) * 2 + 1);
p = str;
q = ret;
while (*p != '\0') {
switch (*p) {
case ' ':
case '\t':
*q++ = '\\';
break;
default:
break;
}
*q++ = *p++;
}
*q++ = '\0';
return (ret);
}
char **
MAKEFLAGS_break(const char *str, int *pargc)
{
char *q, *start;
int len;
/* allocate room for a copy of the string */
if ((len = strlen(str) + 1) > curlen)
buffer = erealloc(buffer, curlen = len);
start = NULL;
*pargc = 1;
for (q = buffer;;) {
switch (*str) {
case ' ':
case '\t':
/* word separator */
if (start == NULL) {
/* not in a word */
str++;
continue;
}
/* FALLTHRU */
case '\0':
if (start == NULL)
goto done;
/* finish word */
*q++ = '\0';
if (argmax == *pargc) {
argmax *= 2;
argv = erealloc(argv,
sizeof(*argv) * (argmax + 1));
}
argv[(*pargc)++] = start;
start = NULL;
if (*str++ == '\0')
goto done;
continue;
case '\\':
if (str[1] == ' ' || str[1] == '\t')
/* was a quote */
str++;
break;
default:
break;
}
if (start == NULL)
/* start of new word */
start = q;
*q++ = *str++;
}
done:
argv[(*pargc)] = NULL;
return (argv);
}
/*
* Str_Match --
*