Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Windows: use unicode environment

  • Loading branch information...
piscisaureus committed Feb 15, 2012
1 parent 0685707 commit 077f9d7293468ad5446b330999fe47bc40e47571
Showing with 94 additions and 36 deletions.
  1. +94 −36 src/node.cc
@@ -1296,7 +1296,8 @@ static Handle<Value> CwdForDrive(const Arguments& args) {
env_key[1] = (WCHAR) drive;

DWORD len = GetEnvironmentVariableW(env_key, NULL, 0);
if (len == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
if (len == 0 && (GetLastError() == ERROR_ENVVAR_NOT_FOUND ||
GetLastError() == ERROR_SUCCESS)) {
// There is no current directory for that drive. Default to drive + ":\".
Local<String> cwd = String::Concat(String::New(&drive, 1),
String::New(":\\"));
@@ -1317,7 +1318,7 @@ static Handle<Value> CwdForDrive(const Arguments& args) {
}

DWORD len2 = GetEnvironmentVariableW(env_key, buffer, len);
if (len2 == 0 || len2 >= len) {
if ((len2 == 0 && GetLastError() != ERROR_SUCCESS) || len2 >= len) {
// Error
delete[] buffer;
Local<Value> exception = Exception::Error(
@@ -1869,12 +1870,28 @@ static void ProcessTitleSetter(Local<String> property,

static Handle<Value> EnvGetter(Local<String> property,
const AccessorInfo& info) {
HandleScope scope;
#ifdef __POSIX__
String::Utf8Value key(property);
const char* val = getenv(*key);
if (val) {
HandleScope scope;
return scope.Close(String::New(val));
}
#else // _WIN32
String::Value key(property);
WCHAR buffer[32767]; // The maximum size allowed for environment variables.
DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key),
buffer,
ARRAY_SIZE(buffer));
// If result >= sizeof buffer the buffer was too small. That should never
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not
// not found.
if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
result < ARRAY_SIZE(buffer)) {
return scope.Close(String::New(reinterpret_cast<uint16_t*>(buffer), result));
}
#endif
// Not found
return Undefined();
}

@@ -1883,66 +1900,82 @@ static Handle<Value> EnvSetter(Local<String> property,
Local<Value> value,
const AccessorInfo& info) {
HandleScope scope;
#ifdef __POSIX__
String::Utf8Value key(property);
String::Utf8Value val(value);

#ifdef __POSIX__
setenv(*key, *val, 1);
#else // __WIN32__
int n = key.length() + val.length() + 2;
char* pair = new char[n];
snprintf(pair, n, "%s=%s", *key, *val);
int r = _putenv(pair);
if (r) {
fprintf(stderr, "error putenv: '%s'\n", pair);
#else // _WIN32
String::Value key(property);
String::Value val(value);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
// Environment variables that start with '=' are read-only.
if (key_ptr[0] != L'=') {
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
}
delete [] pair;
#endif

return value;
// Whether it worked or not, always return rval.
return scope.Close(value);
}


static Handle<Integer> EnvQuery(Local<String> property,
const AccessorInfo& info) {
HandleScope scope;
#ifdef __POSIX__
String::Utf8Value key(property);
if (getenv(*key)) {
HandleScope scope;
return scope.Close(Integer::New(None));
}
return Handle<Integer>();
#else // _WIN32
String::Value key(property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 ||
GetLastError() == ERROR_SUCCESS) {
if (key_ptr[0] == L'=') {
// Environment variables that start with '=' are hidden and read-only.

This comment has been minimized.

Copy link
@bnoordhuis

bnoordhuis Jun 24, 2012

Member

Why is that?

This comment has been minimized.

Copy link
@piscisaureus

piscisaureus Jan 7, 2013

Author Member

Because windows also hides them from the user. Hidden env vars are used to store the current directory on non-current drives (e.g. as =D:=D:\libuv). I also don't want people to fiddle with them because weird stuff may happen. But they need to be readable because path.resolve relies on it.

return scope.Close(Integer::New(v8::ReadOnly ||
v8::DontDelete ||
v8::DontEnum));

This comment has been minimized.

Copy link
@bnoordhuis

bnoordhuis Jan 6, 2013

Member

Looks like | was meant to be used here instead of ||? /cc @piscisaureus

This comment has been minimized.

Copy link
@piscisaureus

piscisaureus Jan 7, 2013

Author Member

Yep, you're right.

} else {
return scope.Close(Integer::New(None));
}
}
#endif
// Not found
return scope.Close(Handle<Integer>());
}


static Handle<Boolean> EnvDeleter(Local<String> property,
const AccessorInfo& info) {
HandleScope scope;

String::Utf8Value key(property);

if (getenv(*key)) {
#ifdef __POSIX__
unsetenv(*key); // prototyped as `void unsetenv(const char*)` on some platforms
String::Utf8Value key(property);
// prototyped as `void unsetenv(const char*)` on some platforms
if (unsetenv(*key) < 0) {
// Deletion failed. Return true if the key wasn't there in the first place,
// false if it is still there.
return scope.Close(Boolean::New(getenv(*key) == NULL));
};
#else
int n = key.length() + 2;
char* pair = new char[n];
snprintf(pair, n, "%s=", *key);
int r = _putenv(pair);
if (r) {
fprintf(stderr, "error unsetenv: '%s'\n", pair);
}
delete [] pair;
#endif
return True();
String::Value key(property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) {
// Deletion failed. Return true if the key wasn't there in the first place,
// false if it is still there.
bool rv = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 &&
GetLastError() != ERROR_SUCCESS;
return scope.Close(Boolean::New(rv));
}

return False();
#endif
// It worked
return v8::True();
}


static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
HandleScope scope;

#ifdef __POSIX__
int size = 0;
while (environ[size]) size++;

@@ -1954,7 +1987,32 @@ static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
const int length = s ? s - var : strlen(var);
env->Set(i, String::New(var, length));
}

#else // _WIN32
WCHAR* environment = GetEnvironmentStringsW();
if (environment == NULL) {
// This should not happen.
return scope.Close(Handle<Array>());
}
Local<Array> env = Array::New();
WCHAR* p = environment;
int i = 0;
while (*p != NULL) {
WCHAR *s;
if (*p == L'=') {
// If the key starts with '=' it is a hidden environment variable.
p += wcslen(p) + 1;
continue;
} else {
s = wcschr(p, L'=');
}
if (!s) {
s = p + wcslen(p);
}
env->Set(i++, String::New(reinterpret_cast<uint16_t*>(p), s - p));
p = s + wcslen(s) + 1;
}
FreeEnvironmentStringsW(environment);
#endif
return scope.Close(env);
}

0 comments on commit 077f9d7

Please sign in to comment.
You can’t perform that action at this time.