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 <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& value) {
    213   if (value.empty()) return true;
    214   char ch = value[0];
    215   return isalnum(ch) &&
    216          !(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N');
    217 }
    218 }  // end namespace benchmark
    219