Skip to content

Commit 077f9d7

Browse files
committed
Windows: use unicode environment
1 parent 0685707 commit 077f9d7

File tree

1 file changed

+94
-36
lines changed

1 file changed

+94
-36
lines changed

src/node.cc

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,8 @@ static Handle<Value> CwdForDrive(const Arguments& args) {
12961296
env_key[1] = (WCHAR) drive;
12971297

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

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

18701871
static Handle<Value> EnvGetter(Local<String> property,
18711872
const AccessorInfo& info) {
1873+
HandleScope scope;
1874+
#ifdef __POSIX__
18721875
String::Utf8Value key(property);
18731876
const char* val = getenv(*key);
18741877
if (val) {
1875-
HandleScope scope;
18761878
return scope.Close(String::New(val));
18771879
}
1880+
#else // _WIN32
1881+
String::Value key(property);
1882+
WCHAR buffer[32767]; // The maximum size allowed for environment variables.
1883+
DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key),
1884+
buffer,
1885+
ARRAY_SIZE(buffer));
1886+
// If result >= sizeof buffer the buffer was too small. That should never
1887+
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not
1888+
// not found.
1889+
if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
1890+
result < ARRAY_SIZE(buffer)) {
1891+
return scope.Close(String::New(reinterpret_cast<uint16_t*>(buffer), result));
1892+
}
1893+
#endif
1894+
// Not found
18781895
return Undefined();
18791896
}
18801897

@@ -1883,66 +1900,82 @@ static Handle<Value> EnvSetter(Local<String> property,
18831900
Local<Value> value,
18841901
const AccessorInfo& info) {
18851902
HandleScope scope;
1903+
#ifdef __POSIX__
18861904
String::Utf8Value key(property);
18871905
String::Utf8Value val(value);
1888-
1889-
#ifdef __POSIX__
18901906
setenv(*key, *val, 1);
1891-
#else // __WIN32__
1892-
int n = key.length() + val.length() + 2;
1893-
char* pair = new char[n];
1894-
snprintf(pair, n, "%s=%s", *key, *val);
1895-
int r = _putenv(pair);
1896-
if (r) {
1897-
fprintf(stderr, "error putenv: '%s'\n", pair);
1907+
#else // _WIN32
1908+
String::Value key(property);
1909+
String::Value val(value);
1910+
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
1911+
// Environment variables that start with '=' are read-only.
1912+
if (key_ptr[0] != L'=') {
1913+
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
18981914
}
1899-
delete [] pair;
19001915
#endif
1901-
1902-
return value;
1916+
// Whether it worked or not, always return rval.
1917+
return scope.Close(value);
19031918
}
19041919

19051920

19061921
static Handle<Integer> EnvQuery(Local<String> property,
19071922
const AccessorInfo& info) {
1923+
HandleScope scope;
1924+
#ifdef __POSIX__
19081925
String::Utf8Value key(property);
19091926
if (getenv(*key)) {
1910-
HandleScope scope;
19111927
return scope.Close(Integer::New(None));
19121928
}
1913-
return Handle<Integer>();
1929+
#else // _WIN32
1930+
String::Value key(property);
1931+
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
1932+
if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 ||
1933+
GetLastError() == ERROR_SUCCESS) {
1934+
if (key_ptr[0] == L'=') {
1935+
// Environment variables that start with '=' are hidden and read-only.
1936+
return scope.Close(Integer::New(v8::ReadOnly ||
1937+
v8::DontDelete ||
1938+
v8::DontEnum));
1939+
} else {
1940+
return scope.Close(Integer::New(None));
1941+
}
1942+
}
1943+
#endif
1944+
// Not found
1945+
return scope.Close(Handle<Integer>());
19141946
}
19151947

19161948

19171949
static Handle<Boolean> EnvDeleter(Local<String> property,
19181950
const AccessorInfo& info) {
19191951
HandleScope scope;
1920-
1921-
String::Utf8Value key(property);
1922-
1923-
if (getenv(*key)) {
19241952
#ifdef __POSIX__
1925-
unsetenv(*key); // prototyped as `void unsetenv(const char*)` on some platforms
1953+
String::Utf8Value key(property);
1954+
// prototyped as `void unsetenv(const char*)` on some platforms
1955+
if (unsetenv(*key) < 0) {
1956+
// Deletion failed. Return true if the key wasn't there in the first place,
1957+
// false if it is still there.
1958+
return scope.Close(Boolean::New(getenv(*key) == NULL));
1959+
};
19261960
#else
1927-
int n = key.length() + 2;
1928-
char* pair = new char[n];
1929-
snprintf(pair, n, "%s=", *key);
1930-
int r = _putenv(pair);
1931-
if (r) {
1932-
fprintf(stderr, "error unsetenv: '%s'\n", pair);
1933-
}
1934-
delete [] pair;
1935-
#endif
1936-
return True();
1961+
String::Value key(property);
1962+
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
1963+
if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) {
1964+
// Deletion failed. Return true if the key wasn't there in the first place,
1965+
// false if it is still there.
1966+
bool rv = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 &&
1967+
GetLastError() != ERROR_SUCCESS;
1968+
return scope.Close(Boolean::New(rv));
19371969
}
1938-
1939-
return False();
1970+
#endif
1971+
// It worked
1972+
return v8::True();
19401973
}
19411974

19421975

19431976
static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
19441977
HandleScope scope;
1945-
1978+
#ifdef __POSIX__
19461979
int size = 0;
19471980
while (environ[size]) size++;
19481981

@@ -1954,7 +1987,32 @@ static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
19541987
const int length = s ? s - var : strlen(var);
19551988
env->Set(i, String::New(var, length));
19561989
}
1957-
1990+
#else // _WIN32
1991+
WCHAR* environment = GetEnvironmentStringsW();
1992+
if (environment == NULL) {
1993+
// This should not happen.
1994+
return scope.Close(Handle<Array>());
1995+
}
1996+
Local<Array> env = Array::New();
1997+
WCHAR* p = environment;
1998+
int i = 0;
1999+
while (*p != NULL) {
2000+
WCHAR *s;
2001+
if (*p == L'=') {
2002+
// If the key starts with '=' it is a hidden environment variable.
2003+
p += wcslen(p) + 1;
2004+
continue;
2005+
} else {
2006+
s = wcschr(p, L'=');
2007+
}
2008+
if (!s) {
2009+
s = p + wcslen(p);
2010+
}
2011+
env->Set(i++, String::New(reinterpret_cast<uint16_t*>(p), s - p));
2012+
p = s + wcslen(s) + 1;
2013+
}
2014+
FreeEnvironmentStringsW(environment);
2015+
#endif
19582016
return scope.Close(env);
19592017
}
19602018

0 commit comments

Comments
 (0)