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