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