Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Options.cpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2021 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#include "Options.hpp"
18
19#include <toolbox/util/Argv.hpp>
21
22#include <iostream>
23
24namespace toolbox {
25inline namespace util {
26using namespace std;
27
28Options::Options(string description)
29: description_{std::move(description)}
30{
31}
32
33bool Options::operator[](const string& long_opt) const noexcept
34{
35 return opts_.count(long_opt);
36}
37
38bool Options::operator[](char short_opt) const noexcept
39{
40 return opts_.count(std::string_view{&short_opt, 1});
41}
42
43void Options::parse(int argc, const char* const argv[])
44{
45 size_t positional_idx{0};
46 ArgvLexer lex{argc - 1, argv + 1};
47 while (!lex.empty()) {
48 const auto opt = lex.opt();
49
50 bool positional{false};
51 OptsMap::iterator it{opts_.end()};
52
53 if (!opt.empty()) {
54 it = opts_.find(opt);
55 } else {
56 if (positional_idx >= positional_.size()) {
57 throw runtime_error{"unexpected argument: " + string{lex.arg()}};
58 }
59 positional = true;
60 }
61
62 if (!positional && it == opts_.end()) {
63 throw runtime_error{"unknown option: " + string{opt}};
64 }
65
66 auto& data = positional ? positional_[positional_idx++] : it->second->data;
67
68 visit(overloaded{[&](const Help& /*arg*/) {
69 lex.pop_switch();
70 cout << *this << "\n";
71 exit(0);
72 },
73 [&](Switch& arg) {
74 lex.pop_switch();
75 arg.run();
76 },
77 [&](Value& arg) {
78 const auto val = lex.pop_value();
79 if (arg.set_ && !arg.multitoken_) {
80 throw runtime_error{"duplicate option: " + string{opt}};
81 }
82 arg.run(val);
83 },
84 [&](const NoOp&) { lex.pop(); }},
85 data);
86 }
87
88 // Ensure all required parameters have been set.
89 // FIXME: but we're not checking required positional arguments?
90 for (const auto& data : opts_) {
91 visit(overloaded{[](const auto& /*def*/) {},
92 [&](const Value& arg) {
93 if (arg.presence() == Value::Required && !arg.set()) {
94 throw runtime_error{"missing required option: "
95 + data.second->opt()};
96 }
97 }},
98 data.second->data);
99 }
100 for (const auto& data : positional_) {
101 visit(overloaded{[](const auto& /*def*/) {},
102 [&](const Value& arg) {
103 if (arg.presence() == Value::Required && !arg.set()) {
104 throw runtime_error{"missing positional argument"};
105 }
106 }},
107 data);
108 }
109}
110
111} // namespace util
112} // namespace toolbox
Command-line options parser.
std::string_view opt() const noexcept
Definition Argv.hpp:84
void parse(int argc, const char *const argv[])
Definition Options.cpp:43
Options(std::string description="")
Definition Options.cpp:28
bool operator[](const std::string &long_opt) const noexcept
Definition Options.cpp:33
STL namespace.
const DataT & data(const MsgEvent &ev) noexcept
Definition Event.hpp:54
constexpr auto bind() noexcept
Definition Slot.hpp:92