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