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 }