Make also the g_spawn*() functions take parameters in the GLib file name

2005-08-25  Tor Lillqvist  <tml@novell.com>

	Make also the g_spawn*() functions take parameters in the GLib
	file name encoding, i.e. UTF-8, on Windows. Has no impact on Unix
	API or ABI. Like the other GLib API that was earlier changed to
	use UTF-8 on Windows, the names of the functions that take UTF-8
	have _utf8 suffixes added by using preprocessor macros in the
	header file. The old names are kept for functions with the old
	behaviour, taking parameters in the system codepage, for DLL ABI
	stability.

	* glib/gspawn.h: On Win32 add the suffix _utf8 to the names of the
	g_spawn*() functions.

	* glib/gspawn-win32.c: Use wide-char API on NT-based
	Windows. Convert parameters from UTF-8 to wide chars (NT) or
	system codepage (Win9x) and call the C library _wspawn*() or
	spawn*() functions respectvely. Add DLL ABI stability versions
	that take parameters in the system codepage.

	* glib/gspawn-win32-helper.c: On NT-based Windows use the
	wide-char versions of argv and envp, and use wide-char API to
	change directory and spawn the program to run. Remove the verbose
	debugging output, it was too complex to modify for the wide-char
	features. (Just add temporary debugging printouts if needed, no
	need to have them permanently in the source.)

	* glib/gspawn.c: Corresponding documentation updates.

	* glib/glib.symbols: Corresponding changes: Mark the ABI stability
	symbols as PRIVATE, add the new _utf8-suffixed ones.
This commit is contained in:
Tor Lillqvist
2005-08-29 22:12:15 +00:00
committed by Tor Lillqvist
parent 73aaeb741f
commit d6501b422f
7 changed files with 1006 additions and 281 deletions

View File

@@ -1,3 +1,35 @@
2005-08-25 Tor Lillqvist <tml@novell.com>
Make also the g_spawn*() functions take parameters in the GLib
file name encoding, i.e. UTF-8, on Windows. Has no impact on Unix
API or ABI. Like the other GLib API that was earlier changed to
use UTF-8 on Windows, the names of the functions that take UTF-8
have _utf8 suffixes added by using preprocessor macros in the
header file. The old names are kept for functions with the old
behaviour, taking parameters in the system codepage, for DLL ABI
stability.
* glib/gspawn.h: On Win32 add the suffix _utf8 to the names of the
g_spawn*() functions.
* glib/gspawn-win32.c: Use wide-char API on NT-based
Windows. Convert parameters from UTF-8 to wide chars (NT) or
system codepage (Win9x) and call the C library _wspawn*() or
spawn*() functions respectvely. Add DLL ABI stability versions
that take parameters in the system codepage.
* glib/gspawn-win32-helper.c: On NT-based Windows use the
wide-char versions of argv and envp, and use wide-char API to
change directory and spawn the program to run. Remove the verbose
debugging output, it was too complex to modify for the wide-char
features. (Just add temporary debugging printouts if needed, no
need to have them permanently in the source.)
* glib/gspawn.c: Corresponding documentation updates.
* glib/glib.symbols: Corresponding changes: Mark the ABI stability
symbols as PRIVATE, add the new _utf8-suffixed ones.
2005-08-24 Stepan Kasal <kasal@ucw.cz> 2005-08-24 Stepan Kasal <kasal@ucw.cz>
* glib/gtypes.h (G_MININT64): Cast the constant to gint64; it is * glib/gtypes.h (G_MININT64): Cast the constant to gint64; it is

View File

@@ -1,3 +1,35 @@
2005-08-25 Tor Lillqvist <tml@novell.com>
Make also the g_spawn*() functions take parameters in the GLib
file name encoding, i.e. UTF-8, on Windows. Has no impact on Unix
API or ABI. Like the other GLib API that was earlier changed to
use UTF-8 on Windows, the names of the functions that take UTF-8
have _utf8 suffixes added by using preprocessor macros in the
header file. The old names are kept for functions with the old
behaviour, taking parameters in the system codepage, for DLL ABI
stability.
* glib/gspawn.h: On Win32 add the suffix _utf8 to the names of the
g_spawn*() functions.
* glib/gspawn-win32.c: Use wide-char API on NT-based
Windows. Convert parameters from UTF-8 to wide chars (NT) or
system codepage (Win9x) and call the C library _wspawn*() or
spawn*() functions respectvely. Add DLL ABI stability versions
that take parameters in the system codepage.
* glib/gspawn-win32-helper.c: On NT-based Windows use the
wide-char versions of argv and envp, and use wide-char API to
change directory and spawn the program to run. Remove the verbose
debugging output, it was too complex to modify for the wide-char
features. (Just add temporary debugging printouts if needed, no
need to have them permanently in the source.)
* glib/gspawn.c: Corresponding documentation updates.
* glib/glib.symbols: Corresponding changes: Mark the ABI stability
symbols as PRIVATE, add the new _utf8-suffixed ones.
2005-08-24 Stepan Kasal <kasal@ucw.cz> 2005-08-24 Stepan Kasal <kasal@ucw.cz>
* glib/gtypes.h (G_MININT64): Cast the constant to gint64; it is * glib/gtypes.h (G_MININT64): Cast the constant to gint64; it is

View File

