The only problem I see with this version of the patch is that it modifies orig_args, which is supposed to preserve the original argument list for later usage in failed() if needed, so I applied your patch and then made cc_process_args work on a copy of orig_args instead.
Thanks! -- Joel On 7 August 2012 01:30, Andrew Boie <[email protected]> wrote: > From: "Boie, Andrew P" <[email protected]> > > 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_gcc_atfile() reads and processes the argument files using the > quoting/escape conventions that GCC expects. > > Signed-off-by: Andrew Boie <[email protected]> > --- > args.c | 125 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ccache.c | 21 ++++++++- > ccache.h | 2 + > test/test_args.c | 65 ++++++++++++++++++++++++++++ > 4 files changed, 212 insertions(+), 1 deletion(-) > > diff --git a/args.c b/args.c > index 13a3d37..068338c 100644 > --- a/args.c > +++ b/args.c > @@ -52,11 +52,136 @@ args_init_from_string(const char *command) > } > > struct args * > +args_init_from_gcc_atfile(const char *filename) > +{ > + struct args *args; > + char *pos, *argtext, *argpos, *argbuf; > + char quoting; > + > + /* Used to track quoting state; if \0, we're not > + * inside quotes. Otherwise stores the quoting character > + * that started it, for matching the end quote */ > + quoting = '\0'; > + > + if (!(argtext = read_text_file(filename, 0))) > + return NULL; > + > + args = args_init(0, NULL); > + pos = argtext; > + argbuf = x_malloc(strlen(argtext) + 1); > + argpos = argbuf; > + > + 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); > + free(argtext); > + return args; > +} > + > +struct args * > 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) > { > diff --git a/ccache.c b/ccache.c > index 8e36bdd..5792482 100644 > --- a/ccache.c > +++ b/ccache.c > @@ -1445,9 +1445,28 @@ 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; > + > + file_args = args_init_from_gcc_atfile(argpath); > + if (!file_args) { > + cc_log("Coudln't read arg file %s", argpath); > + stats_update(STATS_ARGS); > + result = false; > + goto out; > + } > + > + 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); > diff --git a/ccache.h b/ccache.h > index 7e25883..a0a82aa 100644 > --- a/ccache.h > +++ b/ccache.h > @@ -70,11 +70,13 @@ struct args { > > struct args *args_init(int, char **); > struct args *args_init_from_string(const char *); > +struct args *args_init_from_gcc_atfile(const char *filename); > struct args *args_copy(struct args *args); > 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..8da83bd 100644 > --- a/test/test_args.c > +++ b/test/test_args.c > @@ -59,6 +59,31 @@ TEST(args_init_from_string) > args_free(args); > } > > +TEST(args_init_from_gcc_atfile) > +{ > + int fd; > + struct args *args; > + const char *argtext = "first sec\\\tond\tthi\\\\rd\nfourth \tfif\\ > th \"si'x\\\" th\" 'seve\nth'\\"; > + > + fd = open("gcc_atfile", O_CREAT | O_WRONLY, 0600); > + CHECK(fd >= 0); > + CHECK(write(fd, argtext, strlen(argtext)) == > (ssize_t)strlen(argtext)); > + close(fd); > + > + args = args_init_from_gcc_atfile("gcc_atfile"); > + CHECK(args); > + CHECK_INT_EQ(7, args->argc); > + CHECK_STR_EQ("first", args->argv[0]); > + CHECK_STR_EQ("sec\tond", args->argv[1]); > + CHECK_STR_EQ("thi\\rd", args->argv[2]); > + CHECK_STR_EQ("fourth", args->argv[3]); > + 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); > +} > + > TEST(args_copy) > { > struct args *args1 = args_init_from_string("foo"); > @@ -144,4 +169,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_FREE2("first second alpha beta gamma fourth fifth", > + args_to_string(args)); > + CHECK_INT_EQ(7, args->argc); > + args_insert(args, 2, src2, true); > + CHECK_STR_EQ_FREE2("first second one beta gamma fourth fifth", > + args_to_string(args)); > + CHECK_INT_EQ(7, args->argc); > + args_insert(args, 2, src3, true); > + CHECK_STR_EQ_FREE2("first second beta gamma fourth fifth", > + args_to_string(args)); > + CHECK_INT_EQ(6, args->argc); > + > + args_insert(args, 1, src4, false); > + CHECK_STR_EQ_FREE2("first alpha beta gamma second beta gamma fourth > fifth", > + args_to_string(args)); > + CHECK_INT_EQ(9, args->argc); > + args_insert(args, 1, src5, false); > + CHECK_STR_EQ_FREE2("first one alpha beta gamma second beta gamma > fourth fifth", > + args_to_string(args)); > + CHECK_INT_EQ(10, args->argc); > + args_insert(args, 1, src6, false); > + CHECK_STR_EQ_FREE2("first one alpha beta gamma second beta gamma > fourth fifth", > + args_to_string(args)); > + CHECK_INT_EQ(10, args->argc); > + > + args_free(args); > +} > + > TEST_SUITE_END > -- > 1.7.9.5 > > _______________________________________________ > ccache mailing list > [email protected] > https://lists.samba.org/mailman/listinfo/ccache _______________________________________________ ccache mailing list [email protected] https://lists.samba.org/mailman/listinfo/ccache
