Home | History | Annotate | Download | only in src
      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