1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module glib.Spawn;
26 
27 private import core.stdc.stdio;
28 private import core.stdc.string;
29 private import core.thread;
30 private import glib.ErrorG;
31 private import glib.GException;
32 private import glib.Str;
33 private import glib.c.functions;
34 public  import glib.c.types;
35 private import std.string;
36 private import std.traits;
37 
38 
39 /** */
40 public class Spawn
41 {
42 	//we need fdopen.
43 	version(Posix)
44 	{
45 		private import core.sys.posix.stdio;
46 	}
47 	//fdopen for Windows is defined in glib.c.types.
48 
49 	string workingDirectory = ".";
50 	string[] argv;
51 	string[] envp;
52 	GSpawnFlags flags = SpawnFlags.SEARCH_PATH;
53 	GSpawnChildSetupFunc childSetup;
54 	void* userData;
55 	GPid childPid;
56 	FILE* standardInput;
57 	FILE* standardOutput;
58 	FILE* standardError;
59 	GError* error;
60 	int stdIn;
61 	int stdOut;
62 	int stdErr;
63 
64 	// for commandLineSync
65 	int exitStatus;
66 	char* strOutput;
67 	char* strError;
68 
69 	alias bool delegate(Spawn) ChildWatch;
70 	ChildWatch externalWatch;
71 
72 	/**
73 	 * Creates a Spawn for execution.
74 	 */
75 	public this(string program, string[] envp=null)
76 	{
77 		argv ~= program;
78 		this.envp = envp;
79 	}
80 
81 	/**
82 	 * Creates a Spawn for execution.
83 	 */
84 	public this(string[] program, string[] envp=null)
85 	{
86 		argv = program;
87 		this.envp = envp;
88 	}
89 
90 	/**
91 	 * Adds a delegate to be notified on the end of the child process.
92 	 * Params:
93 	 *    	dlg =
94 	 */
95 	public void addChildWatch(ChildWatch dlg)
96 	{
97 		externalWatch = dlg;
98 	}
99 
100 	/**
101 	 * Closes all open streams and child process.
102 	 */
103 	public void close()
104 	{
105 		if (stdIn != 0 )
106 		{
107 			fclose(standardInput);
108 			stdIn = 0;
109 		}
110 		if (stdOut != 0 )
111 		{
112 			fclose(standardOutput);
113 			stdOut = 0;
114 		}
115 		if (stdErr != 0 )
116 		{
117 			fclose(standardError);
118 			stdErr = 0;
119 		}
120 		static if ( isPointer!(GPid) )
121 		{
122 			if ( childPid !is null )
123 			{
124 				closePid(childPid);
125 				childPid = null;
126 			}
127 		}
128 		else
129 		{
130 			if ( childPid != 0 )
131 			{
132 				closePid(childPid);
133 				childPid = 0;
134 			}
135 		}
136 	}
137 
138 	/**
139 	 * Adds a parameter to the execution program
140 	 */
141 	public void addParm(string parm)
142 	{
143 		argv ~= parm;
144 	}
145 
146 	/**
147 	 * Gets the last error message
148 	 */
149 	public string getLastError()
150 	{
151 		if ( error != null )
152 		{
153 			return Str.toString(error.message);
154 		}
155 		return "";
156 	}
157 
158 	/**
159 	 * Executes the prepared process
160 	 */
161 	public int execAsyncWithPipes(
162 		ChildWatch externalWatch = null,
163 		bool delegate(string) readOutput = null,
164 	bool delegate(string) readError = null )
165 	{
166 		int result = g_spawn_async_with_pipes(
167 			Str.toStringz(workingDirectory),
168 			Str.toStringzArray(argv),
169 			Str.toStringzArray(envp),
170 			flags,
171 			childSetup,
172 			userData,
173 			&childPid,
174 			&stdIn,
175 			&stdOut,
176 			&stdErr,
177 			&error
178 		);
179 
180 		if ( result != 0 )
181 		{
182 			this.externalWatch = externalWatch;
183 			g_child_watch_add(childPid, cast(GChildWatchFunc)(&childWatchCallback), cast(void*)this);
184 			standardInput = fdopen(stdIn, Str.toStringz("w"));
185 			standardOutput = fdopen(stdOut, Str.toStringz("r"));
186 			standardError = fdopen(stdErr, Str.toStringz("r"));
187 
188 			if ( readOutput !is null )
189 			{
190 				(new ReadFile(standardOutput, readOutput)).start();
191 			}
192 			if ( readError !is null )
193 			{
194 				(new ReadFile(standardError, readError)).start();
195 			}
196 		}
197 
198 		return result;
199 	}
200 
201 	class ReadFile : Thread
202 	{
203 		bool delegate(string) read;
204 		FILE* file;
205 
206 		int lineCount;
207 
208 		this(FILE* file, bool delegate (string) read )
209 		{
210 			this.file = file;
211 			this.read = read;
212 
213 			super(&run);
214 		}
215 
216 		public void run()
217 		{
218 			string line = readLine(file);
219 			while( line !is null )
220 			{
221 				++lineCount;
222 				if ( read !is null )
223 				{
224 					read(line);
225 				}
226 				line = readLine(file);
227 			}
228 		}
229 	}
230 
231 	private string readLine(FILE* stream, int max=4096)
232 	{
233 		if ( feof(stream) )
234 		{
235 			if ( externalWatch !is null )
236 			{
237 				externalWatch(this);
238 			}
239 			return null;
240 		}
241 		string line;
242 		line.length = max+1;
243 		char* lineP = fgets(Str.toStringz(line), max, stream);
244 		if ( lineP is null )
245 		{
246 			return "";
247 		}
248 		size_t l = strlen(line.ptr);
249 		if ( l > 0 ) --l;
250 
251 		return line[0..l];
252 	}
253 
254 	extern(C) static void childWatchCallback(int pid, int status, Spawn spawn)
255 	{
256 		//writefln("Spawn.childWatchCallback %s %s", pid, status);
257 		spawn.exitStatus = status;
258 		if ( spawn.externalWatch !is null )
259 		{
260 			spawn.externalWatch(spawn);
261 		}
262 		spawn.close();
263 	}
264 
265 
266 	public bool endOfOutput()
267 	{
268 		if ( standardOutput is null ) return true;
269 		return feof(standardOutput) != 0;
270 	}
271 
272 	public bool endOfError()
273 	{
274 		if ( standardError is null ) return true;
275 		return feof(standardError) != 0;
276 	}
277 
278 	string getOutputString()
279 	{
280 		return Str.toString(strOutput);
281 	}
282 
283 	string getErrorString()
284 	{
285 		return Str.toString(strError);
286 	}
287 
288 	int getExitStatus()
289 	{
290 		return exitStatus;
291 	}
292 
293 	/**
294 	 * Executes a command synchronasly and
295 	 * optionally calls delegates for sysout, syserr and end of job
296 	 *
297 	 */
298 	public int commandLineSync(
299 		ChildWatch externalWatch = null,
300 		bool delegate(string) readOutput = null,
301 	bool delegate(string) readError = null )
302 	{
303 		string commandLine;
304 		foreach ( count, string arg; argv)
305 		{
306 			if ( count > 0 )
307 			{
308 				commandLine ~= ' ';
309 			}
310 			commandLine ~= arg;
311 		}
312 		int status = g_spawn_command_line_sync(
313 			Str.toStringz(commandLine),
314 			&strOutput,
315 			&strError,
316 			&exitStatus,
317 			&error);
318 		if ( readOutput != null )
319 		{
320 			foreach ( string line ; splitLines(Str.toString(strOutput)) )
321 			{
322 				readOutput(line);
323 			}
324 		}
325 		if ( readError != null )
326 		{
327 			foreach ( string line ; splitLines(Str.toString(strError)) )
328 			{
329 				readError(line);
330 			}
331 		}
332 		if ( externalWatch != null )
333 		{
334 			externalWatch(this);
335 		}
336 		return status;
337 	}
338 
339 	/**
340 	 */
341 
342 	/**
343 	 * See g_spawn_async_with_pipes() for a full description; this function
344 	 * simply calls the g_spawn_async_with_pipes() without any pipes.
345 	 *
346 	 * You should call g_spawn_close_pid() on the returned child process
347 	 * reference when you don't need it any more.
348 	 *
349 	 * If you are writing a GTK+ application, and the program you are spawning is a
350 	 * graphical application too, then to ensure that the spawned program opens its
351 	 * windows on the right screen, you may want to use #GdkAppLaunchContext,
352 	 * #GAppLaunchContext, or set the %DISPLAY environment variable.
353 	 *
354 	 * Note that the returned @child_pid on Windows is a handle to the child
355 	 * process and not its identifier. Process handles and process identifiers
356 	 * are different concepts on Windows.
357 	 *
358 	 * Params:
359 	 *     workingDirectory = child's current working
360 	 *         directory, or %NULL to inherit parent's
361 	 *     argv = child's argument vector
362 	 *     envp = child's environment, or %NULL to inherit parent's
363 	 *     flags = flags from #GSpawnFlags
364 	 *     childSetup = function to run in the child just before exec()
365 	 *     userData = user data for @child_setup
366 	 *     childPid = return location for child process reference, or %NULL
367 	 *
368 	 * Returns: %TRUE on success, %FALSE if error is set
369 	 *
370 	 * Throws: GException on failure.
371 	 */
372 	public static bool async(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out GPid childPid)
373 	{
374 		GError* err = null;
375 
376 		auto __p = g_spawn_async(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &childPid, &err) != 0;
377 
378 		if (err !is null)
379 		{
380 			throw new GException( new ErrorG(err) );
381 		}
382 
383 		return __p;
384 	}
385 
386 	/**
387 	 * Set @error if @exit_status indicates the child exited abnormally
388 	 * (e.g. with a nonzero exit code, or via a fatal signal).
389 	 *
390 	 * The g_spawn_sync() and g_child_watch_add() family of APIs return an
391 	 * exit status for subprocesses encoded in a platform-specific way.
392 	 * On Unix, this is guaranteed to be in the same format waitpid() returns,
393 	 * and on Windows it is guaranteed to be the result of GetExitCodeProcess().
394 	 *
395 	 * Prior to the introduction of this function in GLib 2.34, interpreting
396 	 * @exit_status required use of platform-specific APIs, which is problematic
397 	 * for software using GLib as a cross-platform layer.
398 	 *
399 	 * Additionally, many programs simply want to determine whether or not
400 	 * the child exited successfully, and either propagate a #GError or
401 	 * print a message to standard error. In that common case, this function
402 	 * can be used. Note that the error message in @error will contain
403 	 * human-readable information about the exit status.
404 	 *
405 	 * The @domain and @code of @error have special semantics in the case
406 	 * where the process has an "exit code", as opposed to being killed by
407 	 * a signal. On Unix, this happens if WIFEXITED() would be true of
408 	 * @exit_status. On Windows, it is always the case.
409 	 *
410 	 * The special semantics are that the actual exit code will be the
411 	 * code set in @error, and the domain will be %G_SPAWN_EXIT_ERROR.
412 	 * This allows you to differentiate between different exit codes.
413 	 *
414 	 * If the process was terminated by some means other than an exit
415 	 * status, the domain will be %G_SPAWN_ERROR, and the code will be
416 	 * %G_SPAWN_ERROR_FAILED.
417 	 *
418 	 * This function just offers convenience; you can of course also check
419 	 * the available platform via a macro such as %G_OS_UNIX, and use
420 	 * WIFEXITED() and WEXITSTATUS() on @exit_status directly. Do not attempt
421 	 * to scan or parse the error message string; it may be translated and/or
422 	 * change in future versions of GLib.
423 	 *
424 	 * Params:
425 	 *     exitStatus = An exit code as returned from g_spawn_sync()
426 	 *
427 	 * Returns: %TRUE if child exited successfully, %FALSE otherwise (and
428 	 *     @error will be set)
429 	 *
430 	 * Since: 2.34
431 	 *
432 	 * Throws: GException on failure.
433 	 */
434 	public static bool checkExitStatus(int exitStatus)
435 	{
436 		GError* err = null;
437 
438 		auto __p = g_spawn_check_exit_status(exitStatus, &err) != 0;
439 
440 		if (err !is null)
441 		{
442 			throw new GException( new ErrorG(err) );
443 		}
444 
445 		return __p;
446 	}
447 
448 	/**
449 	 * On some platforms, notably Windows, the #GPid type represents a resource
450 	 * which must be closed to prevent resource leaking. g_spawn_close_pid()
451 	 * is provided for this purpose. It should be used on all platforms, even
452 	 * though it doesn't do anything under UNIX.
453 	 *
454 	 * Params:
455 	 *     pid = The process reference to close
456 	 */
457 	public static void closePid(GPid pid)
458 	{
459 		g_spawn_close_pid(pid);
460 	}
461 
462 	/**
463 	 * A simple version of g_spawn_async() that parses a command line with
464 	 * g_shell_parse_argv() and passes it to g_spawn_async(). Runs a
465 	 * command line in the background. Unlike g_spawn_async(), the
466 	 * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note
467 	 * that %G_SPAWN_SEARCH_PATH can have security implications, so
468 	 * consider using g_spawn_async() directly if appropriate. Possible
469 	 * errors are those from g_shell_parse_argv() and g_spawn_async().
470 	 *
471 	 * The same concerns on Windows apply as for g_spawn_command_line_sync().
472 	 *
473 	 * Params:
474 	 *     commandLine = a command line
475 	 *
476 	 * Returns: %TRUE on success, %FALSE if error is set
477 	 *
478 	 * Throws: GException on failure.
479 	 */
480 	public static bool commandLineAsync(string commandLine)
481 	{
482 		GError* err = null;
483 
484 		auto __p = g_spawn_command_line_async(Str.toStringz(commandLine), &err) != 0;
485 
486 		if (err !is null)
487 		{
488 			throw new GException( new ErrorG(err) );
489 		}
490 
491 		return __p;
492 	}
493 
494 	/**
495 	 * A simple version of g_spawn_sync() with little-used parameters
496 	 * removed, taking a command line instead of an argument vector.  See
497 	 * g_spawn_sync() for full details. @command_line will be parsed by
498 	 * g_shell_parse_argv(). Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag
499 	 * is enabled. Note that %G_SPAWN_SEARCH_PATH can have security
500 	 * implications, so consider using g_spawn_sync() directly if
501 	 * appropriate. Possible errors are those from g_spawn_sync() and those
502 	 * from g_shell_parse_argv().
503 	 *
504 	 * If @exit_status is non-%NULL, the platform-specific exit status of
505 	 * the child is stored there; see the documentation of
506 	 * g_spawn_check_exit_status() for how to use and interpret this.
507 	 *
508 	 * On Windows, please note the implications of g_shell_parse_argv()
509 	 * parsing @command_line. Parsing is done according to Unix shell rules, not
510 	 * Windows command interpreter rules.
511 	 * Space is a separator, and backslashes are
512 	 * special. Thus you cannot simply pass a @command_line containing
513 	 * canonical Windows paths, like "c:\\program files\\app\\app.exe", as
514 	 * the backslashes will be eaten, and the space will act as a
515 	 * separator. You need to enclose such paths with single quotes, like
516 	 * "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'".
517 	 *
518 	 * Params:
519 	 *     commandLine = a command line
520 	 *     standardOutput = return location for child output
521 	 *     standardError = return location for child errors
522 	 *     exitStatus = return location for child exit status, as returned by waitpid()
523 	 *
524 	 * Returns: %TRUE on success, %FALSE if an error was set
525 	 *
526 	 * Throws: GException on failure.
527 	 */
528 	public static bool commandLineSync(string commandLine, out string standardOutput, out string standardError, out int exitStatus)
529 	{
530 		char* outstandardOutput = null;
531 		char* outstandardError = null;
532 		GError* err = null;
533 
534 		auto __p = g_spawn_command_line_sync(Str.toStringz(commandLine), &outstandardOutput, &outstandardError, &exitStatus, &err) != 0;
535 
536 		if (err !is null)
537 		{
538 			throw new GException( new ErrorG(err) );
539 		}
540 
541 		standardOutput = Str.toString(outstandardOutput);
542 		standardError = Str.toString(outstandardError);
543 
544 		return __p;
545 	}
546 
547 	/** */
548 	public static GQuark errorQuark()
549 	{
550 		return g_spawn_error_quark();
551 	}
552 
553 	/** */
554 	public static GQuark exitErrorQuark()
555 	{
556 		return g_spawn_exit_error_quark();
557 	}
558 
559 	/**
560 	 * Executes a child synchronously (waits for the child to exit before returning).
561 	 * All output from the child is stored in @standard_output and @standard_error,
562 	 * if those parameters are non-%NULL. Note that you must set the
563 	 * %G_SPAWN_STDOUT_TO_DEV_NULL and %G_SPAWN_STDERR_TO_DEV_NULL flags when
564 	 * passing %NULL for @standard_output and @standard_error.
565 	 *
566 	 * If @exit_status is non-%NULL, the platform-specific exit status of
567 	 * the child is stored there; see the documentation of
568 	 * g_spawn_check_exit_status() for how to use and interpret this.
569 	 * Note that it is invalid to pass %G_SPAWN_DO_NOT_REAP_CHILD in
570 	 * @flags, and on POSIX platforms, the same restrictions as for
571 	 * g_child_watch_source_new() apply.
572 	 *
573 	 * If an error occurs, no data is returned in @standard_output,
574 	 * @standard_error, or @exit_status.
575 	 *
576 	 * This function calls g_spawn_async_with_pipes() internally; see that
577 	 * function for full details on the other parameters and details on
578 	 * how these functions work on Windows.
579 	 *
580 	 * Params:
581 	 *     workingDirectory = child's current working
582 	 *         directory, or %NULL to inherit parent's
583 	 *     argv = child's argument vector
584 	 *     envp = child's environment, or %NULL to inherit parent's
585 	 *     flags = flags from #GSpawnFlags
586 	 *     childSetup = function to run in the child just before exec()
587 	 *     userData = user data for @child_setup
588 	 *     standardOutput = return location for child output, or %NULL
589 	 *     standardError = return location for child error messages, or %NULL
590 	 *     exitStatus = return location for child exit status, as returned by waitpid(), or %NULL
591 	 *
592 	 * Returns: %TRUE on success, %FALSE if an error was set
593 	 *
594 	 * Throws: GException on failure.
595 	 */
596 	public static bool sync(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out string standardOutput, out string standardError, out int exitStatus)
597 	{
598 		char* outstandardOutput = null;
599 		char* outstandardError = null;
600 		GError* err = null;
601 
602 		auto __p = g_spawn_sync(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &outstandardOutput, &outstandardError, &exitStatus, &err) != 0;
603 
604 		if (err !is null)
605 		{
606 			throw new GException( new ErrorG(err) );
607 		}
608 
609 		standardOutput = Str.toString(outstandardOutput);
610 		standardError = Str.toString(outstandardError);
611 
612 		return __p;
613 	}
614 
615 	/**
616 	 * Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero,
617 	 * so no FD assignments are used.
618 	 *
619 	 * Params:
620 	 *     workingDirectory = child's current working directory, or %NULL to inherit parent's, in the GLib file name encoding
621 	 *     argv = child's argument vector, in the GLib file name encoding
622 	 *     envp = child's environment, or %NULL to inherit parent's, in the GLib file name encoding
623 	 *     flags = flags from #GSpawnFlags
624 	 *     childSetup = function to run in the child just before exec()
625 	 *     userData = user data for @child_setup
626 	 *     childPid = return location for child process ID, or %NULL
627 	 *     stdinFd = file descriptor to use for child's stdin, or `-1`
628 	 *     stdoutFd = file descriptor to use for child's stdout, or `-1`
629 	 *     stderrFd = file descriptor to use for child's stderr, or `-1`
630 	 *
631 	 * Returns: %TRUE on success, %FALSE if an error was set
632 	 *
633 	 * Since: 2.58
634 	 *
635 	 * Throws: GException on failure.
636 	 */
637 	public static bool asyncWithFds(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out GPid childPid, int stdinFd, int stdoutFd, int stderrFd)
638 	{
639 		GError* err = null;
640 
641 		auto __p = g_spawn_async_with_fds(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &childPid, stdinFd, stdoutFd, stderrFd, &err) != 0;
642 
643 		if (err !is null)
644 		{
645 			throw new GException( new ErrorG(err) );
646 		}
647 
648 		return __p;
649 	}
650 }