@@ -1,3 +1,35 @@
2005-08-25 Tor Lillqvist <tml@novell.com>
Make also the g_spawn*() functions take parameters in the GLib
file name encoding, i.e. UTF-8, on Windows. Has no impact on Unix
API or ABI. Like the other GLib API that was earlier changed to
use UTF-8 on Windows, the names of the functions that take UTF-8
have _utf8 suffixes added by using preprocessor macros in the
header file. The old names are kept for functions with the old
behaviour, taking parameters in the system codepage, for DLL ABI
stability.
* glib/gspawn.h: On Win32 add the suffix _utf8 to the names of the
g_spawn*() functions.
* glib/gspawn-win32.c: Use wide-char API on NT-based
Windows. Convert parameters from UTF-8 to wide chars (NT) or
system codepage (Win9x) and call the C library _wspawn*() or
spawn*() functions respectvely. Add DLL ABI stability versions
that take parameters in the system codepage.
* glib/gspawn-win32-helper.c: On NT-based Windows use the
wide-char versions of argv and envp, and use wide-char API to
change directory and spawn the program to run. Remove the verbose
debugging output, it was too complex to modify for the wide-char
features. (Just add temporary debugging printouts if needed, no
need to have them permanently in the source.)
* glib/gspawn.c: Corresponding documentation updates.
* glib/glib.symbols: Corresponding changes: Mark the ABI stability
symbols as PRIVATE, add the new _utf8-suffixed ones.
2005-08-24 Stepan Kasal <kasal@ucw.cz> 2005-08-24 Stepan Kasal <kasal@ucw.cz>
* glib/gtypes.h (G_MININT64): Cast the constant to gint64; it is * glib/gtypes.h (G_MININT64): Cast the constant to gint64; it is

View File

@@ -851,13 +851,20 @@ g_slist_sort_with_data
#if IN_HEADER(__G_SPAWN_H__) #if IN_HEADER(__G_SPAWN_H__)
#if IN_FILE(__G_SPAWN_C__) #if IN_FILE(__G_SPAWN_C__)
g_spawn_async g_spawn_async PRIVATE
g_spawn_async_with_pipes g_spawn_async_with_pipes PRIVATE
g_spawn_close_pid g_spawn_close_pid
g_spawn_command_line_async g_spawn_command_line_async PRIVATE
g_spawn_command_line_sync g_spawn_command_line_sync PRIVATE
g_spawn_error_quark g_spawn_error_quark
g_spawn_sync g_spawn_sync PRIVATE
#ifdef G_OS_WIN32
g_spawn_async_utf8
g_spawn_async_with_pipes_utf8
g_spawn_command_line_async_utf8
g_spawn_command_line_sync_utf8
g_spawn_sync_utf8
#endif
#endif #endif
#endif #endif

View File

