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