Imported Upstream version 3.2.6
[platform/upstream/ccache.git] / args.c
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 args_init(int init_argc, char **init_args)
23 {
24         struct args *args;
25         int i;
26         args = (struct args *)x_malloc(sizeof(struct args));
27         args->argc = 0;
28         args->argv = (char **)x_malloc(sizeof(char *));
29         args->argv[0] = NULL;
30         for (i = 0; i < init_argc; i++) {
31                 args_add(args, init_args[i]);
32         }
33         return args;
34 }
35
36 struct args *
37 args_init_from_string(const char *command)
38 {
39         struct args *args;
40         char *p = x_strdup(command);
41         char *q = p;
42         char *word, *saveptr = NULL;
43
44         args = args_init(0, NULL);
45         while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
46                 args_add(args, word);
47                 q = NULL;
48         }
49
50         free(p);
51         return args;
52 }
53
54 struct args *
55 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 are not inside quotes. Otherwise
62          * stores the quoting character that started it, for matching the end
63          * quote */
64         quoting = '\0';
65
66         if (!(argtext = read_text_file(filename, 0)))
67                 return NULL;
68
69         args = args_init(0, NULL);
70         pos = argtext;
71         argbuf = x_malloc(strlen(argtext) + 1);
72         argpos = argbuf;
73
74         while (1) {
75                 switch (*pos) {
76                 case '\\':
77                         pos++;
78                         if (*pos == '\0') {
79                                 continue;
80                         }
81                         break;
82
83                 case '\"':
84                 case '\'':
85                         if (quoting != '\0') {
86                                 if (quoting == *pos) {
87                                         quoting = '\0';
88                                         pos++;
89                                         continue;
90                                 } else {
91                                         break;
92                                 }
93                         } else {
94                                 quoting = *pos;
95                                 pos++;
96                                 continue;
97                         }
98
99                 case '\n':
100                 case '\r':
101                 case '\t':
102                 case ' ':
103                         if (quoting) {
104                                 break;
105                         }
106                 /* Fall through */
107
108                 case '\0':
109                         /* end of token */
110                         *argpos = '\0';
111                         if (argbuf[0] != '\0')
112                                 args_add(args, argbuf);
113                         argpos = argbuf;
114                         if (*pos == '\0') {
115                                 goto out;
116                         } else {
117                                 pos++;
118                                 continue;
119                         }
120                 }
121
122                 *argpos = *pos;
123                 pos++;
124                 argpos++;
125         }
126
127 out:
128         free(argbuf);
129         free(argtext);
130         return args;
131 }
132
133 struct args *
134 args_copy(struct args *args)
135 {
136         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 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         offset = replace ? 1 : 0;
155
156         if (replace) {
157                 free(dest->argv[index]);
158         }
159
160         if (src->argc == 0) {
161                 if (replace) {
162                         /* Have to shift everything down by 1 since
163                          * we replaced with an empty list */
164                         for (i = index; i < dest->argc; i++) {
165                                 dest->argv[i] = dest->argv[i + 1];
166                         }
167                         dest->argc--;
168                 }
169                 args_free(src);
170                 return;
171         }
172
173         if (src->argc == 1 && replace) {
174                 /* Trivial case; replace with 1 element */
175                 dest->argv[index] = src->argv[0];
176                 src->argc = 0;
177                 args_free(src);
178                 return;
179         }
180
181         dest->argv = (char **)x_realloc(
182           dest->argv,
183           (src->argc + dest->argc + 1 - offset) *
184           sizeof(char *));
185
186         /* Shift arguments over */
187         for (i = dest->argc; i >= index + offset; i--) {
188                 dest->argv[i + src->argc - offset] = dest->argv[i];
189         }
190
191         /* Copy the new arguments into place */
192         for (i = 0; i < src->argc; i++) {
193                 dest->argv[i + index] = src->argv[i];
194         }
195
196         dest->argc += src->argc - offset;
197         src->argc = 0;
198         args_free(src);
199 }
200
201 void
202 args_free(struct args *args)
203 {
204         int i;
205         if (!args) {
206                 return;
207         }
208         for (i = 0; i < args->argc; ++i) {
209                 if (args->argv[i]) {
210                         free(args->argv[i]);
211                 }
212         }
213         free(args->argv);
214         free(args);
215 }
216
217 void
218 args_add(struct args *args, const char *s)
219 {
220         args->argv = (char **)x_realloc(args->argv,
221                                         (args->argc + 2) * sizeof(char *));
222         args->argv[args->argc] = x_strdup(s);
223         args->argc++;
224         args->argv[args->argc] = NULL;
225 }
226
227 /* Add all arguments in to_append to args. */
228 void
229 args_extend(struct args *args, struct args *to_append)
230 {
231         int i;
232         for (i = 0; i < to_append->argc; i++) {
233                 args_add(args, to_append->argv[i]);
234         }
235 }
236
237 /* pop the last element off the args list */
238 void
239 args_pop(struct args *args, int n)
240 {
241         while (n--) {
242                 args->argc--;
243                 free(args->argv[args->argc]);
244                 args->argv[args->argc] = NULL;
245         }
246 }
247
248 /* set argument at given index */
249 void
250 args_set(struct args *args, int index, const char *value)
251 {
252         assert(index < args->argc);
253         free(args->argv[index]);
254         args->argv[index] = x_strdup(value);
255 }
256
257 /* remove the first element of the argument list */
258 void
259 args_remove_first(struct args *args)
260 {
261         free(args->argv[0]);
262         memmove(&args->argv[0], &args->argv[1], args->argc * sizeof(args->argv[0]));
263         args->argc--;
264 }
265
266 /* add an argument into the front of the argument list */
267 void
268 args_add_prefix(struct args *args, const char *s)
269 {
270         args->argv = (char **)x_realloc(args->argv,
271                                         (args->argc + 2) * sizeof(char *));
272         memmove(&args->argv[1], &args->argv[0],
273                 (args->argc+1) * sizeof(args->argv[0]));
274         args->argv[0] = x_strdup(s);
275         args->argc++;
276 }
277
278 /* strip any arguments beginning with the specified prefix */
279 void
280 args_strip(struct args *args, const char *prefix)
281 {
282         int i;
283         for (i = 0; i < args->argc; ) {
284                 if (str_startswith(args->argv[i], prefix)) {
285                         free(args->argv[i]);
286                         memmove(&args->argv[i],
287                                 &args->argv[i+1],
288                                 (args->argc - i) * sizeof(args->argv[i]));
289                         args->argc--;
290                 } else {
291                         i++;
292                 }
293         }
294 }
295
296 /*
297  * Format args to a space-separated string. Does not quote spaces. Caller
298  * frees.
299  */
300 char *
301 args_to_string(struct args *args)
302 {
303         char *result;
304         char **p;
305         unsigned size = 0;
306         int pos;
307         for (p = args->argv; *p; p++) {
308                 size += strlen(*p) + 1;
309         }
310         result = x_malloc(size + 1);
311         pos = 0;
312         for (p = args->argv; *p; p++) {
313                 pos += sprintf(&result[pos], "%s ", *p);
314         }
315         result[pos - 1] = '\0';
316         return result;
317 }
318
319 /* Returns true if args1 equals args2, else false. */
320 bool
321 args_equal(struct args *args1, struct args *args2)
322 {
323         int i;
324         if (args1->argc != args2->argc) {
325                 return false;
326         }
327         for (i = 0; i < args1->argc; i++) {
328                 if (!str_eq(args1->argv[i], args2->argv[i])) {
329                         return false;
330                 }
331         }
332         return true;
333 }
334