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