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