Config: reformat all descriptions to fill 80 columns
[ncmpcpp.git] / src / utility / option_parser.h
blob7f9cc9cac040d13082cfdbaed05ae18741336813
1 /*
2 * Copyright (c) 2014-2017, Andrzej Rybczak <electricityispower@gmail.com>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #ifndef NCMPCPP_UTILITY_OPTION_PARSER_H
34 #define NCMPCPP_UTILITY_OPTION_PARSER_H
36 #include <boost/algorithm/string/trim.hpp>
37 #include <boost/tokenizer.hpp>
38 #include <boost/lexical_cast.hpp>
39 #include <cassert>
40 #include <stdexcept>
41 #include <unordered_map>
43 [[noreturn]] inline void invalid_value(const std::string &v)
45 throw std::runtime_error("invalid value: " + v);
48 template <typename DestT>
49 DestT verbose_lexical_cast(const std::string &v)
51 try {
52 return boost::lexical_cast<DestT>(v);
53 } catch (boost::bad_lexical_cast &) {
54 invalid_value(v);
58 template <typename ValueT, typename ConvertT>
59 std::vector<ValueT> list_of(const std::string &v, ConvertT convert)
61 std::vector<ValueT> result;
62 boost::tokenizer<boost::escaped_list_separator<char>> elems(v);
63 for (auto &value : elems)
64 result.push_back(convert(boost::trim_copy(value)));
65 if (result.empty())
66 throw std::runtime_error("empty list");
67 return result;
70 template <typename ValueT>
71 std::vector<ValueT> list_of(const std::string &v)
73 return list_of<ValueT>(v, verbose_lexical_cast<ValueT>);
76 bool yes_no(const std::string &v);
78 ////////////////////////////////////////////////////////////////////////////////
80 class option_parser
82 template <typename DestT>
83 struct worker
85 template <typename MapT>
86 worker(DestT *dest, MapT &&map)
87 : m_dest(dest), m_map(std::forward<MapT>(map)), m_dest_set(false)
88 { }
90 void operator()(std::string value)
92 if (m_dest_set)
93 throw std::runtime_error("option already set");
94 assign<DestT, void>::apply(m_dest, m_map, value);
95 m_dest_set = true;
98 private:
99 template <typename ValueT, typename VoidT>
100 struct assign {
101 static void apply(ValueT *dest,
102 std::function<DestT(std::string)> &map,
103 std::string &value) {
104 *dest = map(std::move(value));
107 template <typename VoidT>
108 struct assign<void, VoidT> {
109 static void apply(void *,
110 std::function<void(std::string)> &map,
111 std::string &value) {
112 map(std::move(value));
116 DestT *m_dest;
117 std::function<DestT(std::string)> m_map;
118 bool m_dest_set;
121 struct parser {
122 template <typename StringT, typename SetterT>
123 parser(StringT &&default_, SetterT &&setter_)
124 : m_used(false)
125 , m_default_value(std::forward<StringT>(default_))
126 , m_worker(std::forward<SetterT>(setter_))
129 bool used() const
131 return m_used;
134 void parse(std::string v)
136 m_worker(std::move(v));
137 m_used = true;
140 void parse_default() const
142 assert(!m_used);
143 m_worker(m_default_value);
146 private:
147 bool m_used;
148 std::string m_default_value;
149 std::function<void(std::string)> m_worker;
152 std::unordered_map<std::string, parser> m_parsers;
154 public:
155 template <typename DestT, typename MapT>
156 void add(std::string option, DestT *dest, std::string default_, MapT &&map)
158 assert(m_parsers.count(option) == 0);
159 m_parsers.emplace(
160 std::move(option),
161 parser(
162 std::move(default_),
163 worker<DestT>(dest, std::forward<MapT>(map))));
166 template <typename DestT>
167 void add(std::string option, DestT *dest, std::string default_)
169 add(std::move(option), dest, std::move(default_), verbose_lexical_cast<DestT>);
172 bool run(std::istream &is, bool warn_on_errors);
173 bool initialize_undefined(bool warn_on_errors);
176 #endif // NCMPCPP_UTILITY_OPTION_PARSER_H