Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2002 Andrew Tridgell
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify it
5 : : * under the terms of the GNU General Public License as published by the Free
6 : : * Software Foundation; either version 3 of the License, or (at your option)
7 : : * any later version.
8 : : *
9 : : * This program is distributed in the hope that it will be useful, but WITHOUT
10 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 : : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 : : * more details.
13 : : *
14 : : * You should have received a copy of the GNU General Public License along with
15 : : * this program; if not, write to the Free Software Foundation, Inc., 51
16 : : * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 : : */
18 : :
19 : : #include "ccache.h"
20 : :
21 : : struct args *
22 : 172 : args_init(int init_argc, char **init_args)
23 : : {
24 : : struct args *args;
25 : : int i;
26 : 172 : args = (struct args *)x_malloc(sizeof(struct args));
27 : 172 : args->argc = 0;
28 : 172 : args->argv = (char **)x_malloc(sizeof(char *));
29 : 172 : args->argv[0] = NULL;
30 [ + + ]: 376 : for (i = 0; i < init_argc; i++) {
31 : 204 : args_add(args, init_args[i]);
32 : : }
33 : 172 : return args;
34 : : }
35 : :
36 : : struct args *
37 : 75 : args_init_from_string(const char *command)
38 : : {
39 : : struct args *args;
40 : 75 : char *p = x_strdup(command);
41 : 75 : char *q = p;
42 : 75 : char *word, *saveptr = NULL;
43 : :
44 : 75 : args = args_init(0, NULL);
45 [ + + ]: 438 : while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
46 : 363 : args_add(args, word);
47 : 363 : q = NULL;
48 : : }
49 : :
50 : 75 : free(p);
51 : 75 : return args;
52 : : }
53 : :
54 : : struct args *
55 : 1 : args_init_from_gcc_atfile(const char *filename)
56 : : {
57 : : struct args *args;
58 : : char *pos, *argtext, *argpos, *argbuf;
59 : : char quoting;
60 : :
61 : : /* Used to track quoting state; if \0, we're not
62 : : * inside quotes. Otherwise stores the quoting character
63 : : * that started it, for matching the end quote */
64 : 1 : quoting = '\0';
65 : :
66 [ - + ]: 1 : if (!(argtext = read_text_file(filename, 0)))
67 : 0 : return NULL;
68 : :
69 : 1 : args = args_init(0, NULL);
70 : 1 : pos = argtext;
71 : 1 : argbuf = x_malloc(strlen(argtext) + 1);
72 : 1 : argpos = argbuf;
73 : :
74 : : while (1) {
75 [ + + + + : 59 : switch (*pos) {
+ ]
76 : : case '\\':
77 : 5 : pos++;
78 [ + + ]: 5 : if (*pos == '\0') {
79 : 1 : continue;
80 : : }
81 : 4 : break;
82 : :
83 : : case '\"':
84 : : case '\'':
85 [ + + ]: 5 : if (quoting != '\0') {
86 [ + + ]: 3 : if (quoting == *pos) {
87 : 2 : quoting = '\0';
88 : 2 : pos++;
89 : 2 : continue;
90 : : } else {
91 : 1 : break;
92 : : }
93 : : } else {
94 : 2 : quoting = *pos;
95 : 2 : pos++;
96 : 2 : continue;
97 : : }
98 : :
99 : : case '\n':
100 : : case '\r':
101 : : case '\t':
102 : : case ' ':
103 [ + + ]: 10 : if (quoting) {
104 : 2 : break;
105 : : }
106 : : /* Fall through */
107 : :
108 : : case '\0':
109 : : /* end of token */
110 : 9 : *argpos = '\0';
111 [ + + ]: 9 : if (argbuf[0] != '\0')
112 : 7 : args_add(args, argbuf);
113 : 9 : argpos = argbuf;
114 [ + + ]: 9 : if (*pos == '\0') {
115 : 1 : goto out;
116 : : } else {
117 : 8 : pos++;
118 : 8 : continue;
119 : : }
120 : : }
121 : :
122 : 45 : *argpos = *pos;
123 : 45 : pos++;
124 : 45 : argpos++;
125 : 58 : }
126 : :
127 : : out:
128 : 1 : free(argbuf);
129 : 1 : free(argtext);
130 : 1 : return args;
131 : : }
132 : :
133 : : struct args *
134 : 45 : args_copy(struct args *args)
135 : : {
136 : 45 : return args_init(args->argc, args->argv);
137 : : }
138 : :
139 : : /* Insert all arguments in src into dest at position index.
140 : : * If replace is true, the element at dest->argv[index] is replaced
141 : : * with the contents of src and everything past it is shifted.
142 : : * Otherwise, dest->argv[index] is also shifted.
143 : : *
144 : : * src is consumed by this operation and should not be freed or used
145 : : * again by the caller */
146 : : void
147 : 6 : args_insert(struct args *dest, int index, struct args *src, bool replace)
148 : : {
149 : : int offset;
150 : : int i;
151 : :
152 : : /* Adjustments made if we are replacing or shifting the element
153 : : * currently at dest->argv[index] */
154 : 6 : offset = replace ? 1 : 0;
155 : :
156 [ + + ]: 6 : if (replace) {
157 : 3 : free(dest->argv[index]);
158 : : }
159 : :
160 [ + + ]: 6 : if (src->argc == 0) {
161 [ + + ]: 2 : if (replace) {
162 : : /* Have to shift everything down by 1 since
163 : : * we replaced with an empty list */
164 [ + + ]: 6 : for (i = index; i < dest->argc; i++) {
165 : 5 : dest->argv[i] = dest->argv[i + 1];
166 : : }
167 : 1 : dest->argc--;
168 : : }
169 : 2 : args_free(src);
170 : 2 : return;
171 : : }
172 : :
173 [ + + ][ + + ]: 4 : if (src->argc == 1 && replace) {
174 : : /* Trivial case; replace with 1 element */
175 : 1 : dest->argv[index] = src->argv[0];
176 : 1 : src->argc = 0;
177 : 1 : args_free(src);
178 : 1 : return;
179 : : }
180 : :
181 : 3 : dest->argv = (char **)x_realloc(
182 : 3 : dest->argv,
183 : 3 : (src->argc + dest->argc + 1 - offset) *
184 : : sizeof(char *));
185 : :
186 : : /* Shift arguments over */
187 [ + + ]: 21 : for (i = dest->argc; i >= index + offset; i--) {
188 : 18 : dest->argv[i + src->argc - offset] = dest->argv[i];
189 : : }
190 : :
191 : : /* Copy the new arguments into place */
192 [ + + ]: 10 : for (i = 0; i < src->argc; i++) {
193 : 7 : dest->argv[i + index] = src->argv[i];
194 : : }
195 : :
196 : 3 : dest->argc += src->argc - offset;
197 : 3 : src->argc = 0;
198 : 6 : args_free(src);
199 : : }
200 : :
201 : : void
202 : 257 : args_free(struct args *args)
203 : : {
204 : : int i;
205 [ + + ]: 257 : if (!args) {
206 : 88 : return;
207 : : }
208 [ + + ]: 1032 : for (i = 0; i < args->argc; ++i) {
209 [ + - ]: 863 : if (args->argv[i]) {
210 : 863 : free(args->argv[i]);
211 : : }
212 : : }
213 : 169 : free(args->argv);
214 : 257 : free(args);
215 : : }
216 : :
217 : : void
218 : 882 : args_add(struct args *args, const char *s)
219 : : {
220 : 882 : args->argv = (char **)x_realloc(args->argv,
221 : 882 : (args->argc + 2) * sizeof(char *));
222 : 882 : args->argv[args->argc] = x_strdup(s);
223 : 882 : args->argc++;
224 : 882 : args->argv[args->argc] = NULL;
225 : 882 : }
226 : :
227 : : /* Add all arguments in to_append to args. */
228 : : void
229 : 29 : args_extend(struct args *args, struct args *to_append)
230 : : {
231 : : int i;
232 [ + + ]: 197 : for (i = 0; i < to_append->argc; i++) {
233 : 168 : args_add(args, to_append->argv[i]);
234 : : }
235 : 29 : }
236 : :
237 : : /* pop the last element off the args list */
238 : : void
239 : 3 : args_pop(struct args *args, int n)
240 : : {
241 [ + + ]: 10 : while (n--) {
242 : 7 : args->argc--;
243 : 7 : free(args->argv[args->argc]);
244 : 7 : args->argv[args->argc] = NULL;
245 : : }
246 : 3 : }
247 : :
248 : : /* set argument at given index */
249 : : void
250 : 2 : args_set(struct args *args, int index, const char *value)
251 : : {
252 [ - + ]: 2 : assert(index < args->argc);
253 : 2 : free(args->argv[index]);
254 : 2 : args->argv[index] = x_strdup(value);
255 : 2 : }
256 : :
257 : : /* remove the first element of the argument list */
258 : : void
259 : 2 : args_remove_first(struct args *args)
260 : : {
261 : 2 : free(args->argv[0]);
262 : 2 : memmove(&args->argv[0], &args->argv[1], args->argc * sizeof(args->argv[0]));
263 : 2 : args->argc--;
264 : 2 : }
265 : :
266 : : /* add an argument into the front of the argument list */
267 : : void
268 : 1 : args_add_prefix(struct args *args, const char *s)
269 : : {
270 : 1 : args->argv = (char **)x_realloc(args->argv,
271 : 1 : (args->argc + 2) * sizeof(char *));
272 : 1 : memmove(&args->argv[1], &args->argv[0],
273 : 1 : (args->argc+1) * sizeof(args->argv[0]));
274 : 1 : args->argv[0] = x_strdup(s);
275 : 1 : args->argc++;
276 : 1 : }
277 : :
278 : : /* strip any arguments beginning with the specified prefix */
279 : : void
280 : 1 : args_strip(struct args *args, const char *prefix)
281 : : {
282 : : int i;
283 [ + + ]: 5 : for (i = 0; i < args->argc; ) {
284 [ + + ]: 4 : if (str_startswith(args->argv[i], prefix)) {
285 : 2 : free(args->argv[i]);
286 : 4 : memmove(&args->argv[i],
287 : 2 : &args->argv[i+1],
288 : 2 : (args->argc - i) * sizeof(args->argv[i]));
289 : 2 : args->argc--;
290 : : } else {
291 : 2 : i++;
292 : : }
293 : : }
294 : 1 : }
295 : :
296 : : /*
297 : : * Format args to a space-separated string. Does not quote spaces. Caller
298 : : * frees.
299 : : */
300 : : char *
301 : 7 : args_to_string(struct args *args)
302 : : {
303 : : char *result;
304 : : char **p;
305 : 7 : unsigned size = 0;
306 : : int pos;
307 [ + + ]: 58 : for (p = args->argv; *p; p++) {
308 : 51 : size += strlen(*p) + 1;
309 : : }
310 : 7 : result = x_malloc(size + 1);
311 : 7 : pos = 0;
312 [ + + ]: 58 : for (p = args->argv; *p; p++) {
313 : 51 : pos += sprintf(&result[pos], "%s ", *p);
314 : : }
315 : 7 : result[pos - 1] = '\0';
316 : 7 : return result;
317 : : }
318 : :
319 : : /* Returns true if args1 equals args2, else false. */
320 : : bool
321 : 28 : args_equal(struct args *args1, struct args *args2)
322 : : {
323 : : int i;
324 [ - + ]: 28 : if (args1->argc != args2->argc) {
325 : 0 : return false;
326 : : }
327 [ + + ]: 174 : for (i = 0; i < args1->argc; i++) {
328 [ - + ]: 146 : if (!str_eq(args1->argv[i], args2->argv[i])) {
329 : 0 : return false;
330 : : }
331 : : }
332 : 28 : return true;
333 : : }
334 : :
|