/*
+@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@var{file})
+
+Write each member of ARGV, handling all necessary quoting, to the file
+named by FILE, separated by whitespace. Return 0 on success, non-zero
+if an error occurred while writing to FILE.
+
+@end deftypefn
+
+*/
+
+int
+writeargv (char **argv, FILE *f)
+{
+ int status = 0;
+
+ if (f == NULL)
+ return 1;
+
+ while (*argv != NULL)
+ {
+ const char *arg = *argv;
+
+ while (*arg != EOS)
+ {
+ char c = *arg;
+
+ if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
+ if (EOF == fputc ('\\', f))
+ {
+ status = 1;
+ goto done;
+ }
+
+ if (EOF == fputc (c, f))
+ {
+ status = 1;
+ goto done;
+ }
+ arg++;
+ }
+
+ if (EOF == fputc ('\n', f))
+ {
+ status = 1;
+ goto done;
+ }
+ argv++;
+ }
+
+ done:
+ return status;
+}
+
+/*
+
@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
The @var{argcp} and @code{argvp} arguments are pointers to the usual
*/
void
-expandargv (argcp, argvp)
- int *argcp;
- char ***argvp;
+expandargv (int *argcp, char ***argvp)
{
/* The argument we are currently processing. */
int i = 0;
const char *filename;
/* The response file. */
FILE *f;
- /* The number of characters in the response file. */
+ /* An upper bound on the number of characters in the response
+ file. */
long pos;
+ /* The number of characters in the response file, when actually
+ read. */
+ size_t len;
/* A dynamically allocated buffer used to hold options read from a
response file. */
char *buffer;
response file. */
char **file_argv;
/* The number of options read from the response file, if any. */
- size_t file_argc;
+ size_t file_argc;
/* We are only interested in options of the form "@file". */
filename = (*argvp)[i];
if (filename[0] != '@')
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)
+ len = fread (buffer, sizeof (char), pos, f);
+ if (len != (size_t) pos
+ /* On Windows, fread may return a value smaller than POS,
+ due to CR/LF->CR translation when reading text files.
+ That does not in-and-of itself indicate failure. */
+ && ferror (f))
goto error;
/* Add a NUL terminator. */
- buffer[pos] = '\0';
+ buffer[len] = '\0';
/* Parse the string. */
file_argv = buildargv (buffer);
/* If *ARGVP is not already dynamically allocated, copy it. */
{
*argvp = dupargv (*argvp);
if (!*argvp)
- /* We do not know exactly many bytes dupargv tried to
- allocate, so make a guess. */
- xmalloc_failed (*argcp * 32);
+ {
+ fputs ("\nout of memory\n", stderr);
+ xexit (1);
+ }
}
/* Count the number of arguments. */
file_argc = 0;