diff options
-rw-r--r-- | include/ChangeLog | 4 | ||||
-rw-r--r-- | include/libiberty.h | 3 | ||||
-rw-r--r-- | libiberty/ChangeLog | 8 | ||||
-rw-r--r-- | libiberty/Makefile.in | 9 | ||||
-rw-r--r-- | libiberty/argv.c | 118 |
5 files changed, 134 insertions, 8 deletions
diff --git a/include/ChangeLog b/include/ChangeLog index c0c22b548c2..bdd47bb98c2 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2005-09-26 Mark Mitchell <mark@codesourcery.com> + + * libiberty.h (expandargv): New function. + 2005-08-17 Mark Kettenis <kettenis@gnu.org> * floatformat.h (struct floatformat): Change type of large diff --git a/include/libiberty.h b/include/libiberty.h index 6fb5e19ccd5..c264cb2ab0e 100644 --- a/include/libiberty.h +++ b/include/libiberty.h @@ -82,6 +82,9 @@ extern void freeargv (char **); extern char **dupargv (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 diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 4cf1a404b11..bf64ee9da92 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,11 @@ +2005-09-26 Mark Mitchell <mark@codesourcery.com> + + * argv.c (safe-ctype.h): Include it. + (ISBLANK): Remove. + (stdio.h): Include. + (buildargv): Use ISSPACE instead of ISBLANK. + (expandargv): New function. + 2005-09-14 Christopher Faylor <cgf@timesys.com> * pex-win32.c: Include "windows.h". diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in index eb8b6df099a..dcd5ebd86d1 100644 --- a/libiberty/Makefile.in +++ b/libiberty/Makefile.in @@ -441,7 +441,8 @@ $(CONFIGURED_OFILES): stamp-picdir else true; fi $(COMPILE.c) $(srcdir)/alloca.c $(OUTPUT_OPTION) -./argv.o: $(srcdir)/argv.c config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h +./argv.o: $(srcdir)/argv.c config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ + $(INCDIR)/safe-ctype.h if [ x"$(PICFLAG)" != x ]; then \ $(COMPILE.c) $(PICFLAG) $(srcdir)/argv.c -o pic/$@; \ else true; fi @@ -601,7 +602,7 @@ $(CONFIGURED_OFILES): stamp-picdir else true; fi $(COMPILE.c) $(srcdir)/getcwd.c $(OUTPUT_OPTION) -./getopt.o: $(srcdir)/getopt.c config.h $(INCDIR)/getopt.h +./getopt.o: $(srcdir)/getopt.c config.h $(INCDIR)/ansidecl.h $(INCDIR)/getopt.h if [ x"$(PICFLAG)" != x ]; then \ $(COMPILE.c) $(PICFLAG) $(srcdir)/getopt.c -o pic/$@; \ else true; fi @@ -996,8 +997,8 @@ $(CONFIGURED_OFILES): stamp-picdir else true; fi $(COMPILE.c) $(srcdir)/strtoul.c $(OUTPUT_OPTION) -./strverscmp.o: $(srcdir)/strverscmp.c $(INCDIR)/safe-ctype.h \ - $(INCDIR)/libiberty.h +./strverscmp.o: $(srcdir)/strverscmp.c $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ + $(INCDIR)/safe-ctype.h if [ x"$(PICFLAG)" != x ]; then \ $(COMPILE.c) $(PICFLAG) $(srcdir)/strverscmp.c -o pic/$@; \ else true; fi diff --git a/libiberty/argv.c b/libiberty/argv.c index 7be8e767342..71f164acf7d 100644 --- a/libiberty/argv.c +++ b/libiberty/argv.c @@ -27,14 +27,14 @@ Boston, MA 02110-1301, USA. */ #endif #include "ansidecl.h" #include "libiberty.h" - -#define ISBLANK(ch) ((ch) == ' ' || (ch) == '\t') +#include "safe-ctype.h" /* Routines imported from standard C runtime libraries. */ #include <stddef.h> #include <string.h> #include <stdlib.h> +#include <stdio.h> #ifndef NULL #define NULL 0 @@ -212,7 +212,7 @@ char **buildargv (const char *input) arg = copybuf; while (*input != EOS) { - if (ISBLANK (*input) && !squote && !dquote && !bsquote) + if (ISSPACE (*input) && !squote && !dquote && !bsquote) { break; } @@ -278,7 +278,7 @@ char **buildargv (const char *input) argc++; argv[argc] = NULL; - while (ISBLANK (*input)) + while (ISSPACE (*input)) { input++; } @@ -288,6 +288,116 @@ char **buildargv (const char *input) 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 can be deallocated by the caller with +@code{freeargv}. However, most callers will simply call +@code{expandargv} near the beginning of @code{main} and allow the +operating system to free the memory when the program exits. + +@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); + /* Rescan all of the arguments just read to support response + files that include other response files. */ + --i; + error: + /* We're all done with the file now. */ + fclose (f); + } +} + #ifdef MAIN /* Simple little test driver. */ |