cepgen
is hosted by
Hepforge
,
IPPP Durham
CepGen
1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
ArgumentsParser.cpp
Go to the documentation of this file.
1
/*
2
* CepGen: a central exclusive processes event generator
3
* Copyright (C) 2019-2023 Laurent Forthomme
4
*
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <strings.h>
20
21
#include <algorithm>
22
#include <fstream>
23
#include <sstream>
24
25
#include "
CepGen/Core/Exception.h
"
26
#include "
CepGen/Utils/ArgumentsParser.h
"
27
#include "
CepGen/Utils/String.h
"
28
#include "
CepGen/Version.h
"
29
30
namespace
cepgen
{
31
ArgumentsParser::ArgumentsParser
(
int
argc,
char
* argv[])
32
: command_name_(argc > 0 ? argv[0] :
""
),
33
help_str_({{
"help,h"
}}),
34
version_str_({{
"version,v"
}}),
35
config_str_({{
"cmd,c"
}}),
36
debug_str_({{
"debug,d"
}}) {
37
//--- first remove the program name
38
std::vector<std::string> args_tmp;
39
if
(argc > 1) {
40
args_tmp.resize(argc - 1);
41
std::copy(argv + 1, argv + argc, args_tmp.begin());
42
}
43
//--- then loop on user arguments to identify word -> value pairs
44
for
(
auto
it_arg = args_tmp.begin(); it_arg != args_tmp.end(); ++it_arg) {
45
auto
arg_val =
utils::split
(*it_arg,
'='
);
// particular case for --arg=value
46
//--- check if help message is requested
47
for
(
const
auto
& str : help_str_)
48
if (arg_val.at(0) ==
"--"
+ str.name.at(0) || (str.name.size() > 1 && arg_val.at(0) ==
"-"
+ str.name.at(1)))
49
help_req_ = true;
50
//--- check if version message is requested
51
for
(
const
auto
& str : version_str_)
52
if (arg_val.at(0) ==
"--"
+ str.name.at(0) || (str.name.size() > 1 && arg_val.at(0) ==
"-"
+ str.name.at(1)))
53
version_req_ = true;
54
//--- check if debugging is requested
55
for
(
const
auto
& str : debug_str_)
56
if (arg_val.at(0) ==
"--"
+ str.name.at(0) || (str.name.size() > 1 && arg_val.at(0) ==
"-"
+ str.name.at(1))) {
57
CG_LOG_LEVEL
(debug);
58
if
(arg_val.size() > 1) {
59
const
auto
& token = arg_val.at(1);
60
if
(token.find(
":"
) == std::string::npos)
61
utils::Logger::get
().
output
().reset(
new
std::ofstream(token));
62
else
{
63
const
auto
tokens =
utils::split
(token,
':'
);
64
utils::Logger::get
().
output
().reset(
new
std::ofstream(tokens.at(1)));
65
for
(
const
auto
& tok : utils::
split
(tokens.at(0),
';'
))
66
utils::Logger::
get
().addExceptionRule(tok);
67
}
68
}
69
debug_req_ =
true
;
70
}
71
//--- check if configuration word is requested
72
auto
it = std::find_if(config_str_.begin(), config_str_.end(), [&arg_val](
const
auto
& str) {
73
return (arg_val.at(0) ==
"--"
+ str.name.at(0) ||
74
(str.name.size() > 1 && arg_val.at(0) ==
"-"
+ str.name.at(1)));
75
});
76
if
(it != config_str_.end()) {
77
// if a configuration word is found, all the remaining flags are parsed as such
78
extra_config_ = std::vector<std::string>(it_arg + 1, args_tmp.end());
79
break
;
80
}
81
//--- parse arguments if word found after
82
if
(arg_val.size() == 1 && arg_val.at(0)[0] ==
'-'
&& it_arg != std::prev(args_tmp.end())) {
83
const
auto
& word = *std::next(it_arg);
84
if
(word[0] !=
'-'
) {
85
arg_val.emplace_back(*std::next(it_arg));
86
++it_arg;
87
}
88
}
89
args_.emplace_back(std::make_pair(arg_val.at(0), arg_val.size() > 1 ? arg_val.at(1) :
""
));
90
}
91
}
92
93
void
ArgumentsParser::print_help
()
const
{
CG_LOG
<<
help_message
(); }
94
95
void
ArgumentsParser::print_version
()
const
{
CG_LOG
<<
cepgen::version::banner
; }
96
97
void
ArgumentsParser::dump
()
const
{
98
CG_INFO
(
"ArgumentsParser"
).log([&](
auto
& info) {
99
info <<
"List of parameters retrieved from command-line:"
;
100
for
(
const
auto
& par : params_)
101
info <<
"\n\t[--"
<< par.name.at(0) << (par.name.size() > 1 ?
"|-"
+ par.name.at(1) :
""
)
102
<< (par.optional ?
", optional"
:
""
) <<
"] = "
<< par.value;
103
});
104
}
105
106
ArgumentsParser
&
ArgumentsParser::parse
() {
107
if
(help_req_) {
108
print_help
();
109
exit(0);
110
}
111
//--- dump the generator version
112
if
(version_req_) {
113
print_version
();
114
exit(0);
115
}
116
if
(debug_req_)
117
CG_DEBUG
(
"ArgumentsParser"
) <<
"Debugging mode enabled."
;
118
//--- loop over all parameters
119
size_t
i = 0;
120
for
(
auto
& par : params_) {
121
if
(par.name.empty()) {
122
//--- no argument name ; fetching by index
123
if
(i >= args_.size())
124
throw
CG_FATAL
(
"ArgumentsParser"
) <<
help_message
() <<
" Failed to retrieve required <arg"
<< i <<
">."
;
125
par.value = !par.boolean() ? args_.at(i).second :
"1"
;
126
}
else
{
127
// for each parameter, loop over arguments to find correspondence
128
auto
it = std::find_if(args_.begin(), args_.end(), [&i, &par](
const
auto
& arg) {
129
if (arg.first !=
"--"
+ par.name.at(0) && (par.name.size() < 2 || arg.first !=
"-"
+ par.name.at(1)))
130
return false;
131
par.value = arg.second;
132
if (par.boolean()) {
// all particular cases for boolean arguments
133
const auto word = utils::toLower(arg.second);
134
if (word.empty() || word ==
"1"
|| word ==
"on"
|| word ==
"yes"
|| word ==
"true"
)
135
par.value =
"1"
;
// if the flag is set, enabled by default
136
else
137
par.value =
"0"
;
138
}
139
++i;
140
return
true
;
141
});
142
if
(it == args_.end()) {
143
if
(args_.size() > i && args_.at(i).first[0] !=
'-'
)
144
par.value = args_.at(i).first;
145
else
if
(!par.optional)
// no match
146
throw
CG_FATAL
(
"ArgumentsParser"
)
147
<<
help_message
() <<
" The following parameter was not set: '"
<< par.name.at(0) <<
"'."
;
148
}
149
}
150
par.parse();
151
CG_DEBUG
(
"ArgumentsParser"
) <<
"Parameter '"
<< i <<
"|--"
<< par.name.at(0)
152
<< (par.name.size() > 1 ?
"|-"
+ par.name.at(1) :
""
) <<
"'"
153
<<
" has value '"
<< par.value <<
"'."
;
154
++i;
155
}
156
return
*
this
;
157
}
158
159
std::string ArgumentsParser::operator[](std::string name)
const
{
160
for
(
const
auto
& par : params_) {
161
if
(
"--"
+ par.name.at(0) == name)
162
return
par.value;
163
if
(par.name.size() > 1 &&
"-"
+ par.name.at(1) == name)
164
return
par.value;
165
}
166
throw
CG_FATAL
(
"ArgumentsParser"
) <<
"The parameter \""
<< name <<
"\" was not declared "
167
<<
"in the arguments parser constructor!"
;
168
}
169
170
std::string ArgumentsParser::help_message()
const
{
171
std::ostringstream oss;
172
std::vector<std::pair<Parameter, size_t> > req_params, opt_params;
173
oss <<
"Usage: "
<< command_name_;
174
size_t
i = 0;
175
for
(
const
auto
& par : params_) {
176
if
(par.optional) {
177
opt_params.emplace_back(std::make_pair(par, i));
178
oss <<
" ["
;
179
}
else
{
180
req_params.emplace_back(std::make_pair(par, i));
181
oss <<
" "
;
182
}
183
oss << (!par.name.at(0).empty() ?
"--"
:
" <arg"
+ std::to_string(i) +
">"
) << par.name.at(0);
184
if
(par.name.size() > 1)
185
oss << (!par.name.at(0).empty() ?
"|"
:
""
) <<
"-"
<< par.name.at(1);
186
if
(par.optional)
187
oss <<
"]"
;
188
++i;
189
}
190
if
(req_params.size() > 0) {
191
oss <<
"\n "
<< utils::s(
"required argument"
, req_params.size(),
false
) <<
":"
;
192
for
(
const
auto
& par : req_params)
193
oss << utils::format(
194
"\n\t%s%-18s\t%-30s"
,
195
(par.first.name.size() > 1 ?
"-"
+ par.first.name.at(1) +
"|"
:
""
).c_str(),
196
(!par.first.name.at(0).empty() ?
"--"
+ par.first.name.at(0) :
"<arg"
+ std::to_string(par.second) +
">"
)
197
.c_str(),
198
par.first.description.c_str());
199
}
200
if
(opt_params.size() > 0) {
201
oss <<
"\n "
<< utils::s(
"optional argument"
, opt_params.size(),
false
) <<
":"
;
202
for
(
const
auto
& par : opt_params)
203
oss << utils::format(
204
"\n\t%s%-18s\t%-30s\tdef: '%s'"
,
205
(par.first.name.size() > 1 ?
"-"
+ par.first.name.at(1) +
"|"
:
""
).c_str(),
206
(!par.first.name.at(0).empty() ?
"--"
+ par.first.name.at(0) :
"<arg"
+ std::to_string(par.second) +
">"
)
207
.c_str(),
208
par.first.description.c_str(),
209
par.first.value.c_str());
210
}
211
oss <<
"\n "
212
<<
"debugging:\n\t-d|--debug<=output file|=mod1,mod2,...:output file>\tredirect to output file, enable "
213
"module(s)"
;
214
oss << std::endl;
215
return
oss.str();
216
}
217
218
//----- simple parameters
219
220
ArgumentsParser::Parameter::Parameter(std::string pname, std::string pdesc, std::string* var, std::string def)
221
: name(utils::split(pname,
','
)), description(pdesc), value(def), str_variable_(var) {}
222
223
ArgumentsParser::Parameter::Parameter(std::string pname, std::string pdesc,
double
* var,
double
def)
224
: name(utils::split(pname,
','
)), description(pdesc), value(utils::format(
"%g"
, def)), float_variable_(var) {}
225
226
ArgumentsParser::Parameter::Parameter(std::string pname, std::string pdesc,
int
* var,
int
def)
227
: name(utils::
split
(pname,
','
)), description(pdesc), value(utils::
format
(
"%+i"
, def)), int_variable_(var) {}
228
229
ArgumentsParser::Parameter::Parameter(std::string pname, std::string pdesc,
unsigned
int
* var,
unsigned
int
def)
230
: name(utils::
split
(pname,
','
)), description(pdesc), value(std::to_string(def)), uint_variable_(var) {}
231
232
ArgumentsParser::Parameter::Parameter(std::string pname, std::string pdesc,
bool
* var,
bool
def)
233
: name(utils::
split
(pname,
','
)), description(pdesc), value(utils::
format
(
"%d"
, def)), bool_variable_(var) {}
234
235
ArgumentsParser::Parameter::Parameter(std::string pname, std::string pdesc, Limits* var, Limits def)
236
: name(utils::
split
(pname,
','
)),
237
description(pdesc),
238
value(utils::
format
(
"%g,%g"
, def.min(), def.max())),
239
lim_variable_(var) {}
240
241
//----- vector of parameters
242
243
ArgumentsParser::Parameter::Parameter(std::string pname,
244
std::string pdesc,
245
std::vector<std::string>* var,
246
std::vector<std::string> def)
247
: name(utils::
split
(pname,
','
)), description(pdesc), value(utils::
merge
(def,
";"
)), vec_str_variable_(var) {}
248
249
ArgumentsParser::Parameter::Parameter(std::string pname,
250
std::string pdesc,
251
std::vector<int>* var,
252
std::vector<int> def)
253
: name(utils::
split
(pname,
','
)), description(pdesc), value(utils::
merge
(def,
";"
)), vec_int_variable_(var) {}
254
255
ArgumentsParser::Parameter::Parameter(std::string pname,
256
std::string pdesc,
257
std::vector<double>* var,
258
std::vector<double> def)
259
: name(utils::
split
(pname,
','
)), description(pdesc), value(utils::
merge
(def,
";"
)), vec_float_variable_(var) {}
260
261
bool
ArgumentsParser::Parameter::matches(
const
std::string& key)
const
{
262
if
(key ==
"--"
+ name.at(0))
263
return
true
;
264
if
(name.size() > 1 && key ==
"-"
+ name.at(1))
265
return
true
;
266
return
false
;
267
}
268
269
ArgumentsParser::Parameter& ArgumentsParser::Parameter::parse() {
270
CG_DEBUG
(
"ArgumentsParser:Parameter:parse"
) <<
"Parsing argument "
<< name <<
"."
;
271
if
(str_variable_) {
272
*str_variable_ = value;
273
return
*
this
;
274
}
275
if
(float_variable_)
276
try
{
277
*float_variable_ = std::stod(value);
278
return
*
this
;
279
}
catch
(
const
std::invalid_argument&) {
280
throw
CG_FATAL
(
"ArgumentsParser:Parameter:parse"
) <<
"Failed to parse variable '"
<< name <<
"' as float!"
;
281
}
282
if
(int_variable_)
283
try
{
284
*int_variable_ = std::stoi(value);
285
return
*
this
;
286
}
catch
(
const
std::invalid_argument&) {
287
throw
CG_FATAL
(
"ArgumentsParser:Parameter:parse"
) <<
"Failed to parse variable '"
<< name <<
"' as integer!"
;
288
}
289
if
(uint_variable_)
290
try
{
291
*uint_variable_ = std::stoi(value);
292
return
*
this
;
293
}
catch
(
const
std::invalid_argument&) {
294
throw
CG_FATAL
(
"ArgumentsParser:Parameter:parse"
)
295
<<
"Failed to parse variable '"
<< name <<
"' as unsigned integer!"
;
296
}
297
if
(bool_variable_) {
298
try
{
299
*bool_variable_ = (std::stoi(value) != 0);
300
return
*
this
;
301
}
catch
(
const
std::invalid_argument&) {
302
*bool_variable_ = (strcasecmp(
"true"
, value.c_str()) == 0 || strcasecmp(
"yes"
, value.c_str()) == 0 ||
303
strcasecmp(
"on"
, value.c_str()) == 0 || strcasecmp(
"1"
, value.c_str()) == 0) &&
304
strcasecmp(
"false"
, value.c_str()) != 0 && strcasecmp(
"no"
, value.c_str()) != 0 &&
305
strcasecmp(
"off"
, value.c_str()) != 0 && strcasecmp(
"0"
, value.c_str()) != 0;
306
}
307
}
308
if
(vec_str_variable_) {
309
*vec_str_variable_ =
utils::split
(value,
';'
,
true
);
310
return
*
this
;
311
}
312
if
(vec_int_variable_) {
313
vec_int_variable_->clear();
314
const
auto
buf =
utils::split
(value,
';'
);
315
std::transform(buf.begin(), buf.end(), std::back_inserter(*vec_int_variable_), [](
const
std::string& str) {
316
return std::stoi(str);
317
});
318
return
*
this
;
319
}
320
auto
unpack_floats = [](
const
std::string& value,
char
delim) {
321
std::vector<double> vec_flt;
322
const
auto
buf =
utils::split
(value, delim);
323
std::transform(buf.begin(), buf.end(), std::back_inserter(vec_flt), [](
const
std::string& str) {
324
try {
325
return std::stod(str);
326
} catch (
const
std::invalid_argument&) {
327
return
Limits::INVALID
;
328
}
329
});
330
return
vec_flt;
331
};
332
if
(vec_float_variable_) {
333
*vec_float_variable_ = unpack_floats(value,
';'
);
334
return
*
this
;
335
}
336
if
(lim_variable_) {
337
const
auto
vec_flt = unpack_floats(value,
','
);
338
if
(vec_flt.size() == 2) {
339
if
(vec_flt.at(0) !=
Limits::INVALID
)
340
lim_variable_->min() = vec_flt.at(0);
341
if
(vec_flt.at(1) !=
Limits::INVALID
)
342
lim_variable_->max() = vec_flt.at(1);
343
}
344
return
*
this
;
345
}
346
throw
CG_FATAL
(
"Parameter"
) <<
"Failed to parse parameter \""
<< name.at(0) <<
"\"!"
;
347
}
348
}
// namespace cepgen
ArgumentsParser.h
Exception.h
CG_FATAL
#define CG_FATAL(mod)
Definition
Exception.h:61
CG_LOG_LEVEL
#define CG_LOG_LEVEL(type)
Definition
Logger.h:83
CG_LOG
#define CG_LOG
Definition
Message.h:212
CG_DEBUG
#define CG_DEBUG(mod)
Definition
Message.h:220
CG_INFO
#define CG_INFO(mod)
Definition
Message.h:216
String.h
Version.h
cepgen::ArgumentsParser
A generic command line arguments parser.
Definition
ArgumentsParser.h:31
cepgen::ArgumentsParser::print_version
void print_version() const
Show version.
Definition
ArgumentsParser.cpp:95
cepgen::ArgumentsParser::ArgumentsParser
ArgumentsParser(int argc, char *argv[])
Arguments parser constructor.
Definition
ArgumentsParser.cpp:31
cepgen::ArgumentsParser::parse
ArgumentsParser & parse()
Associate command-line arguments to parameters.
Definition
ArgumentsParser.cpp:106
cepgen::ArgumentsParser::print_help
void print_help() const
Show usage.
Definition
ArgumentsParser.cpp:93
cepgen::ArgumentsParser::help_message
std::string help_message() const
Usage message.
Definition
ArgumentsParser.cpp:170
cepgen::ArgumentsParser::dump
void dump() const
Dump the list of arguments into the terminal.
Definition
ArgumentsParser.cpp:97
cepgen::Limits::INVALID
static constexpr double INVALID
Invalid value placeholder (single-edged or invalid limits)
Definition
Limits.h:86
cepgen::utils::Logger::get
static Logger & get(std::ostream *=nullptr)
Retrieve the running instance of the logger.
Definition
Logger.cpp:31
cepgen::utils::Logger::output
StreamHandler & output()
Output stream to use for all logging operations.
Definition
Logger.cpp:58
cepgen::utils::env::get
std::string get(const std::string &var, const std::string &def)
Get an environment variable.
Definition
Environment.cpp:28
cepgen::utils::format
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition
String.h:61
cepgen::utils::merge
std::string merge(const std::vector< T > &vec, const std::string &delim)
Merge a collection of a printable type in a single string.
Definition
String.cpp:248
cepgen::utils::split
std::vector< std::string > split(const std::string &str, char delim, bool trim)
Split a string according to a separation character.
Definition
String.cpp:233
cepgen
Common namespace for this Monte Carlo generator.
Definition
CommandLineHandler.cpp:36
cepgen::version::banner
static const std::string banner
CepGen banner.
Definition
Version.h:32
CepGen
Utils
ArgumentsParser.cpp
Generated on Mon Jul 29 2024 for CepGen by
1.9.7