1 // Copyright 2015 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "commandlineflags.h" 16 17 #include <cstdlib> 18 #include <cstring> 19 #include <iostream> 20 #include <limits> 21 22 namespace benchmark { 23 // Parses 'str' for a 32-bit signed integer. If successful, writes 24 // the result to *value and returns true; otherwise leaves *value 25 // unchanged and returns false. 26 bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { 27 // Parses the environment variable as a decimal integer. 28 char* end = nullptr; 29 const long long_value = strtol(str, &end, 10); // NOLINT 30 31 // Has strtol() consumed all characters in the string? 32 if (*end != '\0') { 33 // No - an invalid character was encountered. 34 std::cerr << src_text << " is expected to be a 32-bit integer, " 35 << "but actually has value \"" << str << "\".\n"; 36 return false; 37 } 38 39 // Is the parsed value in the range of an Int32? 40 const int32_t result = static_cast<int32_t>(long_value); 41 if (long_value == std::numeric_limits<long>::max() || 42 long_value == std::numeric_limits<long>::min() || 43 // The parsed value overflows as a long. (strtol() returns 44 // LONG_MAX or LONG_MIN when the input overflows.) 45 result != long_value 46 // The parsed value overflows as an Int32. 47 ) { 48 std::cerr << src_text << " is expected to be a 32-bit integer, " 49 << "but actually has value \"" << str << "\", " 50 << "which overflows.\n"; 51 return false; 52 } 53 54 *value = result; 55 return true; 56 } 57 58 // Parses 'str' for a double. If successful, writes the result to *value and 59 // returns true; otherwise leaves *value unchanged and returns false. 60 bool ParseDouble(const std::string& src_text, const char* str, double* value) { 61 // Parses the environment variable as a decimal integer. 62 char* end = nullptr; 63 const double double_value = strtod(str, &end); // NOLINT 64 65 // Has strtol() consumed all characters in the string? 66 if (*end != '\0') { 67 // No - an invalid character was encountered. 68 std::cerr << src_text << " is expected to be a double, " 69 << "but actually has value \"" << str << "\".\n"; 70 return false; 71 } 72 73 *value = double_value; 74 return true; 75 } 76 77 inline const char* GetEnv(const char* name) { 78 #if defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) 79 // Environment variables which we programmatically clear will be set to the 80 // empty string rather than unset (nullptr). Handle that case. 81 const char* const env = getenv(name); 82 return (env != nullptr && env[0] != '\0') ? env : nullptr; 83 #else 84 return getenv(name); 85 #endif 86 } 87 88 // Returns the name of the environment variable corresponding to the 89 // given flag. For example, FlagToEnvVar("foo") will return 90 // "BENCHMARK_FOO" in the open-source version. 91 static std::string FlagToEnvVar(const char* flag) { 92 const std::string flag_str(flag); 93 94 std::string env_var; 95 for (size_t i = 0; i != flag_str.length(); ++i) 96 env_var += static_cast<char>(::toupper(flag_str.c_str()[i])); 97 98 return "BENCHMARK_" + env_var; 99 } 100 101 // Reads and returns the Boolean environment variable corresponding to 102 // the given flag; if it's not set, returns default_value. 103 // 104 // The value is considered true iff it's not "0". 105 bool BoolFromEnv(const char* flag, bool default_value) { 106 const std::string env_var = FlagToEnvVar(flag); 107 const char* const string_value = GetEnv(env_var.c_str()); 108 return string_value == nullptr ? default_value : strcmp(string_value, "0") != 0; 109 } 110 111 // Reads and returns a 32-bit integer stored in the environment 112 // variable corresponding to the given flag; if it isn't set or 113 // doesn't represent a valid 32-bit integer, returns default_value. 114 int32_t Int32FromEnv(const char* flag, int32_t default_value) { 115 const std::string env_var = FlagToEnvVar(flag); 116 const char* const string_value = GetEnv(env_var.c_str()); 117 if (string_value == nullptr) { 118 // The environment variable is not set. 119 return default_value; 120 } 121 122 int32_t result = default_value; 123 if (!ParseInt32(std::string("Environment variable ") + env_var, string_value, 124 &result)) { 125 std::cout << "The default value " << default_value << " is used.\n"; 126 return default_value; 127 } 128 129 return result; 130 } 131 132 // Reads and returns the string environment variable corresponding to 133 // the given flag; if it's not set, returns default_value. 134 const char* StringFromEnv(const char* flag, const char* default_value) { 135 const std::string env_var = FlagToEnvVar(flag); 136 const char* const value = GetEnv(env_var.c_str()); 137 return value == nullptr ? default_value : value; 138 } 139 140 // Parses a string as a command line flag. The string should have 141 // the format "--flag=value". When def_optional is true, the "=value" 142 // part can be omitted. 143 // 144 // Returns the value of the flag, or nullptr if the parsing failed. 145 const char* ParseFlagValue(const char* str, const char* flag, 146 bool def_optional) { 147 // str and flag must not be nullptr. 148 if (str == nullptr || flag == nullptr) return nullptr; 149 150 // The flag must start with "--". 151 const std::string flag_str = std::string("--") + std::string(flag); 152 const size_t flag_len = flag_str.length(); 153 if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; 154 155 // Skips the flag name. 156 const char* flag_end = str + flag_len; 157 158 // When def_optional is true, it's OK to not have a "=value" part. 159 if (def_optional && (flag_end[0] == '\0')) return flag_end; 160 161 // If def_optional is true and there are more characters after the 162 // flag name, or if def_optional is false, there must be a '=' after 163 // the flag name. 164 if (flag_end[0] != '=') return nullptr; 165 166 // Returns the string after "=". 167 return flag_end + 1; 168 } 169 170 bool ParseBoolFlag(const char* str, const char* flag, bool* value) { 171 // Gets the value of the flag as a string. 172 const char* const value_str = ParseFlagValue(str, flag, true); 173 174 // Aborts if the parsing failed. 175 if (value_str == nullptr) return false; 176 177 // Converts the string value to a bool. 178 *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); 179 return true; 180 } 181 182 bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { 183 // Gets the value of the flag as a string. 184 const char* const value_str = ParseFlagValue(str, flag, false); 185 186 // Aborts if the parsing failed. 187 if (value_str == nullptr) return false; 188 189 // Sets *value to the value of the flag. 190 return ParseInt32(std::string("The value of flag --") + flag, value_str, 191 value); 192 } 193 194 bool ParseDoubleFlag(const char* str, const char* flag, double* value) { 195 // Gets the value of the flag as a string. 196 const char* const value_str = ParseFlagValue(str, flag, false); 197 198 // Aborts if the parsing failed. 199 if (value_str == nullptr) return false; 200 201 // Sets *value to the value of the flag. 202 return ParseDouble(std::string("The value of flag --") + flag, value_str, 203 value); 204 } 205 206 bool ParseStringFlag(const char* str, const char* flag, std::string* value) { 207 // Gets the value of the flag as a string. 208 const char* const value_str = ParseFlagValue(str, flag, false); 209 210 // Aborts if the parsing failed. 211 if (value_str == nullptr) return false; 212 213 *value = value_str; 214 return true; 215 } 216 217 bool IsFlag(const char* str, const char* flag) { 218 return (ParseFlagValue(str, flag, true) != nullptr); 219 } 220 } // end namespace benchmark 221