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