From: "Boie, Andrew P" <andrew.p.b...@intel.com> 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.b...@intel.com> --- args.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++----- ccache.c | 25 ++++++++++++- ccache.h | 1 + test/test_args.c | 47 +++++++++++++++++++++--- 4 files changed, 166 insertions(+), 15 deletions(-) diff --git a/args.c b/args.c index 13a3d37..ee84951 100644 --- a/args.c +++ b/args.c @@ -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'; + + while (1) { + switch (*pos) { + case '\\': + pos++; + if (*pos == '\0') + continue; + break; - free(p); + 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,56 @@ 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. + * + * This operation modifies dest but leaves src untouched. */ +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]; + } + return; + } + + if (src->argc == 1 && replace) { + /* Trivial case; replace with 1 element */ + dest->argv[index] = x_strdup(src->argv[0]); + 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] = x_strdup(src->argv[j]); + + dest->argc += src->argc - offset; +} + void args_free(struct args *args) { diff --git a/ccache.c b/ccache.c index 8e36bdd..a3d27ab 100644 --- a/ccache.c +++ b/ccache.c @@ -1445,9 +1445,32 @@ 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); + + args_free(file_args); + 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); diff --git a/ccache.h b/ccache.h index 7e25883..ed04c04 100644 --- a/ccache.h +++ b/ccache.h @@ -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); diff --git a/test/test_args.c b/test/test_args.c index 50608fc..3a595be 100644 --- a/test/test_args.c +++ b/test/test_args.c @@ -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,38 @@ 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(""); + + args_insert(args, 2, src1, true); + CHECK_STR_EQ(args_to_string(args), + "first second alpha beta gamma fourth fifth"); + args_insert(args, 2, src2, true); + CHECK_STR_EQ(args_to_string(args), + "first second one beta gamma fourth fifth"); + args_insert(args, 2, src3, true); + CHECK_STR_EQ(args_to_string(args), + "first second beta gamma fourth fifth"); + + args_insert(args, 1, src1, false); + CHECK_STR_EQ(args_to_string(args), + "first alpha beta gamma second beta gamma fourth fifth"); + args_insert(args, 1, src2, false); + CHECK_STR_EQ(args_to_string(args), + "first one alpha beta gamma second beta gamma fourth fifth"); + args_insert(args, 1, src3, false); + CHECK_STR_EQ(args_to_string(args), + "first one alpha beta gamma second beta gamma fourth fifth"); + + args_free(args); + args_free(src1); + args_free(src2); + args_free(src3); +} + TEST_SUITE_END -- 1.7.9.5 _______________________________________________ ccache mailing list ccache@lists.samba.org https://lists.samba.org/mailman/listinfo/ccache