+2006-04-11 Jim Blandy <jimb@codesourcery.com>
+
+ * libiberty.h (pex_input_file, pex_input_pipe): New declarations.
+
2006-01-18 DJ Delorie <dj@redhat.com>
* md5.h: Include ansidecl.h
const char *outname, const char *errname,
int *err);
+/* Return a `FILE' pointer FP for the standard input of the first
+ program in the pipeline; FP is opened for writing. You must have
+ passed `PEX_USE_PIPES' to the `pex_init' call that returned OBJ.
+ You must close FP yourself with `fclose' to indicate that the
+ pipeline's input is complete.
+
+ The file descriptor underlying FP is marked not to be inherited by
+ child processes.
+
+ This call is not supported on systems which do not support pipes;
+ it returns with an error. (We could implement it by writing a
+ temporary file, but then you would need to write all your data and
+ close FP before your first call to `pex_run' -- and that wouldn't
+ work on systems that do support pipes: the pipe would fill up, and
+ you would block. So there isn't any easy way to conceal the
+ differences between the two types of systems.)
+
+ If you call both `pex_write_input' and `pex_read_output', be
+ careful to avoid deadlock. If the output pipe fills up, so that
+ each program in the pipeline is waiting for the next to read more
+ data, and you fill the input pipe by writing more data to FP, then
+ there is no way to make progress: the only process that could read
+ data from the output pipe is you, but you are blocked on the input
+ pipe. */
+
+extern FILE *pex_write_input (struct pex_obj *obj, int binary);
+
+/* Return a stream for a temporary file to pass to the first program
+ in the pipeline as input. The file name is chosen as for pex_run.
+ pex_run closes the file automatically; don't close it yourself. */
+
+extern FILE *pex_input_file (struct pex_obj *obj, int flags,
+ const char *in_name);
+
+/* Return a stream for a pipe connected to the standard input of the
+ first program in the pipeline. You must have passed
+ `PEX_USE_PIPES' to `pex_init'. Close the returned stream
+ yourself. */
+
+extern FILE *pex_input_pipe (struct pex_obj *obj, int binary);
+
/* Read the standard output of the last program to be executed.
pex_run can not be called after this. BINARY should be non-zero if
the file should be opened in binary mode; this is ignored on Unix.
+2006-03-29 Jim Blandy <jimb@codesourcery.com>
+
+ * pex-common.c (pex_input_file, pex_input_pipe): New functions.
+ (pex_init_common): Initialize obj->input_file.
+ (pex_run): Close any file opened by pex_input_file.
+ * pexecute.txh (pex_input_file, pex_input_pipe): New docs.
+ * pex-common.h (struct pex_obj): New field input_file.
+ (struct pex_funcs): New function ptr fdopenw.
+ * pex-unix.c (pex_unix_fdopenw): New function.
+ (funcs): List it as our fdopenw function.
+ * pex-win32.c (pex_win32_fdopenw): New function.
+ (funcs): List it as our fdopenw function.
+ * pex-djgpp.c (funcs): Leave fdopenw null.
+ * pex-msdos (funcs): Same.
+ * functions.texi: Regenerated.
+
2006-04-10 Jim Blandy <jimb@codesourcery.com>
* pex-common.c (temp_file): New function, containing guts of
@end deftypefn
-@c pexecute.txh:169
+@c pexecute.txh:231
@deftypefn Extension void pex_free (struct pex_obj @var{obj})
Clean up and free all data associated with @var{obj}.
@end deftypefn
-@c pexecute.txh:144
+@c pexecute.txh:206
@deftypefn Extension int pex_get_status (struct pex_obj *@var{obj}, int @var{count}, int *@var{vector})
Returns the exit status of all programs run using @var{obj}.
@end deftypefn
-@c pexecute.txh:153
+@c pexecute.txh:215
@deftypefn Extension int pex_get_times (struct pex_obj *@var{obj}, int @var{count}, struct pex_time *@var{vector})
Returns the process execution times of all programs run using
@end deftypefn
-@c pexecute.txh:1
+@c pexecute.txh:2
@deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase})
Prepare to execute one or more programs, with standard output of each
@end deftypefn
-@c pexecute.txh:175
+@c pexecute.txh:133
+@deftypefn Extension {FILE *} pex_input_file (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{in_name})
+
+Return a stream for a temporary file to pass to the first program in
+the pipeline as input.
+
+The name of the input file is chosen according to the same rules
+@code{pex_run} uses to choose output file names, based on
+@var{in_name}, @var{obj} and the @code{PEX_SUFFIX} bit in @var{flags}.
+
+Don't call @code{fclose} on the returned stream; the first call to
+@code{pex_run} closes it automatically.
+
+If @var{flags} includes @code{PEX_BINARY_OUTPUT}, open the stream in
+binary mode; otherwise, open it in the default mode. Including
+@code{PEX_BINARY_OUTPUT} in @var{flags} has no effect on Unix.
+@end deftypefn
+
+@c pexecute.txh:150
+@deftypefn Extension {FILE *} pex_input_pipe (struct pex_obj *@var{obj}, int @var{binary})
+
+Return a stream @var{fp} for a pipe connected to the standard input of
+the first program in the pipeline; @var{fp} is opened for writing.
+You must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call
+that returned @var{obj}.
+
+You must close @var{fp} using @code{fclose} yourself when you have
+finished writing data to the pipeline.
+
+The file descriptor underlying @var{fp} is marked not to be inherited
+by child processes.
+
+On systems that do not support pipes, this function returns
+@code{NULL}, and sets @code{errno} to @code{EINVAL}. If you would
+like to write code that is portable to all systems the @code{pex}
+functions support, consider using @code{pex_input_file} instead.
+
+There are two opportunities for deadlock using
+@code{pex_input_pipe}:
+
+@itemize @bullet
+@item
+Most systems' pipes can buffer only a fixed amount of data; a process
+that writes to a full pipe blocks. Thus, if you write to @file{fp}
+before starting the first process, you run the risk of blocking when
+there is no child process yet to read the data and allow you to
+continue. @code{pex_input_pipe} makes no promises about the
+size of the pipe's buffer, so if you need to write any data at all
+before starting the first process in the pipeline, consider using
+@code{pex_input_file} instead.
+
+@item
+Using @code{pex_input_pipe} and @code{pex_read_output} together
+may also cause deadlock. If the output pipe fills up, so that each
+program in the pipeline is waiting for the next to read more data, and
+you fill the input pipe by writing more data to @var{fp}, then there
+is no way to make progress: the only process that could read data from
+the output pipe is you, but you are blocked on the input pipe.
+
+@end itemize
+
+@end deftypefn
+
+@c pexecute.txh:237
@deftypefn Extension {const char *} pex_one (int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{pname}, const char *@var{outname}, const char *@var{errname}, int *@var{status}, int *@var{err})
An interface to permit the easy execution of a
@end deftypefn
-@c pexecute.txh:132
+@c pexecute.txh:194
@deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
Returns a @code{FILE} pointer which may be used to read the standard
@end deftypefn
-@c pexecute.txh:32
+@c pexecute.txh:33
@deftypefn Extension {const char *} pex_run (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
Execute one program in a pipeline. On success this returns
@end deftypefn
-@c pexecute.txh:187
+@c pexecute.txh:249
@deftypefn Extension int pexecute (const char *@var{program}, char * const *@var{argv}, const char *@var{this_pname}, const char *@var{temp_base}, char **@var{errmsg_fmt}, char **@var{errmsg_arg}, int flags)
This is the old interface to execute one or more programs. It is
@end deftypefn
-@c pexecute.txh:195
+@c pexecute.txh:257
@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
Another part of the old execution interface.
obj->status = NULL;
obj->time = NULL;
obj->number_waited = 0;
+ obj->input_file = NULL;
obj->read_output = NULL;
obj->remove_count = 0;
obj->remove = NULL;
outname = (char *) orig_outname;
outname_allocated = 0;
+ /* If the user called pex_input_file, close the file now. */
+ if (obj->input_file)
+ {
+ if (fclose (obj->input_file) == EOF)
+ {
+ errmsg = "closing pipeline input file";
+ goto error_exit;
+ }
+ obj->input_file = NULL;
+ }
+
/* Set IN. */
if (obj->next_input_name != NULL)
return errmsg;
}
+/* Return a FILE pointer for a temporary file to fill with input for
+ the pipeline. */
+FILE *
+pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
+{
+ char *name = (char *) in_name;
+ FILE *f;
+
+ /* This must be called before the first pipeline stage is run, and
+ there must not have been any other input selected. */
+ if (obj->count != 0
+ || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ || obj->next_input_name)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ name = temp_file (obj, flags, name);
+ if (! name)
+ return NULL;
+
+ f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
+ if (! f)
+ {
+ free (name);
+ return NULL;
+ }
+
+ obj->input_file = f;
+ obj->next_input_name = name;
+ obj->next_input_name_allocated = (name != in_name);
+
+ return f;
+}
+
+/* Return a stream for a pipe connected to the standard input of the
+ first stage of the pipeline. */
+FILE *
+pex_input_pipe (struct pex_obj *obj, int binary)
+{
+ int p[2];
+ FILE *f;
+
+ /* You must call pex_input_pipe before the first pex_run or pex_one. */
+ if (obj->count > 0)
+ goto usage_error;
+
+ /* You must be using pipes. Implementations that don't support
+ pipes clear this flag before calling pex_init_common. */
+ if (! (obj->flags & PEX_USE_PIPES))
+ goto usage_error;
+
+ /* If we have somehow already selected other input, that's a
+ mistake. */
+ if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ || obj->next_input_name)
+ goto usage_error;
+
+ if (obj->funcs->pipe (obj, p, binary != 0) < 0)
+ return NULL;
+
+ f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
+ if (! f)
+ {
+ int saved_errno = errno;
+ obj->funcs->close (obj, p[READ_PORT]);
+ obj->funcs->close (obj, p[WRITE_PORT]);
+ errno = saved_errno;
+ return NULL;
+ }
+
+ obj->next_input = p[READ_PORT];
+
+ return f;
+
+ usage_error:
+ errno = EINVAL;
+ return NULL;
+}
+
/* Return a FILE pointer for the output of the last program
executed. */
struct pex_time *time;
/* Number of children we have already waited for. */
int number_waited;
+ /* FILE created by pex_input_file. */
+ FILE *input_file;
/* FILE created by pex_read_output. */
FILE *read_output;
/* Number of temporary files to remove. */
PEX_USE_PIPES is set). If BINARY is non-zero, open in binary
mode. Return pointer on success, NULL on error. */
FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */);
+ /* Get a FILE pointer to write to the file descriptor FD (only
+ called if PEX_USE_PIPES is set). If BINARY is non-zero, open in
+ binary mode. Arrange for FD not to be inherited by the child
+ processes. Return pointer on success, NULL on error. */
+ FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */);
/* Free any system dependent data associated with OBJ. May be
NULL if there is nothing to do. */
void (*cleanup) (struct pex_obj *);
pex_djgpp_wait,
NULL, /* pipe */
NULL, /* fdopenr */
+ NULL, /* fdopenw */
NULL /* cleanup */
};
pex_msdos_wait,
NULL, /* pipe */
NULL, /* fdopenr */
+ NULL, /* fdopenw */
pex_msdos_cleanup
};
int, const char **, int *);
static int pex_unix_pipe (struct pex_obj *, int *, int);
static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
static void pex_unix_cleanup (struct pex_obj *);
/* The list of functions we pass to the common routines. */
pex_unix_wait,
pex_unix_pipe,
pex_unix_fdopenr,
+ pex_unix_fdopenw,
pex_unix_cleanup
};
return fdopen (fd, "r");
}
+static FILE *
+pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary ATTRIBUTE_UNUSED)
+{
+ if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
+ return NULL;
+ return fdopen (fd, "w");
+}
+
static void
pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
{
struct pex_time *, int, const char **, int *);
static int pex_win32_pipe (struct pex_obj *, int *, int);
static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
/* The list of functions we pass to the common routines. */
pex_win32_wait,
pex_win32_pipe,
pex_win32_fdopenr,
+ pex_win32_fdopenw,
NULL /* cleanup */
};
return fdopen (fd, binary ? "rb" : "r");
}
+static FILE *
+pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+ return NULL;
+ return fdopen (fd, binary ? "wb" : "w");
+}
+
#ifdef MAIN
#include <stdio.h>
+@c -*- mode: texinfo -*-
@deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase})
Prepare to execute one or more programs, with standard output of each
@end deftypefn
+@deftypefn Extension {FILE *} pex_input_file (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{in_name})
+
+Return a stream for a temporary file to pass to the first program in
+the pipeline as input.
+
+The name of the input file is chosen according to the same rules
+@code{pex_run} uses to choose output file names, based on
+@var{in_name}, @var{obj} and the @code{PEX_SUFFIX} bit in @var{flags}.
+
+Don't call @code{fclose} on the returned stream; the first call to
+@code{pex_run} closes it automatically.
+
+If @var{flags} includes @code{PEX_BINARY_OUTPUT}, open the stream in
+binary mode; otherwise, open it in the default mode. Including
+@code{PEX_BINARY_OUTPUT} in @var{flags} has no effect on Unix.
+@end deftypefn
+
+@deftypefn Extension {FILE *} pex_input_pipe (struct pex_obj *@var{obj}, int @var{binary})
+
+Return a stream @var{fp} for a pipe connected to the standard input of
+the first program in the pipeline; @var{fp} is opened for writing.
+You must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call
+that returned @var{obj}.
+
+You must close @var{fp} using @code{fclose} yourself when you have
+finished writing data to the pipeline.
+
+The file descriptor underlying @var{fp} is marked not to be inherited
+by child processes.
+
+On systems that do not support pipes, this function returns
+@code{NULL}, and sets @code{errno} to @code{EINVAL}. If you would
+like to write code that is portable to all systems the @code{pex}
+functions support, consider using @code{pex_input_file} instead.
+
+There are two opportunities for deadlock using
+@code{pex_input_pipe}:
+
+@itemize @bullet
+@item
+Most systems' pipes can buffer only a fixed amount of data; a process
+that writes to a full pipe blocks. Thus, if you write to @file{fp}
+before starting the first process, you run the risk of blocking when
+there is no child process yet to read the data and allow you to
+continue. @code{pex_input_pipe} makes no promises about the
+size of the pipe's buffer, so if you need to write any data at all
+before starting the first process in the pipeline, consider using
+@code{pex_input_file} instead.
+
+@item
+Using @code{pex_input_pipe} and @code{pex_read_output} together
+may also cause deadlock. If the output pipe fills up, so that each
+program in the pipeline is waiting for the next to read more data, and
+you fill the input pipe by writing more data to @var{fp}, then there
+is no way to make progress: the only process that could read data from
+the output pipe is you, but you are blocked on the input pipe.
+
+@end itemize
+
+@end deftypefn
+
@deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
Returns a @code{FILE} pointer which may be used to read the standard