1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/environment.h"
9 #include "base/strings/string_piece.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
23 class EnvironmentImpl
: public base::Environment
{
25 virtual bool GetVar(const char* variable_name
,
26 std::string
* result
) OVERRIDE
{
27 if (GetVarImpl(variable_name
, result
))
30 // Some commonly used variable names are uppercase while others
31 // are lowercase, which is inconsistent. Let's try to be helpful
32 // and look for a variable name with the reverse case.
33 // I.e. HTTP_PROXY may be http_proxy for some users/systems.
34 char first_char
= variable_name
[0];
35 std::string alternate_case_var
;
36 if (first_char
>= 'a' && first_char
<= 'z')
37 alternate_case_var
= StringToUpperASCII(std::string(variable_name
));
38 else if (first_char
>= 'A' && first_char
<= 'Z')
39 alternate_case_var
= StringToLowerASCII(std::string(variable_name
));
42 return GetVarImpl(alternate_case_var
.c_str(), result
);
45 virtual bool SetVar(const char* variable_name
,
46 const std::string
& new_value
) OVERRIDE
{
47 return SetVarImpl(variable_name
, new_value
);
50 virtual bool UnSetVar(const char* variable_name
) OVERRIDE
{
51 return UnSetVarImpl(variable_name
);
55 bool GetVarImpl(const char* variable_name
, std::string
* result
) {
57 const char* env_value
= getenv(variable_name
);
60 // Note that the variable may be defined but empty.
65 DWORD value_length
= ::GetEnvironmentVariable(
66 UTF8ToWide(variable_name
).c_str(), NULL
, 0);
67 if (value_length
== 0)
70 scoped_ptr
<wchar_t[]> value(new wchar_t[value_length
]);
71 ::GetEnvironmentVariable(UTF8ToWide(variable_name
).c_str(), value
.get(),
73 *result
= WideToUTF8(value
.get());
81 bool SetVarImpl(const char* variable_name
, const std::string
& new_value
) {
83 // On success, zero is returned.
84 return !setenv(variable_name
, new_value
.c_str(), 1);
86 // On success, a nonzero value is returned.
87 return !!SetEnvironmentVariable(UTF8ToWide(variable_name
).c_str(),
88 UTF8ToWide(new_value
).c_str());
92 bool UnSetVarImpl(const char* variable_name
) {
94 // On success, zero is returned.
95 return !unsetenv(variable_name
);
97 // On success, a nonzero value is returned.
98 return !!SetEnvironmentVariable(UTF8ToWide(variable_name
).c_str(), NULL
);
103 // Parses a null-terminated input string of an environment block. The key is
104 // placed into the given string, and the total length of the line, including
105 // the terminating null, is returned.
106 size_t ParseEnvLine(const NativeEnvironmentString::value_type
* input
,
107 NativeEnvironmentString
* key
) {
108 // Skip to the equals or end of the string, this is the key.
110 while (input
[cur
] && input
[cur
] != '=')
112 *key
= NativeEnvironmentString(&input
[0], cur
);
114 // Now just skip to the end of the string.
124 #if defined(OS_POSIX)
125 // On Posix systems, this variable contains the location of the user's home
126 // directory. (e.g, /home/username/).
127 const char kHome
[] = "HOME";
130 } // namespace env_vars
132 Environment::~Environment() {}
135 Environment
* Environment::Create() {
136 return new EnvironmentImpl();
139 bool Environment::HasVar(const char* variable_name
) {
140 return GetVar(variable_name
, NULL
);
145 string16
AlterEnvironment(const wchar_t* env
,
146 const EnvironmentMap
& changes
) {
149 // First copy all unmodified values to the output.
152 while (env
[cur_env
]) {
153 const wchar_t* line
= &env
[cur_env
];
154 size_t line_length
= ParseEnvLine(line
, &key
);
156 // Keep only values not specified in the change vector.
157 EnvironmentMap::const_iterator found_change
= changes
.find(key
);
158 if (found_change
== changes
.end())
159 result
.append(line
, line_length
);
161 cur_env
+= line_length
;
164 // Now append all modified and new values.
165 for (EnvironmentMap::const_iterator i
= changes
.begin();
166 i
!= changes
.end(); ++i
) {
167 if (!i
->second
.empty()) {
168 result
.append(i
->first
);
169 result
.push_back('=');
170 result
.append(i
->second
);
175 // An additional null marks the end of the list. We always need a double-null
176 // in case nothing was added above.
183 #elif defined(OS_POSIX)
185 scoped_ptr
<char*[]> AlterEnvironment(const char* const* const env
,
186 const EnvironmentMap
& changes
) {
187 std::string value_storage
; // Holds concatenated null-terminated strings.
188 std::vector
<size_t> result_indices
; // Line indices into value_storage.
190 // First build up all of the unchanged environment strings. These are
191 // null-terminated of the form "key=value".
193 for (size_t i
= 0; env
[i
]; i
++) {
194 size_t line_length
= ParseEnvLine(env
[i
], &key
);
196 // Keep only values not specified in the change vector.
197 EnvironmentMap::const_iterator found_change
= changes
.find(key
);
198 if (found_change
== changes
.end()) {
199 result_indices
.push_back(value_storage
.size());
200 value_storage
.append(env
[i
], line_length
);
204 // Now append all modified and new values.
205 for (EnvironmentMap::const_iterator i
= changes
.begin();
206 i
!= changes
.end(); ++i
) {
207 if (!i
->second
.empty()) {
208 result_indices
.push_back(value_storage
.size());
209 value_storage
.append(i
->first
);
210 value_storage
.push_back('=');
211 value_storage
.append(i
->second
);
212 value_storage
.push_back(0);
216 size_t pointer_count_required
=
217 result_indices
.size() + 1 + // Null-terminated array of pointers.
218 (value_storage
.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer.
219 scoped_ptr
<char*[]> result(new char*[pointer_count_required
]);
221 // The string storage goes after the array of pointers.
222 char* storage_data
= reinterpret_cast<char*>(
223 &result
.get()[result_indices
.size() + 1]);
224 if (!value_storage
.empty())
225 memcpy(storage_data
, value_storage
.data(), value_storage
.size());
227 // Fill array of pointers at the beginning of the result.
228 for (size_t i
= 0; i
< result_indices
.size(); i
++)
229 result
[i
] = &storage_data
[result_indices
[i
]];
230 result
[result_indices
.size()] = 0; // Null terminator.
232 return result
.Pass();