const char *outname, const char *errname,
int *err);
+/* As for pex_run (), but takes an extra parameter to enable the
+ environment for the child process to be specified.
+
+ ENV The environment for the child process, specified as
+ an array of character pointers. Each element of the
+ array should point to a string of the form VAR=VALUE,
+ with the exception of the last element which must be
+ a null pointer.
+*/
+
+extern const char *pex_run_in_environment (struct pex_obj *obj, int flags,
+ const char *executable,
+ char * const *argv,
+ char * const *env,
+ 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.
+2006-06-01 Mark Shinwell <shinwell@codesourcery.com>
+
+ * pex-common.c: New function pex_run_in_environment.
+ * pex-common.h: Add environment parameter to exec_child.
+ * pex-msdos.c: Add environment parameter to pex_msdos_exec_child.
+ * pex-djgpp.c: Add environment parameter to pex_djgpp_exec_child.
+ (pex_djgpp_exec_child): Pass environment to child process.
+ * pex-unix.c: Add environment parameter to pex_unix_exec_child.
+ (pex_unix_exec_child): Pass environment to child process.
+ * pex-win32.c: Add environment parameter to pex_win32_exec_child.
+ New function env_compare for comparing VAR=VALUE pairs.
+ (win32_spawn): Assemble environment block and pass to CreateProcess.
+ (spawn_script): Pass environment through to win32_spawn.
+ (pex_win32_exec_child): Pass environment through to spawn_script and
+ win32_spawn.
+ * functions.texi: Regenerate.
+ * pexecute.txh: Document pex_run_in_environment.
+
2006-05-28 Mark Shinwell <shinwell@codesourcery.com>
* mkstemps.c: Open temporary files in binary mode.
@end deftypefn
-@c pexecute.txh:231
+@c pexecute.txh:244
@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:206
+@c pexecute.txh:219
@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:215
+@c pexecute.txh:228
@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:133
+@c pexecute.txh:146
@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
@code{PEX_BINARY_OUTPUT} in @var{flags} has no effect on Unix.
@end deftypefn
-@c pexecute.txh:150
+@c pexecute.txh:163
@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
@end deftypefn
-@c pexecute.txh:237
+@c pexecute.txh:250
@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:194
+@c pexecute.txh:207
@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:249
+@c pexecute.txh:133
+@deftypefn Extension {const char *} pex_run_in_environment (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, char * const *@var{env}, int @var{env_size}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
+
+Execute one program in a pipeline, permitting the environment for the
+program to be specified. Behaviour and parameters not listed below are
+as for @code{pex_run}.
+
+@var{env} is the environment for the child process, specified as an array of
+character pointers. Each element of the array should point to a string of the
+form @code{VAR=VALUE}, with the exception of the last element that must be
+@code{NULL}.
+
+@end deftypefn
+
+@c pexecute.txh:262
@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:257
+@c pexecute.txh:270
@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
Another part of the old execution interface.
return name;
}
-/* Run a program. */
+
+/* As for pex_run (), but permits the environment for the child process
+ to be specified. */
const char *
-pex_run (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, const char *orig_outname, const char *errname,
- int *err)
+pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env,
+ const char *orig_outname, const char *errname,
+ int *err)
{
const char *errmsg;
int in, out, errdes;
/* Run the program. */
- pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes,
- &errmsg, err);
+ pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
+ in, out, errdes, &errmsg, err);
if (pid < 0)
goto error_exit;
return errmsg;
}
+/* Run a program. */
+
+const char *
+pex_run (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, const char *orig_outname, const char *errname,
+ int *err)
+{
+ return pex_run_in_environment (obj, flags, executable, argv, NULL,
+ orig_outname, errname, err);
+}
+
/* Return a FILE pointer for a temporary file to fill with input for
the pipeline. */
FILE *
error and set *ERRMSG and *ERR. */
long (*exec_child) (struct pex_obj *, int /* flags */,
const char */* executable */, char * const * /* argv */,
+ char * const * /* env */,
int /* in */, int /* out */, int /* errdes */,
const char **/* errmsg */, int */* err */);
/* Close a descriptor. Return 0 on success, -1 on error. */
static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
static int pex_djgpp_open_write (struct pex_obj *, const char *, int);
static long pex_djgpp_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
+ char * const *, char * const *,
+ int, int, int,
const char **, int *);
static int pex_djgpp_close (struct pex_obj *, int);
static int pex_djgpp_wait (struct pex_obj *, long, int *, struct pex_time *,
static long
pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, int in, int out, int errdes,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
const char **errmsg, int *err)
{
int org_in, org_out, org_errdes;
}
}
- status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv)
- (P_WAIT, executable, (char * const *) argv));
+ if (env)
+ status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve)
+ (P_WAIT, executable, argv, env));
+ else
+ status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv)
+ (P_WAIT, executable, argv));
if (status == -1)
{
static int pex_msdos_open (struct pex_obj *, const char *, int);
static int pex_msdos_fdindex (struct pex_msdos *, int);
static long pex_msdos_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
- const char **, int *);
+ char * const *, char * const *,
+ int, int, int, const char **, int *);
static int pex_msdos_close (struct pex_obj *, int);
static int pex_msdos_wait (struct pex_obj *, long, int *, struct pex_time *,
int, const char **, int *);
static long
pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, int in, int out,
+ char * const * argv, char * const * env, int in, int out,
int errdes ATTRIBUTE_UNUSED, const char **errmsg,
int *err)
{
static int pex_unix_open_read (struct pex_obj *, const char *, int);
static int pex_unix_open_write (struct pex_obj *, const char *, int);
static long pex_unix_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
- const char **, int *);
+ char * const *, char * const *,
+ int, int, int, const char **, int *);
static int pex_unix_close (struct pex_obj *, int);
static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *,
int, const char **, int *);
/* Execute a child. */
+extern char **environ;
+
static long
pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, int in, int out, int errdes,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
const char **errmsg, int *err)
{
pid_t pid;
+
/* We declare these to be volatile to avoid warnings from gcc about
them being clobbered by vfork. */
volatile int sleep_interval;
if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
pex_child_error (obj, executable, "dup2", errno);
}
+
+ if (env)
+ environ = env;
+
if ((flags & PEX_SEARCH) != 0)
{
execvp (executable, argv);
#include <sys/wait.h>
#endif
+#include <assert.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
+#include <ctype.h>
/* mingw32 headers may not define the following. */
#define MINGW_NAME "Minimalist GNU for Windows"
#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
+extern char *stpcpy (char *dst, const char *src);
+
/* Ensure that the executable pathname uses Win32 backslashes. This
is not necessary on NT, but on W9x, forward slashes causes
failure of spawn* and exec* functions (and probably any function
static int pex_win32_open_read (struct pex_obj *, const char *, int);
static int pex_win32_open_write (struct pex_obj *, const char *, int);
static long pex_win32_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
+ char * const *, char * const *,
+ int, int, int,
const char **, int *);
static int pex_win32_close (struct pex_obj *, int);
static int pex_win32_wait (struct pex_obj *, long, int *,
return full_executable;
}
-/* Low-level process creation function. */
+/* Low-level process creation function and helper. */
+
+static int
+env_compare (const void *a_ptr, const void *b_ptr)
+{
+ const char *a;
+ const char *b;
+ unsigned char c1;
+ unsigned char c2;
+
+ a = *(const char **) a_ptr;
+ b = *(const char **) b_ptr;
+
+ /* a and b will be of the form: VAR=VALUE
+ We compare only the variable name part here using a case-insensitive
+ comparison algorithm. It might appear that in fact strcasecmp () can
+ take the place of this whole function, and indeed it could, save for
+ the fact that it would fail in cases such as comparing A1=foo and
+ A=bar (because 1 is less than = in the ASCII character set).
+ (Environment variables containing no numbers would work in such a
+ scenario.) */
+
+ do
+ {
+ c1 = (unsigned char) tolower (*a++);
+ c2 = (unsigned char) tolower (*b++);
+
+ if (c1 == '=')
+ c1 = '\0';
+
+ if (c2 == '=')
+ c2 = '\0';
+ }
+ while (c1 == c2 && c1 != '\0');
+
+ return c1 - c2;
+}
static long
win32_spawn (const char *executable,
BOOL search,
char *const *argv,
+ char *const *env, /* array of strings of the form: VAR=VALUE */
DWORD dwCreationFlags,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
{
char *full_executable;
char *cmdline;
+ char **env_copy;
+ char *env_block = NULL;
full_executable = NULL;
cmdline = NULL;
+ if (env)
+ {
+ int env_size;
+
+ /* Count the number of environment bindings supplied. */
+ for (env_size = 0; env[env_size]; env_size++)
+ continue;
+
+ /* Assemble an environment block, if required. This consists of
+ VAR=VALUE strings juxtaposed (with one null character between each
+ pair) and an additional null at the end. */
+ if (env_size > 0)
+ {
+ int var;
+ int total_size = 1; /* 1 is for the final null. */
+ char *bufptr;
+
+ /* Windows needs the members of the block to be sorted by variable
+ name. */
+ env_copy = alloca (sizeof (char *) * env_size);
+ memcpy (env_copy, env, sizeof (char *) * env_size);
+ qsort (env_copy, env_size, sizeof (char *), env_compare);
+
+ for (var = 0; var < env_size; var++)
+ total_size += strlen (env[var]) + 1;
+
+ env_block = malloc (total_size);
+ bufptr = env_block;
+ for (var = 0; var < env_size; var++)
+ bufptr = stpcpy (bufptr, env_copy[var]) + 1;
+
+ *bufptr = '\0';
+ }
+ }
+
full_executable = find_executable (executable, search);
if (!full_executable)
goto error;
/*lpThreadAttributes=*/NULL,
/*bInheritHandles=*/TRUE,
dwCreationFlags,
- /*lpEnvironment=*/NULL,
+ (LPVOID) env_block,
/*lpCurrentDirectory=*/NULL,
si,
pi))
{
+ if (env_block)
+ free (env_block);
+
free (full_executable);
+
return -1;
}
/* Clean up. */
CloseHandle (pi->hThread);
free (full_executable);
+ if (env_block)
+ free (env_block);
return (long) pi->hProcess;
error:
+ if (env_block)
+ free (env_block);
if (cmdline)
free (cmdline);
if (full_executable)
free (full_executable);
+
return -1;
}
static long
spawn_script (const char *executable, char *const *argv,
+ char* const *env,
DWORD dwCreationFlags,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
executable = strrchr (executable1, '\\') + 1;
if (!executable)
executable = executable1;
- pid = win32_spawn (executable, TRUE, argv,
+ pid = win32_spawn (executable, TRUE, argv, env,
dwCreationFlags, si, pi);
#else
if (strchr (executable1, '\\') == NULL)
- pid = win32_spawn (executable1, TRUE, argv,
+ pid = win32_spawn (executable1, TRUE, argv, env,
dwCreationFlags, si, pi);
else if (executable1[0] != '\\')
- pid = win32_spawn (executable1, FALSE, argv,
+ pid = win32_spawn (executable1, FALSE, argv, env,
dwCreationFlags, si, pi);
else
{
const char *newex = mingw_rootify (executable1);
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv,
+ pid = win32_spawn (newex, FALSE, argv, env,
dwCreationFlags, si, pi);
if (executable1 != newex)
free ((char *) newex);
if (newex != executable1)
{
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv,
+ pid = win32_spawn (newex, FALSE, argv, env,
dwCreationFlags, si, pi);
free ((char *) newex);
}
static long
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
const char *executable, char * const * argv,
+ char* const* env,
int in, int out, int errdes, const char **errmsg,
int *err)
{
/* Create the child process. */
pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
- argv, dwCreationFlags, &si, &pi);
+ argv, env, dwCreationFlags, &si, &pi);
if (pid == -1)
- pid = spawn_script (executable, argv, dwCreationFlags, &si, &pi);
+ pid = spawn_script (executable, argv, env, dwCreationFlags,
+ &si, &pi);
if (pid == -1)
{
*err = ENOENT;
char const *errmsg;
int err;
argv++;
- printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, 0, 1, 2, &errmsg, &err));
+ printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
exit (0);
}
#endif
@end deftypefn
+@deftypefn Extension {const char *} pex_run_in_environment (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, char * const *@var{env}, int @var{env_size}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
+
+Execute one program in a pipeline, permitting the environment for the
+program to be specified. Behaviour and parameters not listed below are
+as for @code{pex_run}.
+
+@var{env} is the environment for the child process, specified as an array of
+character pointers. Each element of the array should point to a string of the
+form @code{VAR=VALUE}, with the exception of the last element that must be
+@code{NULL}.
+
+@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