spawn: Don't depend on utils.h, and fix locale compat on Windows
[geany-mirror.git] / src / spawn.c
blob44dfc2c53550ff82046b449a3d325bf037c864e7
1 /*
2 * spawn.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2013 Dimitar Toshkov Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 /* An ongoing effort to improve the tool spawning situation under Windows.
22 * In particular:
23 * - There is no g_shell_parse_argv() for windows. It's not hard to write one,
24 * but the command line recreated by mscvrt may be wrong.
25 * - GLib converts the argument vector to UNICODE. For non-UTF8 arguments,
26 * the result is often "Invalid string in argument vector at %d: %s: Invalid
27 * byte sequence in conversion input" (YMMV). Our tools (make, grep, gcc, ...)
28 * are "ANSI", so converting to UNICODE and then back only causes problems.
29 * - For various reasons, GLib uses an intermediate program to start children
30 * (see gspawn-win32.c), the result being that the grandchildren output (such
31 * as make -> gcc) is not captured.
32 * - With non-blocking pipes, the g_io_add_watch() callbacks are never invoked,
33 * while with blocking pipes, g_io_channel_read_line() blocks.
34 * - Some other problems are explained in separate comments below.
36 * Even under Unix, using g_io_channel_read_line() is not a good idea, since it may
37 * buffer lines of unlimited length.
39 * This module does not depend on Geany when compiled for testing (-DSPAWN_TEST).
42 /** @file spawn.h
43 * Portable and convenient process spawning and communication.
46 #ifdef HAVE_CONFIG_H
47 # include "config.h"
48 #endif
50 #include <errno.h>
51 #include <string.h>
53 #include "spawn.h"
55 #ifdef G_OS_WIN32
56 # include <ctype.h> /* isspace() */
57 # include <fcntl.h> /* _O_RDONLY, _O_WRONLY */
58 # include <io.h> /* _open_osfhandle, _close */
59 # include <windows.h>
60 #else /* G_OS_WIN32 */
61 # include <signal.h>
62 #endif /* G_OS_WIN32 */
64 #ifdef SPAWN_TEST
65 # define _
66 # define GEANY_API_SYMBOL
67 #else
68 # include "support.h"
69 #endif
71 #if ! GLIB_CHECK_VERSION(2, 31, 20) && ! defined(G_SPAWN_ERROR_TOO_BIG)
72 # define G_SPAWN_ERROR_TOO_BIG G_SPAWN_ERROR_2BIG
73 #endif
75 #ifdef G_OS_WIN32
76 /* Each 4KB under Windows seem to come in 2 portions, so 2K + 2K is more
77 balanced than 4095 + 1. May be different on the latest Windows/glib? */
78 # define DEFAULT_IO_LENGTH 2048
79 #else
80 # define DEFAULT_IO_LENGTH 4096
82 /* helper function that cuts glib citing of the original text on bad quoting: it may be long,
83 and only the caller knows whether it's UTF-8. Thought we lose the ' or " failed info. */
84 static gboolean spawn_parse_argv(const gchar *command_line, gint *argcp, gchar ***argvp,
85 GError **error)
87 GError *gerror = NULL;
89 if (g_shell_parse_argv(command_line, argcp, argvp, &gerror))
90 return TRUE;
92 g_set_error_literal(error, gerror->domain, gerror->code,
93 gerror->code == G_SHELL_ERROR_BAD_QUOTING ?
94 _("Text ended before matching quote was found") : gerror->message);
95 g_error_free(gerror);
96 return FALSE;
98 #endif
100 #define G_IO_FAILURE (G_IO_ERR | G_IO_HUP | G_IO_NVAL) /* always used together */
104 * Checks whether a command line is syntactically valid and extracts the program name from it.
106 * See @c spawn_check_command() for details.
108 * @param command_line the command line to check and get the program name from.
109 * @param error return location for error.
111 * @return allocated string with the program name on success, @c NULL on error.
113 static gchar *spawn_get_program_name(const gchar *command_line, GError **error)
115 gchar *program;
117 #ifdef G_OS_WIN32
118 gboolean open_quote = FALSE;
119 const gchar *s, *arguments;
121 g_return_val_if_fail(command_line != NULL, FALSE);
123 while (*command_line && strchr(" \t\r\n", *command_line))
124 command_line++;
126 if (!*command_line)
128 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_EMPTY_STRING,
129 /* TL note: from glib */
130 _("Text was empty (or contained only whitespace)"));
131 return FALSE;
134 /* To prevent Windows from doing something weird, we want to be 100% sure that the
135 character after the program name is a delimiter, so we allow space and tab only. */
137 if (*command_line == '"')
139 command_line++;
140 /* Windows allows "foo.exe, but we may have extra arguments */
141 if ((s = strchr(command_line, '"')) == NULL)
143 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
144 _("Text ended before matching quote was found"));
145 return FALSE;
148 if (!strchr(" \t", s[1])) /* strchr() catches s[1] == '\0' */
150 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
151 _("A quoted Windows program name must be entirely inside the quotes"));
152 return FALSE;
155 else
157 const gchar *quote = strchr(command_line, '"');
159 /* strchr() catches *s == '\0', and the for body is empty */
160 for (s = command_line; !strchr(" \t", *s); s++);
162 if (quote && quote < s)
164 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
165 _("A quoted Windows program name must be entirely inside the quotes"));
166 return FALSE;
170 program = g_strndup(command_line, s - command_line);
171 arguments = s + (*s == '"');
173 for (s = arguments; *s; s++)
175 if (*s == '"')
177 const char *slash;
179 for (slash = s; slash > arguments && slash[-1] == '\\'; slash--);
180 if ((s - slash) % 2 == 0)
181 open_quote ^= TRUE;
185 if (open_quote)
187 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
188 _("Text ended before matching quote was found"));
189 g_free(program);
190 return FALSE;
192 #else /* G_OS_WIN32 */
193 int argc;
194 char **argv;
196 if (!spawn_parse_argv(command_line, &argc, &argv, error))
197 return FALSE;
199 /* empty string results in parse error, so argv[0] is not NULL */
200 program = g_strdup(argv[0]);
201 g_strfreev(argv);
202 #endif /* G_OS_WIN32 */
204 return program;
209 * Checks whether a command line is valid.
211 * Checks if @a command_line is syntactically valid.
213 * All OS:
214 * - any leading spaces, tabs and new lines are skipped
215 * - an empty command is invalid
217 * Unix:
218 * - the standard shell quoting and escaping rules are used, see @c g_shell_parse_argv()
219 * - as a consequence, an unqouted # at the start of an argument comments to the end of line
221 * Windows:
222 * - leading carriage returns are skipped too
223 * - a quoted program name must be entirely inside the quotes. No "C:\Foo\Bar".pdf or
224 * "C:\Foo\Bar".bat, which would be executed by Windows as `C:\Foo\Bar.exe`
225 * - an unquoted program name may not contain spaces. `Foo Bar Qux` will not be considered
226 * `"Foo Bar.exe" Qux` or `"Foo Bar Qux.exe"`, depending on what executables exist, as
227 * Windows normally does.
228 * - the program name must be separated from the arguments by at least one space or tab
229 * - the standard Windows quoting and escaping rules are used: double quote is escaped with
230 * backslash, and any literal backslashes before a double quote must be duplicated.
232 * If @a execute is TRUE, also checks, using @c g_find_program_in_path(), if the program
233 * specified in @a command_line exists and is executable.
235 * @param command_line the command line to check.
236 * @param execute whether to check if the command line is really executable.
237 * @param error return location for error.
239 * @return @c TRUE on success, @c FALSE on error.
241 * @since 1.25
243 GEANY_API_SYMBOL
244 gboolean spawn_check_command(const gchar *command_line, gboolean execute, GError **error)
246 gchar *program = spawn_get_program_name(command_line, error);
248 if (!program)
249 return FALSE;
251 if (execute)
253 gchar *executable = g_find_program_in_path(program);
255 if (!executable)
257 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
258 _("Program not found"));
259 g_free(program);
260 return FALSE;
263 g_free(executable);
266 g_free(program);
267 return TRUE;
272 * Kills a process.
274 * @param pid id of the process to kill.
275 * @param error return location for error.
277 * On Unix, sends a SIGTERM to the process.
279 * On Windows, terminates the process with exit code 255 (used sometimes as "generic"
280 * error code, or for programs terminated with Ctrl+C / Ctrl+Break).
282 * @return @c TRUE on success, @c FALSE on error.
284 * @since 1.25
286 GEANY_API_SYMBOL
287 gboolean spawn_kill_process(GPid pid, GError **error)
289 #ifdef G_OS_WIN32
290 if (!TerminateProcess(pid, 255))
292 gchar *message = g_win32_error_message(GetLastError());
294 g_set_error_literal(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, message);
295 g_free(message);
296 return FALSE;
298 #else
299 if (kill(pid, SIGTERM))
301 g_set_error_literal(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, g_strerror(errno));
302 return FALSE;
304 #endif
305 return TRUE;
309 #ifdef G_OS_WIN32
310 static gchar *spawn_create_process_with_pipes(wchar_t *w_command_line, const wchar_t *w_working_directory,
311 void *w_environment, HANDLE *hprocess, int *stdin_fd, int *stdout_fd, int *stderr_fd)
313 enum { WRITE_STDIN, READ_STDOUT, READ_STDERR, READ_STDIN, WRITE_STDOUT, WRITE_STDERR };
314 STARTUPINFOW startup;
315 PROCESS_INFORMATION process;
316 HANDLE hpipe[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
317 int *fd[3] = { stdin_fd, stdout_fd, stderr_fd };
318 const char *failed; /* failed WIN32/CRTL function, if any */
319 gchar *message = NULL; /* glib WIN32/CTRL error message */
320 gchar *failure = NULL; /* full error text */
321 gboolean pipe_io;
322 int i;
324 ZeroMemory(&startup, sizeof startup);
325 startup.cb = sizeof startup;
326 pipe_io = stdin_fd || stdout_fd || stderr_fd;
328 if (pipe_io)
330 startup.dwFlags |= STARTF_USESTDHANDLES;
332 /* not all programs accept mixed NULL and non-NULL hStd*, so we create all */
333 for (i = 0; i < 3; i++)
335 static int pindex[3][2] = { { READ_STDIN, WRITE_STDIN },
336 { READ_STDOUT, WRITE_STDOUT }, { READ_STDERR, WRITE_STDERR } };
338 if (!CreatePipe(&hpipe[pindex[i][0]], &hpipe[pindex[i][1]], NULL, 0))
340 hpipe[pindex[i][0]] = hpipe[pindex[i][1]] = NULL;
341 failed = "create pipe";
342 goto leave;
345 if (fd[i])
347 static int mode[3] = { _O_WRONLY, _O_RDONLY, _O_RDONLY };
349 if ((*fd[i] = _open_osfhandle((intptr_t) hpipe[i], mode[i])) == -1)
351 failed = "convert pipe handle to file descriptor";
352 message = g_strdup(g_strerror(errno));
353 goto leave;
356 else if (!CloseHandle(hpipe[i]))
358 failed = "close pipe";
359 goto leave;
362 if (!SetHandleInformation(hpipe[i + 3], HANDLE_FLAG_INHERIT,
363 HANDLE_FLAG_INHERIT))
365 failed = "set pipe handle to inheritable";
366 goto leave;
371 startup.hStdInput = hpipe[READ_STDIN];
372 startup.hStdOutput = hpipe[WRITE_STDOUT];
373 startup.hStdError = hpipe[WRITE_STDERR];
375 if (!CreateProcessW(NULL, w_command_line, NULL, NULL, TRUE,
376 CREATE_UNICODE_ENVIRONMENT | (pipe_io ? CREATE_NO_WINDOW : 0),
377 w_environment, w_working_directory, &startup, &process))
379 failed = ""; /* report the message only */
380 /* further errors will not be reported */
382 else
384 failed = NULL;
385 CloseHandle(process.hThread); /* we don't need this */
387 if (hprocess)
388 *hprocess = process.hProcess;
389 else
390 CloseHandle(process.hProcess);
393 leave:
394 if (failed)
396 if (!message)
398 size_t len;
400 message = g_win32_error_message(GetLastError());
401 len = strlen(message);
403 /* unlike g_strerror(), the g_win32_error messages may include a final '.' */
404 if (len > 0 && message[len - 1] == '.')
405 message[len - 1] = '\0';
408 if (*failed == '\0')
409 failure = message;
410 else
412 failure = g_strdup_printf("Failed to %s (%s)", failed, message);
413 g_free(message);
417 if (pipe_io)
419 for (i = 0; i < 3; i++)
421 if (failed)
423 if (fd[i] && *fd[i] != -1)
424 _close(*fd[i]);
425 else if (hpipe[i])
426 CloseHandle(hpipe[i]);
429 if (hpipe[i + 3])
430 CloseHandle(hpipe[i + 3]);
434 return failure;
438 static void spawn_append_argument(GString *command, const char *text)
440 const char *s;
442 if (command->len)
443 g_string_append_c(command, ' ');
445 for (s = text; *s; s++)
447 /* g_ascii_isspace() fails for '\v', and locale spaces (if any) will do no harm */
448 if (*s == '"' || isspace(*s))
449 break;
452 if (*text && !*s)
453 g_string_append(command, text);
454 else
456 g_string_append_c(command, '"');
458 for (s = text; *s; s++)
460 const char *slash;
462 for (slash = s; *slash == '\\'; slash++);
464 if (slash > s)
466 g_string_append_len(command, s, slash - s);
468 if (!*slash || *slash == '"')
470 g_string_append_len(command, s, slash - s);
472 if (!*slash)
473 break;
476 s = slash;
479 if (*s == '"')
480 g_string_append_c(command, '\\');
482 g_string_append_c(command, *s);
485 g_string_append_c(command, '"');
488 #endif /* G_OS_WIN32 */
492 * Executes a child program asynchronously and setups pipes.
494 * This is the low-level spawning function. Please use @c spawn_with_callbacks() unless
495 * you need to setup specific event source(s).
497 * A command line or an argument vector must be passed. If both are present, the argument
498 * vector is appended to the command line. An empty command line is not allowed.
500 * Under Windows, if the child is a console application, and at least one file descriptor is
501 * specified, the new child console (if any) will be hidden.
503 * If a @a child_pid is passed, it's your responsibility to invoke @c g_spawn_close_pid().
505 * @param working_directory child's current working directory, or @c NULL.
506 * @param command_line child program and arguments, or @c NULL.
507 * @param argv child's argument vector, or @c NULL.
508 * @param envp child's environment, or @c NULL.
509 * @param child_pid return location for child process ID, or @c NULL.
510 * @param stdin_fd return location for file descriptor to write to child's stdin, or @c NULL.
511 * @param stdout_fd return location for file descriptor to read child's stdout, or @c NULL.
512 * @param stderr_fd return location for file descriptor to read child's stderr, or @c NULL.
513 * @param error return location for error.
515 * @return @c TRUE on success, @c FALSE on error.
517 static gboolean spawn_async_with_pipes(const gchar *working_directory, const gchar *command_line,
518 gchar **argv, gchar **envp, GPid *child_pid, gint *stdin_fd, gint *stdout_fd,
519 gint *stderr_fd, GError **error)
521 g_return_val_if_fail(command_line != NULL || argv != NULL, FALSE);
523 #ifdef G_OS_WIN32
524 GString *command;
525 GArray *w_environment;
526 wchar_t *w_working_directory = NULL;
527 wchar_t *w_command = NULL;
528 gboolean success = TRUE;
530 if (command_line)
532 gchar *program = spawn_get_program_name(command_line, error);
533 const gchar *arguments;
535 if (!program)
536 return FALSE;
538 command = g_string_new(NULL);
539 arguments = strstr(command_line, program) + strlen(program);
541 if (*arguments == '"')
543 g_string_append(command, program);
544 arguments++;
546 else
548 /* quote the first token, to avoid Windows attemps to run two or more
549 unquoted tokens as a program until an existing file name is found */
550 g_string_printf(command, "\"%s\"", program);
553 g_string_append(command, arguments);
554 g_free(program);
556 else
557 command = g_string_new(NULL);
559 w_environment = g_array_new(TRUE, FALSE, sizeof(wchar_t));
561 while (argv && *argv)
562 spawn_append_argument(command, *argv++);
564 #if defined(SPAWN_TEST) || defined(GEANY_DEBUG)
565 g_message("full spawn command line: %s", command->str);
566 #endif
568 while (envp && *envp && success)
570 glong w_entry_len;
571 wchar_t *w_entry;
572 gchar *tmp = NULL;
574 // FIXME: remove this and rely on UTF-8 input
575 if (! g_utf8_validate(*envp, -1, NULL))
577 tmp = g_locale_to_utf8(*envp, -1, NULL, NULL, NULL);
578 if (tmp)
579 *envp = tmp;
581 /* TODO: better error message */
582 w_entry = g_utf8_to_utf16(*envp, -1, NULL, &w_entry_len, error);
584 if (! w_entry)
585 success = FALSE;
586 else
588 /* copy the entry, including NUL terminator */
589 g_array_append_vals(w_environment, w_entry, w_entry_len + 1);
590 g_free(w_entry);
593 g_free(tmp);
594 envp++;
597 /* convert working directory into locale encoding */
598 if (success && working_directory)
600 GError *gerror = NULL;
601 const gchar *utf8_working_directory;
602 gchar *tmp = NULL;
604 // FIXME: remove this and rely on UTF-8 input
605 if (! g_utf8_validate(working_directory, -1, NULL))
607 tmp = g_locale_to_utf8(working_directory, -1, NULL, NULL, NULL);
608 if (tmp)
609 utf8_working_directory = tmp;
611 else
612 utf8_working_directory = working_directory;
614 w_working_directory = g_utf8_to_utf16(utf8_working_directory, -1, NULL, NULL, &gerror);
615 if (! w_working_directory)
617 /* TODO use the code below post-1.28 as it introduces a new string
618 g_set_error(error, gerror->domain, gerror->code,
619 _("Failed to convert working directory into locale encoding: %s"), gerror->message);
621 g_propagate_error(error, gerror);
622 success = FALSE;
624 g_free(tmp);
626 /* convert command into locale encoding */
627 if (success)
629 GError *gerror = NULL;
630 const gchar *utf8_cmd;
631 gchar *tmp = NULL;
633 // FIXME: remove this and rely on UTF-8 input
634 if (! g_utf8_validate(command->str, -1, NULL))
636 tmp = g_locale_to_utf8(command->str, -1, NULL, NULL, NULL);
637 if (tmp)
638 utf8_cmd = tmp;
640 else
641 utf8_cmd = command->str;
643 w_command = g_utf8_to_utf16(utf8_cmd, -1, NULL, NULL, &gerror);
644 if (! w_command)
646 /* TODO use the code below post-1.28 as it introduces a new string
647 g_set_error(error, gerror->domain, gerror->code,
648 _("Failed to convert command into locale encoding: %s"), gerror->message);
650 g_propagate_error(error, gerror);
651 success = FALSE;
655 if (success)
657 gchar *failure;
659 failure = spawn_create_process_with_pipes(w_command, w_working_directory,
660 envp ? w_environment->data : NULL, child_pid, stdin_fd, stdout_fd, stderr_fd);
662 if (failure)
664 g_set_error_literal(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, failure);
665 g_free(failure);
668 success = failure == NULL;
671 g_string_free(command, TRUE);
672 g_array_free(w_environment, TRUE);
673 g_free(w_working_directory);
674 g_free(w_command);
676 return success;
677 #else /* G_OS_WIN32 */
678 int cl_argc;
679 char **full_argv;
680 gboolean spawned;
681 GError *gerror = NULL;
683 if (command_line)
685 int argc = 0;
686 char **cl_argv;
688 if (!spawn_parse_argv(command_line, &cl_argc, &cl_argv, error))
689 return FALSE;
691 if (argv)
692 for (argc = 0; argv[argc]; argc++);
694 full_argv = g_renew(gchar *, cl_argv, cl_argc + argc + 1);
695 memcpy(full_argv + cl_argc, argv, argc * sizeof(gchar *));
696 full_argv[cl_argc + argc] = NULL;
698 else
699 full_argv = argv;
701 spawned = g_spawn_async_with_pipes(working_directory, full_argv, envp,
702 G_SPAWN_SEARCH_PATH | (child_pid ? G_SPAWN_DO_NOT_REAP_CHILD : 0), NULL, NULL,
703 child_pid, stdin_fd, stdout_fd, stderr_fd, &gerror);
705 if (!spawned)
707 gint en = 0;
708 const gchar *message = gerror->message;
710 /* try to cut glib citing of the program name or working directory: they may be long,
711 and only the caller knows whether they're UTF-8. We lose the exact chdir error. */
712 switch (gerror->code)
714 #ifdef EACCES
715 case G_SPAWN_ERROR_ACCES : en = EACCES; break;
716 #endif
717 #ifdef EPERM
718 case G_SPAWN_ERROR_PERM : en = EPERM; break;
719 #endif
720 #ifdef E2BIG
721 case G_SPAWN_ERROR_TOO_BIG : en = E2BIG; break;
722 #endif
723 #ifdef ENOEXEC
724 case G_SPAWN_ERROR_NOEXEC : en = ENOEXEC; break;
725 #endif
726 #ifdef ENAMETOOLONG
727 case G_SPAWN_ERROR_NAMETOOLONG : en = ENAMETOOLONG; break;
728 #endif
729 #ifdef ENOENT
730 case G_SPAWN_ERROR_NOENT : en = ENOENT; break;
731 #endif
732 #ifdef ENOMEM
733 case G_SPAWN_ERROR_NOMEM : en = ENOMEM; break;
734 #endif
735 #ifdef ENOTDIR
736 case G_SPAWN_ERROR_NOTDIR : en = ENOTDIR; break;
737 #endif
738 #ifdef ELOOP
739 case G_SPAWN_ERROR_LOOP : en = ELOOP; break;
740 #endif
741 #ifdef ETXTBUSY
742 case G_SPAWN_ERROR_TXTBUSY : en = ETXTBUSY; break;
743 #endif
744 #ifdef EIO
745 case G_SPAWN_ERROR_IO : en = EIO; break;
746 #endif
747 #ifdef ENFILE
748 case G_SPAWN_ERROR_NFILE : en = ENFILE; break;
749 #endif
750 #ifdef EMFILE
751 case G_SPAWN_ERROR_MFILE : en = EMFILE; break;
752 #endif
753 #ifdef EINVAL
754 case G_SPAWN_ERROR_INVAL : en = EINVAL; break;
755 #endif
756 #ifdef EISDIR
757 case G_SPAWN_ERROR_ISDIR : en = EISDIR; break;
758 #endif
759 #ifdef ELIBBAD
760 case G_SPAWN_ERROR_LIBBAD : en = ELIBBAD; break;
761 #endif
762 case G_SPAWN_ERROR_CHDIR :
764 message = _("Failed to change to the working directory");
765 break;
767 case G_SPAWN_ERROR_FAILED :
769 message = _("Unknown error executing child process");
770 break;
774 if (en)
775 message = g_strerror(en);
777 g_set_error_literal(error, gerror->domain, gerror->code, message);
778 g_error_free(gerror);
781 if (full_argv != argv)
783 full_argv[cl_argc] = NULL;
784 g_strfreev(full_argv);
787 return spawned;
788 #endif /* G_OS_WIN32 */
793 * Executes a child asynchronously.
795 * A command line or an argument vector must be passed. If both are present, the argument
796 * vector is appended to the command line. An empty command line is not allowed.
798 * If a @a child_pid is passed, it's your responsibility to invoke @c g_spawn_close_pid().
800 * @param working_directory @nullable child's current working directory, or @c NULL.
801 * @param command_line @nullable child program and arguments, or @c NULL.
802 * @param argv @nullable child's argument vector, or @c NULL.
803 * @param envp @nullable child's environment, or @c NULL.
804 * @param child_pid @out @optional return location for child process ID, or @c NULL.
805 * @param error return location for error.
807 * @return @c TRUE on success, @c FALSE on error.
809 * @since 1.25
811 GEANY_API_SYMBOL
812 gboolean spawn_async(const gchar *working_directory, const gchar *command_line, gchar **argv,
813 gchar **envp, GPid *child_pid, GError **error)
815 return spawn_async_with_pipes(working_directory, command_line, argv, envp, child_pid,
816 NULL, NULL, NULL, error);
821 * Spawn with callbacks - general event sequence:
823 * - Launch the child.
824 * - Setup any I/O callbacks and a child watch callback.
825 * - On sync execution, run a main loop.
826 * - Wait for the child to terminate.
827 * - Check for active I/O sources. If any, add a timeout source to watch them, they should
828 * become inactive real soon now that the child is dead. Otherwise, finalize immediately.
829 * - In the timeout source: check for active I/O sources and finalize if none.
832 typedef struct _SpawnChannelData
834 GIOChannel *channel; /* NULL if not created / already destroyed */
835 union
837 GIOFunc write;
838 SpawnReadFunc read;
839 } cb;
840 gpointer cb_data;
841 /* stdout/stderr only */
842 GString *buffer; /* NULL if recursive */
843 GString *line_buffer; /* NULL if char buffered */
844 gsize max_length;
845 } SpawnChannelData;
848 static void spawn_destroy_cb(gpointer data)
850 SpawnChannelData *sc = (SpawnChannelData *) data;
852 g_io_channel_shutdown(sc->channel, FALSE, NULL);
853 sc->channel = NULL;
855 if (sc->buffer)
856 g_string_free(sc->buffer, TRUE);
858 if (sc->line_buffer)
859 g_string_free(sc->line_buffer, TRUE);
863 static gboolean spawn_write_cb(GIOChannel *channel, GIOCondition condition, gpointer data)
865 SpawnChannelData *sc = (SpawnChannelData *) data;
867 if (!sc->cb.write(channel, condition, sc->cb_data))
868 return FALSE;
870 return !(condition & G_IO_FAILURE);
874 static gboolean spawn_read_cb(GIOChannel *channel, GIOCondition condition, gpointer data)
876 SpawnChannelData *sc = (SpawnChannelData *) data;
877 GString *line_buffer = sc->line_buffer;
878 GString *buffer = sc->buffer ? sc->buffer : g_string_sized_new(sc->max_length);
879 GIOCondition input_cond = condition & (G_IO_IN | G_IO_PRI);
880 GIOCondition failure_cond = condition & G_IO_FAILURE;
882 * - Normally, read only once. With IO watches, our data processing must be immediate,
883 * which may give the child time to emit more data, and a read loop may combine it into
884 * large stdout and stderr portions. Under Windows, looping blocks.
885 * - On failure, read in a loop. It won't block now, there will be no more data, and the
886 * IO watch is not guaranteed to be called again (under Windows this is the last call).
888 if (input_cond)
890 gsize chars_read;
891 GIOStatus status;
893 if (line_buffer)
895 gsize n = line_buffer->len;
897 while ((status = g_io_channel_read_chars(channel, line_buffer->str + n,
898 DEFAULT_IO_LENGTH, &chars_read, NULL)) == G_IO_STATUS_NORMAL)
900 g_string_set_size(line_buffer, n + chars_read);
902 while (n < line_buffer->len)
904 gsize line_len = 0;
906 if (n == sc->max_length)
907 line_len = n;
908 else if (strchr("\n", line_buffer->str[n])) /* '\n' or '\0' */
909 line_len = n + 1;
910 else if (n < line_buffer->len - 1 && line_buffer->str[n] == '\r')
911 line_len = n + 1 + (line_buffer->str[n + 1] == '\n');
913 if (!line_len)
914 n++;
915 else
917 g_string_append_len(buffer, line_buffer->str, line_len);
918 g_string_erase(line_buffer, 0, line_len);
919 /* input only, failures are reported separately below */
920 sc->cb.read(buffer, input_cond, sc->cb_data);
921 g_string_truncate(buffer, 0);
922 n = 0;
926 if (!failure_cond)
927 break;
930 else
932 while ((status = g_io_channel_read_chars(channel, buffer->str, sc->max_length,
933 &chars_read, NULL)) == G_IO_STATUS_NORMAL)
935 g_string_set_size(buffer, chars_read);
936 /* input only, failures are reported separately below */
937 sc->cb.read(buffer, input_cond, sc->cb_data);
939 if (!failure_cond)
940 break;
944 /* Under OSX, after child death, the read watches receive input conditions instead
945 of error conditions, so we convert the termination statuses into conditions.
946 Should not hurt the other OS. */
947 if (status == G_IO_STATUS_ERROR)
948 failure_cond |= G_IO_ERR;
949 else if (status == G_IO_STATUS_EOF)
950 failure_cond |= G_IO_HUP;
953 if (failure_cond) /* we must signal the callback */
955 if (line_buffer && line_buffer->len) /* flush the line buffer */
957 g_string_append_len(buffer, line_buffer->str, line_buffer->len);
958 /* all data may be from a previous call */
959 if (!input_cond)
960 input_cond = G_IO_IN;
962 else
964 input_cond = 0;
965 g_string_truncate(buffer, 0);
968 sc->cb.read(buffer, input_cond | failure_cond, sc->cb_data);
971 if (buffer != sc->buffer)
972 g_string_free(buffer, TRUE);
974 return !failure_cond;
978 typedef struct _SpawnWatcherData
980 SpawnChannelData sc[3]; /* stdin, stdout, stderr */
981 GChildWatchFunc exit_cb;
982 gpointer exit_data;
983 GPid pid;
984 gint exit_status;
985 GMainContext *main_context; /* NULL if async execution */
986 GMainLoop *main_loop; /* NULL if async execution */
987 } SpawnWatcherData;
990 static void spawn_finalize(SpawnWatcherData *sw)
992 if (sw->exit_cb)
993 sw->exit_cb(sw->pid, sw->exit_status, sw->exit_data);
995 if (sw->main_loop)
997 g_main_loop_quit(sw->main_loop);
998 g_main_loop_unref(sw->main_loop);
1001 g_spawn_close_pid(sw->pid);
1002 g_slice_free(SpawnWatcherData, sw);
1006 static gboolean spawn_timeout_cb(gpointer data)
1008 SpawnWatcherData *sw = (SpawnWatcherData *) data;
1009 int i;
1011 for (i = 0; i < 3; i++)
1012 if (sw->sc[i].channel)
1013 return TRUE;
1015 spawn_finalize(sw);
1016 return FALSE;
1020 static void spawn_watch_cb(GPid pid, gint status, gpointer data)
1022 SpawnWatcherData *sw = (SpawnWatcherData *) data;
1023 int i;
1025 sw->pid = pid;
1026 sw->exit_status = status;
1028 for (i = 0; i < 3; i++)
1030 if (sw->sc[i].channel)
1032 GSource *source = g_timeout_source_new(50);
1034 g_source_set_callback(source, spawn_timeout_cb, data, NULL);
1035 g_source_attach(source, sw->main_context);
1036 g_source_unref(source);
1037 return;
1041 spawn_finalize(sw);
1045 /** @girskip
1046 * Executes a child program and setups callbacks.
1048 * A command line or an argument vector must be passed. If both are present, the argument
1049 * vector is appended to the command line. An empty command line is not allowed.
1051 * The synchronous execution may not be combined with recursive callbacks.
1053 * In line buffered mode, the child input is broken on `\n`, `\r\n`, `\r`, `\0` and max length.
1055 * All I/O callbacks are guaranteed to be invoked at least once with @c G_IO_ERR, @c G_IO_HUP
1056 * or @c G_IO_NVAL set (except for a @a stdin_cb which returns @c FALSE before that). For the
1057 * non-recursive callbacks, this is guaranteed to be the last call, and may be used to free any
1058 * resources associated with the callback.
1060 * The @a stdin_cb may write to @c channel only once per invocation, only if @c G_IO_OUT is
1061 * set, and only a non-zero number of characters.
1063 * @c stdout_cb and @c stderr_cb may modify the received strings in any way, but must not
1064 * free them.
1066 * The default max lengths are 24K for line buffered stdout, 8K for line buffered stderr,
1067 * 4K for unbuffered input under Unix, and 2K for unbuffered input under Windows.
1069 * @c exit_cb is always invoked last, after all I/O callbacks.
1071 * The @a child_pid will be closed automatically, after @a exit_cb is invoked.
1073 * @param working_directory @nullable child's current working directory, or @c NULL.
1074 * @param command_line @nullable child program and arguments, or @c NULL.
1075 * @param argv @nullable child's argument vector, or @c NULL.
1076 * @param envp @nullable child's environment, or @c NULL.
1077 * @param spawn_flags flags from SpawnFlags.
1078 * @param stdin_cb @nullable callback to send data to childs's stdin, or @c NULL.
1079 * @param stdin_data data to pass to @a stdin_cb.
1080 * @param stdout_cb @nullable callback to receive child's stdout, or @c NULL.
1081 * @param stdout_data data to pass to @a stdout_cb.
1082 * @param stdout_max_length maximum data length to pass to stdout_cb, @c 0 = default.
1083 * @param stderr_cb @nullable callback to receive child's stderr, or @c NULL.
1084 * @param stderr_data data to pass to @a stderr_cb.
1085 * @param stderr_max_length maximum data length to pass to stderr_cb, @c 0 = default.
1086 * @param exit_cb @nullable callback to invoke when the child exits, or @c NULL.
1087 * @param exit_data data to pass to @a exit_cb.
1088 * @param child_pid @out @optional return location for child process ID, or @c NULL.
1089 * @param error return location for error.
1091 * @return @c TRUE on success, @c FALSE on error.
1093 * @since 1.25
1095 GEANY_API_SYMBOL
1096 gboolean spawn_with_callbacks(const gchar *working_directory, const gchar *command_line,
1097 gchar **argv, gchar **envp, SpawnFlags spawn_flags, GIOFunc stdin_cb, gpointer stdin_data,
1098 SpawnReadFunc stdout_cb, gpointer stdout_data, gsize stdout_max_length,
1099 SpawnReadFunc stderr_cb, gpointer stderr_data, gsize stderr_max_length,
1100 GChildWatchFunc exit_cb, gpointer exit_data, GPid *child_pid, GError **error)
1102 GPid pid;
1103 int pipe[3] = { -1, -1, -1 };
1105 g_return_val_if_fail(!(spawn_flags & SPAWN_RECURSIVE) || !(spawn_flags & SPAWN_SYNC),
1106 FALSE);
1108 if (spawn_async_with_pipes(working_directory, command_line, argv, envp, &pid,
1109 stdin_cb ? &pipe[0] : NULL, stdout_cb ? &pipe[1] : NULL,
1110 stderr_cb ? &pipe[2] : NULL, error))
1112 SpawnWatcherData *sw = g_slice_new0(SpawnWatcherData);
1113 gpointer cb_data[3] = { stdin_data, stdout_data, stderr_data };
1114 GSource *source;
1115 int i;
1117 sw->main_context = spawn_flags & SPAWN_SYNC ? g_main_context_new() : NULL;
1119 if (child_pid)
1120 *child_pid = pid;
1122 for (i = 0; i < 3; i++)
1124 SpawnChannelData *sc = &sw->sc[i];
1125 GIOCondition condition;
1126 GSourceFunc callback;
1128 if (pipe[i] == -1)
1129 continue;
1131 #ifdef G_OS_WIN32
1132 sc->channel = g_io_channel_win32_new_fd(pipe[i]);
1133 #else
1134 sc->channel = g_io_channel_unix_new(pipe[i]);
1135 g_io_channel_set_flags(sc->channel, G_IO_FLAG_NONBLOCK, NULL);
1136 #endif
1137 g_io_channel_set_encoding(sc->channel, NULL, NULL);
1138 /* we have our own buffers, and GIO buffering blocks under Windows */
1139 g_io_channel_set_buffered(sc->channel, FALSE);
1140 sc->cb_data = cb_data[i];
1142 if (i == 0)
1144 sc->cb.write = stdin_cb;
1145 condition = G_IO_OUT | G_IO_FAILURE;
1146 callback = (GSourceFunc) spawn_write_cb;
1148 else
1150 gboolean line_buffered = !(spawn_flags &
1151 ((SPAWN_STDOUT_UNBUFFERED >> 1) << i));
1153 condition = G_IO_IN | G_IO_PRI | G_IO_FAILURE;
1154 callback = (GSourceFunc) spawn_read_cb;
1156 if (i == 1)
1158 sc->cb.read = stdout_cb;
1159 sc->max_length = stdout_max_length ? stdout_max_length :
1160 line_buffered ? 24576 : DEFAULT_IO_LENGTH;
1162 else
1164 sc->cb.read = stderr_cb;
1165 sc->max_length = stderr_max_length ? stderr_max_length :
1166 line_buffered ? 8192 : DEFAULT_IO_LENGTH;
1169 if (line_buffered)
1171 sc->line_buffer = g_string_sized_new(sc->max_length +
1172 DEFAULT_IO_LENGTH);
1176 source = g_io_create_watch(sc->channel, condition);
1177 g_io_channel_unref(sc->channel);
1179 if (spawn_flags & (SPAWN_STDIN_RECURSIVE << i))
1180 g_source_set_can_recurse(source, TRUE);
1181 else if (i) /* to avoid new string on each call */
1182 sc->buffer = g_string_sized_new(sc->max_length);
1184 g_source_set_callback(source, callback, sc, spawn_destroy_cb);
1185 g_source_attach(source, sw->main_context);
1186 g_source_unref(source);
1189 sw->exit_cb = exit_cb;
1190 sw->exit_data = exit_data;
1191 source = g_child_watch_source_new(pid);
1192 g_source_set_callback(source, (GSourceFunc) spawn_watch_cb, sw, NULL);
1193 g_source_attach(source, sw->main_context);
1194 g_source_unref(source);
1196 if (spawn_flags & SPAWN_SYNC)
1198 sw->main_loop = g_main_loop_new(sw->main_context, FALSE);
1199 g_main_context_unref(sw->main_context);
1200 g_main_loop_run(sw->main_loop);
1203 return TRUE;
1206 return FALSE;
1211 * Writes (a portion of) the data pointed by @a data->ptr to the @a channel.
1213 * If @c G_IO_OUT in @a condition is set, and the @a data->size is > 0, attempts to write
1214 * @a data->ptr (or a portion of it, depending on the size) to the @a channel. On success,
1215 * increases ptr and decreases size with the number of characters written.
1217 * This function may converted to @c GIOFunc and passed to @c spawn_with_callbacks() as
1218 * @c stdin_cb, together with a @c SpawnWriteData for @c stdin_data. As with any other
1219 * callback data, make sure that @c stdin_data exists while the child is being executed.
1220 * (For example, on asynchronous execution, you can allocate the data in the heap, and free
1221 * it in your @c spawn_with_callbacks() @c exit_cb callback.)
1223 * @param channel the channel to write data to.
1224 * @param condition condition to check for @c G_IO_OUT.
1225 * @param data @c SpawnWriteData to write to @a channel.
1227 * @return @c TRUE if the remaining size is > 0 and @a condition does not indicate any error,
1228 * @c FALSE otherwise.
1230 * @since 1.25
1232 GEANY_API_SYMBOL
1233 gboolean spawn_write_data(GIOChannel *channel, GIOCondition condition, SpawnWriteData *data)
1235 if ((condition & G_IO_OUT) && data->size)
1237 gsize chars_written = 0;
1239 g_io_channel_write_chars(channel, data->ptr, data->size < DEFAULT_IO_LENGTH ?
1240 data->size : DEFAULT_IO_LENGTH, &chars_written, NULL);
1242 /* "This can be nonzero even if the return value is not G_IO_STATUS_NORMAL." */
1243 if (chars_written)
1245 data->ptr += chars_written;
1246 data->size -= chars_written;
1250 return data->size > 0 && !(condition & G_IO_FAILURE);
1254 static void spawn_append_gstring_cb(GString *string, GIOCondition condition, gpointer data)
1256 if (condition & (G_IO_IN | G_IO_PRI))
1257 g_string_append_len((GString *) data, string->str, string->len);
1261 static void spawn_get_exit_status_cb(G_GNUC_UNUSED GPid pid, gint status, gpointer exit_status)
1263 *(gint *) exit_status = status;
1268 * Executes a child synchronously.
1270 * A command line or an argument vector must be passed. If both are present, the argument
1271 * vector is appended to the command line. An empty command line is not allowed.
1273 * The @a stdin_data is sent to the child with @c spawn_write_data().
1275 * All output from the child, including the nul characters, is stored in @a stdout_data and
1276 * @a stderr_data (if non-NULL). Any existing data in these strings will be erased.
1278 * @param working_directory @nullable child's current working directory, or @c NULL.
1279 * @param command_line @nullable child program and arguments, or @c NULL.
1280 * @param argv @nullable child's argument vector, or @c NULL.
1281 * @param envp @nullable child's environment, or @c NULL.
1282 * @param stdin_data @nullable data to send to childs's stdin, or @c NULL.
1283 * @param stdout_data @nullable GString location to receive the child's stdout, or @c NULL.
1284 * @param stderr_data @nullable GString location to receive the child's stderr, or @c NULL.
1285 * @param exit_status @out @optional return location for the child exit code, or @c NULL.
1286 * @param error return location for error.
1288 * @return @c TRUE on success, @c FALSE on error.
1290 * @since 1.25
1292 GEANY_API_SYMBOL
1293 gboolean spawn_sync(const gchar *working_directory, const gchar *command_line, gchar **argv,
1294 gchar **envp, SpawnWriteData *stdin_data, GString *stdout_data, GString *stderr_data,
1295 gint *exit_status, GError **error)
1297 if (stdout_data)
1298 g_string_truncate(stdout_data, 0);
1299 if (stderr_data)
1300 g_string_truncate(stderr_data, 0);
1302 return spawn_with_callbacks(working_directory, command_line, argv, envp, SPAWN_SYNC |
1303 SPAWN_UNBUFFERED, stdin_data ? (GIOFunc) spawn_write_data : NULL, stdin_data,
1304 stdout_data ? spawn_append_gstring_cb : NULL, stdout_data, 0,
1305 stderr_data ? spawn_append_gstring_cb : NULL, stderr_data, 0,
1306 exit_status ? spawn_get_exit_status_cb : NULL, exit_status, NULL, error);
1310 /* tests, not part of the API */
1311 #ifdef SPAWN_TEST
1312 #include <stdio.h>
1315 static gboolean read_line(const char *prompt, char *buffer, size_t size)
1317 fputs(prompt, stderr);
1318 *buffer = '\0';
1320 if (fgets(buffer, size, stdin))
1322 char *s = strchr(buffer, '\n');
1324 if (s)
1325 *s = '\0';
1328 return *buffer;
1332 static GString *read_string(const char *prompt)
1334 char buffer[0x1000]; /* larger portions for spawn < file */
1335 GString *string = g_string_sized_new(sizeof buffer);
1337 while (read_line(prompt, buffer, sizeof buffer))
1339 if (string->len)
1340 g_string_append_c(string, '\n');
1342 g_string_append(string, buffer);
1345 if (!string->len)
1347 g_string_free(string, TRUE);
1348 string = NULL;
1351 return string;
1355 static void print_cb(GString *string, GIOCondition condition, gpointer data)
1357 if (condition & (G_IO_IN | G_IO_PRI))
1359 gsize i;
1361 printf("%s: ", (const gchar *) data);
1362 /*fputs(string->str, stdout);*/
1363 for (i = 0; i < string->len; i++)
1365 unsigned char c = (unsigned char) string->str[i];
1366 printf(c >= ' ' && c < 0x80 ? "%c" : "\\x%02x", c);
1368 putchar('\n');
1373 static void print_status(gint status)
1375 fputs("finished, ", stderr);
1377 if (SPAWN_WIFEXITED(status))
1378 fprintf(stderr, "exit code %d\n", SPAWN_WEXITSTATUS(status));
1379 else
1380 fputs("abnormal termination\n", stderr);
1384 static void exit_cb(GPid pid, gint status, G_GNUC_UNUSED gpointer data)
1386 fprintf(stderr, "process %u ", (guint) pid);
1387 print_status(status);
1391 static void watch_cb(GPid pid, gint status, gpointer data)
1393 g_spawn_close_pid(pid);
1394 exit_cb(pid, status, NULL);
1395 g_main_loop_quit((GMainLoop *) data);
1399 int main(int argc, char **argv)
1401 char *test_type;
1403 if (argc != 2)
1405 fputs("usage: spawn <test-type>\n", stderr);
1406 return 1;
1409 test_type = argv[1];
1411 if (!strcmp(test_type, "syntax") || !strcmp(test_type, "syntexec"))
1413 char command_line[0x100];
1415 while (read_line("command line: ", command_line, sizeof command_line))
1417 GError *error = NULL;
1419 if (spawn_check_command(command_line, argv[1][4] == 'e', &error))
1420 fputs("valid\n", stderr);
1421 else
1423 fprintf(stderr, "error: %s\n", error->message);
1424 g_error_free(error);
1428 else if (!strcmp(test_type, "execute"))
1430 char command_line[0x100];
1432 while (read_line("command line: ", command_line, sizeof command_line))
1434 char working_directory[0x100];
1435 char args[4][0x100];
1436 char envs[4][0x100];
1437 char *argv[] = { args[0], args[1], args[2], args[3], NULL };
1438 char *envp[] = { envs[0], envs[1], envs[2], envs[3], NULL };
1439 int i;
1440 GPid pid;
1441 GError *error = NULL;
1443 read_line("working directory: ", working_directory, sizeof working_directory);
1445 fputs("up to 4 arguments\n", stderr);
1446 for (i = 0; i < 4 && read_line("argument: ", args[i], sizeof args[i]); i++);
1447 argv[i] = NULL;
1449 fputs("up to 4 variables, or empty line for parent environment\n", stderr);
1450 for (i = 0; i < 4 && read_line("variable: ", envs[i], sizeof envs[i]); i++);
1451 envp[i] = NULL;
1453 if (spawn_async_with_pipes(*working_directory ? working_directory : NULL,
1454 *command_line ? command_line : NULL, argv, i ? envp : NULL, &pid, NULL,
1455 NULL, NULL, &error))
1457 GMainLoop *loop = g_main_loop_new(NULL, TRUE);
1459 g_child_watch_add(pid, watch_cb, loop);
1460 g_main_loop_run(loop);
1461 g_main_loop_unref(loop);
1463 else
1465 fprintf(stderr, "error: %s\n", error->message);
1466 g_error_free(error);
1470 else if (!strcmp(test_type, "redirect") || !strcmp(test_type, "redinput"))
1472 char command_line[0x100];
1473 gboolean output = test_type[4] == 'r';
1475 while (read_line("command line: ", command_line, sizeof command_line))
1477 GString *stdin_text = read_string("text to send: ");
1478 SpawnWriteData stdin_data;
1479 GError *error = NULL;
1481 if (stdin_text)
1483 stdin_data.ptr = stdin_text->str;
1484 stdin_data.size = stdin_text->len;
1487 if (!spawn_with_callbacks(NULL, command_line, NULL, NULL, SPAWN_SYNC,
1488 stdin_text ? (GIOFunc) spawn_write_data : NULL, &stdin_data,
1489 output ? print_cb : NULL, "stdout", 0, output ? print_cb : NULL,
1490 "stderr", 0, exit_cb, NULL, NULL, &error))
1492 fprintf(stderr, "error: %s\n", error->message);
1493 g_error_free(error);
1496 if (stdin_text)
1497 g_string_free(stdin_text, TRUE);
1500 else if (!strcmp(test_type, "capture"))
1502 char command_line[0x100];
1504 while (read_line("command line: ", command_line, sizeof command_line))
1506 GString *stdin_text = read_string("text to send: ");
1507 SpawnWriteData stdin_data = { NULL, 0 };
1508 GString *stdout_data = g_string_sized_new(0x10000); /* may grow */
1509 GString *stderr_data = g_string_sized_new(0x1000); /* may grow */
1510 gint exit_status;
1511 GError *error = NULL;
1513 if (stdin_text)
1515 stdin_data.ptr = stdin_text->str;
1516 stdin_data.size = stdin_text->len;
1519 if (spawn_sync(NULL, command_line, NULL, NULL, &stdin_data, stdout_data,
1520 stderr_data, &exit_status, &error))
1522 printf("stdout: %s\n", stdout_data->str);
1523 printf("stderr: %s\n", stderr_data->str);
1524 print_status(exit_status);
1526 else
1528 fprintf(stderr, "error: %s\n", error->message);
1529 g_error_free(error);
1532 if (stdin_text)
1533 g_string_free(stdin_text, TRUE);
1535 g_string_free(stdout_data, TRUE);
1536 g_string_free(stderr_data, TRUE);
1539 else
1541 fprintf(stderr, "spawn: unknown test type '%s'", argv[1]);
1542 return 1;
1545 return 0;
1547 #endif /* SPAWN_TEST */