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