monotone

monotone Mtn Source Tree

Root/option.hh

1// Copyright 2006 Timothy Brownawell <tbrownaw@gmail.com>
2// This is made available under the GNU GPL v2 or later.
3
4#ifndef __OPTION_HH__
5#define __OPTION_HH__
6
7/*
8 * Infrastructure for parsing options.
9 *
10 * This can be used on its own with concrete_option_set::operator()(), or
11 * used with something like options.{cc,hh} and option_set. The former is
12 * very simple to do, while the latter should allow slightly better code
13 * structure for more involved uses.
14 */
15
16#include <stdexcept>
17#include <map>
18#include <set>
19#include "vector.hh"
20
21#include <boost/function.hpp>
22#include "lexical_cast.hh"
23
24#include "sanity.hh"
25#include "vocab.hh"
26
27// The types to represent the command line's parameters.
28class arg_type : public utf8 {
29public:
30 explicit arg_type(void) : utf8() {}
31 explicit arg_type(std::string const & s) : utf8(s) {}
32 explicit arg_type(utf8 const & u) : utf8(u) {}
33};
34template <>
35inline void dump(arg_type const & a, std::string & out) { out = a(); }
36typedef std::vector< arg_type > args_vector;
37
38namespace option {
39 // Base for errors thrown by this code.
40 struct option_error : public std::invalid_argument
41 {
42 option_error(std::string const & str);
43 };
44 struct unknown_option : public option_error
45 {
46 unknown_option(std::string const & opt);
47 };
48 struct missing_arg : public option_error
49 {
50 missing_arg(std::string const & opt);
51 };
52 // -ofoo or --opt=foo when the option doesn't take an argument
53 struct extra_arg : public option_error
54 {
55 extra_arg(std::string const & opt);
56 };
57 // thrown by from_command_line when setting an option fails
58 // by either boost::bad_lexical_cast or bad_arg_internal
59 struct bad_arg : public option_error
60 {
61 bad_arg(std::string const & opt, arg_type const & arg);
62 bad_arg(std::string const & opt,
63 arg_type const & arg,
64 std::string const & reason);
65 };
66 // from_command_line() catches this and boost::bad_lexical_cast
67 // and converts them to bad_arg exceptions
68 struct bad_arg_internal
69 {
70 std::string reason;
71 bad_arg_internal(std::string const & str = "");
72 };
73
74 // Split a "long,s" option name into long and short names.
75 void splitname(std::string const & from, std::string & name, std::string & n);
76
77 // An option that can be set and reset.
78 struct concrete_option
79 {
80 std::string description;
81 std::string longname;
82 std::string shortname;
83 bool has_arg;
84 boost::function<void (std::string)> setter;
85 boost::function<void ()> resetter;
86
87 concrete_option();
88 concrete_option(std::string const & names,
89 std::string const & desc,
90 bool arg,
91 boost::function<void (std::string)> set,
92 boost::function<void ()> reset);
93
94 bool operator<(concrete_option const & other) const;
95 };
96
97 // A group of options, which can be set from a command line
98 // and can produce a usage string.
99 struct concrete_option_set
100 {
101 std::set<concrete_option> options;
102 concrete_option_set();
103 concrete_option_set(std::set<concrete_option> const & other);
104 concrete_option_set(concrete_option const & opt);
105
106 // for building a concret_option_set directly (as done in unit_tests.cc),
107 // rather than using intermediate machinery like in options*
108 concrete_option_set &
109 operator()(std::string const & names,
110 std::string const & desc,
111 boost::function<void ()> set,
112 boost::function<void ()> reset = 0);
113 concrete_option_set &
114 operator()(std::string const & names,
115 std::string const & desc,
116 boost::function<void (std::string)> set,
117 boost::function<void ()> reset = 0);
118
119 concrete_option_set operator | (concrete_option_set const & other) const;
120 void reset() const;
121 std::string get_usage_str() const;
122 void from_command_line(args_vector & args, bool allow_xargs = true);
123 void from_command_line(int argc, char const * const * argv);
124 void from_key_value_pairs(std::vector<std::pair<std::string, std::string> > const & keyvals);
125 };
126 concrete_option_set
127 operator | (concrete_option const & a, concrete_option const & b);
128
129 // used by the setter() functions below
130 template<typename T>
131 struct setter_class
132 {
133 T & item;
134 setter_class(T & i)
135 : item(i)
136 {}
137 void operator()(std::string s)
138 {
139 item = boost::lexical_cast<T>(s);
140 }
141 };
142 template<>
143 struct setter_class<bool>
144 {
145 bool & item;
146 setter_class(bool & i)
147 : item(i)
148 {}
149 void operator()()
150 {
151 item = true;
152 }
153 };
154 template<typename T>
155 struct setter_class<std::vector<T> >
156 {
157 std::vector<T> & items;
158 setter_class(std::vector<T> & i)
159 : items(i)
160 {}
161 void operator()(std::string s)
162 {
163 items.push_back(boost::lexical_cast<T>(s));
164 }
165 };
166 template<typename T>
167 struct resetter_class
168 {
169 T & item;
170 T value;
171 resetter_class(T & i, T const & v)
172 : item(i), value(v)
173 {}
174 void operator()()
175 {
176 item = value;
177 }
178 };
179
180 // convenience functions to generate a setter for a var
181 template<typename T> inline
182 boost::function<void(std::string)> setter(T & item)
183 {
184 return setter_class<T>(item);
185 }
186 inline boost::function<void()> setter(bool & item)
187 {
188 return setter_class<bool>(item);
189 }
190 // convenience function to generate a resetter for a var
191 template<typename T> inline
192 boost::function<void()> resetter(T & item, T const & value = T())
193 {
194 return resetter_class<T>(item, value);
195 }
196
197 // because std::bind1st can't handle producing a nullary functor
198 template<typename T>
199 struct binder_only
200 {
201 T * obj;
202 boost::function<void(T*)> fun;
203 binder_only(boost::function<void(T*)> const & f, T * o)
204 : obj(o), fun(f)
205 {}
206 void operator()()
207 {
208 fun(obj);
209 }
210 };
211
212 // Options that need to be attached to some other object
213 // in order for set and reset to be meaningful.
214 template<typename T>
215 struct option
216 {
217 std::string description;
218 std::string names;
219 bool has_arg;
220 boost::function<void (T*, std::string)> setter;
221 boost::function<void (T*)> resetter;
222
223 option(std::string const & name,
224 std::string const & desc,
225 bool arg,
226 void(T::*set)(std::string),
227 void(T::*reset)())
228 {
229 I(!name.empty() || !desc.empty());
230 description = desc;
231 names = name;
232 has_arg = arg;
233 setter = set;
234 resetter = reset;
235 }
236
237 concrete_option instantiate(T * obj) const
238 {
239 concrete_option out;
240 out.description = description;
241 splitname(names, out.longname, out.shortname);
242 out.has_arg = has_arg;
243
244 if (setter)
245out.setter = std::bind1st(setter, obj);
246 if (resetter)
247out.resetter = binder_only<T>(resetter, obj);
248 return out;
249 }
250
251 bool operator<(option const & other) const
252 {
253 if (names != other.names)
254 return names < other.names;
255 return description < other.description;
256 }
257 };
258
259 // A group of unattached options, which can be given an object
260 // to attach themselves to.
261 template<typename T>
262 struct option_set
263 {
264 std::set<option<T> > options;
265 option_set(){}
266 option_set(option_set<T> const & other)
267 : options(other.options)
268 {}
269 option_set(option<T> const & opt)
270 {
271 options.insert(opt);
272 }
273
274 option_set(std::string const & name,
275 std::string const & desc,
276 bool arg,
277 void(T::*set)(std::string),
278 void(T::*reset)())
279 {
280 options.insert(option<T>(name, desc, arg, set, reset));
281 }
282 concrete_option_set instantiate(T * obj) const
283 {
284 std::set<concrete_option> out;
285 for (typename std::set<option<T> >::const_iterator i = options.begin();
286 i != options.end(); ++i)
287out.insert(i->instantiate(obj));
288 return out;
289 }
290 option_set<T> operator | (option_set<T> const & other) const
291 {
292 option_set<T> combined;
293 std::set_union(options.begin(), options.end(),
294 other.options.begin(), other.options.end(),
295 std::inserter(combined.options, combined.options.begin()));
296 return combined;
297 }
298 option_set<T> operator - (option_set<T> const & other) const
299 {
300 option_set<T> combined;
301 std::set_difference(options.begin(), options.end(),
302 other.options.begin(), other.options.end(),
303 std::inserter(combined.options,
304 combined.options.begin()));
305 return combined;
306 }
307 bool empty() const {return options.empty();}
308 };
309 template<typename T>
310 option_set<T>
311 operator | (option<T> const & a, option<T> const & b)
312 {
313 return option_set<T>(a) | b;
314 }
315
316}
317
318
319#endif
320
321// Local Variables:
322// mode: C++
323// fill-column: 76
324// c-file-style: "gnu"
325// indent-tabs-mode: nil
326// End:
327// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status