I've created a new 4.2 Project page for "response files", which is what Microsoft calls files that contain command-line options. Conventionally, if you pass "@file" as an argument to a program, the file is read, and the contents are treated as command-line options. On systems with small command-line buffers, this is a must-have feature.
This is clearly not Stage 3 material. I'm posting it now in the hopes that any issues can be resolved in advance of 4.2 Stage 1. Also, because this patch comes from a 3.4 toolchain, I know there are a few updates (like using XRESIZEVEC) that should be made before committing to mainline. And, as penance for posting new features in Stage 3, I'm committing to fixing some C++ bugs before bedtime. -- Mark Mitchell CodeSourcery, LLC [EMAIL PROTECTED] 2005-08-24 Mark Mitchell <[EMAIL PROTECTED]> * include/libiberty.h (expandargv): New function. * libiberty/argv.c (safe-ctype.h): Include it. (ISBLANK): Remove. (stdio.h): Include. (expandargv): New function. * libiberty/Makefile.in: Regenerated. * gcc/gcc.c (main): Use expandargv. * gcc/doc/invoke.texi: Describe "@file" option. Index: include/libiberty.h =================================================================== RCS file: /cvs/gcc/gcc/include/libiberty.h,v retrieving revision 1.35.10.1 diff -c -5 -p -r1.35.10.1 libiberty.h *** include/libiberty.h 23 Dec 2003 17:25:29 -0000 1.35.10.1 --- include/libiberty.h 25 Aug 2005 03:31:49 -0000 *************** 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 const char *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/gcc/gcc/libiberty/argv.c,v retrieving revision 1.13 diff -c -5 -p -r1.13 argv.c *** libiberty/argv.c 15 Apr 2003 20:36:33 -0000 1.13 --- libiberty/argv.c 25 Aug 2005 03:31:49 -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) *** 302,311 **** --- 303,457 ---- while (*input != EOS); } return (argv); } + /* + + @deftypefn Extension const char* expandargv (int [EMAIL PROTECTED], char [EMAIL PROTECTED]) + + 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}. + + If the value returned is not @code{NULL}, then it is the name of a + response file that could not be read. + + @end deftypefn + + */ + + const char * + expandargv (argcp, argvp) + int *argcp; + char ***argvp; + { + /* A dynamically allocated buffer used to hold options read from a + response file. NULL until needed. */ + char *buffer = NULL; + /* The number of bytes in BUFFER. */ + size_t buffer_len = 0; + /* Dynamically allocated storage for the options read from the + response file. NULL until needed. */ + char **file_options = NULL; + /* The number of slots in the FILE_OPTIONS array. */ + size_t file_options_len = 0; + /* If non-NULL, the name of the response file that caused a + failure. */ + const char *error_file = NULL; + /* 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 options read from the response file, if any. */ + size_t num_options; + + /* We are only interested in options of the form "@file". */ + filename = (*argvp)[i]; + if (filename[0] != '@') + continue; + + /* Open the file. */ + f = fopen (++filename, "r"); + if (!f) + { + error_file = filename; + goto done; + } + + /* Read all the options. */ + num_options = 0; + while (1) + { + /* The insertion point in BUFFER. */ + size_t buffer_pos = 0; + /* The character immediately following the option in + BUFFER. */ + int c; + /* Read the next option from the file. */ + while (1) + { + if (buffer_pos + 32 > buffer_len) + { + buffer_len = buffer_len ? 2 * buffer_len : 32; + buffer = (char *) xrealloc (buffer, buffer_len); + } + c = fscanf (f, "%31s", buffer + buffer_pos); + if (c == EOF) + break; + /* If the next character in the file is not whitespace, + then we didn't yet read the entire argument. */ + c = getc (f); + if (c == EOF || ISSPACE (c)) + break; + /* Put back the character at which we peeked. */ + ungetc (c, f); + buffer_pos += 31; + } + if (c == EOF) + break; + /* Insert the option into FILE_OPTIONS. */ + if (num_options == file_options_len) + { + file_options_len = file_options_len ? 2 * file_options_len : 32; + file_options + = (char **) xrealloc (file_options, + file_options_len * sizeof (char *)); + } + file_options[num_options++] = xstrdup(buffer); + } + + /* We're done with the file now. */ + fclose (f); + /* Insert all the options into ARGV. */ + 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); + } + /* The "+1" below handles the NULL terminator at the end of ARGV. */ + *argvp = ((char **) + xrealloc (*argvp, + (*argcp + num_options + 1) * sizeof (char *))); + memmove (*argvp + i + num_options, *argvp + i + 1, + (*argcp - i) * sizeof (char *)); + memcpy (*argvp + i, file_options, num_options * sizeof (char *)); + /* The original option has been replaced by all the new + options. */ + *argcp += num_options - 1; + } + + done: + if (buffer) + free (buffer); + if (file_options) + free (file_options); + + return error_file; + } + #ifdef MAIN /* Simple little test driver. */ static const char *const tests[] = Index: libiberty/Makefile.in =================================================================== RCS file: /cvs/gcc/gcc/libiberty/Makefile.in,v retrieving revision 1.93.8.2 diff -c -5 -p -r1.93.8.2 Makefile.in *** libiberty/Makefile.in 3 Mar 2004 16:05:26 -0000 1.93.8.2 --- libiberty/Makefile.in 25 Aug 2005 03:37:55 -0000 *************** $(CONFIGURED_OFILES): stamp-picdir *** 415,425 **** # The dependencies in the remainder of this file are automatically # generated by "make maint-deps". Manual edits will be lost. _doprnt.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h alloca.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h ! argv.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h asprintf.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h atexit.o: config.h basename.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ $(INCDIR)/safe-ctype.h bsearch.o: config.h $(INCDIR)/ansidecl.h --- 415,426 ---- # The dependencies in the remainder of this file are automatically # generated by "make maint-deps". Manual edits will be lost. _doprnt.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h alloca.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h ! argv.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ ! $(INCDIR)/safe-ctype.h asprintf.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h atexit.o: config.h basename.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ $(INCDIR)/safe-ctype.h bsearch.o: config.h $(INCDIR)/ansidecl.h Index: gcc/gcc.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/gcc.c,v retrieving revision 1.395.2.10 diff -c -5 -p -r1.395.2.10 gcc.c *** gcc/gcc.c 27 Jul 2005 20:27:14 -0000 1.395.2.10 --- gcc/gcc.c 25 Aug 2005 03:31:49 -0000 *************** main (int argc, const char **argv) *** 5990,5999 **** --- 5990,6005 ---- /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will receive the signal. A different setting is inheritable */ signal (SIGCHLD, SIG_DFL); #endif + { + const char *response_file = expandargv (&argc, &argv); + if (response_file) + pfatal_with_name (response_file); + } + /* Allocate the argument vector. */ alloc_args (); obstack_init (&obstack); Index: gcc/doc/invoke.texi =================================================================== RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v retrieving revision 1.356.2.18 diff -c -5 -p -r1.356.2.18 invoke.texi *** gcc/doc/invoke.texi 27 Jul 2005 20:27:16 -0000 1.356.2.18 --- gcc/doc/invoke.texi 25 Aug 2005 03:31:49 -0000 *************** in the following sections. *** 154,164 **** @table @emph @item Overall Options @xref{Overall Options,,Options Controlling the Kind of Output}. @gccoptlist{-c -S -E -o @var{file} -pipe -pass-exit-codes @gol ! -x @var{language} -v -### --help --target-help --version} @item C Language Options @xref{C Dialect Options,,Options Controlling C Dialect}. @gccoptlist{-ansi [EMAIL PROTECTED] -aux-info @var{filename} @gol -fno-asm -fno-builtin [EMAIL PROTECTED] @gol --- 154,164 ---- @table @emph @item Overall Options @xref{Overall Options,,Options Controlling the Kind of Output}. @gccoptlist{-c -S -E -o @var{file} -pipe -pass-exit-codes @gol ! -x @var{language} -v -### --help --target-help --version @@@var{file} } @item C Language Options @xref{C Dialect Options,,Options Controlling C Dialect}. @gccoptlist{-ansi [EMAIL PROTECTED] -aux-info @var{filename} @gol -fno-asm -fno-builtin [EMAIL PROTECTED] @gol *************** Print (on the standard output) a descrip *** 931,940 **** --- 931,948 ---- line options for each tool. @item --version @opindex version Display the version number and copyrights of the invoked GCC. + + @item @@@var{file} + @opindex @@ + Read command-line options from @var{file}. The content of the + @var{file} is separated into whitespace-separated strings. Each + string is treated as a command-line option. The options read from the + file are inserted in place of the @@@var{file} option. + @end table @node Invoking G++ @section Compiling C++ Programs