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 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. 571 * 572 * If an error occurs, no data is returned in @standard_output, 573 * @standard_error, or @exit_status. 574 * 575 * This function calls g_spawn_async_with_pipes() internally; see that 576 * function for full details on the other parameters and details on 577 * how these functions work on Windows. 578 * 579 * Params: 580 * workingDirectory = child's current working directory, or %NULL to inherit parent's 581 * argv = child's argument vector 582 * envp = child's environment, or %NULL to inherit parent's 583 * flags = flags from #GSpawnFlags 584 * childSetup = function to run in the child just before exec() 585 * userData = user data for @child_setup 586 * standardOutput = return location for child output, or %NULL 587 * standardError = return location for child error messages, or %NULL 588 * exitStatus = return location for child exit status, as returned by waitpid(), or %NULL 589 * 590 * Returns: %TRUE on success, %FALSE if an error was set 591 * 592 * Throws: GException on failure. 593 */ 594 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) 595 { 596 char* outstandardOutput = null; 597 char* outstandardError = null; 598 GError* err = null; 599 600 auto p = g_spawn_sync(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &outstandardOutput, &outstandardError, &exitStatus, &err) != 0; 601 602 if (err !is null) 603 { 604 throw new GException( new ErrorG(err) ); 605 } 606 607 standardOutput = Str.toString(outstandardOutput); 608 standardError = Str.toString(outstandardError); 609 610 return p; 611 } 612 }