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 gio.Subprocess; 26 27 private import gio.AsyncResultIF; 28 private import gio.Cancellable; 29 private import gio.InitableIF; 30 private import gio.InitableT; 31 private import gio.InputStream; 32 private import gio.OutputStream; 33 private import glib.Bytes; 34 private import glib.ConstructionException; 35 private import glib.ErrorG; 36 private import glib.GException; 37 private import glib.Str; 38 private import gobject.ObjectG; 39 private import gtkc.gio; 40 public import gtkc.giotypes; 41 42 43 /** 44 * #GSubprocess allows the creation of and interaction with child 45 * processes. 46 * 47 * Processes can be communicated with using standard GIO-style APIs (ie: 48 * #GInputStream, #GOutputStream). There are GIO-style APIs to wait for 49 * process termination (ie: cancellable and with an asynchronous 50 * variant). 51 * 52 * There is an API to force a process to terminate, as well as a 53 * race-free API for sending UNIX signals to a subprocess. 54 * 55 * One major advantage that GIO brings over the core GLib library is 56 * comprehensive API for asynchronous I/O, such 57 * g_output_stream_splice_async(). This makes GSubprocess 58 * significantly more powerful and flexible than equivalent APIs in 59 * some other languages such as the `subprocess.py` 60 * included with Python. For example, using #GSubprocess one could 61 * create two child processes, reading standard output from the first, 62 * processing it, and writing to the input stream of the second, all 63 * without blocking the main loop. 64 * 65 * A powerful g_subprocess_communicate() API is provided similar to the 66 * `communicate()` method of `subprocess.py`. This enables very easy 67 * interaction with a subprocess that has been opened with pipes. 68 * 69 * #GSubprocess defaults to tight control over the file descriptors open 70 * in the child process, avoiding dangling-fd issues that are caused by 71 * a simple fork()/exec(). The only open file descriptors in the 72 * spawned process are ones that were explicitly specified by the 73 * #GSubprocess API (unless %G_SUBPROCESS_FLAGS_INHERIT_FDS was 74 * specified). 75 * 76 * #GSubprocess will quickly reap all child processes as they exit, 77 * avoiding "zombie processes" remaining around for long periods of 78 * time. g_subprocess_wait() can be used to wait for this to happen, 79 * but it will happen even without the call being explicitly made. 80 * 81 * As a matter of principle, #GSubprocess has no API that accepts 82 * shell-style space-separated strings. It will, however, match the 83 * typical shell behaviour of searching the PATH for executables that do 84 * not contain a directory separator in their name. 85 * 86 * #GSubprocess attempts to have a very simple API for most uses (ie: 87 * spawning a subprocess with arguments and support for most typical 88 * kinds of input and output redirection). See g_subprocess_new(). The 89 * #GSubprocessLauncher API is provided for more complicated cases 90 * (advanced types of redirection, environment variable manipulation, 91 * change of working directory, child setup functions, etc). 92 * 93 * A typical use of #GSubprocess will involve calling 94 * g_subprocess_new(), followed by g_subprocess_wait_async() or 95 * g_subprocess_wait(). After the process exits, the status can be 96 * checked using functions such as g_subprocess_get_if_exited() (which 97 * are similar to the familiar WIFEXITED-style POSIX macros). 98 * 99 * Since: 2.40 100 */ 101 public class Subprocess : ObjectG, InitableIF 102 { 103 /** the main Gtk struct */ 104 protected GSubprocess* gSubprocess; 105 106 /** Get the main Gtk struct */ 107 public GSubprocess* getSubprocessStruct(bool transferOwnership = false) 108 { 109 if (transferOwnership) 110 ownedRef = false; 111 return gSubprocess; 112 } 113 114 /** the main Gtk struct as a void* */ 115 protected override void* getStruct() 116 { 117 return cast(void*)gSubprocess; 118 } 119 120 protected override void setStruct(GObject* obj) 121 { 122 gSubprocess = cast(GSubprocess*)obj; 123 super.setStruct(obj); 124 } 125 126 /** 127 * Sets our main struct and passes it to the parent class. 128 */ 129 public this (GSubprocess* gSubprocess, bool ownedRef = false) 130 { 131 this.gSubprocess = gSubprocess; 132 super(cast(GObject*)gSubprocess, ownedRef); 133 } 134 135 // add the Initable capabilities 136 mixin InitableT!(GSubprocess); 137 138 139 /** */ 140 public static GType getType() 141 { 142 return g_subprocess_get_type(); 143 } 144 145 /** 146 * Create a new process with the given flags and argument list. 147 * 148 * The argument list is expected to be %NULL-terminated. 149 * 150 * Params: 151 * argv = commandline arguments for the subprocess 152 * flags = flags that define the behaviour of the subprocess 153 * 154 * Returns: A newly created #GSubprocess, or %NULL on error (and @error 155 * will be set) 156 * 157 * Since: 2.40 158 * 159 * Throws: GException on failure. 160 * Throws: ConstructionException GTK+ fails to create the object. 161 */ 162 public this(string[] argv, GSubprocessFlags flags) 163 { 164 GError* err = null; 165 166 auto p = g_subprocess_newv(Str.toStringzArray(argv), flags, &err); 167 168 if (err !is null) 169 { 170 throw new GException( new ErrorG(err) ); 171 } 172 173 if(p is null) 174 { 175 throw new ConstructionException("null returned by newv"); 176 } 177 178 this(cast(GSubprocess*) p, true); 179 } 180 181 /** 182 * Communicate with the subprocess until it terminates, and all input 183 * and output has been completed. 184 * 185 * If @stdin_buf is given, the subprocess must have been created with 186 * %G_SUBPROCESS_FLAGS_STDIN_PIPE. The given data is fed to the 187 * stdin of the subprocess and the pipe is closed (ie: EOF). 188 * 189 * At the same time (as not to cause blocking when dealing with large 190 * amounts of data), if %G_SUBPROCESS_FLAGS_STDOUT_PIPE or 191 * %G_SUBPROCESS_FLAGS_STDERR_PIPE were used, reads from those 192 * streams. The data that was read is returned in @stdout and/or 193 * the @stderr. 194 * 195 * If the subprocess was created with %G_SUBPROCESS_FLAGS_STDOUT_PIPE, 196 * @stdout_buf will contain the data read from stdout. Otherwise, for 197 * subprocesses not created with %G_SUBPROCESS_FLAGS_STDOUT_PIPE, 198 * @stdout_buf will be set to %NULL. Similar provisions apply to 199 * @stderr_buf and %G_SUBPROCESS_FLAGS_STDERR_PIPE. 200 * 201 * As usual, any output variable may be given as %NULL to ignore it. 202 * 203 * If you desire the stdout and stderr data to be interleaved, create 204 * the subprocess with %G_SUBPROCESS_FLAGS_STDOUT_PIPE and 205 * %G_SUBPROCESS_FLAGS_STDERR_MERGE. The merged result will be returned 206 * in @stdout_buf and @stderr_buf will be set to %NULL. 207 * 208 * In case of any error (including cancellation), %FALSE will be 209 * returned with @error set. Some or all of the stdin data may have 210 * been written. Any stdout or stderr data that has been read will be 211 * discarded. None of the out variables (aside from @error) will have 212 * been set to anything in particular and should not be inspected. 213 * 214 * In the case that %TRUE is returned, the subprocess has exited and the 215 * exit status inspection APIs (eg: g_subprocess_get_if_exited(), 216 * g_subprocess_get_exit_status()) may be used. 217 * 218 * You should not attempt to use any of the subprocess pipes after 219 * starting this function, since they may be left in strange states, 220 * even if the operation was cancelled. You should especially not 221 * attempt to interact with the pipes while the operation is in progress 222 * (either from another thread or if using the asynchronous version). 223 * 224 * Params: 225 * stdinBuf = data to send to the stdin of the subprocess, or %NULL 226 * cancellable = a #GCancellable 227 * stdoutBuf = data read from the subprocess stdout 228 * stderrBuf = data read from the subprocess stderr 229 * 230 * Returns: %TRUE if successful 231 * 232 * Since: 2.40 233 * 234 * Throws: GException on failure. 235 */ 236 public bool communicate(Bytes stdinBuf, Cancellable cancellable, out Bytes stdoutBuf, out Bytes stderrBuf) 237 { 238 GBytes* outstdoutBuf = null; 239 GBytes* outstderrBuf = null; 240 GError* err = null; 241 242 auto p = g_subprocess_communicate(gSubprocess, (stdinBuf is null) ? null : stdinBuf.getBytesStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 243 244 if (err !is null) 245 { 246 throw new GException( new ErrorG(err) ); 247 } 248 249 stdoutBuf = new Bytes(outstdoutBuf); 250 stderrBuf = new Bytes(outstderrBuf); 251 252 return p; 253 } 254 255 /** 256 * Asynchronous version of g_subprocess_communicate(). Complete 257 * invocation with g_subprocess_communicate_finish(). 258 * 259 * Params: 260 * stdinBuf = Input data, or %NULL 261 * cancellable = Cancellable 262 * callback = Callback 263 * userData = User data 264 */ 265 public void communicateAsync(Bytes stdinBuf, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 266 { 267 g_subprocess_communicate_async(gSubprocess, (stdinBuf is null) ? null : stdinBuf.getBytesStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 268 } 269 270 /** 271 * Complete an invocation of g_subprocess_communicate_async(). 272 * 273 * Params: 274 * result = Result 275 * stdoutBuf = Return location for stdout data 276 * stderrBuf = Return location for stderr data 277 * 278 * Throws: GException on failure. 279 */ 280 public bool communicateFinish(AsyncResultIF result, out Bytes stdoutBuf, out Bytes stderrBuf) 281 { 282 GBytes* outstdoutBuf = null; 283 GBytes* outstderrBuf = null; 284 GError* err = null; 285 286 auto p = g_subprocess_communicate_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 287 288 if (err !is null) 289 { 290 throw new GException( new ErrorG(err) ); 291 } 292 293 stdoutBuf = new Bytes(outstdoutBuf); 294 stderrBuf = new Bytes(outstderrBuf); 295 296 return p; 297 } 298 299 /** 300 * Like g_subprocess_communicate(), but validates the output of the 301 * process as UTF-8, and returns it as a regular NUL terminated string. 302 * 303 * Params: 304 * stdinBuf = data to send to the stdin of the subprocess, or %NULL 305 * cancellable = a #GCancellable 306 * stdoutBuf = data read from the subprocess stdout 307 * stderrBuf = data read from the subprocess stderr 308 * 309 * Throws: GException on failure. 310 */ 311 public bool communicateUtf8(string stdinBuf, Cancellable cancellable, out string stdoutBuf, out string stderrBuf) 312 { 313 char* outstdoutBuf = null; 314 char* outstderrBuf = null; 315 GError* err = null; 316 317 auto p = g_subprocess_communicate_utf8(gSubprocess, Str.toStringz(stdinBuf), (cancellable is null) ? null : cancellable.getCancellableStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 318 319 if (err !is null) 320 { 321 throw new GException( new ErrorG(err) ); 322 } 323 324 stdoutBuf = Str.toString(outstdoutBuf); 325 stderrBuf = Str.toString(outstderrBuf); 326 327 return p; 328 } 329 330 /** 331 * Asynchronous version of g_subprocess_communicate_utf8(). Complete 332 * invocation with g_subprocess_communicate_utf8_finish(). 333 * 334 * Params: 335 * stdinBuf = Input data, or %NULL 336 * cancellable = Cancellable 337 * callback = Callback 338 * userData = User data 339 */ 340 public void communicateUtf8Async(string stdinBuf, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 341 { 342 g_subprocess_communicate_utf8_async(gSubprocess, Str.toStringz(stdinBuf), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 343 } 344 345 /** 346 * Complete an invocation of g_subprocess_communicate_utf8_async(). 347 * 348 * Params: 349 * result = Result 350 * stdoutBuf = Return location for stdout data 351 * stderrBuf = Return location for stderr data 352 * 353 * Throws: GException on failure. 354 */ 355 public bool communicateUtf8Finish(AsyncResultIF result, out string stdoutBuf, out string stderrBuf) 356 { 357 char* outstdoutBuf = null; 358 char* outstderrBuf = null; 359 GError* err = null; 360 361 auto p = g_subprocess_communicate_utf8_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &outstdoutBuf, &outstderrBuf, &err) != 0; 362 363 if (err !is null) 364 { 365 throw new GException( new ErrorG(err) ); 366 } 367 368 stdoutBuf = Str.toString(outstdoutBuf); 369 stderrBuf = Str.toString(outstderrBuf); 370 371 return p; 372 } 373 374 /** 375 * Use an operating-system specific method to attempt an immediate, 376 * forceful termination of the process. There is no mechanism to 377 * determine whether or not the request itself was successful; 378 * however, you can use g_subprocess_wait() to monitor the status of 379 * the process after calling this function. 380 * 381 * On Unix, this function sends %SIGKILL. 382 * 383 * Since: 2.40 384 */ 385 public void forceExit() 386 { 387 g_subprocess_force_exit(gSubprocess); 388 } 389 390 /** 391 * Check the exit status of the subprocess, given that it exited 392 * normally. This is the value passed to the exit() system call or the 393 * return value from main. 394 * 395 * This is equivalent to the system WEXITSTATUS macro. 396 * 397 * It is an error to call this function before g_subprocess_wait() and 398 * unless g_subprocess_get_if_exited() returned %TRUE. 399 * 400 * Returns: the exit status 401 * 402 * Since: 2.40 403 */ 404 public int getExitStatus() 405 { 406 return g_subprocess_get_exit_status(gSubprocess); 407 } 408 409 /** 410 * On UNIX, returns the process ID as a decimal string. 411 * On Windows, returns the result of GetProcessId() also as a string. 412 */ 413 public string getIdentifier() 414 { 415 return Str.toString(g_subprocess_get_identifier(gSubprocess)); 416 } 417 418 /** 419 * Check if the given subprocess exited normally (ie: by way of exit() 420 * or return from main()). 421 * 422 * This is equivalent to the system WIFEXITED macro. 423 * 424 * It is an error to call this function before g_subprocess_wait() has 425 * returned. 426 * 427 * Returns: %TRUE if the case of a normal exit 428 * 429 * Since: 2.40 430 */ 431 public bool getIfExited() 432 { 433 return g_subprocess_get_if_exited(gSubprocess) != 0; 434 } 435 436 /** 437 * Check if the given subprocess terminated in response to a signal. 438 * 439 * This is equivalent to the system WIFSIGNALED macro. 440 * 441 * It is an error to call this function before g_subprocess_wait() has 442 * returned. 443 * 444 * Returns: %TRUE if the case of termination due to a signal 445 * 446 * Since: 2.40 447 */ 448 public bool getIfSignaled() 449 { 450 return g_subprocess_get_if_signaled(gSubprocess) != 0; 451 } 452 453 /** 454 * Gets the raw status code of the process, as from waitpid(). 455 * 456 * This value has no particular meaning, but it can be used with the 457 * macros defined by the system headers such as WIFEXITED. It can also 458 * be used with g_spawn_check_exit_status(). 459 * 460 * It is more likely that you want to use g_subprocess_get_if_exited() 461 * followed by g_subprocess_get_exit_status(). 462 * 463 * It is an error to call this function before g_subprocess_wait() has 464 * returned. 465 * 466 * Returns: the (meaningless) waitpid() exit status from the kernel 467 * 468 * Since: 2.40 469 */ 470 public int getStatus() 471 { 472 return g_subprocess_get_status(gSubprocess); 473 } 474 475 /** 476 * Gets the #GInputStream from which to read the stderr output of 477 * @subprocess. 478 * 479 * The process must have been created with 480 * %G_SUBPROCESS_FLAGS_STDERR_PIPE. 481 * 482 * Returns: the stderr pipe 483 * 484 * Since: 2.40 485 */ 486 public InputStream getStderrPipe() 487 { 488 auto p = g_subprocess_get_stderr_pipe(gSubprocess); 489 490 if(p is null) 491 { 492 return null; 493 } 494 495 return ObjectG.getDObject!(InputStream)(cast(GInputStream*) p); 496 } 497 498 /** 499 * Gets the #GOutputStream that you can write to in order to give data 500 * to the stdin of @subprocess. 501 * 502 * The process must have been created with 503 * %G_SUBPROCESS_FLAGS_STDIN_PIPE. 504 * 505 * Returns: the stdout pipe 506 * 507 * Since: 2.40 508 */ 509 public OutputStream getStdinPipe() 510 { 511 auto p = g_subprocess_get_stdin_pipe(gSubprocess); 512 513 if(p is null) 514 { 515 return null; 516 } 517 518 return ObjectG.getDObject!(OutputStream)(cast(GOutputStream*) p); 519 } 520 521 /** 522 * Gets the #GInputStream from which to read the stdout output of 523 * @subprocess. 524 * 525 * The process must have been created with 526 * %G_SUBPROCESS_FLAGS_STDOUT_PIPE. 527 * 528 * Returns: the stdout pipe 529 * 530 * Since: 2.40 531 */ 532 public InputStream getStdoutPipe() 533 { 534 auto p = g_subprocess_get_stdout_pipe(gSubprocess); 535 536 if(p is null) 537 { 538 return null; 539 } 540 541 return ObjectG.getDObject!(InputStream)(cast(GInputStream*) p); 542 } 543 544 /** 545 * Checks if the process was "successful". A process is considered 546 * successful if it exited cleanly with an exit status of 0, either by 547 * way of the exit() system call or return from main(). 548 * 549 * It is an error to call this function before g_subprocess_wait() has 550 * returned. 551 * 552 * Returns: %TRUE if the process exited cleanly with a exit status of 0 553 * 554 * Since: 2.40 555 */ 556 public bool getSuccessful() 557 { 558 return g_subprocess_get_successful(gSubprocess) != 0; 559 } 560 561 /** 562 * Get the signal number that caused the subprocess to terminate, given 563 * that it terminated due to a signal. 564 * 565 * This is equivalent to the system WTERMSIG macro. 566 * 567 * It is an error to call this function before g_subprocess_wait() and 568 * unless g_subprocess_get_if_signaled() returned %TRUE. 569 * 570 * Returns: the signal causing termination 571 * 572 * Since: 2.40 573 */ 574 public int getTermSig() 575 { 576 return g_subprocess_get_term_sig(gSubprocess); 577 } 578 579 /** 580 * Sends the UNIX signal @signal_num to the subprocess, if it is still 581 * running. 582 * 583 * This API is race-free. If the subprocess has terminated, it will not 584 * be signalled. 585 * 586 * This API is not available on Windows. 587 * 588 * Params: 589 * signalNum = the signal number to send 590 * 591 * Since: 2.40 592 */ 593 public void sendSignal(int signalNum) 594 { 595 g_subprocess_send_signal(gSubprocess, signalNum); 596 } 597 598 /** 599 * Synchronously wait for the subprocess to terminate. 600 * 601 * After the process terminates you can query its exit status with 602 * functions such as g_subprocess_get_if_exited() and 603 * g_subprocess_get_exit_status(). 604 * 605 * This function does not fail in the case of the subprocess having 606 * abnormal termination. See g_subprocess_wait_check() for that. 607 * 608 * Cancelling @cancellable doesn't kill the subprocess. Call 609 * g_subprocess_force_exit() if it is desirable. 610 * 611 * Params: 612 * cancellable = a #GCancellable 613 * 614 * Returns: %TRUE on success, %FALSE if @cancellable was cancelled 615 * 616 * Since: 2.40 617 * 618 * Throws: GException on failure. 619 */ 620 public bool wait(Cancellable cancellable) 621 { 622 GError* err = null; 623 624 auto p = g_subprocess_wait(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err) != 0; 625 626 if (err !is null) 627 { 628 throw new GException( new ErrorG(err) ); 629 } 630 631 return p; 632 } 633 634 /** 635 * Wait for the subprocess to terminate. 636 * 637 * This is the asynchronous version of g_subprocess_wait(). 638 * 639 * Params: 640 * cancellable = a #GCancellable, or %NULL 641 * callback = a #GAsyncReadyCallback to call when the operation is complete 642 * userData = user_data for @callback 643 * 644 * Since: 2.40 645 */ 646 public void waitAsync(Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 647 { 648 g_subprocess_wait_async(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 649 } 650 651 /** 652 * Combines g_subprocess_wait() with g_spawn_check_exit_status(). 653 * 654 * Params: 655 * cancellable = a #GCancellable 656 * 657 * Returns: %TRUE on success, %FALSE if process exited abnormally, or 658 * @cancellable was cancelled 659 * 660 * Since: 2.40 661 * 662 * Throws: GException on failure. 663 */ 664 public bool waitCheck(Cancellable cancellable) 665 { 666 GError* err = null; 667 668 auto p = g_subprocess_wait_check(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err) != 0; 669 670 if (err !is null) 671 { 672 throw new GException( new ErrorG(err) ); 673 } 674 675 return p; 676 } 677 678 /** 679 * Combines g_subprocess_wait_async() with g_spawn_check_exit_status(). 680 * 681 * This is the asynchronous version of g_subprocess_wait_check(). 682 * 683 * Params: 684 * cancellable = a #GCancellable, or %NULL 685 * callback = a #GAsyncReadyCallback to call when the operation is complete 686 * userData = user_data for @callback 687 * 688 * Since: 2.40 689 */ 690 public void waitCheckAsync(Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 691 { 692 g_subprocess_wait_check_async(gSubprocess, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 693 } 694 695 /** 696 * Collects the result of a previous call to 697 * g_subprocess_wait_check_async(). 698 * 699 * Params: 700 * result = the #GAsyncResult passed to your #GAsyncReadyCallback 701 * 702 * Returns: %TRUE if successful, or %FALSE with @error set 703 * 704 * Since: 2.40 705 * 706 * Throws: GException on failure. 707 */ 708 public bool waitCheckFinish(AsyncResultIF result) 709 { 710 GError* err = null; 711 712 auto p = g_subprocess_wait_check_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 713 714 if (err !is null) 715 { 716 throw new GException( new ErrorG(err) ); 717 } 718 719 return p; 720 } 721 722 /** 723 * Collects the result of a previous call to 724 * g_subprocess_wait_async(). 725 * 726 * Params: 727 * result = the #GAsyncResult passed to your #GAsyncReadyCallback 728 * 729 * Returns: %TRUE if successful, or %FALSE with @error set 730 * 731 * Since: 2.40 732 * 733 * Throws: GException on failure. 734 */ 735 public bool waitFinish(AsyncResultIF result) 736 { 737 GError* err = null; 738 739 auto p = g_subprocess_wait_finish(gSubprocess, (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 740 741 if (err !is null) 742 { 743 throw new GException( new ErrorG(err) ); 744 } 745 746 return p; 747 } 748 }