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