mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
appConfigurator.hpp
Go to the documentation of this file.
1/** \file appConfigurator.hpp
2 * \author Jared R. Males
3 * \brief An application configuration manager
4 *
5 * \ingroup mxApp_files
6 *
7 */
8
9//***********************************************************************//
10// Copyright 2015, 2016, 2017, 2018 Jared R. Males (jaredmales@gmail.com)
11//
12// This file is part of mxlib.
13//
14// mxlib is free software: you can redistribute it and/or modify
15// it under the terms of the GNU General Public License as published by
16// the Free Software Foundation, either version 3 of the License, or
17// (at your option) any later version.
18//
19// mxlib is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License
25// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
26//***********************************************************************//
27
28#ifndef app_appConfigurator_hpp
29#define app_appConfigurator_hpp
30
31#include <list>
32#include <fstream>
33#include <format>
34
35#include "../mxlib.hpp"
36
37#include "clOptions.hpp"
38#include "iniFile.hpp"
39#include "configTarget.hpp"
40
41namespace mx
42{
43namespace app
44{
45
46namespace detail
47{
48
49/// Optional parser override used to deterministically test appConfigurator parser failures.
50inline int ( *appConfiguratorParser )( iniFile &parser /**< [in,out] parser receiving file contents. */,
51 const std::string &filename /**< [in] file requested by readConfig. */ ) =
52 nullptr;
53
54} // namespace detail
55
56/// Class to manage a set of configurable values, and read their values from config/ini files and the command line.
57/**
58 * The configuration files are TOML/ini-style, with sections. That is
59 \verbatim
60 key1=value1
61 key2=value2
62
63 [section1]
64 key3=value3
65 key4=value4,value4.1, value4.2, value4.3
66
67 [section2]
68 key3=value5
69 key3=value5.1
70 key4=value6_over_
71 multiple_lines
72
73 \endverbatim
74 * such that section1.key3 is distinct from section2.key3 (they must have different config-target names though).
75 *
76 * Additional syntax rules:
77 * - Leading whitespace is stripped from the value, so `key=val` and `key= val` are equivalent.
78 * - Additional entries within one file with the same section and key are appended to the previous entry.
79 * So the value of section2.key3 is "value5value5.1".
80 * - Multi-line values are handled such that in the above example the result is key4=value6_over_multiple_lines.
81 * - Vectors are input as comma separated lists, as in section1.key4 above. Leading whitespace is stripped from each
82 * component of the vector.
83 *
84 * \todo add handling of += in subsequent files.
85 * \todo should just swith to strict TOML
86 *
87 * The command line parser handles both short-opt ("-h -vArg -n Arg") and long-opt ("--help --value=Arg --number=Arg")
88 styles.
89 *
90 *
91 * \bug a config=value pair listed in a conf file twice seems to cause a failure, even if they are the same value.
92 *
93 * \ingroup mxApp
94 *
95 */
97{
98 /// Iterator for the targets unordered_map
99 typedef std::unordered_map<std::string, configTarget>::iterator targetIterator;
100
101 /// Iterator for the clOnlyTargets list.
102 typedef std::list<configTarget>::iterator clOnlyTargetIterator;
103
104 /// The targets are stored in an unordered_map for fast access by key.
105 std::unordered_map<std::string, configTarget> m_targets;
106
107 /// Config file entries present in the file(s), but not corresponding to a target when parsed. Set aside for
108 /// possible analysis.
109 std::unordered_map<std::string, configTarget> m_unusedConfigs;
110
111 /// Targets which are only for the command line are stored separately in a list.
112 std::list<configTarget> clOnlyTargets;
113
114 /// Non-option arguments from the command line.
115 std::vector<std::string> nonOptions;
116
117 /// Running count of options added, used to track order.
118 int nAdded{ 0 };
119
120 /// Flag controlling whether or not to record config sources
121 bool m_sources{ false };
122
123 /// Clear the containers and free up the associated memory.
124 void clear();
125
126 /// Add a configTarget
127 /** Note that if name is a duplicate but the section and keyword are empty, it is handled as command-line only.
128 */
129 void add( const configTarget &tgt /**< [in] The configuration target to add */ );
130
131 /// Add a configTarget
132 /**
133 * \overload
134 */
135 void add( const std::string &n, /**< [in] The name of the target */
136 const std::string &so, /**< [in] The command-line short option (e.g. "f" for -f) */
137 const std::string &lo, /**< [in] The command-line long option (e.g. "file" for --file) */
138 int clt, /**< [in] The command-line option type, argType::false,
139 argType::true, argType::optional, argType::required */
140 const std::string &s, /**< [in] The config file section name, can be empty "" */
141 const std::string &kw, /**< [in] The config file keyword, read in a "keyword=value" pair */
142 bool isReq = false, /**< [in] Whether or not this option is required to be set */
143 const std::string &ht = "", /**< [in] The type to display in the help message */
144 const std::string &he = "" /**< [in] The explanation to display in the help message */
145 );
146
147 /// Parse the command line, updating the targets
148 void parseCommandLine( int argc, /**< [in] standard command line result specifying number
149 of argumetns in argv */
150 char **argv, /**< [in] standard command line result containing the
151 arguments. */
152 const std::string &oneTarget = "" /**< [in] [optional] if not empty, then only this target
153 is extracted by the parser. */
154 );
155
156 /// Read and parse a config/ini file, updating the targets
157 /** \todo handle += here, by appending to the last value as if a vector.
158 */
159 int readConfig( const std::string &fname, ///< [in] the config file name
160 bool reportFileNotFound = true ///< [in] [optiona] control whether a file not found is reported.
161 );
162
163 /// Check if a target has been set by the configuration
164 /**
165 * \returns true if the configuration set at least one value for this target
166 * \returns false if no value was set.
167 */
168 bool isSet( const std::string &name, ///< [in] the target name
169 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
170 );
171
172 /// Check if a target has been set by the configuration
173 /**
174 * \overload
175 *
176 * \returns true if the configuration set at least one value for this target
177 * \returns false if no value was set.
178 */
179 bool isSet( const std::string &name /**< [in] the target name */ );
180
181 /// Get the number of different values set for the specified config target
182 /**
183 * \returns the number of different values set for name.
184 */
185 int count( const std::string &name, ///< [in] the target name
186 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
187 );
188
189 /// Get the number of different values set for the specified config target
190 /**
191 * \overload
192 *
193 * \returns the number of different values set for name.
194 */
195 int count( const std::string &name /**< [in] the target name */ );
196
197 /// Get the command line verbosity count for this option.
198 /** E.g., -v ==> 1, -vv ==> 2, -vvv ==> 3, etc. Note that for this to work
199 * properly, this must be of type mx::argType::True.
200 *
201 * \returns the verbosity count.
202 */
203 int verbosity( const std::string &name, ///< [in] the target name
204 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
205 );
206
207 /// Get the command line verbosity count for this option.
208 /** E.g., -v ==> 1, -vv ==> 2, -vvv ==> 3, etc. Note that for this to work
209 * properly, this must be of type mx::argType::True.
210 *
211 * \overload
212 *
213 * \returns the verbosity count.
214 */
215 int verbosity( const std::string &name /**< [in] the target name */ );
216
217 /// Get the i-th value of the target, converted to the specified type
218 /** The supplied value is only altered if the config target was set, which preserves.
219 * default values.
220 *
221 * \retval 0 on success
222 * \retval -1 on error
223 */
224 template <typename typeT>
225 int get( typeT &v, ///< [out] the variable to store the value in, unaltered if not set.
226 const std::string &name, ///< [in] the config target name
227 size_t i, ///< [in] the number of config specification to get.
228 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
229 );
230
231 /// Get the i-th value of the target from the used set, converted to the specified type
232 /** The supplied value is only altered if the config target was set, which preserves.
233 * default values.
234 *
235 * \overload
236 *
237 * \retval 0 on success
238 * \retval -1 on error
239 */
240 template <typename typeT>
241 int get( typeT &v, ///< [out] the variable to store the value in
242 const std::string &name, ///< [in] the config target name
243 size_t i ///< [in] the number of config specification to get.
244 );
245
246 /// Get the final value of the target, converted to the specified type
247 /** The supplied value is only altered if the config target was set, which preserves.
248 * default values.
249 *
250 * \overload
251 *
252 * \retval 0 on success.
253 * \retval -1 on error.
254 */
255 template <typename typeT>
256 int get( typeT &v, ///< [out] the variable to store the value in
257 const std::string &name, ///< [in] the config target name
258 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
259 );
260
261 /// Get the final value of the target from the used set, converted to the specified type
262 /** The supplied value is only altered if the config target was set, which preserves.
263 * default values.
264 *
265 * \overload
266 *
267 * \retval 0 on success.
268 * \retval -1 on error.
269 */
270 template <typename typeT>
271 int get( typeT &v, ///< [out] the variable to store the value in
272 const std::string &name ///< [in] the config target name
273 );
274
275 /// Get the i-th value of the target, converted to the specified config target
276 /** The vector is only populated if the config target was set. If it is populated,
277 * it is cleared first. Thus if a vector filled with default values is passed
278 * in, it will only be overwritten if the user specified new values.
279 *
280 * \returns 0 on success
281 * \returns -1 on error
282 */
283 template <typename typeT>
284 int get( std::vector<typeT> &v, ///< [out] the vector to populate
285 const std::string &name, ///< [in] the config target name.
286 size_t i, ///< [in] the number of config specification to get.
287 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
288 );
289
290 /// Get the i-th value of the target, converted to the specified config target
291 /** The vector is only populated if the config target was set. If it is populated,
292 * it is cleared first. Thus if a vector filled with default values is passed
293 * in, it will only be overwritten if the user specified new values.
294 *
295 * \returns 0 on success
296 * \returns -1 on error
297 */
298 template <typename typeT>
299 int get( std::vector<typeT> &v, ///< [out] the vector to populate
300 const std::string &name, ///< [in] the config target name.
301 size_t i ///< [in] the number of config specification to get.
302 );
303
304 /// Get the i-th value of the target as a vector containing the specified type.
305 /** The vector is only populated if the config target was set. If it is populated,
306 * it is cleared first. Thus if a vector filled with default values is passed
307 * in, it will only be overwritten if the user specified new values.
308 *
309 * \retval 0 on success.
310 * \retval -1 on error.
311 */
312 template <typename typeT>
313 int get( std::vector<typeT> &v, ///< [out] the vector to populate
314 const std::string &name, ///< [in] the config target name.
315 std::unordered_map<std::string, configTarget> &targets ///< [in] the map of config targets to use
316 );
317
318 /// Get the final value of the target in the used set, as a vector containing the specified type.
319 /** The vector is only populated if the config target was set. If it is populated,
320 * it is cleared first. Thus if a vector filled with default values is passed
321 * in, it will only be overwritten if the user specified new values.
322 *
323 * \retval 0 on success.
324 * \retval -1 on error.
325 */
326 template <typename typeT>
327 int get( std::vector<typeT> &v, ///< [out] the vector to populate
328 const std::string &name ///< [in] the config target name.
329 );
330
331 /// Access operator, configures a value by calling get.
332 /**
333 * \retval 0 on success
334 * \retval -1 on error
335 */
336 template <typename typeT>
337 int
338 operator()( typeT &v, ///< [out] the variable to populate (either scalar or vector), will be unaltered if not set.
339 const std::string &name ///< [in] the config target name.
340 );
341
342 /// Configure a value from the unused map, using the iniFile key.
343 /**
344 * \retval 0 on success
345 * \retval -1 on error
346 */
347 template <typename typeT>
348 int
349 configUnused( typeT &v, ///< [out] the variable to populate (either scalar or vector), will be unaltered if not set.
350 const std::string &key ///< [in] the iniFile key for this target.
351 );
352
353 /// Configure a value from the unused map, using the section and keyword.
354 /**
355 * \retval 0 on success
356 * \retval -1 on error
357 */
358 template <typename typeT>
359 int
360 configUnused( typeT &v, ///< [out] the variable to populate (either scalar or vector), will be unaltered if not set.
361 const std::string &section, ///< [in] the section name for this target
362 const std::string &keyword ///< [in] the keyword for this target.
363 );
364
365 /// Get the unique sections in the unused config targets.
366 /**
367 * \retval 0 on success
368 * \retval -1 on error
369 */
370 int unusedSections( std::vector<std::string> &sections );
371
372 /// Check if a target has been set in the unused configuration
373 /**
374 * \returns true if the unused configuration set at least one value for this target
375 * \returns false if no value was set.
376 */
377 int isSetUnused( const std::string &name /**< [in] the target name */ );
378
379 /// Call an external logging function whenever a config value is accessed by get or operator().
380 /** Only called if this is not a nullptr (the default), otherwise no logging or reporting is done.
381 */
382 void ( *configLog )(
383 const std::string &name, ///< [in] The name of the config target.
384 const int &code, ///< [in] The type code from mx::typeDescription
385 const std::string &valueStr, ///< [in] The value in its string form as found in the configuration
386 const std::string &source ///< [in] The source of the value, either default, command line, or a path.
387 ){ nullptr };
388
389 /// Get the number of unknown options found during config processing.
391};
392
393template <typename typeT>
395 const std::string &name,
396 size_t i,
397 std::unordered_map<std::string, configTarget> &targets )
398{
399 targets[name].used = true; // This means this was checked.
400
401 if( !isSet( name, targets ) )
402 {
403 if( configLog )
404 {
405 configLog( name, meta::typeDescription<typeT>::code(), std::format( "{}", v ), "default" );
406 }
407
408 return 0;
409 }
410
411 if( targets[name].values.size() <= i )
412 {
413 return -1;
414 }
415
416 v = ioutils::stoT<typeT>( targets[name].values[i] );
417
418 // Log it here.
419 if( configLog )
420 {
421 if( m_sources )
422 {
423 configLog( name, meta::typeDescription<typeT>::code(), targets[name].values[i], targets[name].sources[i] );
424 }
425 else
426 {
427 configLog( name, meta::typeDescription<typeT>::code(), targets[name].values[i], "" );
428 }
429 }
430
431 return 0;
432}
433// explicits
434extern template int appConfigurator::get<char>( char &v,
435 const std::string &name,
436 size_t i,
437 std::unordered_map<std::string, configTarget> &targets );
438
439extern template int appConfigurator::get<signed char>( signed char &v,
440 const std::string &name,
441 size_t i,
442 std::unordered_map<std::string, configTarget> &targets );
443
444extern template int appConfigurator::get<short>( short &v,
445 const std::string &name,
446 size_t i,
447 std::unordered_map<std::string, configTarget> &targets );
448
449extern template int appConfigurator::get<int>( int &v,
450 const std::string &name,
451 size_t i,
452 std::unordered_map<std::string, configTarget> &targets );
453
454extern template int appConfigurator::get<long>( long &v,
455 const std::string &name,
456 size_t i,
457 std::unordered_map<std::string, configTarget> &targets );
458
459extern template int appConfigurator::get<long long>( long long &v,
460 const std::string &name,
461 size_t i,
462 std::unordered_map<std::string, configTarget> &targets );
463
464extern template int appConfigurator::get<unsigned char>( unsigned char &v,
465 const std::string &name,
466 size_t i,
467 std::unordered_map<std::string, configTarget> &targets );
468
469extern template int appConfigurator::get<unsigned short>( unsigned short &v,
470 const std::string &name,
471 size_t i,
472 std::unordered_map<std::string, configTarget> &targets );
473
474extern template int appConfigurator::get<unsigned int>( unsigned int &v,
475 const std::string &name,
476 size_t i,
477 std::unordered_map<std::string, configTarget> &targets );
478
479extern template int appConfigurator::get<unsigned long>( unsigned long &v,
480 const std::string &name,
481 size_t i,
482 std::unordered_map<std::string, configTarget> &targets );
483
484extern template int appConfigurator::get<unsigned long long>( unsigned long long &v,
485 const std::string &name,
486 size_t i,
487 std::unordered_map<std::string, configTarget> &targets );
488
489extern template int appConfigurator::get<float>( float &v,
490 const std::string &name,
491 size_t i,
492 std::unordered_map<std::string, configTarget> &targets );
493
494extern template int appConfigurator::get<double>( double &v,
495 const std::string &name,
496 size_t i,
497 std::unordered_map<std::string, configTarget> &targets );
498
499extern template int appConfigurator::get<long double>( long double &v,
500 const std::string &name,
501 size_t i,
502 std::unordered_map<std::string, configTarget> &targets );
503
504#ifdef HASQUAD
505extern template int appConfigurator::get<__float128>( __float128 &v,
506 const std::string &name,
507 size_t i,
508 std::unordered_map<std::string, configTarget> &targets );
509#endif
510
511extern template int appConfigurator::get<bool>( bool &v,
512 const std::string &name,
513 size_t i,
514 std::unordered_map<std::string, configTarget> &targets );
515
516extern template int appConfigurator::get<std::string>( std::string &v,
517 const std::string &name,
518 size_t i,
519 std::unordered_map<std::string, configTarget> &targets );
520
521//+++++++++++++++++++++++++++++++++++++
522
523template <typename typeT>
524int appConfigurator::get( typeT &v, const std::string &name, size_t i )
525{
526 return get( v, name, i, m_targets );
527}
528
529// explicits
530extern template int appConfigurator::get<char>( char &v, const std::string &name, size_t i );
531
532extern template int appConfigurator::get<signed char>( signed char &v, const std::string &name, size_t i );
533
534extern template int appConfigurator::get<short>( short &v, const std::string &name, size_t i );
535
536extern template int appConfigurator::get<int>( int &v, const std::string &name, size_t i );
537
538extern template int appConfigurator::get<long>( long &v, const std::string &name, size_t i );
539
540extern template int appConfigurator::get<long long>( long long &v, const std::string &name, size_t i );
541
542extern template int appConfigurator::get<unsigned char>( unsigned char &v, const std::string &name, size_t i );
543
544extern template int appConfigurator::get<unsigned short>( unsigned short &v, const std::string &name, size_t i );
545
546extern template int appConfigurator::get<unsigned int>( unsigned int &v, const std::string &name, size_t i );
547
548extern template int appConfigurator::get<unsigned long>( unsigned long &v, const std::string &name, size_t i );
549
550extern template int
551appConfigurator::get<unsigned long long>( unsigned long long &v, const std::string &name, size_t i );
552
553extern template int appConfigurator::get<float>( float &v, const std::string &name, size_t i );
554
555extern template int appConfigurator::get<double>( double &v, const std::string &name, size_t i );
556
557extern template int appConfigurator::get<long double>( long double &v, const std::string &name, size_t i );
558
559#ifdef HASQUAD
560extern template int appConfigurator::get<__float128>( __float128 &v, const std::string &name, size_t i );
561#endif
562
563extern template int appConfigurator::get<bool>( bool &v, const std::string &name, size_t i );
564
565extern template int appConfigurator::get<std::string>( std::string &v, const std::string &name, size_t i );
566
567//+++++++++++++++++++++++++++++++++++++
568
569template <typename typeT>
570int appConfigurator::get( typeT &v, const std::string &name, std::unordered_map<std::string, configTarget> &targets )
571{
572 targets[name].used = true; // This means this was checked.
573
574 if( !isSet( name, targets ) )
575 {
576 if( configLog )
577 {
578 configLog( name, meta::typeDescription<typeT>::code(), std::format( "{}", v ), "default" );
579 }
580
581 return 0;
582 }
583
584 int i = targets[name].values.size() - 1;
585
586 if( i < 0 )
587 return -1;
588
589 return get( v, name, i, targets );
590}
591// explicits:
592
593extern template int
594appConfigurator::get<char>( char &v, const std::string &name, std::unordered_map<std::string, configTarget> &targets );
595
596extern template int appConfigurator::get<signed char>( signed char &v,
597 const std::string &name,
598 std::unordered_map<std::string, configTarget> &targets );
599
600extern template int appConfigurator::get<short>( short &v,
601 const std::string &name,
602 std::unordered_map<std::string, configTarget> &targets );
603
604extern template int
605appConfigurator::get<int>( int &v, const std::string &name, std::unordered_map<std::string, configTarget> &targets );
606
607extern template int
608appConfigurator::get<long>( long &v, const std::string &name, std::unordered_map<std::string, configTarget> &targets );
609
610extern template int appConfigurator::get<long long>( long long &v,
611 const std::string &name,
612 std::unordered_map<std::string, configTarget> &targets );
613
614extern template int appConfigurator::get<unsigned char>( unsigned char &v,
615 const std::string &name,
616 std::unordered_map<std::string, configTarget> &targets );
617
618extern template int appConfigurator::get<unsigned short>( unsigned short &v,
619 const std::string &name,
620 std::unordered_map<std::string, configTarget> &targets );
621
622extern template int appConfigurator::get<unsigned int>( unsigned int &v,
623 const std::string &name,
624 std::unordered_map<std::string, configTarget> &targets );
625
626extern template int appConfigurator::get<unsigned long>( unsigned long &v,
627 const std::string &name,
628 std::unordered_map<std::string, configTarget> &targets );
629
630extern template int appConfigurator::get<unsigned long long>( unsigned long long &v,
631 const std::string &name,
632 std::unordered_map<std::string, configTarget> &targets );
633
634extern template int appConfigurator::get<float>( float &v,
635 const std::string &name,
636 std::unordered_map<std::string, configTarget> &targets );
637
638extern template int appConfigurator::get<double>( double &v,
639 const std::string &name,
640 std::unordered_map<std::string, configTarget> &targets );
641
642extern template int appConfigurator::get<long double>( long double &v,
643 const std::string &name,
644 std::unordered_map<std::string, configTarget> &targets );
645
646#ifdef HASQUAD
647extern template int appConfigurator::get<__float128>( __float128 &v,
648 const std::string &name,
649 std::unordered_map<std::string, configTarget> &targets );
650#endif
651
652extern template int
653appConfigurator::get<bool>( bool &v, const std::string &name, std::unordered_map<std::string, configTarget> &targets );
654
655extern template int appConfigurator::get<std::string>( std::string &v,
656 const std::string &name,
657 std::unordered_map<std::string, configTarget> &targets );
658
659//+++++++++++++++++++++++++++++++++++++
660
661template <typename typeT>
662int appConfigurator::get( typeT &v, const std::string &name )
663{
664 return get( v, name, m_targets );
665}
666// explicits:
667
668extern template int appConfigurator::get<char>( char &v, const std::string &name );
669
670extern template int appConfigurator::get<signed char>( signed char &v, const std::string &name );
671
672extern template int appConfigurator::get<short>( short &v, const std::string &name );
673
674extern template int appConfigurator::get<int>( int &v, const std::string &name );
675
676extern template int appConfigurator::get<long>( long &v, const std::string &name );
677
678extern template int appConfigurator::get<long long>( long long &v, const std::string &name );
679
680extern template int appConfigurator::get<unsigned char>( unsigned char &v, const std::string &name );
681
682extern template int appConfigurator::get<unsigned short>( unsigned short &v, const std::string &name );
683
684extern template int appConfigurator::get<unsigned int>( unsigned int &v, const std::string &name );
685
686extern template int appConfigurator::get<unsigned long>( unsigned long &v, const std::string &name );
687
688extern template int appConfigurator::get<unsigned long long>( unsigned long long &v, const std::string &name );
689
690extern template int appConfigurator::get<float>( float &v, const std::string &name );
691
692extern template int appConfigurator::get<double>( double &v, const std::string &name );
693
694extern template int appConfigurator::get<long double>( long double &v, const std::string &name );
695
696#ifdef HASQUAD
697extern template int appConfigurator::get<__float128>( __float128 &v, const std::string &name );
698#endif
699
700extern template int appConfigurator::get<bool>( bool &v, const std::string &name );
701
702extern template int appConfigurator::get<std::string>( std::string &v, const std::string &name );
703
704//+++++++++++++++++++++++++++++++++++++
705template <typename typeT>
706int appConfigurator::get( std::vector<typeT> &v,
707 const std::string &name,
708 size_t i,
709 std::unordered_map<std::string, configTarget> &targets )
710{
711 targets[name].used = true; // This means this was checked.
712
713 if( !isSet( name, targets ) )
714 {
715 if( configLog )
716 {
717 configLog( name, meta::typeDescription<typeT>::code(), "[need a vector to string]", "default" );
718 }
719
720 return 0;
721 }
722
723 if( targets[name].values.size() <= i )
724 return -1;
725
726 std::string s;
727
728 s = ioutils::stoT<std::string>( targets[name].values[i] );
729
730 // if( get<std::string>(s, name, i, targets) < 0) return -1;
731
732 // Case that s was set to be empty.
733 if( s.size() == 0 )
734 {
735 if( configLog )
736 {
737 if( m_sources )
738 {
739 configLog( name, meta::typeDescription<typeT>::code(), "", targets[name].sources[i] );
740 }
741 else
742 {
744 }
745 }
746
747 v.clear(); // We clear the vector passed as default
748 return 0;
749 }
750
751 size_t st;
752 size_t com;
753
754 st = 0;
755
756 while( st < s.size() && ::isspace( static_cast<unsigned char>( s[st] ) ) )
757 ++st;
758
759 com = s.find( ',', st );
760
761 v.clear();
762
763 while( com != std::string::npos )
764 {
765 v.push_back( ioutils::stoT<typeT>( s.substr( st, com - st ) ) );
766 st = com + 1;
767 while( st < s.size() && ::isspace( static_cast<unsigned char>( s[st] ) ) )
768 ++st;
769
770 com = s.find( ',', st );
771 }
772 v.push_back( ioutils::stoT<typeT>( s.substr( st, s.size() - st ) ) );
773
774 // Log it here.
775 if( configLog )
776 {
777 if( m_sources )
778 {
779 configLog( name, meta::typeDescription<typeT>::code(), targets[name].values[i], targets[name].sources[i] );
780 }
781 else
782 {
783 configLog( name, meta::typeDescription<typeT>::code(), targets[name].values[i], "" );
784 }
785 }
786
787 return 0;
788}
789// explicits:
790
791extern template int appConfigurator::get<char>( std::vector<char> &v,
792 const std::string &name,
793 size_t i,
794 std::unordered_map<std::string, configTarget> &targets );
795
796extern template int appConfigurator::get<signed char>( std::vector<signed char> &v,
797 const std::string &name,
798 size_t i,
799 std::unordered_map<std::string, configTarget> &targets );
800
801extern template int appConfigurator::get<short>( std::vector<short> &v,
802 const std::string &name,
803 size_t i,
804 std::unordered_map<std::string, configTarget> &targets );
805
806extern template int appConfigurator::get<int>( std::vector<int> &v,
807 const std::string &name,
808 size_t i,
809 std::unordered_map<std::string, configTarget> &targets );
810
811extern template int appConfigurator::get<long>( std::vector<long> &v,
812 const std::string &name,
813 size_t i,
814 std::unordered_map<std::string, configTarget> &targets );
815
816extern template int appConfigurator::get<long long>( std::vector<long long> &v,
817 const std::string &name,
818 size_t i,
819 std::unordered_map<std::string, configTarget> &targets );
820
821extern template int appConfigurator::get<unsigned char>( std::vector<unsigned char> &v,
822 const std::string &name,
823 size_t i,
824 std::unordered_map<std::string, configTarget> &targets );
825
826extern template int appConfigurator::get<unsigned short>( std::vector<unsigned short> &v,
827 const std::string &name,
828 size_t i,
829 std::unordered_map<std::string, configTarget> &targets );
830
831extern template int appConfigurator::get<unsigned int>( std::vector<unsigned int> &v,
832 const std::string &name,
833 size_t i,
834 std::unordered_map<std::string, configTarget> &targets );
835
836extern template int appConfigurator::get<unsigned long>( std::vector<unsigned long> &v,
837 const std::string &name,
838 size_t i,
839 std::unordered_map<std::string, configTarget> &targets );
840
841extern template int appConfigurator::get<unsigned long long>( std::vector<unsigned long long> &v,
842 const std::string &name,
843 size_t i,
844 std::unordered_map<std::string, configTarget> &targets );
845
846extern template int appConfigurator::get<float>( std::vector<float> &v,
847 const std::string &name,
848 size_t i,
849 std::unordered_map<std::string, configTarget> &targets );
850
851extern template int appConfigurator::get<double>( std::vector<double> &v,
852 const std::string &name,
853 size_t i,
854 std::unordered_map<std::string, configTarget> &targets );
855
856extern template int appConfigurator::get<long double>( std::vector<long double> &v,
857 const std::string &name,
858 size_t i,
859 std::unordered_map<std::string, configTarget> &targets );
860
861#ifdef HASQUAD
862extern template int appConfigurator::get<__float128>( std::vector<__float128> &v,
863 const std::string &name,
864 size_t i,
865 std::unordered_map<std::string, configTarget> &targets );
866#endif
867
868extern template int appConfigurator::get<bool>( std::vector<bool> &v,
869 const std::string &name,
870 size_t i,
871 std::unordered_map<std::string, configTarget> &targets );
872
873extern template int appConfigurator::get<std::string>( std::vector<std::string> &v,
874 const std::string &name,
875 size_t i,
876 std::unordered_map<std::string, configTarget> &targets );
877
878//+++++++++++++++++++++++++++++++++++++
879
880template <typename typeT>
881int appConfigurator::get( std::vector<typeT> &v, const std::string &name, size_t i )
882{
883 return get( v, name, i, m_targets );
884}
885
886// explicits:
887
888extern template int appConfigurator::get<char>( std::vector<char> &v, const std::string &name, size_t i );
889
890extern template int appConfigurator::get<signed char>( std::vector<signed char> &v, const std::string &name, size_t i );
891
892extern template int appConfigurator::get<short>( std::vector<short> &v, const std::string &name, size_t i );
893
894extern template int appConfigurator::get<int>( std::vector<int> &v, const std::string &name, size_t i );
895
896extern template int appConfigurator::get<long>( std::vector<long> &v, const std::string &name, size_t i );
897
898extern template int appConfigurator::get<long long>( std::vector<long long> &v, const std::string &name, size_t i );
899
900extern template int
901appConfigurator::get<unsigned char>( std::vector<unsigned char> &v, const std::string &name, size_t i );
902
903extern template int
904appConfigurator::get<unsigned short>( std::vector<unsigned short> &v, const std::string &name, size_t i );
905
906extern template int
907appConfigurator::get<unsigned int>( std::vector<unsigned int> &v, const std::string &name, size_t i );
908
909extern template int
910appConfigurator::get<unsigned long>( std::vector<unsigned long> &v, const std::string &name, size_t i );
911
912extern template int
913appConfigurator::get<unsigned long long>( std::vector<unsigned long long> &v, const std::string &name, size_t i );
914
915extern template int appConfigurator::get<float>( std::vector<float> &v, const std::string &name, size_t i );
916
917extern template int appConfigurator::get<double>( std::vector<double> &v, const std::string &name, size_t i );
918
919extern template int appConfigurator::get<long double>( std::vector<long double> &v, const std::string &name, size_t i );
920
921#ifdef HASQUAD
922extern template int appConfigurator::get<__float128>( std::vector<__float128> &v, const std::string &name, size_t i );
923#endif
924
925extern template int appConfigurator::get<bool>( std::vector<bool> &v, const std::string &name, size_t i );
926
927extern template int appConfigurator::get<std::string>( std::vector<std::string> &v, const std::string &name, size_t i );
928
929//+++++++++++++++++++++++++++++++++++++
930template <typename typeT>
931int appConfigurator::get( std::vector<typeT> &v,
932 const std::string &name,
933 std::unordered_map<std::string, configTarget> &targets )
934{
935 targets[name].used = true; // This means this was checked.
936
937 if( !isSet( name, targets ) )
938 {
939 if( configLog )
940 {
941 configLog( name, meta::typeDescription<typeT>::code(), "[need a vector to string]", "default" );
942 }
943 return 0;
944 }
945 int i = targets[name].values.size() - 1;
946
947 if( i < 0 )
948 return -1;
949
950 return get( v, name, i, targets );
951}
952// explicits:
953
954extern template int appConfigurator::get<char>( std::vector<char> &v,
955 const std::string &name,
956 std::unordered_map<std::string, configTarget> &targets );
957
958extern template int appConfigurator::get<signed char>( std::vector<signed char> &v,
959 const std::string &name,
960 std::unordered_map<std::string, configTarget> &targets );
961
962extern template int appConfigurator::get<short>( std::vector<short> &v,
963 const std::string &name,
964 std::unordered_map<std::string, configTarget> &targets );
965
966extern template int appConfigurator::get<int>( std::vector<int> &v,
967 const std::string &name,
968 std::unordered_map<std::string, configTarget> &targets );
969
970extern template int appConfigurator::get<long>( std::vector<long> &v,
971 const std::string &name,
972 std::unordered_map<std::string, configTarget> &targets );
973
974extern template int appConfigurator::get<long long>( std::vector<long long> &v,
975 const std::string &name,
976 std::unordered_map<std::string, configTarget> &targets );
977
978extern template int appConfigurator::get<unsigned char>( std::vector<unsigned char> &v,
979 const std::string &name,
980 std::unordered_map<std::string, configTarget> &targets );
981
982extern template int appConfigurator::get<unsigned short>( std::vector<unsigned short> &v,
983 const std::string &name,
984 std::unordered_map<std::string, configTarget> &targets );
985
986extern template int appConfigurator::get<unsigned int>( std::vector<unsigned int> &v,
987 const std::string &name,
988 std::unordered_map<std::string, configTarget> &targets );
989
990extern template int appConfigurator::get<unsigned long>( std::vector<unsigned long> &v,
991 const std::string &name,
992 std::unordered_map<std::string, configTarget> &targets );
993
994extern template int appConfigurator::get<unsigned long long>( std::vector<unsigned long long> &v,
995 const std::string &name,
996 std::unordered_map<std::string, configTarget> &targets );
997
998extern template int appConfigurator::get<float>( std::vector<float> &v,
999 const std::string &name,
1000 std::unordered_map<std::string, configTarget> &targets );
1001
1002extern template int appConfigurator::get<double>( std::vector<double> &v,
1003 const std::string &name,
1004 std::unordered_map<std::string, configTarget> &targets );
1005
1006extern template int appConfigurator::get<long double>( std::vector<long double> &v,
1007 const std::string &name,
1008 std::unordered_map<std::string, configTarget> &targets );
1009
1010#ifdef HASQUAD
1011extern template int appConfigurator::get<__float128>( std::vector<__float128> &v,
1012 const std::string &name,
1013 std::unordered_map<std::string, configTarget> &targets );
1014#endif
1015
1016extern template int appConfigurator::get<bool>( std::vector<bool> &v,
1017 const std::string &name,
1018 std::unordered_map<std::string, configTarget> &targets );
1019
1020extern template int appConfigurator::get<std::string>( std::vector<std::string> &v,
1021 const std::string &name,
1022 std::unordered_map<std::string, configTarget> &targets );
1023
1024//+++++++++++++++++++++++++++++++++++++
1025
1026template <typename typeT>
1027int appConfigurator::get( std::vector<typeT> &v, const std::string &name )
1028{
1029 return get( v, name, m_targets );
1030}
1031// explicits:
1032
1033extern template int appConfigurator::get<char>( std::vector<char> &v, const std::string &name );
1034
1035extern template int appConfigurator::get<signed char>( std::vector<signed char> &v, const std::string &name );
1036
1037extern template int appConfigurator::get<short>( std::vector<short> &v, const std::string &name );
1038
1039extern template int appConfigurator::get<int>( std::vector<int> &v, const std::string &name );
1040
1041extern template int appConfigurator::get<long>( std::vector<long> &v, const std::string &name );
1042
1043extern template int appConfigurator::get<long long>( std::vector<long long> &v, const std::string &name );
1044
1045extern template int appConfigurator::get<unsigned char>( std::vector<unsigned char> &v, const std::string &name );
1046
1047extern template int appConfigurator::get<unsigned short>( std::vector<unsigned short> &v, const std::string &name );
1048
1049extern template int appConfigurator::get<unsigned int>( std::vector<unsigned int> &v, const std::string &name );
1050
1051extern template int appConfigurator::get<unsigned long>( std::vector<unsigned long> &v, const std::string &name );
1052
1053extern template int appConfigurator::get<unsigned long long>( std::vector<unsigned long long> &v,
1054 const std::string &name );
1055
1056extern template int appConfigurator::get<float>( std::vector<float> &v, const std::string &name );
1057
1058extern template int appConfigurator::get<double>( std::vector<double> &v, const std::string &name );
1059
1060extern template int appConfigurator::get<long double>( std::vector<long double> &v, const std::string &name );
1061
1062#ifdef HASQUAD
1063extern template int appConfigurator::get<__float128>( std::vector<__float128> &v, const std::string &name );
1064#endif
1065
1066extern template int appConfigurator::get<bool>( std::vector<bool> &v, const std::string &name );
1067
1068extern template int appConfigurator::get<std::string>( std::vector<std::string> &v, const std::string &name );
1069
1070//+++++++++++++++++++++++++++++++++++++
1071
1072template <typename typeT>
1073int appConfigurator::operator()( typeT &v, const std::string &name )
1074{
1075 return get( v, name, m_targets );
1076}
1077
1078// explicits:
1079
1080extern template int appConfigurator::operator()<char>( char &v, const std::string &name );
1081
1082extern template int appConfigurator::operator()<signed char>( signed char &v, const std::string &name );
1083
1084extern template int appConfigurator::operator()<short>( short &v, const std::string &name );
1085
1086extern template int appConfigurator::operator()<int>( int &v, const std::string &name );
1087
1088extern template int appConfigurator::operator()<long>( long &v, const std::string &name );
1089
1090extern template int appConfigurator::operator()<long long>( long long &v, const std::string &name );
1091
1092extern template int appConfigurator::operator()<unsigned char>( unsigned char &v, const std::string &name );
1093
1094extern template int appConfigurator::operator()<unsigned short>( unsigned short &v, const std::string &name );
1095
1096extern template int appConfigurator::operator()<unsigned int>( unsigned int &v, const std::string &name );
1097
1098extern template int appConfigurator::operator()<unsigned long>( unsigned long &v, const std::string &name );
1099
1100extern template int appConfigurator::operator()<unsigned long long>( unsigned long long &v, const std::string &name );
1101
1102extern template int appConfigurator::operator()<float>( float &v, const std::string &name );
1103
1104extern template int appConfigurator::operator()<double>( double &v, const std::string &name );
1105
1106extern template int appConfigurator::operator()<long double>( long double &v, const std::string &name );
1107
1108#ifdef HASQUAD
1109extern template int appConfigurator::operator()<__float128>( __float128 &v, const std::string &name );
1110#endif
1111
1112extern template int appConfigurator::operator()<bool>( bool &v, const std::string &name );
1113
1114extern template int appConfigurator::operator()<std::string>( std::string &v, const std::string &name );
1115
1116//+++++++++++++++++++++++++++++++++++++
1117
1118template <typename typeT>
1119int appConfigurator::configUnused( typeT &v, const std::string &key )
1120{
1121 return get( v, key, m_unusedConfigs );
1122}
1123
1124extern template int appConfigurator::configUnused<char>( char &v, const std::string &key );
1125
1126extern template int appConfigurator::configUnused<signed char>( signed char &v, const std::string &key );
1127
1128extern template int appConfigurator::configUnused<short>( short &v, const std::string &key );
1129
1130extern template int appConfigurator::configUnused<int>( int &v, const std::string &key );
1131
1132extern template int appConfigurator::configUnused<long>( long &v, const std::string &key );
1133
1134extern template int appConfigurator::configUnused<long long>( long long &v, const std::string &key );
1135
1136extern template int appConfigurator::configUnused<unsigned char>( unsigned char &v, const std::string &key );
1137
1138extern template int appConfigurator::configUnused<unsigned short>( unsigned short &v, const std::string &key );
1139
1140extern template int appConfigurator::configUnused<unsigned int>( unsigned int &v, const std::string &key );
1141
1142extern template int appConfigurator::configUnused<unsigned long>( unsigned long &v, const std::string &key );
1143
1144extern template int appConfigurator::configUnused<unsigned long long>( unsigned long long &v, const std::string &key );
1145
1146extern template int appConfigurator::configUnused<float>( float &v, const std::string &key );
1147
1148extern template int appConfigurator::configUnused<double>( double &v, const std::string &key );
1149
1150extern template int appConfigurator::configUnused<long double>( long double &v, const std::string &key );
1151
1152#ifdef HASQUAD
1153extern template int appConfigurator::configUnused<__float128>( __float128 &v, const std::string &key );
1154#endif
1155
1156extern template int appConfigurator::configUnused<bool>( bool &v, const std::string &key );
1157
1158extern template int appConfigurator::configUnused<std::string>( std::string &v, const std::string &key );
1159//+++++++++++++++++++++++++++++++++++++
1160
1161template <typename typeT>
1162int appConfigurator::configUnused( typeT &v, const std::string &section, const std::string &keyword )
1163{
1164 return configUnused( v, iniFile::makeKey( section, keyword ) );
1165}
1166
1167extern template int
1168appConfigurator::configUnused<char>( char &v, const std::string &section, const std::string &keyword );
1169
1170extern template int
1171appConfigurator::configUnused<signed char>( signed char &v, const std::string &section, const std::string &keyword );
1172
1173extern template int
1174appConfigurator::configUnused<short>( short &v, const std::string &section, const std::string &keyword );
1175
1176extern template int
1177appConfigurator::configUnused<int>( int &v, const std::string &section, const std::string &keyword );
1178
1179extern template int
1180appConfigurator::configUnused<long>( long &v, const std::string &section, const std::string &keyword );
1181
1182extern template int
1183appConfigurator::configUnused<long long>( long long &v, const std::string &section, const std::string &keyword );
1184
1185extern template int appConfigurator::configUnused<unsigned char>( unsigned char &v,
1186 const std::string &section,
1187 const std::string &keyword );
1188
1189extern template int appConfigurator::configUnused<unsigned short>( unsigned short &v,
1190 const std::string &section,
1191 const std::string &keyword );
1192
1193extern template int
1194appConfigurator::configUnused<unsigned int>( unsigned int &v, const std::string &section, const std::string &keyword );
1195
1196extern template int appConfigurator::configUnused<unsigned long>( unsigned long &v,
1197 const std::string &section,
1198 const std::string &keyword );
1199
1200extern template int appConfigurator::configUnused<unsigned long long>( unsigned long long &v,
1201 const std::string &section,
1202 const std::string &keyword );
1203
1204extern template int
1205appConfigurator::configUnused<float>( float &v, const std::string &section, const std::string &keyword );
1206
1207extern template int
1208appConfigurator::configUnused<double>( double &v, const std::string &section, const std::string &keyword );
1209
1210extern template int
1211appConfigurator::configUnused<long double>( long double &v, const std::string &section, const std::string &keyword );
1212
1213#ifdef HASQUAD
1214extern template int
1215appConfigurator::configUnused<__float128>( __float128 &v, const std::string &section, const std::string &keyword );
1216#endif
1217
1218extern template int
1219appConfigurator::configUnused<bool>( bool &v, const std::string &section, const std::string &keyword );
1220
1221extern template int
1222appConfigurator::configUnused<std::string>( std::string &v, const std::string &section, const std::string &keyword );
1223
1224//+++++++++++++++++++++++++++++++++++++
1225
1226/// A simple config file writing function, useful for testing.
1227/** Write a config file to the path specified by `fname`. Each of the parameters
1228 * is a vector, and each component is required of each vector.
1229 *
1230 * Example:
1231 *\code
1232 writeConfigFile( "/tmp/test.conf", {"", "", "sect1", "sect1", "sect2", "sect2"},
1233 {"key0", "key1", "key2", "key3", "key4", "key5"},
1234 {"val0", "val1", "val2", "val3", "val4", "val5"} );
1235
1236 *\endcode
1237 * results in the file `/tmp/test.conf` containing
1238 * \verbatim
1239 key0=val0
1240 key1=val1
1241
1242 [sect1]
1243 key2=val2
1244 key3=val3
1245
1246 [sect2]
1247 key4=val4
1248 key5=val5
1249
1250 * \endverbatim
1251 *
1252 * No error checking is done.
1253 */
1254void writeConfigFile( const std::string &fname, ///< [in] the complete path for the output file.
1255 const std::vector<std::string> &sections, ///< [in] sections, one per config value
1256 const std::vector<std::string> &keywords, ///< [in] keywords, one per config value
1257 const std::vector<std::string> &values ///< [in] the values
1258);
1259
1260} // namespace app
1261} // namespace mx
1262
1263#endif // app_appConfigurator_hpp
void writeConfigFile(const std::string &fname, const std::vector< std::string > &sections, const std::vector< std::string > &keywords, const std::vector< std::string > &values)
A simple config file writing function, useful for testing.
int(* appConfiguratorParser)(iniFile &parser, const std::string &filename)
Optional parser override used to deterministically test appConfigurator parser failures.
A command line parser.
Targets for the configuration manager, and utiltities.
typeT stoT(const std::string &str, error_t *errc=nullptr)
Convert a string to a numerical value.
Declares and defines an ini-style (toml) file parser.
Declarations of some libarary wide utilities.
The mxlib c++ namespace.
Definition mxlib.hpp:37
Class to manage a set of configurable values, and read their values from config/ini files and the com...
std::unordered_map< std::string, configTarget > m_targets
The targets are stored in an unordered_map for fast access by key.
int readConfig(const std::string &fname, bool reportFileNotFound=true)
Read and parse a config/ini file, updating the targets.
int operator()(typeT &v, const std::string &name)
Access operator, configures a value by calling get.
void add(const configTarget &tgt)
Add a configTarget.
bool m_sources
Flag controlling whether or not to record config sources.
int get(typeT &v, const std::string &name, size_t i, std::unordered_map< std::string, configTarget > &targets)
Get the i-th value of the target, converted to the specified type.
std::vector< std::string > nonOptions
Non-option arguments from the command line.
int configUnused(typeT &v, const std::string &key)
Configure a value from the unused map, using the iniFile key.
void(* configLog)(const std::string &name, const int &code, const std::string &valueStr, const std::string &source)
Call an external logging function whenever a config value is accessed by get or operator().
int verbosity(const std::string &name, std::unordered_map< std::string, configTarget > &targets)
Get the command line verbosity count for this option.
std::unordered_map< std::string, configTarget >::iterator targetIterator
Iterator for the targets unordered_map.
int isSetUnused(const std::string &name)
Check if a target has been set in the unused configuration.
bool isSet(const std::string &name, std::unordered_map< std::string, configTarget > &targets)
Check if a target has been set by the configuration.
void clear()
Clear the containers and free up the associated memory.
int unusedSections(std::vector< std::string > &sections)
Get the unique sections in the unused config targets.
int numUnknownOptions()
Get the number of unknown options found during config processing.
std::list< configTarget > clOnlyTargets
Targets which are only for the command line are stored separately in a list.
int count(const std::string &name, std::unordered_map< std::string, configTarget > &targets)
Get the number of different values set for the specified config target.
void parseCommandLine(int argc, char **argv, const std::string &oneTarget="")
Parse the command line, updating the targets.
int nAdded
Running count of options added, used to track order.
std::unordered_map< std::string, configTarget > m_unusedConfigs
std::list< configTarget >::iterator clOnlyTargetIterator
Iterator for the clOnlyTargets list.
A configuration target.
A wrapper for the ini functions.
Definition iniFile.hpp:47
static std::string makeKey(const std::string &section, const std::string &name)
Return a key generated from the section and name.
Definition iniFile.hpp:57
static constexpr int code()
Returns a unique numeric code for this type.