add support for '@' parameters

These indicate to the compiler that additional command line options
should be read from a text file. If encountered, read the file,
tokenize any arguments, and if any are found, do an in-place replacement
of the '@' parameter with the arguments within the file.

args_insert() added to insert a set of arguments into a position within
another set of arguments.

args_init_from_string() has been improved so that any character may be
included by prefixing that character with a backslash, and support for
quoted arguments which pass special characters within the quotation marks
unmodified.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Boie, Andrew P 2012-07-30 17:50:33 -07:00 committed by Joel Rosdahl
parent 1fe48c9cdf
commit e11912151c
4 changed files with 178 additions and 15 deletions

115
args.c
View File

@ -37,17 +37,57 @@ struct args *
args_init_from_string(const char *command)
{
struct args *args;
char *p = x_strdup(command);
char *q = p;
char *word, *saveptr = NULL;
const char *pos = command;
char *argbuf = x_malloc(strlen(command) + 1);
char *argpos = argbuf;
args = args_init(0, NULL);
while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
args_add(args, word);
q = NULL;
}
argpos = argbuf;
char quoting = '\0';
free(p);
while (1) {
switch (*pos) {
case '\\':
pos++;
if (*pos == '\0')
continue;
break;
case '\"': case '\'':
if (quoting != '\0') {
if (quoting == *pos) {
quoting = '\0';
pos++;
continue;
} else
break;
} else {
quoting = *pos;
pos++;
continue;
}
case '\n': case '\t': case ' ':
if (quoting)
break;
/* Fall through */
case '\0':
/* end of token */
*argpos = '\0';
if (argbuf[0] != '\0')
args_add(args, argbuf);
argpos = argbuf;
if (*pos == '\0')
goto out;
else {
pos++;
continue;
}
}
*argpos = *pos;
pos++;
argpos++;
}
out:
free(argbuf);
return args;
}
@ -57,6 +97,63 @@ args_copy(struct args *args)
return args_init(args->argc, args->argv);
}
/* Insert all arguments in src into dest at position index.
* If replace is true, the element at dest->argv[index] is replaced
* with the contents of src and everything past it is shifted.
* Otherwise, dest->argv[index] is also shifted.
*
* src is consumed by this operation and should not be freed or used
* again by the caller */
void
args_insert(struct args *dest, int index, struct args *src, bool replace)
{
int offset;
int j;
/* Adjustments made if we are replacing or shifting the element
* currently at dest->argv[index] */
offset = replace ? 1 : 0;
if (replace)
free(dest->argv[index]);
if (src->argc == 0) {
if (replace) {
/* Have to shift everything down by 1 since
* we replaced with an empty list */
for (j = index; j < dest->argc; j++)
dest->argv[j] = dest->argv[j + 1];
dest->argc--;
}
args_free(src);
return;
}
if (src->argc == 1 && replace) {
/* Trivial case; replace with 1 element */
dest->argv[index] = src->argv[0];
src->argc = 0;
args_free(src);
return;
}
dest->argv = (char**)x_realloc(dest->argv,
(src->argc + dest->argc + 1 - offset) *
sizeof(char *));
/* Shift arguments over */
for (j = dest->argc; j >= index + offset; j--)
dest->argv[j + src->argc - offset] = dest->argv[j];
/* Copy the new arguments into place */
for (j = 0; j < src->argc; j++)
dest->argv[j + index] = src->argv[j];
dest->argc += src->argc - offset;
src->argc = 0;
args_free(src);
}
void
args_free(struct args *args)
{

View File

@ -1455,9 +1455,31 @@ cc_process_args(struct args *orig_args, struct args **preprocessor_args,
goto out;
}
if (str_startswith(argv[i], "@")) {
char *argpath = argv[i] + 1;
struct args *file_args;
char *argdata;
if (!(argdata = read_text_file(argpath, 0))) {
cc_log("Coudln't read arg file %s", argpath);
stats_update(STATS_ARGS);
result = false;
goto out;
}
file_args = args_init_from_string(argdata);
free(argdata);
args_insert(orig_args, i, file_args, true);
argc = orig_args->argc;
argv = orig_args->argv;
i--;
continue;
}
/* These are always too hard. */
if (compopt_too_hard(argv[i])
|| str_startswith(argv[i], "@")
|| str_startswith(argv[i], "-fdump-")) {
cc_log("Compiler option %s is unsupported", argv[i]);
stats_update(STATS_UNSUPPORTED);

View File

@ -75,6 +75,7 @@ void args_free(struct args *args);
void args_add(struct args *args, const char *s);
void args_add_prefix(struct args *args, const char *s);
void args_extend(struct args *args, struct args *to_append);
void args_insert(struct args *dest, int index, struct args *src, bool replace);
void args_pop(struct args *args, int n);
void args_set(struct args *args, int index, const char *value);
void args_strip(struct args *args, const char *prefix);

View File

@ -48,14 +48,17 @@ TEST(args_init_populated)
TEST(args_init_from_string)
{
struct args *args = args_init_from_string("first second\tthird\nfourth");
struct args *args = args_init_from_string("first sec\\\tond\tthi\\\\rd\nfourth \tfif\\ th \"si'x\\\" th\" 'seve\nth'\\");
CHECK(args);
CHECK_INT_EQ(4, args->argc);
CHECK_INT_EQ(7, args->argc);
CHECK_STR_EQ("first", args->argv[0]);
CHECK_STR_EQ("second", args->argv[1]);
CHECK_STR_EQ("third", args->argv[2]);
CHECK_STR_EQ("sec\tond", args->argv[1]);
CHECK_STR_EQ("thi\\rd", args->argv[2]);
CHECK_STR_EQ("fourth", args->argv[3]);
CHECK(!args->argv[4]);
CHECK_STR_EQ("fif th", args->argv[4]);
CHECK_STR_EQ("si'x\" th", args->argv[5]);
CHECK_STR_EQ("seve\nth", args->argv[6]);
CHECK(!args->argv[7]);
args_free(args);
}
@ -144,4 +147,44 @@ TEST(args_to_string)
args_free(args);
}
TEST(args_insert)
{
struct args *args = args_init_from_string("first second third fourth fifth");
struct args *src1 = args_init_from_string("alpha beta gamma");
struct args *src2 = args_init_from_string("one");
struct args *src3 = args_init_from_string("");
struct args *src4 = args_init_from_string("alpha beta gamma");
struct args *src5 = args_init_from_string("one");
struct args *src6 = args_init_from_string("");
args_insert(args, 2, src1, true);
CHECK_STR_EQ(args_to_string(args),
"first second alpha beta gamma fourth fifth");
CHECK_INT_EQ(7, args->argc);
args_insert(args, 2, src2, true);
CHECK_STR_EQ(args_to_string(args),
"first second one beta gamma fourth fifth");
CHECK_INT_EQ(7, args->argc);
args_insert(args, 2, src3, true);
CHECK_STR_EQ(args_to_string(args),
"first second beta gamma fourth fifth");
CHECK_INT_EQ(6, args->argc);
args_insert(args, 1, src4, false);
CHECK_STR_EQ(args_to_string(args),
"first alpha beta gamma second beta gamma fourth fifth");
CHECK_INT_EQ(9, args->argc);
args_insert(args, 1, src5, false);
CHECK_STR_EQ(args_to_string(args),
"first one alpha beta gamma second beta gamma fourth fifth");
CHECK_INT_EQ(10, args->argc);
args_insert(args, 1, src6, false);
CHECK_STR_EQ(args_to_string(args),
"first one alpha beta gamma second beta gamma fourth fifth");
CHECK_INT_EQ(10, args->argc);
args_free(args);
}
TEST_SUITE_END