mirror of
https://github.com/reactos/ccache.git
synced 2024-10-07 00:53:23 +00:00
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_gcc_atfile() reads and processes the argument files using the quoting/escape conventions that GCC expects. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
a213940718
commit
0da6ddc169
125
args.c
125
args.c
@ -51,12 +51,137 @@ args_init_from_string(const char *command)
|
||||
return args;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
21
ccache.c
21
ccache.c
@ -1455,9 +1455,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);
|
||||
|
2
ccache.h
2
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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user