Revised response-file patch

Mark Mitchell mark@codesourcery.com
Fri Sep 23 20:52:00 GMT 2005


DJ --

Here's a revised version of the "response file", aka "@-file" patch.

I believe I've addressed your key concerns.  

The expandargv function no longer returns a value; it just silently
treats "@foo" as literal if "foo" cannot be opened or read.

We also now use the existing libiberty buildargv function, which turns
a string into argv.  So, the details of quoting, etc., are almost as
per existing libiberty semantics.  The one gotcha was that buildargv
was using ISBLANK, and, as such, treating newlines as part of
arguments, even with no quoting.  That seemed contrary to its
documentation, and certainly contrary to what people want from
response files, so I changed it to use ISSPACE.

I tested this patch on GNU/Linux and on MinGW.  On MinGW, I tried both
DOS text and UNIX text response files.

Thanks to Danny Smith for helping me find a bug in an earlier version
of this patch; of course, any remaining errors are mine along.

OK to apply?

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2005-09-23  Mark Mitchell  <mark@codesourcery.com>

	* libiberty.h (expandargv): New function.

2005-09-23  Mark Mitchell  <mark@codesourcery.com>

	* argv.c (safe-ctype.h): Include it.
	(ISBLANK): Remove.
	(stdio.h): Include.
	(buildargv): Use ISSPACE, not ISBLANK.
	(expandargv): New function.
	* Makefile.in: Regenerated.

Index: include/libiberty.h
===================================================================
RCS file: /cvs/src/src/include/libiberty.h,v
retrieving revision 1.30
retrieving revision 1.30.6.1
diff -c -5 -p -r1.30 -r1.30.6.1
*** include/libiberty.h	1 Mar 2005 14:32:34 -0000	1.30
--- include/libiberty.h	30 Aug 2005 19:57:33 -0000	1.30.6.1
*************** extern void freeargv PARAMS ((char **));
*** 60,69 ****
--- 60,72 ----
  /* Duplicate an argument vector. Allocates memory using malloc.  Use
     freeargv to free the vector.  */
  
  extern char **dupargv PARAMS ((char **)) ATTRIBUTE_MALLOC;
  
+ /* Expand "@file" arguments in argv.  */
+ 
+ extern void expandargv PARAMS ((int *, char ***));
  
  /* Return the last component of a path name.  Note that we can't use a
     prototype here because the parameter is declared inconsistently
     across different systems, sometimes as "char *" and sometimes as
     "const char *" */
Index: libiberty/argv.c
===================================================================
RCS file: /cvs/src/src/libiberty/argv.c,v
retrieving revision 1.9
diff -c -5 -p -r1.9 argv.c
*** libiberty/argv.c	15 Apr 2003 21:29:34 -0000	1.9
--- libiberty/argv.c	23 Sep 2005 20:30:39 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 22,33 ****
  /*  Create and destroy argument vectors.  An argument vector is simply an
      array of string pointers, terminated by a NULL pointer. */
  
  #include "ansidecl.h"
  #include "libiberty.h"
  
! #define ISBLANK(ch) ((ch) == ' ' || (ch) == '\t')
  
  /*  Routines imported from standard C runtime libraries. */
  
  #ifdef ANSI_PROTOTYPES
  
--- 22,34 ----
  /*  Create and destroy argument vectors.  An argument vector is simply an
      array of string pointers, terminated by a NULL pointer. */
  
  #include "ansidecl.h"
  #include "libiberty.h"
+ #include "safe-ctype.h"
  
! #include <stdio.h>
  
  /*  Routines imported from standard C runtime libraries. */
  
  #ifdef ANSI_PROTOTYPES
  
*************** char **buildargv (input)
*** 226,236 ****
  	    }
  	  /* Begin scanning arg */
  	  arg = copybuf;
  	  while (*input != EOS)
  	    {
! 	      if (ISBLANK (*input) && !squote && !dquote && !bsquote)
  		{
  		  break;
  		}
  	      else
  		{
--- 227,237 ----
  	    }
  	  /* Begin scanning arg */
  	  arg = copybuf;
  	  while (*input != EOS)
  	    {
! 	      if (ISSPACE (*input) && !squote && !dquote && !bsquote)
  		{
  		  break;
  		}
  	      else
  		{
*************** char **buildargv (input)
*** 292,311 ****
  	      break;
  	    }
  	  argc++;
  	  argv[argc] = NULL;
  
! 	  while (ISBLANK (*input))
  	    {
  	      input++;
  	    }
  	}
        while (*input != EOS);
      }
    return (argv);
  }
  
  #ifdef MAIN
  
  /* Simple little test driver. */
  
  static const char *const tests[] =
