1/* Create and destroy argument vectors (argv's)
2   Copyright (C) 1992, 2001 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 **) malloc ((argc + 1) * sizeof (char *));
76  if (copy == NULL)
77    return NULL;
78
79  /* the strings */
80  for (argc = 0; argv[argc] != NULL; argc++)
81    {
82      int len = strlen (argv[argc]);
83      copy[argc] = (char *) malloc (len + 1);
84      if (copy[argc] == NULL)
85	{
86	  freeargv (copy);
87	  return NULL;
88	}
89      strcpy (copy[argc], argv[argc]);
90    }
91  copy[argc] = NULL;
92  return copy;
93}
94
95/*
96
97@deftypefn Extension void freeargv (char **@var{vector})
98
99Free an argument vector that was built using @code{buildargv}.  Simply
100scans through @var{vector}, freeing the memory for each argument until
101the terminating @code{NULL} is found, and then frees @var{vector}
102itself.
103
104@end deftypefn
105
106*/
107
108void freeargv (char **vector)
109{
110  register char **scan;
111
112  if (vector != NULL)
113    {
114      for (scan = vector; *scan != NULL; scan++)
115	{
116	  free (*scan);
117	}
118      free (vector);
119    }
120}
121
122/*
123
124@deftypefn Extension char** buildargv (char *@var{sp})
125
126Given a pointer to a string, parse the string extracting fields
127separated by whitespace and optionally enclosed within either single
128or double quotes (which are stripped off), and build a vector of
129pointers to copies of the string for each field.  The input string
130remains unchanged.  The last element of the vector is followed by a
131@code{NULL} element.
132
133All of the memory for the pointer array and copies of the string
134is obtained from @code{malloc}.  All of the memory can be returned to the
135system with the single function call @code{freeargv}, which takes the
136returned result of @code{buildargv}, as it's argument.
137
138Returns a pointer to the argument vector if successful.  Returns
139@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
140memory to complete building the argument vector.
141
142If the input is a null string (as opposed to a @code{NULL} pointer),
143then buildarg returns an argument vector that has one arg, a null
144string.
145
146@end deftypefn
147
148The memory for the argv array is dynamically expanded as necessary.
149
150In order to provide a working buffer for extracting arguments into,
151with appropriate stripping of quotes and translation of backslash
152sequences, we allocate a working buffer at least as long as the input
153string.  This ensures that we always have enough space in which to
154work, since the extracted arg is never larger than the input string.
155
156The argument vector is always kept terminated with a @code{NULL} arg
157pointer, so it can be passed to @code{freeargv} at any time, or
158returned, as appropriate.
159
160*/
161
162char **buildargv (const char *input)
163{
164  char *arg;
165  char *copybuf;
166  int squote = 0;
167  int dquote = 0;
168  int bsquote = 0;
169  int argc = 0;
170  int maxargc = 0;
171  char **argv = NULL;
172  char **nargv;
173
174  if (input != NULL)
175    {
176      copybuf = (char *) alloca (strlen (input) + 1);
177      /* Is a do{}while to always execute the loop once.  Always return an
178	 argv, even for null strings.  See NOTES above, test case below. */
179      do
180	{
181	  /* Pick off argv[argc] */
182	  while (ISBLANK (*input))
183	    {
184	      input++;
185	    }
186	  if ((maxargc == 0) || (argc >= (maxargc - 1)))
187	    {
188	      /* argv needs initialization, or expansion */
189	      if (argv == NULL)
190		{
191		  maxargc = INITIAL_MAXARGC;
192		  nargv = (char **) malloc (maxargc * sizeof (char *));
193		}
194	      else
195		{
196		  maxargc *= 2;
197		  nargv = (char **) realloc (argv, maxargc * sizeof (char *));
198		}
199	      if (nargv == NULL)
200		{
201		  if (argv != NULL)
202		    {
203		      freeargv (argv);
204		      argv = NULL;
205		    }
206		  break;
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] = strdup (copybuf);
272	  if (argv[argc] == NULL)
273	    {
274	      freeargv (argv);
275	      argv = NULL;
276	      break;
277	    }
278	  argc++;
279	  argv[argc] = NULL;
280
281	  while (ISSPACE (*input))
282	    {
283	      input++;
284	    }
285	}
286      while (*input != EOS);
287    }
288  return (argv);
289}
290
291/*
292
293@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
294
295The @var{argcp} and @code{argvp} arguments are pointers to the usual
296@code{argc} and @code{argv} arguments to @code{main}.  This function
297looks for arguments that begin with the character @samp{@@}.  Any such
298arguments are interpreted as ``response files''.  The contents of the
299response file are interpreted as additional command line options.  In
300particular, the file is separated into whitespace-separated strings;
301each such string is taken as a command-line option.  The new options
302are inserted in place of the option naming the response file, and
303@code{*argcp} and @code{*argvp} will be updated.  If the value of
304@code{*argvp} is modified by this function, then the new value has
305been dynamically allocated and can be deallocated by the caller with
306@code{freeargv}.  However, most callers will simply call
307@code{expandargv} near the beginning of @code{main} and allow the
308operating system to free the memory when the program exits.
309
310@end deftypefn
311
312*/
313
314void
315expandargv (argcp, argvp)
316     int *argcp;
317     char ***argvp;
318{
319  /* The argument we are currently processing.  */
320  int i = 0;
321  /* Non-zero if ***argvp has been dynamically allocated.  */
322  int argv_dynamic = 0;
323  /* Loop over the arguments, handling response files.  We always skip
324     ARGVP[0], as that is the name of the program being run.  */
325  while (++i < *argcp)
326    {
327      /* The name of the response file.  */
328      const char *filename;
329      /* The response file.  */
330      FILE *f;
331      /* An upper bound on the number of characters in the response
332	 file.  */
333      long pos;
334      /* The number of characters in the response file, when actually
335	 read.  */
336      size_t len;
337      /* A dynamically allocated buffer used to hold options read from a
338	 response file.  */
339      char *buffer;
340      /* Dynamically allocated storage for the options read from the
341	 response file.  */
342      char **file_argv;
343      /* The number of options read from the response file, if any.  */
344      size_t file_argc;
345      /* We are only interested in options of the form "@file".  */
346      filename = (*argvp)[i];
347      if (filename[0] != '@')
348	continue;
349      /* Read the contents of the file.  */
350      f = fopen (++filename, "r");
351      if (!f)
352	continue;
353      if (fseek (f, 0L, SEEK_END) == -1)
354	goto error;
355      pos = ftell (f);
356      if (pos == -1)
357	goto error;
358      if (fseek (f, 0L, SEEK_SET) == -1)
359	goto error;
360      buffer = (char *) xmalloc (pos * sizeof (char) + 1);
361      len = fread (buffer, sizeof (char), pos, f);
362      if (len != (size_t) pos
363	  /* On Windows, fread may return a value smaller than POS,
364	     due to CR/LF->CR translation when reading text files.
365	     That does not in-and-of itself indicate failure.  */
366	  && ferror (f))
367	goto error;
368      /* Add a NUL terminator.  */
369      buffer[len] = '\0';
370      /* Parse the string.  */
371      file_argv = buildargv (buffer);
372      /* If *ARGVP is not already dynamically allocated, copy it.  */
373      if (!argv_dynamic)
374	{
375	  *argvp = dupargv (*argvp);
376	  if (!*argvp)
377	    {
378	      fputs ("\nout of memory\n", stderr);
379	      xexit (1);
380	    }
381	}
382      /* Count the number of arguments.  */
383      file_argc = 0;
384      while (file_argv[file_argc] && *file_argv[file_argc])
385	++file_argc;
386      /* Now, insert FILE_ARGV into ARGV.  The "+1" below handles the
387	 NULL terminator at the end of ARGV.  */
388      *argvp = ((char **)
389		xrealloc (*argvp,
390			  (*argcp + file_argc + 1) * sizeof (char *)));
391      memmove (*argvp + i + file_argc, *argvp + i + 1,
392	       (*argcp - i) * sizeof (char *));
393      memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
394      /* The original option has been replaced by all the new
395	 options.  */
396      *argcp += file_argc - 1;
397      /* Free up memory allocated to process the response file.  We do
398	 not use freeargv because the individual options in FILE_ARGV
399	 are now in the main ARGV.  */
400      free (file_argv);
401      free (buffer);
402      /* Rescan all of the arguments just read to support response
403	 files that include other response files.  */
404      --i;
405    error:
406      /* We're all done with the file now.  */
407      fclose (f);
408    }
409}
410
411#ifdef MAIN
412
413/* Simple little test driver. */
414
415static const char *const tests[] =
416{
417  "a simple command line",
418  "arg 'foo' is single quoted",
419  "arg \"bar\" is double quoted",
420  "arg \"foo bar\" has embedded whitespace",
421  "arg 'Jack said \\'hi\\'' has single quotes",
422  "arg 'Jack said \\\"hi\\\"' has double quotes",
423  "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",
424
425  /* This should be expanded into only one argument.  */
426  "trailing-whitespace ",
427
428  "",
429  NULL
430};
431
432int
433main (void)
434{
435  char **argv;
436  const char *const *test;
437  char **targs;
438
439  for (test = tests; *test != NULL; test++)
440    {
441      printf ("buildargv(\"%s\")\n", *test);
442      if ((argv = buildargv (*test)) == NULL)
443	{
444	  printf ("failed!\n\n");
445	}
446      else
447	{
448	  for (targs = argv; *targs != NULL; targs++)
449	    {
450	      printf ("\t\"%s\"\n", *targs);
451	    }
452	  printf ("\n");
453	}
454      freeargv (argv);
455    }
456
457  return 0;
458}
459
460#endif	/* MAIN */
461