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