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