Line data Source code
1 : /** \file iniFile.hpp
2 : * \author Jared R. Males
3 : * \brief Declares and defines an ini-style (toml) file parser
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 iniFile_hpp
29 : #define iniFile_hpp
30 :
31 : #include <unordered_map>
32 :
33 : #include "ini.hpp"
34 :
35 : namespace mx
36 : {
37 : namespace app
38 : {
39 :
40 : /// A wrapper for the ini functions.
41 : /** Places results of the ini parser in an unordered map, with keys of "section=name", and value
42 : * strings containing the value of the config item.
43 : *
44 : * \ingroup mxApp
45 : */
46 : struct iniFile
47 : {
48 : typedef std::unordered_map<std::string, std::string> nameMapT; ///< the unordered map type used for storing values.
49 :
50 : nameMapT names; ///< The map of section=name keys to values.
51 :
52 : /// Return a key generated from the section and name.
53 : /** Constructs the key as "section=name".
54 : *
55 : * \returns the created key.
56 : */
57 973 : static std::string makeKey( const std::string §ion, ///< [in] The section for the key
58 : const std::string &name ///< [in] the name for the key
59 : )
60 : {
61 973 : return section + "=" + name;
62 : }
63 :
64 : /// Parse a key into its section and name consituents.
65 : /** Requires that `=` be present.
66 : *
67 : * \returns 0 on success
68 : * \returns -1 on error, if no `=` found.
69 : */
70 5 : static int parseKey( std::string §ion, ///< [out] the section extracted from the key
71 : std::string &name, ///< [out] the name extracted from the key
72 : const std::string &key ///< [in] th key to parse.
73 : )
74 : {
75 5 : size_t eq = key.find( '=', 0 );
76 :
77 5 : if( eq == std::string::npos )
78 0 : return -1;
79 :
80 5 : section = key.substr( 0, eq );
81 :
82 5 : name = key.substr( eq + 1 );
83 :
84 5 : return 0;
85 : }
86 :
87 : /// Calls the inih parse function with this->handler.
88 : /** This returns the result of the ini_parse function.
89 : *
90 : * \returns 0 on success
91 : * \returns >0 is the line number of the first parsing error
92 : * \returns -1 on file open error
93 : * \return -2 on memory allocation error
94 : */
95 37 : int parse( const std::string &fname /**< [in] the full path of the file*/ )
96 : {
97 37 : return ini_parse( fname.c_str(), handler, this );
98 : }
99 :
100 : /// Insert a config value. Appends if the key already exists in the map.
101 : /** \todo need error checking.
102 : *
103 : * \returns 0 on success
104 : * \returns -1 on error.
105 : */
106 130 : int insert( const char *section, ///< [in] The section for the key
107 : const char *name, ///< [in] the name for the key
108 : const char *value ///< [in] the value to insert
109 : )
110 : {
111 390 : std::string nkey = makeKey( section, name );
112 :
113 130 : names[nkey]; // Inserts with empty value if doesn't exist, otherwise does nothing.
114 :
115 130 : names[nkey] += value; // This is just an update to the existing value.
116 :
117 130 : return 0;
118 130 : }
119 :
120 : /// Config entry handler for the parser.
121 : /** Calls insert, and returns its result. Any non-zero return will cause ini_parse to report the current
122 : * line number as an error.
123 : *
124 : * \returns 1 on success
125 : * \returns 0 on error
126 : */
127 130 : static int handler( void *user, ///< [in] a pointer to this.
128 : const char *section, ///< [in] the section of the config entry
129 : const char *name, ///< [in] the name of the config entry
130 : const char *value ///< [in] the value of the config entry
131 : )
132 : {
133 130 : iniFile *iF = static_cast<iniFile *>( user );
134 130 : return ( iF->insert( section, name, value ) == 0 );
135 : }
136 :
137 : /// Get the number of entries for the given section and name.
138 : /** Is either 1 or 0, depending on if this cconfig key exists.
139 : *
140 : * \returns the number of entries for the section=name key.
141 : */
142 607 : size_t count( const std::string §ion, ///< [in] The section for the key
143 : const std::string &name ///< [in] the name for the key
144 : )
145 : {
146 607 : return names.count( makeKey( section, name ) );
147 : }
148 :
149 : /// Erase the entry for the given section and name.
150 : /**
151 : * \returns 0 on sucess
152 : * \returns -1 if no section=name entry in the map.
153 : */
154 115 : int erase( const std::string §ion, ///< [in] The section for the key
155 : const std::string &name ///< [in] the name for the key
156 : )
157 : {
158 115 : if( names.erase( makeKey( section, name ) ) > 0 )
159 115 : return 0;
160 : else
161 0 : return -1;
162 : }
163 :
164 : /// Get the value associated with this section=name pair.
165 : /**
166 : * \returns the value if the section=name key exists
167 : * \returns and empty string if the section=name key does not exist.
168 : */
169 115 : std::string operator()( const std::string §ion, ///< [in] The section for the key
170 : const std::string &name ///< [in] the name for the key
171 : )
172 : {
173 115 : std::string key = makeKey( section, name );
174 115 : if( names.count( key ) > 0 )
175 : {
176 115 : return names[key];
177 : }
178 : else
179 : {
180 0 : return std::string( "" );
181 : }
182 115 : }
183 :
184 : /// Get the value associated with this name with an empty section.
185 : /**
186 : * \returns the value if the section=name key exists, with section empty
187 : * \returns and empty string if the section=name key does not exist, with section empty.
188 : */
189 : std::string operator()( const std::string &name /**< [in] the name for the key*/ )
190 : {
191 : return operator()( "", name );
192 : }
193 : };
194 :
195 : } // namespace app
196 : } // namespace mx
197 :
198 : #endif
|