]> gcc.gnu.org Git - gcc.git/blame - libiberty/argv.c
aarch64: Assume zero gather/scatter set-up cost for -mtune=generic
[gcc.git] / libiberty / argv.c
CommitLineData
6599da04 1/* Create and destroy argument vectors (argv's)
a945c346 2 Copyright (C) 1992-2024 Free Software Foundation, Inc.
6599da04
JM
3 Written by Fred Fish @ Cygnus Support
4
5This file is part of the libiberty library.
6Libiberty is free software; you can redistribute it and/or
7modify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11Libiberty is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14Library General Public License for more details.
15
16You should have received a copy of the GNU Library General Public
17License along with libiberty; see the file COPYING.LIB. If
ee58dffd
NC
18not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19Boston, MA 02110-1301, USA. */
6599da04
JM
20
21
22/* Create and destroy argument vectors. An argument vector is simply an
23 array of string pointers, terminated by a NULL pointer. */
24
3c60ae5a
GDR
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
6599da04
JM
28#include "ansidecl.h"
29#include "libiberty.h"
97393d0a 30#include "safe-ctype.h"
6599da04
JM
31
32/* Routines imported from standard C runtime libraries. */
33
6599da04 34#include <stddef.h>
a81c752a
RH
35#include <string.h>
36#include <stdlib.h>
97393d0a 37#include <stdio.h>
2207ff5d
DD
38#include <sys/types.h>
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#if HAVE_SYS_STAT_H
43#include <sys/stat.h>
44#endif
6599da04 45
6599da04
JM
46#ifndef NULL
47#define NULL 0
48#endif
49
50#ifndef EOS
51#define EOS '\0'
52#endif
53
54#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
55
56
19ddc834
JM
57/*
58
66f49f07 59@deftypefn Extension char** dupargv (char * const *@var{vector})
19ddc834 60
aac04c15
DD
61Duplicate an argument vector. Simply scans through @var{vector},
62duplicating each argument until the terminating @code{NULL} is found.
5bed56d9 63Returns a pointer to the argument vector if successful. Returns
aac04c15
DD
64@code{NULL} if there is insufficient memory to complete building the
65argument vector.
19ddc834 66
aac04c15 67@end deftypefn
19ddc834
JM
68
69*/
70
71char **
66f49f07 72dupargv (char * const *argv)
19ddc834
JM
73{
74 int argc;
75 char **copy;
76
77 if (argv == NULL)
78 return NULL;
79
80 /* the vector */
81 for (argc = 0; argv[argc] != NULL; argc++);
fabfa16b
L
82 copy = (char **) xmalloc ((argc + 1) * sizeof (char *));
83
19ddc834
JM
84 /* the strings */
85 for (argc = 0; argv[argc] != NULL; argc++)
ae120683 86 copy[argc] = xstrdup (argv[argc]);
19ddc834
JM
87 copy[argc] = NULL;
88 return copy;
89}
90
6599da04
JM
91/*
92
aac04c15 93@deftypefn Extension void freeargv (char **@var{vector})
6599da04 94
aac04c15
DD
95Free an argument vector that was built using @code{buildargv}. Simply
96scans through @var{vector}, freeing the memory for each argument until
97the terminating @code{NULL} is found, and then frees @var{vector}
98itself.
6599da04 99
aac04c15 100@end deftypefn
6599da04
JM
101
102*/
103
9486db4f 104void freeargv (char **vector)
6599da04
JM
105{
106 register char **scan;
107
108 if (vector != NULL)
109 {
110 for (scan = vector; *scan != NULL; scan++)
111 {
112 free (*scan);
113 }
114 free (vector);
115 }
116}
117
70277b30
DG
118static void
119consume_whitespace (const char **input)
120{
121 while (ISSPACE (**input))
122 {
123 (*input)++;
124 }
125}
126
6599da04
JM
127/*
128
aac04c15 129@deftypefn Extension char** buildargv (char *@var{sp})
6599da04 130
aac04c15
DD
131Given a pointer to a string, parse the string extracting fields
132separated by whitespace and optionally enclosed within either single
133or double quotes (which are stripped off), and build a vector of
134pointers to copies of the string for each field. The input string
135remains unchanged. The last element of the vector is followed by a
136@code{NULL} element.
6599da04 137
aac04c15 138All of the memory for the pointer array and copies of the string
fabfa16b 139is obtained from @code{xmalloc}. All of the memory can be returned to the
aac04c15
DD
140system with the single function call @code{freeargv}, which takes the
141returned result of @code{buildargv}, as it's argument.
6599da04 142
5bed56d9 143Returns a pointer to the argument vector if successful. Returns
aac04c15
DD
144@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
145memory to complete building the argument vector.
6599da04 146
aac04c15
DD
147If the input is a null string (as opposed to a @code{NULL} pointer),
148then buildarg returns an argument vector that has one arg, a null
149string.
6599da04 150
aac04c15 151@end deftypefn
6599da04 152
aac04c15 153The memory for the argv array is dynamically expanded as necessary.
6599da04 154
aac04c15
DD
155In order to provide a working buffer for extracting arguments into,
156with appropriate stripping of quotes and translation of backslash
157sequences, we allocate a working buffer at least as long as the input
158string. This ensures that we always have enough space in which to
159work, since the extracted arg is never larger than the input string.
6599da04 160
aac04c15
DD
161The argument vector is always kept terminated with a @code{NULL} arg
162pointer, so it can be passed to @code{freeargv} at any time, or
163returned, as appropriate.
6599da04 164
6599da04
JM
165*/
166
9486db4f 167char **buildargv (const char *input)
6599da04
JM
168{
169 char *arg;
170 char *copybuf;
171 int squote = 0;
172 int dquote = 0;
173 int bsquote = 0;
174 int argc = 0;
175 int maxargc = 0;
176 char **argv = NULL;
177 char **nargv;
178
179 if (input != NULL)
180 {
55529d36 181 copybuf = (char *) xmalloc (strlen (input) + 1);
6599da04
JM
182 /* Is a do{}while to always execute the loop once. Always return an
183 argv, even for null strings. See NOTES above, test case below. */
184 do
185 {
186 /* Pick off argv[argc] */
70277b30
DG
187 consume_whitespace (&input);
188
6599da04
JM
189 if ((maxargc == 0) || (argc >= (maxargc - 1)))
190 {
191 /* argv needs initialization, or expansion */
192 if (argv == NULL)
193 {
194 maxargc = INITIAL_MAXARGC;
fabfa16b 195 nargv = (char **) xmalloc (maxargc * sizeof (char *));
6599da04
JM
196 }
197 else
198 {
199 maxargc *= 2;
fabfa16b 200 nargv = (char **) xrealloc (argv, maxargc * sizeof (char *));
6599da04
JM
201 }
202 argv = nargv;
203 argv[argc] = NULL;
204 }
205 /* Begin scanning arg */
5e1d530d 206 if (*input != EOS)
6599da04 207 {
5e1d530d
AB
208 arg = copybuf;
209 while (*input != EOS)
6599da04 210 {
5e1d530d 211 if (ISSPACE (*input) && !squote && !dquote && !bsquote)
6599da04 212 {
5e1d530d 213 break;
6599da04 214 }
5e1d530d 215 else
6599da04 216 {
5e1d530d 217 if (bsquote)
6599da04 218 {
5e1d530d
AB
219 bsquote = 0;
220 if (*input != '\n')
221 *arg++ = *input;
6599da04 222 }
5e1d530d
AB
223 else if (*input == '\\'
224 && !squote
225 && (!dquote
226 || strchr ("$`\"\\\n", *(input + 1)) != NULL))
6599da04 227 {
5e1d530d 228 bsquote = 1;
6599da04 229 }
5e1d530d 230 else if (squote)
6599da04 231 {
5e1d530d
AB
232 if (*input == '\'')
233 {
234 squote = 0;
235 }
236 else
237 {
238 *arg++ = *input;
239 }
6599da04 240 }
5e1d530d 241 else if (dquote)
6599da04 242 {
5e1d530d
AB
243 if (*input == '"')
244 {
245 dquote = 0;
246 }
247 else
248 {
249 *arg++ = *input;
250 }
6599da04
JM
251 }
252 else
253 {
5e1d530d
AB
254 if (*input == '\'')
255 {
256 squote = 1;
257 }
258 else if (*input == '"')
259 {
260 dquote = 1;
261 }
262 else
263 {
264 *arg++ = *input;
265 }
6599da04 266 }
5e1d530d 267 input++;
6599da04 268 }
6599da04 269 }
5e1d530d
AB
270 *arg = EOS;
271 argv[argc] = xstrdup (copybuf);
272 argc++;
6599da04 273 }
6599da04
JM
274 argv[argc] = NULL;
275
70277b30 276 consume_whitespace (&input);
6599da04
JM
277 }
278 while (*input != EOS);
55529d36
L
279
280 free (copybuf);
6599da04
JM
281 }
282 return (argv);
283}
284
97393d0a
MM
285/*
286
66f49f07 287@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file})
2091ff66
NF
288
289Write each member of ARGV, handling all necessary quoting, to the file
4d1e4ce9
CA
290associated with FILE, separated by whitespace. Return 0 on success,
291non-zero if an error occurred while writing to FILE.
2091ff66
NF
292
293@end deftypefn
294
295*/
296
297int
66f49f07 298writeargv (char * const *argv, FILE *f)
2091ff66 299{
2091ff66
NF
300 if (f == NULL)
301 return 1;
302
303 while (*argv != NULL)
304 {
2091ff66
NF
305 const char *arg = *argv;
306
307 while (*arg != EOS)
308 {
309 char c = *arg;
310
311 if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
312 if (EOF == fputc ('\\', f))
4d1e4ce9 313 return 1;
2091ff66
NF
314
315 if (EOF == fputc (c, f))
4d1e4ce9
CA
316 return 1;
317
2091ff66
NF
318 arg++;
319 }
320
18193e8f
AO
321 /* Write out a pair of quotes for an empty argument. */
322 if (arg == *argv)
4d1e4ce9
CA
323 if (EOF == fputs ("\"\"", f))
324 return 1;
18193e8f 325
2091ff66 326 if (EOF == fputc ('\n', f))
4d1e4ce9
CA
327 return 1;
328
2091ff66
NF
329 argv++;
330 }
331
3fe017ee 332 return 0;
2091ff66
NF
333}
334
335/*
336
97393d0a
MM
337@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
338
339The @var{argcp} and @code{argvp} arguments are pointers to the usual
340@code{argc} and @code{argv} arguments to @code{main}. This function
341looks for arguments that begin with the character @samp{@@}. Any such
342arguments are interpreted as ``response files''. The contents of the
343response file are interpreted as additional command line options. In
344particular, the file is separated into whitespace-separated strings;
345each such string is taken as a command-line option. The new options
346are inserted in place of the option naming the response file, and
347@code{*argcp} and @code{*argvp} will be updated. If the value of
348@code{*argvp} is modified by this function, then the new value has
349been dynamically allocated and can be deallocated by the caller with
350@code{freeargv}. However, most callers will simply call
351@code{expandargv} near the beginning of @code{main} and allow the
352operating system to free the memory when the program exits.
353
354@end deftypefn
355
356*/
357
358void
017133fd 359expandargv (int *argcp, char ***argvp)
97393d0a
MM
360{
361 /* The argument we are currently processing. */
362 int i = 0;
3ec62f54
DG
363 /* To check if ***argvp has been dynamically allocated. */
364 char ** const original_argv = *argvp;
ec760bea
NC
365 /* Limit the number of response files that we parse in order
366 to prevent infinite recursion. */
367 unsigned int iteration_limit = 2000;
97393d0a
MM
368 /* Loop over the arguments, handling response files. We always skip
369 ARGVP[0], as that is the name of the program being run. */
370 while (++i < *argcp)
371 {
372 /* The name of the response file. */
373 const char *filename;
374 /* The response file. */
375 FILE *f;
974c2c56
CD
376 /* An upper bound on the number of characters in the response
377 file. */
97393d0a 378 long pos;
974c2c56
CD
379 /* The number of characters in the response file, when actually
380 read. */
381 size_t len;
97393d0a
MM
382 /* A dynamically allocated buffer used to hold options read from a
383 response file. */
384 char *buffer;
385 /* Dynamically allocated storage for the options read from the
386 response file. */
387 char **file_argv;
388 /* The number of options read from the response file, if any. */
974c2c56 389 size_t file_argc;
2207ff5d
DD
390#ifdef S_ISDIR
391 struct stat sb;
392#endif
97393d0a
MM
393 /* We are only interested in options of the form "@file". */
394 filename = (*argvp)[i];
395 if (filename[0] != '@')
396 continue;
ec760bea
NC
397 /* If we have iterated too many times then stop. */
398 if (-- iteration_limit == 0)
399 {
400 fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]);
401 xexit (1);
402 }
2207ff5d
DD
403#ifdef S_ISDIR
404 if (stat (filename+1, &sb) < 0)
405 continue;
406 if (S_ISDIR(sb.st_mode))
407 {
408 fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]);
409 xexit (1);
410 }
411#endif
97393d0a
MM
412 /* Read the contents of the file. */
413 f = fopen (++filename, "r");
414 if (!f)
415 continue;
416 if (fseek (f, 0L, SEEK_END) == -1)
417 goto error;
418 pos = ftell (f);
419 if (pos == -1)
420 goto error;
421 if (fseek (f, 0L, SEEK_SET) == -1)
422 goto error;
423 buffer = (char *) xmalloc (pos * sizeof (char) + 1);
974c2c56
CD
424 len = fread (buffer, sizeof (char), pos, f);
425 if (len != (size_t) pos
426 /* On Windows, fread may return a value smaller than POS,
427 due to CR/LF->CR translation when reading text files.
428 That does not in-and-of itself indicate failure. */
429 && ferror (f))
0b2b7ef3
AM
430 {
431 free (buffer);
432 goto error;
433 }
97393d0a 434 /* Add a NUL terminator. */
974c2c56 435 buffer[len] = '\0';
5e1d530d
AB
436 /* Parse the string. */
437 file_argv = buildargv (buffer);
97393d0a 438 /* If *ARGVP is not already dynamically allocated, copy it. */
3ec62f54 439 if (*argvp == original_argv)
fabfa16b 440 *argvp = dupargv (*argvp);
97393d0a
MM
441 /* Count the number of arguments. */
442 file_argc = 0;
70277b30 443 while (file_argv[file_argc])
97393d0a 444 ++file_argc;
d6df811e
DG
445 /* Free the original option's memory. */
446 free ((*argvp)[i]);
97393d0a
MM
447 /* Now, insert FILE_ARGV into ARGV. The "+1" below handles the
448 NULL terminator at the end of ARGV. */
449 *argvp = ((char **)
450 xrealloc (*argvp,
451 (*argcp + file_argc + 1) * sizeof (char *)));
452 memmove (*argvp + i + file_argc, *argvp + i + 1,
453 (*argcp - i) * sizeof (char *));
454 memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
455 /* The original option has been replaced by all the new
456 options. */
457 *argcp += file_argc - 1;
458 /* Free up memory allocated to process the response file. We do
459 not use freeargv because the individual options in FILE_ARGV
460 are now in the main ARGV. */
461 free (file_argv);
462 free (buffer);
463 /* Rescan all of the arguments just read to support response
464 files that include other response files. */
465 --i;
466 error:
467 /* We're all done with the file now. */
468 fclose (f);
469 }
470}
471
be50fcea
DE
472/*
473
66f49f07 474@deftypefn Extension int countargv (char * const *@var{argv})
be50fcea
DE
475
476Return the number of elements in @var{argv}.
477Returns zero if @var{argv} is NULL.
478
479@end deftypefn
480
481*/
482
483int
66f49f07 484countargv (char * const *argv)
be50fcea
DE
485{
486 int argc;
487
488 if (argv == NULL)
489 return 0;
490 for (argc = 0; argv[argc] != NULL; argc++)
491 continue;
492 return argc;
493}
494
6599da04
JM
495#ifdef MAIN
496
497/* Simple little test driver. */
498
0be6abca 499static const char *const tests[] =
6599da04
JM
500{
501 "a simple command line",
502 "arg 'foo' is single quoted",
503 "arg \"bar\" is double quoted",
504 "arg \"foo bar\" has embedded whitespace",
505 "arg 'Jack said \\'hi\\'' has single quotes",
506 "arg 'Jack said \\\"hi\\\"' has double quotes",
507 "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9",
508
509 /* This should be expanded into only one argument. */
510 "trailing-whitespace ",
511
512 "",
513 NULL
514};
515
9486db4f
GDR
516int
517main (void)
6599da04
JM
518{
519 char **argv;
0be6abca 520 const char *const *test;
6599da04
JM
521 char **targs;
522
523 for (test = tests; *test != NULL; test++)
524 {
525 printf ("buildargv(\"%s\")\n", *test);
526 if ((argv = buildargv (*test)) == NULL)
527 {
528 printf ("failed!\n\n");
529 }
530 else
531 {
532 for (targs = argv; *targs != NULL; targs++)
533 {
534 printf ("\t\"%s\"\n", *targs);
535 }
536 printf ("\n");
537 }
538 freeargv (argv);
539 }
540
0be6abca 541 return 0;
6599da04
JM
542}
543
544#endif /* MAIN */
This page took 2.055431 seconds and 6 git commands to generate.