Loading...
Searching...
No Matches
option.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2023, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
44#pragma once
45
46#include "scope.h"
47
48namespace ledger {
49
50using namespace boost::placeholders;
51
52class call_scope_t;
53
54template <typename T>
56{
57protected:
58 const char * name;
59 string::size_type name_len;
60 const char ch;
61 bool handled;
63
65
66public:
67 T * parent;
68 string value;
70
71 option_t(const char * _name, const char _ch = '\0')
72 : name(_name), name_len(std::strlen(name)), ch(_ch),
74 wants_arg(name_len > 0 ? name[name_len - 1] == '_' : false) {
75 DEBUG("option.names", "Option: " << name);
76 TRACE_CTOR(option_t, "const char *, const char");
77 }
89
90 virtual ~option_t() {
92 }
93
94 void report(std::ostream& out) const {
95 if (handled && source) {
96 out.width(24);
97 out << std::right << desc();
98 if (wants_arg) {
99 out << " = ";
100 out.width(42);
101 out << std::left << value;
102 } else {
103 out.width(45);
104 out << ' ';
105 }
106 out << std::left << *source << std::endl;
107 }
108 }
109
110 string desc() const {
111 std::ostringstream out;
112 out << "--";
113 for (const char * p = name; *p; p++) {
114 if (*p == '_') {
115 if (*(p + 1))
116 out << '-';
117 } else {
118 out << *p;
119 }
120 }
121 if (ch)
122 out << " (-" << ch << ")";
123 return out.str();
124 }
125
126 operator bool() const {
127 return handled;
128 }
129
130 string str() const {
132 if (value.empty())
133 throw_(std::runtime_error, _f("No argument provided for %1%") % desc());
134 return value;
135 }
136
137 void on(const char * whence) {
138 on(string(whence));
139 }
140 void on(const optional<string>& whence) {
141 handler_thunk(whence);
142
143 handled = true;
144 source = whence;
145 }
146
147 void on(const char * whence, const string& str) {
148 on(string(whence), str);
149 }
150 void on(const optional<string>& whence, const string& str) {
151 string before = value;
152
153 handler_thunk(whence, str);
154
155 if (value == before)
156 value = str;
157
158 handled = true;
159 source = whence;
160 }
161
162 void off() {
163 handled = false;
164 value = "";
165 source = none;
166 }
167
168 virtual void handler_thunk(const optional<string>&) {}
169 virtual void handler_thunk(const optional<string>&, const string&) {}
170
172 if (wants_arg) {
173 if (args.size() < 2)
174 throw_(std::runtime_error, _f("No argument provided for %1%") % desc());
175 else if (args.size() > 2)
176 throw_(std::runtime_error, _f("Too many arguments provided for %1%") % desc());
177 else if (! args[0].is_string())
178 throw_(std::runtime_error, _f("Context argument for %1% not a string") % desc());
179 on(args.get<string>(0), args.get<string>(1));
180 }
181 else if (args.size() < 1) {
182 throw_(std::runtime_error, _f("No argument provided for %1%") % desc());
183 }
184 else if (! args[0].is_string()) {
185 throw_(std::runtime_error, _f("Context argument for %1% not a string") % desc());
186 }
187 else {
188 on(args.get<string>(0));
189 }
190 return true;
191 }
192
194 if (! args.empty()) {
195 args.push_front(string_value("?expr"));
196 return handler(args);
197 }
198 else if (wants_arg) {
199 return string_value(value);
200 }
201 else {
202 return handled;
203 }
204 }
205};
206
207#define BEGIN(type, name) \
208 struct name ## option_t : public option_t<type>
209
210#define CTOR(type, name) \
211 name ## option_t() : option_t<type>(#name)
212#define CTOR_(type, name, base) \
213 name ## option_t() : option_t<type>(#name), base
214#define DECL1(type, name, vartype, var, value) \
215 vartype var ; \
216 name ## option_t() : option_t<type>(#name), var value
217
218#define DO() virtual void handler_thunk(const optional<string>& whence)
219#define DO_(var) virtual void handler_thunk(const optional<string>& whence, \
220 const string& var)
221
222#define END(name) name ## handler
223
224#define COPY_OPT(name, other) name ## handler(other.name ## handler)
225
226#define MAKE_OPT_HANDLER(type, x) \
227 expr_t::op_t::wrap_functor(bind(&option_t<type>::handler, x, _1))
228
229#define MAKE_OPT_FUNCTOR(type, x) \
230 expr_t::op_t::wrap_functor(bind(&option_t<type>::operator(), x, _1))
231
232inline bool is_eq(const char * p, const char * n) {
233 // Test whether p matches n, substituting - in p for _ in n.
234 for (; *p && *n; p++, n++) {
235 if (! (*p == '-' && *n == '_') && *p != *n)
236 return false;
237 }
238 // Ignore any trailing underscore
239 return *p == *n || (! *p && *n == '_' && ! *(n + 1));
240}
241
242#define OPT(name) \
243 if (is_eq(p, #name)) \
244 return ((name ## handler).parent = this, &(name ## handler))
245
246#define OPT_ALT(name, alt) \
247 if (is_eq(p, #name) || is_eq(p, #alt)) \
248 return ((name ## handler).parent = this, &(name ## handler))
249
250#define OPT_(name) \
251 if (! *(p + 1) || \
252 ((name ## handler).wants_arg && \
253 *(p + 1) == '_' && ! *(p + 2)) || \
254 is_eq(p, #name)) \
255 return ((name ## handler).parent = this, &(name ## handler))
256
257#define OPT_CH(name) \
258 if (! *(p + 1) || \
259 ((name ## handler).wants_arg && \
260 *(p + 1) == '_' && ! *(p + 2))) \
261 return ((name ## handler).parent = this, &(name ## handler))
262
263#define HANDLER(name) name ## handler
264#define HANDLED(name) HANDLER(name)
265
266#define OPTION(type, name) \
267 BEGIN(type, name) \
268 { \
269 CTOR(type, name) {} \
270 } \
271 END(name)
272
273#define OPTION_(type, name, body) \
274 BEGIN(type, name) \
275 { \
276 CTOR(type, name) {} \
277 body \
278 } \
279 END(name)
280
281#define OPTION__(type, name, body) \
282 BEGIN(type, name) \
283 { \
284 body \
285 } \
286 END(name)
287
288#define OTHER(name) \
289 parent->HANDLER(name).parent = parent; \
290 parent->HANDLER(name)
291
292bool process_option(const string& whence, const string& name, scope_t& scope,
293 const char * arg, const string& varname);
294
295void process_environment(const char ** envp, const string& tag,
296 scope_t& scope);
297
299
300DECLARE_EXCEPTION(option_error, std::runtime_error);
301
302} // namespace ledger
#define TRACE_DTOR(cls)
Definition utils.h:144
#define TRACE_CTOR(cls, args)
Definition utils.h:143
#define DEBUG(cat, msg)
Definition utils.h:327
#define assert(x)
Definition utils.h:92
#define throw_(cls, msg)
Definition error.h:55
#define DECLARE_EXCEPTION(name, kind)
Definition error.h:88
bool is_eq(const char *p, const char *n)
Definition option.h:232
value_t string_value(const string &str="")
Definition value.h:949
std::list< string > strings_list
Definition utils.h:60
strings_list process_arguments(strings_list args, scope_t &scope)
T & downcast(U &object)
Definition utils.h:468
bool process_option(const string &whence, const string &name, scope_t &scope, const char *arg, const string &varname)
void process_environment(const char **envp, const string &tag, scope_t &scope)
const char * name
Definition option.h:58
virtual void handler_thunk(const optional< string > &)
Definition option.h:168
virtual ~option_t()
Definition option.h:90
value_t handler(call_scope_t &args)
Definition option.h:171
option_t & operator=(const option_t &)
void on(const char *whence, const string &str)
Definition option.h:147
string::size_type name_len
Definition option.h:59
virtual value_t operator()(call_scope_t &args)
Definition option.h:193
option_t(const option_t &other)
Definition option.h:78
void on(const char *whence)
Definition option.h:137
virtual void handler_thunk(const optional< string > &, const string &)
Definition option.h:169
void on(const optional< string > &whence)
Definition option.h:140
void report(std::ostream &out) const
Definition option.h:94
option_t(const char *_name, const char _ch='\0')
Definition option.h:71
const char ch
Definition option.h:60
string value
Definition option.h:68
optional< string > source
Definition option.h:62
void on(const optional< string > &whence, const string &str)
Definition option.h:150
string desc() const
Definition option.h:110
string str() const
Definition option.h:130
T get(std::size_t index, bool convert=true)
bool empty() const
Definition scope.h:398
void push_front(const value_t &val)
Definition scope.h:367
std::size_t size() const
Definition scope.h:395
Dynamic type representing various numeric types.
Definition value.h:83