Line data Source code
1 : /*
2 : * License:
3 : * Copyright (c) 2006-2019 Made to Order Software Corp. All Rights Reserved
4 : *
5 : * https://snapwebsites.org/
6 : * contact@m2osw.com
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 2 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License along
19 : * with this program; if not, write to the Free Software Foundation, Inc.,
20 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 : *
22 : * Authors:
23 : * Alexis Wilke alexis@m2osw.com
24 : * Doug Barbieri doug@m2osw.com
25 : */
26 : #pragma once
27 :
28 : /** \file
29 : * \brief Definitions of the options class a initialization functions.
30 : *
31 : * The advgetopt library offers an advanced way to manage your command
32 : * line tools options on the command line, in environment variables, and
33 : * in configuration files.
34 : */
35 :
36 : // advgetopt lib
37 : //
38 : #include "advgetopt/option_info.h"
39 :
40 :
41 : // snapdev lib
42 : //
43 : #include <snapdev/not_used.h>
44 :
45 :
46 :
47 : namespace advgetopt
48 : {
49 :
50 :
51 :
52 :
53 :
54 :
55 : // this structure is used to declare your command line options in a
56 : // constexpr array
57 : //
58 : // TODO: plan to transform all the strings in an array with a scheme such
59 : // as:
60 : //
61 : // "a:<alias>",
62 : // "d:<default>",
63 : // "h:<help>",
64 : // "n:<name>",
65 : // "s:<separator>",
66 : // "v:<validator>(<param>, ...)"
67 : //
68 : // our templates should be able to create that array automatically.
69 : // This way we avoid many nullptr in so many definitions (i.e. most
70 : // our definitions do not have a default, separators, or a validator)
71 : // We would also avoid the alias/help overload.
72 : //
73 : struct option
74 : {
75 : short_name_t f_short_name = NO_SHORT_NAME; // letter option (or '\0')
76 : flag_t f_flags = GETOPT_FLAG_NONE; // set of flags
77 : char const * f_name = nullptr; // name of the option (i.e. "test" for --test, or nullptr)
78 : char const * f_default = nullptr; // a default value if not nullptr
79 : char const * f_help = nullptr; // help for this option, if nullptr it's a hidden option; if ALIAS then this is the actual alias
80 : char const * f_validator = nullptr; // the name of a validator and optional parameters between parenthesis
81 : char const * const *f_multiple_separators = nullptr;// nullptr terminated list of strings used as separators when GETOPT_FLAG_MULTIPLE is set
82 : };
83 :
84 :
85 :
86 : template<typename T>
87 : class OptionValue
88 : {
89 : public:
90 : typedef T value_t;
91 :
92 234 : constexpr OptionValue<T>(T const v)
93 234 : : f_value(v)
94 : {
95 234 : }
96 :
97 162 : constexpr value_t get() const
98 : {
99 162 : return f_value;
100 : }
101 :
102 : private:
103 : value_t f_value;
104 : };
105 :
106 :
107 : class ShortName
108 : : public OptionValue<short_name_t>
109 : {
110 : public:
111 18 : constexpr ShortName()
112 18 : : OptionValue<short_name_t>(NO_SHORT_NAME)
113 : {
114 18 : }
115 :
116 12 : constexpr ShortName(short_name_t name)
117 12 : : OptionValue<short_name_t>(name)
118 : {
119 12 : }
120 : };
121 :
122 : class Flags
123 : : public OptionValue<flag_t>
124 : {
125 : public:
126 18 : constexpr Flags()
127 18 : : OptionValue<flag_t>(GETOPT_FLAG_NONE)
128 : {
129 18 : }
130 :
131 18 : constexpr Flags(flag_t flags)
132 18 : : OptionValue<flag_t>(flags)
133 : {
134 18 : }
135 : };
136 :
137 : class Name
138 : : public OptionValue<char const *>
139 : {
140 : public:
141 : constexpr Name()
142 : : OptionValue<char const *>(nullptr)
143 : {
144 : }
145 :
146 18 : constexpr Name(char const * name)
147 18 : : OptionValue<char const *>(name)
148 : {
149 18 : }
150 : };
151 :
152 : class DefaultValue
153 : : public OptionValue<char const *>
154 : {
155 : public:
156 18 : constexpr DefaultValue()
157 18 : : OptionValue<char const *>(nullptr)
158 : {
159 18 : }
160 :
161 9 : constexpr DefaultValue(char const * help)
162 9 : : OptionValue<char const *>(help)
163 : {
164 9 : }
165 : };
166 :
167 : class Alias
168 : : public OptionValue<char const *>
169 : {
170 : public:
171 36 : constexpr Alias()
172 36 : : OptionValue<char const *>(nullptr)
173 : {
174 36 : }
175 :
176 : constexpr Alias(char const * alias)
177 : : OptionValue<char const *>(alias)
178 : {
179 : }
180 : };
181 :
182 : class Help
183 : : public OptionValue<char const *>
184 : {
185 : public:
186 18 : constexpr Help()
187 18 : : OptionValue<char const *>(nullptr)
188 : {
189 18 : }
190 :
191 18 : constexpr Help(char const * help)
192 18 : : OptionValue<char const *>(help)
193 : {
194 18 : }
195 : };
196 :
197 : class Validator
198 : : public OptionValue<char const *>
199 : {
200 : public:
201 18 : constexpr Validator()
202 18 : : OptionValue<char const *>(nullptr)
203 : {
204 18 : }
205 :
206 : constexpr Validator(char const * validator)
207 : : OptionValue<char const *>(validator)
208 : {
209 : }
210 : };
211 :
212 : class Separators
213 : : public OptionValue<char const * const *>
214 : {
215 : public:
216 18 : constexpr Separators()
217 18 : : OptionValue<char const * const *>(nullptr)
218 : {
219 18 : }
220 :
221 15 : constexpr Separators(char const * const * separators)
222 15 : : OptionValue<char const * const *>(separators)
223 : {
224 15 : }
225 : };
226 :
227 :
228 :
229 : template<typename T, typename F, class ...ARGS>
230 162 : constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
231 : {
232 162 : snap::NOTUSED(args...);
233 162 : return first.get();
234 : }
235 :
236 :
237 : template<typename T, typename F, class ...ARGS>
238 540 : constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
239 : {
240 540 : snap::NOTUSED(first);
241 540 : return find_option<T>(args...);
242 : }
243 :
244 :
245 :
246 : template<class ...ARGS>
247 18 : constexpr option define_option(ARGS ...args)
248 : {
249 : #pragma GCC diagnostic push
250 : #pragma GCC diagnostic ignored "-Wpedantic"
251 : option opt =
252 : {
253 36 : .f_short_name = find_option<ShortName >(args..., ShortName()),
254 36 : .f_flags = find_option<Flags >(args..., Flags())
255 36 : | (find_option<Alias >(args..., Alias()) != nullptr
256 : ? GETOPT_FLAG_ALIAS
257 : : GETOPT_FLAG_NONE),
258 18 : .f_name = find_option<Name >(args...), // no default, must be defined
259 36 : .f_default = find_option<DefaultValue>(args..., DefaultValue()),
260 36 : .f_help = find_option<Alias >(args..., Alias()) != nullptr
261 18 : ? find_option<Alias >(args..., Alias())
262 36 : : find_option<Help >(args..., Help()),
263 36 : .f_validator = find_option<Validator >(args..., Validator()),
264 36 : .f_multiple_separators = find_option<Separators >(args..., Separators()),
265 144 : };
266 : #pragma GCC diagnostic pop
267 :
268 : // TODO: once possible (C++17/20?) add verification tests here
269 :
270 18 : return opt;
271 : }
272 :
273 :
274 :
275 :
276 :
277 : constexpr option end_options()
278 : {
279 : return define_option(
280 : advgetopt::Name(nullptr)
281 : , advgetopt::Flags(advgetopt::end_flags())
282 : );
283 : }
284 :
285 :
286 :
287 :
288 :
289 :
290 :
291 :
292 : struct group_description
293 : {
294 : flag_t f_group = GETOPT_FLAG_GROUP_NONE; // the default is used to mark the end of the list
295 : char const * f_name = nullptr; // for --<name>-help
296 : char const * f_description = nullptr; // for usage() output
297 : };
298 :
299 :
300 :
301 :
302 : template<typename T>
303 : class GroupValue
304 : {
305 : public:
306 : typedef T value_t;
307 :
308 : constexpr GroupValue<T>(T const v)
309 : : f_value(v)
310 : {
311 : }
312 :
313 : constexpr value_t get() const
314 : {
315 : return f_value;
316 : }
317 :
318 : private:
319 : value_t f_value;
320 : };
321 :
322 : class GroupNumber
323 : : public OptionValue<flag_t>
324 : {
325 : public:
326 : constexpr GroupNumber()
327 : : OptionValue<flag_t>(GETOPT_FLAG_GROUP_NONE)
328 : {
329 : }
330 :
331 : constexpr GroupNumber(flag_t group)
332 : : OptionValue<flag_t>(group)
333 : {
334 : }
335 : };
336 :
337 : class GroupName
338 : : public GroupValue<char const *>
339 : {
340 : public:
341 : constexpr GroupName()
342 : : GroupValue<char const *>(nullptr)
343 : {
344 : }
345 :
346 : constexpr GroupName(char const * name)
347 : : GroupValue<char const *>(name)
348 : {
349 : }
350 : };
351 :
352 : class GroupDescription
353 : : public GroupValue<char const *>
354 : {
355 : public:
356 : constexpr GroupDescription()
357 : : GroupValue<char const *>(nullptr)
358 : {
359 : }
360 :
361 : constexpr GroupDescription(char const * description)
362 : : GroupValue<char const *>(description)
363 : {
364 : }
365 : };
366 :
367 :
368 : template<typename T, typename F, class ...ARGS>
369 : constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_group(F first, ARGS ...args)
370 : {
371 : snap::NOTUSED(args...);
372 : return first.get();
373 : }
374 :
375 :
376 : template<typename T, typename F, class ...ARGS>
377 : constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_group(F first, ARGS ...args)
378 : {
379 : snap::NOTUSED(first);
380 : return find_group<T>(args...);
381 : }
382 :
383 :
384 :
385 : template<class ...ARGS>
386 : constexpr group_description define_group(ARGS ...args)
387 : {
388 : #pragma GCC diagnostic push
389 : #pragma GCC diagnostic ignored "-Wpedantic"
390 : group_description grp =
391 : {
392 : .f_group = find_group<GroupNumber >(args..., GroupNumber()),
393 : .f_name = find_group<GroupName >(args..., GroupName()),
394 : .f_description = find_group<GroupDescription>(args..., GroupDescription()),
395 : };
396 : #pragma GCC diagnostic pop
397 :
398 : return grp;
399 : }
400 :
401 :
402 : constexpr group_description end_groups()
403 : {
404 : // the defaults are what we expect to end the list of groups
405 : return define_group();
406 : }
407 :
408 :
409 :
410 :
411 :
412 :
413 :
414 :
415 : constexpr flag_t GETOPT_ENVIRONMENT_FLAG_DYNAMIC_PARAMETERS = 0x0001; // accept parameters that are not declared
416 :
417 : constexpr flag_t GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS = 0x0002; // add system parameters (i.e. --help, --version, etc.)
418 : constexpr flag_t GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS = 0x0004; // add & process system parameters
419 :
420 :
421 328 : struct options_environment
422 : {
423 : char const * f_project_name = nullptr; // project/application name--used as filename for the .conf files (%a)
424 : option const * f_options = nullptr; // raw options
425 : char const * f_options_files_directory = nullptr; // directory to check for option files (default "/usr/shared/advgetopt")
426 : char const * f_environment_variable_name = nullptr; // environment variable with additional options (%e)
427 : char const * const * f_configuration_files = nullptr; // nullptr terminated array of full paths to configuration files (%f)
428 : char const * f_configuration_filename = nullptr; // the configuration filename to search in f_configuration_directories (%g)
429 : char const * const * f_configuration_directories = nullptr; // nullptr terminated array of paths only to configuration files (%d)
430 : flag_t f_environment_flags = 0; // GETOPT_ENVIRONMENT_FLAG_...
431 : char const * f_help_header = nullptr; // show on --help
432 : char const * f_help_footer = nullptr; // show on --help
433 : char const * f_version = nullptr; // show on --version and %v
434 : char const * f_license = nullptr; // show on --license and %l
435 : char const * f_copyright = nullptr; // show on --copyright and %c
436 : char const * f_build_date = __DATE__; // available to parameter %b
437 : char const * f_build_time = __TIME__; // available to parameter %t
438 : group_description const * f_groups = nullptr; // nullptr terminated array of group names
439 : };
440 :
441 :
442 :
443 :
444 :
445 : } // namespace advgetopt
446 : // vim: ts=4 sw=4 et
|