xref: /openbsd-src/gnu/lib/libiberty/src/argv.c (revision 781be6a6d45d9bdf749c8beb196154076430c262)
100bf4279Sespie /* Create and destroy argument vectors (argv's)
237c53322Sespie    Copyright (C) 1992, 2001 Free Software Foundation, Inc.
300bf4279Sespie    Written by Fred Fish @ Cygnus Support
400bf4279Sespie 
500bf4279Sespie This file is part of the libiberty library.
600bf4279Sespie Libiberty is free software; you can redistribute it and/or
700bf4279Sespie modify it under the terms of the GNU Library General Public
800bf4279Sespie License as published by the Free Software Foundation; either
900bf4279Sespie version 2 of the License, or (at your option) any later version.
1000bf4279Sespie 
1100bf4279Sespie Libiberty is distributed in the hope that it will be useful,
1200bf4279Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
1300bf4279Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1400bf4279Sespie Library General Public License for more details.
1500bf4279Sespie 
1600bf4279Sespie You should have received a copy of the GNU Library General Public
1700bf4279Sespie License along with libiberty; see the file COPYING.LIB.  If
18150b7e42Smiod not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19150b7e42Smiod Boston, MA 02110-1301, USA.  */
2000bf4279Sespie 
2100bf4279Sespie 
2200bf4279Sespie /*  Create and destroy argument vectors.  An argument vector is simply an
2300bf4279Sespie     array of string pointers, terminated by a NULL pointer. */
2400bf4279Sespie 
25150b7e42Smiod #ifdef HAVE_CONFIG_H
26150b7e42Smiod #include "config.h"
27150b7e42Smiod #endif
2800bf4279Sespie #include "ansidecl.h"
2900bf4279Sespie #include "libiberty.h"
30150b7e42Smiod #include "safe-ctype.h"
3100bf4279Sespie 
3200bf4279Sespie /*  Routines imported from standard C runtime libraries. */
3300bf4279Sespie 
3400bf4279Sespie #include <stddef.h>
3500bf4279Sespie #include <string.h>
3600bf4279Sespie #include <stdlib.h>
37150b7e42Smiod #include <stdio.h>
3800bf4279Sespie 
3900bf4279Sespie #ifndef NULL
4000bf4279Sespie #define NULL 0
4100bf4279Sespie #endif
4200bf4279Sespie 
4300bf4279Sespie #ifndef EOS
4400bf4279Sespie #define EOS '\0'
4500bf4279Sespie #endif
4600bf4279Sespie 
4700bf4279Sespie #define INITIAL_MAXARGC 8	/* Number of args + NULL in initial argv */
4800bf4279Sespie 
4900bf4279Sespie 
5000bf4279Sespie /*
5100bf4279Sespie 
5237c53322Sespie @deftypefn Extension char** dupargv (char **@var{vector})
5300bf4279Sespie 
5437c53322Sespie Duplicate an argument vector.  Simply scans through @var{vector},
5537c53322Sespie duplicating each argument until the terminating @code{NULL} is found.
5637c53322Sespie Returns a pointer to the argument vector if successful.  Returns
5737c53322Sespie @code{NULL} if there is insufficient memory to complete building the
5837c53322Sespie argument vector.
5900bf4279Sespie 
6037c53322Sespie @end deftypefn
6100bf4279Sespie 
6200bf4279Sespie */
6300bf4279Sespie 
6400bf4279Sespie char **
dupargv(char ** argv)65150b7e42Smiod dupargv (char **argv)
6600bf4279Sespie {
6700bf4279Sespie   int argc;
6800bf4279Sespie   char **copy;
6900bf4279Sespie 
7000bf4279Sespie   if (argv == NULL)
7100bf4279Sespie     return NULL;
7200bf4279Sespie 
7300bf4279Sespie   /* the vector */
7400bf4279Sespie   for (argc = 0; argv[argc] != NULL; argc++);
7500bf4279Sespie   copy = (char **) malloc ((argc + 1) * sizeof (char *));
7600bf4279Sespie   if (copy == NULL)
7700bf4279Sespie     return NULL;
7800bf4279Sespie 
7900bf4279Sespie   /* the strings */
8000bf4279Sespie   for (argc = 0; argv[argc] != NULL; argc++)
8100bf4279Sespie     {
82*781be6a6Smiod       copy[argc] = strdup (argv[argc]);
8300bf4279Sespie       if (copy[argc] == NULL)
8400bf4279Sespie 	{
8500bf4279Sespie 	  freeargv (copy);
8600bf4279Sespie 	  return NULL;
8700bf4279Sespie 	}
8800bf4279Sespie     }
8900bf4279Sespie   copy[argc] = NULL;
9000bf4279Sespie   return copy;
9100bf4279Sespie }
9200bf4279Sespie 
9300bf4279Sespie /*
9400bf4279Sespie 
9537c53322Sespie @deftypefn Extension void freeargv (char **@var{vector})
9600bf4279Sespie 
9737c53322Sespie Free an argument vector that was built using @code{buildargv}.  Simply
9837c53322Sespie scans through @var{vector}, freeing the memory for each argument until
9937c53322Sespie the terminating @code{NULL} is found, and then frees @var{vector}
10037c53322Sespie itself.
10100bf4279Sespie 
10237c53322Sespie @end deftypefn
10300bf4279Sespie 
10400bf4279Sespie */
10500bf4279Sespie 
freeargv(char ** vector)106150b7e42Smiod void freeargv (char **vector)
10700bf4279Sespie {
10800bf4279Sespie   register char **scan;
10900bf4279Sespie 
11000bf4279Sespie   if (vector != NULL)
11100bf4279Sespie     {
11200bf4279Sespie       for (scan = vector; *scan != NULL; scan++)
11300bf4279Sespie 	{
11400bf4279Sespie 	  free (*scan);
11500bf4279Sespie 	}
11600bf4279Sespie       free (vector);
11700bf4279Sespie     }
11800bf4279Sespie }
11900bf4279Sespie 
12000bf4279Sespie /*
12100bf4279Sespie 
12237c53322Sespie @deftypefn Extension char** buildargv (char *@var{sp})
12300bf4279Sespie 
12400bf4279Sespie Given a pointer to a string, parse the string extracting fields
12500bf4279Sespie separated by whitespace and optionally enclosed within either single
12600bf4279Sespie or double quotes (which are stripped off), and build a vector of
12700bf4279Sespie pointers to copies of the string for each field.  The input string
12837c53322Sespie remains unchanged.  The last element of the vector is followed by a
12937c53322Sespie @code{NULL} element.
13000bf4279Sespie 
13100bf4279Sespie All of the memory for the pointer array and copies of the string
13237c53322Sespie is obtained from @code{malloc}.  All of the memory can be returned to the
13337c53322Sespie system with the single function call @code{freeargv}, which takes the
13437c53322Sespie returned result of @code{buildargv}, as it's argument.
13500bf4279Sespie 
13637c53322Sespie Returns a pointer to the argument vector if successful.  Returns
13737c53322Sespie @code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
13800bf4279Sespie memory to complete building the argument vector.
13900bf4279Sespie 
14037c53322Sespie If the input is a null string (as opposed to a @code{NULL} pointer),
14137c53322Sespie then buildarg returns an argument vector that has one arg, a null
14237c53322Sespie string.
14337c53322Sespie 
14437c53322Sespie @end deftypefn
14537c53322Sespie 
14637c53322Sespie The memory for the argv array is dynamically expanded as necessary.
14700bf4279Sespie 
14800bf4279Sespie In order to provide a working buffer for extracting arguments into,
14900bf4279Sespie with appropriate stripping of quotes and translation of backslash
15000bf4279Sespie sequences, we allocate a working buffer at least as long as the input
15100bf4279Sespie string.  This ensures that we always have enough space in which to
15200bf4279Sespie work, since the extracted arg is never larger than the input string.
15300bf4279Sespie 
15437c53322Sespie The argument vector is always kept terminated with a @code{NULL} arg
15537c53322Sespie pointer, so it can be passed to @code{freeargv} at any time, or
15637c53322Sespie returned, as appropriate.
15700bf4279Sespie 
15800bf4279Sespie */
15900bf4279Sespie 
buildargv(const char * input)160150b7e42Smiod char **buildargv (const char *input)
16100bf4279Sespie {
16200bf4279Sespie   char *arg;
16300bf4279Sespie   char *copybuf;
16400bf4279Sespie   int squote = 0;
16500bf4279Sespie   int dquote = 0;
16600bf4279Sespie   int bsquote = 0;
16700bf4279Sespie   int argc = 0;
16800bf4279Sespie   int maxargc = 0;
16900bf4279Sespie   char **argv = NULL;
17000bf4279Sespie   char **nargv;
17100bf4279Sespie 
17200bf4279Sespie   if (input != NULL)
17300bf4279Sespie     {
17400bf4279Sespie       copybuf = (char *) alloca (strlen (input) + 1);
17500bf4279Sespie       /* Is a do{}while to always execute the loop once.  Always return an
17600bf4279Sespie 	 argv, even for null strings.  See NOTES above, test case below. */
17700bf4279Sespie       do
17800bf4279Sespie 	{
17900bf4279Sespie 	  /* Pick off argv[argc] */
180f5dd06f4Sespie 	  while (ISBLANK (*input))
18100bf4279Sespie 	    {
18200bf4279Sespie 	      input++;
18300bf4279Sespie 	    }
18400bf4279Sespie 	  if ((maxargc == 0) || (argc >= (maxargc - 1)))
18500bf4279Sespie 	    {
18600bf4279Sespie 	      /* argv needs initialization, or expansion */
18700bf4279Sespie 	      if (argv == NULL)
18800bf4279Sespie 		{
18900bf4279Sespie 		  maxargc = INITIAL_MAXARGC;
19000bf4279Sespie 		  nargv = (char **) malloc (maxargc * sizeof (char *));
19100bf4279Sespie 		}
19200bf4279Sespie 	      else
19300bf4279Sespie 		{
19400bf4279Sespie 		  maxargc *= 2;
19500bf4279Sespie 		  nargv = (char **) realloc (argv, maxargc * sizeof (char *));
19600bf4279Sespie 		}
19700bf4279Sespie 	      if (nargv == NULL)
19800bf4279Sespie 		{
19900bf4279Sespie 		  if (argv != NULL)
20000bf4279Sespie 		    {
20100bf4279Sespie 		      freeargv (argv);
20200bf4279Sespie 		      argv = NULL;
20300bf4279Sespie 		    }
20400bf4279Sespie 		  break;
20500bf4279Sespie 		}
20600bf4279Sespie 	      argv = nargv;
20700bf4279Sespie 	      argv[argc] = NULL;
20800bf4279Sespie 	    }
20900bf4279Sespie 	  /* Begin scanning arg */
21000bf4279Sespie 	  arg = copybuf;
21100bf4279Sespie 	  while (*input != EOS)
21200bf4279Sespie 	    {
213150b7e42Smiod 	      if (ISSPACE (*input) && !squote && !dquote && !bsquote)
21400bf4279Sespie 		{
21500bf4279Sespie 		  break;
21600bf4279Sespie 		}
21700bf4279Sespie 	      else
21800bf4279Sespie 		{
21900bf4279Sespie 		  if (bsquote)
22000bf4279Sespie 		    {
22100bf4279Sespie 		      bsquote = 0;
22200bf4279Sespie 		      *arg++ = *input;
22300bf4279Sespie 		    }
22400bf4279Sespie 		  else if (*input == '\\')
22500bf4279Sespie 		    {
22600bf4279Sespie 		      bsquote = 1;
22700bf4279Sespie 		    }
22800bf4279Sespie 		  else if (squote)
22900bf4279Sespie 		    {
23000bf4279Sespie 		      if (*input == '\'')
23100bf4279Sespie 			{
23200bf4279Sespie 			  squote = 0;
23300bf4279Sespie 			}
23400bf4279Sespie 		      else
23500bf4279Sespie 			{
23600bf4279Sespie 			  *arg++ = *input;
23700bf4279Sespie 			}
23800bf4279Sespie 		    }
23900bf4279Sespie 		  else if (dquote)
24000bf4279Sespie 		    {
24100bf4279Sespie 		      if (*input == '"')
24200bf4279Sespie 			{
24300bf4279Sespie 			  dquote = 0;
24400bf4279Sespie 			}
24500bf4279Sespie 		      else
24600bf4279Sespie 			{
24700bf4279Sespie 			  *arg++ = *input;
24800bf4279Sespie 			}
24900bf4279Sespie 		    }
25000bf4279Sespie 		  else
25100bf4279Sespie 		    {
25200bf4279Sespie 		      if (*input == '\'')
25300bf4279Sespie 			{
25400bf4279Sespie 			  squote = 1;
25500bf4279Sespie 			}
25600bf4279Sespie 		      else if (*input == '"')
25700bf4279Sespie 			{
25800bf4279Sespie 			  dquote = 1;
25900bf4279Sespie 			}
26000bf4279Sespie 		      else
26100bf4279Sespie 			{
26200bf4279Sespie 			  *arg++ = *input;
26300bf4279Sespie 			}
26400bf4279Sespie 		    }
26500bf4279Sespie 		  input++;
26600bf4279Sespie 		}
26700bf4279Sespie 	    }
26800bf4279Sespie 	  *arg = EOS;
26900bf4279Sespie 	  argv[argc] = strdup (copybuf);
27000bf4279Sespie 	  if (argv[argc] == NULL)
27100bf4279Sespie 	    {
27200bf4279Sespie 	      freeargv (argv);
27300bf4279Sespie 	      argv = NULL;
27400bf4279Sespie 	      break;
27500bf4279Sespie 	    }
27600bf4279Sespie 	  argc++;
27700bf4279Sespie 	  argv[argc] = NULL;
27800bf4279Sespie 
279150b7e42Smiod 	  while (ISSPACE (*input))
28000bf4279Sespie 	    {
28100bf4279Sespie 	      input++;
28200bf4279Sespie 	    }
28300bf4279Sespie 	}
28400bf4279Sespie       while (*input != EOS);
28500bf4279Sespie     }
28600bf4279Sespie   return (argv);
28700bf4279Sespie }
28800bf4279Sespie 
289150b7e42Smiod /*
290150b7e42Smiod 
291150b7e42Smiod @deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
292150b7e42Smiod 
293150b7e42Smiod The @var{argcp} and @code{argvp} arguments are pointers to the usual
294150b7e42Smiod @code{argc} and @code{argv} arguments to @code{main}.  This function
295150b7e42Smiod looks for arguments that begin with the character @samp{@@}.  Any such
296150b7e42Smiod arguments are interpreted as ``response files''.  The contents of the
297150b7e42Smiod response file are interpreted as additional command line options.  In
298150b7e42Smiod particular, the file is separated into whitespace-separated strings;
299150b7e42Smiod each such string is taken as a command-line option.  The new options
300150b7e42Smiod are inserted in place of the option naming the response file, and
301150b7e42Smiod @code{*argcp} and @code{*argvp} will be updated.  If the value of
302150b7e42Smiod @code{*argvp} is modified by this function, then the new value has
303150b7e42Smiod been dynamically allocated and can be deallocated by the caller with
304150b7e42Smiod @code{freeargv}.  However, most callers will simply call
305150b7e42Smiod @code{expandargv} near the beginning of @code{main} and allow the
306150b7e42Smiod operating system to free the memory when the program exits.
307150b7e42Smiod 
308150b7e42Smiod @end deftypefn
309150b7e42Smiod 
310150b7e42Smiod */
311150b7e42Smiod 
312150b7e42Smiod void
expandargv(argcp,argvp)313150b7e42Smiod expandargv (argcp, argvp)
314150b7e42Smiod      int *argcp;
315150b7e42Smiod      char ***argvp;
316150b7e42Smiod {
317150b7e42Smiod   /* The argument we are currently processing.  */
318150b7e42Smiod   int i = 0;
319150b7e42Smiod   /* Non-zero if ***argvp has been dynamically allocated.  */
320150b7e42Smiod   int argv_dynamic = 0;
321150b7e42Smiod   /* Loop over the arguments, handling response files.  We always skip
322150b7e42Smiod      ARGVP[0], as that is the name of the program being run.  */
323150b7e42Smiod   while (++i < *argcp)
324150b7e42Smiod     {
325150b7e42Smiod       /* The name of the response file.  */
326150b7e42Smiod       const char *filename;
327150b7e42Smiod       /* The response file.  */
328150b7e42Smiod       FILE *f;
329150b7e42Smiod       /* An upper bound on the number of characters in the response
330150b7e42Smiod 	 file.  */
331*781be6a6Smiod       off_t pos;
332150b7e42Smiod       /* The number of characters in the response file, when actually
333150b7e42Smiod 	 read.  */
334150b7e42Smiod       size_t len;
335150b7e42Smiod       /* A dynamically allocated buffer used to hold options read from a
336150b7e42Smiod 	 response file.  */
337150b7e42Smiod       char *buffer;
338150b7e42Smiod       /* Dynamically allocated storage for the options read from the
339150b7e42Smiod 	 response file.  */
340150b7e42Smiod       char **file_argv;
341150b7e42Smiod       /* The number of options read from the response file, if any.  */
342150b7e42Smiod       size_t file_argc;
343150b7e42Smiod       /* We are only interested in options of the form "@file".  */
344150b7e42Smiod       filename = (*argvp)[i];
345150b7e42Smiod       if (filename[0] != '@')
346150b7e42Smiod 	continue;
347150b7e42Smiod       /* Read the contents of the file.  */
348150b7e42Smiod       f = fopen (++filename, "r");
349150b7e42Smiod       if (!f)
350150b7e42Smiod 	continue;
351150b7e42Smiod       if (fseek (f, 0L, SEEK_END) == -1)
352150b7e42Smiod 	goto error;
353*781be6a6Smiod       pos = ftello (f);
354150b7e42Smiod       if (pos == -1)
355150b7e42Smiod 	goto error;
356150b7e42Smiod       if (fseek (f, 0L, SEEK_SET) == -1)
357150b7e42Smiod 	goto error;
358150b7e42Smiod       buffer = (char *) xmalloc (pos * sizeof (char) + 1);
359150b7e42Smiod       len = fread (buffer, sizeof (char), pos, f);
360150b7e42Smiod       if (len != (size_t) pos
361150b7e42Smiod 	  /* On Windows, fread may return a value smaller than POS,
362150b7e42Smiod 	     due to CR/LF->CR translation when reading text files.
363150b7e42Smiod 	     That does not in-and-of itself indicate failure.  */
364150b7e42Smiod 	  && ferror (f))
365150b7e42Smiod 	goto error;
366150b7e42Smiod       /* Add a NUL terminator.  */
367150b7e42Smiod       buffer[len] = '\0';
368150b7e42Smiod       /* Parse the string.  */
369150b7e42Smiod       file_argv = buildargv (buffer);
370150b7e42Smiod       /* If *ARGVP is not already dynamically allocated, copy it.  */
371150b7e42Smiod       if (!argv_dynamic)
372150b7e42Smiod 	{
373150b7e42Smiod 	  *argvp = dupargv (*argvp);
374150b7e42Smiod 	  if (!*argvp)
375150b7e42Smiod 	    {
376150b7e42Smiod 	      fputs ("\nout of memory\n", stderr);
377150b7e42Smiod 	      xexit (1);
378150b7e42Smiod 	    }
379150b7e42Smiod 	}
380150b7e42Smiod       /* Count the number of arguments.  */
381150b7e42Smiod       file_argc = 0;
382150b7e42Smiod       while (file_argv[file_argc] && *file_argv[file_argc])
383150b7e42Smiod 	++file_argc;
384150b7e42Smiod       /* Now, insert FILE_ARGV into ARGV.  The "+1" below handles the
385150b7e42Smiod 	 NULL terminator at the end of ARGV.  */
386150b7e42Smiod       *argvp = ((char **)
387150b7e42Smiod 		xrealloc (*argvp,
388150b7e42Smiod 			  (*argcp + file_argc + 1) * sizeof (char *)));
389150b7e42Smiod       memmove (*argvp + i + file_argc, *argvp + i + 1,
390150b7e42Smiod 	       (*argcp - i) * sizeof (char *));
391150b7e42Smiod       memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
392150b7e42Smiod       /* The original option has been replaced by all the new
393150b7e42Smiod 	 options.  */
394150b7e42Smiod       *argcp += file_argc - 1;
395150b7e42Smiod       /* Free up memory allocated to process the response file.  We do
396150b7e42Smiod 	 not use freeargv because the individual options in FILE_ARGV
397150b7e42Smiod 	 are now in the main ARGV.  */
398150b7e42Smiod       free (file_argv);
399150b7e42Smiod       free (buffer);
400150b7e42Smiod       /* Rescan all of the arguments just read to support response
401150b7e42Smiod 	 files that include other response files.  */
402150b7e42Smiod       --i;
403150b7e42Smiod     error:
404150b7e42Smiod       /* We're all done with the file now.  */
405150b7e42Smiod       fclose (f);
406150b7e42Smiod     }
407150b7e42Smiod }
408150b7e42Smiod 
40900bf4279Sespie #ifdef MAIN
41000bf4279Sespie 
41100bf4279Sespie /* Simple little test driver. */
41200bf4279Sespie 
41337c53322Sespie static const char *const tests[] =
41400bf4279Sespie {
41500bf4279Sespie   "a simple command line",
41600bf4279Sespie   "arg 'foo' is single quoted",
41700bf4279Sespie   "arg \"bar\" is double quoted",
41800bf4279Sespie   "arg \"foo bar\" has embedded whitespace",
41900bf4279Sespie   "arg 'Jack said \\'hi\\'' has single quotes",
42000bf4279Sespie   "arg 'Jack said \\\"hi\\\"' has double quotes",
42100bf4279Sespie   "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",
42200bf4279Sespie 
42300bf4279Sespie   /* This should be expanded into only one argument.  */
42400bf4279Sespie   "trailing-whitespace ",
42500bf4279Sespie 
42600bf4279Sespie   "",
42700bf4279Sespie   NULL
42800bf4279Sespie };
42900bf4279Sespie 
430150b7e42Smiod int
main(void)431150b7e42Smiod main (void)
43200bf4279Sespie {
43300bf4279Sespie   char **argv;
43437c53322Sespie   const char *const *test;
43500bf4279Sespie   char **targs;
43600bf4279Sespie 
43700bf4279Sespie   for (test = tests; *test != NULL; test++)
43800bf4279Sespie     {
43900bf4279Sespie       printf ("buildargv(\"%s\")\n", *test);
44000bf4279Sespie       if ((argv = buildargv (*test)) == NULL)
44100bf4279Sespie 	{
44200bf4279Sespie 	  printf ("failed!\n\n");
44300bf4279Sespie 	}
44400bf4279Sespie       else
44500bf4279Sespie 	{
44600bf4279Sespie 	  for (targs = argv; *targs != NULL; targs++)
44700bf4279Sespie 	    {
44800bf4279Sespie 	      printf ("\t\"%s\"\n", *targs);
44900bf4279Sespie 	    }
45000bf4279Sespie 	  printf ("\n");
45100bf4279Sespie 	}
45200bf4279Sespie       freeargv (argv);
45300bf4279Sespie     }
45400bf4279Sespie 
45537c53322Sespie   return 0;
45600bf4279Sespie }
45700bf4279Sespie 
45800bf4279Sespie #endif	/* MAIN */
459