133965Sjdp/* Create and destroy argument vectors (argv's)
289857Sobrien   Copyright (C) 1992, 2001 Free Software Foundation, Inc.
333965Sjdp   Written by Fred Fish @ Cygnus Support
433965Sjdp
533965SjdpThis file is part of the libiberty library.
633965SjdpLibiberty is free software; you can redistribute it and/or
733965Sjdpmodify it under the terms of the GNU Library General Public
833965SjdpLicense as published by the Free Software Foundation; either
933965Sjdpversion 2 of the License, or (at your option) any later version.
1033965Sjdp
1133965SjdpLibiberty is distributed in the hope that it will be useful,
1233965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1333965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1433965SjdpLibrary General Public License for more details.
1533965Sjdp
1633965SjdpYou should have received a copy of the GNU Library General Public
1733965SjdpLicense along with libiberty; see the file COPYING.LIB.  If
18218822Sdimnot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19218822SdimBoston, MA 02110-1301, USA.  */
2033965Sjdp
2133965Sjdp
2233965Sjdp/*  Create and destroy argument vectors.  An argument vector is simply an
2333965Sjdp    array of string pointers, terminated by a NULL pointer. */
2433965Sjdp
25218822Sdim#ifdef HAVE_CONFIG_H
26218822Sdim#include "config.h"
27218822Sdim#endif
2833965Sjdp#include "ansidecl.h"
2933965Sjdp#include "libiberty.h"
30218822Sdim#include "safe-ctype.h"
3133965Sjdp
3233965Sjdp/*  Routines imported from standard C runtime libraries. */
3333965Sjdp
3433965Sjdp#include <stddef.h>
3560484Sobrien#include <string.h>
3660484Sobrien#include <stdlib.h>
37218822Sdim#include <stdio.h>
3833965Sjdp
3933965Sjdp#ifndef NULL
4033965Sjdp#define NULL 0
4133965Sjdp#endif
4233965Sjdp
4333965Sjdp#ifndef EOS
4433965Sjdp#define EOS '\0'
4533965Sjdp#endif
4633965Sjdp
4733965Sjdp#define INITIAL_MAXARGC 8	/* Number of args + NULL in initial argv */
4833965Sjdp
4933965Sjdp
5033965Sjdp/*
5133965Sjdp
5289857Sobrien@deftypefn Extension char** dupargv (char **@var{vector})
5333965Sjdp
5489857SobrienDuplicate an argument vector.  Simply scans through @var{vector},
5589857Sobrienduplicating each argument until the terminating @code{NULL} is found.
5689857SobrienReturns a pointer to the argument vector if successful.  Returns
5789857Sobrien@code{NULL} if there is insufficient memory to complete building the
5889857Sobrienargument vector.
5938889Sjdp
6089857Sobrien@end deftypefn
6138889Sjdp
6238889Sjdp*/
6338889Sjdp
6438889Sjdpchar **
65218822Sdimdupargv (char **argv)
6638889Sjdp{
6738889Sjdp  int argc;
6838889Sjdp  char **copy;
6938889Sjdp
7038889Sjdp  if (argv == NULL)
7138889Sjdp    return NULL;
7238889Sjdp
7338889Sjdp  /* the vector */
7438889Sjdp  for (argc = 0; argv[argc] != NULL; argc++);
7538889Sjdp  copy = (char **) malloc ((argc + 1) * sizeof (char *));
7638889Sjdp  if (copy == NULL)
7738889Sjdp    return NULL;
7838889Sjdp
7938889Sjdp  /* the strings */
8038889Sjdp  for (argc = 0; argv[argc] != NULL; argc++)
8138889Sjdp    {
8238889Sjdp      int len = strlen (argv[argc]);
83218822Sdim      copy[argc] = (char *) malloc (len + 1);
8438889Sjdp      if (copy[argc] == NULL)
8538889Sjdp	{
8638889Sjdp	  freeargv (copy);
8738889Sjdp	  return NULL;
8838889Sjdp	}
8938889Sjdp      strcpy (copy[argc], argv[argc]);
9038889Sjdp    }
9138889Sjdp  copy[argc] = NULL;
9238889Sjdp  return copy;
9338889Sjdp}
9438889Sjdp
9538889Sjdp/*
9638889Sjdp
9789857Sobrien@deftypefn Extension void freeargv (char **@var{vector})
9838889Sjdp
9989857SobrienFree an argument vector that was built using @code{buildargv}.  Simply
10089857Sobrienscans through @var{vector}, freeing the memory for each argument until
10189857Sobrienthe terminating @code{NULL} is found, and then frees @var{vector}
10289857Sobrienitself.
10333965Sjdp
10489857Sobrien@end deftypefn
10533965Sjdp
10633965Sjdp*/
10733965Sjdp
108218822Sdimvoid freeargv (char **vector)
10933965Sjdp{
11033965Sjdp  register char **scan;
11133965Sjdp
11233965Sjdp  if (vector != NULL)
11333965Sjdp    {
11433965Sjdp      for (scan = vector; *scan != NULL; scan++)
11533965Sjdp	{
11633965Sjdp	  free (*scan);
11733965Sjdp	}
11833965Sjdp      free (vector);
11933965Sjdp    }
12033965Sjdp}
12133965Sjdp
12233965Sjdp/*
12333965Sjdp
12489857Sobrien@deftypefn Extension char** buildargv (char *@var{sp})
12533965Sjdp
12689857SobrienGiven a pointer to a string, parse the string extracting fields
12789857Sobrienseparated by whitespace and optionally enclosed within either single
12889857Sobrienor double quotes (which are stripped off), and build a vector of
12989857Sobrienpointers to copies of the string for each field.  The input string
13089857Sobrienremains unchanged.  The last element of the vector is followed by a
13189857Sobrien@code{NULL} element.
13233965Sjdp
13389857SobrienAll of the memory for the pointer array and copies of the string
13489857Sobrienis obtained from @code{malloc}.  All of the memory can be returned to the
13589857Sobriensystem with the single function call @code{freeargv}, which takes the
13689857Sobrienreturned result of @code{buildargv}, as it's argument.
13733965Sjdp
13889857SobrienReturns a pointer to the argument vector if successful.  Returns
13989857Sobrien@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
14089857Sobrienmemory to complete building the argument vector.
14133965Sjdp
14289857SobrienIf the input is a null string (as opposed to a @code{NULL} pointer),
14389857Sobrienthen buildarg returns an argument vector that has one arg, a null
14489857Sobrienstring.
14533965Sjdp
14689857Sobrien@end deftypefn
14733965Sjdp
14889857SobrienThe memory for the argv array is dynamically expanded as necessary.
14933965Sjdp
15089857SobrienIn order to provide a working buffer for extracting arguments into,
15189857Sobrienwith appropriate stripping of quotes and translation of backslash
15289857Sobriensequences, we allocate a working buffer at least as long as the input
15389857Sobrienstring.  This ensures that we always have enough space in which to
15489857Sobrienwork, since the extracted arg is never larger than the input string.
15533965Sjdp
15689857SobrienThe argument vector is always kept terminated with a @code{NULL} arg
15789857Sobrienpointer, so it can be passed to @code{freeargv} at any time, or
15889857Sobrienreturned, as appropriate.
15933965Sjdp
16033965Sjdp*/
16133965Sjdp
162218822Sdimchar **buildargv (const char *input)
16333965Sjdp{
16433965Sjdp  char *arg;
16533965Sjdp  char *copybuf;
16633965Sjdp  int squote = 0;
16733965Sjdp  int dquote = 0;
16833965Sjdp  int bsquote = 0;
16933965Sjdp  int argc = 0;
17033965Sjdp  int maxargc = 0;
17133965Sjdp  char **argv = NULL;
17233965Sjdp  char **nargv;
17333965Sjdp
17433965Sjdp  if (input != NULL)
17533965Sjdp    {
17660484Sobrien      copybuf = (char *) alloca (strlen (input) + 1);
17733965Sjdp      /* Is a do{}while to always execute the loop once.  Always return an
17833965Sjdp	 argv, even for null strings.  See NOTES above, test case below. */
17933965Sjdp      do
18033965Sjdp	{
18133965Sjdp	  /* Pick off argv[argc] */
18277298Sobrien	  while (ISBLANK (*input))
18333965Sjdp	    {
18433965Sjdp	      input++;
18533965Sjdp	    }
18633965Sjdp	  if ((maxargc == 0) || (argc >= (maxargc - 1)))
18733965Sjdp	    {
18833965Sjdp	      /* argv needs initialization, or expansion */
18933965Sjdp	      if (argv == NULL)
19033965Sjdp		{
19133965Sjdp		  maxargc = INITIAL_MAXARGC;
19233965Sjdp		  nargv = (char **) malloc (maxargc * sizeof (char *));
19333965Sjdp		}
19433965Sjdp	      else
19533965Sjdp		{
19633965Sjdp		  maxargc *= 2;
19733965Sjdp		  nargv = (char **) realloc (argv, maxargc * sizeof (char *));
19833965Sjdp		}
19933965Sjdp	      if (nargv == NULL)
20033965Sjdp		{
20133965Sjdp		  if (argv != NULL)
20233965Sjdp		    {
20333965Sjdp		      freeargv (argv);
20433965Sjdp		      argv = NULL;
20533965Sjdp		    }
20633965Sjdp		  break;
20733965Sjdp		}
20833965Sjdp	      argv = nargv;
20933965Sjdp	      argv[argc] = NULL;
21033965Sjdp	    }
21133965Sjdp	  /* Begin scanning arg */
21233965Sjdp	  arg = copybuf;
21333965Sjdp	  while (*input != EOS)
21433965Sjdp	    {
215218822Sdim	      if (ISSPACE (*input) && !squote && !dquote && !bsquote)
21633965Sjdp		{
21733965Sjdp		  break;
21833965Sjdp		}
21933965Sjdp	      else
22033965Sjdp		{
22133965Sjdp		  if (bsquote)
22233965Sjdp		    {
22333965Sjdp		      bsquote = 0;
22433965Sjdp		      *arg++ = *input;
22533965Sjdp		    }
22633965Sjdp		  else if (*input == '\\')
22733965Sjdp		    {
22833965Sjdp		      bsquote = 1;
22933965Sjdp		    }
23033965Sjdp		  else if (squote)
23133965Sjdp		    {
23233965Sjdp		      if (*input == '\'')
23333965Sjdp			{
23433965Sjdp			  squote = 0;
23533965Sjdp			}
23633965Sjdp		      else
23733965Sjdp			{
23833965Sjdp			  *arg++ = *input;
23933965Sjdp			}
24033965Sjdp		    }
24133965Sjdp		  else if (dquote)
24233965Sjdp		    {
24333965Sjdp		      if (*input == '"')
24433965Sjdp			{
24533965Sjdp			  dquote = 0;
24633965Sjdp			}
24733965Sjdp		      else
24833965Sjdp			{
24933965Sjdp			  *arg++ = *input;
25033965Sjdp			}
25133965Sjdp		    }
25233965Sjdp		  else
25333965Sjdp		    {
25433965Sjdp		      if (*input == '\'')
25533965Sjdp			{
25633965Sjdp			  squote = 1;
25733965Sjdp			}
25833965Sjdp		      else if (*input == '"')
25933965Sjdp			{
26033965Sjdp			  dquote = 1;
26133965Sjdp			}
26233965Sjdp		      else
26333965Sjdp			{
26433965Sjdp			  *arg++ = *input;
26533965Sjdp			}
26633965Sjdp		    }
26733965Sjdp		  input++;
26833965Sjdp		}
26933965Sjdp	    }
27033965Sjdp	  *arg = EOS;
27133965Sjdp	  argv[argc] = strdup (copybuf);
27233965Sjdp	  if (argv[argc] == NULL)
27333965Sjdp	    {
27433965Sjdp	      freeargv (argv);
27533965Sjdp	      argv = NULL;
27633965Sjdp	      break;
27733965Sjdp	    }
27833965Sjdp	  argc++;
27933965Sjdp	  argv[argc] = NULL;
28033965Sjdp
281218822Sdim	  while (ISSPACE (*input))
28233965Sjdp	    {
28333965Sjdp	      input++;
28433965Sjdp	    }
28533965Sjdp	}
28633965Sjdp      while (*input != EOS);
28733965Sjdp    }
28833965Sjdp  return (argv);
28933965Sjdp}
29033965Sjdp
291218822Sdim/*
292218822Sdim
293218822Sdim@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@{file})
294218822Sdim
295218822SdimWrite each member of ARGV, handling all necessary quoting, to the file
296218822Sdimnamed by FILE, separated by whitespace.  Return 0 on success, non-zero
297218822Sdimif an error occurred while writing to FILE.
298218822Sdim
299218822Sdim@end deftypefn
300218822Sdim
301218822Sdim*/
302218822Sdim
303218822Sdimint
304218822Sdimwriteargv (char **argv, FILE *f)
305218822Sdim{
306218822Sdim  int status = 0;
307218822Sdim
308218822Sdim  if (f == NULL)
309218822Sdim    return 1;
310218822Sdim
311218822Sdim  while (*argv != NULL)
312218822Sdim    {
313218822Sdim      const char *arg = *argv;
314218822Sdim
315218822Sdim      while (*arg != EOS)
316218822Sdim        {
317218822Sdim          char c = *arg;
318218822Sdim
319218822Sdim          if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
320218822Sdim            if (EOF == fputc ('\\', f))
321218822Sdim              {
322218822Sdim                status = 1;
323218822Sdim                goto done;
324218822Sdim              }
325218822Sdim
326218822Sdim          if (EOF == fputc (c, f))
327218822Sdim            {
328218822Sdim              status = 1;
329218822Sdim              goto done;
330218822Sdim            }
331218822Sdim          arg++;
332218822Sdim        }
333218822Sdim
334218822Sdim      if (EOF == fputc ('\n', f))
335218822Sdim        {
336218822Sdim          status = 1;
337218822Sdim          goto done;
338218822Sdim        }
339218822Sdim      argv++;
340218822Sdim    }
341218822Sdim
342218822Sdim done:
343218822Sdim  return status;
344218822Sdim}
345218822Sdim
346218822Sdim/*
347218822Sdim
348218822Sdim@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
349218822Sdim
350218822SdimThe @var{argcp} and @code{argvp} arguments are pointers to the usual
351218822Sdim@code{argc} and @code{argv} arguments to @code{main}.  This function
352218822Sdimlooks for arguments that begin with the character @samp{@@}.  Any such
353218822Sdimarguments are interpreted as ``response files''.  The contents of the
354218822Sdimresponse file are interpreted as additional command line options.  In
355218822Sdimparticular, the file is separated into whitespace-separated strings;
356218822Sdimeach such string is taken as a command-line option.  The new options
357218822Sdimare inserted in place of the option naming the response file, and
358218822Sdim@code{*argcp} and @code{*argvp} will be updated.  If the value of
359218822Sdim@code{*argvp} is modified by this function, then the new value has
360218822Sdimbeen dynamically allocated and can be deallocated by the caller with
361218822Sdim@code{freeargv}.  However, most callers will simply call
362218822Sdim@code{expandargv} near the beginning of @code{main} and allow the
363218822Sdimoperating system to free the memory when the program exits.
364218822Sdim
365218822Sdim@end deftypefn
366218822Sdim
367218822Sdim*/
368218822Sdim
369218822Sdimvoid
370218822Sdimexpandargv (int *argcp, char ***argvp)
371218822Sdim{
372218822Sdim  /* The argument we are currently processing.  */
373218822Sdim  int i = 0;
374218822Sdim  /* Non-zero if ***argvp has been dynamically allocated.  */
375218822Sdim  int argv_dynamic = 0;
376218822Sdim  /* Loop over the arguments, handling response files.  We always skip
377218822Sdim     ARGVP[0], as that is the name of the program being run.  */
378218822Sdim  while (++i < *argcp)
379218822Sdim    {
380218822Sdim      /* The name of the response file.  */
381218822Sdim      const char *filename;
382218822Sdim      /* The response file.  */
383218822Sdim      FILE *f;
384218822Sdim      /* An upper bound on the number of characters in the response
385218822Sdim	 file.  */
386218822Sdim      long pos;
387218822Sdim      /* The number of characters in the response file, when actually
388218822Sdim	 read.  */
389218822Sdim      size_t len;
390218822Sdim      /* A dynamically allocated buffer used to hold options read from a
391218822Sdim	 response file.  */
392218822Sdim      char *buffer;
393218822Sdim      /* Dynamically allocated storage for the options read from the
394218822Sdim	 response file.  */
395218822Sdim      char **file_argv;
396218822Sdim      /* The number of options read from the response file, if any.  */
397218822Sdim      size_t file_argc;
398218822Sdim      /* We are only interested in options of the form "@file".  */
399218822Sdim      filename = (*argvp)[i];
400218822Sdim      if (filename[0] != '@')
401218822Sdim	continue;
402218822Sdim      /* Read the contents of the file.  */
403218822Sdim      f = fopen (++filename, "r");
404218822Sdim      if (!f)
405218822Sdim	continue;
406218822Sdim      if (fseek (f, 0L, SEEK_END) == -1)
407218822Sdim	goto error;
408218822Sdim      pos = ftell (f);
409218822Sdim      if (pos == -1)
410218822Sdim	goto error;
411218822Sdim      if (fseek (f, 0L, SEEK_SET) == -1)
412218822Sdim	goto error;
413218822Sdim      buffer = (char *) xmalloc (pos * sizeof (char) + 1);
414218822Sdim      len = fread (buffer, sizeof (char), pos, f);
415218822Sdim      if (len != (size_t) pos
416218822Sdim	  /* On Windows, fread may return a value smaller than POS,
417218822Sdim	     due to CR/LF->CR translation when reading text files.
418218822Sdim	     That does not in-and-of itself indicate failure.  */
419218822Sdim	  && ferror (f))
420218822Sdim	goto error;
421218822Sdim      /* Add a NUL terminator.  */
422218822Sdim      buffer[len] = '\0';
423218822Sdim      /* Parse the string.  */
424218822Sdim      file_argv = buildargv (buffer);
425218822Sdim      /* If *ARGVP is not already dynamically allocated, copy it.  */
426218822Sdim      if (!argv_dynamic)
427218822Sdim	{
428218822Sdim	  *argvp = dupargv (*argvp);
429218822Sdim	  if (!*argvp)
430218822Sdim	    {
431218822Sdim	      fputs ("\nout of memory\n", stderr);
432218822Sdim	      xexit (1);
433218822Sdim	    }
434218822Sdim	}
435218822Sdim      /* Count the number of arguments.  */
436218822Sdim      file_argc = 0;
437218822Sdim      while (file_argv[file_argc] && *file_argv[file_argc])
438218822Sdim	++file_argc;
439218822Sdim      /* Now, insert FILE_ARGV into ARGV.  The "+1" below handles the
440218822Sdim	 NULL terminator at the end of ARGV.  */
441218822Sdim      *argvp = ((char **)
442218822Sdim		xrealloc (*argvp,
443218822Sdim			  (*argcp + file_argc + 1) * sizeof (char *)));
444218822Sdim      memmove (*argvp + i + file_argc, *argvp + i + 1,
445218822Sdim	       (*argcp - i) * sizeof (char *));
446218822Sdim      memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
447218822Sdim      /* The original option has been replaced by all the new
448218822Sdim	 options.  */
449218822Sdim      *argcp += file_argc - 1;
450218822Sdim      /* Free up memory allocated to process the response file.  We do
451218822Sdim	 not use freeargv because the individual options in FILE_ARGV
452218822Sdim	 are now in the main ARGV.  */
453218822Sdim      free (file_argv);
454218822Sdim      free (buffer);
455218822Sdim      /* Rescan all of the arguments just read to support response
456218822Sdim	 files that include other response files.  */
457218822Sdim      --i;
458218822Sdim    error:
459218822Sdim      /* We're all done with the file now.  */
460218822Sdim      fclose (f);
461218822Sdim    }
462218822Sdim}
463218822Sdim
46433965Sjdp#ifdef MAIN
46533965Sjdp
46633965Sjdp/* Simple little test driver. */
46733965Sjdp
46889857Sobrienstatic const char *const tests[] =
46933965Sjdp{
47033965Sjdp  "a simple command line",
47133965Sjdp  "arg 'foo' is single quoted",
47233965Sjdp  "arg \"bar\" is double quoted",
47333965Sjdp  "arg \"foo bar\" has embedded whitespace",
47433965Sjdp  "arg 'Jack said \\'hi\\'' has single quotes",
47533965Sjdp  "arg 'Jack said \\\"hi\\\"' has double quotes",
47633965Sjdp  "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",
47733965Sjdp
47833965Sjdp  /* This should be expanded into only one argument.  */
47933965Sjdp  "trailing-whitespace ",
48033965Sjdp
48133965Sjdp  "",
48233965Sjdp  NULL
48333965Sjdp};
48433965Sjdp
485218822Sdimint
486218822Sdimmain (void)
48733965Sjdp{
48833965Sjdp  char **argv;
48989857Sobrien  const char *const *test;
49033965Sjdp  char **targs;
49133965Sjdp
49233965Sjdp  for (test = tests; *test != NULL; test++)
49333965Sjdp    {
49433965Sjdp      printf ("buildargv(\"%s\")\n", *test);
49533965Sjdp      if ((argv = buildargv (*test)) == NULL)
49633965Sjdp	{
49733965Sjdp	  printf ("failed!\n\n");
49833965Sjdp	}
49933965Sjdp      else
50033965Sjdp	{
50133965Sjdp	  for (targs = argv; *targs != NULL; targs++)
50233965Sjdp	    {
50333965Sjdp	      printf ("\t\"%s\"\n", *targs);
50433965Sjdp	    }
50533965Sjdp	  printf ("\n");
50633965Sjdp	}
50733965Sjdp      freeargv (argv);
50833965Sjdp    }
50933965Sjdp
51089857Sobrien  return 0;
51133965Sjdp}
51233965Sjdp
51333965Sjdp#endif	/* MAIN */
514