1
+ // Ini Parser for Modern C++
2
+ // Version 2.0.0
3
+ // https://github.com/liner-exe/IniParser
4
+ // 2024-2024 liner-exe
5
+ // License: MIT
6
+
7
+
1
8
#ifndef INI_PARSER_LINEREXE
2
9
#define INI_PARSER_LINEREXE
3
10
4
11
#include < fstream>
5
12
#include < iostream>
6
13
#include < string>
7
- #include < map>
14
+ #include < vector>
15
+ #include < algorithm>
8
16
9
17
class IniParser
10
18
{
11
- std::map <std::string, std::map<std::string, std::string>> m_data;
19
+ public:
20
+ using KeyValuePair = std::pair<std::string, std::string>;
21
+ using Section = std::pair<std::string, std::vector<KeyValuePair>>;
22
+
23
+ private:
24
+ std::vector<Section> m_data;
12
25
13
26
static void trim (std::string& str)
14
27
{
@@ -22,16 +35,26 @@ class IniParser
22
35
const size_t last = str.find_last_not_of (" \t\r\n " );
23
36
str = str.substr (first, last - first + 1 );
24
37
}
38
+
39
+ static std::string toLower (const std::string &str)
40
+ {
41
+ std::string result = str;
42
+ std::transform (result.begin (), result.end (), result.begin (), ::tolower);
43
+ return result;
44
+ }
45
+
46
+ static bool contains (const std::vector<std::string>& vec, const std::string& sub)
47
+ {
48
+ return std::find (vec.begin (), vec.end (), sub) != vec.end ();
49
+ }
50
+
25
51
public:
26
52
void read (const std::string& filename)
27
53
{
28
54
std::ifstream file (filename);
29
55
30
- std::map<std::string, std::string> innerData;
31
- std::string line;
32
- std::string section;
33
- std::string key;
34
- std::string value;
56
+ std::vector<KeyValuePair> innerData;
57
+ std::string line, section;
35
58
36
59
while (getline (file, line))
37
60
{
@@ -41,37 +64,171 @@ class IniParser
41
64
continue ;
42
65
}
43
66
44
- size_t openBracketPos = line.find (' [' );
45
- size_t closeBracketPos = line.find (' ]' );
67
+ const size_t openBracketPos = line.find (' [' );
68
+ const size_t closeBracketPos = line.find (' ]' );
46
69
47
70
if (openBracketPos == std::string::npos)
48
71
{
49
72
size_t equalSign = line.find (' =' );
50
- key = line.substr (0 , equalSign);
51
- value = line.substr (equalSign + 1 );
73
+ std::string key = line.substr (0 , equalSign);
74
+ std::string value = line.substr (equalSign + 1 );
52
75
53
76
trim (key);
54
77
trim (value);
55
78
56
- innerData[ key] = value;
79
+ innerData. emplace_back ( key, value) ;
57
80
continue ;
58
81
}
59
82
60
83
if (!section.empty ())
61
84
{
62
- m_data[ section] = innerData;
85
+ m_data. emplace_back ( section, innerData) ;
63
86
innerData.clear ();
64
87
}
65
88
66
89
section = line.substr (openBracketPos + 1 , closeBracketPos - 1 );
90
+ trim (section);
91
+ }
92
+
93
+ if (!section.empty ())
94
+ {
95
+ m_data.emplace_back (section, innerData);
96
+ innerData.clear ();
67
97
}
68
98
69
99
file.close ();
70
100
}
71
101
72
102
std::string get (const std::string& section, const std::string& key)
73
103
{
74
- return m_data[section][key];
104
+ for (const auto & [storedSection, storedKeyValuePair] : m_data)
105
+ {
106
+ if (storedSection == section)
107
+ {
108
+ for (const auto & [storedKey, storedValue] : storedKeyValuePair)
109
+ {
110
+ if (storedKey == key)
111
+ {
112
+ return storedValue;
113
+ }
114
+ }
115
+ }
116
+ }
117
+
118
+ return " -1" ;
119
+ }
120
+
121
+ std::vector<std::string> getSectionNames ()
122
+ {
123
+ std::vector<std::string> result;
124
+
125
+ for (const auto & [storedSection, storedKeyValuePair] : m_data)
126
+ {
127
+ result.push_back (storedSection);
128
+ }
129
+
130
+ return result;
131
+ }
132
+
133
+ std::vector<KeyValuePair> getSectionData (const std::string& section) const
134
+ {
135
+ for (const auto & [storedSection, storedKeyValuePair] : m_data)
136
+ {
137
+ if (storedSection == section) {
138
+ return storedKeyValuePair;
139
+ }
140
+ }
141
+
142
+ throw std::invalid_argument (" Section not found" );
143
+ }
144
+
145
+ bool hasSection (const std::string §ionName) const
146
+ {
147
+ for (const auto & [storedSection, storedKeyValuePair] : m_data) {
148
+ if (storedSection == sectionName)
149
+ {
150
+ return true ;
151
+ }
152
+ }
153
+
154
+ return false ;
155
+ }
156
+
157
+ bool hasKey (const std::string& section, const std::string& key)
158
+ {
159
+ for (const auto & [storedSection, storedKeyValuePair] : m_data)
160
+ {
161
+ if (storedSection == section)
162
+ {
163
+ for (const auto & [storedKey, storedValue] : storedKeyValuePair)
164
+ {
165
+ if (storedKey == key)
166
+ {
167
+ return true ;
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ return false ;
174
+ }
175
+
176
+ bool getBoolean (const std::string& section, const std::string& key)
177
+ {
178
+ std::vector<std::string> trueValues { " 1" , " yes" , " true" , " on" };
179
+ std::vector<std::string> falseValues { " 0" , " no" , " false" , " off" };
180
+
181
+ for (const auto & [storedSection, storedKeyValuePair] : m_data)
182
+ {
183
+ if (storedSection == section)
184
+ {
185
+ for (const auto & [storedKey, storedValue] : storedKeyValuePair)
186
+ {
187
+ if (storedKey == key)
188
+ {
189
+ std::string storedValue_ = toLower (storedValue);
190
+ if (contains (trueValues, storedValue_))
191
+ {
192
+ return true ;
193
+ }
194
+ if (contains (falseValues, storedValue_))
195
+ {
196
+ return false ;
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ throw std::invalid_argument (" Can't get boolean" );
204
+ }
205
+
206
+ int getInteger (const std::string& section, const std::string& key)
207
+ {
208
+ for (const auto & [storedSection, storedKeyValuePair] : m_data)
209
+ {
210
+ if (storedSection == section)
211
+ {
212
+ for (const auto & [storedKey, storedValue] : storedKeyValuePair)
213
+ {
214
+ if (storedKey == key)
215
+ {
216
+ try
217
+ {
218
+ return std::stoi (storedValue);
219
+ } catch (const std::invalid_argument&)
220
+ {
221
+ throw std::invalid_argument (" Invalid integer value" );
222
+ } catch (const std::out_of_range&)
223
+ {
224
+ throw std::invalid_argument (" Integer value out of range" );
225
+ }
226
+ }
227
+ }
228
+ }
229
+ }
230
+
231
+ return -1 ;
75
232
}
76
233
77
234
void show () const
0 commit comments