1 /*
2 * Copyright 2013 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Original source is copyright 2010 - 2011. Alexey Tsoy.
7 * http://sourceforge.net/projects/interpreter11/
8 *
9 * Boost Software License - Version 1.0 - August 17th, 2003
10 *
11 * Permission is hereby granted, free of charge, to any person or organization
12 * obtaining a copy of the software and accompanying documentation covered by
13 * this license (the "Software") to use, reproduce, display, distribute,
14 * execute, and transmit the Software, and to prepare derivative works of the
15 * Software, and to permit third-parties to whom the Software is furnished to
16 * do so, all subject to the following:
17 *
18 * The copyright notices in the Software and this entire statement, including
19 * the above license grant, this restriction and the following disclaimer,
20 * must be included in all copies of the Software, in whole or in part, and
21 * all derivative works of the Software, unless such copies or derivative
22 * works are solely in the form of machine-executable object code generated by
23 * a source language processor.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
28 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
29 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 */
33
34 #ifndef ARX_UTIL_CMDLINE_INTERPRETER_H
35 #define ARX_UTIL_CMDLINE_INTERPRETER_H
36
37 #include <string>
38 #include <cstring>
39 #include <iomanip>
40
41 #include <boost/foreach.hpp>
42
43 #include "util/cmdline/detail/Interpreter.h"
44 #include "util/cmdline/Keys.h"
45 #include "util/cmdline/TypeCast.h"
46
47 namespace util { namespace cmdline {
48
49 // default strategy for types conversion
50 struct type_cast;
51
52 /*!
53 * A storage of option handlers and their descriptions.
54 *
55 * This provides convenient interface for adding new option (the add) method,
56 * and executing option handlers by name.
57 *
58 * @param StringType type of string
59 *
60 * @param TypeCast type of class that is used to convertation StringType to
61 * expected type by option handler.
62 */
63 template<typename StringType, typename TypeCast = type_cast>
64 class interpreter : detail::interpreter<key_type<StringType>, TypeCast> {
65 typedef detail::interpreter<key_type<StringType>, TypeCast> super_t;
66
67 public:
68 typedef typename super_t::type_cast_t type_cast_t;
69 typedef typename super_t::string_type string_type;
70 typedef typename super_t::op_name_t op_name_t;
71
72 /*!
73 * Registers options.
74 *
75 * This function registrates command options.
76 * The option parameters count and their types will be obtained
77 * automatically from the handler signature.
78 *
79 * @param handler This one can either be a pointer to a function or an
80 * object whose class contains only one operator().
81 *
82 * @param option_name "Name" of this option.
83 *
84 * @returns none.
85 *
86 * @throws If an option with one of the names that are contained in op_name_t
87 * already exists an exception will be thrown.
88 *
89 * @code
90 * interpreter<> l;
91 *
92 * l.add(&some_fn, op_name_t("option_name").description("some info"));
93 * // where some_fn is function.
94 *
95 * l.add(object, op_name_t("op_name_2").description("some info"));
96 * //object whose class contains a single operator(), except for template one.
97 *
98 * @endcode
99 */
100 template<typename Handler>
add(const Handler & handler,const op_name_t & option_name)101 void add(const Handler & handler, const op_name_t & option_name) {
102 super_t::add(handler, option_name);
103 }
104
105 /*!
106 * Registers options.
107 *
108 * This function registrates command options.
109 *
110 * @param handler This one can either be a pointer to a function or an
111 * object whose class contains only one operator().
112 *
113 * @param option_name "Name" of this option.
114 *
115 * @returns none.
116 *
117 * @throws If an option with one of the names that are contained in op_name_t
118 * already exists an exception will be thrown.
119 *
120 * @code
121 * interpreter<> l;
122 * l.add<void (A1,...,An)> (object, op_name_t("option_name").description("some info"));
123 * @endcode
124 */
125 template<typename HndlSign, typename Handler>
add(const Handler & handler,const op_name_t & option_name)126 void add(const Handler & handler, const op_name_t & option_name) {
127 super_t::template add<HndlSign>(handler, option_name);
128 }
129
130 /*!
131 * Removes an option in an interpreter with name.
132 *
133 * This function removes an option by name.
134 * @param option_name Name of the option.
135 */
erase(const string_type & option_name)136 void erase(const string_type & option_name) {
137 super_t::erase(option_name);
138 }
139
140 /*!
141 * Visits all options.
142 *
143 * @param visitor An object or pointer to a function.
144 * @note The visitor has to support call semantic : operator(const op_name_t &).
145 */
146 template<typename Visitor>
visit(Visitor & visitor)147 void visit(Visitor & visitor) const {
148 super_t::visit(visitor);
149 }
150
151 /*!
152 * Invokes handler by option name with parameters [args_begin, args_end).
153 *
154 * @param option_name Name of an option
155 *
156 * @param args_begin Iterator referring to the first argument for the option.
157 * @param args_optend Iterator referring to the end of arguments to be consumed by \ref optional.
158 * @param args_end Iterator referring to the past-the-end argument for the option.
159 *
160 * @throws If option isn't found or the handler of this options takes more
161 * than required arguments or they can't be converted, an exception
162 * will be thrown.
163 */
164 template<typename It>
invoke(const string_type & option_name,It & args_begin,It args_opend,It args_end,type_cast_t & type_cast)165 void invoke(const string_type & option_name, It & args_begin, It args_opend, It args_end,
166 type_cast_t & type_cast) const {
167 super_t::invoke(option_name, args_begin, args_opend, args_end, type_cast);
168 }
169
170 /*!
171 * Invokes handler by option name with parameters [args_begin, args_end).
172 *
173 * @param option_name Name of an option
174 *
175 * @param args_begin Iterator referring to the first argument for the option.
176 * @param args_end Iterator referring to the past-the-end argument for the option.
177 *
178 * @throws If option isn't found or the handler of this options takes more
179 * than required arguments or they can't be converted, an exception
180 * will be thrown.
181 */
182 template<typename It>
invoke(const string_type & option_name,It & args_begin,It args_end,type_cast_t & type_cast)183 void invoke(const string_type & option_name, It & args_begin, It args_end,
184 type_cast_t & type_cast) const {
185 invoke(option_name, args_begin, args_end, args_end, type_cast);
186 }
187
interpreter()188 interpreter() : super_t() { }
189
interpreter(const interpreter & rh)190 explicit interpreter(const interpreter & rh) : super_t(rh) { }
191
192 interpreter & operator=(const interpreter & rh) {
193 if(this != &rh) {
194 swap(interpreter(rh));
195 }
196 return *this;
197 }
198
199 };
200
201
202 namespace detail {
203 // visitor for command_line::interpreter.
204
205 template<typename Interpreter>
206 struct opname_size {
207
208 Interpreter const * interpreter;
209
210 size_t value;
211
opname_sizeopname_size212 explicit opname_size(const Interpreter & interpreter)
213 : interpreter(&interpreter)
214 , value(0)
215 { }
216
217 template<typename Key>
operatoropname_size218 void operator()(Key & key) {
219 typename Key::const_iterator it(key.begin()) , end(key.end());
220
221 if(it == end) { return; }
222
223 size_t cur_size(0);
224
225 cur_size += it->size();
226 for(++it; it != end; ++it) {
227 cur_size += 1 + it->size();
228 }
229
230 if(key.has_args()) {
231 if(key.has_arg_names()) {
232 cur_size += std::strlen(key.get_arg_names()) + 1;
233 } else {
234 cur_size += 4 * key.get_arg_count();
235 }
236 }
237
238 value = std::max(cur_size, value);
239 }
240
241 };
242
243 template<typename Stream, typename Interpreter>
244 struct print_op_t {
245
246 Stream * stream_;
247 Interpreter const* interpreter;
248
249 size_t offset;
250
print_op_tprint_op_t251 print_op_t(Stream & stream, const Interpreter & interpreter, size_t offset)
252 : stream_(&stream)
253 , interpreter(&interpreter)
254 , offset(offset)
255 { }
256
257 template<typename Key>
alignprint_op_t258 void align(Key & key) const {
259 opname_size<Interpreter> tmp(*interpreter);
260 tmp(key);
261
262 for(size_t i(tmp.value); i < offset; ++i)
263 (*stream_) << " ";
264 }
265
266 template<typename Key>
operatorprint_op_t267 void operator()(Key & key) const {
268 typename Key::const_iterator it(key.begin()) , end(key.end());
269
270 if(it == end) {
271 return;
272 }
273
274 (*stream_) << " ";
275
276 for(; it != end; ++it) {
277 (*stream_) << " " << *it;
278 }
279
280 if(key.has_args()) {
281 if(key.has_arg_names()) {
282 (*stream_) << ' ' << key.get_arg_names();
283 } else {
284 for(size_t i = 0; i < key.get_arg_count(); i++) {
285 (*stream_) << " ARG";
286 }
287 }
288 }
289
290 align(key);
291 (*stream_) << " " << key.get_description() << std::endl;
292 }
293 };
294
295 template<typename OStream, typename Interpreter>
print_op(OStream & os,const Interpreter & interpreter)296 void print_op(OStream & os, const Interpreter & interpreter) {
297 opname_size<Interpreter> calc_size(interpreter);
298 interpreter.visit(calc_size);
299
300 print_op_t<OStream, Interpreter> op(os, interpreter, calc_size.value);
301 interpreter.visit(op);
302 }
303
304 } // namespace detail
305
306 template<typename CharType, typename StringType, typename TypeCast>
307 std::basic_ostream<CharType> & operator<<(std::basic_ostream<CharType> & os,
308 const interpreter<StringType,TypeCast> & l) {
309 return detail::print_op(os, l), os;
310 }
311
312 } } // namespace util::cmdline
313
314 #endif // ARX_UTIL_CMDLINE_INTERPRETER_H
315