| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "base/environment.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/strings/string_piece.h" | |
| 10 #include "base/strings/string_util.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 | |
| 13 #if defined(OS_POSIX) | |
| 14 #include <stdlib.h> | |
| 15 #elif defined(OS_WIN) | |
| 16 #include <windows.h> | |
| 17 #endif | |
| 18 | |
| 19 namespace base { | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 class EnvironmentImpl : public Environment { | |
| 24 public: | |
| 25 bool GetVar(const char* variable_name, std::string* result) override { | |
| 26 if (GetVarImpl(variable_name, result)) | |
| 27 return true; | |
| 28 | |
| 29 // Some commonly used variable names are uppercase while others | |
| 30 // are lowercase, which is inconsistent. Let's try to be helpful | |
| 31 // and look for a variable name with the reverse case. | |
| 32 // I.e. HTTP_PROXY may be http_proxy for some users/systems. | |
| 33 char first_char = variable_name[0]; | |
| 34 std::string alternate_case_var; | |
| 35 if (first_char >= 'a' && first_char <= 'z') | |
| 36 alternate_case_var = StringToUpperASCII(std::string(variable_name)); | |
| 37 else if (first_char >= 'A' && first_char <= 'Z') | |
| 38 alternate_case_var = StringToLowerASCII(std::string(variable_name)); | |
| 39 else | |
| 40 return false; | |
| 41 return GetVarImpl(alternate_case_var.c_str(), result); | |
| 42 } | |
| 43 | |
| 44 bool SetVar(const char* variable_name, | |
| 45 const std::string& new_value) override { | |
| 46 return SetVarImpl(variable_name, new_value); | |
| 47 } | |
| 48 | |
| 49 bool UnSetVar(const char* variable_name) override { | |
| 50 return UnSetVarImpl(variable_name); | |
| 51 } | |
| 52 | |
| 53 private: | |
| 54 bool GetVarImpl(const char* variable_name, std::string* result) { | |
| 55 #if defined(OS_POSIX) | |
| 56 const char* env_value = getenv(variable_name); | |
| 57 if (!env_value) | |
| 58 return false; | |
| 59 // Note that the variable may be defined but empty. | |
| 60 if (result) | |
| 61 *result = env_value; | |
| 62 return true; | |
| 63 #elif defined(OS_WIN) | |
| 64 DWORD value_length = ::GetEnvironmentVariable( | |
| 65 UTF8ToWide(variable_name).c_str(), NULL, 0); | |
| 66 if (value_length == 0) | |
| 67 return false; | |
| 68 if (result) { | |
| 69 scoped_ptr<wchar_t[]> value(new wchar_t[value_length]); | |
| 70 ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(), | |
| 71 value_length); | |
| 72 *result = WideToUTF8(value.get()); | |
| 73 } | |
| 74 return true; | |
| 75 #else | |
| 76 #error need to port | |
| 77 #endif | |
| 78 } | |
| 79 | |
| 80 bool SetVarImpl(const char* variable_name, const std::string& new_value) { | |
| 81 #if defined(OS_POSIX) | |
| 82 // On success, zero is returned. | |
| 83 return !setenv(variable_name, new_value.c_str(), 1); | |
| 84 #elif defined(OS_WIN) | |
| 85 // On success, a nonzero value is returned. | |
| 86 return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), | |
| 87 UTF8ToWide(new_value).c_str()); | |
| 88 #endif | |
| 89 } | |
| 90 | |
| 91 bool UnSetVarImpl(const char* variable_name) { | |
| 92 #if defined(OS_POSIX) | |
| 93 // On success, zero is returned. | |
| 94 return !unsetenv(variable_name); | |
| 95 #elif defined(OS_WIN) | |
| 96 // On success, a nonzero value is returned. | |
| 97 return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL); | |
| 98 #endif | |
| 99 } | |
| 100 }; | |
| 101 | |
| 102 // Parses a null-terminated input string of an environment block. The key is | |
| 103 // placed into the given string, and the total length of the line, including | |
| 104 // the terminating null, is returned. | |
| 105 size_t ParseEnvLine(const NativeEnvironmentString::value_type* input, | |
| 106 NativeEnvironmentString* key) { | |
| 107 // Skip to the equals or end of the string, this is the key. | |
| 108 size_t cur = 0; | |
| 109 while (input[cur] && input[cur] != '=') | |
| 110 cur++; | |
| 111 *key = NativeEnvironmentString(&input[0], cur); | |
| 112 | |
| 113 // Now just skip to the end of the string. | |
| 114 while (input[cur]) | |
| 115 cur++; | |
| 116 return cur + 1; | |
| 117 } | |
| 118 | |
| 119 } // namespace | |
| 120 | |
| 121 namespace env_vars { | |
| 122 | |
| 123 #if defined(OS_POSIX) | |
| 124 // On Posix systems, this variable contains the location of the user's home | |
| 125 // directory. (e.g, /home/username/). | |
| 126 const char kHome[] = "HOME"; | |
| 127 #endif | |
| 128 | |
| 129 } // namespace env_vars | |
| 130 | |
| 131 Environment::~Environment() {} | |
| 132 | |
| 133 // static | |
| 134 Environment* Environment::Create() { | |
| 135 return new EnvironmentImpl(); | |
| 136 } | |
| 137 | |
| 138 bool Environment::HasVar(const char* variable_name) { | |
| 139 return GetVar(variable_name, NULL); | |
| 140 } | |
| 141 | |
| 142 #if defined(OS_WIN) | |
| 143 | |
| 144 string16 AlterEnvironment(const wchar_t* env, | |
| 145 const EnvironmentMap& changes) { | |
| 146 string16 result; | |
| 147 | |
| 148 // First copy all unmodified values to the output. | |
| 149 size_t cur_env = 0; | |
| 150 string16 key; | |
| 151 while (env[cur_env]) { | |
| 152 const wchar_t* line = &env[cur_env]; | |
| 153 size_t line_length = ParseEnvLine(line, &key); | |
| 154 | |
| 155 // Keep only values not specified in the change vector. | |
| 156 EnvironmentMap::const_iterator found_change = changes.find(key); | |
| 157 if (found_change == changes.end()) | |
| 158 result.append(line, line_length); | |
| 159 | |
| 160 cur_env += line_length; | |
| 161 } | |
| 162 | |
| 163 // Now append all modified and new values. | |
| 164 for (EnvironmentMap::const_iterator i = changes.begin(); | |
| 165 i != changes.end(); ++i) { | |
| 166 if (!i->second.empty()) { | |
| 167 result.append(i->first); | |
| 168 result.push_back('='); | |
| 169 result.append(i->second); | |
| 170 result.push_back(0); | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 // An additional null marks the end of the list. We always need a double-null | |
| 175 // in case nothing was added above. | |
| 176 if (result.empty()) | |
| 177 result.push_back(0); | |
| 178 result.push_back(0); | |
| 179 return result; | |
| 180 } | |
| 181 | |
| 182 #elif defined(OS_POSIX) | |
| 183 | |
| 184 scoped_ptr<char*[]> AlterEnvironment(const char* const* const env, | |
| 185 const EnvironmentMap& changes) { | |
| 186 std::string value_storage; // Holds concatenated null-terminated strings. | |
| 187 std::vector<size_t> result_indices; // Line indices into value_storage. | |
| 188 | |
| 189 // First build up all of the unchanged environment strings. These are | |
| 190 // null-terminated of the form "key=value". | |
| 191 std::string key; | |
| 192 for (size_t i = 0; env[i]; i++) { | |
| 193 size_t line_length = ParseEnvLine(env[i], &key); | |
| 194 | |
| 195 // Keep only values not specified in the change vector. | |
| 196 EnvironmentMap::const_iterator found_change = changes.find(key); | |
| 197 if (found_change == changes.end()) { | |
| 198 result_indices.push_back(value_storage.size()); | |
| 199 value_storage.append(env[i], line_length); | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 // Now append all modified and new values. | |
| 204 for (EnvironmentMap::const_iterator i = changes.begin(); | |
| 205 i != changes.end(); ++i) { | |
| 206 if (!i->second.empty()) { | |
| 207 result_indices.push_back(value_storage.size()); | |
| 208 value_storage.append(i->first); | |
| 209 value_storage.push_back('='); | |
| 210 value_storage.append(i->second); | |
| 211 value_storage.push_back(0); | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 size_t pointer_count_required = | |
| 216 result_indices.size() + 1 + // Null-terminated array of pointers. | |
| 217 (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer. | |
| 218 scoped_ptr<char*[]> result(new char*[pointer_count_required]); | |
| 219 | |
| 220 // The string storage goes after the array of pointers. | |
| 221 char* storage_data = reinterpret_cast<char*>( | |
| 222 &result.get()[result_indices.size() + 1]); | |
| 223 if (!value_storage.empty()) | |
| 224 memcpy(storage_data, value_storage.data(), value_storage.size()); | |
| 225 | |
| 226 // Fill array of pointers at the beginning of the result. | |
| 227 for (size_t i = 0; i < result_indices.size(); i++) | |
| 228 result[i] = &storage_data[result_indices[i]]; | |
| 229 result[result_indices.size()] = 0; // Null terminator. | |
| 230 | |
| 231 return result.Pass(); | |
| 232 } | |
| 233 | |
| 234 #endif // OS_POSIX | |
| 235 | |
| 236 } // namespace base | |
| OLD | NEW |