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