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