HyperDbg Debugger
Loading...
Searching...
No Matches
inipp.h
Go to the documentation of this file.
1/*
2MIT License
3
4Copyright (c) 2017-2020 Matthias C. M. Troffaes
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <algorithm>
28#include <cctype>
29#include <cstring>
30#include <functional>
31#include <iostream>
32#include <list>
33#include <vector>
34#include <locale>
35#include <map>
36#include <memory>
37#include <sstream>
38#include <string>
39
40namespace inipp {
41
42namespace detail {
43
44// trim functions based on http://stackoverflow.com/a/217605
45
46template <class CharT>
47inline void
48ltrim(std::basic_string<CharT> & s, const std::locale & loc)
49{
50 s.erase(s.begin(),
51 std::find_if(s.begin(), s.end(), [&loc](CharT ch) { return !std::isspace(ch, loc); }));
52}
53
54template <class CharT>
55inline void
56rtrim(std::basic_string<CharT> & s, const std::locale & loc)
57{
58 s.erase(std::find_if(s.rbegin(), s.rend(), [&loc](CharT ch) { return !std::isspace(ch, loc); }).base(),
59 s.end());
60}
61
62template <class CharT, class UnaryPredicate>
63inline void
64rtrim2(std::basic_string<CharT> & s, UnaryPredicate pred)
65{
66 s.erase(std::find_if(s.begin(), s.end(), pred), s.end());
67}
68
69// string replacement function based on http://stackoverflow.com/a/3418285
70
71template <class CharT>
72inline bool
73replace(std::basic_string<CharT> & str, const std::basic_string<CharT> & from, const std::basic_string<CharT> & to)
74{
75 auto changed = false;
76 size_t start_pos = 0;
77 while ((start_pos = str.find(from, start_pos)) != std::basic_string<CharT>::npos)
78 {
79 str.replace(start_pos, from.length(), to);
80 start_pos += to.length();
81 changed = true;
82 }
83 return changed;
84}
85
86} // namespace detail
87
88template <typename CharT, typename T>
89inline bool
90extract(const std::basic_string<CharT> & value, T & dst)
91{
92 CharT c;
93 std::basic_istringstream<CharT> is {value};
94 T result;
95 if ((is >> std::boolalpha >> result) && !(is >> c))
96 {
97 dst = result;
98 return true;
99 }
100 else
101 {
102 return false;
103 }
104}
105
106template <typename CharT>
107inline bool
108extract(const std::basic_string<CharT> & value, std::basic_string<CharT> & dst)
109{
110 dst = value;
111 return true;
112}
113
114template <typename CharT, typename T>
115inline bool
116get_value(const std::map<std::basic_string<CharT>, std::basic_string<CharT>> & sec, const std::basic_string<CharT> & key, T & dst)
117{
118 const auto it = sec.find(key);
119 if (it == sec.end())
120 return false;
121 return extract(it->second, dst);
122}
123
124template <typename CharT, typename T>
125inline bool
126get_value(const std::map<std::basic_string<CharT>, std::basic_string<CharT>> & sec, const CharT * key, T & dst)
127{
128 return get_value(sec, std::basic_string<CharT>(key), dst);
129}
130
131template <class CharT>
133{
134public:
135 // used for generating
137 const CharT char_section_end;
138 const CharT char_assign;
139 const CharT char_comment;
140
141 // used for parsing
142 virtual bool is_section_start(CharT ch) const { return ch == char_section_start; }
143 virtual bool is_section_end(CharT ch) const { return ch == char_section_end; }
144 virtual bool is_assign(CharT ch) const { return ch == char_assign; }
145 virtual bool is_comment(CharT ch) const { return ch == char_comment; }
146
147 // used for interpolation
148 const CharT char_interpol;
150 const CharT char_interpol_sep;
151 const CharT char_interpol_end;
152
153 Format(CharT section_start, CharT section_end, CharT assign, CharT comment, CharT interpol, CharT interpol_start, CharT interpol_sep, CharT interpol_end) :
154 char_section_start(section_start), char_section_end(section_end), char_assign(assign), char_comment(comment), char_interpol(interpol), char_interpol_start(interpol_start), char_interpol_sep(interpol_sep), char_interpol_end(interpol_end) { }
155
157 Format('[', ']', '=', ';', '$', '{', ':', '}') { }
158
159 const std::basic_string<CharT> local_symbol(const std::basic_string<CharT> & name) const
160 {
162 }
163
164 const std::basic_string<CharT> global_symbol(const std::basic_string<CharT> & sec_name, const std::basic_string<CharT> & name) const
165 {
166 return local_symbol(sec_name + char_interpol_sep + name);
167 }
168};
169
170template <class CharT>
171class Ini
172{
173public:
174 using String = std::basic_string<CharT>;
175 using Section = std::map<String, String>;
176 using Sections = std::map<String, Section>;
177
179 std::list<String> errors;
180 std::shared_ptr<Format<CharT>> format;
181
182 static const int max_interpolation_depth = 10;
183
184 Ini() :
185 format(std::make_shared<Format<CharT>>()) {};
186 Ini(std::shared_ptr<Format<CharT>> fmt) :
187 format(fmt) {};
188
189 void generate(std::basic_ostream<CharT> & os) const
190 {
191 for (auto const & sec : sections)
192 {
193 os << format->char_section_start << sec.first << format->char_section_end << std::endl;
194 for (auto const & val : sec.second)
195 {
196 os << val.first << format->char_assign << val.second << std::endl;
197 }
198 os << std::endl;
199 }
200 }
201
202 void parse(std::basic_istream<CharT> & is)
203 {
204 String line;
205 String section;
206 const std::locale loc {"C"};
207 while (std::getline(is, line))
208 {
209 detail::ltrim(line, loc);
210 detail::rtrim(line, loc);
211 const auto length = line.length();
212 if (length > 0)
213 {
214 const auto pos = std::find_if(line.begin(), line.end(), [this](CharT ch) { return format->is_assign(ch); });
215 const auto & front = line.front();
216 if (format->is_comment(front))
217 {
218 }
219 else if (format->is_section_start(front))
220 {
221 if (format->is_section_end(line.back()))
222 section = line.substr(1, length - 2);
223 else
224 errors.push_back(line);
225 }
226 else if (pos != line.begin() && pos != line.end())
227 {
228 String variable(line.begin(), pos);
229 String value(pos + 1, line.end());
230 detail::rtrim(variable, loc);
231 detail::ltrim(value, loc);
232 auto & sec = sections[section];
233 if (sec.find(variable) == sec.end())
234 sec.emplace(variable, value);
235 else
236 errors.push_back(line);
237 }
238 else
239 {
240 errors.push_back(line);
241 }
242 }
243 }
244 }
245
247 {
248 int global_iteration = 0;
249 auto changed = false;
250 // replace each "${variable}" by "${section:variable}"
251 for (auto & sec : sections)
252 replace_symbols(local_symbols(sec.first, sec.second), sec.second);
253 // replace each "${section:variable}" by its value
254 do
255 {
256 changed = false;
257 const auto syms = global_symbols();
258 for (auto & sec : sections)
259 changed |= replace_symbols(syms, sec.second);
260 } while (changed && (max_interpolation_depth > global_iteration++));
261 }
262
263 void default_section(const Section & sec)
264 {
265 for (auto & sec2 : sections)
266 for (const auto & val : sec)
267 sec2.second.insert(val);
268 }
269
271 {
272 const std::locale loc {"C"};
273 for (auto & sec : sections)
274 for (auto & val : sec.second)
275 {
276 detail::rtrim2(val.second, [this](CharT ch) { return format->is_comment(ch); });
277 detail::rtrim(val.second, loc);
278 }
279 }
280
281 void clear()
282 {
283 sections.clear();
284 errors.clear();
285 }
286
287private:
288 using Symbols = std::vector<std::pair<String, String>>;
289
290 const Symbols local_symbols(const String & sec_name, const Section & sec) const
291 {
292 Symbols result;
293 for (const auto & val : sec)
294 result.emplace_back(format->local_symbol(val.first), format->global_symbol(sec_name, val.first));
295 return result;
296 }
297
298 const Symbols global_symbols() const
299 {
300 Symbols result;
301 for (const auto & sec : sections)
302 for (const auto & val : sec.second)
303 result.emplace_back(format->global_symbol(sec.first, val.first), val.second);
304 return result;
305 }
306
307 bool replace_symbols(const Symbols & syms, Section & sec) const
308 {
309 auto changed = false;
310 for (auto & sym : syms)
311 for (auto & val : sec)
312 changed |= detail::replace(val.second, sym.first, sym.second);
313 return changed;
314 }
315};
316
317} // namespace inipp
Definition inipp.h:133
const CharT char_section_start
Definition inipp.h:136
const CharT char_interpol_end
Definition inipp.h:151
const CharT char_interpol_start
Definition inipp.h:149
Format()
Definition inipp.h:156
const CharT char_section_end
Definition inipp.h:137
const CharT char_interpol_sep
Definition inipp.h:150
const std::basic_string< CharT > local_symbol(const std::basic_string< CharT > &name) const
Definition inipp.h:159
const CharT char_comment
Definition inipp.h:139
const std::basic_string< CharT > global_symbol(const std::basic_string< CharT > &sec_name, const std::basic_string< CharT > &name) const
Definition inipp.h:164
const CharT char_assign
Definition inipp.h:138
virtual bool is_comment(CharT ch) const
Definition inipp.h:145
virtual bool is_section_end(CharT ch) const
Definition inipp.h:143
virtual bool is_section_start(CharT ch) const
Definition inipp.h:142
virtual bool is_assign(CharT ch) const
Definition inipp.h:144
Format(CharT section_start, CharT section_end, CharT assign, CharT comment, CharT interpol, CharT interpol_start, CharT interpol_sep, CharT interpol_end)
Definition inipp.h:153
const CharT char_interpol
Definition inipp.h:148
Definition inipp.h:172
void default_section(const Section &sec)
Definition inipp.h:263
Sections sections
Definition inipp.h:178
Ini(std::shared_ptr< Format< CharT > > fmt)
Definition inipp.h:186
std::map< String, String > Section
Definition inipp.h:175
static const int max_interpolation_depth
Definition inipp.h:182
void generate(std::basic_ostream< CharT > &os) const
Definition inipp.h:189
void parse(std::basic_istream< CharT > &is)
Definition inipp.h:202
void clear()
Definition inipp.h:281
std::map< String, Section > Sections
Definition inipp.h:176
std::shared_ptr< Format< CharT > > format
Definition inipp.h:180
void interpolate()
Definition inipp.h:246
std::list< String > errors
Definition inipp.h:179
std::basic_string< CharT > String
Definition inipp.h:174
Ini()
Definition inipp.h:184
void strip_trailing_comments()
Definition inipp.h:270
void rtrim(std::basic_string< CharT > &s, const std::locale &loc)
Definition inipp.h:56
void rtrim2(std::basic_string< CharT > &s, UnaryPredicate pred)
Definition inipp.h:64
bool replace(std::basic_string< CharT > &str, const std::basic_string< CharT > &from, const std::basic_string< CharT > &to)
Definition inipp.h:73
void ltrim(std::basic_string< CharT > &s, const std::locale &loc)
Definition inipp.h:48
Definition inipp.h:40
bool extract(const std::basic_string< CharT > &value, T &dst)
Definition inipp.h:90
bool get_value(const std::map< std::basic_string< CharT >, std::basic_string< CharT > > &sec, const std::basic_string< CharT > &key, T &dst)
Definition inipp.h:116
val
Definition test-case-generator.py:590
for(;;x)
Definition script-test-cases.txt:2