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