1/* Create and destroy argument vectors (argv's)
2   Copyright (C) 1992-2020 Free Software Foundation, Inc.
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
18not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19Boston, MA 02110-1301, USA.  */
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
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28#include "ansidecl.h"
29#include "libiberty.h"
30#include "safe-ctype.h"
31
32/*  Routines imported from standard C runtime libraries. */
33
34#include <stddef.h>
35#include <string.h>
36#include <stdlib.h>
37#include <stdio.h>
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
45
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
57/*
58
59@deftypefn Extension char** dupargv (char * const *@var{vector})
60
61Duplicate an argument vector.  Simply scans through @var{vector},
62duplicating each argument until the terminating @code{NULL} is found.
63Returns a pointer to the argument vector if successful.  Returns
64@code{NULL} if there is insufficient memory to complete building the
65argument vector.
66
67@end deftypefn
68
69*/
70
71char **
72dupargv (char * const *argv)
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++);
82  copy = (char **) xmalloc ((argc + 1) * sizeof (char *));
83
84  /* the strings */
85  for (argc = 0; argv[argc] != NULL; argc++)
86    copy[argc] = xstrdup (argv[argc]);
87  copy[argc] = NULL;
88  return copy;
89}
90
91/*
92
93@deftypefn Extension void freeargv (char **@var{vector})
94
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.
99
100@end deftypefn
101
102*/
103
104void freeargv (char **vector)
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
118static void
119consume_whitespace (const char **input)
120{
121  while (ISSPACE (**input))
122    {
123      (*input)++;
124    }
125}
126
127static int
128only_whitespace (const char* input)
129{
130  while (*input != EOS && ISSPACE (*input))
131    input++;
132
133  return (*input == EOS);
134}
135
136/*
137
138@deftypefn Extension char** buildargv (char *@var{sp})
139
140Given a pointer to a string, parse the string extracting fields
141separated by whitespace and optionally enclosed within either single
142or double quotes (which are stripped off), and build a vector of
143pointers to copies of the string for each field.  The input string
144remains unchanged.  The last element of the vector is followed by a
145@code{NULL} element.
146
147All of the memory for the pointer array and copies of the string
148is obtained from @code{xmalloc}.  All of the memory can be returned to the
149system with the single function call @code{freeargv}, which takes the
150returned result of @code{buildargv}, as it's argument.
151
152Returns a pointer to the argument vector if successful.  Returns
153@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
154memory to complete building the argument vector.
155
156If the input is a null string (as opposed to a @code{NULL} pointer),
157then buildarg returns an argument vector that has one arg, a null
158string.
159
160@end deftypefn
161
162The memory for the argv array is dynamically expanded as necessary.
163
164In order to provide a working buffer for extracting arguments into,
165with appropriate stripping of quotes and translation of backslash
166sequences, we allocate a working buffer at least as long as the input
167string.  This ensures that we always have enough space in which to
168work, since the extracted arg is never larger than the input string.
169
170The argument vector is always kept terminated with a @code{NULL} arg
171pointer, so it can be passed to @code{freeargv} at any time, or
172returned, as appropriate.
173
174*/
175
176char **buildargv (const char *input)
177{
178  char *arg;
179  char *copybuf;
180  int squote = 0;
181  int dquote = 0;
182  int bsquote = 0;
183  int argc = 0;
184  int maxargc = 0;
185  char **argv = NULL;
186  char **nargv;
187
188  if (input != NULL)
189    {
190      copybuf = (char *) xmalloc (strlen (input) + 1);
191      /* Is a do{}while to always execute the loop once.  Always return an
192	 argv, even for null strings.  See NOTES above, test case below. */
193      do
194	{
195	  /* Pick off argv[argc] */
196	  consume_whitespace (&input);
197
198	  if ((maxargc == 0) || (argc >= (maxargc - 1)))
199	    {
200	      /* argv needs initialization, or expansion */
201	      if (argv == NULL)
202		{
203		  maxargc = INITIAL_MAXARGC;
204		  nargv = (char **) xmalloc (maxargc * sizeof (char *));
205		}
206	      else
207		{
208		  maxargc *= 2;
209		  nargv = (char **) xrealloc (argv, maxargc * sizeof (char *));
210		}
211	      argv = nargv;
212	      argv[argc] = NULL;
213	    }
214	  /* Begin scanning arg */
215	  arg = copybuf;
216	  while (*input != EOS)
217	    {
218	      if (ISSPACE (*input) && !squote && !dquote && !bsquote)
219		{
220		  break;
221		}
222	      else
223		{
224		  if (bsquote)
225		    {
226		      bsquote = 0;
227		      *arg++ = *input;
228		    }
229		  else if (*input == '\\')
230		    {
231		      bsquote = 1;
232		    }
233		  else if (squote)
234		    {
235		      if (*input == '\'')
236			{
237			  squote = 0;
238			}
239		      else
240			{
241			  *arg++ = *input;
242			}
243		    }
244		  else if (dquote)
245		    {
246		      if (*input == '"')
247			{
248			  dquote = 0;
249			}
250		      else
251			{
252			  *arg++ = *input;
253			}
254		    }
255		  else
256		    {
257		      if (*input == '\'')
258			{
259			  squote = 1;
260			}
261		      else if (*input == '"')
262			{
263			  dquote = 1;
264			}
265		      else
266			{
267			  *arg++ = *input;
268			}
269		    }
270		  input++;
271		}
272	    }
273	  *arg = EOS;
274	  argv[argc] = xstrdup (copybuf);
275	  argc++;
276	  argv[argc] = NULL;
277
278	  consume_whitespace (&input);
279	}
280      while (*input != EOS);
281
282      free (copybuf);
283    }
284  return (argv);
285}
286
287/*
288
289@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file})
290
291Write each member of ARGV, handling all necessary quoting, to the file
292named by FILE, separated by whitespace.  Return 0 on success, non-zero
293if an error occurred while writing to FILE.
294
295@end deftypefn
296
297*/
298
299int
300writeargv (char * const *argv, FILE *f)
301{
302  int status = 0;
303
304  if (f == NULL)
305    return 1;
306
307  while (*argv != NULL)
308    {
309      const char *arg = *argv;
310
311      while (*arg != EOS)
312        {
313          char c = *arg;
314
315          if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
316            if (EOF == fputc ('\\', f))
317              {
318                status = 1;
319                goto done;
320              }
321
322          if (EOF == fputc (c, f))
323            {
324              status = 1;
325              goto done;
326            }
327          arg++;
328        }
329
330      /* Write out a pair of quotes for an empty argument.  */
331      if (arg == *argv)
332	if (EOF == fputs ("\"\"", f))
333	  {
334	    status = 1;
335	    goto done;
336	  }
337
338      if (EOF == fputc ('\n', f))
339        {
340          status = 1;
341          goto done;
342        }
343      argv++;
344    }
345
346 done:
347  return status;
348}
349
350/*
351
352@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
353
354The @var{argcp} and @code{argvp} arguments are pointers to the usual
355@code{argc} and @code{argv} arguments to @code{main}.  This function
356looks for arguments that begin with the character @samp{@@}.  Any such
357arguments are interpreted as ``response files''.  The contents of the
358response file are interpreted as additional command line options.  In
359particular, the file is separated into whitespace-separated strings;
360each such string is taken as a command-line option.  The new options
361are inserted in place of the option naming the response file, and
362@code{*argcp} and @code{*argvp} will be updated.  If the value of
363@code{*argvp} is modified by this function, then the new value has
364been dynamically allocated and can be deallocated by the caller with
365@code{freeargv}.  However, most callers will simply call
366@code{expandargv} near the beginning of @code{main} and allow the
367operating system to free the memory when the program exits.
368
369@end deftypefn
370
371*/
372
373void
374expandargv (int *argcp, char ***argvp)
375{
376  /* The argument we are currently processing.  */
377  int i = 0;
378  /* To check if ***argvp has been dynamically allocated.  */
379  char ** const original_argv = *argvp;
380  /* Limit the number of response files that we parse in order
381     to prevent infinite recursion.  */
382  unsigned int iteration_limit = 2000;
383  /* Loop over the arguments, handling response files.  We always skip
384     ARGVP[0], as that is the name of the program being run.  */
385  while (++i < *argcp)
386    {
387      /* The name of the response file.  */
388      const char *filename;
389      /* The response file.  */
390      FILE *f;
391      /* An upper bound on the number of characters in the response
392	 file.  */
393      long pos;
394      /* The number of characters in the response file, when actually
395	 read.  */
396      size_t len;
397      /* A dynamically allocated buffer used to hold options read from a
398	 response file.  */
399      char *buffer;
400      /* Dynamically allocated storage for the options read from the
401	 response file.  */
402      char **file_argv;
403      /* The number of options read from the response file, if any.  */
404      size_t file_argc;
405#ifdef S_ISDIR
406      struct stat sb;
407#endif
408      /* We are only interested in options of the form "@file".  */
409      filename = (*argvp)[i];
410      if (filename[0] != '@')
411	continue;
412      /* If we have iterated too many times then stop.  */
413      if (-- iteration_limit == 0)
414	{
415	  fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]);
416	  xexit (1);
417	}
418#ifdef S_ISDIR
419      if (stat (filename+1, &sb) < 0)
420	continue;
421      if (S_ISDIR(sb.st_mode))
422	{
423	  fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]);
424	  xexit (1);
425	}
426#endif
427      /* Read the contents of the file.  */
428      f = fopen (++filename, "r");
429      if (!f)
430	continue;
431      if (fseek (f, 0L, SEEK_END) == -1)
432	goto error;
433      pos = ftell (f);
434      if (pos == -1)
435	goto error;
436      if (fseek (f, 0L, SEEK_SET) == -1)
437	goto error;
438      buffer = (char *) xmalloc (pos * sizeof (char) + 1);
439      len = fread (buffer, sizeof (char), pos, f);
440      if (len != (size_t) pos
441	  /* On Windows, fread may return a value smaller than POS,
442	     due to CR/LF->CR translation when reading text files.
443	     That does not in-and-of itself indicate failure.  */
444	  && ferror (f))
445	goto error;
446      /* Add a NUL terminator.  */
447      buffer[len] = '\0';
448      /* If the file is empty or contains only whitespace, buildargv would
449	 return a single empty argument.  In this context we want no arguments,
450	 instead.  */
451      if (only_whitespace (buffer))
452	{
453	  file_argv = (char **) xmalloc (sizeof (char *));
454	  file_argv[0] = NULL;
455	}
456      else
457	/* Parse the string.  */
458	file_argv = buildargv (buffer);
459      /* If *ARGVP is not already dynamically allocated, copy it.  */
460      if (*argvp == original_argv)
461	*argvp = dupargv (*argvp);
462      /* Count the number of arguments.  */
463      file_argc = 0;
464      while (file_argv[file_argc])
465	++file_argc;
466      /* Free the original option's memory.  */
467      free ((*argvp)[i]);
468      /* Now, insert FILE_ARGV into ARGV.  The "+1" below handles the
469	 NULL terminator at the end of ARGV.  */
470      *argvp = ((char **)
471		xrealloc (*argvp,
472			  (*argcp + file_argc + 1) * sizeof (char *)));
473      memmove (*argvp + i + file_argc, *argvp + i + 1,
474	       (*argcp - i) * sizeof (char *));
475      memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
476      /* The original option has been replaced by all the new
477	 options.  */
478      *argcp += file_argc - 1;
479      /* Free up memory allocated to process the response file.  We do
480	 not use freeargv because the individual options in FILE_ARGV
481	 are now in the main ARGV.  */
482      free (file_argv);
483      free (buffer);
484      /* Rescan all of the arguments just read to support response
485	 files that include other response files.  */
486      --i;
487    error:
488      /* We're all done with the file now.  */
489      fclose (f);
490    }
491}
492
493/*
494
495@deftypefn Extension int countargv (char * const *@var{argv})
496
497Return the number of elements in @var{argv}.
498Returns zero if @var{argv} is NULL.
499
500@end deftypefn
501
502*/
503
504int
505countargv (char * const *argv)
506{
507  int argc;
508
509  if (argv == NULL)
510    return 0;
511  for (argc = 0; argv[argc] != NULL; argc++)
512    continue;
513  return argc;
514}
515
516#ifdef MAIN
517
518/* Simple little test driver. */
519
520static const char *const tests[] =
521{
522  "a simple command line",
523  "arg 'foo' is single quoted",
524  "arg \"bar\" is double quoted",
525  "arg \"foo bar\" has embedded whitespace",
526  "arg 'Jack said \\'hi\\'' has single quotes",
527  "arg 'Jack said \\\"hi\\\"' has double quotes",
528  "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",
529
530  /* This should be expanded into only one argument.  */
531  "trailing-whitespace ",
532
533  "",
534  NULL
535};
536
537int
538main (void)
539{
540  char **argv;
541  const char *const *test;
542  char **targs;
543
544  for (test = tests; *test != NULL; test++)
545    {
546      printf ("buildargv(\"%s\")\n", *test);
547      if ((argv = buildargv (*test)) == NULL)
548	{
549	  printf ("failed!\n\n");
550	}
551      else
552	{
553	  for (targs = argv; *targs != NULL; targs++)
554	    {
555	      printf ("\t\"%s\"\n", *targs);
556	    }
557	  printf ("\n");
558	}
559      freeargv (argv);
560    }
561
562  return 0;
563}
564
565#endif	/* MAIN */
566