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