41 inline void trim(std::string &str)
48 if(lastpos == std::string::npos)
54 str.erase(lastpos + 1);
62 inline bool strToLong(
const std::string &value,
long &result)
66 result = std::strtol(value.c_str(), &endptr, 10);
70 result = std::strtol(value.c_str(), &endptr, 8);
74 result = std::strtol(value.c_str(), &endptr, 16);
81 inline bool strToULong(
const std::string &value,
unsigned long &result)
85 result = std::strtoul(value.c_str(), &endptr, 10);
89 result = std::strtoul(value.c_str(), &endptr, 8);
93 result = std::strtoul(value.c_str(), &endptr, 16);
107 void decode(
const std::string &value,
bool &result)
109 std::string str(value);
110 std::transform(str.begin(), str.end(), str.begin(), [](
const char c){
111 return static_cast<char>(::toupper(c));
116 else if(str ==
"FALSE")
119 throw std::invalid_argument(
"field is not a bool");
122 void encode(
const bool value, std::string &result)
124 result = value ?
"true" :
"false";
131 void decode(
const std::string &value,
char &result)
133 assert(value.size() > 0);
137 void encode(
const char value, std::string &result)
146 void decode(
const std::string &value,
unsigned char &result)
148 assert(value.size() > 0);
152 void encode(
const unsigned char value, std::string &result)
161 void decode(
const std::string &value,
short &result)
165 throw std::invalid_argument(
"field is not a short");
166 result =
static_cast<short>(tmp);
169 void encode(
const short value, std::string &result)
171 std::stringstream ss;
180 void decode(
const std::string &value,
unsigned short &result)
184 throw std::invalid_argument(
"field is not an unsigned short");
185 result =
static_cast<unsigned short>(tmp);
188 void encode(
const unsigned short value, std::string &result)
190 std::stringstream ss;
199 void decode(
const std::string &value,
int &result)
203 throw std::invalid_argument(
"field is not an int");
204 result =
static_cast<int>(tmp);
207 void encode(
const int value, std::string &result)
209 std::stringstream ss;
218 void decode(
const std::string &value,
unsigned int &result)
222 throw std::invalid_argument(
"field is not an unsigned int");
223 result =
static_cast<unsigned int>(tmp);
226 void encode(
const unsigned int value, std::string &result)
228 std::stringstream ss;
237 void decode(
const std::string &value,
long &result)
240 throw std::invalid_argument(
"field is not a long");
243 void encode(
const long value, std::string &result)
245 std::stringstream ss;
254 void decode(
const std::string &value,
unsigned long &result)
257 throw std::invalid_argument(
"field is not an unsigned long");
260 void encode(
const unsigned long value, std::string &result)
262 std::stringstream ss;
271 void decode(
const std::string &value,
double &result)
273 result = std::stod(value);
276 void encode(
const double value, std::string &result)
278 std::stringstream ss;
287 void decode(
const std::string &value,
float &result)
289 result = std::stof(value);
292 void encode(
const float value, std::string &result)
294 std::stringstream ss;
303 void decode(
const std::string &value, std::string &result)
308 void encode(
const std::string &value, std::string &result)
317 void encode(
const char*
const &value, std::string &result)
322 void decode(
const std::string &value,
const char* &result)
324 result = value.c_str();
331 void encode(
const char*
const &value, std::string &result)
340 void encode(
const char *value, std::string &result)
368 conv.decode(value_, result);
376 conv.encode(value, value_);
382 value_ = field.value_;
391 std::transform(lhs.begin(), lhs.end(), lhs.begin(), [](
const char c){
392 return static_cast<char>(::tolower(c));
394 std::transform(rhs.begin(), rhs.end(), rhs.begin(), [](
const char c){
395 return static_cast<char>(::tolower(c));
401 template <
typename Comparator>
414 template <
typename Comparator>
415 class IniFileBase :
public std::map<std::string, IniSectionBase<Comparator>, Comparator>
418 char fieldSep_ =
'=';
420 std::vector<std::string> commentPrefixes_ = {
"#" ,
";" };
421 bool multiLineValues_ =
false;
423 void eraseComment(
const std::string &commentPrefix,
425 std::string::size_type startpos = 0)
427 size_t prefixpos = str.find(commentPrefix, startpos);
428 if(std::string::npos == prefixpos)
431 if(0 != prefixpos && str[prefixpos - 1] == esc_)
435 str.erase(prefixpos - 1, 1);
437 commentPrefix, str, prefixpos - 1 + commentPrefix.size());
441 str.erase(prefixpos);
445 void eraseComments(std::string &str)
447 for(
const std::string &commentPrefix : commentPrefixes_)
448 eraseComment(commentPrefix, str);
453 std::vector<std::string>::const_iterator findCommentPrefix(
const std::string &str,
454 const std::size_t startpos)
const
457 if(startpos >= str.size())
458 return commentPrefixes_.end();
460 for(
size_t i = 0; i < commentPrefixes_.size(); ++i)
462 const std::string &prefix = commentPrefixes_[i];
465 if(prefix.size() + startpos > str.size())
469 for(
size_t j = 0; j < prefix.size() && match; ++j)
470 match = str[startpos + j] == prefix[j];
473 return commentPrefixes_.begin() + i;
476 return commentPrefixes_.end();
479 void writeEscaped(std::ostream &os,
const std::string &str)
const
481 for(
size_t i = 0; i < str.length(); ++i)
483 auto prefixpos = findCommentPrefix(str, i);
486 if(prefixpos != commentPrefixes_.end())
488 const std::string &prefix = *prefixpos;
490 os.write(prefix.c_str(), prefix.size());
491 i += prefix.size() - 1;
493 else if (multiLineValues_ && str[i] ==
'\n')
504 : fieldSep_(fieldSep), commentPrefixes_(1,
std::string(1, comment))
518 const std::vector<std::string> &commentPrefixes)
519 : fieldSep_(fieldSep), commentPrefixes_(commentPrefixes)
524 const std::vector<std::string> &commentPrefixes)
525 : fieldSep_(fieldSep), commentPrefixes_(commentPrefixes)
532 const std::vector<std::string> &commentPrefixes)
533 : fieldSep_(fieldSep), commentPrefixes_(commentPrefixes)
555 commentPrefixes_ = {std::string(1, comment)};
565 commentPrefixes_ = commentPrefixes;
581 multiLineValues_ = enable;
591 std::string mutliLineValueFieldName =
"";
594 while(!is.eof() && !is.fail())
596 std::getline(is, line,
'\n');
598 bool hasIndent = line.find_first_not_of(
indents()) != 0;
610 std::size_t pos = line.find(
"]");
611 if(pos == std::string::npos)
613 std::stringstream ss;
615 <<
": ini parsing failed, section not closed";
616 throw std::logic_error(ss.str());
621 std::stringstream ss;
623 <<
": ini parsing failed, section is empty";
624 throw std::logic_error(ss.str());
628 std::string secName = line.substr(1, pos - 1);
629 currentSection = &((*this)[secName]);
633 mutliLineValueFieldName =
"";
639 if(currentSection ==
nullptr)
641 std::stringstream ss;
643 <<
": ini parsing failed, field has no section";
644 throw std::logic_error(ss.str());
648 std::size_t pos = line.find(fieldSep_);
649 if (multiLineValues_ && hasIndent && mutliLineValueFieldName !=
"")
652 IniField previous_value = (*currentSection)[mutliLineValueFieldName];
653 std::string value = previous_value.
as<std::string>() +
"\n" + line;
654 (*currentSection)[mutliLineValueFieldName] = value;
656 else if(pos == std::string::npos)
658 std::stringstream ss;
660 <<
": ini parsing failed, no '"
663 if (multiLineValues_)
664 ss <<
", and not a multi-line value continuation";
665 throw std::logic_error(ss.str());
670 std::string name = line.substr(0, pos);
672 std::string value = line.substr(pos + 1, std::string::npos);
674 (*currentSection)[name] = value;
676 mutliLineValueFieldName = name;
686 std::istringstream ss(content);
692 void load(
const std::string &fileName)
694 std::ifstream is(fileName.c_str());
703 for(
const auto &filePair : *
this)
706 writeEscaped(os, filePair.first);
711 for(
const auto &secPair : filePair.second)
713 writeEscaped(os, secPair.first);
715 writeEscaped(os, secPair.second.template as<std::string>());
725 std::ostringstream ss;
732 void save(
const std::string &fileName)
const
734 std::ofstream os(fileName.c_str());
IniField & operator=(const T &value)
IniField(const IniField &field)
IniField(const std::string &value)
IniField & operator=(const IniField &field)
void decode(std::istream &is)
void save(const std::string &fileName) const
void setCommentPrefixes(const std::vector< std::string > &commentPrefixes)
IniFileBase(const char fieldSep, const std::vector< std::string > &commentPrefixes)
IniFileBase(const char fieldSep, const char comment)
void setMultiLineValues(bool enable)
IniFileBase(const std::string &filename)
IniFileBase(std::istream &is, const char fieldSep, const std::vector< std::string > &commentPrefixes)
void load(const std::string &fileName)
void setFieldSep(const char sep)
IniFileBase(std::istream &is)
void setCommentChar(const char comment)
void decode(const std::string &content)
void setEscapeChar(const char esc)
IniFileBase(const std::string &filename, const char fieldSep, const std::vector< std::string > &commentPrefixes)
void encode(std::ostream &os) const
std::string encode() const
constexpr const char * whitespaces()
bool strToLong(const std::string &value, long &result)
bool strToULong(const std::string &value, unsigned long &result)
void trim(std::string &str)
constexpr const char * indents()
void encode(const bool value, std::string &result)
void decode(const std::string &value, bool &result)
void decode(const std::string &value, char &result)
void encode(const char value, std::string &result)
void encode(const char *const &value, std::string &result)
void encode(const char *value, std::string &result)
void decode(const std::string &value, const char *&result)
void encode(const char *const &value, std::string &result)
void encode(const double value, std::string &result)
void decode(const std::string &value, double &result)
void decode(const std::string &value, float &result)
void encode(const float value, std::string &result)
void decode(const std::string &value, int &result)
void encode(const int value, std::string &result)
void encode(const long value, std::string &result)
void decode(const std::string &value, long &result)
void encode(const short value, std::string &result)
void decode(const std::string &value, short &result)
void decode(const std::string &value, std::string &result)
void encode(const std::string &value, std::string &result)
void encode(const unsigned char value, std::string &result)
void decode(const std::string &value, unsigned char &result)
void encode(const unsigned int value, std::string &result)
void decode(const std::string &value, unsigned int &result)
void encode(const unsigned long value, std::string &result)
void decode(const std::string &value, unsigned long &result)
void encode(const unsigned short value, std::string &result)
void decode(const std::string &value, unsigned short &result)
bool operator()(std::string lhs, std::string rhs) const