Mercurial > projects > ldc
diff lphobos/std/process.d @ 473:373489eeaf90
Applied downs' lphobos update
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 04 Aug 2008 19:28:49 +0200 |
parents | |
children | 88e23f8c2354 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lphobos/std/process.d Mon Aug 04 19:28:49 2008 +0200 @@ -0,0 +1,293 @@ + +/* + * Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com + * Written by Matthew Wilson and Walter Bright + * + * Incorporating idea (for execvpe() on Linux) from Russ Lewis + * + * Updated: 21st August 2004 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ +/* NOTE: This file has been patched from the original DMD distribution to + work with the GDC compiler. + + Modified by David Friedman, October 2004 +*/ + +/** + * Macros: + * WIKI=Phobos/StdProcess + */ + + +module std.process; + +private import std.c.stdlib; +private import std.c.string; +private import std.string; +private import std.c.process; + +/** + * Execute command in a _command shell. + * + * Returns: exit status of command + */ + +int system(char[] command) +{ + return std.c.process.system(toStringz(command)); +} + +private void toAStringz(char[][] a, char**az) +{ + foreach(char[] s; a) + { + *az++ = toStringz(s); + } + *az = null; +} + + +/* ========================================================== */ + +//version (Windows) +//{ +// int spawnvp(int mode, char[] pathname, char[][] argv) +// { +// char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length)); +// +// toAStringz(argv, argv_); +// +// return std.c.process.spawnvp(mode, toStringz(pathname), argv_); +// } +//} + +// Incorporating idea (for spawnvp() on linux) from Dave Fladebo + +alias std.c.process._P_WAIT P_WAIT; +alias std.c.process._P_NOWAIT P_NOWAIT; + +int spawnvp(int mode, char[] pathname, char[][] argv) +{ + char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length)); + + toAStringz(argv, argv_); + + version(Unix) + { + return _spawnvp(mode, toStringz(pathname), argv_); + } + else + { + return std.c.process.spawnvp(mode, toStringz(pathname), argv_); + } +} + +version(Unix) +{ +version(linux) import std.c.linux.linux; +else import std.c.unix.unix; +int _spawnvp(int mode, char *pathname, char **argv) +{ + int retval = 0; + pid_t pid = fork(); + + if(!pid) + { // child + std.c.process.execvp(pathname, argv); + goto Lerror; + } + else if(pid > 0) + { // parent + if(mode == _P_NOWAIT) + { + retval = pid; // caller waits + } + else + { + while(1) + { + int status; + pid_t wpid = waitpid(pid, &status, 0); + if(exited(status)) + { + retval = exitstatus(status); + break; + } + else if(signaled(status)) + { + retval = -termsig(status); + break; + } + else if(stopped(status)) // ptrace support + continue; + else + goto Lerror; + } + } + + return retval; + } + +Lerror: + retval = getErrno; + throw new Exception( + "Cannot spawn " ~ toString(pathname) ~ "; " + ~ toString(strerror(retval)) + ~ " [errno " ~ toString(retval) ~ "]"); +} // _spawnvp +private +{ +bool stopped(int status) { return cast(bool)((status & 0xff) == 0x7f); } +bool signaled(int status) { return cast(bool)((cast(char)((status & 0x7f) + 1) >> 1) > 0); } +int termsig(int status) { return status & 0x7f; } +bool exited(int status) { return cast(bool)((status & 0x7f) == 0); } +int exitstatus(int status) { return (status & 0xff00) >> 8; } +} // private +} // version(linux) + +/* ========================================================== */ + +/** + * Execute program specified by pathname, passing it the arguments (argv) + * and the environment (envp), returning the exit status. + * The 'p' versions of exec search the PATH environment variable + * setting for the program. + */ + +int execv(char[] pathname, char[][] argv) +{ + char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length)); + + toAStringz(argv, argv_); + + return std.c.process.execv(toStringz(pathname), argv_); +} + +/** ditto */ +int execve(char[] pathname, char[][] argv, char[][] envp) +{ + char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length)); + char** envp_ = cast(char**)alloca((char*).sizeof * (1 + envp.length)); + + toAStringz(argv, argv_); + toAStringz(envp, envp_); + + return std.c.process.execve(toStringz(pathname), argv_, envp_); +} + +/** ditto */ +int execvp(char[] pathname, char[][] argv) +{ + char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length)); + + toAStringz(argv, argv_); + + return std.c.process.execvp(toStringz(pathname), argv_); +} + +/** ditto */ +int execvpe(char[] pathname, char[][] argv, char[][] envp) +{ +version (GNU_Need_execvpe) +{ + // Is pathname rooted? + if(pathname[0] == '/') + { + // Yes, so just call execve() + return execve(pathname, argv, envp); + } + else + { + // No, so must traverse PATHs, looking for first match + char[][] envPaths = std.string.split(std.string.toString(std.c.stdlib.getenv("PATH")), ":"); + int iRet = 0; + + // Note: if any call to execve() succeeds, this process will cease + // execution, so there's no need to check the execve() result through + // the loop. + + foreach(char[] pathDir; envPaths) + { + char[] composite = pathDir ~ "/" ~ pathname; + + iRet = execve(composite, argv, envp); + } + if(0 != iRet) + { + iRet = execve(pathname, argv, envp); + } + + return iRet; + } +} +else version(Windows) +{ + char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length)); + char** envp_ = cast(char**)alloca((char*).sizeof * (1 + envp.length)); + + toAStringz(argv, argv_); + toAStringz(envp, envp_); + + return std.c.process.execvpe(toStringz(pathname), argv_, envp_); +} +else +{ + throw new Exception("Not supported on this platform."); +} // version +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +version(MainTest) +{ + int main(char[][] args) + { + if(args.length < 2) + { + printf("Must supply executable (and optional arguments)\n"); + + return 1; + } + else + { + char[][] dummy_env; + + dummy_env ~= "VAL0=value"; + dummy_env ~= "VAL1=value"; + +/+ + foreach(char[] arg; args) + { + printf("%.*s\n", arg); + } ++/ + +// int i = execv(args[1], args[1 .. args.length]); +// int i = execvp(args[1], args[1 .. args.length]); + int i = execvpe(args[1], args[1 .. args.length], dummy_env); + + printf("exec??() has returned! Error code: %d; errno: %d\n", i, /* std.c.stdlib.getErrno() */-1); + + return 0; + } + } +} + +/* ////////////////////////////////////////////////////////////////////////// */