rpcgen: Perform shell-style word expansion on RPCGEN_CPP
Up until recently, CPP has been a list of space-separated words, with no quotes, backslashes or other characters with special meaning to a shell. However, as of8fad2cda93
, (escaped) quotes appear in CPP, and the rudimentary parser in rpcgen is insufficient, since it will leave the escaped quotes as escaped rather than performing one level of expansion as would be done by a shell (whether in a script or a Makefile). Rather than hack around this in all the places RPCGEN_CPP gets set, implement proper expansion inside rpcgen. Note that this only deals with a subset of shell syntax, since we don't handle any of: | & ; < > ( ) $ ` * ? [ # ˜ = % having special meaning (with the exception of how a backslash behaves inside double quotes, where \$ means a literal $ inside double quotes but \a means a literal \a), instead using their literal value, but those are all reasonable restrictions, and can be worked around by avoiding their use; what's important is that we get the quoting and splitting right. This fixes -Winvalid-pp-token spew during build${libcompat}. Reviewed by: brooks Fixes:8fad2cda93
("bsd.compat.mk: Provide new CPP and sub-make variables") Differential Revision: https://reviews.freebsd.org/D41013
This commit is contained in:
parent
39248950a0
commit
587458b7d6
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <err.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -270,20 +271,114 @@ add_warning(void)
|
||||
static void
|
||||
prepend_cpp(void)
|
||||
{
|
||||
int idx = 0;
|
||||
const char *var;
|
||||
char *dupvar, *s, *t;
|
||||
int idx = 0, quoted;
|
||||
const char *var, *s;
|
||||
char *dupvar, *t, *word;
|
||||
|
||||
if (CPP != NULL)
|
||||
insarg(idx++, CPP);
|
||||
else if ((var = getenv("RPCGEN_CPP")) == NULL)
|
||||
insarg(idx++, "/usr/bin/cpp");
|
||||
else {
|
||||
/* Parse command line in a rudimentary way */
|
||||
dupvar = xstrdup(var);
|
||||
for (s = dupvar; (t = strsep(&s, " \t")) != NULL; ) {
|
||||
if (t[0])
|
||||
insarg(idx++, t);
|
||||
/*
|
||||
* Parse command line like a shell (but only handle whitespace,
|
||||
* quotes and backslash).
|
||||
*/
|
||||
dupvar = malloc(strlen(var) + 1);
|
||||
quoted = 0;
|
||||
word = NULL;
|
||||
for (s = var, t = dupvar; *s; ++s) {
|
||||
switch (quoted) {
|
||||
/* Unquoted */
|
||||
case 0:
|
||||
switch (*s) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
if (word != NULL) {
|
||||
*t++ = '\0';
|
||||
insarg(idx++, word);
|
||||
word = NULL;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (word == NULL)
|
||||
word = t;
|
||||
quoted = 1;
|
||||
break;
|
||||
case '"':
|
||||
if (word == NULL)
|
||||
word = t;
|
||||
quoted = 2;
|
||||
break;
|
||||
case '\\':
|
||||
switch (*(s + 1)) {
|
||||
case '\0':
|
||||
break;
|
||||
case '\n':
|
||||
++s;
|
||||
continue;
|
||||
default:
|
||||
++s;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (word == NULL)
|
||||
word = t;
|
||||
*t++ = *s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Single-quoted */
|
||||
case 1:
|
||||
switch (*s) {
|
||||
case '\'':
|
||||
quoted = 0;
|
||||
break;
|
||||
default:
|
||||
*t++ = *s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Double-quoted */
|
||||
case 2:
|
||||
switch (*s) {
|
||||
case '"':
|
||||
quoted = 0;
|
||||
break;
|
||||
case '\\':
|
||||
switch (*(s + 1)) {
|
||||
case '\0':
|
||||
break;
|
||||
case '$':
|
||||
case '`':
|
||||
case '"':
|
||||
case '\\':
|
||||
++s;
|
||||
break;
|
||||
case '\n':
|
||||
++s;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
*t++ = *s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (quoted)
|
||||
errx(1, "RPCGEN_CPP: unterminated %c",
|
||||
quoted == 1 ? '\'' : '"');
|
||||
if (word != NULL) {
|
||||
*t++ = '\0';
|
||||
insarg(idx++, word);
|
||||
}
|
||||
free(dupvar);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user