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