"Fix" some GCC -Wparentheses warnings
[geany-mirror.git] / src / spawn.c
blob1560d71aecf1349db198891e0de4682ecf23bd01
1 /*
2 * spawn.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2013 The Geany contributors
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 # define geany_debug g_debug
68 #else
69 # include "support.h"
70 # include "geany.h"
71 #endif
73 #if ! GLIB_CHECK_VERSION(2, 31, 20) && ! defined(G_SPAWN_ERROR_TOO_BIG)
74 # define G_SPAWN_ERROR_TOO_BIG G_SPAWN_ERROR_2BIG
75 #endif
77 #ifdef G_OS_WIN32
78 /* Each 4KB under Windows seem to come in 2 portions, so 2K + 2K is more
79 balanced than 4095 + 1. May be different on the latest Windows/glib? */
80 # define DEFAULT_IO_LENGTH 2048
81 #else
82 # define DEFAULT_IO_LENGTH 4096
84 /* helper function that cuts glib citing of the original text on bad quoting: it may be long,
85 and only the caller knows whether it's UTF-8. Thought we lose the ' or " failed info. */
86 static gboolean spawn_parse_argv(const gchar *command_line, gint *argcp, gchar ***argvp,
87 GError **error)
89 GError *gerror = NULL;
91 if (g_shell_parse_argv(command_line, argcp, argvp, &gerror))
92 return TRUE;
94 g_set_error_literal(error, gerror->domain, gerror->code,
95 gerror->code == G_SHELL_ERROR_BAD_QUOTING ?
96 _("Text ended before matching quote was found") : gerror->message);
97 g_error_free(gerror);
98 return FALSE;
100 #endif
102 #define SPAWN_IO_FAILURE (G_IO_ERR | G_IO_HUP | G_IO_NVAL) /* always used together */
106 * Checks whether a command line is syntactically valid and extracts the program name from it.
108 * See @c spawn_check_command() for details.
110 * @param command_line the command line to check and get the program name from.
111 * @param error return location for error.
113 * @return allocated string with the program name on success, @c NULL on error.
115 static gchar *spawn_get_program_name(const gchar *command_line, GError **error)
117 gchar *program;
119 #ifdef G_OS_WIN32
120 gboolean open_quote = FALSE;
121 const gchar *s, *arguments;
123 g_return_val_if_fail(command_line != NULL, FALSE);
125 while (*command_line && strchr(" \t\r\n", *command_line))
126 command_line++;
128 if (!*command_line)
130 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_EMPTY_STRING,
131 /* TL note: from glib */
132 _("Text was empty (or contained only whitespace)"));
133 return FALSE;
136 /* To prevent Windows from doing something weird, we want to be 100% sure that the
137 character after the program name is a delimiter, so we allow space and tab only. */
139 if (*command_line == '"')
141 command_line++;
142 /* Windows allows "foo.exe, but we may have extra arguments */
143 if ((s = strchr(command_line, '"')) == NULL)
145 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
146 _("Text ended before matching quote was found"));
147 return FALSE;
150 if (!strchr(" \t", s[1])) /* strchr() catches s[1] == '\0' */
152 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
153 _("A quoted Windows program name must be entirely inside the quotes"));
154 return FALSE;
157 else
159 const gchar *quote = strchr(command_line, '"');
161 /* strchr() catches *s == '\0', and the for body is empty */
162 for (s = command_line; !strchr(" \t", *s); s++);
164 if (quote && quote < s)
166 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
167 _("A quoted Windows program name must be entirely inside the quotes"));
168 return FALSE;
172 program = g_strndup(command_line, s - command_line);
173 arguments = s + (*s == '"');
175 for (s = arguments; *s; s++)
177 if (*s == '"')
179 const char *slash;
181 for (slash = s; slash > arguments && slash[-1] == '\\'; slash--);
182 if ((s - slash) % 2 == 0)
183 open_quote ^= TRUE;
187 if (open_quote)
189 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING,
190 _("Text ended before matching quote was found"));
191 g_free(program);
192 return FALSE;
194 #else /* G_OS_WIN32 */
195 int argc;
196 char **argv;
198 if (!spawn_parse_argv(command_line, &argc, &argv, error))
199 return FALSE;
201 /* empty string results in parse error, so argv[0] is not NULL */
202 program = g_strdup(argv[0]);
203 g_strfreev(argv);
204 #endif /* G_OS_WIN32 */
206 return program;
211 * Checks whether a command line is valid.
213 * Checks if @a command_line is syntactically valid.
215 * All OS:
216 * - any leading spaces, tabs and new lines are skipped
217 * - an empty command is invalid
219 * Unix:
220 * - the standard shell quoting and escaping rules are used, see @c g_shell_parse_argv()
221 * - as a consequence, an unqouted # at the start of an argument comments to the end of line
223 * Windows:
224 * - leading carriage returns are skipped too
225 * - a quoted program name must be entirely inside the quotes. No "C:\Foo\Bar".pdf or
226 * "C:\Foo\Bar".bat, which would be executed by Windows as `C:\Foo\Bar.exe`
227 * - an unquoted program name may not contain spaces. `Foo Bar Qux` will not be considered
228 * `"Foo Bar.exe" Qux` or `"Foo Bar Qux.exe"`, depending on what executables exist, as
229 * Windows normally does.
230 * - the program name must be separated from the arguments by at least one space or tab
231 * - the standard Windows quoting and escaping rules are used: double quote is escaped with
232 * backslash, and any literal backslashes before a double quote must be duplicated.
234 * If @a execute is TRUE, also checks, using @c g_find_program_in_path(), if the program
235 * specified in @a command_line exists and is executable.
237 * @param command_line the command line to check.
238 * @param execute whether to check if the command line is really executable.
239 * @param error return location for error.
241 * @return @c TRUE on success, @c FALSE on error.
243 * @since 1.25
245 GEANY_API_SYMBOL
246 gboolean spawn_check_command(const gchar *command_line, gboolean execute, GError **error)
248 gchar *program = spawn_get_program_name(command_line, error);
250 if (!program)
251 return FALSE;
253 if (execute)
255 gchar *executable = g_find_program_in_path(program);
257 if (!executable)
259 g_set_error_literal(error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
260 _("Program not found"));
261 g_free(program);
262 return FALSE;
265 g_free(executable);
268 g_free(program);
269 return TRUE;
274 * Kills a process.
276 * @param pid id of the process to kill.
277 * @param error return location for error.
279 * On Unix, sends a SIGTERM to the process.
281 * On Windows, terminates the process with exit code 255 (used sometimes as "generic"
282 * error code, or for programs terminated with Ctrl+C / Ctrl+Break).
284 * @return @c TRUE on success, @c FALSE on error.
286 * @since 1.25
288 GEANY_API_SYMBOL
289 gboolean spawn_kill_process(GPid pid, GError **error)
291 #ifdef G_OS_WIN32
292 if (!TerminateProcess(pid, 255))
294 gchar *message = g_win32_error_message(GetLastError());
296 g_set_error_literal(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, message);
297 g_free(message);
298 return FALSE;
300 #else
301 if (kill(pid, SIGTERM))
303 g_set_error_literal(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, g_strerror(errno));
304 return FALSE;
306 #endif
307 return TRUE;
311 #ifdef G_OS_WIN32
312 static gchar *spawn_create_process_with_pipes(wchar_t *w_command_line, const wchar_t *w_working_directory,
313 void *w_environment, HANDLE *hprocess, int *stdin_fd, int *stdout_fd, int *stderr_fd)
315 enum { WRITE_STDIN, READ_STDOUT, READ_STDERR, READ_STDIN, WRITE_STDOUT, WRITE_STDERR };
316 STARTUPINFOW startup;
317 PROCESS_INFORMATION process;
318 HANDLE hpipe[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
319 int *fd[3] = { stdin_fd, stdout_fd, stderr_fd };
320 const char *failed; /* failed WIN32/CRTL function, if any */
321 gchar *message = NULL; /* glib WIN32/CTRL error message */
322 gchar *failure = NULL; /* full error text */
323 gboolean pipe_io;
324 int i;
326 ZeroMemory(&startup, sizeof startup);
327 startup.cb = sizeof startup;
328 pipe_io = stdin_fd || stdout_fd || stderr_fd;
330 if (pipe_io)
332 startup.dwFlags |= STARTF_USESTDHANDLES;
334 /* not all programs accept mixed NULL and non-NULL hStd*, so we create all */
335 for (i = 0; i < 3; i++)
337 static int pindex[3][2] = { { READ_STDIN, WRITE_STDIN },
338 { READ_STDOUT, WRITE_STDOUT }, { READ_STDERR, WRITE_STDERR } };
340 if (!CreatePipe(&hpipe[pindex[i][0]], &hpipe[pindex[i][1]], NULL, 0))
342 hpipe[pindex[i][0]] = hpipe[pindex[i][1]] = NULL;
343 failed = "create pipe";
344 goto leave;
347 if (fd[i])
349 static int mode[3] = { _O_WRONLY, _O_RDONLY, _O_RDONLY };
351 if ((*fd[i] = _open_osfhandle((intptr_t) hpipe[i], mode[i])) == -1)
353 failed = "convert pipe handle to file descriptor";
354 message = g_strdup(g_strerror(errno));
355 goto leave;
358 else if (!CloseHandle(hpipe[i]))
360 failed = "close pipe";
361 goto leave;
364 if (!SetHandleInformation(hpipe[i + 3], HANDLE_FLAG_INHERIT,
365 HANDLE_FLAG_INHERIT))
367 failed = "set pipe handle to inheritable";
368 goto leave;
373 startup.hStdInput = hpipe[READ_STDIN];
374 startup.hStdOutput = hpipe[WRITE_STDOUT];
375 startup.hStdError = hpipe[WRITE_STDERR];
377 if (!CreateProcessW(NULL, w_command_line, NULL, NULL, TRUE,
378 CREATE_UNICODE_ENVIRONMENT | (pipe_io ? CREATE_NO_WINDOW : 0),
379 w_environment, w_working_directory, &startup, &process))
381 failed = ""; /* report the message only */
382 /* further errors will not be reported */
384 else
386 failed = NULL;
387 CloseHandle(process.hThread); /* we don't need this */
389 if (hprocess)
390 *hprocess = process.hProcess;
391 else
392 CloseHandle(process.hProcess);
395 leave:
396 if (failed)
398 if (!message)
400 size_t len;
402 message = g_win32_error_message(GetLastError());
403 len = strlen(message);
405 /* unlike g_strerror(), the g_win32_error messages may include a final '.' */
406 if (len > 0 && message[len - 1] == '.')
407 message[len - 1] = '\0';
410 if (*failed == '\0')
411 failure = message;
412 else
414 failure = g_strdup_printf("Failed to %s (%s)", failed, message);
415 g_free(message);
419 if (pipe_io)
421 for (i = 0; i < 3; i++)
423 if (failed)
425 if (fd[i] && *fd[i] != -1)
426 _close(*fd[i]);
427 else if (hpipe[i])
428 CloseHandle(hpipe[i]);
431 if (hpipe[i + 3])
432 CloseHandle(hpipe[i + 3]);
436 return failure;
440 static void spawn_append_argument(GString *command, const char *text)
442 const char *s;
444 if (command->len)
445 g_string_append_c(command, ' ');
447 for (s = text; *s; s++)
449 /* g_ascii_isspace() fails for '\v', and locale spaces (if any) will do no harm */
450 if (*s == '"' || isspace(*s))
451 break;
454 if (*text && !*s)
455 g_string_append(command, text);
456 else
458 g_string_append_c(command, '"');
460 for (s = text; *s; s++)
462 const char *slash;
464 for (slash = s; *slash == '\\'; slash++);
466 if (slash > s)
468 g_string_append_len(command, s, slash - s);
470 if (!*slash || *slash == '"')
472 g_string_append_len(command, s, slash - s);
474 if (!*slash)
475 break;
478 s = slash;
481 if (*s == '"')
482 g_string_append_c(command, '\\');
484 g_string_append_c(command, *s);
487 g_string_append_c(command, '"');
490 #endif /* G_OS_WIN32 */
494 * Executes a child program asynchronously and setups pipes.
496 * This is the low-level spawning function. Please use @c spawn_with_callbacks() unless
497 * you need to setup specific event source(s).
499 * A command line or an argument vector must be passed. If both are present, the argument
500 * vector is appended to the command line. An empty command line is not allowed.
502 * Under Windows, if the child is a console application, and at least one file descriptor is
503 * specified, the new child console (if any) will be hidden.
505 * If a @a child_pid is passed, it's your responsibility to invoke @c g_spawn_close_pid().
507 * @param working_directory child's current working directory, or @c NULL.
508 * @param command_line child program and arguments, or @c NULL.
509 * @param argv child's argument vector, or @c NULL.
510 * @param envp child's environment, or @c NULL.
511 * @param child_pid return location for child process ID, or @c NULL.
512 * @param stdin_fd return location for file descriptor to write to child's stdin, or @c NULL.
513 * @param stdout_fd return location for file descriptor to read child's stdout, or @c NULL.
514 * @param stderr_fd return location for file descriptor to read child's stderr, or @c NULL.
515 * @param error return location for error.
517 * @return @c TRUE on success, @c FALSE on error.
519 static gboolean spawn_async_with_pipes(const gchar *working_directory, const gchar *command_line,
520 gchar **argv, gchar **envp, GPid *child_pid, gint *stdin_fd, gint *stdout_fd,
521 gint *stderr_fd, GError **error)
523 g_return_val_if_fail(command_line != NULL || argv != NULL, FALSE);
525 #ifdef G_OS_WIN32
526 GString *command;
527 GArray *w_environment;
528 wchar_t *w_working_directory = NULL;
529 wchar_t *w_command = NULL;
530 gboolean success = TRUE;
532 if (command_line)
534 gchar *program = spawn_get_program_name(command_line, error);
535 const gchar *arguments;
537 if (!program)
538 return FALSE;
540 command = g_string_new(NULL);
541 arguments = strstr(command_line, program) + strlen(program);
543 if (*arguments == '"')
545 g_string_append(command, program);
546 arguments++;
548 else
550 /* quote the first token, to avoid Windows attemps to run two or more
551 unquoted tokens as a program until an existing file name is found */
552 g_string_printf(command, "\"%s\"", program);
555 g_string_append(command, arguments);
556 g_free(program);
558 else
559 command = g_string_new(NULL);
561 w_environment = g_array_new(TRUE, FALSE, sizeof(wchar_t));
563 while (argv && *argv)
564 spawn_append_argument(command, *argv++);
566 #if defined(SPAWN_TEST) || defined(GEANY_DEBUG)
567 g_message("full spawn command line: %s", command->str);
568 #endif
570 while (envp && *envp && success)
572 glong w_entry_len;
573 wchar_t *w_entry;
574 gchar *tmp = NULL;
576 // FIXME: remove this and rely on UTF-8 input
577 if (! g_utf8_validate(*envp, -1, NULL))
579 tmp = g_locale_to_utf8(*envp, -1, NULL, NULL, NULL);
580 if (tmp)
581 *envp = tmp;
583 /* TODO: better error message */
584 w_entry = g_utf8_to_utf16(*envp, -1, NULL, &w_entry_len, error);
586 if (! w_entry)
587 success = FALSE;
588 else
590 /* copy the entry, including NUL terminator */
591 g_array_append_vals(w_environment, w_entry, w_entry_len + 1);
592 g_free(w_entry);
595 g_free(tmp);
596 envp++;
599 /* convert working directory into locale encoding */
600 if (success && working_directory)
602 GError *gerror = NULL;
603 const gchar *utf8_working_directory;
604 gchar *tmp = NULL;
606 // FIXME: remove this and rely on UTF-8 input
607 if (! g_utf8_validate(working_directory, -1, NULL))
609 tmp = g_locale_to_utf8(working_directory, -1, NULL, NULL, NULL);
610 if (tmp)
611 utf8_working_directory = tmp;
613 else
614 utf8_working_directory = working_directory;
616 w_working_directory = g_utf8_to_utf16(utf8_working_directory, -1, NULL, NULL, &gerror);
617 if (! w_working_directory)
619 /* TODO use the code below post-1.28 as it introduces a new string
620 g_set_error(error, gerror->domain, gerror->code,
621 _("Failed to convert working directory into locale encoding: %s"), gerror->message);
623 g_propagate_error(error, gerror);
624 success = FALSE;
626 g_free(tmp);
628 /* convert command into locale encoding */
629 if (success)
631 GError *gerror = NULL;
632 const gchar *utf8_cmd;
633 gchar *tmp = NULL;
635 // FIXME: remove this and rely on UTF-8 input
636 if (! g_utf8_validate(command->str, -1, NULL))
638 tmp = g_locale_to_utf8(command->str, -1, NULL, NULL, NULL);
639 if (tmp)
640 utf8_cmd = tmp;
642 else
643 utf8_cmd = command->str;
645 w_command = g_utf8_to_utf16(utf8_cmd, -1, NULL, NULL, &gerror);
646 if (! w_command)
648 /* TODO use the code below post-1.28 as it introduces a new string
649 g_set_error(error, gerror->domain, gerror->code,
650 _("Failed to convert command into locale encoding: %s"), gerror->message);
652 g_propagate_error(error, gerror);
653 success = FALSE;
657 if (success)
659 gchar *failure;
661 failure = spawn_create_process_with_pipes(w_command, w_working_directory,
662 envp ? w_environment->data : NULL, child_pid, stdin_fd, stdout_fd, stderr_fd);
664 if (failure)
666 g_set_error_literal(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, failure);
667 g_free(failure);
670 success = failure == NULL;
673 g_string_free(command, TRUE);
674 g_array_free(w_environment, TRUE);
675 g_free(w_working_directory);
676 g_free(w_command);
678 return success;
679 #else /* G_OS_WIN32 */
680 int cl_argc;
681 char **full_argv;
682 gboolean spawned;
683 GError *gerror = NULL;
685 if (command_line)
687 int argc = 0;
688 char **cl_argv;
690 if (!spawn_parse_argv(command_line, &cl_argc, &cl_argv, error))
691 return FALSE;
693 if (argv)
694 for (argc = 0; argv[argc]; argc++);
696 full_argv = g_renew(gchar *, cl_argv, cl_argc + argc + 1);
697 memcpy(full_argv + cl_argc, argv, argc * sizeof(gchar *));
698 full_argv[cl_argc + argc] = NULL;
700 else
701 full_argv = argv;
703 spawned = g_spawn_async_with_pipes(working_directory, full_argv, envp,
704 G_SPAWN_SEARCH_PATH | (child_pid ? G_SPAWN_DO_NOT_REAP_CHILD : 0), NULL, NULL,
705 child_pid, stdin_fd, stdout_fd, stderr_fd, &gerror);
707 if (!spawned)
709 gint en = 0;
710 const gchar *message = gerror->message;
712 /* try to cut glib citing of the program name or working directory: they may be long,
713 and only the caller knows whether they're UTF-8. We lose the exact chdir error. */
714 switch (gerror->code)
716 #ifdef EACCES
717 case G_SPAWN_ERROR_ACCES : en = EACCES; break;
718 #endif
719 #ifdef EPERM
720 case G_SPAWN_ERROR_PERM : en = EPERM; break;
721 #endif
722 #ifdef E2BIG
723 case G_SPAWN_ERROR_TOO_BIG : en = E2BIG; break;
724 #endif
725 #ifdef ENOEXEC
726 case G_SPAWN_ERROR_NOEXEC : en = ENOEXEC; break;
727 #endif
728 #ifdef ENAMETOOLONG
729 case G_SPAWN_ERROR_NAMETOOLONG : en = ENAMETOOLONG; break;
730 #endif
731 #ifdef ENOENT
732 case G_SPAWN_ERROR_NOENT : en = ENOENT; break;
733 #endif
734 #ifdef ENOMEM
735 case G_SPAWN_ERROR_NOMEM : en = ENOMEM; break;
736 #endif
737 #ifdef ENOTDIR
738 case G_SPAWN_ERROR_NOTDIR : en = ENOTDIR; break;
739 #endif
740 #ifdef ELOOP
741 case G_SPAWN_ERROR_LOOP : en = ELOOP; break;
742 #endif
743 #ifdef ETXTBUSY
744 case G_SPAWN_ERROR_TXTBUSY : en = ETXTBUSY; break;
745 #endif
746 #ifdef EIO
747 case G_SPAWN_ERROR_IO : en = EIO; break;
748 #endif
749 #ifdef ENFILE
750 case G_SPAWN_ERROR_NFILE : en = ENFILE; break;
751 #endif
752 #ifdef EMFILE
753 case G_SPAWN_ERROR_MFILE : en = EMFILE; break;
754 #endif
755 #ifdef EINVAL
756 case G_SPAWN_ERROR_INVAL : en = EINVAL; break;
757 #endif
758 #ifdef EISDIR
759 case G_SPAWN_ERROR_ISDIR : en = EISDIR; break;
760 #endif
761 #ifdef ELIBBAD
762 case G_SPAWN_ERROR_LIBBAD : en = ELIBBAD; break;
763 #endif
764 case G_SPAWN_ERROR_CHDIR :
766 message = _("Failed to change to the working directory");
767 break;
769 case G_SPAWN_ERROR_FAILED :
771 message = _("Unknown error executing child process");
772 break;
776 if (en)
777 message = g_strerror(en);
779 g_set_error_literal(error, gerror->domain, gerror->code, message);
780 g_error_free(gerror);
783 if (full_argv != argv)
785 full_argv[cl_argc] = NULL;
786 g_strfreev(full_argv);
789 return spawned;
790 #endif /* G_OS_WIN32 */
795 * Executes a child asynchronously.
797 * A command line or an argument vector must be passed. If both are present, the argument
798 * vector is appended to the command line. An empty command line is not allowed.
800 * If a @a child_pid is passed, it's your responsibility to invoke @c g_spawn_close_pid().
802 * @param working_directory @nullable child's current working directory, or @c NULL.
803 * @param command_line @nullable child program and arguments, or @c NULL.
804 * @param argv @nullable child's argument vector, or @c NULL.
805 * @param envp @nullable child's environment, or @c NULL.
806 * @param child_pid @out @optional return location for child process ID, or @c NULL.
807 * @param error return location for error.
809 * @return @c TRUE on success, @c FALSE on error.
811 * @since 1.25
813 GEANY_API_SYMBOL
814 gboolean spawn_async(const gchar *working_directory, const gchar *command_line, gchar **argv,
815 gchar **envp, GPid *child_pid, GError **error)
817 return spawn_async_with_pipes(working_directory, command_line, argv, envp, child_pid,
818 NULL, NULL, NULL, error);
823 * Spawn with callbacks - general event sequence:
825 * - Launch the child.
826 * - Setup any I/O callbacks and a child watch callback.
827 * - On sync execution, run a main loop.
828 * - Wait for the child to terminate.
829 * - Check for active I/O sources. If any, add a timeout source to watch them, they should
830 * become inactive real soon now that the child is dead. Otherwise, finalize immediately.
831 * - In the timeout source: check for active I/O sources and finalize if none.
834 typedef struct _SpawnChannelData
836 GIOChannel *channel; /* NULL if not created / already destroyed */
837 union
839 GIOFunc write;
840 SpawnReadFunc read;
841 } cb;
842 gpointer cb_data;
843 /* stdout/stderr only */
844 GString *buffer; /* NULL if recursive */
845 GString *line_buffer; /* NULL if char buffered */
846 gsize max_length;
847 /* stdout/stderr: fix continuous empty G_IO_IN-s for recursive channels */
848 guint empty_gio_ins;
849 } SpawnChannelData;
851 #define SPAWN_CHANNEL_GIO_WATCH(sc) ((sc)->empty_gio_ins < 200)
854 static void spawn_destroy_common(SpawnChannelData *sc)
856 g_io_channel_shutdown(sc->channel, FALSE, NULL);
858 if (sc->buffer)
859 g_string_free(sc->buffer, TRUE);
861 if (sc->line_buffer)
862 g_string_free(sc->line_buffer, TRUE);
866 static void spawn_timeout_destroy_cb(gpointer data)
868 SpawnChannelData *sc = (SpawnChannelData *) data;
870 spawn_destroy_common(sc);
871 g_io_channel_unref(sc->channel);
872 sc->channel = NULL;
876 static void spawn_destroy_cb(gpointer data)
878 SpawnChannelData *sc = (SpawnChannelData *) data;
880 if (SPAWN_CHANNEL_GIO_WATCH(sc))
882 spawn_destroy_common(sc);
883 sc->channel = NULL;
888 static gboolean spawn_write_cb(GIOChannel *channel, GIOCondition condition, gpointer data)
890 SpawnChannelData *sc = (SpawnChannelData *) data;
892 if (!sc->cb.write(channel, condition, sc->cb_data))
893 return FALSE;
895 return !(condition & SPAWN_IO_FAILURE);
899 static gboolean spawn_read_cb(GIOChannel *channel, GIOCondition condition, gpointer data);
901 static gboolean spawn_timeout_read_cb(gpointer data)
903 SpawnChannelData *sc = (SpawnChannelData *) data;
905 /* The solution for continuous empty G_IO_IN-s is to generate them outselves. :) */
906 return spawn_read_cb(sc->channel, G_IO_IN, data);
909 static gboolean spawn_read_cb(GIOChannel *channel, GIOCondition condition, gpointer data)
911 SpawnChannelData *sc = (SpawnChannelData *) data;
912 GString *line_buffer = sc->line_buffer;
913 GString *buffer = sc->buffer ? sc->buffer : g_string_sized_new(sc->max_length);
914 GIOCondition input_cond = condition & (G_IO_IN | G_IO_PRI);
915 GIOCondition failure_cond = condition & SPAWN_IO_FAILURE;
916 GIOStatus status = G_IO_STATUS_NORMAL;
918 * - Normally, read only once. With IO watches, our data processing must be immediate,
919 * which may give the child time to emit more data, and a read loop may combine it into
920 * large stdout and stderr portions. Under Windows, looping blocks.
921 * - On failure, read in a loop. It won't block now, there will be no more data, and the
922 * IO watch is not guaranteed to be called again (under Windows this is the last call).
923 * - When using timeout callbacks, read in a loop. Otherwise, the input processing will
924 * be limited to (1/0.050 * DEFAULT_IO_LENGTH) KB/sec, which is pretty low.
926 if (input_cond)
928 gsize chars_read;
930 if (line_buffer)
932 gsize n = line_buffer->len;
934 while ((status = g_io_channel_read_chars(channel, line_buffer->str + n,
935 DEFAULT_IO_LENGTH, &chars_read, NULL)) == G_IO_STATUS_NORMAL)
937 g_string_set_size(line_buffer, n + chars_read);
939 while (n < line_buffer->len)
941 gsize line_len = 0;
943 if (n == sc->max_length)
944 line_len = n;
945 else if (strchr("\n", line_buffer->str[n])) /* '\n' or '\0' */
946 line_len = n + 1;
947 else if (n < line_buffer->len - 1 && line_buffer->str[n] == '\r')
948 line_len = n + 1 + (line_buffer->str[n + 1] == '\n');
950 if (!line_len)
951 n++;
952 else
954 g_string_append_len(buffer, line_buffer->str, line_len);
955 g_string_erase(line_buffer, 0, line_len);
956 /* input only, failures are reported separately below */
957 sc->cb.read(buffer, input_cond, sc->cb_data);
958 g_string_truncate(buffer, 0);
959 n = 0;
963 if (SPAWN_CHANNEL_GIO_WATCH(sc) && !failure_cond)
964 break;
967 else
969 while ((status = g_io_channel_read_chars(channel, buffer->str, sc->max_length,
970 &chars_read, NULL)) == G_IO_STATUS_NORMAL)
972 g_string_set_size(buffer, chars_read);
973 /* input only, failures are reported separately below */
974 sc->cb.read(buffer, input_cond, sc->cb_data);
976 if (SPAWN_CHANNEL_GIO_WATCH(sc) && !failure_cond)
977 break;
981 /* Under OSX, after child death, the read watches receive input conditions instead
982 of error conditions, so we convert the termination statuses into conditions.
983 Should not hurt the other OS. */
984 if (status == G_IO_STATUS_ERROR)
985 failure_cond |= G_IO_ERR;
986 else if (status == G_IO_STATUS_EOF)
987 failure_cond |= G_IO_HUP;
990 if (failure_cond) /* we must signal the callback */
992 if (line_buffer && line_buffer->len) /* flush the line buffer */
994 g_string_append_len(buffer, line_buffer->str, line_buffer->len);
995 /* all data may be from a previous call */
996 if (!input_cond)
997 input_cond = G_IO_IN;
999 else
1001 input_cond = 0;
1002 g_string_truncate(buffer, 0);
1005 sc->cb.read(buffer, input_cond | failure_cond, sc->cb_data);
1007 /* Check for continuous activations with G_IO_IN | G_IO_PRI, without any
1008 data to read and without errors. If detected, switch to timeout source. */
1009 else if (SPAWN_CHANNEL_GIO_WATCH(sc) && status == G_IO_STATUS_AGAIN)
1011 sc->empty_gio_ins++;
1013 if (!SPAWN_CHANNEL_GIO_WATCH(sc))
1015 GSource *old_source = g_main_current_source();
1016 GSource *new_source = g_timeout_source_new(50);
1018 geany_debug("Switching spawn source %s ((GSource*)%p on (GIOChannel*)%p) to a timeout source",
1019 g_source_get_name(old_source), (gpointer) old_source, (gpointer)sc->channel);
1021 g_io_channel_ref(sc->channel);
1022 g_source_set_can_recurse(new_source, g_source_get_can_recurse(old_source));
1023 g_source_set_callback(new_source, spawn_timeout_read_cb, data, spawn_timeout_destroy_cb);
1024 g_source_attach(new_source, g_source_get_context(old_source));
1025 g_source_unref(new_source);
1026 failure_cond |= G_IO_ERR;
1030 if (buffer != sc->buffer)
1031 g_string_free(buffer, TRUE);
1033 return !failure_cond;
1037 typedef struct _SpawnWatcherData
1039 SpawnChannelData sc[3]; /* stdin, stdout, stderr */
1040 GChildWatchFunc exit_cb;
1041 gpointer exit_data;
1042 GPid pid;
1043 gint exit_status;
1044 GMainContext *main_context; /* NULL if async execution */
1045 GMainLoop *main_loop; /* NULL if async execution */
1046 } SpawnWatcherData;
1049 static void spawn_finalize(SpawnWatcherData *sw)
1051 if (sw->exit_cb)
1052 sw->exit_cb(sw->pid, sw->exit_status, sw->exit_data);
1054 if (sw->main_loop)
1056 g_main_loop_quit(sw->main_loop);
1057 g_main_loop_unref(sw->main_loop);
1060 g_spawn_close_pid(sw->pid);
1061 g_slice_free(SpawnWatcherData, sw);
1065 static gboolean spawn_timeout_watch_cb(gpointer data)
1067 SpawnWatcherData *sw = (SpawnWatcherData *) data;
1068 int i;
1070 for (i = 0; i < 3; i++)
1071 if (sw->sc[i].channel)
1072 return TRUE;
1074 spawn_finalize(sw);
1075 return FALSE;
1079 static void spawn_watch_cb(GPid pid, gint status, gpointer data)
1081 SpawnWatcherData *sw = (SpawnWatcherData *) data;
1082 int i;
1084 sw->pid = pid;
1085 sw->exit_status = status;
1087 for (i = 0; i < 3; i++)
1089 if (sw->sc[i].channel)
1091 GSource *source = g_timeout_source_new(50);
1093 g_source_set_callback(source, spawn_timeout_watch_cb, data, NULL);
1094 g_source_attach(source, sw->main_context);
1095 g_source_unref(source);
1096 return;
1100 spawn_finalize(sw);
1104 /** @girskip
1105 * Executes a child program and setups callbacks.
1107 * A command line or an argument vector must be passed. If both are present, the argument
1108 * vector is appended to the command line. An empty command line is not allowed.
1110 * The synchronous execution may not be combined with recursive callbacks.
1112 * In line buffered mode, the child input is broken on `\n`, `\r\n`, `\r`, `\0` and max length.
1114 * All I/O callbacks are guaranteed to be invoked at least once with @c G_IO_ERR, @c G_IO_HUP
1115 * or @c G_IO_NVAL set (except for a @a stdin_cb which returns @c FALSE before that). For the
1116 * non-recursive callbacks, this is guaranteed to be the last call, and may be used to free any
1117 * resources associated with the callback.
1119 * The @a stdin_cb may write to @c channel only once per invocation, only if @c G_IO_OUT is
1120 * set, and only a non-zero number of characters.
1122 * @c stdout_cb and @c stderr_cb may modify the received strings in any way, but must not
1123 * free them.
1125 * The default max lengths are 24K for line buffered stdout, 8K for line buffered stderr,
1126 * 4K for unbuffered input under Unix, and 2K for unbuffered input under Windows.
1128 * Due to a bug in some glib versions, the sources for recursive stdout/stderr callbacks may
1129 * be converted from child watch to timeout(50ms). No callback changes are required.
1131 * @c exit_cb is always invoked last, after all I/O callbacks.
1133 * The @a child_pid will be closed automatically, after @a exit_cb is invoked.
1135 * @param working_directory @nullable child's current working directory, or @c NULL.
1136 * @param command_line @nullable child program and arguments, or @c NULL.
1137 * @param argv @nullable child's argument vector, or @c NULL.
1138 * @param envp @nullable child's environment, or @c NULL.
1139 * @param spawn_flags flags from SpawnFlags.
1140 * @param stdin_cb @nullable callback to send data to childs's stdin, or @c NULL.
1141 * @param stdin_data data to pass to @a stdin_cb.
1142 * @param stdout_cb @nullable callback to receive child's stdout, or @c NULL.
1143 * @param stdout_data data to pass to @a stdout_cb.
1144 * @param stdout_max_length maximum data length to pass to stdout_cb, @c 0 = default.
1145 * @param stderr_cb @nullable callback to receive child's stderr, or @c NULL.
1146 * @param stderr_data data to pass to @a stderr_cb.
1147 * @param stderr_max_length maximum data length to pass to stderr_cb, @c 0 = default.
1148 * @param exit_cb @nullable callback to invoke when the child exits, or @c NULL.
1149 * @param exit_data data to pass to @a exit_cb.
1150 * @param child_pid @out @optional return location for child process ID, or @c NULL.
1151 * @param error return location for error.
1153 * @return @c TRUE on success, @c FALSE on error.
1155 * @since 1.25
1157 GEANY_API_SYMBOL
1158 gboolean spawn_with_callbacks(const gchar *working_directory, const gchar *command_line,
1159 gchar **argv, gchar **envp, SpawnFlags spawn_flags, GIOFunc stdin_cb, gpointer stdin_data,
1160 SpawnReadFunc stdout_cb, gpointer stdout_data, gsize stdout_max_length,
1161 SpawnReadFunc stderr_cb, gpointer stderr_data, gsize stderr_max_length,
1162 GChildWatchFunc exit_cb, gpointer exit_data, GPid *child_pid, GError **error)
1164 GPid pid;
1165 int pipe[3] = { -1, -1, -1 };
1167 g_return_val_if_fail(!(spawn_flags & SPAWN_RECURSIVE) || !(spawn_flags & SPAWN_SYNC),
1168 FALSE);
1170 if (spawn_async_with_pipes(working_directory, command_line, argv, envp, &pid,
1171 stdin_cb ? &pipe[0] : NULL, stdout_cb ? &pipe[1] : NULL,
1172 stderr_cb ? &pipe[2] : NULL, error))
1174 SpawnWatcherData *sw = g_slice_new0(SpawnWatcherData);
1175 gpointer cb_data[3] = { stdin_data, stdout_data, stderr_data };
1176 GSource *source;
1177 int i;
1179 sw->main_context = spawn_flags & SPAWN_SYNC ? g_main_context_new() : NULL;
1181 if (child_pid)
1182 *child_pid = pid;
1184 for (i = 0; i < 3; i++)
1186 SpawnChannelData *sc = &sw->sc[i];
1187 GIOCondition condition;
1188 GSourceFunc callback;
1190 if (pipe[i] == -1)
1191 continue;
1193 #ifdef G_OS_WIN32
1194 sc->channel = g_io_channel_win32_new_fd(pipe[i]);
1195 #else
1196 sc->channel = g_io_channel_unix_new(pipe[i]);
1197 g_io_channel_set_flags(sc->channel, G_IO_FLAG_NONBLOCK, NULL);
1198 #endif
1199 g_io_channel_set_encoding(sc->channel, NULL, NULL);
1200 /* we have our own buffers, and GIO buffering blocks under Windows */
1201 g_io_channel_set_buffered(sc->channel, FALSE);
1202 sc->cb_data = cb_data[i];
1204 if (i == 0)
1206 sc->cb.write = stdin_cb;
1207 condition = G_IO_OUT | SPAWN_IO_FAILURE;
1208 callback = (GSourceFunc) spawn_write_cb;
1210 else
1212 gboolean line_buffered = !(spawn_flags &
1213 ((SPAWN_STDOUT_UNBUFFERED >> 1) << i));
1215 condition = G_IO_IN | G_IO_PRI | SPAWN_IO_FAILURE;
1216 callback = (GSourceFunc) spawn_read_cb;
1218 if (i == 1)
1220 sc->cb.read = stdout_cb;
1221 sc->max_length = stdout_max_length ? stdout_max_length :
1222 line_buffered ? 24576 : DEFAULT_IO_LENGTH;
1224 else
1226 sc->cb.read = stderr_cb;
1227 sc->max_length = stderr_max_length ? stderr_max_length :
1228 line_buffered ? 8192 : DEFAULT_IO_LENGTH;
1231 if (line_buffered)
1233 sc->line_buffer = g_string_sized_new(sc->max_length +
1234 DEFAULT_IO_LENGTH);
1237 sc->empty_gio_ins = 0;
1240 source = g_io_create_watch(sc->channel, condition);
1241 g_io_channel_unref(sc->channel);
1243 if (spawn_flags & (SPAWN_STDIN_RECURSIVE << i))
1244 g_source_set_can_recurse(source, TRUE);
1245 else if (i) /* to avoid new string on each call */
1246 sc->buffer = g_string_sized_new(sc->max_length);
1248 g_source_set_callback(source, callback, sc, spawn_destroy_cb);
1249 g_source_attach(source, sw->main_context);
1250 g_source_unref(source);
1253 sw->exit_cb = exit_cb;
1254 sw->exit_data = exit_data;
1255 source = g_child_watch_source_new(pid);
1256 g_source_set_callback(source, (GSourceFunc) spawn_watch_cb, sw, NULL);
1257 g_source_attach(source, sw->main_context);
1258 g_source_unref(source);
1260 if (spawn_flags & SPAWN_SYNC)
1262 sw->main_loop = g_main_loop_new(sw->main_context, FALSE);
1263 g_main_context_unref(sw->main_context);
1264 g_main_loop_run(sw->main_loop);
1267 return TRUE;
1270 return FALSE;
1275 * Writes (a portion of) the data pointed by @a data->ptr to the @a channel.
1277 * If @c G_IO_OUT in @a condition is set, and the @a data->size is > 0, attempts to write
1278 * @a data->ptr (or a portion of it, depending on the size) to the @a channel. On success,
1279 * increases ptr and decreases size with the number of characters written.
1281 * This function may converted to @c GIOFunc and passed to @c spawn_with_callbacks() as
1282 * @c stdin_cb, together with a @c SpawnWriteData for @c stdin_data. As with any other
1283 * callback data, make sure that @c stdin_data exists while the child is being executed.
1284 * (For example, on asynchronous execution, you can allocate the data in the heap, and free
1285 * it in your @c spawn_with_callbacks() @c exit_cb callback.)
1287 * @param channel the channel to write data to.
1288 * @param condition condition to check for @c G_IO_OUT.
1289 * @param data @c SpawnWriteData to write to @a channel.
1291 * @return @c TRUE if the remaining size is > 0 and @a condition does not indicate any error,
1292 * @c FALSE otherwise.
1294 * @since 1.25
1296 GEANY_API_SYMBOL
1297 gboolean spawn_write_data(GIOChannel *channel, GIOCondition condition, SpawnWriteData *data)
1299 if ((condition & G_IO_OUT) && data->size)
1301 gsize chars_written = 0;
1303 g_io_channel_write_chars(channel, data->ptr, data->size < DEFAULT_IO_LENGTH ?
1304 data->size : DEFAULT_IO_LENGTH, &chars_written, NULL);
1306 /* "This can be nonzero even if the return value is not G_IO_STATUS_NORMAL." */
1307 if (chars_written)
1309 data->ptr += chars_written;
1310 data->size -= chars_written;
1314 return data->size > 0 && !(condition & SPAWN_IO_FAILURE);
1318 static void spawn_append_gstring_cb(GString *string, GIOCondition condition, gpointer data)
1320 if (condition & (G_IO_IN | G_IO_PRI))
1321 g_string_append_len((GString *) data, string->str, string->len);
1325 static void spawn_get_exit_status_cb(G_GNUC_UNUSED GPid pid, gint status, gpointer exit_status)
1327 *(gint *) exit_status = status;
1332 * Executes a child synchronously.
1334 * A command line or an argument vector must be passed. If both are present, the argument
1335 * vector is appended to the command line. An empty command line is not allowed.
1337 * The @a stdin_data is sent to the child with @c spawn_write_data().
1339 * All output from the child, including the nul characters, is stored in @a stdout_data and
1340 * @a stderr_data (if non-NULL). Any existing data in these strings will be erased.
1342 * @param working_directory @nullable child's current working directory, or @c NULL.
1343 * @param command_line @nullable child program and arguments, or @c NULL.
1344 * @param argv @nullable child's argument vector, or @c NULL.
1345 * @param envp @nullable child's environment, or @c NULL.
1346 * @param stdin_data @nullable data to send to childs's stdin, or @c NULL.
1347 * @param stdout_data @nullable GString location to receive the child's stdout, or @c NULL.
1348 * @param stderr_data @nullable GString location to receive the child's stderr, or @c NULL.
1349 * @param exit_status @out @optional return location for the child exit code, or @c NULL.
1350 * @param error return location for error.
1352 * @return @c TRUE on success, @c FALSE on error.
1354 * @since 1.25
1356 GEANY_API_SYMBOL
1357 gboolean spawn_sync(const gchar *working_directory, const gchar *command_line, gchar **argv,
1358 gchar **envp, SpawnWriteData *stdin_data, GString *stdout_data, GString *stderr_data,
1359 gint *exit_status, GError **error)
1361 if (stdout_data)
1362 g_string_truncate(stdout_data, 0);
1363 if (stderr_data)
1364 g_string_truncate(stderr_data, 0);
1366 return spawn_with_callbacks(working_directory, command_line, argv, envp, SPAWN_SYNC |
1367 SPAWN_UNBUFFERED, stdin_data ? (GIOFunc) spawn_write_data : NULL, stdin_data,
1368 stdout_data ? spawn_append_gstring_cb : NULL, stdout_data, 0,
1369 stderr_data ? spawn_append_gstring_cb : NULL, stderr_data, 0,
1370 exit_status ? spawn_get_exit_status_cb : NULL, exit_status, NULL, error);
1374 /* tests, not part of the API */
1375 #ifdef SPAWN_TEST
1376 #include <stdio.h>
1379 static gboolean read_line(const char *prompt, char *buffer, size_t size)
1381 fputs(prompt, stderr);
1382 *buffer = '\0';
1384 if (fgets(buffer, size, stdin))
1386 char *s = strchr(buffer, '\n');
1388 if (s)
1389 *s = '\0';
1392 return *buffer;
1396 static GString *read_string(const char *prompt)
1398 char buffer[0x1000]; /* larger portions for spawn < file */
1399 GString *string = g_string_sized_new(sizeof buffer);
1401 while (read_line(prompt, buffer, sizeof buffer))
1403 if (string->len)
1404 g_string_append_c(string, '\n');
1406 g_string_append(string, buffer);
1409 if (!string->len)
1411 g_string_free(string, TRUE);
1412 string = NULL;
1415 return string;
1419 static void print_cb(GString *string, GIOCondition condition, gpointer data)
1421 if (condition & (G_IO_IN | G_IO_PRI))
1423 gsize i;
1425 printf("%s: ", (const gchar *) data);
1426 /*fputs(string->str, stdout);*/
1427 for (i = 0; i < string->len; i++)
1429 unsigned char c = (unsigned char) string->str[i];
1430 printf(c >= ' ' && c < 0x80 ? "%c" : "\\x%02x", c);
1432 putchar('\n');
1437 static void print_status(gint status)
1439 fputs("finished, ", stderr);
1441 if (SPAWN_WIFEXITED(status))
1442 fprintf(stderr, "exit code %d\n", SPAWN_WEXITSTATUS(status));
1443 else
1444 fputs("abnormal termination\n", stderr);
1448 static void exit_cb(GPid pid, gint status, G_GNUC_UNUSED gpointer data)
1450 fprintf(stderr, "process %u ", (guint) pid);
1451 print_status(status);
1455 static void watch_cb(GPid pid, gint status, gpointer data)
1457 g_spawn_close_pid(pid);
1458 exit_cb(pid, status, NULL);
1459 g_main_loop_quit((GMainLoop *) data);
1463 int main(int argc, char **argv)
1465 char *test_type;
1467 if (argc != 2)
1469 fputs("usage: spawn <test-type>\n", stderr);
1470 return 1;
1473 test_type = argv[1];
1475 if (!strcmp(test_type, "syntax") || !strcmp(test_type, "syntexec"))
1477 char command_line[0x100];
1479 while (read_line("command line: ", command_line, sizeof command_line))
1481 GError *error = NULL;
1483 if (spawn_check_command(command_line, argv[1][4] == 'e', &error))
1484 fputs("valid\n", stderr);
1485 else
1487 fprintf(stderr, "error: %s\n", error->message);
1488 g_error_free(error);
1492 else if (!strcmp(test_type, "execute"))
1494 char command_line[0x100];
1496 while (read_line("command line: ", command_line, sizeof command_line))
1498 char working_directory[0x100];
1499 char args[4][0x100];
1500 char envs[4][0x100];
1501 char *argv[] = { args[0], args[1], args[2], args[3], NULL };
1502 char *envp[] = { envs[0], envs[1], envs[2], envs[3], NULL };
1503 int i;
1504 GPid pid;
1505 GError *error = NULL;
1507 read_line("working directory: ", working_directory, sizeof working_directory);
1509 fputs("up to 4 arguments\n", stderr);
1510 for (i = 0; i < 4 && read_line("argument: ", args[i], sizeof args[i]); i++);
1511 argv[i] = NULL;
1513 fputs("up to 4 variables, or empty line for parent environment\n", stderr);
1514 for (i = 0; i < 4 && read_line("variable: ", envs[i], sizeof envs[i]); i++);
1515 envp[i] = NULL;
1517 if (spawn_async_with_pipes(*working_directory ? working_directory : NULL,
1518 *command_line ? command_line : NULL, argv, i ? envp : NULL, &pid, NULL,
1519 NULL, NULL, &error))
1521 GMainLoop *loop = g_main_loop_new(NULL, TRUE);
1523 g_child_watch_add(pid, watch_cb, loop);
1524 g_main_loop_run(loop);
1525 g_main_loop_unref(loop);
1527 else
1529 fprintf(stderr, "error: %s\n", error->message);
1530 g_error_free(error);
1534 else if (!strcmp(test_type, "redirect") || !strcmp(test_type, "redinput"))
1536 char command_line[0x100];
1537 gboolean output = test_type[4] == 'r';
1539 while (read_line("command line: ", command_line, sizeof command_line))
1541 GString *stdin_text = read_string("text to send: ");
1542 SpawnWriteData stdin_data;
1543 GError *error = NULL;
1545 if (stdin_text)
1547 stdin_data.ptr = stdin_text->str;
1548 stdin_data.size = stdin_text->len;
1551 if (!spawn_with_callbacks(NULL, command_line, NULL, NULL, SPAWN_SYNC,
1552 stdin_text ? (GIOFunc) spawn_write_data : NULL, &stdin_data,
1553 output ? print_cb : NULL, "stdout", 0, output ? print_cb : NULL,
1554 "stderr", 0, exit_cb, NULL, NULL, &error))
1556 fprintf(stderr, "error: %s\n", error->message);
1557 g_error_free(error);
1560 if (stdin_text)
1561 g_string_free(stdin_text, TRUE);
1564 else if (!strcmp(test_type, "capture"))
1566 char command_line[0x100];
1568 while (read_line("command line: ", command_line, sizeof command_line))
1570 GString *stdin_text = read_string("text to send: ");
1571 SpawnWriteData stdin_data = { NULL, 0 };
1572 GString *stdout_data = g_string_sized_new(0x10000); /* may grow */
1573 GString *stderr_data = g_string_sized_new(0x1000); /* may grow */
1574 gint exit_status;
1575 GError *error = NULL;
1577 if (stdin_text)
1579 stdin_data.ptr = stdin_text->str;
1580 stdin_data.size = stdin_text->len;
1583 if (spawn_sync(NULL, command_line, NULL, NULL, &stdin_data, stdout_data,
1584 stderr_data, &exit_status, &error))
1586 printf("stdout: %s\n", stdout_data->str);
1587 printf("stderr: %s\n", stderr_data->str);
1588 print_status(exit_status);
1590 else
1592 fprintf(stderr, "error: %s\n", error->message);
1593 g_error_free(error);
1596 if (stdin_text)
1597 g_string_free(stdin_text, TRUE);
1599 g_string_free(stdout_data, TRUE);
1600 g_string_free(stderr_data, TRUE);
1603 else
1605 fprintf(stderr, "spawn: unknown test type '%s'", argv[1]);
1606 return 1;
1609 return 0;
1611 #endif /* SPAWN_TEST */