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
22namespace 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.
26bool 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.
60bool 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
77inline 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.
91static 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".
105bool 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.
114int32_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.
134const 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.
145const 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
170bool 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
182bool 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
194bool 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
206bool 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
217bool IsFlag(const char* str, const char* flag) {
218  return (ParseFlagValue(str, flag, true) != nullptr);
219}
220}  // end namespace benchmark
221