@@ -27,23 +27,12 @@
#include "gspawn-win32.c" /* For shared definitions */ #include "gspawn-win32.c" /* For shared definitions */
static GString *debugstring;
static void static void
write_err_and_exit (gint fd, write_err_and_exit (gint fd,
gint msg) gint msg)
{ {
gint en = errno; gint en = errno;
if (debug)
{
debugstring = g_string_new (NULL);
g_string_append (debugstring,
g_strdup_printf ("writing error code %d and errno %d",
msg, en));
MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
}
write (fd, &msg, sizeof(msg)); write (fd, &msg, sizeof(msg));
write (fd, &en, sizeof(en)); write (fd, &en, sizeof(en));
@@ -63,6 +52,99 @@ write_err_and_exit (gint fd,
* away in the global __argc and __argv by the C runtime startup code. * away in the global __argc and __argv by the C runtime startup code.
*/ */
/* Info peeked from mingw runtime's source code. __wgetmainargs() is a
* function to get the program's argv in wide char format.
*/
typedef struct {
int newmode;
} _startupinfo;
extern void __wgetmainargs(int *argc,
wchar_t ***wargv,
wchar_t ***wenviron,
int expand_wildcards,
_startupinfo *startupinfo);
/* Copy of protect_argv that handles wchar_t strings */
static gint
protect_wargv (wchar_t **wargv,
wchar_t ***new_wargv)
{
gint i;
gint argc = 0;
while (wargv[argc])
++argc;
*new_wargv = g_new (wchar_t *, argc+1);
/* Quote each argv element if necessary, so that it will get
* reconstructed correctly in the C runtime startup code. Note that
* the unquoting algorithm in the C runtime is really weird, and
* rather different than what Unix shells do. See stdargv.c in the C
* runtime sources (in the Platform SDK, in src/crt).
*
* Note that an new_wargv[0] constructed by this function should
* *not* be passed as the filename argument to a _wspawn* or _wexec*
* family function. That argument should be the real file name
* without any quoting.
*/
for (i = 0; i < argc; i++)
{
wchar_t *p = wargv[i];
wchar_t *q;
gint len = 0;
gboolean need_dblquotes = FALSE;
while (*p)
{
if (*p == ' ' || *p == '\t')
need_dblquotes = TRUE;
else if (*p == '"')
len++;
else if (*p == '\\')
{
wchar_t *pp = p;
while (*pp && *pp == '\\')
pp++;
if (*pp == '"')
len++;
}
len++;
p++;
}
q = (*new_wargv)[i] = g_new (wchar_t, len + need_dblquotes*2 + 1);
p = wargv[i];
if (need_dblquotes)
*q++ = '"';
while (*p)
{
if (*p == '"')
*q++ = '\\';
else if (*p == '\\')
{
wchar_t *pp = p;
while (*pp && *pp == '\\')
pp++;
if (*pp == '"')
*q++ = '\\';
}
*q++ = *p;
p++;
}
if (need_dblquotes)
*q++ = '"';
*q++ = '\0';
}
(*new_wargv)[argc] = NULL;
return argc;
}
int _stdcall int _stdcall
WinMain (struct HINSTANCE__ *hInstance, WinMain (struct HINSTANCE__ *hInstance,
struct HINSTANCE__ *hPrevInstance, struct HINSTANCE__ *hPrevInstance,
@@ -77,44 +159,43 @@ WinMain (struct HINSTANCE__ *hInstance,
int saved_errno; int saved_errno;
int no_error = CHILD_NO_ERROR; int no_error = CHILD_NO_ERROR;
int zero = 0; int zero = 0;
gint file_and_argv_zero = 0; gint argv_zero_offset = ARG_PROGRAM;
gchar **new_argv; gchar **new_argv;
wchar_t **new_wargv;
SETUP_DEBUG(); int argc;
wchar_t **wargv, **wenvp;
if (debug) _startupinfo si = { 0 };
{
debugstring = g_string_new (NULL);
g_string_append (debugstring,
g_strdup_printf ("g-spawn-win32-helper: "
"argc = %d, argv: ",
__argc));
for (i = 0; i < __argc; i++)
{
if (i > 0)
g_string_append (debugstring, " ");
g_string_append (debugstring, __argv[i]);
}
MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
}
g_assert (__argc >= ARG_COUNT); g_assert (__argc >= ARG_COUNT);
/* argv[ARG_CHILD_ERR_REPORT] is the file descriptor onto which if (G_WIN32_HAVE_WIDECHAR_API ())
* write error messages. {
/* Fetch the wide-char argument vector */
__wgetmainargs (&argc, &wargv, &wenvp, 0, &si);
/* We still have the system codepage args in __argv. We can look
* at the first args in which gspawn-win32.c passes us flags and
* fd numbers in __argv, as we know those are just ASCII anyway.
*/
g_assert (argc == __argc);
}
/* argv[ARG_CHILD_ERR_REPORT] is the file descriptor number onto
* which write error messages.
*/ */
child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]); child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
/* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO */ /* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO. If
* argv[ARG_CHILD_ERR_REPORT] is suffixed with a '#' it means we get
* the program to run and its argv[0] separately.
*/
if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#') if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#')
file_and_argv_zero = 1; argv_zero_offset++;
/* argv[ARG_STDIN..ARG_STDERR] are the file descriptors that should /* argv[ARG_STDIN..ARG_STDERR] are the file descriptor numbers that
* be dup2'd to stdin, stdout and stderr, '-' if the corresponding * should be dup2'd to 0, 1 and 2. '-' if the corresponding fd
* std* should be let alone, and 'z' if it should be connected to * should be left alone, and 'z' if it should be connected to the
* the bit bucket NUL:. * bit bucket NUL:.
*/ */
if (__argv[ARG_STDIN][0] == '-') if (__argv[ARG_STDIN][0] == '-')
; /* Nothing */ ; /* Nothing */
@@ -185,21 +266,21 @@ WinMain (struct HINSTANCE__ *hInstance,
if (__argv[ARG_WORKING_DIRECTORY][0] == '-' && if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
__argv[ARG_WORKING_DIRECTORY][1] == 0) __argv[ARG_WORKING_DIRECTORY][1] == 0)
; /* Nothing */ ; /* Nothing */
else if (chdir (__argv[ARG_WORKING_DIRECTORY]) < 0) else if ((G_WIN32_HAVE_WIDECHAR_API () &&
write_err_and_exit (child_err_report_fd, _wchdir (wargv[ARG_WORKING_DIRECTORY]) < 0) ||
CHILD_CHDIR_FAILED); (!G_WIN32_HAVE_WIDECHAR_API () &&
chdir (__argv[ARG_WORKING_DIRECTORY]) < 0))
write_err_and_exit (child_err_report_fd, CHILD_CHDIR_FAILED);
/* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3 /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
* upwards should be closed * upwards should be closed
*/ */
if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y') if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
for (i = 3; i < 1000; i++) /* FIXME real limit? */ for (i = 3; i < 1000; i++) /* FIXME real limit? */
if (i != child_err_report_fd) if (i != child_err_report_fd)
close (i); close (i);
/* __argv[ARG_WAIT] is "w" to wait for the program to exit */ /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
if (__argv[ARG_WAIT][0] == 'w') if (__argv[ARG_WAIT][0] == 'w')
mode = P_WAIT; mode = P_WAIT;
else else
@@ -207,53 +288,36 @@ WinMain (struct HINSTANCE__ *hInstance,
/* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */ /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
/* __argv[ARG_PROGRAM] is program file to run, /* __argv[ARG_PROGRAM] is executable file to run,
* __argv[ARG_PROGRAM+1]... is its __argv. * __argv[argv_zero_offset]... is its argv. argv_zero_offset equals
* ARG_PROGRAM unless G_SPAWN_FILE_AND_ARGV_ZERO was used, in which
* case we have a separate executable name and argv[0].
*/ */
protect_argv (__argv, &new_argv);
/* For the program name passed to spawnv(), don't use the quoted /* For the program name passed to spawnv(), don't use the quoted
* version. */ * version.
*/
if (debug) if (G_WIN32_HAVE_WIDECHAR_API ())
{ {
debugstring = g_string_new (NULL); protect_wargv (wargv + argv_zero_offset, &new_wargv);
g_string_append (debugstring,
g_strdup_printf ("calling %s %s mode=%s argv: ",
(__argv[ARG_USE_PATH][0] == 'y' ?
"spawnvp" : "spawnv"),
__argv[ARG_PROGRAM],
(mode == P_WAIT ?
"P_WAIT" : "P_NOWAIT")));
i = ARG_PROGRAM + 1 + file_and_argv_zero;
while (new_argv[i])
{
g_string_append (debugstring, new_argv[i++]);
if (new_argv[i])
g_string_append (debugstring, " ");
}
MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
}
if (new_argv[ARG_USE_PATH][0] == 'y') if (__argv[ARG_USE_PATH][0] == 'y')
handle = spawnvp (mode, __argv[ARG_PROGRAM], new_argv + ARG_PROGRAM + file_and_argv_zero); handle = _wspawnvp (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
else else
handle = spawnv (mode, __argv[ARG_PROGRAM], new_argv + ARG_PROGRAM + file_and_argv_zero); handle = _wspawnv (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
}
else
{
protect_argv (__argv + argv_zero_offset, &new_argv);
if (__argv[ARG_USE_PATH][0] == 'y')
handle = spawnvp (mode, __argv[ARG_PROGRAM], (const char **) new_argv);
else
handle = spawnv (mode, __argv[ARG_PROGRAM], (const char **) new_argv);
}
saved_errno = errno; saved_errno = errno;
if (debug)
{
debugstring = g_string_new (NULL);
g_string_append (debugstring,
g_strdup_printf ("%s returned %#x",
(__argv[ARG_USE_PATH][0] == 'y' ?
"spawnvp" : "spawnv"),
handle));
MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
}
if (handle == -1 && saved_errno != 0) if (handle == -1 && saved_errno != 0)
write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED); write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
@@ -264,4 +328,3 @@ WinMain (struct HINSTANCE__ *hInstance,
write (child_err_report_fd, &zero, sizeof (zero)); write (child_err_report_fd, &zero, sizeof (zero));
return 0; return 0;
} }

View File

@@ -59,6 +59,14 @@
#include <process.h> #include <process.h>
#include <direct.h> #include <direct.h>
#ifdef __MINGW32__
/* Mingw doesn't have prototypes for these */
int _wspawnvpe (int, const wchar_t *, const wchar_t **, const wchar_t **);
int _wspawnvp (int, const wchar_t *, const wchar_t **);
int _wspawnve (int, const wchar_t *, const wchar_t **, const wchar_t **);
int _wspawnv (int, const wchar_t *, const wchar_t **);
#endif
#include "glibintl.h" #include "glibintl.h"
#ifdef G_SPAWN_WIN32_DEBUG #ifdef G_SPAWN_WIN32_DEBUG
@@ -100,6 +108,60 @@ enum {
ARG_COUNT = ARG_PROGRAM ARG_COUNT = ARG_PROGRAM
}; };
static gchar *
protect_argv_string (const gchar *string)
{
const gchar *p = string;
gchar *retval, *q;
gint len = 0;
gboolean need_dblquotes = FALSE;
while (*p)
{
if (*p == ' ' || *p == '\t')
need_dblquotes = TRUE;
else if (*p == '"')
len++;
else if (*p == '\\')
{
const gchar *pp = p;
while (*pp && *pp == '\\')
pp++;
if (*pp == '"')
len++;
}
len++;
p++;
}
q = retval = g_malloc (len + need_dblquotes*2 + 1);
p = string;
if (need_dblquotes)
*q++ = '"';
while (*p)
{
if (*p == '"')
*q++ = '\\';
else if (*p == '\\')
{
const gchar *pp = p;
while (*pp && *pp == '\\')
pp++;
if (*pp == '"')
*q++ = '\\';
}
*q++ = *p;
p++;
}
if (need_dblquotes)
*q++ = '"';
*q++ = '\0';
return retval;
}
static gint static gint
protect_argv (gchar **argv, protect_argv (gchar **argv,
gchar ***new_argv) gchar ***new_argv)
@@ -123,56 +185,8 @@ protect_argv (gchar **argv,
* without any quoting. * without any quoting.
*/ */
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
{ (*new_argv)[i] = protect_argv_string (argv[i]);
gchar *p = argv[i];
gchar *q;
gint len = 0;
gboolean need_dblquotes = FALSE;
while (*p)
{
if (*p == ' ' || *p == '\t')
need_dblquotes = TRUE;
else if (*p == '"')
len++;
else if (*p == '\\')
{
gchar *pp = p;
while (*pp && *pp == '\\')
pp++;
if (*pp == '"')
len++;
}
len++;
p++;
}
q = (*new_argv)[i] = g_malloc (len + need_dblquotes*2 + 1);
p = argv[i];
if (need_dblquotes)
*q++ = '"';
while (*p)
{
if (*p == '"')
*q++ = '\\';
else if (*p == '\\')
{
gchar *pp = p;
while (*pp && *pp == '\\')
pp++;
if (*pp == '"')
*q++ = '\\';
}
*q++ = *p;
p++;
}
if (need_dblquotes)
*q++ = '"';
*q++ = '\0';
/* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
}
(*new_argv)[argc] = NULL; (*new_argv)[argc] = NULL;
return argc; return argc;
@@ -192,7 +206,7 @@ g_spawn_error_quark (void)
} }
gboolean gboolean
g_spawn_async (const gchar *working_directory, g_spawn_async_utf8 (const gchar *working_directory,
gchar **argv, gchar **argv,
gchar **envp, gchar **envp,
GSpawnFlags flags, GSpawnFlags flags,
@@ -203,7 +217,7 @@ g_spawn_async (const gchar *working_directory,
{ {
g_return_val_if_fail (argv != NULL, FALSE); g_return_val_if_fail (argv != NULL, FALSE);
return g_spawn_async_with_pipes (working_directory, return g_spawn_async_with_pipes_utf8 (working_directory,
argv, envp, argv, envp,
flags, flags,
child_setup, child_setup,
@@ -258,9 +272,7 @@ read_data (GString *str,
goto again; goto again;
else if (giostatus == G_IO_STATUS_ERROR) else if (giostatus == G_IO_STATUS_ERROR)
{ {
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
G_SPAWN_ERROR,
G_SPAWN_ERROR_READ,
_("Failed to read data from child process")); _("Failed to read data from child process"));
return READ_FAILED; return READ_FAILED;
@@ -275,9 +287,7 @@ make_pipe (gint p[2],
{ {
if (pipe (p) < 0) if (pipe (p) < 0)
{ {
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
G_SPAWN_ERROR,
G_SPAWN_ERROR_FAILED,
_("Failed to create pipe for communicating with child process (%s)"), _("Failed to create pipe for communicating with child process (%s)"),
g_strerror (errno)); g_strerror (errno));
return FALSE; return FALSE;
@@ -315,9 +325,7 @@ read_helper_report (int fd,
{ {
/* Some weird shit happened, bail out */ /* Some weird shit happened, bail out */
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
G_SPAWN_ERROR,
G_SPAWN_ERROR_FAILED,
_("Failed to read from child pipe (%s)"), _("Failed to read from child pipe (%s)"),
g_strerror (errno)); g_strerror (errno));
@@ -343,17 +351,13 @@ set_child_error (gint report[2],
switch (report[0]) switch (report[0])
{ {
case CHILD_CHDIR_FAILED: case CHILD_CHDIR_FAILED:
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
G_SPAWN_ERROR,
G_SPAWN_ERROR_CHDIR,
_("Failed to change to directory '%s' (%s)"), _("Failed to change to directory '%s' (%s)"),
working_directory, working_directory,
g_strerror (report[1])); g_strerror (report[1]));
break; break;
case CHILD_SPAWN_FAILED: case CHILD_SPAWN_FAILED:
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
G_SPAWN_ERROR,
G_SPAWN_ERROR_FAILED,
_("Failed to execute child process (%s)"), _("Failed to execute child process (%s)"),
g_strerror (report[1])); g_strerror (report[1]));
break; break;
@@ -362,6 +366,241 @@ set_child_error (gint report[2],
} }
} }
static gboolean
utf8_charv_to_wcharv (char **utf8_charv,
wchar_t ***wcharv,
int *error_index,
GError **error)
{
wchar_t **retval = NULL;
*wcharv = NULL;
if (utf8_charv != NULL)
{
int n = 0, i;
while (utf8_charv[n])
n++;
retval = g_new (wchar_t *, n + 1);
for (i = 0; i < n; i++)
{
retval[i] = g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error);
if (retval[i] == NULL)
{
if (error_index)
*error_index = i;
while (i)
g_free (retval[--i]);
g_free (retval);
return FALSE;
}
}
retval[n] = NULL;
}
*wcharv = retval;
return TRUE;
}
static gboolean
utf8_charv_to_cp_charv (char **utf8_charv,
gchar ***cp_charv,
int *error_index,
GError **error)
{
char **retval = NULL;
*cp_charv = NULL;
if (utf8_charv != NULL)
{
int n = 0, i;
while (utf8_charv[n])
n++;
retval = g_new (char *, n + 1);
for (i = 0; i < n; i++)
{
retval[i] = g_locale_from_utf8 (utf8_charv[i], -1, NULL, NULL, error);
if (retval[i] == NULL)
{
if (error_index)
*error_index = i;
while (i)
g_free (retval[--i]);
g_free (retval);
return FALSE;
}
}
retval[n] = NULL;
}
*cp_charv = retval;
return TRUE;
}
static gboolean
do_spawn_directly (gboolean dont_wait,
gboolean dont_return_handle,
GSpawnFlags flags,
gchar **argv,
char **envp,
char **protected_argv,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
GPid *child_handle,
gint *exit_status,
GError **error)
{
int mode = dont_wait ? P_NOWAIT : P_WAIT;
char **new_argv;
int rc = -1;
int saved_errno;
GError *conv_error = NULL;
gint conv_error_index;
new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
if (G_WIN32_HAVE_WIDECHAR_API ())
{
wchar_t *wargv0, **wargv, **wenvp;
wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
if (wargv0 == NULL)
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid program name: %s",
conv_error->message);
g_error_free (conv_error);
return FALSE;
}
if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in argument vector at %d: %s",
conv_error_index, conv_error->message);
g_error_free (conv_error);
g_free (wargv0);
return FALSE;
}
if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in environment: %s",
conv_error->message);
g_error_free (conv_error);
g_free (wargv0);
g_strfreev ((gchar **) wargv);
return FALSE;
}
if (child_setup)
(* child_setup) (user_data);
if (flags & G_SPAWN_SEARCH_PATH)
if (wenvp != NULL)
rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
else
rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
else
if (wenvp != NULL)
rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
else
rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
g_free (wargv0);
g_strfreev ((gchar **) wargv);
g_strfreev ((gchar **) wenvp);
}
else
{
char *cpargv0, **cpargv, **cpenvp;
cpargv0 = g_locale_from_utf8 (argv[0], -1, NULL, NULL, &conv_error);
if (cpargv0 == NULL)
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid program name: %s",
conv_error->message);
g_error_free (conv_error);
return FALSE;
}
if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in argument vector at %d: %s",
conv_error_index, conv_error->message);
g_error_free (conv_error);
g_free (cpargv0);
return FALSE;
}
if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in environment: %s",
conv_error->message);
g_error_free (conv_error);
g_free (cpargv0);
g_strfreev (cpargv);
return FALSE;
}
if (child_setup)
(* child_setup) (user_data);
if (flags & G_SPAWN_SEARCH_PATH)
if (cpenvp != NULL)
rc = spawnvpe (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
else
rc = spawnvp (mode, cpargv0, (const char **) cpargv);
else
if (envp != NULL)
rc = spawnve (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
else
rc = spawnv (mode, cpargv0, (const char **) cpargv);
g_free (cpargv0);
g_strfreev (cpargv);
g_strfreev (cpenvp);
}
saved_errno = errno;
if (rc == -1 && saved_errno != 0)
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
_("Failed to execute child process (%s)"),
g_strerror (saved_errno));
return FALSE;
}
if (dont_wait)
{
if (child_handle && !dont_return_handle)
*child_handle = (GPid) rc;
else
{
CloseHandle ((HANDLE) rc);
if (child_handle)
*child_handle = 0;
}
}
else if (exit_status)
*exit_status = rc;
return TRUE;
}
static gboolean static gboolean
do_spawn_with_pipes (gboolean dont_wait, do_spawn_with_pipes (gboolean dont_wait,
gboolean dont_return_handle, gboolean dont_return_handle,
@@ -391,9 +630,18 @@ do_spawn_with_pipes (gboolean dont_wait,
int stderr_pipe[2] = { -1, -1 }; int stderr_pipe[2] = { -1, -1 };
int child_err_report_pipe[2] = { -1, -1 }; int child_err_report_pipe[2] = { -1, -1 };
int helper_report[2]; int helper_report[2];
static gboolean warned_about_child_setup = FALSE;
GError *conv_error = NULL;
gint conv_error_index;
SETUP_DEBUG(); SETUP_DEBUG();
if (child_setup && !warned_about_child_setup)
{
warned_about_child_setup = TRUE;
g_warning ("passing a child setup function to the g_spawn functions is pointless and dangerous on Win32");
}
argc = protect_argv (argv, &protected_argv); argc = protect_argv (argv, &protected_argv);
if (!standard_input && !standard_output && !standard_error && if (!standard_input && !standard_output && !standard_error &&
@@ -404,65 +652,15 @@ do_spawn_with_pipes (gboolean dont_wait,
(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) (flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
{ {
/* We can do without the helper process */ /* We can do without the helper process */
int mode = dont_wait ? P_NOWAIT : P_WAIT; gboolean retval =
do_spawn_directly (dont_wait, dont_return_handle, flags,
if (debug) argv, envp, protected_argv,
g_print ("doing without " HELPER_PROCESS "\n"); child_setup, user_data, child_handle,
exit_status, error);
/* Call user function just before we spawn the program. Dunno g_strfreev (protected_argv);
* what's the usefulness of this. A child setup function used on return retval;
* Unix probably isn't of much use as such on Win32, anyhow.
*/
if (child_setup)
(* child_setup) (user_data);
new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
if (flags & G_SPAWN_SEARCH_PATH)
if (envp != NULL)
rc = spawnvpe (mode, argv[0], (const char **) new_argv, (const char **) envp);
else
rc = spawnvp (mode, argv[0], (const char **) new_argv);
else
if (envp != NULL)
rc = spawnve (mode, argv[0], (const char **) new_argv, (const char **) envp);
else
rc = spawnv (mode, argv[0], (const char **) new_argv);
saved_errno = errno;
for (i = 0; i < argc; i++)
g_free (protected_argv[i]);
g_free (protected_argv);
if (rc == -1 && saved_errno != 0)
{
g_set_error (error,
G_SPAWN_ERROR,
G_SPAWN_ERROR_FAILED,
_("Failed to execute child process (%s)"),
g_strerror (errno));
goto cleanup_and_fail;
} }
if (dont_wait)
{
if (child_handle && !dont_return_handle)
*child_handle = (GPid) rc;
else
{
CloseHandle (rc);
if (child_handle)
*child_handle = 0;
}
}
else if (exit_status)
*exit_status = rc;
return TRUE;
}
new_argv = g_new (char *, argc + 1 + ARG_COUNT);
if (standard_input && !make_pipe (stdin_pipe, error)) if (standard_input && !make_pipe (stdin_pipe, error))
goto cleanup_and_fail; goto cleanup_and_fail;
@@ -475,6 +673,7 @@ do_spawn_with_pipes (gboolean dont_wait,
if (!make_pipe (child_err_report_pipe, error)) if (!make_pipe (child_err_report_pipe, error))
goto cleanup_and_fail; goto cleanup_and_fail;
new_argv = g_new (char *, argc + 1 + ARG_COUNT);
new_argv[0] = HELPER_PROCESS; new_argv[0] = HELPER_PROCESS;
_g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]); _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT]; new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
@@ -532,8 +731,7 @@ do_spawn_with_pipes (gboolean dont_wait,
} }
if (working_directory && *working_directory) if (working_directory && *working_directory)
/* The g_strdup() to lose the constness */ new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory);
new_argv[ARG_WORKING_DIRECTORY] = g_strdup (working_directory);
else else
new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-"); new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
@@ -562,30 +760,121 @@ do_spawn_with_pipes (gboolean dont_wait,
g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL")); g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
} }
if (G_WIN32_HAVE_WIDECHAR_API ())
{
wchar_t *whelper = g_utf8_to_utf16 (HELPER_PROCESS, -1, NULL, NULL, NULL);
wchar_t **wargv, **wenvp;
if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
{
if (conv_error_index == ARG_WORKING_DIRECTORY)
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
"Invalid working directory: %s",
conv_error->message);
else
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in argument vector at %d: %s",
conv_error_index - ARG_PROGRAM, conv_error->message);
g_error_free (conv_error);
g_strfreev (protected_argv);
g_free (new_argv[ARG_WORKING_DIRECTORY]);
g_free (new_argv);
g_free (whelper);
return FALSE;
}
if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in environment: %s",
conv_error->message);
g_error_free (conv_error);
g_strfreev (protected_argv);
g_free (new_argv[ARG_WORKING_DIRECTORY]);
g_free (new_argv);
g_free (whelper);
g_strfreev ((gchar **) wargv);
return FALSE;
}
if (child_setup) if (child_setup)
(* child_setup) (user_data); (* child_setup) (user_data);
if (envp != NULL) if (wenvp != NULL)
/* Let's hope envp hasn't mucked with PATH so that /* Let's hope envp hasn't mucked with PATH so that
* gspawn-win32-helper.exe isn't found. * gspawn-win32-helper.exe isn't found.
*/ */
rc = spawnvpe (P_NOWAIT, HELPER_PROCESS, (const char **) new_argv, (const char **) envp); rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
else else
rc = spawnvp (P_NOWAIT, HELPER_PROCESS, (const char **) new_argv); rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
saved_errno = errno; saved_errno = errno;
/* Close thed the other process's ends of the pipes in this g_free (whelper);
* process, otherwise the reader will never get EOF. g_strfreev ((gchar **) wargv);
g_strfreev ((gchar **) wenvp);
}
else
{
char **cpargv, **cpenvp;
if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
{
if (conv_error_index == ARG_WORKING_DIRECTORY)
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
"Invalid working directory: %s",
conv_error->message);
else
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in argument vector at %d: %s",
conv_error_index - ARG_PROGRAM, conv_error->message);
g_error_free (conv_error);
g_strfreev (protected_argv);
g_free (new_argv[ARG_WORKING_DIRECTORY]);
g_free (new_argv);
return FALSE;
}
if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in environment: %s",
conv_error->message);
g_error_free (conv_error);
g_strfreev (protected_argv);
g_free (new_argv[ARG_WORKING_DIRECTORY]);
g_free (new_argv);
g_strfreev (cpargv);
return FALSE;
}
if (child_setup)
(* child_setup) (user_data);
if (cpenvp != NULL)
rc = spawnvpe (P_NOWAIT, HELPER_PROCESS, (const char **) cpargv, (const char **) cpenvp);
else
rc = spawnvp (P_NOWAIT, HELPER_PROCESS, (const char **) cpargv);
saved_errno = errno;
g_strfreev (cpargv);
g_strfreev (cpenvp);
}
/* Close the other process's ends of the pipes in this process,
* otherwise the reader will never get EOF.
*/ */
close_and_invalidate (&child_err_report_pipe[1]); close_and_invalidate (&child_err_report_pipe[1]);
close_and_invalidate (&stdin_pipe[0]); close_and_invalidate (&stdin_pipe[0]);
close_and_invalidate (&stdout_pipe[1]); close_and_invalidate (&stdout_pipe[1]);
close_and_invalidate (&stderr_pipe[1]); close_and_invalidate (&stderr_pipe[1]);
for (i = 0; i < argc; i++) g_strfreev (protected_argv);
g_free (protected_argv[i]);
g_free (protected_argv);
g_free (new_argv[ARG_WORKING_DIRECTORY]); g_free (new_argv[ARG_WORKING_DIRECTORY]);
g_free (new_argv); g_free (new_argv);
@@ -593,10 +882,9 @@ do_spawn_with_pipes (gboolean dont_wait,
/* Check if gspawn-win32-helper couldn't be run */ /* Check if gspawn-win32-helper couldn't be run */
if (rc == -1 && saved_errno != 0) if (rc == -1 && saved_errno != 0)
{ {
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
G_SPAWN_ERROR, _("Failed to execute helper program (%s)"),
G_SPAWN_ERROR_FAILED, g_strerror (saved_errno));
_("Failed to execute helper program"));
goto cleanup_and_fail; goto cleanup_and_fail;
} }
@@ -680,7 +968,7 @@ do_spawn_with_pipes (gboolean dont_wait,
} }
gboolean gboolean
g_spawn_sync (const gchar *working_directory, g_spawn_sync_utf8 (const gchar *working_directory,
gchar **argv, gchar **argv,
gchar **envp, gchar **envp,
GSpawnFlags flags, GSpawnFlags flags,
@@ -791,9 +1079,7 @@ g_spawn_sync (const gchar *working_directory,
{ {
failed = TRUE; failed = TRUE;
g_set_error (error, g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
G_SPAWN_ERROR,
G_SPAWN_ERROR_READ,
_("Unexpected error in g_io_channel_win32_poll() reading data from a child process")); _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
break; break;
@@ -920,7 +1206,7 @@ g_spawn_sync (const gchar *working_directory,
} }
gboolean gboolean
g_spawn_async_with_pipes (const gchar *working_directory, g_spawn_async_with_pipes_utf8 (const gchar *working_directory,
gchar **argv, gchar **argv,
gchar **envp, gchar **envp,
GSpawnFlags flags, GSpawnFlags flags,
@@ -958,6 +1244,277 @@ g_spawn_async_with_pipes (const gchar *working_directory,
error); error);
} }
gboolean
g_spawn_command_line_sync_utf8 (const gchar *command_line,
gchar **standard_output,
gchar **standard_error,
gint *exit_status,
GError **error)
{
gboolean retval;
gchar **argv = 0;
g_return_val_if_fail (command_line != NULL, FALSE);
if (!g_shell_parse_argv (command_line,
NULL, &argv,
error))
return FALSE;
retval = g_spawn_sync_utf8 (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH,
NULL,
NULL,
standard_output,
standard_error,
exit_status,
error);
g_strfreev (argv);
return retval;
}
gboolean
g_spawn_command_line_async_utf8 (const gchar *command_line,
GError **error)
{
gboolean retval;
gchar **argv = 0;
g_return_val_if_fail (command_line != NULL, FALSE);
if (!g_shell_parse_argv (command_line,
NULL, &argv,
error))
return FALSE;
retval = g_spawn_async_utf8 (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH,
NULL,
NULL,
NULL,
error);
g_strfreev (argv);
return retval;
}
void
g_spawn_close_pid (GPid pid)
{
CloseHandle (pid);
}
/* Binary compatibility versions that take system codepage pathnames,
* argument vectors and environments. These get used only by code
* built against 2.8.1 or earlier. Code built against 2.8.2 or later
* will use the _utf8 versions above (see the #defines in gspawn.h).
*/
#undef g_spawn_async
#undef g_spawn_async_with_pipes
#undef g_spawn_sync
#undef g_spawn_command_line_sync
#undef g_spawn_command_line_async
static gboolean
setup_utf8_copies (const gchar *working_directory,
gchar **utf8_working_directory,
gchar **argv,
gchar ***utf8_argv,
gchar **envp,
gchar ***utf8_envp,
GError **error)
{
gint i, argc, envc;
if (working_directory == NULL)
*utf8_working_directory = NULL;
else
{
GError *conv_error = NULL;
*utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error);
if (*utf8_working_directory == NULL)
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
"Invalid working directory: %s",
conv_error->message);
g_error_free (conv_error);
return FALSE;
}
}
argc = 0;
while (argv[argc])
++argc;
*utf8_argv = g_new (gchar *, argc + 1);
for (i = 0; i < argc; i++)
{
GError *conv_error = NULL;
(*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error);
if ((*utf8_argv)[i] == NULL)
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in argument vector at %d: %s",
i, conv_error->message);
g_error_free (conv_error);
g_strfreev (*utf8_argv);
*utf8_argv = NULL;
g_free (*utf8_working_directory);
*utf8_working_directory = NULL;
return FALSE;
}
}
(*utf8_argv)[argc] = NULL;
if (envp == NULL)
{
*utf8_envp = NULL;
}
else
{
envc = 0;
while (envp[envc])
++envc;
*utf8_envp = g_new (gchar *, envc + 1);
for (i = 0; i < envc; i++)
{
GError *conv_error = NULL;
(*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error);
if ((*utf8_envp)[i] == NULL)
{
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
"Invalid string in environment: %s",
conv_error->message);
g_error_free (conv_error);
g_strfreev (*utf8_envp);
*utf8_envp = NULL;
g_strfreev (*utf8_argv);
*utf8_argv = NULL;
g_free (*utf8_working_directory);
*utf8_working_directory = NULL;
return FALSE;
}
}
(*utf8_envp)[envc] = NULL;
}
return TRUE;
}
static void
free_utf8_copies (gchar *utf8_working_directory,
gchar **utf8_argv,
gchar **utf8_envp)
{
g_free (utf8_working_directory);
g_strfreev (utf8_argv);
g_strfreev (utf8_envp);
}
gboolean
g_spawn_async_with_pipes (const gchar *working_directory,
gchar **argv,
gchar **envp,
GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
GPid *child_handle,
gint *standard_input,
gint *standard_output,
gint *standard_error,
GError **error)
{
gchar *utf8_working_directory;
gchar **utf8_argv;
gchar **utf8_envp;
gboolean retval;
if (!setup_utf8_copies (working_directory, &utf8_working_directory,
argv, &utf8_argv,
envp, &utf8_envp,
error))
return FALSE;
retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory,
utf8_argv, utf8_envp,
flags, child_setup, user_data,
child_handle,
standard_input, standard_output, standard_error,
error);
free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
return retval;
}
gboolean
g_spawn_async (const gchar *working_directory,
gchar **argv,
gchar **envp,
GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
GPid *child_handle,
GError **error)
{
return g_spawn_async_with_pipes (working_directory,
argv, envp,
flags,
child_setup,
user_data,
child_handle,
NULL, NULL, NULL,
error);
}
gboolean
g_spawn_sync (const gchar *working_directory,
gchar **argv,
gchar **envp,
GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
gchar **standard_output,
gchar **standard_error,
gint *exit_status,
GError **error)
{
gchar *utf8_working_directory;
gchar **utf8_argv;
gchar **utf8_envp;
gboolean retval;
if (!setup_utf8_copies (working_directory, &utf8_working_directory,
argv, &utf8_argv,
envp, &utf8_envp,
error))
return FALSE;
retval = g_spawn_sync_utf8 (utf8_working_directory,
utf8_argv, utf8_envp,
flags, child_setup, user_data,
standard_output, standard_error, exit_status,
error);
free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
return retval;
}
gboolean gboolean
g_spawn_command_line_sync (const gchar *command_line, g_spawn_command_line_sync (const gchar *command_line,
gchar **standard_output, gchar **standard_output,
@@ -1019,11 +1576,5 @@ g_spawn_command_line_async (const gchar *command_line,
#endif /* !GSPAWN_HELPER */ #endif /* !GSPAWN_HELPER */
void
g_spawn_close_pid (GPid pid)
{
CloseHandle (pid);
}
#define __G_SPAWN_C__ #define __G_SPAWN_C__
#include "galiasdef.c" #include "galiasdef.c"

View File

@@ -71,6 +71,14 @@ typedef enum
GQuark g_spawn_error_quark (void); GQuark g_spawn_error_quark (void);
#ifdef G_OS_WIN32
#define g_spawn_async g_spawn_async_utf8
#define g_spawn_async_with_pipes g_spawn_async_with_pipes_utf8
#define g_spawn_sync g_spawn_sync_utf8
#define g_spawn_command_line_sync g_spawn_command_line_sync_utf8
#define g_spawn_command_line_async g_spawn_command_line_async_utf8
#endif
gboolean g_spawn_async (const gchar *working_directory, gboolean g_spawn_async (const gchar *working_directory,
gchar **argv, gchar **argv,
gchar **envp, gchar **envp,