Changes from patch set 3:

- args_insert() now consumes the arguments to be inserted, the caller doesn't 
need to subsequently free it. Avoids some strdups
- test cases and args_insert use in ccache.c updated to reflect new semantics

Andrew

> -----Original Message-----
> From: Boie, Andrew P
> Sent: Monday, July 30, 2012 5:51 PM
> To: ccache@lists.samba.org
> Cc: Boie, Andrew P
> Subject: [PATCH v4] add support for '@' parameters
> 
> 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           |  115
> +++++++++++++++++++++++++++++++++++++++++++++++++-----
>  ccache.c         |   24 +++++++++++-
>  ccache.h         |    1 +
>  test/test_args.c |   53 ++++++++++++++++++++++---
>  4 files changed, 178 insertions(+), 15 deletions(-)
> 
> diff --git a/args.c b/args.c
> index 13a3d37..aa0e5ac 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,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)
>  {
> diff --git a/ccache.c b/ccache.c
> index 8e36bdd..78efd35 100644
> --- a/ccache.c
> +++ b/ccache.c
> @@ -1445,9 +1445,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);
> 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..a513c9d 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,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
> --
> 1.7.9.5

_______________________________________________
ccache mailing list
ccache@lists.samba.org
https://lists.samba.org/mailman/listinfo/ccache

Reply via email to