• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ParseInt32(const std::string & src_text,const char * str,int32_t * value)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.
ParseDouble(const std::string & src_text,const char * str,double * value)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.
FlagToEnvVar(const char * flag)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".
BoolFromEnv(const char * flag,bool default_value)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.
Int32FromEnv(const char * flag,int32_t 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.
StringFromEnv(const char * flag,const char * 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.
ParseFlagValue(const char * str,const char * flag,bool def_optional)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 
ParseBoolFlag(const char * str,const char * flag,bool * value)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 
ParseInt32Flag(const char * str,const char * flag,int32_t * value)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 
ParseDoubleFlag(const char * str,const char * flag,double * value)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 
ParseStringFlag(const char * str,const char * flag,std::string * value)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 
IsFlag(const char * str,const char * flag)208 bool IsFlag(const char* str, const char* flag) {
209   return (ParseFlagValue(str, flag, true) != nullptr);
210 }
211 
IsTruthyFlagValue(const std::string & value)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