77 * -----------------------------------------------------------------------------
88 * Ini file consists of two parts: section and property
99 * -) Case sensitive: e.g: key=val, Key=val are two different properties
10- * -) Comments: support semicolons ';', comment can appear anywhere
11- * -) Line break: using '\n' in file
1210 * -) Duplicate key: will trigger a error, don't allow this
13- * -) Escape: '\\', '\0', '\a', '\b', '\t', '\r', '\n', '\;', '\#', '\=', '\:', '\x????', '\"'
1411 * -) Global key: allowed this, its section name will be empty
12+ * -) Comments: support semicolons ';', comment can appear anywhere
1513 * -) Hierarchy: now allowed
14+ * -) Line break: using '\n' in file
15+ * -) Escape: '\\', '\0', '\a', '\b', '\t', '\r', '\n', '\;', '\#', '\=', '\:', '\x????', '\"'
1616 * -) Quoted values: allow double quotes, will remove it automatically
1717 * -) Whitespace: left and right whitespaces are removed automatically, add double quote if you want preserved
1818 * -----------------------------------------------------------------------------
@@ -129,12 +129,14 @@ void chen::ini::exception(const InputIterator &beg, InputIterator &cur, InputIte
129129{
130130 if (cur == end)
131131 {
132- throw error (" ini: unexpected end of input" );
132+ throw chen::ini:: error (" ini: unexpected end of input" );
133133 }
134134 else
135135 {
136136 auto pos = chen::num::str (std::distance (beg, cur));
137- throw error (chen::str::format (" ini: unexpected token '%c' at position %s" , *cur, pos.c_str ()));
137+ auto tok = std::isprint (*cur) ? std::string (1 , *cur) : chen::str::format (" \\ x%02x" , static_cast <int >(*cur));
138+
139+ throw chen::ini::error (chen::str::format (" ini: unexpected token '%s' at position %s" , tok.c_str (), pos.c_str ()));
138140 }
139141}
140142
@@ -181,7 +183,7 @@ void chen::ini::decode(chen::ini::value_type &out, const InputIterator &beg, Inp
181183 if (out.find (s.first ) == out.end ())
182184 out.emplace (std::move (s));
183185 else
184- chen::ini::exception (beg, cur, end );
186+ throw chen::ini::error ( chen::str::format ( " ini: duplicate section '%s' found " , s. first . c_str ()) );
185187 }
186188 break ;
187189
@@ -255,6 +257,12 @@ void chen::ini::decode(chen::ini::property_type &out, const InputIterator &beg,
255257 if (key.empty ())
256258 chen::ini::exception (beg, cur, end);
257259
260+ if (out.find (key) != out.end ())
261+ {
262+ auto pos = chen::num::str (std::distance (beg, cur) - key.size ());
263+ throw chen::ini::error (chen::str::format (" ini: duplicate key '%s' found at position %s" , key.c_str (), pos.c_str ()));
264+ }
265+
258266 // equal
259267 if ((cur == end) || (*cur != ' =' ))
260268 chen::ini::exception (beg, cur, end);
@@ -273,15 +281,7 @@ void chen::ini::decode(chen::ini::property_type &out, const InputIterator &beg,
273281 }
274282
275283 // store
276- if (out.find (key) == out.end ())
277- {
278- out.emplace (std::move (key), std::move (val));
279- }
280- else
281- {
282- auto pos = chen::num::str (std::distance (beg, cur) - 4 );
283- throw error (chen::str::format (" ini: duplicate key %s found at position %s" , key.c_str (), pos.c_str ()));
284- }
284+ out.emplace (std::move (key), std::move (val));
285285
286286 // skip
287287 if ((cur != end) && (*cur == ' \n ' ))
@@ -396,7 +396,7 @@ void chen::ini::decode(std::string &out, const InputIterator &beg, InputIterator
396396 {
397397 // e.g: \xD83D\xDE00, it's a emoji character
398398 auto pos = chen::num::str (std::distance (beg, cur) - 4 );
399- throw error (chen::str::format (" ini: invalid unicode char \\ u%s at position %s" , unicode, pos.c_str ()));
399+ throw chen::ini:: error (chen::str::format (" ini: invalid unicode char ' \\ u%s' at position %s" , unicode, pos.c_str ()));
400400 }
401401 }
402402 break ;
0 commit comments