1 // Written in the D programming language.
2 
3 /**
4 Functions for starting and interacting with other processes, and for
5 working with the current process' execution environment.
6 
7 Process_handling:
8 $(UL $(LI
9     $(LREF spawnProcess) spawns a new process, optionally assigning it an
10     arbitrary set of standard input, output, and error streams.
11     The function returns immediately, leaving the child process to execute
12     in parallel with its parent.  All other functions in this module that
13     spawn processes are built around `spawnProcess`.)
14 $(LI
15     $(LREF wait) makes the parent process wait for a child process to
16     terminate.  In general one should always do this, to avoid
17     child processes becoming "zombies" when the parent process exits.
18     Scope guards are perfect for this – see the $(LREF spawnProcess)
19     documentation for examples.  $(LREF tryWait) is similar to `wait`,
20     but does not block if the process has not yet terminated.)
21 $(LI
22     $(LREF pipeProcess) also spawns a child process which runs
23     in parallel with its parent.  However, instead of taking
24     arbitrary streams, it automatically creates a set of
25     pipes that allow the parent to communicate with the child
26     through the child's standard input, output, and/or error streams.
27     This function corresponds roughly to C's `popen` function.)
28 $(LI
29     $(LREF execute) starts a new process and waits for it
30     to complete before returning.  Additionally, it captures
31     the process' standard output and error streams and returns
32     the output of these as a string.)
33 $(LI
34     $(LREF spawnShell), $(LREF pipeShell) and $(LREF executeShell) work like
35     `spawnProcess`, `pipeProcess` and `execute`, respectively,
36     except that they take a single command string and run it through
37     the current user's default command interpreter.
38     `executeShell` corresponds roughly to C's `system` function.)
39 $(LI
40     $(LREF kill) attempts to terminate a running process.)
41 )
42 
43 The following table compactly summarises the different process creation
44 functions and how they relate to each other:
45 $(BOOKTABLE,
46     $(TR $(TH )
47          $(TH Runs program directly)
48          $(TH Runs shell command))
49     $(TR $(TD Low-level process creation)
50          $(TD $(LREF spawnProcess))
51          $(TD $(LREF spawnShell)))
52     $(TR $(TD Automatic input/output redirection using pipes)
53          $(TD $(LREF pipeProcess))
54          $(TD $(LREF pipeShell)))
55     $(TR $(TD Execute and wait for completion, collect output)
56          $(TD $(LREF execute))
57          $(TD $(LREF executeShell)))
58 )
59 
60 Other_functionality:
61 $(UL
62 $(LI
63     $(LREF pipe) is used to create unidirectional pipes.)
64 $(LI
65     $(LREF environment) is an interface through which the current process'
66     environment variables can be read and manipulated.)
67 $(LI
68     $(LREF escapeShellCommand) and $(LREF escapeShellFileName) are useful
69     for constructing shell command lines in a portable way.)
70 )
71 
72 Authors:
73     $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad),
74     $(LINK2 https://github.com/schveiguy, Steven Schveighoffer),
75     $(HTTP thecybershadow.net, Vladimir Panteleev)
76 Copyright:
77     Copyright (c) 2013, the authors. All rights reserved.
78 License:
79    $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
80 Source:
81     $(PHOBOSSRC std/process.d)
82 Macros:
83     OBJECTREF=$(REF1 $0, object)
84 
85 Note:
86 Most of the functionality in this module is not available on iOS, tvOS
87 and watchOS. The only functions available on those platforms are:
88 $(LREF environment), $(LREF thisProcessID) and $(LREF thisThreadID).
89 */
90 module std.process;
91 
92 import core.thread : ThreadID;
93 
94 version (Posix)
95 {
96     import core.sys.posix.sys.wait;
97     import core.sys.posix.unistd;
98 }
99 version (Windows)
100 {
101     import core.stdc.stdio;
102     import core.sys.windows.winbase;
103     import core.sys.windows.winnt;
104     import std.utf;
105     import std.windows.syserror;
106 }
107 
108 import std.internal.cstring;
109 import std.range.primitives;
110 import std.stdio;
111 
112 version (OSX)
113     version = Darwin;
114 else version (iOS)
115 {
116     version = Darwin;
117     version = iOSDerived;
118 }
119 else version (TVOS)
120 {
121     version = Darwin;
122     version = iOSDerived;
123 }
124 else version (WatchOS)
125 {
126     version = Darwin;
127     version = iOSDerived;
128 }
129 
130 // When the DMC runtime is used, we have to use some custom functions
131 // to convert between Windows file handles and FILE*s.
132 version (Win32) version (CRuntime_DigitalMars) version = DMC_RUNTIME;
133 
134 
135 // Some of the following should be moved to druntime.
136 private
137 {
138     // Microsoft Visual C Runtime (MSVCRT) declarations.
139     version (Windows)
140     {
141         version (DMC_RUNTIME) { } else
142         {
143             import core.stdc.stdint;
144             enum
145             {
146                 STDIN_FILENO  = 0,
147                 STDOUT_FILENO = 1,
148                 STDERR_FILENO = 2,
149             }
150         }
151     }
152 
153     // POSIX API declarations.
154     version (Posix)
155     {
156         version (Darwin)
157         {
158             extern(C) char*** _NSGetEnviron() nothrow;
159             const(char**) getEnvironPtr() @trusted
160             {
161                 return *_NSGetEnviron;
162             }
163         }
164         else
165         {
166             // Made available by the C runtime:
167             extern(C) extern __gshared const char** environ;
168             const(char**) getEnvironPtr() @trusted
169             {
170                 return environ;
171             }
172         }
173 
174         @system unittest
175         {
176             import core.thread : Thread;
177             new Thread({assert(getEnvironPtr !is null);}).start();
178         }
179     }
180 } // private
181 
182 // =============================================================================
183 // Environment variable manipulation.
184 // =============================================================================
185 
186 /**
187 Manipulates _environment variables using an associative-array-like
188 interface.
189 
190 This class contains only static methods, and cannot be instantiated.
191 See below for examples of use.
192 */
193 abstract final class environment
194 {
195     static import core.sys.posix.stdlib;
196     import core.stdc.errno : errno, EINVAL;
197 
198 static:
199     /**
200     Retrieves the value of the environment variable with the given `name`.
201     ---
202     auto path = environment["PATH"];
203     ---
204 
205     Throws:
206     $(OBJECTREF Exception) if the environment variable does not exist,
207     or $(REF UTFException, std,utf) if the variable contains invalid UTF-16
208     characters (Windows only).
209 
210     See_also:
211     $(LREF environment.get), which doesn't throw on failure.
212     */
213     string opIndex(scope const(char)[] name) @safe
214     {
215         import std.exception : enforce;
216         string value;
217         enforce(getImpl(name, value), "Environment variable not found: "~name);
218         return value;
219     }
220 
221     /**
222     Retrieves the value of the environment variable with the given `name`,
223     or a default value if the variable doesn't exist.
224 
225     Unlike $(LREF environment.opIndex), this function never throws on Posix.
226     ---
227     auto sh = environment.get("SHELL", "/bin/sh");
228     ---
229     This function is also useful in checking for the existence of an
230     environment variable.
231     ---
232     auto myVar = environment.get("MYVAR");
233     if (myVar is null)
234     {
235         // Environment variable doesn't exist.
236         // Note that we have to use 'is' for the comparison, since
237         // myVar == null is also true if the variable exists but is
238         // empty.
239     }
240     ---
241     Params:
242         name = name of the environment variable to retrieve
243         defaultValue = default value to return if the environment variable doesn't exist.
244 
245     Returns:
246         the value of the environment variable if found, otherwise
247         `null` if the environment doesn't exist.
248 
249     Throws:
250     $(REF UTFException, std,utf) if the variable contains invalid UTF-16
251     characters (Windows only).
252     */
253     string get(scope const(char)[] name, string defaultValue = null) @safe
254     {
255         string value;
256         auto found = getImpl(name, value);
257         return found ? value : defaultValue;
258     }
259 
260     /**
261     Assigns the given `value` to the environment variable with the given
262     `name`.
263     If `value` is null the variable is removed from environment.
264 
265     If the variable does not exist, it will be created. If it already exists,
266     it will be overwritten.
267     ---
268     environment["foo"] = "bar";
269     ---
270 
271     Throws:
272     $(OBJECTREF Exception) if the environment variable could not be added
273         (e.g. if the name is invalid).
274 
275     Note:
276     On some platforms, modifying environment variables may not be allowed in
277     multi-threaded programs. See e.g.
278     $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
279     */
280     inout(char)[] opIndexAssign(inout char[] value, scope const(char)[] name) @trusted
281     {
282         version (Posix)
283         {
284             import std.exception : enforce, errnoEnforce;
285             if (value is null)
286             {
287                 remove(name);
288                 return value;
289             }
290             if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1)
291             {
292                 return value;
293             }
294             // The default errno error message is very uninformative
295             // in the most common case, so we handle it manually.
296             enforce(errno != EINVAL,
297                 "Invalid environment variable name: '"~name~"'");
298             errnoEnforce(false,
299                 "Failed to add environment variable");
300             assert(0);
301         }
302         else version (Windows)
303         {
304             import std.exception : enforce;
305             enforce(
306                 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
307                 sysErrorString(GetLastError())
308             );
309             return value;
310         }
311         else static assert(0);
312     }
313 
314     /**
315     Removes the environment variable with the given `name`.
316 
317     If the variable isn't in the environment, this function returns
318     successfully without doing anything.
319 
320     Note:
321     On some platforms, modifying environment variables may not be allowed in
322     multi-threaded programs. See e.g.
323     $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
324     */
325     void remove(scope const(char)[] name) @trusted nothrow @nogc // TODO: @safe
326     {
327         version (Windows)    SetEnvironmentVariableW(name.tempCStringW(), null);
328         else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString());
329         else static assert(0);
330     }
331 
332     /**
333     Identify whether a variable is defined in the environment.
334 
335     Because it doesn't return the value, this function is cheaper than `get`.
336     However, if you do need the value as well, you should just check the
337     return of `get` for `null` instead of using this function first.
338 
339     Example:
340     -------------
341     // good usage
342     if ("MY_ENV_FLAG" in environment)
343         doSomething();
344 
345     // bad usage
346     if ("MY_ENV_VAR" in environment)
347         doSomething(environment["MY_ENV_VAR"]);
348 
349     // do this instead
350     if (auto var = environment.get("MY_ENV_VAR"))
351         doSomething(var);
352     -------------
353     */
354     bool opBinaryRight(string op : "in")(scope const(char)[] name) @trusted
355     {
356         version (Posix)
357             return core.sys.posix.stdlib.getenv(name.tempCString()) !is null;
358         else version (Windows)
359         {
360             SetLastError(NO_ERROR);
361             if (GetEnvironmentVariableW(name.tempCStringW, null, 0) > 0)
362                 return true;
363             immutable err = GetLastError();
364             if (err == NO_ERROR)
365                 return true; // zero-length environment variable on Wine / XP
366             if (err == ERROR_ENVVAR_NOT_FOUND)
367                 return false;
368             // Some other Windows error, throw.
369             throw new WindowsException(err);
370         }
371         else static assert(0);
372     }
373 
374     /**
375     Copies all environment variables into an associative array.
376 
377     Windows_specific:
378     While Windows environment variable names are case insensitive, D's
379     built-in associative arrays are not.  This function will store all
380     variable names in uppercase (e.g. `PATH`).
381 
382     Throws:
383     $(OBJECTREF Exception) if the environment variables could not
384         be retrieved (Windows only).
385     */
386     string[string] toAA() @trusted
387     {
388         import std.conv : to;
389         string[string] aa;
390         version (Posix)
391         {
392             auto environ = getEnvironPtr;
393             for (int i=0; environ[i] != null; ++i)
394             {
395                 import std..string : indexOf;
396 
397                 immutable varDef = to!string(environ[i]);
398                 immutable eq = indexOf(varDef, '=');
399                 assert(eq >= 0);
400 
401                 immutable name = varDef[0 .. eq];
402                 immutable value = varDef[eq+1 .. $];
403 
404                 // In POSIX, environment variables may be defined more
405                 // than once.  This is a security issue, which we avoid
406                 // by checking whether the key already exists in the array.
407                 // For more info:
408                 // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html
409                 if (name !in aa)  aa[name] = value;
410             }
411         }
412         else version (Windows)
413         {
414             import std.exception : enforce;
415             import std.uni : toUpper;
416             auto envBlock = GetEnvironmentStringsW();
417             enforce(envBlock, "Failed to retrieve environment variables.");
418             scope(exit) FreeEnvironmentStringsW(envBlock);
419 
420             for (int i=0; envBlock[i] != '\0'; ++i)
421             {
422                 auto start = i;
423                 while (envBlock[i] != '=') ++i;
424                 immutable name = toUTF8(toUpper(envBlock[start .. i]));
425 
426                 start = i+1;
427                 while (envBlock[i] != '\0') ++i;
428 
429                 // Ignore variables with empty names. These are used internally
430                 // by Windows to keep track of each drive's individual current
431                 // directory.
432                 if (!name.length)
433                     continue;
434 
435                 // Just like in POSIX systems, environment variables may be
436                 // defined more than once in an environment block on Windows,
437                 // and it is just as much of a security issue there.  Moreso,
438                 // in fact, due to the case insensensitivity of variable names,
439                 // which is not handled correctly by all programs.
440                 auto val = toUTF8(envBlock[start .. i]);
441                 if (name !in aa) aa[name] = val is null ? "" : val;
442             }
443         }
444         else static assert(0);
445         return aa;
446     }
447 
448 private:
449     // Retrieves the environment variable, returns false on failure.
450     bool getImpl(scope const(char)[] name, out string value) @trusted
451     {
452         version (Windows)
453         {
454             // first we ask windows how long the environment variable is,
455             // then we try to read it in to a buffer of that length. Lots
456             // of error conditions because the windows API is nasty.
457 
458             import std.conv : to;
459             const namezTmp = name.tempCStringW();
460             WCHAR[] buf;
461 
462             // clear error because GetEnvironmentVariable only says it sets it
463             // if the environment variable is missing, not on other errors.
464             SetLastError(NO_ERROR);
465             // len includes terminating null
466             immutable len = GetEnvironmentVariableW(namezTmp, null, 0);
467             if (len == 0)
468             {
469                 immutable err = GetLastError();
470                 if (err == ERROR_ENVVAR_NOT_FOUND)
471                     return false;
472                 if (err != NO_ERROR) // Some other Windows error, throw.
473                     throw new WindowsException(err);
474             }
475             if (len <= 1)
476             {
477                 value = "";
478                 return true;
479             }
480             buf.length = len;
481 
482             while (true)
483             {
484                 // lenRead is either the number of bytes read w/o null - if buf was long enough - or
485                 // the number of bytes necessary *including* null if buf wasn't long enough
486                 immutable lenRead = GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length));
487                 if (lenRead == 0)
488                 {
489                     immutable err = GetLastError();
490                     if (err == NO_ERROR) // sucessfully read a 0-length variable
491                     {
492                         value = "";
493                         return true;
494                     }
495                     if (err == ERROR_ENVVAR_NOT_FOUND) // variable didn't exist
496                         return false;
497                     // some other windows error
498                     throw new WindowsException(err);
499                 }
500                 assert(lenRead != buf.length, "impossible according to msft docs");
501                 if (lenRead < buf.length) // the buffer was long enough
502                 {
503                     value = toUTF8(buf[0 .. lenRead]);
504                     return true;
505                 }
506                 // resize and go around again, because the environment variable grew
507                 buf.length = lenRead;
508             }
509         }
510         else version (Posix)
511         {
512             import core.stdc..string : strlen;
513 
514             const vz = core.sys.posix.stdlib.getenv(name.tempCString());
515             if (vz == null) return false;
516             auto v = vz[0 .. strlen(vz)];
517 
518             // Cache the last call's result.
519             static string lastResult;
520             if (v.empty)
521             {
522                 // Return non-null array for blank result to distinguish from
523                 // not-present result.
524                 lastResult = "";
525             }
526             else if (v != lastResult)
527             {
528                 lastResult = v.idup;
529             }
530             value = lastResult;
531             return true;
532         }
533         else static assert(0);
534     }
535 }
536 
537 @safe unittest
538 {
539     import std.exception : assertThrown;
540     // New variable
541     environment["std_process"] = "foo";
542     assert(environment["std_process"] == "foo");
543     assert("std_process" in environment);
544 
545     // Set variable again (also tests length 1 case)
546     environment["std_process"] = "b";
547     assert(environment["std_process"] == "b");
548     assert("std_process" in environment);
549 
550     // Remove variable
551     environment.remove("std_process");
552     assert("std_process" !in environment);
553 
554     // Remove again, should succeed
555     environment.remove("std_process");
556     assert("std_process" !in environment);
557 
558     // Throw on not found.
559     assertThrown(environment["std_process"]);
560 
561     // get() without default value
562     assert(environment.get("std_process") is null);
563 
564     // get() with default value
565     assert(environment.get("std_process", "baz") == "baz");
566 
567     // get() on an empty (but present) value
568     environment["std_process"] = "";
569     auto res = environment.get("std_process");
570     assert(res !is null);
571     assert(res == "");
572     assert("std_process" in environment);
573 
574     // Important to do the following round-trip after the previous test
575     // because it tests toAA with an empty var
576 
577     // Convert to associative array
578     auto aa = environment.toAA();
579     assert(aa.length > 0);
580     foreach (n, v; aa)
581     {
582         // Wine has some bugs related to environment variables:
583         //  - Wine allows the existence of an env. variable with the name
584         //    "\0", but GetEnvironmentVariable refuses to retrieve it.
585         //    As of 2.067 we filter these out anyway (see comment in toAA).
586 
587         assert(v == environment[n]);
588     }
589 
590     // ... and back again.
591     foreach (n, v; aa)
592         environment[n] = v;
593 
594     // Complete the roundtrip
595     auto aa2 = environment.toAA();
596     import std.conv : text;
597     assert(aa == aa2, text(aa, " != ", aa2));
598     assert("std_process" in environment);
599 
600     // Setting null must have the same effect as remove
601     environment["std_process"] = null;
602     assert("std_process" !in environment);
603 }
604 
605 // =============================================================================
606 // Functions and classes for process management.
607 // =============================================================================
608 
609 /**
610  * Returns the process ID of the current process,
611  * which is guaranteed to be unique on the system.
612  *
613  * Example:
614  * ---
615  * writefln("Current process ID: %d", thisProcessID);
616  * ---
617  */
618 @property int thisProcessID() @trusted nothrow //TODO: @safe
619 {
620     version (Windows)    return GetCurrentProcessId();
621     else version (Posix) return core.sys.posix.unistd.getpid();
622 }
623 
624 
625 /**
626  * Returns the process ID of the current thread,
627  * which is guaranteed to be unique within the current process.
628  *
629  * Returns:
630  * A $(REF ThreadID, core,thread) value for the calling thread.
631  *
632  * Example:
633  * ---
634  * writefln("Current thread ID: %s", thisThreadID);
635  * ---
636  */
637 @property ThreadID thisThreadID() @trusted nothrow //TODO: @safe
638 {
639     version (Windows)
640         return GetCurrentThreadId();
641     else
642     version (Posix)
643     {
644         import core.sys.posix.pthread : pthread_self;
645         return pthread_self();
646     }
647 }
648 
649 
650 @system unittest
651 {
652     int pidA, pidB;
653     ThreadID tidA, tidB;
654     pidA = thisProcessID;
655     tidA = thisThreadID;
656 
657     import core.thread;
658     auto t = new Thread({
659         pidB = thisProcessID;
660         tidB = thisThreadID;
661     });
662     t.start();
663     t.join();
664 
665     assert(pidA == pidB);
666     assert(tidA != tidB);
667 }
668 
669 version (iOSDerived) {}
670 else:
671 
672 /**
673 Spawns a new process, optionally assigning it an arbitrary set of standard
674 input, output, and error streams.
675 
676 The function returns immediately, leaving the child process to execute
677 in parallel with its parent.  It is recommended to always call $(LREF wait)
678 on the returned $(LREF Pid) unless the process was spawned with
679 `Config.detached` flag, as detailed in the documentation for `wait`.
680 
681 Command_line:
682 There are four overloads of this function.  The first two take an array
683 of strings, `args`, which should contain the program name as the
684 zeroth element and any command-line arguments in subsequent elements.
685 The third and fourth versions are included for convenience, and may be
686 used when there are no command-line arguments.  They take a single string,
687 `program`, which specifies the program name.
688 
689 Unless a directory is specified in `args[0]` or `program`,
690 `spawnProcess` will search for the program in a platform-dependent
691 manner.  On POSIX systems, it will look for the executable in the
692 directories listed in the PATH environment variable, in the order
693 they are listed.  On Windows, it will search for the executable in
694 the following sequence:
695 $(OL
696     $(LI The directory from which the application loaded.)
697     $(LI The current directory for the parent process.)
698     $(LI The 32-bit Windows system directory.)
699     $(LI The 16-bit Windows system directory.)
700     $(LI The Windows directory.)
701     $(LI The directories listed in the PATH environment variable.)
702 )
703 ---
704 // Run an executable called "prog" located in the current working
705 // directory:
706 auto pid = spawnProcess("./prog");
707 scope(exit) wait(pid);
708 // We can do something else while the program runs.  The scope guard
709 // ensures that the process is waited for at the end of the scope.
710 ...
711 
712 // Run DMD on the file "myprog.d", specifying a few compiler switches:
713 auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
714 if (wait(dmdPid) != 0)
715     writeln("Compilation failed!");
716 ---
717 
718 Environment_variables:
719 By default, the child process inherits the environment of the parent
720 process, along with any additional variables specified in the `env`
721 parameter.  If the same variable exists in both the parent's environment
722 and in `env`, the latter takes precedence.
723 
724 If the $(LREF Config.newEnv) flag is set in `config`, the child
725 process will $(I not) inherit the parent's environment.  Its entire
726 environment will then be determined by `env`.
727 ---
728 wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
729 ---
730 
731 Standard_streams:
732 The optional arguments `stdin`, `stdout` and `stderr` may
733 be used to assign arbitrary $(REF File, std,stdio) objects as the standard
734 input, output and error streams, respectively, of the child process.  The
735 former must be opened for reading, while the latter two must be opened for
736 writing.  The default is for the child process to inherit the standard
737 streams of its parent.
738 ---
739 // Run DMD on the file myprog.d, logging any error messages to a
740 // file named errors.log.
741 auto logFile = File("errors.log", "w");
742 auto pid = spawnProcess(["dmd", "myprog.d"],
743                         std.stdio.stdin,
744                         std.stdio.stdout,
745                         logFile);
746 if (wait(pid) != 0)
747     writeln("Compilation failed. See errors.log for details.");
748 ---
749 
750 Note that if you pass a `File` object that is $(I not)
751 one of the standard input/output/error streams of the parent process,
752 that stream will by default be $(I closed) in the parent process when
753 this function returns.  See the $(LREF Config) documentation below for
754 information about how to disable this behaviour.
755 
756 Beware of buffering issues when passing `File` objects to
757 `spawnProcess`.  The child process will inherit the low-level raw
758 read/write offset associated with the underlying file descriptor, but
759 it will not be aware of any buffered data.  In cases where this matters
760 (e.g. when a file should be aligned before being passed on to the
761 child process), it may be a good idea to use unbuffered streams, or at
762 least ensure all relevant buffers are flushed.
763 
764 Params:
765 args    = An array which contains the program name as the zeroth element
766           and any command-line arguments in the following elements.
767 stdin   = The standard input stream of the child process.
768           This can be any $(REF File, std,stdio) that is opened for reading.
769           By default the child process inherits the parent's input
770           stream.
771 stdout  = The standard output stream of the child process.
772           This can be any $(REF File, std,stdio) that is opened for writing.
773           By default the child process inherits the parent's output stream.
774 stderr  = The standard error stream of the child process.
775           This can be any $(REF File, std,stdio) that is opened for writing.
776           By default the child process inherits the parent's error stream.
777 env     = Additional environment variables for the child process.
778 config  = Flags that control process creation. See $(LREF Config)
779           for an overview of available flags.
780 workDir = The working directory for the new process.
781           By default the child process inherits the parent's working
782           directory.
783 
784 Returns:
785 A $(LREF Pid) object that corresponds to the spawned process.
786 
787 Throws:
788 $(LREF ProcessException) on failure to start the process.$(BR)
789 $(REF StdioException, std,stdio) on failure to pass one of the streams
790     to the child process (Windows only).$(BR)
791 $(REF RangeError, core,exception) if `args` is empty.
792 */
793 Pid spawnProcess(scope const(char[])[] args,
794                  File stdin = std.stdio.stdin,
795                  File stdout = std.stdio.stdout,
796                  File stderr = std.stdio.stderr,
797                  const string[string] env = null,
798                  Config config = Config.none,
799                  scope const char[] workDir = null)
800     @trusted // TODO: Should be @safe
801 {
802     version (Windows)    auto  args2 = escapeShellArguments(args);
803     else version (Posix) alias args2 = args;
804     return spawnProcessImpl(args2, stdin, stdout, stderr, env, config, workDir);
805 }
806 
807 /// ditto
808 Pid spawnProcess(scope const(char[])[] args,
809                  const string[string] env,
810                  Config config = Config.none,
811                  scope const(char)[] workDir = null)
812     @trusted // TODO: Should be @safe
813 {
814     return spawnProcess(args,
815                         std.stdio.stdin,
816                         std.stdio.stdout,
817                         std.stdio.stderr,
818                         env,
819                         config,
820                         workDir);
821 }
822 
823 /// ditto
824 Pid spawnProcess(scope const(char)[] program,
825                  File stdin = std.stdio.stdin,
826                  File stdout = std.stdio.stdout,
827                  File stderr = std.stdio.stderr,
828                  const string[string] env = null,
829                  Config config = Config.none,
830                  scope const(char)[] workDir = null)
831     @trusted
832 {
833     return spawnProcess((&program)[0 .. 1],
834                         stdin, stdout, stderr, env, config, workDir);
835 }
836 
837 /// ditto
838 Pid spawnProcess(scope const(char)[] program,
839                  const string[string] env,
840                  Config config = Config.none,
841                  scope const(char)[] workDir = null)
842     @trusted
843 {
844     return spawnProcess((&program)[0 .. 1], env, config, workDir);
845 }
846 
847 version (Posix) private enum InternalError : ubyte
848 {
849     noerror,
850     exec,
851     chdir,
852     getrlimit,
853     doubleFork,
854     malloc,
855 }
856 
857 /*
858 Implementation of spawnProcess() for POSIX.
859 
860 envz should be a zero-terminated array of zero-terminated strings
861 on the form "var=value".
862 */
863 version (Posix)
864 private Pid spawnProcessImpl(scope const(char[])[] args,
865                              File stdin,
866                              File stdout,
867                              File stderr,
868                              scope const string[string] env,
869                              Config config,
870                              scope const(char)[] workDir)
871     @trusted // TODO: Should be @safe
872 {
873     import core.exception : RangeError;
874     import std.algorithm.searching : any;
875     import std.conv : text;
876     import std.path : isDirSeparator;
877     import std..string : toStringz;
878 
879     if (args.empty) throw new RangeError();
880     const(char)[] name = args[0];
881     if (!any!isDirSeparator(name))
882     {
883         name = searchPathFor(name);
884         if (name is null)
885             throw new ProcessException(text("Executable file not found: ", args[0]));
886     }
887 
888     // Convert program name and arguments to C-style strings.
889     auto argz = new const(char)*[args.length+1];
890     argz[0] = toStringz(name);
891     foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]);
892     argz[$-1] = null;
893 
894     // Prepare environment.
895     auto envz = createEnv(env, !(config & Config.newEnv));
896 
897     // Open the working directory.
898     // We use open in the parent and fchdir in the child
899     // so that most errors (directory doesn't exist, not a directory)
900     // can be propagated as exceptions before forking.
901     int workDirFD = -1;
902     scope(exit) if (workDirFD >= 0) close(workDirFD);
903     if (workDir.length)
904     {
905         import core.sys.posix.fcntl : open, O_RDONLY, stat_t, fstat, S_ISDIR;
906         workDirFD = open(workDir.tempCString(), O_RDONLY);
907         if (workDirFD < 0)
908             throw ProcessException.newFromErrno("Failed to open working directory");
909         stat_t s;
910         if (fstat(workDirFD, &s) < 0)
911             throw ProcessException.newFromErrno("Failed to stat working directory");
912         if (!S_ISDIR(s.st_mode))
913             throw new ProcessException("Not a directory: " ~ cast(string) workDir);
914     }
915 
916     static int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); }
917 
918     // Get the file descriptors of the streams.
919     // These could potentially be invalid, but that is OK.  If so, later calls
920     // to dup2() and close() will just silently fail without causing any harm.
921     auto stdinFD  = getFD(stdin);
922     auto stdoutFD = getFD(stdout);
923     auto stderrFD = getFD(stderr);
924 
925     // We don't have direct access to the errors that may happen in a child process.
926     // So we use this pipe to deliver them.
927     int[2] forkPipe;
928     if (core.sys.posix.unistd.pipe(forkPipe) == 0)
929         setCLOEXEC(forkPipe[1], true);
930     else
931         throw ProcessException.newFromErrno("Could not create pipe to check startup of child");
932     scope(exit) close(forkPipe[0]);
933 
934     /*
935     To create detached process, we use double fork technique
936     but we don't have a direct access to the second fork pid from the caller side thus use a pipe.
937     We also can't reuse forkPipe for that purpose
938     because we can't predict the order in which pid and possible error will be written
939     since the first and the second forks will run in parallel.
940     */
941     int[2] pidPipe;
942     if (config & Config.detached)
943     {
944         if (core.sys.posix.unistd.pipe(pidPipe) != 0)
945             throw ProcessException.newFromErrno("Could not create pipe to get process pid");
946         setCLOEXEC(pidPipe[1], true);
947     }
948     scope(exit) if (config & Config.detached) close(pidPipe[0]);
949 
950     static void abortOnError(int forkPipeOut, InternalError errorType, int error) nothrow
951     {
952         core.sys.posix.unistd.write(forkPipeOut, &errorType, errorType.sizeof);
953         core.sys.posix.unistd.write(forkPipeOut, &error, error.sizeof);
954         close(forkPipeOut);
955         core.sys.posix.unistd._exit(1);
956         assert(0);
957     }
958 
959     void closePipeWriteEnds()
960     {
961         close(forkPipe[1]);
962         if (config & Config.detached)
963             close(pidPipe[1]);
964     }
965 
966     auto id = core.sys.posix.unistd.fork();
967     if (id < 0)
968     {
969         closePipeWriteEnds();
970         throw ProcessException.newFromErrno("Failed to spawn new process");
971     }
972 
973     void forkChild() nothrow @nogc
974     {
975         static import core.sys.posix.stdio;
976 
977         // Child process
978 
979         // no need for the read end of pipe on child side
980         if (config & Config.detached)
981             close(pidPipe[0]);
982         close(forkPipe[0]);
983         immutable forkPipeOut = forkPipe[1];
984         immutable pidPipeOut = pidPipe[1];
985 
986         // Set the working directory.
987         if (workDirFD >= 0)
988         {
989             if (fchdir(workDirFD) < 0)
990             {
991                 // Fail. It is dangerous to run a program
992                 // in an unexpected working directory.
993                 abortOnError(forkPipeOut, InternalError.chdir, .errno);
994             }
995             close(workDirFD);
996         }
997 
998         void execProcess()
999         {
1000             // Redirect streams and close the old file descriptors.
1001             // In the case that stderr is redirected to stdout, we need
1002             // to backup the file descriptor since stdout may be redirected
1003             // as well.
1004             if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
1005             dup2(stdinFD,  STDIN_FILENO);
1006             dup2(stdoutFD, STDOUT_FILENO);
1007             dup2(stderrFD, STDERR_FILENO);
1008 
1009             // Ensure that the standard streams aren't closed on execute, and
1010             // optionally close all other file descriptors.
1011             setCLOEXEC(STDIN_FILENO, false);
1012             setCLOEXEC(STDOUT_FILENO, false);
1013             setCLOEXEC(STDERR_FILENO, false);
1014 
1015             if (!(config & Config.inheritFDs))
1016             {
1017                 // NOTE: malloc() and getrlimit() are not on the POSIX async
1018                 // signal safe functions list, but practically this should
1019                 // not be a problem. Java VM and CPython also use malloc()
1020                 // in its own implementation via opendir().
1021                 import core.stdc.stdlib : malloc;
1022                 import core.sys.posix.poll : pollfd, poll, POLLNVAL;
1023                 import core.sys.posix.sys.resource : rlimit, getrlimit, RLIMIT_NOFILE;
1024 
1025                 // Get the maximum number of file descriptors that could be open.
1026                 rlimit r;
1027                 if (getrlimit(RLIMIT_NOFILE, &r) != 0)
1028                 {
1029                     abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
1030                 }
1031                 immutable maxDescriptors = cast(int) r.rlim_cur;
1032 
1033                 // The above, less stdin, stdout, and stderr
1034                 immutable maxToClose = maxDescriptors - 3;
1035 
1036                 // Call poll() to see which ones are actually open:
1037                 auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
1038                 if (pfds is null)
1039                 {
1040                     abortOnError(forkPipeOut, InternalError.malloc, .errno);
1041                 }
1042                 foreach (i; 0 .. maxToClose)
1043                 {
1044                     pfds[i].fd = i + 3;
1045                     pfds[i].events = 0;
1046                     pfds[i].revents = 0;
1047                 }
1048                 if (poll(pfds, maxToClose, 0) >= 0)
1049                 {
1050                     foreach (i; 0 .. maxToClose)
1051                     {
1052                         // don't close pipe write end
1053                         if (pfds[i].fd == forkPipeOut) continue;
1054                         // POLLNVAL will be set if the file descriptor is invalid.
1055                         if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
1056                     }
1057                 }
1058                 else
1059                 {
1060                     // Fall back to closing everything.
1061                     foreach (i; 3 .. maxDescriptors)
1062                     {
1063                         if (i == forkPipeOut) continue;
1064                         close(i);
1065                     }
1066                 }
1067             }
1068             else // This is already done if we don't inherit descriptors.
1069             {
1070                 // Close the old file descriptors, unless they are
1071                 // either of the standard streams.
1072                 if (stdinFD  > STDERR_FILENO)  close(stdinFD);
1073                 if (stdoutFD > STDERR_FILENO)  close(stdoutFD);
1074                 if (stderrFD > STDERR_FILENO)  close(stderrFD);
1075             }
1076 
1077             // Execute program.
1078             core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
1079 
1080             // If execution fails, exit as quickly as possible.
1081             abortOnError(forkPipeOut, InternalError.exec, .errno);
1082         }
1083 
1084         if (config & Config.detached)
1085         {
1086             auto secondFork = core.sys.posix.unistd.fork();
1087             if (secondFork == 0)
1088             {
1089                 close(pidPipeOut);
1090                 execProcess();
1091             }
1092             else if (secondFork == -1)
1093             {
1094                 auto secondForkErrno = .errno;
1095                 close(pidPipeOut);
1096                 abortOnError(forkPipeOut, InternalError.doubleFork, secondForkErrno);
1097             }
1098             else
1099             {
1100                 core.sys.posix.unistd.write(pidPipeOut, &secondFork, pid_t.sizeof);
1101                 close(pidPipeOut);
1102                 close(forkPipeOut);
1103                 _exit(0);
1104             }
1105         }
1106         else
1107         {
1108             execProcess();
1109         }
1110     }
1111 
1112     if (id == 0)
1113     {
1114         forkChild();
1115         assert(0);
1116     }
1117     else
1118     {
1119         closePipeWriteEnds();
1120         auto status = InternalError.noerror;
1121         auto readExecResult = core.sys.posix.unistd.read(forkPipe[0], &status, status.sizeof);
1122         // Save error number just in case if subsequent "waitpid" fails and overrides errno
1123         immutable lastError = .errno;
1124 
1125         if (config & Config.detached)
1126         {
1127             // Forked child exits right after creating second fork. So it should be safe to wait here.
1128             import core.sys.posix.sys.wait : waitpid;
1129             int waitResult;
1130             waitpid(id, &waitResult, 0);
1131         }
1132 
1133         if (readExecResult == -1)
1134             throw ProcessException.newFromErrno(lastError, "Could not read from pipe to get child status");
1135 
1136         bool owned = true;
1137         if (status != InternalError.noerror)
1138         {
1139             int error;
1140             readExecResult = read(forkPipe[0], &error, error.sizeof);
1141             string errorMsg;
1142             final switch (status)
1143             {
1144                 case InternalError.chdir:
1145                     errorMsg = "Failed to set working directory";
1146                     break;
1147                 case InternalError.getrlimit:
1148                     errorMsg = "getrlimit failed";
1149                     break;
1150                 case InternalError.exec:
1151                     errorMsg = "Failed to execute program";
1152                     break;
1153                 case InternalError.doubleFork:
1154                     // Can happen only when starting detached process
1155                     assert(config & Config.detached);
1156                     errorMsg = "Failed to fork twice";
1157                     break;
1158                 case InternalError.malloc:
1159                     errorMsg = "Failed to allocate memory";
1160                     break;
1161                 case InternalError.noerror:
1162                     assert(false);
1163             }
1164             if (readExecResult == error.sizeof)
1165                 throw ProcessException.newFromErrno(error, errorMsg);
1166             throw new ProcessException(errorMsg);
1167         }
1168         else if (config & Config.detached)
1169         {
1170             owned = false;
1171             if (read(pidPipe[0], &id, id.sizeof) != id.sizeof)
1172                 throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
1173         }
1174 
1175         // Parent process:  Close streams and return.
1176         if (!(config & Config.retainStdin ) && stdinFD  > STDERR_FILENO
1177                                             && stdinFD  != getFD(std.stdio.stdin ))
1178             stdin.close();
1179         if (!(config & Config.retainStdout) && stdoutFD > STDERR_FILENO
1180                                             && stdoutFD != getFD(std.stdio.stdout))
1181             stdout.close();
1182         if (!(config & Config.retainStderr) && stderrFD > STDERR_FILENO
1183                                             && stderrFD != getFD(std.stdio.stderr))
1184             stderr.close();
1185         return new Pid(id, owned);
1186     }
1187 }
1188 
1189 /*
1190 Implementation of spawnProcess() for Windows.
1191 
1192 commandLine must contain the entire command line, properly
1193 quoted/escaped as required by CreateProcessW().
1194 
1195 envz must be a pointer to a block of UTF-16 characters on the form
1196 "var1=value1\0var2=value2\0...varN=valueN\0\0".
1197 */
1198 version (Windows)
1199 private Pid spawnProcessImpl(scope const(char)[] commandLine,
1200                              File stdin,
1201                              File stdout,
1202                              File stderr,
1203                              const string[string] env,
1204                              Config config,
1205                              scope const(char)[] workDir)
1206     @trusted
1207 {
1208     import core.exception : RangeError;
1209 
1210     if (commandLine.empty) throw new RangeError("Command line is empty");
1211 
1212     // Prepare environment.
1213     auto envz = createEnv(env, !(config & Config.newEnv));
1214 
1215     // Startup info for CreateProcessW().
1216     STARTUPINFO_W startinfo;
1217     startinfo.cb = startinfo.sizeof;
1218     static int getFD(ref File f) { return f.isOpen ? f.fileno : -1; }
1219 
1220     // Extract file descriptors and HANDLEs from the streams and make the
1221     // handles inheritable.
1222     static void prepareStream(ref File file, DWORD stdHandle, string which,
1223                               out int fileDescriptor, out HANDLE handle)
1224     {
1225         enum _NO_CONSOLE_FILENO = cast(HANDLE)-2;
1226         fileDescriptor = getFD(file);
1227         handle = null;
1228         if (fileDescriptor >= 0)
1229             handle = file.windowsHandle;
1230         // Windows GUI applications have a fd but not a valid Windows HANDLE.
1231         if (handle is null || handle == INVALID_HANDLE_VALUE || handle == _NO_CONSOLE_FILENO)
1232             handle = GetStdHandle(stdHandle);
1233 
1234         DWORD dwFlags;
1235         if (GetHandleInformation(handle, &dwFlags))
1236         {
1237             if (!(dwFlags & HANDLE_FLAG_INHERIT))
1238             {
1239                 if (!SetHandleInformation(handle,
1240                                           HANDLE_FLAG_INHERIT,
1241                                           HANDLE_FLAG_INHERIT))
1242                 {
1243                     throw new StdioException(
1244                         "Failed to make "~which~" stream inheritable by child process ("
1245                         ~sysErrorString(GetLastError()) ~ ')',
1246                         0);
1247                 }
1248             }
1249         }
1250     }
1251     int stdinFD = -1, stdoutFD = -1, stderrFD = -1;
1252     prepareStream(stdin,  STD_INPUT_HANDLE,  "stdin" , stdinFD,  startinfo.hStdInput );
1253     prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput);
1254     prepareStream(stderr, STD_ERROR_HANDLE,  "stderr", stderrFD, startinfo.hStdError );
1255 
1256     if ((startinfo.hStdInput  != null && startinfo.hStdInput  != INVALID_HANDLE_VALUE)
1257      || (startinfo.hStdOutput != null && startinfo.hStdOutput != INVALID_HANDLE_VALUE)
1258      || (startinfo.hStdError  != null && startinfo.hStdError  != INVALID_HANDLE_VALUE))
1259         startinfo.dwFlags = STARTF_USESTDHANDLES;
1260 
1261     // Create process.
1262     PROCESS_INFORMATION pi;
1263     DWORD dwCreationFlags =
1264         CREATE_UNICODE_ENVIRONMENT |
1265         ((config & Config.suppressConsole) ? CREATE_NO_WINDOW : 0);
1266     // workaround until https://issues.dlang.org/show_bug.cgi?id=14696 is fixed
1267     auto pworkDir = workDir.tempCStringW();
1268     if (!CreateProcessW(null, commandLine.tempCStringW().buffPtr,
1269                         null, null, true, dwCreationFlags,
1270                         envz, workDir.length ? pworkDir : null, &startinfo, &pi))
1271         throw ProcessException.newFromLastError("Failed to spawn new process");
1272 
1273     // figure out if we should close any of the streams
1274     if (!(config & Config.retainStdin ) && stdinFD  > STDERR_FILENO
1275                                         && stdinFD  != getFD(std.stdio.stdin ))
1276         stdin.close();
1277     if (!(config & Config.retainStdout) && stdoutFD > STDERR_FILENO
1278                                         && stdoutFD != getFD(std.stdio.stdout))
1279         stdout.close();
1280     if (!(config & Config.retainStderr) && stderrFD > STDERR_FILENO
1281                                         && stderrFD != getFD(std.stdio.stderr))
1282         stderr.close();
1283 
1284     // close the thread handle in the process info structure
1285     CloseHandle(pi.hThread);
1286     if (config & Config.detached)
1287     {
1288         CloseHandle(pi.hProcess);
1289         return new Pid(pi.dwProcessId);
1290     }
1291     return new Pid(pi.dwProcessId, pi.hProcess);
1292 }
1293 
1294 // Converts childEnv to a zero-terminated array of zero-terminated strings
1295 // on the form "name=value", optionally adding those of the current process'
1296 // environment strings that are not present in childEnv.  If the parent's
1297 // environment should be inherited without modification, this function
1298 // returns environ directly.
1299 version (Posix)
1300 private const(char*)* createEnv(const string[string] childEnv,
1301                                 bool mergeWithParentEnv)
1302 {
1303     // Determine the number of strings in the parent's environment.
1304     int parentEnvLength = 0;
1305     auto environ = getEnvironPtr;
1306     if (mergeWithParentEnv)
1307     {
1308         if (childEnv.length == 0) return environ;
1309         while (environ[parentEnvLength] != null) ++parentEnvLength;
1310     }
1311 
1312     // Convert the "new" variables to C-style strings.
1313     auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
1314     int pos = 0;
1315     foreach (var, val; childEnv)
1316         envz[pos++] = (var~'='~val~'\0').ptr;
1317 
1318     // Add the parent's environment.
1319     foreach (environStr; environ[0 .. parentEnvLength])
1320     {
1321         int eqPos = 0;
1322         while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos;
1323         if (environStr[eqPos] != '=') continue;
1324         auto var = environStr[0 .. eqPos];
1325         if (var in childEnv) continue;
1326         envz[pos++] = environStr;
1327     }
1328     envz[pos] = null;
1329     return envz.ptr;
1330 }
1331 
1332 version (Posix) @system unittest
1333 {
1334     auto e1 = createEnv(null, false);
1335     assert(e1 != null && *e1 == null);
1336 
1337     auto e2 = createEnv(null, true);
1338     assert(e2 != null);
1339     int i = 0;
1340     auto environ = getEnvironPtr;
1341     for (; environ[i] != null; ++i)
1342     {
1343         assert(e2[i] != null);
1344         import core.stdc..string;
1345         assert(strcmp(e2[i], environ[i]) == 0);
1346     }
1347     assert(e2[i] == null);
1348 
1349     auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
1350     assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
1351     assert((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0")
1352          || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0"));
1353 }
1354 
1355 
1356 // Converts childEnv to a Windows environment block, which is on the form
1357 // "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding
1358 // those of the current process' environment strings that are not present
1359 // in childEnv.  Returns null if the parent's environment should be
1360 // inherited without modification, as this is what is expected by
1361 // CreateProcess().
1362 version (Windows)
1363 private LPVOID createEnv(const string[string] childEnv,
1364                          bool mergeWithParentEnv)
1365 {
1366     if (mergeWithParentEnv && childEnv.length == 0) return null;
1367     import std.array : appender;
1368     import std.uni : toUpper;
1369     auto envz = appender!(wchar[])();
1370     void put(string var, string val)
1371     {
1372         envz.put(var);
1373         envz.put('=');
1374         envz.put(val);
1375         envz.put(cast(wchar) '\0');
1376     }
1377 
1378     // Add the variables in childEnv, removing them from parentEnv
1379     // if they exist there too.
1380     auto parentEnv = mergeWithParentEnv ? environment.toAA() : null;
1381     foreach (k, v; childEnv)
1382     {
1383         auto uk = toUpper(k);
1384         put(uk, v);
1385         if (uk in parentEnv) parentEnv.remove(uk);
1386     }
1387 
1388     // Add remaining parent environment variables.
1389     foreach (k, v; parentEnv) put(k, v);
1390 
1391     // Two final zeros are needed in case there aren't any environment vars,
1392     // and the last one does no harm when there are.
1393     envz.put("\0\0"w);
1394     return envz.data.ptr;
1395 }
1396 
1397 version (Windows) @system unittest
1398 {
1399     assert(createEnv(null, true) == null);
1400     assert((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w);
1401     auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14];
1402     assert(e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w);
1403 }
1404 
1405 // Searches the PATH variable for the given executable file,
1406 // (checking that it is in fact executable).
1407 version (Posix)
1408 private string searchPathFor(scope const(char)[] executable)
1409     @trusted //TODO: @safe nothrow
1410 {
1411     import std.algorithm.iteration : splitter;
1412     import std.conv : to;
1413     import std.path : buildPath;
1414 
1415     auto pathz = core.stdc.stdlib.getenv("PATH");
1416     if (pathz == null)  return null;
1417 
1418     foreach (dir; splitter(to!string(pathz), ':'))
1419     {
1420         auto execPath = buildPath(dir, executable);
1421         if (isExecutable(execPath))  return execPath;
1422     }
1423 
1424     return null;
1425 }
1426 
1427 // Checks whether the file exists and can be executed by the
1428 // current user.
1429 version (Posix)
1430 private bool isExecutable(scope const(char)[] path) @trusted nothrow @nogc //TODO: @safe
1431 {
1432     return (access(path.tempCString(), X_OK) == 0);
1433 }
1434 
1435 version (Posix) @safe unittest
1436 {
1437     import std.algorithm;
1438     auto lsPath = searchPathFor("ls");
1439     assert(!lsPath.empty);
1440     assert(lsPath[0] == '/');
1441     assert(lsPath.endsWith("ls"));
1442     auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm");
1443     assert(unlikely is null, "Are you kidding me?");
1444 }
1445 
1446 // Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
1447 version (Posix)
1448 private void setCLOEXEC(int fd, bool on) nothrow @nogc
1449 {
1450     import core.sys.posix.fcntl : fcntl, F_GETFD, FD_CLOEXEC, F_SETFD;
1451     auto flags = fcntl(fd, F_GETFD);
1452     if (flags >= 0)
1453     {
1454         if (on) flags |= FD_CLOEXEC;
1455         else    flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
1456         flags = fcntl(fd, F_SETFD, flags);
1457     }
1458     assert(flags != -1 || .errno == EBADF);
1459 }
1460 
1461 @system unittest // Command line arguments in spawnProcess().
1462 {
1463     version (Windows) TestScript prog =
1464        "if not [%~1]==[foo] ( exit 1 )
1465         if not [%~2]==[bar] ( exit 2 )
1466         exit 0";
1467     else version (Posix) TestScript prog =
1468        `if test "$1" != "foo"; then exit 1; fi
1469         if test "$2" != "bar"; then exit 2; fi
1470         exit 0`;
1471     assert(wait(spawnProcess(prog.path)) == 1);
1472     assert(wait(spawnProcess([prog.path])) == 1);
1473     assert(wait(spawnProcess([prog.path, "foo"])) == 2);
1474     assert(wait(spawnProcess([prog.path, "foo", "baz"])) == 2);
1475     assert(wait(spawnProcess([prog.path, "foo", "bar"])) == 0);
1476 }
1477 
1478 // test that file descriptors are correctly closed / left open.
1479 // ideally this would be done by the child process making libc
1480 // calls, but we make do...
1481 version (Posix) @system unittest
1482 {
1483     import core.sys.posix.fcntl : open, O_RDONLY;
1484     import core.sys.posix.unistd : close;
1485     import std.algorithm.searching : canFind, findSplitBefore;
1486     import std.array : split;
1487     import std.conv : to;
1488     static import std.file;
1489     import std.functional : reverseArgs;
1490     import std.path : buildPath;
1491 
1492     auto directory = uniqueTempPath();
1493     std.file.mkdir(directory);
1494     scope(exit) std.file.rmdirRecurse(directory);
1495     auto path = buildPath(directory, "tmp");
1496     std.file.write(path, null);
1497     auto fd = open(path.tempCString, O_RDONLY);
1498     scope(exit) close(fd);
1499 
1500     // command >&2 (or any other number) checks whethether that number
1501     // file descriptor is open.
1502     // Can't use this for arbitrary descriptors as many shells only support
1503     // single digit fds.
1504     TestScript testDefaults = `command >&0 && command >&1 && command >&2`;
1505     assert(execute(testDefaults.path).status == 0);
1506     assert(execute(testDefaults.path, null, Config.inheritFDs).status == 0);
1507 
1508     // Try a few different methods to check whether there are any
1509     // incorrectly-open files.
1510     void testFDs()
1511     {
1512         // try /proc/<pid>/fd/ on linux
1513         version (linux)
1514         {
1515             TestScript proc = "ls /proc/$$/fd";
1516             auto procRes = execute(proc.path, null);
1517             if (procRes.status == 0)
1518             {
1519                 auto fdStr = fd.to!string;
1520                 assert(!procRes.output.split.canFind(fdStr));
1521                 assert(execute(proc.path, null, Config.inheritFDs)
1522                         .output.split.canFind(fdStr));
1523                 return;
1524             }
1525         }
1526 
1527         // try fuser (might sometimes need permissions)
1528         TestScript fuser = "echo $$ && fuser -f " ~ path;
1529         auto fuserRes = execute(fuser.path, null);
1530         if (fuserRes.status == 0)
1531         {
1532             assert(!reverseArgs!canFind(fuserRes
1533                         .output.findSplitBefore("\n").expand));
1534             assert(reverseArgs!canFind(execute(fuser.path, null, Config.inheritFDs)
1535                         .output.findSplitBefore("\n").expand));
1536             return;
1537         }
1538 
1539         // last resort, try lsof (not available on all Posix)
1540         TestScript lsof = "lsof -p$$";
1541         auto lsofRes = execute(lsof.path, null);
1542         if (lsofRes.status == 0)
1543         {
1544             assert(!lsofRes.output.canFind(path));
1545             assert(execute(lsof.path, null, Config.inheritFDs).output.canFind(path));
1546             return;
1547         }
1548 
1549         std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1550                 ": Warning: Couldn't find any way to check open files");
1551     }
1552     testFDs();
1553 }
1554 
1555 @system unittest // Environment variables in spawnProcess().
1556 {
1557     // We really should use set /a on Windows, but Wine doesn't support it.
1558     version (Windows) TestScript envProg =
1559        `if [%STD_PROCESS_UNITTEST1%] == [1] (
1560             if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3)
1561             exit 1
1562         )
1563         if [%STD_PROCESS_UNITTEST1%] == [4] (
1564             if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
1565             exit 4
1566         )
1567         if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
1568         exit 0`;
1569     version (Posix) TestScript envProg =
1570        `if test "$std_process_unittest1" = ""; then
1571             std_process_unittest1=0
1572         fi
1573         if test "$std_process_unittest2" = ""; then
1574             std_process_unittest2=0
1575         fi
1576         exit $(($std_process_unittest1+$std_process_unittest2))`;
1577 
1578     environment.remove("std_process_unittest1"); // Just in case.
1579     environment.remove("std_process_unittest2");
1580     assert(wait(spawnProcess(envProg.path)) == 0);
1581     assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1582 
1583     environment["std_process_unittest1"] = "1";
1584     assert(wait(spawnProcess(envProg.path)) == 1);
1585     assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1586 
1587     auto env = ["std_process_unittest2" : "2"];
1588     assert(wait(spawnProcess(envProg.path, env)) == 3);
1589     assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2);
1590 
1591     env["std_process_unittest1"] = "4";
1592     assert(wait(spawnProcess(envProg.path, env)) == 6);
1593     assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1594 
1595     environment.remove("std_process_unittest1");
1596     assert(wait(spawnProcess(envProg.path, env)) == 6);
1597     assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1598 }
1599 
1600 @system unittest // Stream redirection in spawnProcess().
1601 {
1602     import std.path : buildPath;
1603     import std..string;
1604     version (Windows) TestScript prog =
1605        "set /p INPUT=
1606         echo %INPUT% output %~1
1607         echo %INPUT% error %~2 1>&2
1608         echo done > %3";
1609     else version (Posix) TestScript prog =
1610        "read INPUT
1611         echo $INPUT output $1
1612         echo $INPUT error $2 >&2
1613         echo done > \"$3\"";
1614 
1615     // Pipes
1616     void testPipes(Config config)
1617     {
1618         import std.file, std.uuid, core.thread, std.exception;
1619         auto pipei = pipe();
1620         auto pipeo = pipe();
1621         auto pipee = pipe();
1622         auto done = buildPath(tempDir(), randomUUID().toString());
1623         auto pid = spawnProcess([prog.path, "foo", "bar", done],
1624                                     pipei.readEnd, pipeo.writeEnd, pipee.writeEnd, null, config);
1625         pipei.writeEnd.writeln("input");
1626         pipei.writeEnd.flush();
1627         assert(pipeo.readEnd.readln().chomp() == "input output foo");
1628         assert(pipee.readEnd.readln().chomp().stripRight() == "input error bar");
1629         if (config & Config.detached)
1630             while (!done.exists) Thread.sleep(10.msecs);
1631         else
1632             wait(pid);
1633         while (remove(done).collectException) Thread.sleep(10.msecs);
1634     }
1635 
1636     // Files
1637     void testFiles(Config config)
1638     {
1639         import std.ascii, std.file, std.uuid, core.thread, std.exception;
1640         auto pathi = buildPath(tempDir(), randomUUID().toString());
1641         auto patho = buildPath(tempDir(), randomUUID().toString());
1642         auto pathe = buildPath(tempDir(), randomUUID().toString());
1643         std.file.write(pathi, "INPUT"~std.ascii.newline);
1644         auto filei = File(pathi, "r");
1645         auto fileo = File(patho, "w");
1646         auto filee = File(pathe, "w");
1647         auto done = buildPath(tempDir(), randomUUID().toString());
1648         auto pid = spawnProcess([prog.path, "bar", "baz", done], filei, fileo, filee, null, config);
1649         if (config & Config.detached)
1650             while (!done.exists) Thread.sleep(10.msecs);
1651         else
1652             wait(pid);
1653         assert(readText(patho).chomp() == "INPUT output bar");
1654         assert(readText(pathe).chomp().stripRight() == "INPUT error baz");
1655         while (remove(pathi).collectException) Thread.sleep(10.msecs);
1656         while (remove(patho).collectException) Thread.sleep(10.msecs);
1657         while (remove(pathe).collectException) Thread.sleep(10.msecs);
1658         while (remove(done).collectException) Thread.sleep(10.msecs);
1659     }
1660 
1661     testPipes(Config.none);
1662     testFiles(Config.none);
1663     testPipes(Config.detached);
1664     testFiles(Config.detached);
1665 }
1666 
1667 @system unittest // Error handling in spawnProcess()
1668 {
1669     import std.exception : assertThrown;
1670     assertThrown!ProcessException(spawnProcess("ewrgiuhrifuheiohnmnvqweoijwf"));
1671     assertThrown!ProcessException(spawnProcess("./rgiuhrifuheiohnmnvqweoijwf"));
1672     assertThrown!ProcessException(spawnProcess("ewrgiuhrifuheiohnmnvqweoijwf", null, Config.detached));
1673     assertThrown!ProcessException(spawnProcess("./rgiuhrifuheiohnmnvqweoijwf", null, Config.detached));
1674 
1675     // can't execute malformed file with executable permissions
1676     version (Posix)
1677     {
1678         import std.path : buildPath;
1679         import std.file : remove, write, setAttributes, tempDir;
1680         import core.sys.posix.sys.stat : S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH;
1681         import std.conv : to;
1682         string deleteme = buildPath(tempDir(), "deleteme.std.process.unittest.pid") ~ to!string(thisProcessID);
1683         write(deleteme, "");
1684         scope(exit) remove(deleteme);
1685         setAttributes(deleteme, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
1686         assertThrown!ProcessException(spawnProcess(deleteme));
1687         assertThrown!ProcessException(spawnProcess(deleteme, null, Config.detached));
1688     }
1689 }
1690 
1691 @system unittest // Specifying a working directory.
1692 {
1693     import std.path;
1694     import std.file;
1695     TestScript prog = "echo foo>bar";
1696 
1697     auto directory = uniqueTempPath();
1698     mkdir(directory);
1699     scope(exit) rmdirRecurse(directory);
1700 
1701     auto pid = spawnProcess([prog.path], null, Config.none, directory);
1702     wait(pid);
1703     assert(exists(buildPath(directory, "bar")));
1704 }
1705 
1706 @system unittest // Specifying a bad working directory.
1707 {
1708     import std.exception : assertThrown;
1709     import std.file;
1710     TestScript prog = "echo";
1711 
1712     auto directory = uniqueTempPath();
1713     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1714     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1715 
1716     std.file.write(directory, "foo");
1717     scope(exit) remove(directory);
1718     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1719     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1720 
1721     // can't run in directory if user does not have search permission on this directory
1722     version (Posix)
1723     {
1724         if (core.sys.posix.unistd.getuid() != 0)
1725         {
1726             import core.sys.posix.sys.stat : S_IRUSR;
1727             auto directoryNoSearch = uniqueTempPath();
1728             mkdir(directoryNoSearch);
1729             scope(exit) rmdirRecurse(directoryNoSearch);
1730             setAttributes(directoryNoSearch, S_IRUSR);
1731             assertThrown!ProcessException(spawnProcess(prog.path, null, Config.none, directoryNoSearch));
1732             assertThrown!ProcessException(spawnProcess(prog.path, null, Config.detached, directoryNoSearch));
1733         }
1734     }
1735 }
1736 
1737 @system unittest // Specifying empty working directory.
1738 {
1739     TestScript prog = "";
1740 
1741     string directory = "";
1742     assert(directory.ptr && !directory.length);
1743     spawnProcess([prog.path], null, Config.none, directory).wait();
1744 }
1745 
1746 // Reopening the standard streams (https://issues.dlang.org/show_bug.cgi?id=13258)
1747 @system unittest
1748 {
1749     import std..string;
1750     import std.file;
1751     void fun()
1752     {
1753         spawnShell("echo foo").wait();
1754         spawnShell("echo bar").wait();
1755     }
1756 
1757     auto tmpFile = uniqueTempPath();
1758     scope(exit) if (exists(tmpFile)) remove(tmpFile);
1759 
1760     {
1761         auto oldOut = std.stdio.stdout;
1762         scope(exit) std.stdio.stdout = oldOut;
1763 
1764         std.stdio.stdout = File(tmpFile, "w");
1765         fun();
1766         std.stdio.stdout.close();
1767     }
1768 
1769     auto lines = readText(tmpFile).splitLines();
1770     assert(lines == ["foo", "bar"]);
1771 }
1772 
1773 // MSVCRT workaround (https://issues.dlang.org/show_bug.cgi?id=14422)
1774 version (Windows)
1775 @system unittest
1776 {
1777     auto fn = uniqueTempPath();
1778     std.file.write(fn, "AAAAAAAAAA");
1779 
1780     auto f = File(fn, "a");
1781     spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait();
1782 
1783     auto data = readText(fn);
1784     assert(data == "AAAAAAAAAABBBBB\r\n", data);
1785 }
1786 
1787 // https://issues.dlang.org/show_bug.cgi?id=20765
1788 // Test that running processes with relative path works in conjunction
1789 // with indicating a workDir.
1790 version (Posix) @system unittest
1791 {
1792     import std.file : mkdir, write, setAttributes;
1793     import std.conv : octal;
1794 
1795     auto dir = uniqueTempPath();
1796     mkdir(dir);
1797     write(dir ~ "/program", "#!/bin/sh\necho Hello");
1798     setAttributes(dir ~ "/program", octal!700);
1799 
1800     assert(execute(["./program"], null, Config.none, size_t.max, dir).output == "Hello\n");
1801 }
1802 
1803 /**
1804 A variation on $(LREF spawnProcess) that runs the given _command through
1805 the current user's preferred _command interpreter (aka. shell).
1806 
1807 The string `command` is passed verbatim to the shell, and is therefore
1808 subject to its rules about _command structure, argument/filename quoting
1809 and escaping of special characters.
1810 The path to the shell executable defaults to $(LREF nativeShell).
1811 
1812 In all other respects this function works just like `spawnProcess`.
1813 Please refer to the $(LREF spawnProcess) documentation for descriptions
1814 of the other function parameters, the return value and any exceptions
1815 that may be thrown.
1816 ---
1817 // Run the command/program "foo" on the file named "my file.txt", and
1818 // redirect its output into foo.log.
1819 auto pid = spawnShell(`foo "my file.txt" > foo.log`);
1820 wait(pid);
1821 ---
1822 
1823 See_also:
1824 $(LREF escapeShellCommand), which may be helpful in constructing a
1825 properly quoted and escaped shell _command line for the current platform.
1826 */
1827 Pid spawnShell(scope const(char)[] command,
1828                File stdin = std.stdio.stdin,
1829                File stdout = std.stdio.stdout,
1830                File stderr = std.stdio.stderr,
1831                scope const string[string] env = null,
1832                Config config = Config.none,
1833                scope const(char)[] workDir = null,
1834                scope string shellPath = nativeShell)
1835     @trusted // TODO: Should be @safe
1836 {
1837     version (Windows)
1838     {
1839         // CMD does not parse its arguments like other programs.
1840         // It does not use CommandLineToArgvW.
1841         // Instead, it treats the first and last quote specially.
1842         // See CMD.EXE /? for details.
1843         auto args = escapeShellFileName(shellPath)
1844                     ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`;
1845     }
1846     else version (Posix)
1847     {
1848         const(char)[][3] args;
1849         args[0] = shellPath;
1850         args[1] = shellSwitch;
1851         args[2] = command;
1852     }
1853     return spawnProcessImpl(args, stdin, stdout, stderr, env, config, workDir);
1854 }
1855 
1856 /// ditto
1857 Pid spawnShell(scope const(char)[] command,
1858                scope const string[string] env,
1859                Config config = Config.none,
1860                scope const(char)[] workDir = null,
1861                scope string shellPath = nativeShell)
1862     @trusted // TODO: Should be @safe
1863 {
1864     return spawnShell(command,
1865                       std.stdio.stdin,
1866                       std.stdio.stdout,
1867                       std.stdio.stderr,
1868                       env,
1869                       config,
1870                       workDir,
1871                       shellPath);
1872 }
1873 
1874 @system unittest
1875 {
1876     version (Windows)
1877         auto cmd = "echo %FOO%";
1878     else version (Posix)
1879         auto cmd = "echo $foo";
1880     import std.file;
1881     auto tmpFile = uniqueTempPath();
1882     scope(exit) if (exists(tmpFile)) remove(tmpFile);
1883     auto redir = "> \""~tmpFile~'"';
1884     auto env = ["foo" : "bar"];
1885     assert(wait(spawnShell(cmd~redir, env)) == 0);
1886     auto f = File(tmpFile, "a");
1887     version (CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before
1888     assert(wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
1889     f.close();
1890     auto output = std.file.readText(tmpFile);
1891     assert(output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
1892 }
1893 
1894 version (Windows)
1895 @system unittest
1896 {
1897     import std..string;
1898     import std.conv : text;
1899     TestScript prog = "echo %0 %*";
1900     auto outputFn = uniqueTempPath();
1901     scope(exit) if (exists(outputFn)) remove(outputFn);
1902     auto args = [`a b c`, `a\b\c\`, `a"b"c"`];
1903     auto result = executeShell(
1904         escapeShellCommand([prog.path] ~ args)
1905         ~ " > " ~
1906         escapeShellFileName(outputFn));
1907     assert(result.status == 0);
1908     auto args2 = outputFn.readText().strip().parseCommandLine()[1..$];
1909     assert(args == args2, text(args2));
1910 }
1911 
1912 
1913 /**
1914 Flags that control the behaviour of process creation functions in this
1915 module. Most flags only apply to $(LREF spawnProcess) and
1916 $(LREF spawnShell).
1917 
1918 Use bitwise OR to combine flags.
1919 
1920 Example:
1921 ---
1922 auto logFile = File("myapp_error.log", "w");
1923 
1924 // Start program, suppressing the console window (Windows only),
1925 // redirect its error stream to logFile, and leave logFile open
1926 // in the parent process as well.
1927 auto pid = spawnProcess("myapp", stdin, stdout, logFile,
1928                         Config.retainStderr | Config.suppressConsole);
1929 scope(exit)
1930 {
1931     auto exitCode = wait(pid);
1932     logFile.writeln("myapp exited with code ", exitCode);
1933     logFile.close();
1934 }
1935 ---
1936 */
1937 enum Config
1938 {
1939     none = 0,
1940 
1941     /**
1942     By default, the child process inherits the parent's environment,
1943     and any environment variables passed to $(LREF spawnProcess) will
1944     be added to it.  If this flag is set, the only variables in the
1945     child process' environment will be those given to spawnProcess.
1946     */
1947     newEnv = 1,
1948 
1949     /**
1950     Unless the child process inherits the standard input/output/error
1951     streams of its parent, one almost always wants the streams closed
1952     in the parent when $(LREF spawnProcess) returns.  Therefore, by
1953     default, this is done.  If this is not desirable, pass any of these
1954     options to spawnProcess.
1955     */
1956     retainStdin  = 2,
1957     retainStdout = 4,                                  /// ditto
1958     retainStderr = 8,                                  /// ditto
1959 
1960     /**
1961     On Windows, if the child process is a console application, this
1962     flag will prevent the creation of a console window.  Otherwise,
1963     it will be ignored. On POSIX, `suppressConsole` has no effect.
1964     */
1965     suppressConsole = 16,
1966 
1967     /**
1968     On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
1969     are by default inherited by the child process.  As this may lead
1970     to subtle bugs when pipes or multiple threads are involved,
1971     $(LREF spawnProcess) ensures that all file descriptors except the
1972     ones that correspond to standard input/output/error are closed
1973     in the child process when it starts.  Use `inheritFDs` to prevent
1974     this.
1975 
1976     On Windows, this option has no effect, and any handles which have been
1977     explicitly marked as inheritable will always be inherited by the child
1978     process.
1979     */
1980     inheritFDs = 32,
1981 
1982     /**
1983     Spawn process in detached state. This removes the need in calling
1984     $(LREF wait) to clean up the process resources.
1985 
1986     Note:
1987     Calling $(LREF wait) or $(LREF kill) with the resulting `Pid` is invalid.
1988     */
1989     detached = 64,
1990 
1991     /**
1992     By default, the $(LREF execute) and $(LREF executeShell) functions
1993     will capture child processes' both stdout and stderr. This can be
1994     undesirable if the standard output is to be processed or otherwise
1995     used by the invoking program, as `execute`'s result would then
1996     contain a mix of output and warning/error messages.
1997 
1998     Specify this flag when calling `execute` or `executeShell` to
1999     cause invoked processes' stderr stream to be sent to $(REF stderr,
2000     std,stdio), and only capture and return standard output.
2001 
2002     This flag has no effect on $(LREF spawnProcess) or $(LREF spawnShell).
2003     */
2004     stderrPassThrough = 128,
2005 }
2006 
2007 
2008 /// A handle that corresponds to a spawned process.
2009 final class Pid
2010 {
2011     /**
2012     The process ID number.
2013 
2014     This is a number that uniquely identifies the process on the operating
2015     system, for at least as long as the process is running.  Once $(LREF wait)
2016     has been called on the $(LREF Pid), this method will return an
2017     invalid (negative) process ID.
2018     */
2019     @property int processID() const @safe pure nothrow
2020     {
2021         return _processID;
2022     }
2023 
2024     /**
2025     An operating system handle to the process.
2026 
2027     This handle is used to specify the process in OS-specific APIs.
2028     On POSIX, this function returns a `core.sys.posix.sys.types.pid_t`
2029     with the same value as $(LREF Pid.processID), while on Windows it returns
2030     a `core.sys.windows.windows.HANDLE`.
2031 
2032     Once $(LREF wait) has been called on the $(LREF Pid), this method
2033     will return an invalid handle.
2034     */
2035     // Note: Since HANDLE is a reference, this function cannot be const.
2036     version (Windows)
2037     @property HANDLE osHandle() @nogc @safe pure nothrow
2038     {
2039         return _handle;
2040     }
2041     else version (Posix)
2042     @property pid_t osHandle() @nogc @safe pure nothrow
2043     {
2044         return _processID;
2045     }
2046 
2047 private:
2048     /*
2049     Pid.performWait() does the dirty work for wait() and nonBlockingWait().
2050 
2051     If block == true, this function blocks until the process terminates,
2052     sets _processID to terminated, and returns the exit code or terminating
2053     signal as described in the wait() documentation.
2054 
2055     If block == false, this function returns immediately, regardless
2056     of the status of the process.  If the process has terminated, the
2057     function has the exact same effect as the blocking version.  If not,
2058     it returns 0 and does not modify _processID.
2059     */
2060     version (Posix)
2061     int performWait(bool block) @trusted
2062     {
2063         import std.exception : enforce;
2064         enforce!ProcessException(owned, "Can't wait on a detached process");
2065         if (_processID == terminated) return _exitCode;
2066         int exitCode;
2067         while (true)
2068         {
2069             int status;
2070             auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
2071             if (check == -1)
2072             {
2073                 if (errno == ECHILD)
2074                 {
2075                     throw new ProcessException(
2076                         "Process does not exist or is not a child process.");
2077                 }
2078                 else
2079                 {
2080                     // waitpid() was interrupted by a signal.  We simply
2081                     // restart it.
2082                     assert(errno == EINTR);
2083                     continue;
2084                 }
2085             }
2086             if (!block && check == 0) return 0;
2087             if (WIFEXITED(status))
2088             {
2089                 exitCode = WEXITSTATUS(status);
2090                 break;
2091             }
2092             else if (WIFSIGNALED(status))
2093             {
2094                 exitCode = -WTERMSIG(status);
2095                 break;
2096             }
2097             // We check again whether the call should be blocking,
2098             // since we don't care about other status changes besides
2099             // "exited" and "terminated by signal".
2100             if (!block) return 0;
2101 
2102             // Process has stopped, but not terminated, so we continue waiting.
2103         }
2104         // Mark Pid as terminated, and cache and return exit code.
2105         _processID = terminated;
2106         _exitCode = exitCode;
2107         return exitCode;
2108     }
2109     else version (Windows)
2110     {
2111         int performWait(bool block) @trusted
2112         {
2113             import std.exception : enforce;
2114             enforce!ProcessException(owned, "Can't wait on a detached process");
2115             if (_processID == terminated) return _exitCode;
2116             assert(_handle != INVALID_HANDLE_VALUE);
2117             if (block)
2118             {
2119                 auto result = WaitForSingleObject(_handle, INFINITE);
2120                 if (result != WAIT_OBJECT_0)
2121                     throw ProcessException.newFromLastError("Wait failed.");
2122             }
2123             if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
2124                 throw ProcessException.newFromLastError();
2125             if (!block && _exitCode == STILL_ACTIVE) return 0;
2126             CloseHandle(_handle);
2127             _handle = INVALID_HANDLE_VALUE;
2128             _processID = terminated;
2129             return _exitCode;
2130         }
2131 
2132         ~this()
2133         {
2134             if (_handle != INVALID_HANDLE_VALUE)
2135             {
2136                 CloseHandle(_handle);
2137                 _handle = INVALID_HANDLE_VALUE;
2138             }
2139         }
2140     }
2141 
2142     // Special values for _processID.
2143     enum invalid = -1, terminated = -2;
2144 
2145     // OS process ID number.  Only nonnegative IDs correspond to
2146     // running processes.
2147     int _processID = invalid;
2148 
2149     // Exit code cached by wait().  This is only expected to hold a
2150     // sensible value if _processID == terminated.
2151     int _exitCode;
2152 
2153     // Whether the process can be waited for by wait() for or killed by kill().
2154     // False if process was started as detached. True otherwise.
2155     bool owned;
2156 
2157     // Pids are only meant to be constructed inside this module, so
2158     // we make the constructor private.
2159     version (Windows)
2160     {
2161         HANDLE _handle = INVALID_HANDLE_VALUE;
2162         this(int pid, HANDLE handle) @safe pure nothrow
2163         {
2164             _processID = pid;
2165             _handle = handle;
2166             this.owned = true;
2167         }
2168         this(int pid) @safe pure nothrow
2169         {
2170             _processID = pid;
2171             this.owned = false;
2172         }
2173     }
2174     else
2175     {
2176         this(int id, bool owned) @safe pure nothrow
2177         {
2178             _processID = id;
2179             this.owned = owned;
2180         }
2181     }
2182 }
2183 
2184 
2185 /**
2186 Waits for the process associated with `pid` to terminate, and returns
2187 its exit status.
2188 
2189 In general one should always _wait for child processes to terminate
2190 before exiting the parent process unless the process was spawned as detached
2191 (that was spawned with `Config.detached` flag).
2192 Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
2193 – processes that are defunct, yet still occupy a slot in the OS process table.
2194 You should not and must not wait for detached processes, since you don't own them.
2195 
2196 If the process has already terminated, this function returns directly.
2197 The exit code is cached, so that if wait() is called multiple times on
2198 the same $(LREF Pid) it will always return the same value.
2199 
2200 POSIX_specific:
2201 If the process is terminated by a signal, this function returns a
2202 negative number whose absolute value is the signal number.
2203 Since POSIX restricts normal exit codes to the range 0-255, a
2204 negative return value will always indicate termination by signal.
2205 Signal codes are defined in the `core.sys.posix.signal` module
2206 (which corresponds to the `signal.h` POSIX header).
2207 
2208 Throws:
2209 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2210 
2211 Example:
2212 See the $(LREF spawnProcess) documentation.
2213 
2214 See_also:
2215 $(LREF tryWait), for a non-blocking function.
2216 */
2217 int wait(Pid pid) @safe
2218 {
2219     assert(pid !is null, "Called wait on a null Pid.");
2220     return pid.performWait(true);
2221 }
2222 
2223 
2224 @system unittest // Pid and wait()
2225 {
2226     version (Windows)    TestScript prog = "exit %~1";
2227     else version (Posix) TestScript prog = "exit $1";
2228     assert(wait(spawnProcess([prog.path, "0"])) == 0);
2229     assert(wait(spawnProcess([prog.path, "123"])) == 123);
2230     auto pid = spawnProcess([prog.path, "10"]);
2231     assert(pid.processID > 0);
2232     version (Windows)    assert(pid.osHandle != INVALID_HANDLE_VALUE);
2233     else version (Posix) assert(pid.osHandle == pid.processID);
2234     assert(wait(pid) == 10);
2235     assert(wait(pid) == 10); // cached exit code
2236     assert(pid.processID < 0);
2237     version (Windows)    assert(pid.osHandle == INVALID_HANDLE_VALUE);
2238     else version (Posix) assert(pid.osHandle < 0);
2239 }
2240 
2241 
2242 /**
2243 A non-blocking version of $(LREF wait).
2244 
2245 If the process associated with `pid` has already terminated,
2246 `tryWait` has the exact same effect as `wait`.
2247 In this case, it returns a tuple where the `terminated` field
2248 is set to `true` and the `status` field has the same
2249 interpretation as the return value of `wait`.
2250 
2251 If the process has $(I not) yet terminated, this function differs
2252 from `wait` in that does not wait for this to happen, but instead
2253 returns immediately.  The `terminated` field of the returned
2254 tuple will then be set to `false`, while the `status` field
2255 will always be 0 (zero).  `wait` or `tryWait` should then be
2256 called again on the same `Pid` at some later time; not only to
2257 get the exit code, but also to avoid the process becoming a "zombie"
2258 when it finally terminates.  (See $(LREF wait) for details).
2259 
2260 Returns:
2261 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2262 
2263 Throws:
2264 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2265 
2266 Example:
2267 ---
2268 auto pid = spawnProcess("dmd myapp.d");
2269 scope(exit) wait(pid);
2270 ...
2271 auto dmd = tryWait(pid);
2272 if (dmd.terminated)
2273 {
2274     if (dmd.status == 0) writeln("Compilation succeeded!");
2275     else writeln("Compilation failed");
2276 }
2277 else writeln("Still compiling...");
2278 ...
2279 ---
2280 Note that in this example, the first `wait` call will have no
2281 effect if the process has already terminated by the time `tryWait`
2282 is called.  In the opposite case, however, the `scope` statement
2283 ensures that we always wait for the process if it hasn't terminated
2284 by the time we reach the end of the scope.
2285 */
2286 auto tryWait(Pid pid) @safe
2287 {
2288     import std.typecons : Tuple;
2289     assert(pid !is null, "Called tryWait on a null Pid.");
2290     auto code = pid.performWait(false);
2291     return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code);
2292 }
2293 // unittest: This function is tested together with kill() below.
2294 
2295 
2296 /**
2297 Attempts to terminate the process associated with `pid`.
2298 
2299 The effect of this function, as well as the meaning of `codeOrSignal`,
2300 is highly platform dependent.  Details are given below.  Common to all
2301 platforms is that this function only $(I initiates) termination of the process,
2302 and returns immediately.  It does not wait for the process to end,
2303 nor does it guarantee that the process does in fact get terminated.
2304 
2305 Always call $(LREF wait) to wait for a process to complete, even if `kill`
2306 has been called on it.
2307 
2308 Windows_specific:
2309 The process will be
2310 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
2311 forcefully and abruptly terminated).  If `codeOrSignal` is specified, it
2312 must be a nonnegative number which will be used as the exit code of the process.
2313 If not, the process wil exit with code 1.  Do not use $(D codeOrSignal = 259),
2314 as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
2315 used by Windows to signal that a process has in fact $(I not) terminated yet.
2316 ---
2317 auto pid = spawnProcess("some_app");
2318 kill(pid, 10);
2319 assert(wait(pid) == 10);
2320 ---
2321 
2322 POSIX_specific:
2323 A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
2324 the process, whose value is given by `codeOrSignal`.  Depending on the
2325 signal sent, this may or may not terminate the process.  Symbolic constants
2326 for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
2327 POSIX signals) are defined in `core.sys.posix.signal`, which corresponds to the
2328 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
2329 `signal.h` POSIX header).  If `codeOrSignal` is omitted, the
2330 `SIGTERM` signal will be sent.  (This matches the behaviour of the
2331 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
2332 `_kill`) shell command.)
2333 ---
2334 import core.sys.posix.signal : SIGKILL;
2335 auto pid = spawnProcess("some_app");
2336 kill(pid, SIGKILL);
2337 assert(wait(pid) == -SIGKILL); // Negative return value on POSIX!
2338 ---
2339 
2340 Throws:
2341 $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
2342     or on attempt to kill detached process.
2343     Note that failure to terminate the process is considered a "normal"
2344     outcome, not an error.$(BR)
2345 */
2346 void kill(Pid pid)
2347 {
2348     version (Windows) kill(pid, 1);
2349     else version (Posix)
2350     {
2351         import core.sys.posix.signal : SIGTERM;
2352         kill(pid, SIGTERM);
2353     }
2354 }
2355 
2356 /// ditto
2357 void kill(Pid pid, int codeOrSignal)
2358 {
2359     import std.exception : enforce;
2360     enforce!ProcessException(pid.owned, "Can't kill detached process");
2361     version (Windows)
2362     {
2363         if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
2364         // On Windows, TerminateProcess() appears to terminate the
2365         // *current* process if it is passed an invalid handle...
2366         if (pid.osHandle == INVALID_HANDLE_VALUE)
2367             throw new ProcessException("Invalid process handle");
2368         if (!TerminateProcess(pid.osHandle, codeOrSignal))
2369             throw ProcessException.newFromLastError();
2370     }
2371     else version (Posix)
2372     {
2373         import core.sys.posix.signal : kill;
2374         if (kill(pid.osHandle, codeOrSignal) == -1)
2375             throw ProcessException.newFromErrno();
2376     }
2377 }
2378 
2379 @system unittest // tryWait() and kill()
2380 {
2381     import core.thread;
2382     import std.exception : assertThrown;
2383     // The test script goes into an infinite loop.
2384     version (Windows)
2385     {
2386         TestScript prog = ":loop
2387                            goto loop";
2388     }
2389     else version (Posix)
2390     {
2391         import core.sys.posix.signal : SIGTERM, SIGKILL;
2392         TestScript prog = "while true; do sleep 1; done";
2393     }
2394     auto pid = spawnProcess(prog.path);
2395     // Android appears to automatically kill sleeping processes very quickly,
2396     // so shorten the wait before killing here.
2397     version (Android)
2398         Thread.sleep(dur!"msecs"(5));
2399     else
2400         Thread.sleep(dur!"msecs"(500));
2401     kill(pid);
2402     version (Windows)    assert(wait(pid) == 1);
2403     else version (Posix) assert(wait(pid) == -SIGTERM);
2404 
2405     pid = spawnProcess(prog.path);
2406     Thread.sleep(dur!"msecs"(500));
2407     auto s = tryWait(pid);
2408     assert(!s.terminated && s.status == 0);
2409     assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
2410     version (Windows)    kill(pid, 123);
2411     else version (Posix) kill(pid, SIGKILL);
2412     do { s = tryWait(pid); } while (!s.terminated);
2413     version (Windows)    assert(s.status == 123);
2414     else version (Posix) assert(s.status == -SIGKILL);
2415     assertThrown!ProcessException(kill(pid));
2416 }
2417 
2418 @system unittest // wait() and kill() detached process
2419 {
2420     import core.thread;
2421     import std.exception : assertThrown;
2422     TestScript prog = "exit 0";
2423     auto pid = spawnProcess([prog.path], null, Config.detached);
2424     /*
2425     This sleep is needed because we can't wait() for detached process to end
2426     and therefore TestScript destructor may run at the same time as /bin/sh tries to start the script.
2427     This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
2428     It does not happen in unittests with non-detached processes because we always wait() for them to finish.
2429     */
2430     Thread.sleep(500.msecs);
2431     assert(!pid.owned);
2432     version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2433     assertThrown!ProcessException(wait(pid));
2434     assertThrown!ProcessException(kill(pid));
2435 }
2436 
2437 
2438 /**
2439 Creates a unidirectional _pipe.
2440 
2441 Data is written to one end of the _pipe and read from the other.
2442 ---
2443 auto p = pipe();
2444 p.writeEnd.writeln("Hello World");
2445 p.writeEnd.flush();
2446 assert(p.readEnd.readln().chomp() == "Hello World");
2447 ---
2448 Pipes can, for example, be used for interprocess communication
2449 by spawning a new process and passing one end of the _pipe to
2450 the child, while the parent uses the other end.
2451 (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
2452 way of doing this.)
2453 ---
2454 // Use cURL to download the dlang.org front page, pipe its
2455 // output to grep to extract a list of links to ZIP files,
2456 // and write the list to the file "D downloads.txt":
2457 auto p = pipe();
2458 auto outFile = File("D downloads.txt", "w");
2459 auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
2460                          std.stdio.stdin, p.writeEnd);
2461 scope(exit) wait(cpid);
2462 auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
2463                          p.readEnd, outFile);
2464 scope(exit) wait(gpid);
2465 ---
2466 
2467 Returns:
2468 A $(LREF Pipe) object that corresponds to the created _pipe.
2469 
2470 Throws:
2471 $(REF StdioException, std,stdio) on failure.
2472 */
2473 version (Posix)
2474 Pipe pipe() @trusted //TODO: @safe
2475 {
2476     import core.sys.posix.stdio : fdopen;
2477     int[2] fds;
2478     if (core.sys.posix.unistd.pipe(fds) != 0)
2479         throw new StdioException("Unable to create pipe");
2480     Pipe p;
2481     auto readFP = fdopen(fds[0], "r");
2482     if (readFP == null)
2483         throw new StdioException("Cannot open read end of pipe");
2484     p._read = File(readFP, null);
2485     auto writeFP = fdopen(fds[1], "w");
2486     if (writeFP == null)
2487         throw new StdioException("Cannot open write end of pipe");
2488     p._write = File(writeFP, null);
2489     return p;
2490 }
2491 else version (Windows)
2492 Pipe pipe() @trusted //TODO: @safe
2493 {
2494     // use CreatePipe to create an anonymous pipe
2495     HANDLE readHandle;
2496     HANDLE writeHandle;
2497     if (!CreatePipe(&readHandle, &writeHandle, null, 0))
2498     {
2499         throw new StdioException(
2500             "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
2501             0);
2502     }
2503 
2504     scope(failure)
2505     {
2506         CloseHandle(readHandle);
2507         CloseHandle(writeHandle);
2508     }
2509 
2510     try
2511     {
2512         Pipe p;
2513         p._read .windowsHandleOpen(readHandle , "r");
2514         p._write.windowsHandleOpen(writeHandle, "a");
2515         return p;
2516     }
2517     catch (Exception e)
2518     {
2519         throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
2520             0);
2521     }
2522 }
2523 
2524 
2525 /// An interface to a pipe created by the $(LREF pipe) function.
2526 struct Pipe
2527 {
2528     /// The read end of the pipe.
2529     @property File readEnd() @safe nothrow { return _read; }
2530 
2531 
2532     /// The write end of the pipe.
2533     @property File writeEnd() @safe nothrow { return _write; }
2534 
2535 
2536     /**
2537     Closes both ends of the pipe.
2538 
2539     Normally it is not necessary to do this manually, as $(REF File, std,stdio)
2540     objects are automatically closed when there are no more references
2541     to them.
2542 
2543     Note that if either end of the pipe has been passed to a child process,
2544     it will only be closed in the parent process.  (What happens in the
2545     child process is platform dependent.)
2546 
2547     Throws:
2548     $(REF ErrnoException, std,exception) if an error occurs.
2549     */
2550     void close() @safe
2551     {
2552         _read.close();
2553         _write.close();
2554     }
2555 
2556 private:
2557     File _read, _write;
2558 }
2559 
2560 @system unittest
2561 {
2562     import std..string;
2563     auto p = pipe();
2564     p.writeEnd.writeln("Hello World");
2565     p.writeEnd.flush();
2566     assert(p.readEnd.readln().chomp() == "Hello World");
2567     p.close();
2568     assert(!p.readEnd.isOpen);
2569     assert(!p.writeEnd.isOpen);
2570 }
2571 
2572 
2573 /**
2574 Starts a new process, creating pipes to redirect its standard
2575 input, output and/or error streams.
2576 
2577 `pipeProcess` and `pipeShell` are convenient wrappers around
2578 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and
2579 automate the task of redirecting one or more of the child process'
2580 standard streams through pipes.  Like the functions they wrap,
2581 these functions return immediately, leaving the child process to
2582 execute in parallel with the invoking process.  It is recommended
2583 to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
2584 as detailed in the documentation for `wait`.
2585 
2586 The `args`/`program`/`command`, `env` and `config`
2587 parameters are forwarded straight to the underlying spawn functions,
2588 and we refer to their documentation for details.
2589 
2590 Params:
2591 args      = An array which contains the program name as the zeroth element
2592             and any command-line arguments in the following elements.
2593             (See $(LREF spawnProcess) for details.)
2594 program   = The program name, $(I without) command-line arguments.
2595             (See $(LREF spawnProcess) for details.)
2596 command   = A shell command which is passed verbatim to the command
2597             interpreter.  (See $(LREF spawnShell) for details.)
2598 redirect  = Flags that determine which streams are redirected, and
2599             how.  See $(LREF Redirect) for an overview of available
2600             flags.
2601 env       = Additional environment variables for the child process.
2602             (See $(LREF spawnProcess) for details.)
2603 config    = Flags that control process creation. See $(LREF Config)
2604             for an overview of available flags, and note that the
2605             `retainStd...` flags have no effect in this function.
2606 workDir   = The working directory for the new process.
2607             By default the child process inherits the parent's working
2608             directory.
2609 shellPath = The path to the shell to use to run the specified program.
2610             By default this is $(LREF nativeShell).
2611 
2612 Returns:
2613 A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
2614 handles that communicate with the redirected streams of the child
2615 process, along with a $(LREF Pid) object that corresponds to the
2616 spawned process.
2617 
2618 Throws:
2619 $(LREF ProcessException) on failure to start the process.$(BR)
2620 $(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
2621 
2622 Example:
2623 ---
2624 // my_application writes to stdout and might write to stderr
2625 auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
2626 scope(exit) wait(pipes.pid);
2627 
2628 // Store lines of output.
2629 string[] output;
2630 foreach (line; pipes.stdout.byLine) output ~= line.idup;
2631 
2632 // Store lines of errors.
2633 string[] errors;
2634 foreach (line; pipes.stderr.byLine) errors ~= line.idup;
2635 
2636 
2637 // sendmail expects to read from stdin
2638 pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
2639 pipes.stdin.writeln("To: you");
2640 pipes.stdin.writeln("From: me");
2641 pipes.stdin.writeln("Subject: dlang");
2642 pipes.stdin.writeln("");
2643 pipes.stdin.writeln(message);
2644 
2645 // a single period tells sendmail we are finished
2646 pipes.stdin.writeln(".");
2647 
2648 // but at this point sendmail might not see it, we need to flush
2649 pipes.stdin.flush();
2650 
2651 // sendmail happens to exit on ".", but some you have to close the file:
2652 pipes.stdin.close();
2653 
2654 // otherwise this wait will wait forever
2655 wait(pipes.pid);
2656 
2657 ---
2658 */
2659 ProcessPipes pipeProcess(scope const(char[])[] args,
2660                          Redirect redirect = Redirect.all,
2661                          const string[string] env = null,
2662                          Config config = Config.none,
2663                          scope const(char)[] workDir = null)
2664     @safe
2665 {
2666     return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir);
2667 }
2668 
2669 /// ditto
2670 ProcessPipes pipeProcess(scope const(char)[] program,
2671                          Redirect redirect = Redirect.all,
2672                          const string[string] env = null,
2673                          Config config = Config.none,
2674                          scope const(char)[] workDir = null)
2675     @safe
2676 {
2677     return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir);
2678 }
2679 
2680 /// ditto
2681 ProcessPipes pipeShell(scope const(char)[] command,
2682                        Redirect redirect = Redirect.all,
2683                        const string[string] env = null,
2684                        Config config = Config.none,
2685                        scope const(char)[] workDir = null,
2686                        string shellPath = nativeShell)
2687     @safe
2688 {
2689     return pipeProcessImpl!spawnShell(command,
2690                                       redirect,
2691                                       env,
2692                                       config,
2693                                       workDir,
2694                                       shellPath);
2695 }
2696 
2697 // Implementation of the pipeProcess() family of functions.
2698 private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...)
2699                                     (Cmd command,
2700                                      Redirect redirectFlags,
2701                                      const string[string] env = null,
2702                                      Config config = Config.none,
2703                                      scope const(char)[] workDir = null,
2704                                      ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init)
2705     @trusted //TODO: @safe
2706 {
2707     File childStdin, childStdout, childStderr;
2708     ProcessPipes pipes;
2709     pipes._redirectFlags = redirectFlags;
2710 
2711     if (redirectFlags & Redirect.stdin)
2712     {
2713         auto p = pipe();
2714         childStdin = p.readEnd;
2715         pipes._stdin = p.writeEnd;
2716     }
2717     else
2718     {
2719         childStdin = std.stdio.stdin;
2720     }
2721 
2722     if (redirectFlags & Redirect.stdout)
2723     {
2724         if ((redirectFlags & Redirect.stdoutToStderr) != 0)
2725             throw new StdioException("Cannot create pipe for stdout AND "
2726                                      ~"redirect it to stderr", 0);
2727         auto p = pipe();
2728         childStdout = p.writeEnd;
2729         pipes._stdout = p.readEnd;
2730     }
2731     else
2732     {
2733         childStdout = std.stdio.stdout;
2734     }
2735 
2736     if (redirectFlags & Redirect.stderr)
2737     {
2738         if ((redirectFlags & Redirect.stderrToStdout) != 0)
2739             throw new StdioException("Cannot create pipe for stderr AND "
2740                                      ~"redirect it to stdout", 0);
2741         auto p = pipe();
2742         childStderr = p.writeEnd;
2743         pipes._stderr = p.readEnd;
2744     }
2745     else
2746     {
2747         childStderr = std.stdio.stderr;
2748     }
2749 
2750     if (redirectFlags & Redirect.stdoutToStderr)
2751     {
2752         if (redirectFlags & Redirect.stderrToStdout)
2753         {
2754             // We know that neither of the other options have been
2755             // set, so we assign the std.stdio.std* streams directly.
2756             childStdout = std.stdio.stderr;
2757             childStderr = std.stdio.stdout;
2758         }
2759         else
2760         {
2761             childStdout = childStderr;
2762         }
2763     }
2764     else if (redirectFlags & Redirect.stderrToStdout)
2765     {
2766         childStderr = childStdout;
2767     }
2768 
2769     config &= ~(Config.retainStdin | Config.retainStdout | Config.retainStderr);
2770     pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr,
2771                            env, config, workDir, extraArgs);
2772     return pipes;
2773 }
2774 
2775 
2776 /**
2777 Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
2778 to specify which of the child process' standard streams are redirected.
2779 Use bitwise OR to combine flags.
2780 */
2781 enum Redirect
2782 {
2783     /// Redirect the standard input, output or error streams, respectively.
2784     stdin = 1,
2785     stdout = 2,                             /// ditto
2786     stderr = 4,                             /// ditto
2787 
2788     /**
2789     Redirect _all three streams.  This is equivalent to
2790     $(D Redirect.stdin | Redirect.stdout | Redirect.stderr).
2791     */
2792     all = stdin | stdout | stderr,
2793 
2794     /**
2795     Redirect the standard error stream into the standard output stream.
2796     This can not be combined with `Redirect.stderr`.
2797     */
2798     stderrToStdout = 8,
2799 
2800     /**
2801     Redirect the standard output stream into the standard error stream.
2802     This can not be combined with `Redirect.stdout`.
2803     */
2804     stdoutToStderr = 16,
2805 }
2806 
2807 @system unittest
2808 {
2809     import std..string;
2810     version (Windows) TestScript prog =
2811        "call :sub %~1 %~2 0
2812         call :sub %~1 %~2 1
2813         call :sub %~1 %~2 2
2814         call :sub %~1 %~2 3
2815         exit 3
2816 
2817         :sub
2818         set /p INPUT=
2819         if -%INPUT%-==-stop- ( exit %~3 )
2820         echo %INPUT% %~1
2821         echo %INPUT% %~2 1>&2";
2822     else version (Posix) TestScript prog =
2823        `for EXITCODE in 0 1 2 3; do
2824             read INPUT
2825             if test "$INPUT" = stop; then break; fi
2826             echo "$INPUT $1"
2827             echo "$INPUT $2" >&2
2828         done
2829         exit $EXITCODE`;
2830     auto pp = pipeProcess([prog.path, "bar", "baz"]);
2831     pp.stdin.writeln("foo");
2832     pp.stdin.flush();
2833     assert(pp.stdout.readln().chomp() == "foo bar");
2834     assert(pp.stderr.readln().chomp().stripRight() == "foo baz");
2835     pp.stdin.writeln("1234567890");
2836     pp.stdin.flush();
2837     assert(pp.stdout.readln().chomp() == "1234567890 bar");
2838     assert(pp.stderr.readln().chomp().stripRight() == "1234567890 baz");
2839     pp.stdin.writeln("stop");
2840     pp.stdin.flush();
2841     assert(wait(pp.pid) == 2);
2842 
2843     pp = pipeProcess([prog.path, "12345", "67890"],
2844                      Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout);
2845     pp.stdin.writeln("xyz");
2846     pp.stdin.flush();
2847     assert(pp.stdout.readln().chomp() == "xyz 12345");
2848     assert(pp.stdout.readln().chomp().stripRight() == "xyz 67890");
2849     pp.stdin.writeln("stop");
2850     pp.stdin.flush();
2851     assert(wait(pp.pid) == 1);
2852 
2853     pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"),
2854                    Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr);
2855     pp.stdin.writeln("ab");
2856     pp.stdin.flush();
2857     assert(pp.stderr.readln().chomp() == "ab AAAAA");
2858     assert(pp.stderr.readln().chomp().stripRight() == "ab BBB");
2859     pp.stdin.writeln("stop");
2860     pp.stdin.flush();
2861     assert(wait(pp.pid) == 1);
2862 }
2863 
2864 @system unittest
2865 {
2866     import std.exception : assertThrown;
2867     TestScript prog = "exit 0";
2868     assertThrown!StdioException(pipeProcess(
2869         prog.path,
2870         Redirect.stdout | Redirect.stdoutToStderr));
2871     assertThrown!StdioException(pipeProcess(
2872         prog.path,
2873         Redirect.stderr | Redirect.stderrToStdout));
2874     auto p = pipeProcess(prog.path, Redirect.stdin);
2875     assertThrown!Error(p.stdout);
2876     assertThrown!Error(p.stderr);
2877     wait(p.pid);
2878     p = pipeProcess(prog.path, Redirect.stderr);
2879     assertThrown!Error(p.stdin);
2880     assertThrown!Error(p.stdout);
2881     wait(p.pid);
2882 }
2883 
2884 /**
2885 Object which contains $(REF File, std,stdio) handles that allow communication
2886 with a child process through its standard streams.
2887 */
2888 struct ProcessPipes
2889 {
2890     /// The $(LREF Pid) of the child process.
2891     @property Pid pid() @safe nothrow
2892     {
2893         return _pid;
2894     }
2895 
2896     /**
2897     An $(REF File, std,stdio) that allows writing to the child process'
2898     standard input stream.
2899 
2900     Throws:
2901     $(OBJECTREF Error) if the child process' standard input stream hasn't
2902     been redirected.
2903     */
2904     @property File stdin() @safe nothrow
2905     {
2906         if ((_redirectFlags & Redirect.stdin) == 0)
2907             throw new Error("Child process' standard input stream hasn't "
2908                             ~"been redirected.");
2909         return _stdin;
2910     }
2911 
2912     /**
2913     An $(REF File, std,stdio) that allows reading from the child process'
2914     standard output stream.
2915 
2916     Throws:
2917     $(OBJECTREF Error) if the child process' standard output stream hasn't
2918     been redirected.
2919     */
2920     @property File stdout() @safe nothrow
2921     {
2922         if ((_redirectFlags & Redirect.stdout) == 0)
2923             throw new Error("Child process' standard output stream hasn't "
2924                             ~"been redirected.");
2925         return _stdout;
2926     }
2927 
2928     /**
2929     An $(REF File, std,stdio) that allows reading from the child process'
2930     standard error stream.
2931 
2932     Throws:
2933     $(OBJECTREF Error) if the child process' standard error stream hasn't
2934     been redirected.
2935     */
2936     @property File stderr() @safe nothrow
2937     {
2938         if ((_redirectFlags & Redirect.stderr) == 0)
2939             throw new Error("Child process' standard error stream hasn't "
2940                             ~"been redirected.");
2941         return _stderr;
2942     }
2943 
2944 private:
2945     Redirect _redirectFlags;
2946     Pid _pid;
2947     File _stdin, _stdout, _stderr;
2948 }
2949 
2950 
2951 
2952 /**
2953 Executes the given program or shell command and returns its exit
2954 code and output.
2955 
2956 `execute` and `executeShell` start a new process using
2957 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait
2958 for the process to complete before returning.  The functions capture
2959 what the child process prints to both its standard output and
2960 standard error streams, and return this together with its exit code.
2961 ---
2962 auto dmd = execute(["dmd", "myapp.d"]);
2963 if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
2964 
2965 auto ls = executeShell("ls -l");
2966 if (ls.status != 0) writeln("Failed to retrieve file listing");
2967 else writeln(ls.output);
2968 ---
2969 
2970 The `args`/`program`/`command`, `env` and `config`
2971 parameters are forwarded straight to the underlying spawn functions,
2972 and we refer to their documentation for details.
2973 
2974 Params:
2975 args      = An array which contains the program name as the zeroth element
2976             and any command-line arguments in the following elements.
2977             (See $(LREF spawnProcess) for details.)
2978 program   = The program name, $(I without) command-line arguments.
2979             (See $(LREF spawnProcess) for details.)
2980 command   = A shell command which is passed verbatim to the command
2981             interpreter.  (See $(LREF spawnShell) for details.)
2982 env       = Additional environment variables for the child process.
2983             (See $(LREF spawnProcess) for details.)
2984 config    = Flags that control process creation. See $(LREF Config)
2985             for an overview of available flags, and note that the
2986             `retainStd...` flags have no effect in this function.
2987 maxOutput = The maximum number of bytes of output that should be
2988             captured.
2989 workDir   = The working directory for the new process.
2990             By default the child process inherits the parent's working
2991             directory.
2992 shellPath = The path to the shell to use to run the specified program.
2993             By default this is $(LREF nativeShell).
2994 
2995 
2996 Returns:
2997 An $(D std.typecons.Tuple!(int, "status", string, "output")).
2998 
2999 POSIX_specific:
3000 If the process is terminated by a signal, the `status` field of
3001 the return value will contain a negative number whose absolute
3002 value is the signal number.  (See $(LREF wait) for details.)
3003 
3004 Throws:
3005 $(LREF ProcessException) on failure to start the process.$(BR)
3006 $(REF StdioException, std,stdio) on failure to capture output.
3007 */
3008 auto execute(scope const(char[])[] args,
3009              const string[string] env = null,
3010              Config config = Config.none,
3011              size_t maxOutput = size_t.max,
3012              scope const(char)[] workDir = null)
3013     @trusted //TODO: @safe
3014 {
3015     return executeImpl!pipeProcess(args, env, config, maxOutput, workDir);
3016 }
3017 
3018 /// ditto
3019 auto execute(scope const(char)[] program,
3020              const string[string] env = null,
3021              Config config = Config.none,
3022              size_t maxOutput = size_t.max,
3023              scope const(char)[] workDir = null)
3024     @trusted //TODO: @safe
3025 {
3026     return executeImpl!pipeProcess(program, env, config, maxOutput, workDir);
3027 }
3028 
3029 /// ditto
3030 auto executeShell(scope const(char)[] command,
3031                   const string[string] env = null,
3032                   Config config = Config.none,
3033                   size_t maxOutput = size_t.max,
3034                   scope const(char)[] workDir = null,
3035                   string shellPath = nativeShell)
3036     @trusted //TODO: @safe
3037 {
3038     return executeImpl!pipeShell(command,
3039                                  env,
3040                                  config,
3041                                  maxOutput,
3042                                  workDir,
3043                                  shellPath);
3044 }
3045 
3046 // Does the actual work for execute() and executeShell().
3047 private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
3048     Cmd commandLine,
3049     const string[string] env = null,
3050     Config config = Config.none,
3051     size_t maxOutput = size_t.max,
3052     scope const(char)[] workDir = null,
3053     ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init)
3054 {
3055     import std.algorithm.comparison : min;
3056     import std.array : appender;
3057     import std.typecons : Tuple;
3058 
3059     auto redirect = (config & Config.stderrPassThrough)
3060         ? Redirect.stdout
3061         : Redirect.stdout | Redirect.stderrToStdout;
3062 
3063     auto p = pipeFunc(commandLine, redirect,
3064                       env, config, workDir, extraArgs);
3065 
3066     auto a = appender!string;
3067     enum size_t defaultChunkSize = 4096;
3068     immutable chunkSize = min(maxOutput, defaultChunkSize);
3069 
3070     // Store up to maxOutput bytes in a.
3071     foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize))
3072     {
3073         immutable size_t remain = maxOutput - a.data.length;
3074 
3075         if (chunk.length < remain) a.put(chunk);
3076         else
3077         {
3078             a.put(chunk[0 .. remain]);
3079             break;
3080         }
3081     }
3082     // Exhaust the stream, if necessary.
3083     foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { }
3084 
3085     return Tuple!(int, "status", string, "output")(wait(p.pid), a.data);
3086 }
3087 
3088 @system unittest
3089 {
3090     import std..string;
3091     // To avoid printing the newline characters, we use the echo|set trick on
3092     // Windows, and printf on POSIX (neither echo -n nor echo \c are portable).
3093     version (Windows) TestScript prog =
3094        "echo|set /p=%~1
3095         echo|set /p=%~2 1>&2
3096         exit 123";
3097     else version (Android) TestScript prog =
3098        `echo -n $1
3099         echo -n $2 >&2
3100         exit 123`;
3101     else version (Posix) TestScript prog =
3102        `printf '%s' $1
3103         printf '%s' $2 >&2
3104         exit 123`;
3105     auto r = execute([prog.path, "foo", "bar"]);
3106     assert(r.status == 123);
3107     assert(r.output.stripRight() == "foobar");
3108     auto s = execute([prog.path, "Hello", "World"]);
3109     assert(s.status == 123);
3110     assert(s.output.stripRight() == "HelloWorld");
3111 }
3112 
3113 @safe unittest
3114 {
3115     import std..string;
3116     auto r1 = executeShell("echo foo");
3117     assert(r1.status == 0);
3118     assert(r1.output.chomp() == "foo");
3119     auto r2 = executeShell("echo bar 1>&2");
3120     assert(r2.status == 0);
3121     assert(r2.output.chomp().stripRight() == "bar");
3122     auto r3 = executeShell("exit 123");
3123     assert(r3.status == 123);
3124     assert(r3.output.empty);
3125     auto r4 = executeShell("echo stderr test, please ignore 1>&2",
3126         null, Config.stderrPassThrough);
3127     assert(r4.status == 0);
3128     assert(r4.output.empty);
3129 }
3130 
3131 @safe unittest
3132 {
3133     import std.typecons : Tuple;
3134     void foo() //Just test the compilation
3135     {
3136         auto ret1 = execute(["dummy", "arg"]);
3137         auto ret2 = executeShell("dummy arg");
3138         static assert(is(typeof(ret1) == typeof(ret2)));
3139 
3140         Tuple!(int, string) ret3 = execute(["dummy", "arg"]);
3141     }
3142 }
3143 
3144 /// An exception that signals a problem with starting or waiting for a process.
3145 class ProcessException : Exception
3146 {
3147     import std.exception : basicExceptionCtors;
3148     mixin basicExceptionCtors;
3149 
3150     // Creates a new ProcessException based on errno.
3151     static ProcessException newFromErrno(string customMsg = null,
3152                                          string file = __FILE__,
3153                                          size_t line = __LINE__)
3154     {
3155         import core.stdc.errno : errno;
3156         return newFromErrno(errno, customMsg, file, line);
3157     }
3158 
3159     // ditto, but error number is provided by caller
3160     static ProcessException newFromErrno(int error,
3161                                          string customMsg = null,
3162                                          string file = __FILE__,
3163                                          size_t line = __LINE__)
3164     {
3165         import std.exception : errnoString;
3166         auto errnoMsg = errnoString(error);
3167         auto msg = customMsg.empty ? errnoMsg
3168                                    : customMsg ~ " (" ~ errnoMsg ~ ')';
3169         return new ProcessException(msg, file, line);
3170     }
3171 
3172     // Creates a new ProcessException based on GetLastError() (Windows only).
3173     version (Windows)
3174     static ProcessException newFromLastError(string customMsg = null,
3175                                              string file = __FILE__,
3176                                              size_t line = __LINE__)
3177     {
3178         auto lastMsg = sysErrorString(GetLastError());
3179         auto msg = customMsg.empty ? lastMsg
3180                                    : customMsg ~ " (" ~ lastMsg ~ ')';
3181         return new ProcessException(msg, file, line);
3182     }
3183 }
3184 
3185 
3186 /**
3187 Determines the path to the current user's preferred command interpreter.
3188 
3189 On Windows, this function returns the contents of the COMSPEC environment
3190 variable, if it exists.  Otherwise, it returns the result of $(LREF nativeShell).
3191 
3192 On POSIX, `userShell` returns the contents of the SHELL environment
3193 variable, if it exists and is non-empty.  Otherwise, it returns the result of
3194 $(LREF nativeShell).
3195 */
3196 @property string userShell() @safe
3197 {
3198     version (Windows)      return environment.get("COMSPEC", nativeShell);
3199     else version (Posix)   return environment.get("SHELL", nativeShell);
3200 }
3201 
3202 /**
3203 The platform-specific native shell path.
3204 
3205 This function returns `"cmd.exe"` on Windows, `"/bin/sh"` on POSIX, and
3206 `"/system/bin/sh"` on Android.
3207 */
3208 @property string nativeShell() @safe @nogc pure nothrow
3209 {
3210     version (Windows)      return "cmd.exe";
3211     else version (Android) return "/system/bin/sh";
3212     else version (Posix)   return "/bin/sh";
3213 }
3214 
3215 // A command-line switch that indicates to the shell that it should
3216 // interpret the following argument as a command to be executed.
3217 version (Posix)   private immutable string shellSwitch = "-c";
3218 version (Windows) private immutable string shellSwitch = "/C";
3219 
3220 // Unittest support code:  TestScript takes a string that contains a
3221 // shell script for the current platform, and writes it to a temporary
3222 // file. On Windows the file name gets a .cmd extension, while on
3223 // POSIX its executable permission bit is set.  The file is
3224 // automatically deleted when the object goes out of scope.
3225 version (StdUnittest)
3226 private struct TestScript
3227 {
3228     this(string code) @system
3229     {
3230         // @system due to chmod
3231         import std.ascii : newline;
3232         import std.file : write;
3233         version (Windows)
3234         {
3235             auto ext = ".cmd";
3236             auto firstLine = "@echo off";
3237         }
3238         else version (Posix)
3239         {
3240             auto ext = "";
3241             auto firstLine = "#!" ~ nativeShell;
3242         }
3243         path = uniqueTempPath()~ext;
3244         write(path, firstLine ~ newline ~ code ~ newline);
3245         version (Posix)
3246         {
3247             import core.sys.posix.sys.stat : chmod;
3248             import std.conv : octal;
3249             chmod(path.tempCString(), octal!777);
3250         }
3251     }
3252 
3253     ~this()
3254     {
3255         import std.file : remove, exists;
3256         if (!path.empty && exists(path))
3257         {
3258             try { remove(path); }
3259             catch (Exception e)
3260             {
3261                 debug std.stdio.stderr.writeln(e.msg);
3262             }
3263         }
3264     }
3265 
3266     string path;
3267 }
3268 
3269 version (StdUnittest)
3270 private string uniqueTempPath() @safe
3271 {
3272     import std.file : tempDir;
3273     import std.path : buildPath;
3274     import std.uuid : randomUUID;
3275     // Path should contain spaces to test escaping whitespace
3276     return buildPath(tempDir(), "std.process temporary file " ~
3277         randomUUID().toString());
3278 }
3279 
3280 
3281 // =============================================================================
3282 // Functions for shell command quoting/escaping.
3283 // =============================================================================
3284 
3285 
3286 /*
3287     Command line arguments exist in three forms:
3288     1) string or char* array, as received by main.
3289        Also used internally on POSIX systems.
3290     2) Command line string, as used in Windows'
3291        CreateProcess and CommandLineToArgvW functions.
3292        A specific quoting and escaping algorithm is used
3293        to distinguish individual arguments.
3294     3) Shell command string, as written at a shell prompt
3295        or passed to cmd /C - this one may contain shell
3296        control characters, e.g. > or | for redirection /
3297        piping - thus, yet another layer of escaping is
3298        used to distinguish them from program arguments.
3299 
3300     Except for escapeWindowsArgument, the intermediary
3301     format (2) is hidden away from the user in this module.
3302 */
3303 
3304 /**
3305 Escapes an argv-style argument array to be used with $(LREF spawnShell),
3306 $(LREF pipeShell) or $(LREF executeShell).
3307 ---
3308 string url = "http://dlang.org/";
3309 executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html"));
3310 ---
3311 
3312 Concatenate multiple `escapeShellCommand` and
3313 $(LREF escapeShellFileName) results to use shell redirection or
3314 piping operators.
3315 ---
3316 executeShell(
3317     escapeShellCommand("curl", "http://dlang.org/download.html") ~
3318     "|" ~
3319     escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
3320     ">" ~
3321     escapeShellFileName("D download links.txt"));
3322 ---
3323 
3324 Throws:
3325 $(OBJECTREF Exception) if any part of the command line contains unescapable
3326 characters (NUL on all platforms, as well as CR and LF on Windows).
3327 */
3328 string escapeShellCommand(scope const(char[])[] args...) @safe pure
3329 {
3330     if (args.empty)
3331         return null;
3332     version (Windows)
3333     {
3334         // Do not ^-escape the first argument (the program path),
3335         // as the shell parses it differently from parameters.
3336         // ^-escaping a program path that contains spaces will fail.
3337         string result = escapeShellFileName(args[0]);
3338         if (args.length > 1)
3339         {
3340             result ~= " " ~ escapeShellCommandString(
3341                 escapeShellArguments(args[1..$]));
3342         }
3343         return result;
3344     }
3345     version (Posix)
3346     {
3347         return escapeShellCommandString(escapeShellArguments(args));
3348     }
3349 }
3350 
3351 @safe unittest
3352 {
3353     // This is a simple unit test without any special requirements,
3354     // in addition to the unittest_burnin one below which requires
3355     // special preparation.
3356 
3357     struct TestVector { string[] args; string windows, posix; }
3358     TestVector[] tests =
3359     [
3360         {
3361             args    : ["foo bar"],
3362             windows : `"foo bar"`,
3363             posix   : `'foo bar'`
3364         },
3365         {
3366             args    : ["foo bar", "hello"],
3367             windows : `"foo bar" hello`,
3368             posix   : `'foo bar' 'hello'`
3369         },
3370         {
3371             args    : ["foo bar", "hello world"],
3372             windows : `"foo bar" ^"hello world^"`,
3373             posix   : `'foo bar' 'hello world'`
3374         },
3375         {
3376             args    : ["foo bar", "hello", "world"],
3377             windows : `"foo bar" hello world`,
3378             posix   : `'foo bar' 'hello' 'world'`
3379         },
3380         {
3381             args    : ["foo bar", `'"^\`],
3382             windows : `"foo bar" ^"'\^"^^\\^"`,
3383             posix   : `'foo bar' ''\''"^\'`
3384         },
3385     ];
3386 
3387     foreach (test; tests)
3388         version (Windows)
3389             assert(escapeShellCommand(test.args) == test.windows);
3390         else
3391             assert(escapeShellCommand(test.args) == test.posix  );
3392 }
3393 
3394 private string escapeShellCommandString(string command) @safe pure
3395 {
3396     version (Windows)
3397         return escapeWindowsShellCommand(command);
3398     else
3399         return command;
3400 }
3401 
3402 private string escapeWindowsShellCommand(scope const(char)[] command) @safe pure
3403 {
3404     import std.array : appender;
3405     auto result = appender!string();
3406     result.reserve(command.length);
3407 
3408     foreach (c; command)
3409         switch (c)
3410         {
3411             case '\0':
3412                 throw new Exception("Cannot put NUL in command line");
3413             case '\r':
3414             case '\n':
3415                 throw new Exception("CR/LF are not escapable");
3416             case '\x01': .. case '\x09':
3417             case '\x0B': .. case '\x0C':
3418             case '\x0E': .. case '\x1F':
3419             case '"':
3420             case '^':
3421             case '&':
3422             case '<':
3423             case '>':
3424             case '|':
3425                 result.put('^');
3426                 goto default;
3427             default:
3428                 result.put(c);
3429         }
3430     return result.data;
3431 }
3432 
3433 private string escapeShellArguments(scope const(char[])[] args...)
3434     @trusted pure nothrow
3435 {
3436     import std.exception : assumeUnique;
3437     char[] buf;
3438 
3439     @safe nothrow
3440     char[] allocator(size_t size)
3441     {
3442         if (buf.length == 0)
3443             return buf = new char[size];
3444         else
3445         {
3446             auto p = buf.length;
3447             buf.length = buf.length + 1 + size;
3448             buf[p++] = ' ';
3449             return buf[p .. p+size];
3450         }
3451     }
3452 
3453     foreach (arg; args)
3454         escapeShellArgument!allocator(arg);
3455     return assumeUnique(buf);
3456 }
3457 
3458 private auto escapeShellArgument(alias allocator)(scope const(char)[] arg) @safe nothrow
3459 {
3460     // The unittest for this function requires special
3461     // preparation - see below.
3462 
3463     version (Windows)
3464         return escapeWindowsArgumentImpl!allocator(arg);
3465     else
3466         return escapePosixArgumentImpl!allocator(arg);
3467 }
3468 
3469 /**
3470 Quotes a command-line argument in a manner conforming to the behavior of
3471 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
3472 CommandLineToArgvW).
3473 */
3474 string escapeWindowsArgument(scope const(char)[] arg) @trusted pure nothrow
3475 {
3476     // Rationale for leaving this function as public:
3477     // this algorithm of escaping paths is also used in other software,
3478     // e.g. DMD's response files.
3479     import std.exception : assumeUnique;
3480     auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
3481     return assumeUnique(buf);
3482 }
3483 
3484 
3485 private char[] charAllocator(size_t size) @safe pure nothrow
3486 {
3487     return new char[size];
3488 }
3489 
3490 
3491 private char[] escapeWindowsArgumentImpl(alias allocator)(scope const(char)[] arg)
3492     @safe nothrow
3493 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3494 {
3495     // References:
3496     // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
3497     // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
3498 
3499     // Check if the string needs to be escaped,
3500     // and calculate the total string size.
3501 
3502     // Trailing backslashes must be escaped
3503     bool escaping = true;
3504     bool needEscape = false;
3505     // Result size = input size + 2 for surrounding quotes + 1 for the
3506     // backslash for each escaped character.
3507     size_t size = 1 + arg.length + 1;
3508 
3509     foreach_reverse (char c; arg)
3510     {
3511         if (c == '"')
3512         {
3513             needEscape = true;
3514             escaping = true;
3515             size++;
3516         }
3517         else
3518         if (c == '\\')
3519         {
3520             if (escaping)
3521                 size++;
3522         }
3523         else
3524         {
3525             if (c == ' ' || c == '\t')
3526                 needEscape = true;
3527             escaping = false;
3528         }
3529     }
3530 
3531     import std.ascii : isDigit;
3532     // Empty arguments need to be specified as ""
3533     if (!arg.length)
3534         needEscape = true;
3535     else
3536     // Arguments ending with digits need to be escaped,
3537     // to disambiguate with 1>file redirection syntax
3538     if (isDigit(arg[$-1]))
3539         needEscape = true;
3540 
3541     if (!needEscape)
3542         return allocator(arg.length)[] = arg;
3543 
3544     // Construct result string.
3545 
3546     auto buf = allocator(size);
3547     size_t p = size;
3548     buf[--p] = '"';
3549     escaping = true;
3550     foreach_reverse (char c; arg)
3551     {
3552         if (c == '"')
3553             escaping = true;
3554         else
3555         if (c != '\\')
3556             escaping = false;
3557 
3558         buf[--p] = c;
3559         if (escaping)
3560             buf[--p] = '\\';
3561     }
3562     buf[--p] = '"';
3563     assert(p == 0);
3564 
3565     return buf;
3566 }
3567 
3568 version (Windows) version (StdUnittest)
3569 {
3570 private:
3571     import core.stdc.stddef;
3572     import core.stdc.wchar_ : wcslen;
3573     import core.sys.windows.shellapi : CommandLineToArgvW;
3574     import core.sys.windows.winbase;
3575     import core.sys.windows.winnt;
3576     import std.array;
3577 
3578     string[] parseCommandLine(string line)
3579     {
3580         import std.algorithm.iteration : map;
3581         import std.array : array;
3582         import std.conv : to;
3583         auto lpCommandLine = (to!(WCHAR[])(line) ~ '\0').ptr;
3584         int numArgs;
3585         auto args = CommandLineToArgvW(lpCommandLine, &numArgs);
3586         scope(exit) LocalFree(args);
3587         return args[0 .. numArgs]
3588             .map!(arg => to!string(arg[0 .. wcslen(arg)]))
3589             .array();
3590     }
3591 
3592     @system unittest
3593     {
3594         import std.conv : text;
3595         string[] testStrings = [
3596             `Hello`,
3597             `Hello, world`,
3598             `Hello, "world"`,
3599             `C:\`,
3600             `C:\dmd`,
3601             `C:\Program Files\`,
3602         ];
3603 
3604         enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing
3605         foreach (c1; CHARS)
3606         foreach (c2; CHARS)
3607         foreach (c3; CHARS)
3608         foreach (c4; CHARS)
3609             testStrings ~= [c1, c2, c3, c4].replace("_", "");
3610 
3611         foreach (s; testStrings)
3612         {
3613             auto q = escapeWindowsArgument(s);
3614             auto args = parseCommandLine("Dummy.exe " ~ q);
3615             assert(args.length == 2, s ~ " => " ~ q ~ " #" ~ text(args.length-1));
3616             assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]);
3617         }
3618     }
3619 }
3620 
3621 private string escapePosixArgument(scope const(char)[] arg) @trusted pure nothrow
3622 {
3623     import std.exception : assumeUnique;
3624     auto buf = escapePosixArgumentImpl!charAllocator(arg);
3625     return assumeUnique(buf);
3626 }
3627 
3628 private char[] escapePosixArgumentImpl(alias allocator)(scope const(char)[] arg)
3629     @safe nothrow
3630 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3631 {
3632     // '\'' means: close quoted part of argument, append an escaped
3633     // single quote, and reopen quotes
3634 
3635     // Below code is equivalent to:
3636     // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
3637 
3638     size_t size = 1 + arg.length + 1;
3639     foreach (char c; arg)
3640         if (c == '\'')
3641             size += 3;
3642 
3643     auto buf = allocator(size);
3644     size_t p = 0;
3645     buf[p++] = '\'';
3646     foreach (char c; arg)
3647         if (c == '\'')
3648         {
3649             buf[p .. p+4] = `'\''`;
3650             p += 4;
3651         }
3652         else
3653             buf[p++] = c;
3654     buf[p++] = '\'';
3655     assert(p == size);
3656 
3657     return buf;
3658 }
3659 
3660 /**
3661 Escapes a filename to be used for shell redirection with $(LREF spawnShell),
3662 $(LREF pipeShell) or $(LREF executeShell).
3663 */
3664 string escapeShellFileName(scope const(char)[] fileName) @trusted pure nothrow
3665 {
3666     // The unittest for this function requires special
3667     // preparation - see below.
3668 
3669     version (Windows)
3670     {
3671         // If a file starts with &, it can cause cmd.exe to misinterpret
3672         // the file name as the stream redirection syntax:
3673         //     command > "&foo.txt"
3674         // gets interpreted as
3675         //     command >&foo.txt
3676         // Prepend .\ to disambiguate.
3677 
3678         if (fileName.length && fileName[0] == '&')
3679             return cast(string)(`".\` ~ fileName ~ '"');
3680 
3681         return cast(string)('"' ~ fileName ~ '"');
3682     }
3683     else
3684         return escapePosixArgument(fileName);
3685 }
3686 
3687 // Loop generating strings with random characters
3688 //version = unittest_burnin;
3689 
3690 version (unittest_burnin)
3691 @system unittest
3692 {
3693     // There are no readily-available commands on all platforms suitable
3694     // for properly testing command escaping. The behavior of CMD's "echo"
3695     // built-in differs from the POSIX program, and Windows ports of POSIX
3696     // environments (Cygwin, msys, gnuwin32) may interfere with their own
3697     // "echo" ports.
3698 
3699     // To run this unit test, create std_process_unittest_helper.d with the
3700     // following content and compile it:
3701     // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
3702     // Then, test this module with:
3703     // rdmd --main -unittest -version=unittest_burnin process.d
3704 
3705     auto helper = absolutePath("std_process_unittest_helper");
3706     assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
3707 
3708     void test(string[] s, string fn)
3709     {
3710         string e;
3711         string[] g;
3712 
3713         e = escapeShellCommand(helper ~ s);
3714         {
3715             scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
3716             auto result = executeShell(e);
3717             assert(result.status == 0, "std_process_unittest_helper failed");
3718             g = result.output.split("\0")[1..$];
3719         }
3720         assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
3721 
3722         e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
3723         {
3724             scope(failure) writefln(
3725                 "executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
3726             auto result = executeShell(e);
3727             assert(result.status == 0, "std_process_unittest_helper failed");
3728             assert(!result.output.length, "No output expected, got:\n" ~ result.output);
3729             g = readText(fn).split("\0")[1..$];
3730         }
3731         remove(fn);
3732         assert(s == g,
3733             format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
3734     }
3735 
3736     while (true)
3737     {
3738         string[] args;
3739         foreach (n; 0 .. uniform(1, 4))
3740         {
3741             string arg;
3742             foreach (l; 0 .. uniform(0, 10))
3743             {
3744                 dchar c;
3745                 while (true)
3746                 {
3747                     version (Windows)
3748                     {
3749                         // As long as DMD's system() uses CreateProcessA,
3750                         // we can't reliably pass Unicode
3751                         c = uniform(0, 128);
3752                     }
3753                     else
3754                         c = uniform!ubyte();
3755 
3756                     if (c == 0)
3757                         continue; // argv-strings are zero-terminated
3758                     version (Windows)
3759                         if (c == '\r' || c == '\n')
3760                             continue; // newlines are unescapable on Windows
3761                     break;
3762                 }
3763                 arg ~= c;
3764             }
3765             args ~= arg;
3766         }
3767 
3768         // generate filename
3769         string fn;
3770         foreach (l; 0 .. uniform(1, 10))
3771         {
3772             dchar c;
3773             while (true)
3774             {
3775                 version (Windows)
3776                     c = uniform(0, 128); // as above
3777                 else
3778                     c = uniform!ubyte();
3779 
3780                 if (c == 0 || c == '/')
3781                     continue; // NUL and / are the only characters
3782                               // forbidden in POSIX filenames
3783                 version (Windows)
3784                     if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
3785                         c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
3786                         continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
3787                 break;
3788             }
3789 
3790             fn ~= c;
3791         }
3792         fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$];
3793 
3794         test(args, fn);
3795     }
3796 }
3797 
3798 // =============================================================================
3799 // Everything below this line was part of the old std.process, and most of
3800 // it will be deprecated and removed.
3801 // =============================================================================
3802 
3803 
3804 /*
3805 Copyright: Copyright The D Language Foundation 2007 - 2009.
3806 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
3807 Authors:   $(HTTP digitalmars.com, Walter Bright),
3808            $(HTTP erdani.org, Andrei Alexandrescu),
3809            $(HTTP thecybershadow.net, Vladimir Panteleev)
3810 Source:    $(PHOBOSSRC std/_process.d)
3811 */
3812 /*
3813          Copyright The D Language Foundation 2007 - 2009.
3814 Distributed under the Boost Software License, Version 1.0.
3815    (See accompanying file LICENSE_1_0.txt or copy at
3816          http://www.boost.org/LICENSE_1_0.txt)
3817 */
3818 
3819 
3820 import core.stdc.errno;
3821 import core.stdc.stdlib;
3822 import core.stdc..string;
3823 import core.thread;
3824 
3825 version (Windows)
3826 {
3827     import std.file, std.format, std.random;
3828 }
3829 version (Posix)
3830 {
3831     import core.sys.posix.stdlib;
3832 }
3833 
3834 private void toAStringz(in string[] a, const(char)**az)
3835 {
3836     import std..string : toStringz;
3837     foreach (string s; a)
3838     {
3839         *az++ = toStringz(s);
3840     }
3841     *az = null;
3842 }
3843 
3844 
3845 /* ========================================================== */
3846 
3847 //version (Windows)
3848 //{
3849 //    int spawnvp(int mode, string pathname, string[] argv)
3850 //    {
3851 //      char** argv_ = cast(char**) core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3852 //      scope(exit) core.stdc.stdlib.free(argv_);
3853 //
3854 //      toAStringz(argv, argv_);
3855 //
3856 //      return spawnvp(mode, pathname.tempCString(), argv_);
3857 //    }
3858 //}
3859 
3860 // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo
3861 
3862 enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }
3863 version (Windows) extern(C) int spawnvp(int, scope const(char) *, scope const(char*)*);
3864 alias P_WAIT = _P_WAIT;
3865 alias P_NOWAIT = _P_NOWAIT;
3866 
3867 /* ========================================================== */
3868 
3869 version (StdDdoc)
3870 {
3871     /**
3872     Replaces the current process by executing a command, `pathname`, with
3873     the arguments in `argv`.
3874 
3875     $(BLUE This function is Posix-Only.)
3876 
3877     Typically, the first element of `argv` is
3878     the command being executed, i.e. $(D argv[0] == pathname). The 'p'
3879     versions of `exec` search the PATH environment variable for $(D
3880     pathname). The 'e' versions additionally take the new process'
3881     environment variables as an array of strings of the form key=value.
3882 
3883     Does not return on success (the current process will have been
3884     replaced). Returns -1 on failure with no indication of the
3885     underlying error.
3886 
3887     Windows_specific:
3888     These functions are only supported on POSIX platforms, as the Windows
3889     operating systems do not provide the ability to overwrite the current
3890     process image with another. In single-threaded programs it is possible
3891     to approximate the effect of `execv*` by using $(LREF spawnProcess)
3892     and terminating the current process once the child process has returned.
3893     For example:
3894     ---
3895     auto commandLine = [ "program", "arg1", "arg2" ];
3896     version (Posix)
3897     {
3898         execv(commandLine[0], commandLine);
3899         throw new Exception("Failed to execute program");
3900     }
3901     else version (Windows)
3902     {
3903         import core.stdc.stdlib : _Exit;
3904         _Exit(wait(spawnProcess(commandLine)));
3905     }
3906     ---
3907     This is, however, NOT equivalent to POSIX' `execv*`.  For one thing, the
3908     executed program is started as a separate process, with all this entails.
3909     Secondly, in a multithreaded program, other threads will continue to do
3910     work while the current thread is waiting for the child process to complete.
3911 
3912     A better option may sometimes be to terminate the current program immediately
3913     after spawning the child process.  This is the behaviour exhibited by the
3914     $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,`__exec`)
3915     functions in Microsoft's C runtime library, and it is how D's now-deprecated
3916     Windows `execv*` functions work. Example:
3917     ---
3918     auto commandLine = [ "program", "arg1", "arg2" ];
3919     version (Posix)
3920     {
3921         execv(commandLine[0], commandLine);
3922         throw new Exception("Failed to execute program");
3923     }
3924     else version (Windows)
3925     {
3926         spawnProcess(commandLine);
3927         import core.stdc.stdlib : _exit;
3928         _exit(0);
3929     }
3930     ---
3931     */
3932     int execv(in string pathname, in string[] argv);
3933     ///ditto
3934     int execve(in string pathname, in string[] argv, in string[] envp);
3935     /// ditto
3936     int execvp(in string pathname, in string[] argv);
3937     /// ditto
3938     int execvpe(in string pathname, in string[] argv, in string[] envp);
3939 }
3940 else version (Posix)
3941 {
3942     int execv(in string pathname, in string[] argv)
3943     {
3944         return execv_(pathname, argv);
3945     }
3946     int execve(in string pathname, in string[] argv, in string[] envp)
3947     {
3948         return execve_(pathname, argv, envp);
3949     }
3950     int execvp(in string pathname, in string[] argv)
3951     {
3952         return execvp_(pathname, argv);
3953     }
3954     int execvpe(in string pathname, in string[] argv, in string[] envp)
3955     {
3956         return execvpe_(pathname, argv, envp);
3957     }
3958 }
3959 
3960 // Move these C declarations to druntime if we decide to keep the D wrappers
3961 extern(C)
3962 {
3963     int execv(scope const(char) *, scope const(char *)*);
3964     int execve(scope const(char)*, scope const(char*)*, scope const(char*)*);
3965     int execvp(scope const(char)*, scope const(char*)*);
3966     version (Windows) int execvpe(scope const(char)*, scope const(char*)*, scope const(char*)*);
3967 }
3968 
3969 private int execv_(in string pathname, in string[] argv)
3970 {
3971     import core.exception : OutOfMemoryError;
3972     import std.exception : enforce;
3973     auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3974     enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
3975     scope(exit) core.stdc.stdlib.free(argv_);
3976 
3977     toAStringz(argv, argv_);
3978 
3979     return execv(pathname.tempCString(), argv_);
3980 }
3981 
3982 private int execve_(in string pathname, in string[] argv, in string[] envp)
3983 {
3984     import core.exception : OutOfMemoryError;
3985     import std.exception : enforce;
3986     auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3987     enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
3988     scope(exit) core.stdc.stdlib.free(argv_);
3989     auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
3990     enforce!OutOfMemoryError(envp_ !is null, "Out of memory in std.process.");
3991     scope(exit) core.stdc.stdlib.free(envp_);
3992 
3993     toAStringz(argv, argv_);
3994     toAStringz(envp, envp_);
3995 
3996     return execve(pathname.tempCString(), argv_, envp_);
3997 }
3998 
3999 private int execvp_(in string pathname, in string[] argv)
4000 {
4001     import core.exception : OutOfMemoryError;
4002     import std.exception : enforce;
4003     auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4004     enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4005     scope(exit) core.stdc.stdlib.free(argv_);
4006 
4007     toAStringz(argv, argv_);
4008 
4009     return execvp(pathname.tempCString(), argv_);
4010 }
4011 
4012 private int execvpe_(in string pathname, in string[] argv, in string[] envp)
4013 {
4014 version (Posix)
4015 {
4016     import std.array : split;
4017     import std.conv : to;
4018     // Is pathname rooted?
4019     if (pathname[0] == '/')
4020     {
4021         // Yes, so just call execve()
4022         return execve(pathname, argv, envp);
4023     }
4024     else
4025     {
4026         // No, so must traverse PATHs, looking for first match
4027         string[]    envPaths    =   split(
4028             to!string(core.stdc.stdlib.getenv("PATH")), ":");
4029         int         iRet        =   0;
4030 
4031         // Note: if any call to execve() succeeds, this process will cease
4032         // execution, so there's no need to check the execve() result through
4033         // the loop.
4034 
4035         foreach (string pathDir; envPaths)
4036         {
4037             string  composite   =  cast(string) (pathDir ~ "/" ~ pathname);
4038 
4039             iRet = execve(composite, argv, envp);
4040         }
4041         if (0 != iRet)
4042         {
4043             iRet = execve(pathname, argv, envp);
4044         }
4045 
4046         return iRet;
4047     }
4048 }
4049 else version (Windows)
4050 {
4051     import core.exception : OutOfMemoryError;
4052     import std.exception : enforce;
4053     auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4054     enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4055     scope(exit) core.stdc.stdlib.free(argv_);
4056     auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
4057     enforce!OutOfMemoryError(envp_ !is null, "Out of memory in std.process.");
4058     scope(exit) core.stdc.stdlib.free(envp_);
4059 
4060     toAStringz(argv, argv_);
4061     toAStringz(envp, envp_);
4062 
4063     return execvpe(pathname.tempCString(), argv_, envp_);
4064 }
4065 else
4066 {
4067     static assert(0);
4068 } // version
4069 }
4070 
4071 version (StdDdoc)
4072 {
4073     /****************************************
4074      * Start up the browser and set it to viewing the page at url.
4075      */
4076     void browse(scope const(char)[] url);
4077 }
4078 else
4079 version (Windows)
4080 {
4081     import core.sys.windows.shellapi, core.sys.windows.winuser;
4082 
4083     pragma(lib,"shell32.lib");
4084 
4085     void browse(scope const(char)[] url)
4086     {
4087         ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL);
4088     }
4089 }
4090 else version (OSX)
4091 {
4092     import core.stdc.stdio;
4093     import core.stdc..string;
4094     import core.sys.posix.unistd;
4095 
4096     void browse(scope const(char)[] url) nothrow @nogc
4097     {
4098         const(char)*[5] args;
4099 
4100         auto curl = url.tempCString();
4101         const(char)* browser = core.stdc.stdlib.getenv("BROWSER");
4102         if (browser)
4103         {   browser = strdup(browser);
4104             args[0] = browser;
4105             args[1] = curl;
4106             args[2] = null;
4107         }
4108         else
4109         {
4110             args[0] = "open".ptr;
4111             args[1] = curl;
4112             args[2] = null;
4113         }
4114 
4115         auto childpid = core.sys.posix.unistd.fork();
4116         if (childpid == 0)
4117         {
4118             core.sys.posix.unistd.execvp(args[0], cast(char**) args.ptr);
4119             perror(args[0]);                // failed to execute
4120             return;
4121         }
4122         if (browser)
4123             free(cast(void*) browser);
4124     }
4125 }
4126 else version (Posix)
4127 {
4128     import core.stdc.stdio;
4129     import core.stdc..string;
4130     import core.sys.posix.unistd;
4131 
4132     void browse(scope const(char)[] url) nothrow @nogc
4133     {
4134         const(char)*[3] args;
4135 
4136         const(char)* browser = core.stdc.stdlib.getenv("BROWSER");
4137         if (browser)
4138         {   browser = strdup(browser);
4139             args[0] = browser;
4140         }
4141         else
4142             //args[0] = "x-www-browser".ptr;  // doesn't work on some systems
4143             args[0] = "xdg-open".ptr;
4144 
4145         args[1] = url.tempCString();
4146         args[2] = null;
4147 
4148         auto childpid = core.sys.posix.unistd.fork();
4149         if (childpid == 0)
4150         {
4151             core.sys.posix.unistd.execvp(args[0], cast(char**) args.ptr);
4152             perror(args[0]);                // failed to execute
4153             return;
4154         }
4155         if (browser)
4156             free(cast(void*) browser);
4157     }
4158 }
4159 else
4160     static assert(0, "os not supported");
Suggestion Box / Bug Report