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 22namespace 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. 26bool 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. 60bool 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 77inline 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. 91static 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". 105bool 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. 114int32_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. 134const 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. 145const 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 170bool 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 182bool 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 194bool 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 206bool 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 217bool IsFlag(const char* str, const char* flag) { 218 return (ParseFlagValue(str, flag, true) != nullptr); 219} 220} // end namespace benchmark 221