1a8c51b3fSopenharmony_ci// Copyright 2015 Google Inc. All rights reserved.
2a8c51b3fSopenharmony_ci//
3a8c51b3fSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4a8c51b3fSopenharmony_ci// you may not use this file except in compliance with the License.
5a8c51b3fSopenharmony_ci// You may obtain a copy of the License at
6a8c51b3fSopenharmony_ci//
7a8c51b3fSopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8a8c51b3fSopenharmony_ci//
9a8c51b3fSopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10a8c51b3fSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11a8c51b3fSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a8c51b3fSopenharmony_ci// See the License for the specific language governing permissions and
13a8c51b3fSopenharmony_ci// limitations under the License.
14a8c51b3fSopenharmony_ci
15a8c51b3fSopenharmony_ci#include "commandlineflags.h"
16a8c51b3fSopenharmony_ci
17a8c51b3fSopenharmony_ci#include <algorithm>
18a8c51b3fSopenharmony_ci#include <cctype>
19a8c51b3fSopenharmony_ci#include <cstdlib>
20a8c51b3fSopenharmony_ci#include <cstring>
21a8c51b3fSopenharmony_ci#include <iostream>
22a8c51b3fSopenharmony_ci#include <limits>
23a8c51b3fSopenharmony_ci#include <map>
24a8c51b3fSopenharmony_ci#include <utility>
25a8c51b3fSopenharmony_ci
26a8c51b3fSopenharmony_ci#include "../src/string_util.h"
27a8c51b3fSopenharmony_ci
28a8c51b3fSopenharmony_cinamespace benchmark {
29a8c51b3fSopenharmony_cinamespace {
30a8c51b3fSopenharmony_ci
31a8c51b3fSopenharmony_ci// Parses 'str' for a 32-bit signed integer.  If successful, writes
32a8c51b3fSopenharmony_ci// the result to *value and returns true; otherwise leaves *value
33a8c51b3fSopenharmony_ci// unchanged and returns false.
34a8c51b3fSopenharmony_cibool ParseInt32(const std::string& src_text, const char* str, int32_t* value) {
35a8c51b3fSopenharmony_ci  // Parses the environment variable as a decimal integer.
36a8c51b3fSopenharmony_ci  char* end = nullptr;
37a8c51b3fSopenharmony_ci  const long long_value = strtol(str, &end, 10);  // NOLINT
38a8c51b3fSopenharmony_ci
39a8c51b3fSopenharmony_ci  // Has strtol() consumed all characters in the string?
40a8c51b3fSopenharmony_ci  if (*end != '\0') {
41a8c51b3fSopenharmony_ci    // No - an invalid character was encountered.
42a8c51b3fSopenharmony_ci    std::cerr << src_text << " is expected to be a 32-bit integer, "
43a8c51b3fSopenharmony_ci              << "but actually has value \"" << str << "\".\n";
44a8c51b3fSopenharmony_ci    return false;
45a8c51b3fSopenharmony_ci  }
46a8c51b3fSopenharmony_ci
47a8c51b3fSopenharmony_ci  // Is the parsed value in the range of an Int32?
48a8c51b3fSopenharmony_ci  const int32_t result = static_cast<int32_t>(long_value);
49a8c51b3fSopenharmony_ci  if (long_value == std::numeric_limits<long>::max() ||
50a8c51b3fSopenharmony_ci      long_value == std::numeric_limits<long>::min() ||
51a8c51b3fSopenharmony_ci      // The parsed value overflows as a long.  (strtol() returns
52a8c51b3fSopenharmony_ci      // LONG_MAX or LONG_MIN when the input overflows.)
53a8c51b3fSopenharmony_ci      result != long_value
54a8c51b3fSopenharmony_ci      // The parsed value overflows as an Int32.
55a8c51b3fSopenharmony_ci  ) {
56a8c51b3fSopenharmony_ci    std::cerr << src_text << " is expected to be a 32-bit integer, "
57a8c51b3fSopenharmony_ci              << "but actually has value \"" << str << "\", "
58a8c51b3fSopenharmony_ci              << "which overflows.\n";
59a8c51b3fSopenharmony_ci    return false;
60a8c51b3fSopenharmony_ci  }
61a8c51b3fSopenharmony_ci
62a8c51b3fSopenharmony_ci  *value = result;
63a8c51b3fSopenharmony_ci  return true;
64a8c51b3fSopenharmony_ci}
65a8c51b3fSopenharmony_ci
66a8c51b3fSopenharmony_ci// Parses 'str' for a double.  If successful, writes the result to *value and
67a8c51b3fSopenharmony_ci// returns true; otherwise leaves *value unchanged and returns false.
68a8c51b3fSopenharmony_cibool ParseDouble(const std::string& src_text, const char* str, double* value) {
69a8c51b3fSopenharmony_ci  // Parses the environment variable as a decimal integer.
70a8c51b3fSopenharmony_ci  char* end = nullptr;
71a8c51b3fSopenharmony_ci  const double double_value = strtod(str, &end);  // NOLINT
72a8c51b3fSopenharmony_ci
73a8c51b3fSopenharmony_ci  // Has strtol() consumed all characters in the string?
74a8c51b3fSopenharmony_ci  if (*end != '\0') {
75a8c51b3fSopenharmony_ci    // No - an invalid character was encountered.
76a8c51b3fSopenharmony_ci    std::cerr << src_text << " is expected to be a double, "
77a8c51b3fSopenharmony_ci              << "but actually has value \"" << str << "\".\n";
78a8c51b3fSopenharmony_ci    return false;
79a8c51b3fSopenharmony_ci  }
80a8c51b3fSopenharmony_ci
81a8c51b3fSopenharmony_ci  *value = double_value;
82a8c51b3fSopenharmony_ci  return true;
83a8c51b3fSopenharmony_ci}
84a8c51b3fSopenharmony_ci
85a8c51b3fSopenharmony_ci// Parses 'str' into KV pairs. If successful, writes the result to *value and
86a8c51b3fSopenharmony_ci// returns true; otherwise leaves *value unchanged and returns false.
87a8c51b3fSopenharmony_cibool ParseKvPairs(const std::string& src_text, const char* str,
88a8c51b3fSopenharmony_ci                  std::map<std::string, std::string>* value) {
89a8c51b3fSopenharmony_ci  std::map<std::string, std::string> kvs;
90a8c51b3fSopenharmony_ci  for (const auto& kvpair : StrSplit(str, ',')) {
91a8c51b3fSopenharmony_ci    const auto kv = StrSplit(kvpair, '=');
92a8c51b3fSopenharmony_ci    if (kv.size() != 2) {
93a8c51b3fSopenharmony_ci      std::cerr << src_text << " is expected to be a comma-separated list of "
94a8c51b3fSopenharmony_ci                << "<key>=<value> strings, but actually has value \"" << str
95a8c51b3fSopenharmony_ci                << "\".\n";
96a8c51b3fSopenharmony_ci      return false;
97a8c51b3fSopenharmony_ci    }
98a8c51b3fSopenharmony_ci    if (!kvs.emplace(kv[0], kv[1]).second) {
99a8c51b3fSopenharmony_ci      std::cerr << src_text << " is expected to contain unique keys but key \""
100a8c51b3fSopenharmony_ci                << kv[0] << "\" was repeated.\n";
101a8c51b3fSopenharmony_ci      return false;
102a8c51b3fSopenharmony_ci    }
103a8c51b3fSopenharmony_ci  }
104a8c51b3fSopenharmony_ci
105a8c51b3fSopenharmony_ci  *value = kvs;
106a8c51b3fSopenharmony_ci  return true;
107a8c51b3fSopenharmony_ci}
108a8c51b3fSopenharmony_ci
109a8c51b3fSopenharmony_ci// Returns the name of the environment variable corresponding to the
110a8c51b3fSopenharmony_ci// given flag.  For example, FlagToEnvVar("foo") will return
111a8c51b3fSopenharmony_ci// "BENCHMARK_FOO" in the open-source version.
112a8c51b3fSopenharmony_cistatic std::string FlagToEnvVar(const char* flag) {
113a8c51b3fSopenharmony_ci  const std::string flag_str(flag);
114a8c51b3fSopenharmony_ci
115a8c51b3fSopenharmony_ci  std::string env_var;
116a8c51b3fSopenharmony_ci  for (size_t i = 0; i != flag_str.length(); ++i)
117a8c51b3fSopenharmony_ci    env_var += static_cast<char>(::toupper(flag_str.c_str()[i]));
118a8c51b3fSopenharmony_ci
119a8c51b3fSopenharmony_ci  return env_var;
120a8c51b3fSopenharmony_ci}
121a8c51b3fSopenharmony_ci
122a8c51b3fSopenharmony_ci}  // namespace
123a8c51b3fSopenharmony_ci
124a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
125a8c51b3fSopenharmony_cibool BoolFromEnv(const char* flag, bool default_val) {
126a8c51b3fSopenharmony_ci  const std::string env_var = FlagToEnvVar(flag);
127a8c51b3fSopenharmony_ci  const char* const value_str = getenv(env_var.c_str());
128a8c51b3fSopenharmony_ci  return value_str == nullptr ? default_val : IsTruthyFlagValue(value_str);
129a8c51b3fSopenharmony_ci}
130a8c51b3fSopenharmony_ci
131a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
132a8c51b3fSopenharmony_ciint32_t Int32FromEnv(const char* flag, int32_t default_val) {
133a8c51b3fSopenharmony_ci  const std::string env_var = FlagToEnvVar(flag);
134a8c51b3fSopenharmony_ci  const char* const value_str = getenv(env_var.c_str());
135a8c51b3fSopenharmony_ci  int32_t value = default_val;
136a8c51b3fSopenharmony_ci  if (value_str == nullptr ||
137a8c51b3fSopenharmony_ci      !ParseInt32(std::string("Environment variable ") + env_var, value_str,
138a8c51b3fSopenharmony_ci                  &value)) {
139a8c51b3fSopenharmony_ci    return default_val;
140a8c51b3fSopenharmony_ci  }
141a8c51b3fSopenharmony_ci  return value;
142a8c51b3fSopenharmony_ci}
143a8c51b3fSopenharmony_ci
144a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
145a8c51b3fSopenharmony_cidouble DoubleFromEnv(const char* flag, double default_val) {
146a8c51b3fSopenharmony_ci  const std::string env_var = FlagToEnvVar(flag);
147a8c51b3fSopenharmony_ci  const char* const value_str = getenv(env_var.c_str());
148a8c51b3fSopenharmony_ci  double value = default_val;
149a8c51b3fSopenharmony_ci  if (value_str == nullptr ||
150a8c51b3fSopenharmony_ci      !ParseDouble(std::string("Environment variable ") + env_var, value_str,
151a8c51b3fSopenharmony_ci                   &value)) {
152a8c51b3fSopenharmony_ci    return default_val;
153a8c51b3fSopenharmony_ci  }
154a8c51b3fSopenharmony_ci  return value;
155a8c51b3fSopenharmony_ci}
156a8c51b3fSopenharmony_ci
157a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
158a8c51b3fSopenharmony_ciconst char* StringFromEnv(const char* flag, const char* default_val) {
159a8c51b3fSopenharmony_ci  const std::string env_var = FlagToEnvVar(flag);
160a8c51b3fSopenharmony_ci  const char* const value = getenv(env_var.c_str());
161a8c51b3fSopenharmony_ci  return value == nullptr ? default_val : value;
162a8c51b3fSopenharmony_ci}
163a8c51b3fSopenharmony_ci
164a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
165a8c51b3fSopenharmony_cistd::map<std::string, std::string> KvPairsFromEnv(
166a8c51b3fSopenharmony_ci    const char* flag, std::map<std::string, std::string> default_val) {
167a8c51b3fSopenharmony_ci  const std::string env_var = FlagToEnvVar(flag);
168a8c51b3fSopenharmony_ci  const char* const value_str = getenv(env_var.c_str());
169a8c51b3fSopenharmony_ci
170a8c51b3fSopenharmony_ci  if (value_str == nullptr) return default_val;
171a8c51b3fSopenharmony_ci
172a8c51b3fSopenharmony_ci  std::map<std::string, std::string> value;
173a8c51b3fSopenharmony_ci  if (!ParseKvPairs("Environment variable " + env_var, value_str, &value)) {
174a8c51b3fSopenharmony_ci    return default_val;
175a8c51b3fSopenharmony_ci  }
176a8c51b3fSopenharmony_ci  return value;
177a8c51b3fSopenharmony_ci}
178a8c51b3fSopenharmony_ci
179a8c51b3fSopenharmony_ci// Parses a string as a command line flag.  The string should have
180a8c51b3fSopenharmony_ci// the format "--flag=value".  When def_optional is true, the "=value"
181a8c51b3fSopenharmony_ci// part can be omitted.
182a8c51b3fSopenharmony_ci//
183a8c51b3fSopenharmony_ci// Returns the value of the flag, or nullptr if the parsing failed.
184a8c51b3fSopenharmony_ciconst char* ParseFlagValue(const char* str, const char* flag,
185a8c51b3fSopenharmony_ci                           bool def_optional) {
186a8c51b3fSopenharmony_ci  // str and flag must not be nullptr.
187a8c51b3fSopenharmony_ci  if (str == nullptr || flag == nullptr) return nullptr;
188a8c51b3fSopenharmony_ci
189a8c51b3fSopenharmony_ci  // The flag must start with "--".
190a8c51b3fSopenharmony_ci  const std::string flag_str = std::string("--") + std::string(flag);
191a8c51b3fSopenharmony_ci  const size_t flag_len = flag_str.length();
192a8c51b3fSopenharmony_ci  if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
193a8c51b3fSopenharmony_ci
194a8c51b3fSopenharmony_ci  // Skips the flag name.
195a8c51b3fSopenharmony_ci  const char* flag_end = str + flag_len;
196a8c51b3fSopenharmony_ci
197a8c51b3fSopenharmony_ci  // When def_optional is true, it's OK to not have a "=value" part.
198a8c51b3fSopenharmony_ci  if (def_optional && (flag_end[0] == '\0')) return flag_end;
199a8c51b3fSopenharmony_ci
200a8c51b3fSopenharmony_ci  // If def_optional is true and there are more characters after the
201a8c51b3fSopenharmony_ci  // flag name, or if def_optional is false, there must be a '=' after
202a8c51b3fSopenharmony_ci  // the flag name.
203a8c51b3fSopenharmony_ci  if (flag_end[0] != '=') return nullptr;
204a8c51b3fSopenharmony_ci
205a8c51b3fSopenharmony_ci  // Returns the string after "=".
206a8c51b3fSopenharmony_ci  return flag_end + 1;
207a8c51b3fSopenharmony_ci}
208a8c51b3fSopenharmony_ci
209a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
210a8c51b3fSopenharmony_cibool ParseBoolFlag(const char* str, const char* flag, bool* value) {
211a8c51b3fSopenharmony_ci  // Gets the value of the flag as a string.
212a8c51b3fSopenharmony_ci  const char* const value_str = ParseFlagValue(str, flag, true);
213a8c51b3fSopenharmony_ci
214a8c51b3fSopenharmony_ci  // Aborts if the parsing failed.
215a8c51b3fSopenharmony_ci  if (value_str == nullptr) return false;
216a8c51b3fSopenharmony_ci
217a8c51b3fSopenharmony_ci  // Converts the string value to a bool.
218a8c51b3fSopenharmony_ci  *value = IsTruthyFlagValue(value_str);
219a8c51b3fSopenharmony_ci  return true;
220a8c51b3fSopenharmony_ci}
221a8c51b3fSopenharmony_ci
222a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
223a8c51b3fSopenharmony_cibool ParseInt32Flag(const char* str, const char* flag, int32_t* value) {
224a8c51b3fSopenharmony_ci  // Gets the value of the flag as a string.
225a8c51b3fSopenharmony_ci  const char* const value_str = ParseFlagValue(str, flag, false);
226a8c51b3fSopenharmony_ci
227a8c51b3fSopenharmony_ci  // Aborts if the parsing failed.
228a8c51b3fSopenharmony_ci  if (value_str == nullptr) return false;
229a8c51b3fSopenharmony_ci
230a8c51b3fSopenharmony_ci  // Sets *value to the value of the flag.
231a8c51b3fSopenharmony_ci  return ParseInt32(std::string("The value of flag --") + flag, value_str,
232a8c51b3fSopenharmony_ci                    value);
233a8c51b3fSopenharmony_ci}
234a8c51b3fSopenharmony_ci
235a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
236a8c51b3fSopenharmony_cibool ParseDoubleFlag(const char* str, const char* flag, double* value) {
237a8c51b3fSopenharmony_ci  // Gets the value of the flag as a string.
238a8c51b3fSopenharmony_ci  const char* const value_str = ParseFlagValue(str, flag, false);
239a8c51b3fSopenharmony_ci
240a8c51b3fSopenharmony_ci  // Aborts if the parsing failed.
241a8c51b3fSopenharmony_ci  if (value_str == nullptr) return false;
242a8c51b3fSopenharmony_ci
243a8c51b3fSopenharmony_ci  // Sets *value to the value of the flag.
244a8c51b3fSopenharmony_ci  return ParseDouble(std::string("The value of flag --") + flag, value_str,
245a8c51b3fSopenharmony_ci                     value);
246a8c51b3fSopenharmony_ci}
247a8c51b3fSopenharmony_ci
248a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
249a8c51b3fSopenharmony_cibool ParseStringFlag(const char* str, const char* flag, std::string* value) {
250a8c51b3fSopenharmony_ci  // Gets the value of the flag as a string.
251a8c51b3fSopenharmony_ci  const char* const value_str = ParseFlagValue(str, flag, false);
252a8c51b3fSopenharmony_ci
253a8c51b3fSopenharmony_ci  // Aborts if the parsing failed.
254a8c51b3fSopenharmony_ci  if (value_str == nullptr) return false;
255a8c51b3fSopenharmony_ci
256a8c51b3fSopenharmony_ci  *value = value_str;
257a8c51b3fSopenharmony_ci  return true;
258a8c51b3fSopenharmony_ci}
259a8c51b3fSopenharmony_ci
260a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
261a8c51b3fSopenharmony_cibool ParseKeyValueFlag(const char* str, const char* flag,
262a8c51b3fSopenharmony_ci                       std::map<std::string, std::string>* value) {
263a8c51b3fSopenharmony_ci  const char* const value_str = ParseFlagValue(str, flag, false);
264a8c51b3fSopenharmony_ci
265a8c51b3fSopenharmony_ci  if (value_str == nullptr) return false;
266a8c51b3fSopenharmony_ci
267a8c51b3fSopenharmony_ci  for (const auto& kvpair : StrSplit(value_str, ',')) {
268a8c51b3fSopenharmony_ci    const auto kv = StrSplit(kvpair, '=');
269a8c51b3fSopenharmony_ci    if (kv.size() != 2) return false;
270a8c51b3fSopenharmony_ci    value->emplace(kv[0], kv[1]);
271a8c51b3fSopenharmony_ci  }
272a8c51b3fSopenharmony_ci
273a8c51b3fSopenharmony_ci  return true;
274a8c51b3fSopenharmony_ci}
275a8c51b3fSopenharmony_ci
276a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
277a8c51b3fSopenharmony_cibool IsFlag(const char* str, const char* flag) {
278a8c51b3fSopenharmony_ci  return (ParseFlagValue(str, flag, true) != nullptr);
279a8c51b3fSopenharmony_ci}
280a8c51b3fSopenharmony_ci
281a8c51b3fSopenharmony_ciBENCHMARK_EXPORT
282a8c51b3fSopenharmony_cibool IsTruthyFlagValue(const std::string& value) {
283a8c51b3fSopenharmony_ci  if (value.size() == 1) {
284a8c51b3fSopenharmony_ci    char v = value[0];
285a8c51b3fSopenharmony_ci    return isalnum(v) &&
286a8c51b3fSopenharmony_ci           !(v == '0' || v == 'f' || v == 'F' || v == 'n' || v == 'N');
287a8c51b3fSopenharmony_ci  }
288a8c51b3fSopenharmony_ci  if (!value.empty()) {
289a8c51b3fSopenharmony_ci    std::string value_lower(value);
290a8c51b3fSopenharmony_ci    std::transform(value_lower.begin(), value_lower.end(), value_lower.begin(),
291a8c51b3fSopenharmony_ci                   [](char c) { return static_cast<char>(::tolower(c)); });
292a8c51b3fSopenharmony_ci    return !(value_lower == "false" || value_lower == "no" ||
293a8c51b3fSopenharmony_ci             value_lower == "off");
294a8c51b3fSopenharmony_ci  }
295a8c51b3fSopenharmony_ci  return true;
296a8c51b3fSopenharmony_ci}
297a8c51b3fSopenharmony_ci
298a8c51b3fSopenharmony_ci}  // end namespace benchmark
299