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 <iomanip>
23#include <iostream>
24
25namespace toolbox {
26inline namespace util {
27using namespace std;
28
29Options::Options(string description)
30: description_{std::move(description)}
31{
32}
33
34bool Options::operator[](const string& long_opt) const noexcept
35{
36 return opts_.count(long_opt);
37}
38
39bool Options::operator[](char short_opt) const noexcept
40{
41 return opts_.count(std::string_view{&short_opt, 1});
42}
43
44void Options::parse(int argc, const char* const argv[])
45{
46 size_t positional_idx{0};
47 ArgvLexer lex{argc - 1, argv + 1};
48 while (!lex.empty()) {
49 const auto opt = lex.opt();
50
51 bool positional{false};
52 OptsMap::iterator it{opts_.end()};
53
54 if (!opt.empty()) {
55 it = opts_.find(opt);
56 } else {
57 if (positional_idx >= positional_.size()) {
58 throw runtime_error{"unexpected argument: " + string{lex.arg()}};
59 }
60 positional = true;
61 }
62
63 if (!positional && it == opts_.end()) {
64 throw runtime_error{"unknown option: " + string{opt}};
65 }
66
67 auto& data = positional ? positional_[positional_idx++] : it->second->data;
68
69 visit(overloaded{[&](const Help& /*arg*/) {
70 lex.pop_switch();
71 cout << *this << "\n";
72 exit(0);
73 },
74 [&](Switch& arg) {
75 lex.pop_switch();
76 arg.run();
77 },
78 [&](Value& arg) {
79 const auto val = lex.pop_value();
80 if (arg.set_ && !arg.multitoken_) {
81 throw runtime_error{"duplicate option: " + string{opt}};
82 }
83 arg.run(val);
84 },
85 [&](const NoOp&) { lex.pop(); }},
86 data);
87 }
88
89 // Ensure all required parameters have been set.
90 // FIXME: but we're not checking required positional arguments?
91 for (const auto& data : opts_) {
92 visit(overloaded{[](const auto& /*def*/) {},
93 [&](const Value& arg) {
94 if (arg.presence() == Value::Required && !arg.set()) {
95 throw runtime_error{"missing required option: "
96 + data.second->opt()};
97 }
98 }},
99 data.second->data);
100 }
101 for (const auto& data : positional_) {
102 visit(overloaded{[](const auto& /*def*/) {},
103 [&](const Value& arg) {
104 if (arg.presence() == Value::Required && !arg.set()) {
105 throw runtime_error{"missing positional argument"};
106 }
107 }},
108 data);
109 }
110}
111
112ostream& operator<<(ostream& out, const Options& options)
113{
114 out << "Usage: " << options.description_ << "\nOptions:\n";
115
116 for (const auto& opt : options.help_) {
117 unsigned max_width{15};
118 // value find
119 out << " ";
120 if (!opt->short_opt.empty()) {
121 max_width -= 2;
122 out << '-' << opt->short_opt;
123 }
124 if (!opt->long_opt.empty()) {
125 if (!opt->short_opt.empty()) {
126 max_width -= 2;
127 out << ", ";
128 }
129 max_width -= 2 + opt->long_opt.size();
130 out << "--" << opt->long_opt;
131 }
132 out << setw(max_width) << ' ' << opt->description << "\n";
133 }
134 return out;
135}
136
137} // namespace util
138} // 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:44
Options(std::string description="")
Definition Options.cpp:29
bool operator[](const std::string &long_opt) const noexcept
Definition Options.cpp:34
STL namespace.
ostream & operator<<(ostream &os, const pair< T, U > &p)
Definition Parser.ut.cpp:29
const DataT & data(const MsgEvent &ev) noexcept
Definition Event.hpp:54
constexpr auto bind() noexcept
Definition Slot.hpp:92