ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
configuration.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_config of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_CONFIG_CONFIGURATION
9#define HPP_ALIB_CONFIG_CONFIGURATION 1
10
11#if !defined (HPP_ALIB_ENUMS_BITWISE)
12 #include "alib/enums/bitwise.hpp"
13#endif
14
15ALIB_ASSERT_MODULE(CONFIGURATION)
16
17#if !defined(HPP_ALIB_STRINGS_SUBSTRING)
19#endif
20
21#if !defined(HPP_ALIB_STRINGS_NUMBERFORMAT)
23#endif
24
25#if !defined(HPP_ALIB_CONFIG_VARIABLE)
27#endif
28#if !defined(HPP_ALIB_CONFIG_PLUGINS)
30#endif
31#if !defined(HPP_ALIB_LANG_PLUGINS)
32 #include "alib/lang/plugins.hpp"
33#endif
34#if !defined(HPP_ALIB_CONFIG_INMEMORY_PLUGIN)
36#endif
37
38
39
40namespace alib { namespace config {
41
42// #################################################################################################
43// class Configuration
44// #################################################################################################
45
46/** ************************************************************************************************
47 * This class is a container for objects of type
48 * \ref alib::config::ConfigurationPlugin "ConfigurationPlugin",
49 * and provides a single user interface to query configuration data
50 * from those.
51 *
52 * By default, all category and variable names are case insensitive. This is at least true for the
53 * default plug-ins delivered with \alib.
54 *
55 * Variables by default can contain other variables, which are recursively substituted
56 * by this method. For more information about the (adjustable) syntax, see
57 * \ref alib_config_substitution "Variable Substitution".
58 *
59 * See documentation of namespace #alib::config for more information on \alib
60 * external configuration variables.
61 **************************************************************************************************/
62class Configuration : public lang::PluginContainer<ConfigurationPlugin, Priorities>
63{
64 // #############################################################################################
65 // internal fields
66 // #############################################################################################
67 protected:
68
69 // #############################################################################################
70 // public fields
71 // #############################################################################################
72 public:
73 /**
74 * Values considered to indicate "true". Defaults to
75 * { "1", "true", "t", "yes", "y", "on", "ok" }.
76 * See methods #IsTrue.
77 *
78 * Application specific values (e.g. localization languages) might be added by publicly
79 * accessing this field and adding new values (or removing existing).
80 */
81 std::vector<String> TrueValues;
82
83 /** Number format definition used to read and write int and float values. */
85
86 /**
87 * The start string to identify substitution variables.
88 * Defaults to single character \c '$'. If a string is set, i.e. \c "${", then field
89 * #SubstitutionVariableEnd may be set accordingly, i.e. \c "}"
90 */
92
93 /**
94 * The end of a substitution variables.
95 * If this field is set, then field #SubstitutionVariableDelimiters is ignored. If this
96 * field is nullptr (the default) or empty, it is ignored and characters in field
97 * #SubstitutionVariableDelimiters are used to identify the end of the variable.
98 */
100
101 /**
102 * The delimiters used to identify the end of a substitutable variable.
103 * If field #SubstitutionVariableEnd is not empty, this field is ignored. Otherwise, all
104 * characters defined in this string are used to identify the end of a substitution
105 * variable.
106 */
107 CString SubstitutionVariableDelimiters= A_CHAR(" $@,.;:\"\'+-*/\\ยง%&()[]{}<>=?'`~#");
108
109 /** A temporary variable to be reused (allocate once pattern). */
111
112 // #############################################################################################
113 // Constructor/destructor
114 // #############################################################################################
115 public:
116 /** ****************************************************************************************
117 * Constructs a Configuration. If \p{addDefaultPlugins} is \c true, registers the initial
118 * plug-ins as follows
119 *
120 * Priority | Plug-in Type
121 * --------------------------------------------------------|------------------------------
122 * \alib{config;Priorities;Priorities::ProtectedValues} | \alib{config;InMemoryPlugin}
123 * \alib{config;Priorities;Priorities::Environment} | \alib{config;Environment}
124 * \alib{config;Priorities;Priorities::CLI} | \alib{config;CLIArgs}
125 * \alib{config;Priorities;Priorities::DefaultValues} | \alib{config;InMemoryPlugin}
126 *
127 * @param addPlugins If \b Yes the default plugins are added.
128 ******************************************************************************************/
130
131 /** ****************************************************************************************
132 * Sets the command line arguments for default plug-in \alib{config;CLIArgs}.
133 * This method should be called for instances of this class after construction.
134 *
135 * \note
136 * For the standard configuration objects found in class \alib{lang;Camp},
137 * this method is automatically invoked by function \alib{Bootstrap}.
138 *
139 * \note On the Windows platform, the Microsoft compiler provides the global variables
140 * <em>__argc</em> and <em>__argv</em> (respectively <em>__wargv</em> for wide
141 * character binaries. These variables a can be used if this method is invoked
142 * outside of the <em>main()</em> method.
143 *
144 * @param argc Parameter usually taken from <em>standard C</em> \c main() method
145 * (the number of arguments in \p{argv}).
146 * Defaults to 0.
147 * @param argv Parameter usually taken from <em>standard C</em> \c main() method
148 * (pointer to a zero-terminated list of zero-terminated strings comprising
149 * the command line arguments).
150 * Defaults to nullptr.
151 ******************************************************************************************/
152 void SetCommandLineArgs( int argc =0, const nchar** argv =nullptr )
153 {
154 if ( argc > 1 )
155 {
156 CLIArgs* cliParameters= GetPluginTypeSafe<CLIArgs>();
157 ALIB_ASSERT_ERROR( cliParameters, "CONFIG", "No CLIArgs plugin registered" )
158 cliParameters->SetArgs( argc, reinterpret_cast<const void**>( argv ), false );
159 }
160 }
161
162 /** ****************************************************************************************
163 * Variant of method #SetCommandLineArgs, accepting command line arguments of
164 * type \c wchar.
165 *
166 * @param argc Parameter usually taken from <em>standard C</em> \c main() method
167 * (the number of arguments in \p{argv}).
168 * @param argv The command line arguments as a zero-terminated list of pointers to
169 * zero-terminated \c wchar_c strings.
170 ******************************************************************************************/
171 void SetCommandLineArgs( int argc, const wchar_t **argv )
172 {
173 if ( argc > 1 )
174 {
175 CLIArgs* cliParameters= GetPluginTypeSafe<CLIArgs>();
176 ALIB_ASSERT_ERROR( cliParameters, "CONFIG", "No CLIArgs plugin registered" )
177 cliParameters->SetArgs( argc, reinterpret_cast<const void**>( argv ), true );
178 }
179 }
180
181 // #############################################################################################
182 // interface
183 // #############################################################################################
184 public:
185
186 #if defined(ALIB_DOX)
187 /** ****************************************************************************************
188 * This method loads all variables of the given enum type in case no placeholders
189 * are contained in their name and a default value is given with the declaraition.
190 *
191 * With that they become stored in this configuration's default plug-in and a later
192 * invocation of #FetchFromDefault may be used to move those to a plug-in that persitently
193 * stores them, for example an INI-file.
194 *
195 * The goal of this approach is to have all (most) variables presented in an external
196 * configuration file that is automatically created on a software's first run - regardless
197 * if that first run used the variables or not.
198 *
199 * @tparam TEnum Enumeration type equipped with \ref alib_enums_records "ALib Enum Records"
200 * of type \alib{config;VariableDecl}.
201 ******************************************************************************************/
202 template<typename TEnum>
203 inline
205 #else
206 template<typename TEnum>
207 ATMP_VOID_IF( EnumRecords<TEnum>::template AreOfType<VariableDecl>() )
209 {
210 for( auto recordIt= EnumRecords<TEnum>::begin()
211 ; recordIt!= EnumRecords<TEnum>::end ()
212 ; ++ recordIt )
213 {
214 VariableDecl decl( recordIt.Enum() );
215 if( decl.DefaultValue.IsNotEmpty()
216 && decl.EnumElementName.IndexOf('%') < 0) // no replacements
217 {
218 tempVar.Declare( decl, nullptr );
219 tempVar.SetConfig (this);
220 tempVar.SetPriority( loadImpl( tempVar, false ) );
221
222 if ( tempVar.Priority() == Priorities::NONE )
224 }
225 }
226 }
227 #endif
228
229 /** ****************************************************************************************
230 * This method fetches all values from a plug-in of priority
231 * \alib{config;Priorities;Priorities::DefaultValues}, which are not present in the given plug-in
232 * \p{dest} and stores them in that.
233 * This is useful to collect all generated default values and store them in a user's
234 * configuration file. This way, the user can identify configurable options easily.
235 *
236 * \note
237 * Applications might want to copy only a portion of the default values (of a section)
238 * to not blow up a user's configuration. To achieve this, a custom method to fetch
239 * selected values has to be implemented. In this respect, this method is a very simple
240 * default and its source might be used as a jump start.
241 *
242 * @param dest The destination plug-in.
243 * @param section Optional string denoting a section to fetch.
244 * Defaults to \b NullString().
245 * @return The number of variables fetched.
246 ******************************************************************************************/
248 int FetchFromDefault( ConfigurationPlugin& dest,
249 const String& section= NullString() );
250
251
252 /** ****************************************************************************************
253 * Utility method that checks if a given value represents boolean \b true.
254 * Uses field #TrueValues. Comparisons are made case insensitive.
255 *
256 * @param value The value to check
257 *
258 * @return Returns \c true, if the value represents 'true', \c false if not.
259 ******************************************************************************************/
261 bool IsTrue( const String& value );
262
263 /** ****************************************************************************************
264 * Receives and optionally creates configuration variable.
265 *
266 * If the variable was not found and \alib{config;Variable::DefaultValue}
267 * in \p{variable} is set, the method adds the value to a plug-in of priority
268 * \alib{config;Priorities;Priorities::DefaultValues},
269 * (respectively to the plug-in found at or below \b DefaultValues).
270 * For the conversion of the value, field
271 * \alib{config;ConfigurationPlugin::StringConverter} of field a plug-in of priority
272 * \b DefaultValues, is used.
273 *
274 * If no plug-in at or below priority \b DefaultValues is found, then the declared default
275 * value is added to the variable using the default implementation of
276 * \alib{config;XTernalizer::LoadFromString}.
277 *
278 * @param variable The variable to receive.
279 *
280 * @returns The priority of the configuration plug-in that provided the result.
281 * \c 0 if not found.
282 ******************************************************************************************/
284 Priorities Load( Variable& variable );
285
286 /** ****************************************************************************************
287 * Writes the variable into one of the plug-ins registered with this configuration object.
288 * The plug-ins are looped in descending order of priority, until a first plug-in
289 * confirms the variable to be written.
290 *
291 * The first (most highly prioritized) plug-in to start the loop with, is defined by
292 * field \alib{config;Variable::Priority} of the given \p{variable}.
293 *
294 * If this is unset (\alib{config;Priorities;Priorities::NONE}), which is the default value of the field
295 * for freshly declared variable objects, the starting priority value of the loop is
296 * \b detected.
297 *
298 * Detection is made by searching the variable in the plug-ins prior to storing it.
299 * The search order is likewise by priority, starting with the highest.
300 * If the variable was not found, \alib{config;Priorities;Priorities::DefaultValues}
301 * is chosen. Usually the writing loop then will also already end there,
302 * because standard configuration sets have a write-enabled in-memory plug-in at
303 * that priority.
304 *
305 * If the variable was found in the plug-in of priority
306 * \alib{config;Priorities;Priorities::ProtectedValues}, the method stops without storing anything.
307 *
308 *
309 * This approach of storing variables, supports various use cases very nicely.
310 * Some of the frequent ones shall be named here:
311 * - By setting the field to \alib{config;Priorities;Priorities::DefaultValues}, the value
312 * becomes just a default and does not overwrite externally specified values.
313 * - Leaving the field to its uninitialized state \alib{config;Priorities;Priorities::NONE},
314 * allows to store the variable in the plug-in that it was originally read from,
315 * or - if not stored already - in default values.
316 * - Setting the field to \alib{config;Priorities;Priorities::ProtectedValues} allows to protect the
317 * variable value in respect to external manipulation.
318 * - Setting the field to \alib{config;Priorities;Priorities::ProtectedValues}<c> - 1</c>,
319 * allows to store the variable just in the plug-in with highest possible priority.
320 * - Finally, an application specific reason might motivate a caller of this method to
321 * preset a distinct priority value prior to invoking this method. For example, a variable
322 * might be related to a second one. If the priority of the second one is
323 * known, that priority might be set prior to invoking this message, to have both
324 * variables potentially stored in the same plug-in.
325 *
326 * The method returns the priority of the configuration plug-in that the value was written
327 * to. This value is as well stored in field \alib{config;Variable::Priority} of the given
328 * object.
329 *
330 * A result of \alib{config;Priorities;Priorities::NONE} indicates that the variable was not written.
331 * This might only happen if
332 * - the default plug-in of this configuration is not configured or does not support
333 * writing variables,
334 * - field \p{Priority} of the variable was set below \alib{config;Priorities;Priorities::DefaultValues}
335 * (but greater than \alib{config;Priorities;Priorities::NONE}),
336 * - the \b detected priority was \alib{config;Priorities;Priorities::ProtectedValues}.
337 * (In this case, obviously the application does not want to allow changes and writing the
338 * variable into a different plug-in has no effect.
339 * This way, such variables also do not appear in a user's configuration
340 * in the case that on program termination, new default values are copied there.)
341 *
342 * Optional parameter \p{externalizedValue} allows to provide a string that is parsed
343 * by the storing plug-in to reset the variable's values prior to writing.
344 *
345 * \see Default variables are often to be stored with the termination of a process.
346 * For this, see method #FetchFromDefault.
347 *
348 * @param variable The variable object.
349 * @param externalizedValue Optional externalized value string. If given, the variable
350 * is set prior to writing.
351 *
352 * @returns The priority of the configuration plug-in that the value was written to.
353 ******************************************************************************************/
355 Priorities Store( Variable& variable, const String& externalizedValue= nullptr );
356
357 /** ****************************************************************************************
358 * Convenience method that stores the \p{variable} with priority
359 * \alib{config;Priorities;Priorities::DefaultValues}.
360 *
361 * The variable value is determined as follows:
362 * - If optional parameter \p{externalizedValue} is provided and not \e nulled, the values
363 * are loaded from that string.
364 * - Otherwise, if the variable has no values set but \alib{config;Variable::DefaultValue}
365 * is not \e nulled then values are loaded from this field.
366 * - If all is unset (the variable values, parameter \p{externalizedValue} and field
367 * \alib{config;Variable::DefaultValue}), then the unset variable is stored, which results
368 * in removing an existing default value from the configuration.
369 *
370 *
371 * @param variable The variable object.
372 * @param externalizedValue Optional externalized value string. If given, the variable
373 * is set prior to writing.
374 * @returns The result of \alib{config;Configuration::Store}.
375 ******************************************************************************************/
377 Priorities StoreDefault( Variable& variable, const String& externalizedValue= nullptr );
378
379 /** ****************************************************************************************
380 * Convenience method that stores the \p{variable} with priority
381 * \alib{config;Priorities;Priorities::ProtectedValues}.
382 *
383 * The variable value is determined as follows:
384 * - If optional parameter \p{externalizedValue} is provided and not \e nulled, the values
385 * are loaded from that string.
386 * - Otherwise, if the variable has no values set but \alib{config;Variable::DefaultValue}
387 * is not \e nulled then values are loaded from this field.
388 * - If all is unset (the variable values, parameter \p{externalizedValue} and field
389 * \alib{config;Variable::DefaultValue}), then the unset variable is stored, which
390 * results in removing an existing protection value from the configuration.
391 *
392 * @param variable The variable object.
393 * @param externalizedValue Optional externalized value string. If given, the variable
394 * is set prior to writing.
395 * @returns The result of \alib{config;Configuration::Store}.
396 ******************************************************************************************/
398 Priorities Protect( Variable& variable, const String& externalizedValue= nullptr );
399
400
401 /** ****************************************************************************************
402 * Convenience method to set values in \p{variable} according to the provided string.
403 * For the conversion of the "externalized" string, method
404 * \ref alib::config::XTernalizer::LoadFromString "XTernalizer::LoadFromString"
405 * of field \alib{config;ConfigurationPlugin::StringConverter}
406 * of a plug-in of priority \alib{config;Priorities;Priorities::DefaultValues}, is used.
407 *
408 * @param variable The variable object.
409 * @param externalizedValue The new value to write.
410 *
411 * @returns The result of \alib{config;Variable::Size} after parsing.
412 ******************************************************************************************/
414 integer LoadFromString( Variable& variable, const String& externalizedValue );
415
416
417
418 // #############################################################################################
419 // Iteration
420 // #############################################################################################
421 public:
422 /** ****************************************************************************************
423 * Iterator interface class, returned by method #GetIterator.
424 ******************************************************************************************/
426 {
427 public:
428 /** The actual variable loaded with successful call to #Next. */
430
431 /** Virtual destructor. */
432 virtual ~Iterator()
433 {}
434
435 /**
436 * Searches and loads the next variable from the iterated section. On success, the
437 * variable data is stored in #Actual.
438 * @return \c true, if a next variable was found. \c false otherwise.
439 */
440 virtual bool Next() = 0;
441
442 /**
443 * Resets this iterator to work on a different section of the same configuration.
444 * @param sectionName The name of the section to iterate.
445 */
446 virtual void ResetToSection( const String& sectionName ) = 0;
447 };
448
449
450 /** ****************************************************************************************
451 * Creates an iterator object to return all variables within a section.
452 *
453 * The iterator object returned, needs to be deleted by the caller.
454 *
455 * @param sectionName The name of the section to iterate.
456 *
457 * @returns The result of \alib{config;Variable::Size} after parsing.
458 ******************************************************************************************/
460 Iterator* GetIterator( const String& sectionName );
461
462 // #############################################################################################
463 // internal methods
464 // #############################################################################################
465 protected:
466 /** ****************************************************************************************
467 * Implementation of method #Load.
468 *
469 * @param variable The variable to get.
470 * @param substitute If \c false, automatic variable substitutions are suppressed.
471 *
472 * @return Zero if the variable was not found. Otherwise it returns the priority of the
473 * (first) plug-in that contained the variable.
474 ******************************************************************************************/
476 Priorities loadImpl( Variable& variable, bool substitute );
477
478}; // class Configuration
479
480} // namespace alib[::config]
481
482/// Type alias in namespace \b alib.
484
485} // namespace [alib]
486
487
488
489#endif // HPP_ALIB_CONFIG_CONFIGURATION
void SetArgs(int argc, const void **argv=nullptr, bool areWideChar=false)
virtual void ResetToSection(const String &sectionName)=0
ALIB_API integer LoadFromString(Variable &variable, const String &externalizedValue)
void SetCommandLineArgs(int argc, const wchar_t **argv)
ALIB_API Priorities Load(Variable &variable)
std::vector< String > TrueValues
alib::NumberFormat NumberFormat
ALIB_API Priorities Store(Variable &variable, const String &externalizedValue=nullptr)
ALIB_API bool IsTrue(const String &value)
ALIB_API Iterator * GetIterator(const String &sectionName)
ALIB_API Priorities Protect(Variable &variable, const String &externalizedValue=nullptr)
ALIB_API Priorities StoreDefault(Variable &variable, const String &externalizedValue=nullptr)
ALIB_API int FetchFromDefault(ConfigurationPlugin &dest, const String &section=NullString())
void SetCommandLineArgs(int argc=0, const nchar **argv=nullptr)
ALIB_API Priorities loadImpl(Variable &variable, bool substitute)
const String & DefaultValue() const
Definition variable.hpp:597
void SetPriority(Priorities priority)
Definition variable.hpp:628
ALIB_API Variable & Declare(const VariableDecl &declaration, const Box &replacements)
Definition variable.cpp:77
Priorities Priority() const
Definition variable.hpp:617
void SetConfig(Configuration *config)
Definition variable.hpp:477
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define A_CHAR(STR)
#define ATMP_VOID_IF(Cond)
Definition tmp.hpp:52
#define ALIB_API
Definition alib.hpp:538
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
Definition alib.cpp:57
config::Variable Variable
Type alias in namespace alib.
Definition variable.hpp:839
constexpr String NullString()
Definition string.hpp:2498
config::Configuration Configuration
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
static constexpr ForwardIterator end()
Definition records.hpp:434