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