@@ -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
18701871static 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
19061921static 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
19171949static 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
19431976static 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