| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 | /******************************************************************************* copyright: Copyright (c) 2007 Tango. All rights reserved license: BSD style: $(LICENSE) version: Feb 2007: Initial release author: Deewiant, Maxter, Gregor, Kris *******************************************************************************/ module tango.sys.Environment; private import tango.sys.Common; private import tango.io.Path, tango.io.FilePath; private import tango.core.Exception; private import tango.io.model.IFile; private import Text = tango.text.Util; private import tango.core.Octal; /******************************************************************************* Platform decls *******************************************************************************/ version (Windows) { private import tango.text.convert.Utf; pragma (lib, "kernel32.lib"); extern (Windows) { private void* GetEnvironmentStringsW(); private bool FreeEnvironmentStringsW(wchar**); } extern (Windows) { private int SetEnvironmentVariableW(const(wchar)*, const(wchar)*); private uint GetEnvironmentVariableW(const(wchar)*, wchar*, uint); private const int ERROR_ENVVAR_NOT_FOUND = 203; } } else { version (darwin) { extern (C) char*** _NSGetEnviron(); private __gshared char** environ; shared static this () { environ = *_NSGetEnviron(); } } else private extern (C) extern __gshared char** environ; import tango.stdc.posix.stdlib; import tango.stdc.string; } /******************************************************************************* Exposes the system Environment settings, along with some handy utilities *******************************************************************************/ struct Environment { public alias cwd directory; /*********************************************************************** Throw an exception ***********************************************************************/ private static void exception (immutable(char)[] msg) { throw new PlatformException (msg); } /*********************************************************************** Returns an absolute version of the provided path, where cwd is used as the prefix. The provided path is returned as is if already absolute. ***********************************************************************/ static char[] toAbsolute(char[] path) { scope fp = new FilePath(path); if (fp.isAbsolute) return path; fp.absolute(cwd()); return fp.cString()[0..$-1]; } /*********************************************************************** Returns the full path location of the provided executable file, rifling through the PATH as necessary. Returns null if the provided filename was not found ***********************************************************************/ static FilePath exePath (char[] file) { auto bin = new FilePath (file); // on Windows, this is a .exe version (Windows) if (bin.ext.length is 0) bin.suffix = "exe"; // is this a directory? Potentially make it absolute if (bin.isChild && !bin.isAbsolute) return bin.absolute (cwd()); // is it in cwd? version (Windows) if (bin.path(cwd()).exists) return bin; // rifle through the path (after converting to standard format) foreach (pe; Text.patterns (standard(get("PATH")), tango.io.model.IFile.FileConst.SystemPathString)) if (bin.path(pe).exists) { version (Windows) return bin; else { stat_t stats; stat(bin.cString().ptr, &stats); if (stats.st_mode & octal!(100)) return bin; } } return null; } /*********************************************************************** Windows implementation ***********************************************************************/ version (Windows) { /************************************************************** Returns the provided 'def' value if the variable does not exist **************************************************************/ static char[] get (const(char)[] variable, char[] def = null) { const(wchar)[] var = toString16(variable) ~ "\0"; uint size = GetEnvironmentVariableW(var.ptr, cast(wchar*)null, 0); if (size is 0) { if (SysError.lastCode is ERROR_ENVVAR_NOT_FOUND) return def; else exception (SysError.lastMsg.idup); } auto buffer = new wchar[size]; size = GetEnvironmentVariableW(var.ptr, buffer.ptr, size); if (size is 0) exception (SysError.lastMsg.idup); return toString (buffer[0 .. size]); } /************************************************************** clears the variable if value is null or empty **************************************************************/ static void set (const(char)[] variable, const(char)[] value = null) { const(wchar) * var, val; var = (toString16 (variable) ~ "\0").ptr; if (value.length > 0) val = (toString16 (value) ~ "\0").ptr; if (! SetEnvironmentVariableW(var, val)) exception (SysError.lastMsg.idup); } /************************************************************** Get all set environment variables as an associative array. **************************************************************/ static char[][char[]] get () { char[][char[]] arr; wchar[] key = new wchar[20], value = new wchar[40]; wchar** env = cast(wchar**) GetEnvironmentStringsW(); scope (exit) FreeEnvironmentStringsW (env); for (wchar* str = cast(wchar*) env; *str; ++str) { size_t k = 0, v = 0; while (*str != '=') { key[k++] = *str++; if (k is key.length) key.length = 2 * key.length; } ++str; while (*str) { value [v++] = *str++; if (v is value.length) value.length = 2 * value.length; } arr [toString(key[0 .. k]).idup] = toString(value[0 .. v]); } return arr; } /************************************************************** Set the current working directory **************************************************************/ static void cwd (const(char)[] path) { version (Win32SansUnicode) { char[MAX_PATH+1] tmp = void; tmp[0..path.length] = path; tmp[path.length] = 0; if (! SetCurrentDirectoryA (tmp.ptr)) exception ("Failed to set current directory"); } else { // convert into output buffer wchar[MAX_PATH+1] tmp = void; assert (path.length < tmp.length); auto i = MultiByteToWideChar (CP_UTF8, 0, cast(PCHAR)path.ptr, path.length, tmp.ptr, tmp.length); tmp[i] = 0; if (! SetCurrentDirectoryW (tmp.ptr)) exception ("Failed to set current directory"); } } /************************************************************** Get the current working directory **************************************************************/ static char[] cwd () { char[] path; version (Win32SansUnicode) { int len = GetCurrentDirectoryA (0, null); auto dir = new char [len]; GetCurrentDirectoryA (len, dir.ptr); if (len) { if (dir[len-2] is '/') dir.length = len-1; else dir[len-1] = '/'; path = standard (dir); } else exception ("Failed to get current directory"); } else { wchar[MAX_PATH+2] tmp = void; auto len = GetCurrentDirectoryW (0, null); assert (len < tmp.length); auto dir = new char [len * 3]; GetCurrentDirectoryW (len, tmp.ptr); auto i = WideCharToMultiByte (CP_UTF8, 0, tmp.ptr, len, cast(PCHAR)dir.ptr, dir.length, null, null); if (len && i) { path = standard (dir[0..i]); if (path[$-2] is '/') path.length = path.length-1; else path[$-1] = '/'; } else exception ("Failed to get current directory"); } return path; } } /*********************************************************************** Posix implementation ***********************************************************************/ version (Posix) { /************************************************************** Returns the provided 'def' value if the variable does not exist **************************************************************/ static char[] get (const(char)[] variable, char[] def = null) { char* ptr = getenv ((variable ~ '\0').ptr); if (ptr is null) return def; return ptr[0 .. strlen(ptr)].dup; } /************************************************************** clears the variable, if value is null or empty **************************************************************/ static void set (const(char)[] variable, const(char)[] value = null) { int result; if (value.length is 0) unsetenv ((variable ~ '\0').ptr); else result = setenv ((variable ~ '\0').ptr, (value ~ '\0').ptr, 1); if (result != 0) exception (SysError.lastMsg.idup); } /************************************************************** Get all set environment variables as an associative array. **************************************************************/ static char[][char[]] get () { char[][char[]] arr; for (char** p = environ; *p; ++p) { size_t k = 0; char* str = *p; while (*str++ != '=') ++k; char[] key = (*p)[0..k]; k = 0; char* val = str; while (*str++) ++k; arr[key.idup] = val[0 .. k]; } return arr; } /************************************************************** Set the current working directory **************************************************************/ static void cwd (const(char)[] path) { char[512] tmp = void; tmp [path.length] = 0; tmp[0..path.length] = path; if (tango.stdc.posix.unistd.chdir (tmp.ptr)) exception ("Failed to set current directory"); } /************************************************************** Get the current working directory **************************************************************/ static char[] cwd () { char[512] tmp = void; char *s = tango.stdc.posix.unistd.getcwd (tmp.ptr, tmp.length); if (s is null) exception ("Failed to get current directory"); auto path = s[0 .. strlen(s)+1].dup; if (path[$-2] is '/') // root path has the slash path.length = path.length-1; else path[$-1] = '/'; return path; } } } /******************************************************************************* *******************************************************************************/ debug (Environment) { import tango.io.Console; void main(const(char)[][] args) { enum immutable(char)[] VAR = "TESTENVVAR"; enum immutable(char)[] VAL1 = "VAL1"; enum immutable(char)[] VAL2 = "VAL2"; assert(Environment.get(VAR) is null); Environment.set(VAR, VAL1); assert(Environment.get(VAR) == VAL1); Environment.set(VAR, VAL2); assert(Environment.get(VAR) == VAL2); Environment.set(VAR, null); assert(Environment.get(VAR) is null); Environment.set(VAR, VAL1); Environment.set(VAR, ""); assert(Environment.get(VAR) is null); foreach (key, value; Environment.get) Cout (key) ("=") (value).newline; if (args.length > 0) { auto p = Environment.exePath (args[0]); Cout (p).newline; } if (args.length > 1) { if (auto p = Environment.exePath (args[1])) Cout (p).newline; } } } |