ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
inifilefeeder.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_variables of the \aliblong.
4///
5/// Copyright 2013-2026 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace variables {
9
10//==================================================================================================
11/// Adapter type between class #"IniFile" and class #"Configuration".
12/// INI-file contents usually are fed in with bootstrapping an application and optionally be
13/// written out when an application ends (to populate empty INI-files or add new variables to
14/// existing ones). For this, an instance of this type is to be created locally each time. In other
15/// words, no instance of this type needs to be kept in memory during the life-span of an
16/// application.
17/// @see Chapter #"alib_variables_external_ini" of the Programmer's Manual of camp \alib_variables.
18/// @throws alib::variables::Exceptions::ErrorWritingFile \I{CLANGDUMMY}
19//==================================================================================================
21 //=========================================== Internals ==========================================
22 protected:
23 /// The configuration to work with. Set with construction.
25
26 /// The priority to use to define variables. Set with construction.
28
29 /// The INI-file. Created with methods #"ImportStart" and #"ExportStart".
30 IniFile* iniFile = nullptr;
31
32 /// Implements overloaded methods #".ImportSection(const String&)".
33 /// @param section The section to import
34 /// @return The number of variables imported.
36 int importSection( IniFile::Section& section );
37
38
39 //========================================= Public Fields ========================================
40 public:
41 /// The desired maximum width of the INI-file. Defaults to <c>100</c>.
42 /// This value is used with utility method #".AddResourcedSectionComments(ResourcePool&)".
43 int LineWidth = 100;
44
45 /// The prefix that is used for comment lines of sections or variables that have been
46 /// added 'in code' (variables that have not been read from the file).
47 /// Comments that were read from the file preserve their prefix.
48 /// If comments including one of the valid prefixes are added to a variable or section
49 /// 'in code', such prefix is preserved.
51
52 /// This flag may be read after invoking the method #"ExportStart", which will try to
53 /// read the file first. If the file could not be opened or is empty, this flag is set.
54 /// The flag may be used to decide, for example, if a file-comment or section comments
55 /// should be generated.
57
58
59 //==================================== Constructors/destructor ===================================
60 public:
61 /// Constructor.
62 /// @param pConfiguration Stored in the field #"configuration".
63 /// @param pPriority Stored in the field #".priority". Defaults to #"Priority::ConfigFile".
64 ///
65 IniFileFeeder( Configuration& pConfiguration, Priority pPriority= Priority::ConfigFile )
66 : configuration(pConfiguration)
67 , priority (pPriority) {}
68
69 /// Virtual destructor. #"alib_mod_assert;Raises an ALib warning" in debug-compilations,
70 /// if the internal INI-file was not disposed before deletion. Disposal is made with methods
71 /// #"ImportEnd" and ExportEnd.
72 virtual ~IniFileFeeder() {
73 #if ALIB_DEBUG && !ALIB_DEBUG_ASSERTION_PRINTABLES
74 ALIB_ASSERT_WARNING(iniFile == nullptr, "VARIABLES",
75 "Export or import sequence not completed before deleting the INI-file.\n"
76 "Filename of previous sequence: {}", iniFile->FileName )
77 delete iniFile;
78 #endif
79
80 }
81
82 //=========================================== Interface ==========================================
83 /// Imports all entries in the section named \p{sectionName} in the underlying INI-file into
84 /// the configuration.
85 /// @param sectionName The name of the section to import.
86 /// @return The number of variables imported.
88 int ImportSection( const String& sectionName );
89
90 /// Imports all entries in the section named \p{sectionName} in the underlying INI-file into
91 /// the configuration. This special version of the method accepts parameter \p{typeName}
92 /// and hence declares the variables in case they have not been declared, yet.
93 ///
94 /// \note
95 /// This method is useful to load a section of variables of the same type with a) avoiding to
96 /// set preset string and b) with the advantage that a using code may use
97 /// #"Variable::Try(const String&);Variable::Try" to find the variable without declaring
98 /// it.<br>
99 /// This method may be used, for example, with camp \alib_expressions to declare nested
100 /// expressions to an #"StandardRepository".
101 /// @param sectionName The name of the section to import.
102 /// @param typeName The type of the variable to declare.
103 /// @return The number of variables imported.
105 int ImportSection( const String& sectionName, const String& typeName );
106
107 /// Imports all entries found INI-file into the configuration. Variables which are already
108 /// declared and have a lower priority definition, will be set with the value found.
109 /// Otherwise, a #"PresetImportString(StringEscaper);preset string" is set for the
110 /// variable.
111 /// @return The number of variables imported.
113 int ImportAll();
114
115 /// Creates the internal \p{iniFile} instance.
116 /// @param path The filepath to the INI-file.
117 /// @return The number of entries read. (The result of method #"IniFile::Read;*".)
118 int ImportStart( const Path& path ) {
119 if( iniFile != nullptr ) {
120 ALIB_ASSERT_WARNING(iniFile == nullptr, "VARIABLES",
121 "Export or import sequence not completed before starting a new one.\n"
122 "Previous filename: ", iniFile->FileName )
123 delete iniFile;
124 }
125 iniFile= new IniFile();
126 int qtyEntries= 0;
127 #if ALIB_CAMP
128 try { qtyEntries= iniFile->Read(path); } catch (Exception& ) {}
129 #else
130 iniFile->Read(path);
131 #endif
132 return qtyEntries;
133 }
134
135 /// Creates the internal \p{iniFile} instance.
136 /// @param path The filepath to the INI-file.
137 /// @return The number of entries read. (The result of method #"IniFile::Read;*".)
138 int ExportStart( const Path& path ) {
139 int qtyEntries= 0;
140 #if ALIB_CAMP
141 try { qtyEntries= ImportStart(path); }
142 catch (Exception& e) {
144 throw;
145 }
146 #else
147 qtyEntries= ImportStart(path);
148 #endif
149 DidNotExistOrWasEmpty= (qtyEntries == 0);
150 return qtyEntries;
151 }
152
153 /// Closes and deletes the internal \p{iniFile} instance.
154 void ImportEnd() {
155 if(iniFile == nullptr) {
156 ALIB_ERROR( "VARIABLES", "No INI-file loaded when trying to end import/export." )
157 return;
158 }
159 delete iniFile;
160 iniFile= nullptr;
161 }
162
163 /// Closes and deletes the internal \p{iniFile} instance without writing an opened INI-file.
164 void ExportEnd() { ImportEnd(); }
165
166 /// Writes the contents of the internal \p{iniFile} instance created with #"ExportStart" into
167 /// an (optionally) different file and then deletes the instance.
168 /// @param path The file path for writing.
169 void ExportEnd(const Path& path ) {
170 if(iniFile == nullptr) {
171 ALIB_ERROR( "VARIABLES", "No INI-file loaded when trying to import data." )
172 return;
173 }
174 iniFile->Write(path);
175 delete iniFile;
176 iniFile= nullptr;
177 }
178
179
180 /// Writes the given variable to the internal INI-file.
181 /// If an INI-file was previously loaded, only those variables which are not existing in the
182 /// INI-file are written. This method can thus be used to "populate" an empty INI-file with
183 /// variables and their resourced or hard-coded default values and this way present all
184 /// configurable options to an end-user.
185 ///
186 /// Furthermore, a user can specify the word "writeback" (respectively what is resourced
187 /// with to token <c>"CFGIniWB"</c>) to force overwriting the INI-file contents with the current
188 /// value of the variable.
189 ///
190 /// @param var The variable to export.
191 /// @return \c true if the variable either did not exist yet in the INI-file or if it existed
192 /// and the write-back mechanism was in place. \c false otherwise.
194 bool Export( const Variable& var );
195
196 /// Creates a variable cursor with the given \p{cfg} and \p{path} and passes it to overloaded
197 /// method #"Export(const" Variable&).
198 /// @param path The path of the variable to export.
199 /// @return \c true if the variable either did not exist yet in the INI-file or if it existed
200 /// and the write-back mechanism was in place. \c false otherwise.
201 bool Export(const String& path) {
202 auto cursor= configuration.Root();
203 auto remainder= cursor.GoTo(path);
204 if( remainder.IsNotEmpty() ) {
205 ALIB_WARNING("VARIABLES", "Configuration variable path \"{}\" to export not found.",
206 path)
207 return false;
208 }
209 return Export( Variable(cursor) );
210 }
211
212
213 /// Writes all variables below the given #"StringTree::Cursor;*"
214 /// of the #"Configuration" into the #"iniFile", previously created with #"ExportStart".
215 /// If an INI-file was previously loaded, only those variables which are not existing in the
216 /// INI-file are written.
217 /// This method can thus be used to "populate" an empty INI-file with default values and
218 /// this way present all configurable options to an end-user.
219 ///
220 /// Furthermore, a user can specify the word "writeback" (respectively what is resourced
221 /// with to token <c>"CFGIniWB"</c>) to force overwriting the INI-file contents with the current
222 /// value of the variable.
223 ///
224 /// @param cursor A cursor into the configuration's #"StringTree".
225 /// @param directChildrenOnly If \c true, only the direct children of this cursor are written
226 /// as variables. Defaults to \c false.
227 /// @return The number of variables exported. A negative value on error.
229 int ExportSubTree( Configuration::Cursor cursor, bool directChildrenOnly= false );
230
231 /// Invokes #".ExportSubTree(Configuration::Cursor, bool)" by creating a cursor from the given
232 /// \p{path}
233 /// @param path The path to the subtree (or single variable) to use.
234 /// @param directChildrenOnly If \c true, only the direct children of this \p{path} are written
235 /// as variables. Defaults to \c false.
236 /// @return The number of variables exported. A negative value on error.
237 int ExportSubTree( const String& path, bool directChildrenOnly= false ) {
238 auto cursor= configuration.Root();
239 auto remainder= cursor.GoTo(path);
240 if( remainder.IsNotEmpty() ) {
241 return -1;
242 }
243
244 return ExportSubTree( cursor, directChildrenOnly );
245 }
246
247 /// Searches the entry of the internal INI-file that represents the given \p{variable}
248 /// @param variable The variable to search in the INI-file.
249 /// @return The section and entry if found. If not found, the second member of the pair is
250 /// emtpy.
252 IniFile::Handle SearchEntry ( const Variable& variable );
253
254 /// Searches the entry of the internal INI-file that represents the given variable determined
255 /// by parameter \p{path}
256 /// @param path The path of the variable to search in the INI-file.
257 /// @return The section and entry if found. If not found, the second member of the pair is
258 /// emtpy.
260 IniFile::Handle SearchEntry ( const String& path );
261
262 /// This method may be used to set the #"config_IniFile_writebackflag;writeback flag"
263 /// of an entry in the associated INI-file. The flag is only set if the entry was
264 /// programmatically created (usually with one of the <b>Export</b>-methods of this class) and
265 /// if it was not present in the INI-file before.
266 /// @see Chapter #"alib_variables_external_session" of the Programmer's Manual of module
267 /// \alib_variables_nl.
268 /// @param path The path of the variable to export.
269 /// @return \c true if the variable did exist and was newly added to the INI-file, \c false
270 /// otherwise.
272 bool SetWriteBackFlag( const String& path );
273
274 /// Invokes overloaded method #".SetWriteBackFlag(const String& path)".
275 /// @param var The variable to modifiy.
276 /// @return \c true if the variable did exist and was newly added to the INI-file, \c false
277 /// otherwise.
279 bool SetWriteBackFlag( const Variable& var );
280
281 #if ALIB_RESOURCES
282 /// This is a utility function that reads section comments from
283 /// #"alib_mod_resources;externalized string resources".
284 ///
285 /// All sections of the underlying INI-file are processed, but resourced comments
286 /// are only added in the case that a section's comment string is \c nulled. This is not the
287 /// case if a section was read from an INI-file, as even if no comments were given,
288 /// the field is empty but not \e nulled. In other words, only sections that have been
289 /// programmatically added during the run of software are changed<br>
290 /// This approach allows a user to remove the comments, without the software restoring them.
291 ///
292 /// The resource names are assembled from given \p{resourceNamePrefix} and the section name.
293 /// The resource strings found are processed using the method
294 /// #"Paragraphs.AddMarked(const BoxedObjects&)".
295 /// This allows using text macros like <b>'\@HL'</b> to format the text.
296 ///
297 /// \see
298 /// Field #".LineWidth", which is respected when formatting comment lines.
299 ///
300 /// @param resourcePool The resource pool to use.
301 /// @param resourceCategory The category of the resourced comments.
302 /// @param resourceNamePrefix A prefix of the resource name.
303 /// @return The number of section comments written.
304 /// This is useful to detect if the INI-file needs to be written.
306 int AddResourcedSectionComments( ResourcePool& resourcePool,
307 const NString& resourceCategory,
308 const NString& resourceNamePrefix );
309
310 /// This is a shortcut to the overloaded method, accepting a #"ResourceHolder"
311 /// instead of parameters \p{resourcePool} and \p{resourceCategory}.
312 /// @param resourceHolder A container holding a resource pool and a fixed category.
313 /// @param resourceNamePrefix A prefix of the resource name.
314 /// @return The number of section comments written.
315 /// This is useful to detect if the INI-file needs to be written.
317 const NString& resourceNamePrefix ) {
318 return AddResourcedSectionComments( resourceHolder.GetResourcePool(),
319 resourceHolder.ResourceCategory,
320 resourceNamePrefix );
321 }
322 #endif
323
324 /// Allows access to the internal INI-file object created with either method #".ImportStart" or
325 /// #".ExportStart". In debug-compilations, this method asserts that an INI-file was opened.
326 /// In release-compilations, a non-existing INI-file leads to undefined behavior.
327 /// @return The currently opened INI-File.
329 ALIB_ASSERT_ERROR( iniFile != nullptr, "VARIABLES",
330 "No INI-file loaded when trying to access it." )
331 return *iniFile;
332 }
333
334}; // class IniFileFeeder
335
336
337} // namespace alib[::config]
338
339/// Type alias in namespace #"%alib".
341
342} // namespace [alib]
#define ALIB_DLL
#define A_CHAR(STR)
#define ALIB_WARNING(domain,...)
#define ALIB_ASSERT_WARNING(cond, domain,...)
#define ALIB_ERROR(domain,...)
#define ALIB_EXPORT
#define ALIB_ASSERT_ERROR(cond, domain,...)
const Enum & Type() const
Definition exception.cpp:92
int ImportStart(const Path &path)
void ExportEnd()
Closes and deletes the internal iniFile instance without writing an opened INI-file.
int AddResourcedSectionComments(ResourcePool &resourcePool, const NString &resourceCategory, const NString &resourceNamePrefix)
int ExportSubTree(Configuration::Cursor cursor, bool directChildrenOnly=false)
IniFile * iniFile
The INI-file. Created with methods #"ImportStart" and #"ExportStart".
bool Export(const String &path)
bool SetWriteBackFlag(const String &path)
Configuration & configuration
The configuration to work with. Set with construction.
int ImportSection(const String &sectionName)
void ImportEnd()
Closes and deletes the internal iniFile instance.
int importSection(IniFile::Section &section)
Priority priority
The priority to use to define variables. Set with construction.
int ExportStart(const Path &path)
int AddResourcedSectionComments(resources::ResourceHolder &resourceHolder, const NString &resourceNamePrefix)
bool Export(const Variable &var)
int ExportSubTree(const String &path, bool directChildrenOnly=false)
IniFile::Handle SearchEntry(const Variable &variable)
IniFileFeeder(Configuration &pConfiguration, Priority pPriority=Priority::ConfigFile)
void ExportEnd(const Path &path)
@ ErrorOpeningFile
File not found when reading.
Definition vmeta.hpp:19
Definition alox.cpp:14
strings::TString< nchar > NString
Type alias in namespace #"%alib".
Definition string.hpp:2174
resources::ResourcePool ResourcePool
Type alias in namespace #"%alib".
variables::Variable Variable
Type alias in namespace #"%alib".
strings::TString< character > String
Type alias in namespace #"%alib".
Definition string.hpp:2165
system::Path Path
Type alias in namespace #"%alib".
Definition path.hpp:417
exceptions::Exception Exception
Type alias in namespace #"%alib".
variables::IniFileFeeder IniFileFeeder
Type alias in namespace #"%alib".
A pair of pointers to a section and an entry in the section.
Definition inifile.hpp:165
A section of the INI-file.
Definition inifile.hpp:148