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