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