Electroneum
command_line.h
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 // Copyrights(c) 2014-2019, The Monero Project
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31 
32 #pragma once
33 
34 #include <functional>
35 #include <iostream>
36 #include <sstream>
37 #include <array>
38 #include <type_traits>
39 
40 #include <boost/program_options/parsers.hpp>
41 #include <boost/program_options/options_description.hpp>
42 #include <boost/program_options/variables_map.hpp>
43 #include "include_base_utils.h"
44 
45 namespace command_line
46 {
47 
49  bool is_yes(const std::string& str);
51  bool is_no(const std::string& str);
52 
53  template<typename T, bool required = false, bool dependent = false, int NUM_DEPS = 1>
55 
56  template<typename T>
58  {
59  typedef T value_type;
60 
61  const char* name;
62  const char* description;
65  };
66 
67  template<typename T>
68  struct arg_descriptor<std::vector<T>, false>
69  {
70  typedef std::vector<T> value_type;
71 
72  const char* name;
73  const char* description;
74  };
75 
76  template<typename T>
78  {
79  static_assert(!std::is_same<T, bool>::value, "Boolean switch can't be required");
80 
81  typedef T value_type;
82 
83  const char* name;
84  const char* description;
85  };
86 
87  template<typename T>
89  {
90  typedef T value_type;
91 
92  const char* name;
93  const char* description;
94 
96 
98  std::function<T(bool, bool, T)> depf;
99 
101  };
102 
103  template<typename T, int NUM_DEPS>
104  struct arg_descriptor<T, false, true, NUM_DEPS>
105  {
106  typedef T value_type;
107 
108  const char* name;
109  const char* description;
110 
112 
113  std::array<const arg_descriptor<bool, false> *, NUM_DEPS> ref;
114  std::function<T(std::array<bool, NUM_DEPS>, bool, T)> depf;
115 
117  };
118 
119  template<typename T>
120  boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/)
121  {
122  return boost::program_options::value<T>()->required();
123  }
124 
125  template<typename T>
126  boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg)
127  {
128  auto semantic = boost::program_options::value<T>();
129  if (!arg.not_use_default)
130  semantic->default_value(arg.default_value);
131  return semantic;
132  }
133 
134  template<typename T>
135  boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false, true>& arg)
136  {
137  auto semantic = boost::program_options::value<T>();
138  if (!arg.not_use_default) {
139  std::ostringstream format;
140  format << arg.depf(false, true, arg.default_value) << ", "
141  << arg.depf(true, true, arg.default_value) << " if '"
142  << arg.ref.name << "'";
143  semantic->default_value(arg.depf(arg.ref.default_value, true, arg.default_value), format.str());
144  }
145  return semantic;
146  }
147 
148  template<typename T, int NUM_DEPS>
149  boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false, true, NUM_DEPS>& arg)
150  {
151  auto semantic = boost::program_options::value<T>();
152  if (!arg.not_use_default) {
153  std::array<bool, NUM_DEPS> depval;
154  depval.fill(false);
155  std::ostringstream format;
156  format << arg.depf(depval, true, arg.default_value);
157  for (size_t i = 0; i < depval.size(); ++i)
158  {
159  depval.fill(false);
160  depval[i] = true;
161  format << ", " << arg.depf(depval, true, arg.default_value) << " if '" << arg.ref[i]->name << "'";
162  }
163  for (size_t i = 0; i < depval.size(); ++i)
164  depval[i] = arg.ref[i]->default_value;
165  semantic->default_value(arg.depf(depval, true, arg.default_value), format.str());
166  }
167  return semantic;
168  }
169 
170  template<typename T>
171  boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def)
172  {
173  auto semantic = boost::program_options::value<T>();
174  if (!arg.not_use_default)
175  semantic->default_value(def);
176  return semantic;
177  }
178 
179  template<typename T>
180  boost::program_options::typed_value<std::vector<T>, char>* make_semantic(const arg_descriptor<std::vector<T>, false>& /*arg*/)
181  {
182  auto semantic = boost::program_options::value< std::vector<T> >();
183  semantic->default_value(std::vector<T>(), "");
184  return semantic;
185  }
186 
187  template<typename T, bool required, bool dependent, int NUM_DEPS>
188  void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg, bool unique = true)
189  {
190  if (0 != description.find_nothrow(arg.name, false))
191  {
192  CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
193  return;
194  }
195 
196  description.add_options()(arg.name, make_semantic(arg), arg.description);
197  }
198 
199  template<typename T>
200  void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, false>& arg, const T& def, bool unique = true)
201  {
202  if (0 != description.find_nothrow(arg.name, false))
203  {
204  CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
205  return;
206  }
207 
208  description.add_options()(arg.name, make_semantic(arg, def), arg.description);
209  }
210 
211  template<>
212  inline void add_arg(boost::program_options::options_description& description, const arg_descriptor<bool, false>& arg, bool unique)
213  {
214  if (0 != description.find_nothrow(arg.name, false))
215  {
216  CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
217  return;
218  }
219 
220  description.add_options()(arg.name, boost::program_options::bool_switch(), arg.description);
221  }
222 
223  template<typename charT>
224  boost::program_options::basic_parsed_options<charT> parse_command_line(int argc, const charT* const argv[],
225  const boost::program_options::options_description& desc, bool allow_unregistered = false)
226  {
227  auto parser = boost::program_options::command_line_parser(argc, argv);
228  parser.options(desc);
229  if (allow_unregistered)
230  {
231  parser.allow_unregistered();
232  }
233  return parser.run();
234  }
235 
236  template<typename F>
237  bool handle_error_helper(const boost::program_options::options_description& desc, F parser)
238  {
239  try
240  {
241  return parser();
242  }
243  catch (const std::exception& e)
244  {
245  std::cerr << "Failed to parse arguments: " << e.what() << std::endl;
246  std::cerr << desc << std::endl;
247  return false;
248  }
249  catch (...)
250  {
251  std::cerr << "Failed to parse arguments: unknown exception" << std::endl;
252  std::cerr << desc << std::endl;
253  return false;
254  }
255  }
256 
257  template<typename T, bool required, bool dependent, int NUM_DEPS>
258  typename std::enable_if<!std::is_same<T, bool>::value, bool>::type has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg)
259  {
260  auto value = vm[arg.name];
261  return !value.empty();
262  }
263 
264  template<typename T, bool required, bool dependent, int NUM_DEPS>
265  bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg)
266  {
267  return vm[arg.name].defaulted();
268  }
269 
270  template<typename T>
271  T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, false, true>& arg)
272  {
273  return arg.depf(get_arg(vm, arg.ref), is_arg_defaulted(vm, arg), vm[arg.name].template as<T>());
274  }
275 
276  template<typename T, int NUM_DEPS>
277  T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, false, true, NUM_DEPS>& arg)
278  {
279  std::array<bool, NUM_DEPS> depval;
280  for (size_t i = 0; i < depval.size(); ++i)
281  depval[i] = get_arg(vm, *arg.ref[i]);
282  return arg.depf(depval, is_arg_defaulted(vm, arg), vm[arg.name].template as<T>());
283  }
284 
285  template<typename T, bool required>
286  T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
287  {
288  return vm[arg.name].template as<T>();
289  }
290 
291  template<bool dependent, int NUM_DEPS>
292  inline bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false, dependent, NUM_DEPS>& arg)
293  {
294  return get_arg(vm, arg);
295  }
296 
297 
298  extern const arg_descriptor<bool> arg_help;
299  extern const arg_descriptor<bool> arg_version;
300 }
bool is_no(const std::string &str)
const uint32_t T[512]
::std::string string
Definition: gtest-port.h:1097
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
bool is_yes(const std::string &str)
STL namespace.
const arg_descriptor< bool > arg_help
std::array< const arg_descriptor< bool, false > *, NUM_DEPS > ref
Definition: command_line.h:113
return true
std::function< T(bool, bool, T)> depf
Definition: command_line.h:98
bool handle_error_helper(const boost::program_options::options_description &desc, F parser)
Definition: command_line.h:237
std::enable_if<!std::is_same< T, bool >::value, bool >::type has_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
Definition: command_line.h:258
boost::program_options::typed_value< T, char > * make_semantic(const arg_descriptor< T, true > &)
Definition: command_line.h:120
const arg_descriptor< bool, false > & ref
Definition: command_line.h:97
#define false
Definition: stdbool.h:38
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
Definition: command_line.h:188
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
Definition: command_line.h:271
boost::program_options::basic_parsed_options< charT > parse_command_line(int argc, const charT *const argv[], const boost::program_options::options_description &desc, bool allow_unregistered=false)
Definition: command_line.h:224
int bool
Definition: stdbool.h:36
#define F(s)
const arg_descriptor< bool > arg_version
bool is_arg_defaulted(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
Definition: command_line.h:265
std::function< T(std::array< bool, NUM_DEPS >, bool, T)> depf
Definition: command_line.h:114