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