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