--- 293,417 ----
  	      break;
  	    }
  	  argc++;
  	  argv[argc] = NULL;
  
! 	  while (ISSPACE (*input))
  	    {
  	      input++;
  	    }
  	}
        while (*input != EOS);
      }
    return (argv);
  }
  
+ /*
+ 
+ @deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
+ 
+ The @var{argcp} and @code{argvp} arguments are pointers to the usual
+ @code{argc} and @code{argv} arguments to @code{main}.  This function
+ looks for arguments that begin with the character @samp{@@}.  Any such
+ arguments are interpreted as ``response files''.  The contents of the
+ response file are interpreted as additional command line options.  In
+ particular, the file is separated into whitespace-separated strings;
+ each such string is taken as a command-line option.  The new options
+ are inserted in place of the option naming the response file, and
+ @code{*argcp} and @code{*argvp} will be updated.  If the value of
+ @code{*argvp} is modified by this function, then the new value has
+ been dynamically allocated and should be deallocated by the caller
+ with @code{freeargv}.
+ 
+ @end deftypefn
+ 
+ */
+ 
+ void
+ expandargv (argcp, argvp)
+      int *argcp;
+      char ***argvp;
+ {
+   /* The argument we are currently processing.  */
+   int i = 0;
+   /* Non-zero if ***argvp has been dynamically allocated.  */
+   int argv_dynamic = 0;
+   /* Loop over the arguments, handling response files.  We always skip
+      ARGVP[0], as that is the name of the program being run.  */
+   while (++i < *argcp)
+     {
+       /* The name of the response file.  */
+       const char *filename;
+       /* The response file.  */
+       FILE *f;
+       /* The number of characters in the response file.  */
+       long pos;
+       /* A dynamically allocated buffer used to hold options read from a
+ 	 response file.  */
+       char *buffer;
+       /* Dynamically allocated storage for the options read from the
+ 	 response file.  */
+       char **file_argv;
+       /* The number of options read from the response file, if any.  */
+      size_t file_argc;
+       /* We are only interested in options of the form "@file".  */
+       filename = (*argvp)[i];
+       if (filename[0] != '@')
+ 	continue;
+       /* Read the contents of the file.  */
+       f = fopen (++filename, "r");
+       if (!f)
+ 	continue;
+       if (fseek (f, 0L, SEEK_END) == -1)
+ 	goto error;
+       pos = ftell (f);
+       if (pos == -1)
+ 	goto error;
+       if (fseek (f, 0L, SEEK_SET) == -1)
+ 	goto error;
+       buffer = (char *) xmalloc (pos * sizeof (char) + 1);
+       if (fread (buffer, sizeof (char), pos, f) != (size_t) pos)
+ 	goto error;
+       /* Add a NUL terminator.  */
+       buffer[pos] = '\0';
+       /* Parse the string.  */
+       file_argv = buildargv (buffer);
+       /* If *ARGVP is not already dynamically allocated, copy it.  */
+       if (!argv_dynamic)
+ 	{
+ 	  *argvp = dupargv (*argvp);
+ 	  if (!*argvp)
+ 	    /* We do not know exactly many bytes dupargv tried to
+ 	       allocate, so make a guess.  */
+ 	    xmalloc_failed (*argcp * 32);
+ 	}
+       /* Count the number of arguments.  */
+       file_argc = 0;
+       while (file_argv[file_argc] && *file_argv[file_argc])
+ 	++file_argc;
+       /* Now, insert FILE_ARGV into ARGV.  The "+1" below handles the
+ 	 NULL terminator at the end of ARGV.  */ 
+       *argvp = ((char **) 
+ 		xrealloc (*argvp, 
+ 			  (*argcp + file_argc + 1) * sizeof (char *)));
+       memmove (*argvp + i + file_argc, *argvp + i + 1, 
+ 	       (*argcp - i) * sizeof (char *));
+       memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
+       /* The original option has been replaced by all the new
+ 	 options.  */
+       *argcp += file_argc - 1;
+       /* Free up memory allocated to process the response file.  We do
+ 	 not use freeargv because the individual options in FILE_ARGV
+ 	 are now in the main ARGV.  */
+       free (file_argv);
+       free (buffer);
+     error:
+       /* We're all done with the file now.  */
+       fclose (f);
+     }
+ }
+ 
  #ifdef MAIN
  
  /* Simple little test driver. */
  
  static const char *const tests[] =



More information about the Gcc-patches mailing list