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