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