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 <cctype> 18 #include <cstdlib> 19 #include <cstring> 20 #include <iostream> 21 #include <limits> 22 23 namespace benchmark { 24 // Parses 'str' for a 32-bit signed integer. If successful, writes 25 // the result to *value and returns true; otherwise leaves *value 26 // unchanged and returns false. 27 bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { 28 // Parses the environment variable as a decimal integer. 29 char* end = nullptr; 30 const long long_value = strtol(str, &end, 10); // NOLINT 31 32 // Has strtol() consumed all characters in the string? 33 if (*end != '\0') { 34 // No - an invalid character was encountered. 35 std::cerr << src_text << " is expected to be a 32-bit integer, " 36 << "but actually has value \"" << str << "\".\n"; 37 return false; 38 } 39 40 // Is the parsed value in the range of an Int32? 41 const int32_t result = static_cast<int32_t>(long_value); 42 if (long_value == std::numeric_limits<long>::max() || 43 long_value == std::numeric_limits<long>::min() || 44 // The parsed value overflows as a long. (strtol() returns 45 // LONG_MAX or LONG_MIN when the input overflows.) 46 result != long_value 47 // The parsed value overflows as an Int32. 48 ) { 49 std::cerr << src_text << " is expected to be a 32-bit integer, " 50 << "but actually has value \"" << str << "\", " 51 << "which overflows.\n"; 52 return false; 53 } 54 55 *value = result; 56 return true; 57 } 58 59 // Parses 'str' for a double. If successful, writes the result to *value and 60 // returns true; otherwise leaves *value unchanged and returns false. 61 bool ParseDouble(const std::string& src_text, const char* str, double* value) { 62 // Parses the environment variable as a decimal integer. 63 char* end = nullptr; 64 const double double_value = strtod(str, &end); // NOLINT 65 66 // Has strtol() consumed all characters in the string? 67 if (*end != '\0') { 68 // No - an invalid character was encountered. 69 std::cerr << src_text << " is expected to be a double, " 70 << "but actually has value \"" << str << "\".\n"; 71 return false; 72 } 73 74 *value = double_value; 75 return true; 76 } 77 78 // Returns the name of the environment variable corresponding to the 79 // given flag. For example, FlagToEnvVar("foo") will return 80 // "BENCHMARK_FOO" in the open-source version. 81 static std::string FlagToEnvVar(const char* flag) { 82 const std::string flag_str(flag); 83 84 std::string env_var; 85 for (size_t i = 0; i != flag_str.length(); ++i) 86 env_var += static_cast<char>(::toupper(flag_str.c_str()[i])); 87 88 return "BENCHMARK_" + env_var; 89 } 90 91 // Reads and returns the Boolean environment variable corresponding to 92 // the given flag; if it's not set, returns default_value. 93 // 94 // The value is considered true iff it's not "0". 95 bool BoolFromEnv(const char* flag, bool default_value) { 96 const std::string env_var = FlagToEnvVar(flag); 97 const char* const string_value = getenv(env_var.c_str()); 98 return string_value == nullptr ? default_value 99 : strcmp(string_value, "0") != 0; 100 } 101 102 // Reads and returns a 32-bit integer stored in the environment 103 // variable corresponding to the given flag; if it isn't set or 104 // doesn't represent a valid 32-bit integer, returns default_value. 105 int32_t Int32FromEnv(const char* flag, int32_t default_value) { 106 const std::string env_var = FlagToEnvVar(flag); 107 const char* const string_value = getenv(env_var.c_str()); 108 if (string_value == nullptr) { 109 // The environment variable is not set. 110 return default_value; 111 } 112 113 int32_t result = default_value; 114 if (!ParseInt32(std::string("Environment variable ") + env_var, string_value, 115 &result)) { 116 std::cout << "The default value " << default_value << " is used.\n"; 117 return default_value; 118 } 119 120 return result; 121 } 122 123 // Reads and returns the string environment variable corresponding to 124 // the given flag; if it's not set, returns default_value. 125 const char* StringFromEnv(const char* flag, const char* default_value) { 126 const std::string env_var = FlagToEnvVar(flag); 127 const char* const value = getenv(env_var.c_str()); 128 return value == nullptr ? default_value : value; 129 } 130 131 // Parses a string as a command line flag. The string should have 132 // the format "--flag=value". When def_optional is true, the "=value" 133 // part can be omitted. 134 // 135 // Returns the value of the flag, or nullptr if the parsing failed. 136 const char* ParseFlagValue(const char* str, const char* flag, 137 bool def_optional) { 138 // str and flag must not be nullptr. 139 if (str == nullptr || flag == nullptr) return nullptr; 140 141 // The flag must start with "--". 142 const std::string flag_str = std::string("--") + std::string(flag); 143 const size_t flag_len = flag_str.length(); 144 if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; 145 146 // Skips the flag name. 147 const char* flag_end = str + flag_len; 148 149 // When def_optional is true, it's OK to not have a "=value" part. 150 if (def_optional && (flag_end[0] == '\0')) return flag_end; 151 152 // If def_optional is true and there are more characters after the 153 // flag name, or if def_optional is false, there must be a '=' after 154 // the flag name. 155 if (flag_end[0] != '=') return nullptr; 156 157 // Returns the string after "=". 158 return flag_end + 1; 159 } 160 161 bool ParseBoolFlag(const char* str, const char* flag, bool* value) { 162 // Gets the value of the flag as a string. 163 const char* const value_str = ParseFlagValue(str, flag, true); 164 165 // Aborts if the parsing failed. 166 if (value_str == nullptr) return false; 167 168 // Converts the string value to a bool. 169 *value = IsTruthyFlagValue(value_str); 170 return true; 171 } 172 173 bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { 174 // Gets the value of the flag as a string. 175 const char* const value_str = ParseFlagValue(str, flag, false); 176 177 // Aborts if the parsing failed. 178 if (value_str == nullptr) return false; 179 180 // Sets *value to the value of the flag. 181 return ParseInt32(std::string("The value of flag --") + flag, value_str, 182 value); 183 } 184 185 bool ParseDoubleFlag(const char* str, const char* flag, double* value) { 186 // Gets the value of the flag as a string. 187 const char* const value_str = ParseFlagValue(str, flag, false); 188 189 // Aborts if the parsing failed. 190 if (value_str == nullptr) return false; 191 192 // Sets *value to the value of the flag. 193 return ParseDouble(std::string("The value of flag --") + flag, value_str, 194 value); 195 } 196 197 bool ParseStringFlag(const char* str, const char* flag, std::string* value) { 198 // Gets the value of the flag as a string. 199 const char* const value_str = ParseFlagValue(str, flag, false); 200 201 // Aborts if the parsing failed. 202 if (value_str == nullptr) return false; 203 204 *value = value_str; 205 return true; 206 } 207 208 bool IsFlag(const char* str, const char* flag) { 209 return (ParseFlagValue(str, flag, true) != nullptr); 210 } 211 212 bool IsTruthyFlagValue(const std::string& str) { 213 if (str.empty()) return true; 214 char ch = str[0]; 215 return isalnum(ch) && 216 !(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N'); 217 } 218 } // end namespace benchmark 219