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