Electroneum
Loading...
Searching...
No Matches
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
45namespace 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}
#define F(s)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
const arg_descriptor< bool > arg_help
bool is_no(const std::string &str)
const arg_descriptor< bool > arg_version
bool is_yes(const std::string &str)
boost::program_options::typed_value< T, char > * make_semantic(const arg_descriptor< T, true > &)
bool is_arg_defaulted(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
bool handle_error_helper(const boost::program_options::options_description &desc, F parser)
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)
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)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
STL namespace.
const GenericPointer< typename T::ValueType > T2 value
Definition pointer.h:1225
#define true
#define false
std::array< const arg_descriptor< bool, false > *, NUM_DEPS > ref
std::function< T(std::array< bool, NUM_DEPS >, bool, T)> depf
const arg_descriptor< bool, false > & ref
std::function< T(bool, bool, T)> depf
#define T(x)