blob: adb73871d07d12d800bce5f9a6b735a0aef26296 [file] [log] [blame]
[email protected]44106182012-04-06 03:53:021// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]9bc8cff2010-04-03 01:05:392// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]76b90d312010-08-03 03:00:505#include "base/environment.h"
[email protected]9bc8cff2010-04-03 01:05:396
avi9b6f42932015-12-26 22:15:147#include <stddef.h>
8
[email protected]b345c482013-08-30 18:00:399#include <vector>
10
11#include "base/strings/string_piece.h"
12#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
avi9b6f42932015-12-26 22:15:1414#include "build/build_config.h"
[email protected]b345c482013-08-30 18:00:3915
[email protected]9bc8cff2010-04-03 01:05:3916#if defined(OS_POSIX)
17#include <stdlib.h>
18#elif defined(OS_WIN)
19#include <windows.h>
20#endif
21
[email protected]b345c482013-08-30 18:00:3922namespace base {
[email protected]9bc8cff2010-04-03 01:05:3923
24namespace {
25
brettw7622fbed2015-06-09 20:20:1426class EnvironmentImpl : public Environment {
[email protected]9bc8cff2010-04-03 01:05:3927 public:
dcheng56488182014-10-21 10:54:5128 bool GetVar(const char* variable_name, std::string* result) override {
[email protected]3ba7e082010-08-07 02:57:5929 if (GetVarImpl(variable_name, result))
[email protected]9bc8cff2010-04-03 01:05:3930 return true;
31
32 // Some commonly used variable names are uppercase while others
33 // are lowercase, which is inconsistent. Let's try to be helpful
34 // and look for a variable name with the reverse case.
35 // I.e. HTTP_PROXY may be http_proxy for some users/systems.
36 char first_char = variable_name[0];
37 std::string alternate_case_var;
38 if (first_char >= 'a' && first_char <= 'z')
brettwc15100c2015-08-06 22:54:1639 alternate_case_var = ToUpperASCII(variable_name);
[email protected]9bc8cff2010-04-03 01:05:3940 else if (first_char >= 'A' && first_char <= 'Z')
brettwc15100c2015-08-06 22:54:1641 alternate_case_var = ToLowerASCII(variable_name);
[email protected]9bc8cff2010-04-03 01:05:3942 else
43 return false;
[email protected]3ba7e082010-08-07 02:57:5944 return GetVarImpl(alternate_case_var.c_str(), result);
[email protected]9bc8cff2010-04-03 01:05:3945 }
[email protected]ac7264c2010-07-08 13:32:5146
dcheng56488182014-10-21 10:54:5147 bool SetVar(const char* variable_name,
48 const std::string& new_value) override {
[email protected]c87bcf002010-08-06 01:03:3749 return SetVarImpl(variable_name, new_value);
[email protected]ac7264c2010-07-08 13:32:5150 }
51
dcheng56488182014-10-21 10:54:5152 bool UnSetVar(const char* variable_name) override {
[email protected]4fae3162010-08-04 02:13:3453 return UnSetVarImpl(variable_name);
[email protected]fc586c72010-07-31 16:55:4054 }
55
[email protected]9bc8cff2010-04-03 01:05:3956 private:
[email protected]3ba7e082010-08-07 02:57:5957 bool GetVarImpl(const char* variable_name, std::string* result) {
[email protected]9bc8cff2010-04-03 01:05:3958#if defined(OS_POSIX)
59 const char* env_value = getenv(variable_name);
60 if (!env_value)
61 return false;
62 // Note that the variable may be defined but empty.
63 if (result)
64 *result = env_value;
65 return true;
66#elif defined(OS_WIN)
67 DWORD value_length = ::GetEnvironmentVariable(
68 UTF8ToWide(variable_name).c_str(), NULL, 0);
69 if (value_length == 0)
70 return false;
71 if (result) {
[email protected]604eb052013-01-18 14:21:5872 scoped_ptr<wchar_t[]> value(new wchar_t[value_length]);
[email protected]9bc8cff2010-04-03 01:05:3973 ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(),
74 value_length);
75 *result = WideToUTF8(value.get());
76 }
77 return true;
78#else
79#error need to port
80#endif
81 }
[email protected]ac7264c2010-07-08 13:32:5182
[email protected]c87bcf002010-08-06 01:03:3783 bool SetVarImpl(const char* variable_name, const std::string& new_value) {
[email protected]ac7264c2010-07-08 13:32:5184#if defined(OS_POSIX)
[email protected]e9032c62010-07-16 03:34:2585 // On success, zero is returned.
[email protected]c10688622010-08-17 23:33:4186 return !setenv(variable_name, new_value.c_str(), 1);
[email protected]ac7264c2010-07-08 13:32:5187#elif defined(OS_WIN)
[email protected]c10688622010-08-17 23:33:4188 // On success, a nonzero value is returned.
89 return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(),
90 UTF8ToWide(new_value).c_str());
[email protected]ac7264c2010-07-08 13:32:5191#endif
92 }
[email protected]fc586c72010-07-31 16:55:4093
[email protected]4fae3162010-08-04 02:13:3494 bool UnSetVarImpl(const char* variable_name) {
[email protected]fc586c72010-07-31 16:55:4095#if defined(OS_POSIX)
96 // On success, zero is returned.
[email protected]c10688622010-08-17 23:33:4197 return !unsetenv(variable_name);
[email protected]fc586c72010-07-31 16:55:4098#elif defined(OS_WIN)
[email protected]c10688622010-08-17 23:33:4199 // On success, a nonzero value is returned.
100 return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL);
[email protected]fc586c72010-07-31 16:55:40101#endif
102 }
[email protected]9bc8cff2010-04-03 01:05:39103};
104
[email protected]b345c482013-08-30 18:00:39105// Parses a null-terminated input string of an environment block. The key is
106// placed into the given string, and the total length of the line, including
107// the terminating null, is returned.
108size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
109 NativeEnvironmentString* key) {
110 // Skip to the equals or end of the string, this is the key.
111 size_t cur = 0;
112 while (input[cur] && input[cur] != '=')
113 cur++;
114 *key = NativeEnvironmentString(&input[0], cur);
[email protected]9bc8cff2010-04-03 01:05:39115
[email protected]b345c482013-08-30 18:00:39116 // Now just skip to the end of the string.
117 while (input[cur])
118 cur++;
119 return cur + 1;
120}
121
122} // namespace
[email protected]9bc8cff2010-04-03 01:05:39123
[email protected]574f6f0c2010-07-21 02:59:28124namespace env_vars {
125
126#if defined(OS_POSIX)
127// On Posix systems, this variable contains the location of the user's home
128// directory. (e.g, /home/username/).
129const char kHome[] = "HOME";
130#endif
131
132} // namespace env_vars
133
[email protected]76b90d312010-08-03 03:00:50134Environment::~Environment() {}
[email protected]3a3d47472010-07-15 21:03:54135
[email protected]9bc8cff2010-04-03 01:05:39136// static
[email protected]76b90d312010-08-03 03:00:50137Environment* Environment::Create() {
138 return new EnvironmentImpl();
[email protected]9bc8cff2010-04-03 01:05:39139}
140
[email protected]9432ade2010-08-04 23:43:20141bool Environment::HasVar(const char* variable_name) {
[email protected]3ba7e082010-08-07 02:57:59142 return GetVar(variable_name, NULL);
[email protected]fc586c72010-07-31 16:55:40143}
144
[email protected]b345c482013-08-30 18:00:39145#if defined(OS_WIN)
146
147string16 AlterEnvironment(const wchar_t* env,
148 const EnvironmentMap& changes) {
149 string16 result;
150
151 // First copy all unmodified values to the output.
152 size_t cur_env = 0;
153 string16 key;
154 while (env[cur_env]) {
155 const wchar_t* line = &env[cur_env];
156 size_t line_length = ParseEnvLine(line, &key);
157
158 // Keep only values not specified in the change vector.
159 EnvironmentMap::const_iterator found_change = changes.find(key);
160 if (found_change == changes.end())
161 result.append(line, line_length);
162
163 cur_env += line_length;
164 }
165
166 // Now append all modified and new values.
167 for (EnvironmentMap::const_iterator i = changes.begin();
168 i != changes.end(); ++i) {
169 if (!i->second.empty()) {
170 result.append(i->first);
171 result.push_back('=');
172 result.append(i->second);
173 result.push_back(0);
174 }
175 }
176
177 // An additional null marks the end of the list. We always need a double-null
178 // in case nothing was added above.
179 if (result.empty())
180 result.push_back(0);
181 result.push_back(0);
182 return result;
183}
184
185#elif defined(OS_POSIX)
186
187scoped_ptr<char*[]> AlterEnvironment(const char* const* const env,
188 const EnvironmentMap& changes) {
189 std::string value_storage; // Holds concatenated null-terminated strings.
190 std::vector<size_t> result_indices; // Line indices into value_storage.
191
192 // First build up all of the unchanged environment strings. These are
193 // null-terminated of the form "key=value".
194 std::string key;
195 for (size_t i = 0; env[i]; i++) {
196 size_t line_length = ParseEnvLine(env[i], &key);
197
198 // Keep only values not specified in the change vector.
199 EnvironmentMap::const_iterator found_change = changes.find(key);
200 if (found_change == changes.end()) {
201 result_indices.push_back(value_storage.size());
202 value_storage.append(env[i], line_length);
203 }
204 }
205
206 // Now append all modified and new values.
207 for (EnvironmentMap::const_iterator i = changes.begin();
208 i != changes.end(); ++i) {
209 if (!i->second.empty()) {
210 result_indices.push_back(value_storage.size());
211 value_storage.append(i->first);
212 value_storage.push_back('=');
213 value_storage.append(i->second);
214 value_storage.push_back(0);
215 }
216 }
217
218 size_t pointer_count_required =
219 result_indices.size() + 1 + // Null-terminated array of pointers.
220 (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer.
221 scoped_ptr<char*[]> result(new char*[pointer_count_required]);
222
223 // The string storage goes after the array of pointers.
224 char* storage_data = reinterpret_cast<char*>(
225 &result.get()[result_indices.size() + 1]);
226 if (!value_storage.empty())
227 memcpy(storage_data, value_storage.data(), value_storage.size());
228
229 // Fill array of pointers at the beginning of the result.
230 for (size_t i = 0; i < result_indices.size(); i++)
231 result[i] = &storage_data[result_indices[i]];
232 result[result_indices.size()] = 0; // Null terminator.
233
danakj0c8d4aa2015-11-25 05:29:58234 return result;
[email protected]b345c482013-08-30 18:00:39235}
236
237#endif // OS_POSIX
238
[email protected]9bc8cff2010-04-03 01:05:39239} // namespace base