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