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 <algorithm> 18 #include <cctype> 19 #include <cstdlib> 20 #include <cstring> 21 #include <iostream> 22 #include <limits> 23 #include <map> 24 #include <utility> 25 26 #include "../src/string_util.h" 27 28 namespace benchmark { 29 namespace { 30 31 // Parses 'str' for a 32-bit signed integer. If successful, writes 32 // the result to *value and returns true; otherwise leaves *value 33 // unchanged and returns false. 34 bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { 35 // Parses the environment variable as a decimal integer. 36 char* end = nullptr; 37 const long long_value = strtol(str, &end, 10); // NOLINT 38 39 // Has strtol() consumed all characters in the string? 40 if (*end != '\0') { 41 // No - an invalid character was encountered. 42 std::cerr << src_text << " is expected to be a 32-bit integer, " 43 << "but actually has value \"" << str << "\".\n"; 44 return false; 45 } 46 47 // Is the parsed value in the range of an Int32? 48 const int32_t result = static_cast<int32_t>(long_value); 49 if (long_value == std::numeric_limits<long>::max() || 50 long_value == std::numeric_limits<long>::min() || 51 // The parsed value overflows as a long. (strtol() returns 52 // LONG_MAX or LONG_MIN when the input overflows.) 53 result != long_value 54 // The parsed value overflows as an Int32. 55 ) { 56 std::cerr << src_text << " is expected to be a 32-bit integer, " 57 << "but actually has value \"" << str << "\", " 58 << "which overflows.\n"; 59 return false; 60 } 61 62 *value = result; 63 return true; 64 } 65 66 // Parses 'str' for a double. If successful, writes the result to *value and 67 // returns true; otherwise leaves *value unchanged and returns false. 68 bool ParseDouble(const std::string& src_text, const char* str, double* value) { 69 // Parses the environment variable as a decimal integer. 70 char* end = nullptr; 71 const double double_value = strtod(str, &end); // NOLINT 72 73 // Has strtol() consumed all characters in the string? 74 if (*end != '\0') { 75 // No - an invalid character was encountered. 76 std::cerr << src_text << " is expected to be a double, " 77 << "but actually has value \"" << str << "\".\n"; 78 return false; 79 } 80 81 *value = double_value; 82 return true; 83 } 84 85 // Parses 'str' into KV pairs. If successful, writes the result to *value and 86 // returns true; otherwise leaves *value unchanged and returns false. 87 bool ParseKvPairs(const std::string& src_text, const char* str, 88 std::map<std::string, std::string>* value) { 89 std::map<std::string, std::string> kvs; 90 for (const auto& kvpair : StrSplit(str, ',')) { 91 const auto kv = StrSplit(kvpair, '='); 92 if (kv.size() != 2) { 93 std::cerr << src_text << " is expected to be a comma-separated list of " 94 << "<key>=<value> strings, but actually has value \"" << str 95 << "\".\n"; 96 return false; 97 } 98 if (!kvs.emplace(kv[0], kv[1]).second) { 99 std::cerr << src_text << " is expected to contain unique keys but key \"" 100 << kv[0] << "\" was repeated.\n"; 101 return false; 102 } 103 } 104 105 *value = kvs; 106 return true; 107 } 108 109 // Returns the name of the environment variable corresponding to the 110 // given flag. For example, FlagToEnvVar("foo") will return 111 // "BENCHMARK_FOO" in the open-source version. 112 static std::string FlagToEnvVar(const char* flag) { 113 const std::string flag_str(flag); 114 115 std::string env_var; 116 for (size_t i = 0; i != flag_str.length(); ++i) 117 env_var += static_cast<char>(::toupper(flag_str.c_str()[i])); 118 119 return env_var; 120 } 121 122 } // namespace 123 124 bool BoolFromEnv(const char* flag, bool default_val) { 125 const std::string env_var = FlagToEnvVar(flag); 126 const char* const value_str = getenv(env_var.c_str()); 127 return value_str == nullptr ? default_val : IsTruthyFlagValue(value_str); 128 } 129 130 int32_t Int32FromEnv(const char* flag, int32_t default_val) { 131 const std::string env_var = FlagToEnvVar(flag); 132 const char* const value_str = getenv(env_var.c_str()); 133 int32_t value = default_val; 134 if (value_str == nullptr || 135 !ParseInt32(std::string("Environment variable ") + env_var, value_str, 136 &value)) { 137 return default_val; 138 } 139 return value; 140 } 141 142 double DoubleFromEnv(const char* flag, double default_val) { 143 const std::string env_var = FlagToEnvVar(flag); 144 const char* const value_str = getenv(env_var.c_str()); 145 double value = default_val; 146 if (value_str == nullptr || 147 !ParseDouble(std::string("Environment variable ") + env_var, value_str, 148 &value)) { 149 return default_val; 150 } 151 return value; 152 } 153 154 const char* StringFromEnv(const char* flag, const char* default_val) { 155 const std::string env_var = FlagToEnvVar(flag); 156 const char* const value = getenv(env_var.c_str()); 157 return value == nullptr ? default_val : value; 158 } 159 160 std::map<std::string, std::string> KvPairsFromEnv( 161 const char* flag, std::map<std::string, std::string> default_val) { 162 const std::string env_var = FlagToEnvVar(flag); 163 const char* const value_str = getenv(env_var.c_str()); 164 165 if (value_str == nullptr) return default_val; 166 167 std::map<std::string, std::string> value; 168 if (!ParseKvPairs("Environment variable " + env_var, value_str, &value)) { 169 return default_val; 170 } 171 return value; 172 } 173 174 // Parses a string as a command line flag. The string should have 175 // the format "--flag=value". When def_optional is true, the "=value" 176 // part can be omitted. 177 // 178 // Returns the value of the flag, or nullptr if the parsing failed. 179 const char* ParseFlagValue(const char* str, const char* flag, 180 bool def_optional) { 181 // str and flag must not be nullptr. 182 if (str == nullptr || flag == nullptr) return nullptr; 183 184 // The flag must start with "--". 185 const std::string flag_str = std::string("--") + std::string(flag); 186 const size_t flag_len = flag_str.length(); 187 if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; 188 189 // Skips the flag name. 190 const char* flag_end = str + flag_len; 191 192 // When def_optional is true, it's OK to not have a "=value" part. 193 if (def_optional && (flag_end[0] == '\0')) return flag_end; 194 195 // If def_optional is true and there are more characters after the 196 // flag name, or if def_optional is false, there must be a '=' after 197 // the flag name. 198 if (flag_end[0] != '=') return nullptr; 199 200 // Returns the string after "=". 201 return flag_end + 1; 202 } 203 204 bool ParseBoolFlag(const char* str, const char* flag, bool* value) { 205 // Gets the value of the flag as a string. 206 const char* const value_str = ParseFlagValue(str, flag, true); 207 208 // Aborts if the parsing failed. 209 if (value_str == nullptr) return false; 210 211 // Converts the string value to a bool. 212 *value = IsTruthyFlagValue(value_str); 213 return true; 214 } 215 216 bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { 217 // Gets the value of the flag as a string. 218 const char* const value_str = ParseFlagValue(str, flag, false); 219 220 // Aborts if the parsing failed. 221 if (value_str == nullptr) return false; 222 223 // Sets *value to the value of the flag. 224 return ParseInt32(std::string("The value of flag --") + flag, value_str, 225 value); 226 } 227 228 bool ParseDoubleFlag(const char* str, const char* flag, double* value) { 229 // Gets the value of the flag as a string. 230 const char* const value_str = ParseFlagValue(str, flag, false); 231 232 // Aborts if the parsing failed. 233 if (value_str == nullptr) return false; 234 235 // Sets *value to the value of the flag. 236 return ParseDouble(std::string("The value of flag --") + flag, value_str, 237 value); 238 } 239 240 bool ParseStringFlag(const char* str, const char* flag, std::string* value) { 241 // Gets the value of the flag as a string. 242 const char* const value_str = ParseFlagValue(str, flag, false); 243 244 // Aborts if the parsing failed. 245 if (value_str == nullptr) return false; 246 247 *value = value_str; 248 return true; 249 } 250 251 bool ParseKeyValueFlag(const char* str, const char* flag, 252 std::map<std::string, std::string>* value) { 253 const char* const value_str = ParseFlagValue(str, flag, false); 254 255 if (value_str == nullptr) return false; 256 257 for (const auto& kvpair : StrSplit(value_str, ',')) { 258 const auto kv = StrSplit(kvpair, '='); 259 if (kv.size() != 2) return false; 260 value->emplace(kv[0], kv[1]); 261 } 262 263 return true; 264 } 265 266 bool IsFlag(const char* str, const char* flag) { 267 return (ParseFlagValue(str, flag, true) != nullptr); 268 } 269 270 bool IsTruthyFlagValue(const std::string& value) { 271 if (value.size() == 1) { 272 char v = value[0]; 273 return isalnum(v) && 274 !(v == '0' || v == 'f' || v == 'F' || v == 'n' || v == 'N'); 275 } else if (!value.empty()) { 276 std::string value_lower(value); 277 std::transform(value_lower.begin(), value_lower.end(), value_lower.begin(), 278 [](char c) { return static_cast<char>(::tolower(c)); }); 279 return !(value_lower == "false" || value_lower == "no" || 280 value_lower == "off"); 281 } else 282 return true; 283 } 284 285 } // end namespace benchmark 286