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 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.
571 	 *
572 	 * If an error occurs, no data is returned in @standard_output,
573 	 * @standard_error, or @exit_status.
574 	 *
575 	 * This function calls g_spawn_async_with_pipes() internally; see that
576 	 * function for full details on the other parameters and details on
577 	 * how these functions work on Windows.
578 	 *
579 	 * Params:
580 	 *     workingDirectory = child's current working directory, or %NULL to inherit parent's
581 	 *     argv = child's argument vector
582 	 *     envp = child's environment, or %NULL to inherit parent's
583 	 *     flags = flags from #GSpawnFlags
584 	 *     childSetup = function to run in the child just before exec()
585 	 *     userData = user data for @child_setup
586 	 *     standardOutput = return location for child output, or %NULL
587 	 *     standardError = return location for child error messages, or %NULL
588 	 *     exitStatus = return location for child exit status, as returned by waitpid(), or %NULL
589 	 *
590 	 * Returns: %TRUE on success, %FALSE if an error was set
591 	 *
592 	 * Throws: GException on failure.
593 	 */
594 	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)
595 	{
596 		char* outstandardOutput = null;
597 		char* outstandardError = null;
598 		GError* err = null;
599 
600 		auto p = g_spawn_sync(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &outstandardOutput, &outstandardError, &exitStatus, &err) != 0;
601 
602 		if (err !is null)
603 		{
604 			throw new GException( new ErrorG(err) );
605 		}
606 
607 		standardOutput = Str.toString(outstandardOutput);
608 		standardError = Str.toString(outstandardError);
609 
610 		return p;
611 	}
612 }