13#include "arccore/common/internal/ProgramOptions.h"
20namespace Arcane::ProgramOptions
30 _parseNameString(
const std::string& name_str, std::string& long_name,
31 std::string& short_name,
bool& has_short)
33 auto pos = name_str.find(
',');
34 if (pos != std::string::npos) {
35 long_name = name_str.substr(0, pos);
36 short_name = name_str.substr(pos + 1);
51options_description(
const std::string& title)
58options_description::options_proxy options_description::
61 return options_proxy(*
this);
67void options_description::
68add_option(
const std::string& name,
69 std::shared_ptr<option_value> value_semantic,
70 const std::string& description)
72 option_descriptor opt;
73 _parseNameString(name, opt.long_name, opt.short_name, opt.has_short);
74 opt.description = description;
75 opt.value_semantic = std::move(value_semantic);
76 m_options.push_back(std::move(opt));
82const option_descriptor* options_description::
83find(
const std::string& name)
const
85 for (
const auto& opt : m_options) {
86 if (opt.long_name == name)
95const option_descriptor* options_description::
96find_by_short(
char short_name)
const
98 for (
const auto& opt : m_options) {
99 if (opt.has_short && !opt.short_name.empty() && opt.short_name[0] == short_name)
108options_description::options_proxy& options_description::options_proxy::
109operator()(
const char* name,
const char* description)
111 m_desc.add_option(name, std::make_shared<untyped_value>(), description);
118options_description::options_proxy& options_description::options_proxy::
119operator()(
const char* name,
120 const typed_value<bool>* value,
121 const char* description)
123 m_desc.add_option(name,
124 std::shared_ptr<option_value>(
const_cast<typed_value<bool>*
>(value)),
132options_description::options_proxy& options_description::options_proxy::
133operator()(
const char* name,
134 const typed_value<bool>* value)
136 m_desc.add_option(name,
137 std::shared_ptr<option_value>(
const_cast<typed_value<bool>*
>(value)),
146operator<<(std::ostream& os,
const options_description& desc)
148 if (!desc.m_title.empty())
149 os << desc.m_title <<
":\n";
151 for (
const auto& opt : desc.m_options) {
154 if (opt.has_short && !opt.short_name.empty()) {
155 if (opt.short_name.size() == 1 && std::isalnum(
static_cast<unsigned char>(opt.short_name[0])))
156 os <<
"-" << opt.short_name <<
" ";
158 os <<
"--" << opt.short_name <<
" ";
161 os <<
"[--" << opt.long_name;
163 if (opt.value_semantic && !opt.value_semantic->is_bool_switch())
168 if (opt.value_semantic && opt.value_semantic->has_default()) {
169 auto ds = opt.value_semantic->default_string();
171 os <<
" (=" << ds <<
")";
174 if (!opt.description.empty())
175 os <<
"\t" << opt.description;
186positional_options_description& positional_options_description::
187add(
const std::string& name,
int count)
189 m_options.emplace_back(name, count);
197add(
const std::string& name, variable_value value)
199 m_values[name] = std::move(value);
206count(
const std::string& name)
const
208 return m_values.find(name) != m_values.end();
214const variables_map::variable_value& variables_map::
215operator[](
const std::string& name)
const
217 static variable_value empty_value;
218 auto it = m_values.find(name);
219 if (it != m_values.end())
228set_semantic(
const std::string& name,
229 std::shared_ptr<option_value> semantic)
231 auto it = m_values.find(name);
232 if (it != m_values.end())
233 it->second.set_semantic(std::move(semantic));
247parsed_options command_line_parser::
250 parsed_options result(m_desc);
255 std::vector<std::string> positional_args;
256 bool end_of_options =
false;
258 for (
int i = 1; i < m_argc; ++i) {
259 std::string token(m_argv[i]);
261 if (end_of_options || token.empty() || token[0] !=
'-') {
262 positional_args.push_back(token);
268 end_of_options =
true;
272 if (token.size() >= 2 && token[1] ==
'-') {
276 bool has_eq_value =
false;
278 auto eq_pos = token.find(
'=', 2);
279 if (eq_pos != std::string::npos) {
280 name = token.substr(2, eq_pos - 2);
281 value = token.substr(eq_pos + 1);
285 name = token.substr(2);
291 const auto* opt = m_desc->find(name);
292 if (!opt || !opt->value_semantic)
295 if (opt->value_semantic->is_bool_switch()) {
296 result.add_option(name, { has_eq_value ? value :
"true" });
298 else if (opt->value_semantic->is_multitoken()) {
299 std::vector<std::string> values;
301 values.push_back(value);
302 while (i + 1 < m_argc) {
303 std::string next(m_argv[i + 1]);
304 if (!next.empty() && next[0] ==
'-' && next.size() > 1)
307 values.push_back(next);
309 result.add_option(name, std::move(values));
313 result.add_option(name, { value });
315 else if (i + 1 < m_argc) {
317 result.add_option(name, { std::string(m_argv[i]) });
323 if (token.size() < 2)
326 char short_char = token[1];
327 const auto* opt = m_desc->find_by_short(short_char);
328 if (!opt || !opt->value_semantic)
331 std::string name = opt->long_name;
332 std::string inline_value;
333 bool has_inline_value = (token.size() > 2);
335 if (has_inline_value)
336 inline_value = token.substr(2);
338 if (opt->value_semantic->is_bool_switch()) {
339 result.add_option(name, {
"true" });
341 else if (opt->value_semantic->is_multitoken()) {
342 std::vector<std::string> values;
343 if (has_inline_value)
344 values.push_back(inline_value);
345 while (i + 1 < m_argc) {
346 std::string next(m_argv[i + 1]);
347 if (!next.empty() && next[0] ==
'-' && next.size() > 1)
350 values.push_back(next);
352 result.add_option(name, std::move(values));
355 if (has_inline_value) {
356 result.add_option(name, { inline_value });
358 else if (i + 1 < m_argc) {
360 result.add_option(name, { std::string(m_argv[i]) });
367 if (m_positional && !positional_args.empty()) {
369 for (
const auto& pos_opt : m_positional->options()) {
370 if (pos_idx >= positional_args.size())
373 if (pos_opt.second == -1) {
375 std::vector<std::string> remaining(positional_args.begin() + pos_idx,
376 positional_args.end());
377 result.add_option(pos_opt.first, std::move(remaining));
381 int count = pos_opt.second;
382 std::vector<std::string> values;
383 for (
int c = 0; c < count && pos_idx < positional_args.size(); ++c, ++pos_idx)
384 values.push_back(positional_args[pos_idx]);
385 result.add_option(pos_opt.first, std::move(values));
397parse_command_line(
int argc,
char** argv,
const options_description& desc)
399 command_line_parser parser(argc, argv);
400 parser.options(desc);
413void store(
const parsed_options& parsed, variables_map& vm)
416 for (
const auto& po : parsed.options()) {
417 const auto* opt_desc = parsed.description().find(po.name);
418 if (!opt_desc || !opt_desc->value_semantic)
421 const auto& semantic = opt_desc->value_semantic;
423 if (po.values.empty())
426 if (semantic->is_multitoken()) {
427 std::any value = std::make_any<std::vector<std::string>>(po.values);
428 variables_map::variable_value vv(value,
false);
429 vv.set_semantic(semantic);
430 vm.add(po.name, std::move(vv));
433 std::any value = semantic->parse(po.values[0]);
434 variables_map::variable_value vv(value,
false);
435 vv.set_semantic(semantic);
436 vm.add(po.name, std::move(vv));
441 for (
const auto& opt : parsed.description().options()) {
442 if (!vm.count(opt.long_name) && opt.value_semantic && opt.value_semantic->has_default()) {
443 std::any default_val = opt.value_semantic->default_value_any();
444 variables_map::variable_value vv(default_val,
true);
445 vv.set_semantic(opt.value_semantic);
446 vm.add(opt.long_name, std::move(vv));
459void notify(variables_map& vm)
461 for (
auto& [name, val] : vm) {
464 if (
auto semantic = val.semantic())
465 semantic->assign_bound(val.value_ref());
std::ostream & operator<<(std::ostream &ostr, eItemKind item_kind)
Output operator for a stream.