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;
}
}
}
|