#include <algorithm>
#include <cctype>
+#include <experimental/iterator>
#include <fstream>
#include <iostream>
#include <iterator>
}
}
std::ifstream ifs{fname};
- const std::string buffer{std::istreambuf_iterator<char>(ifs),
- std::istreambuf_iterator<char>()};
- if (load_from_buffer(buffer, warnings)) {
+ std::string buffer{std::istreambuf_iterator<char>(ifs),
+ std::istreambuf_iterator<char>()};
+ if (parse_buffer(buffer, warnings)) {
return 0;
} else {
return -EINVAL;
};
}
-bool ConfFile::load_from_buffer(std::string_view buf, std::ostream* err)
+bool ConfFile::parse_buffer(std::string_view buf, std::ostream* err)
{
- if (int err_pos = check_utf8(buf.data(), buf.size()); err_pos > 0) {
+ assert(err);
+#ifdef _WIN32
+ // We'll need to ensure that there's a new line at the end of the buffer,
+ // otherwise the config parsing will fail.
+ std::string _buf = std::string(buf) + "\n";
+#else
+ std::string_view _buf = buf;
+#endif
+ if (int err_pos = check_utf8(_buf.data(), _buf.size()); err_pos > 0) {
*err << "parse error: invalid UTF-8 found at line "
- << std::count(buf.begin(), std::next(buf.begin(), err_pos), '\n') + 1;
+ << std::count(_buf.begin(), std::next(_buf.begin(), err_pos), '\n') + 1;
return false;
}
- using iter_t = boost::spirit::line_pos_iterator<decltype(buf.begin())>;
- iter_t first{buf.begin()};
+ using iter_t = boost::spirit::line_pos_iterator<decltype(_buf.begin())>;
+ iter_t first{_buf.begin()};
using skipper_t = qi::rule<iter_t>;
IniGrammer<iter_t, skipper_t> grammar{first, *err};
skipper_t skipper = grammar.continue_marker | grammar.comment;
- return qi::phrase_parse(first, iter_t{buf.end()},
+ return qi::phrase_parse(first, iter_t{_buf.end()},
grammar, skipper, *this);
}
if (!warnings) {
warnings = &oss;
}
- return load_from_buffer({bl->c_str(), bl->length()}, warnings) ? 0 : -EINVAL;
+ return parse_buffer({bl->c_str(), bl->length()}, warnings) ? 0 : -EINVAL;
}
-int ConfFile::read(const std::string& section_name,
+int ConfFile::read(std::string_view section_name,
std::string_view key,
std::string &val) const
{
return k;
}
+void ConfFile::check_old_style_section_names(const std::vector<std::string>& prefixes,
+ std::ostream& os)
+{
+ // Warn about section names that look like old-style section names
+ std::vector<std::string> old_style_section_names;
+ for (auto& [name, section] : *this) {
+ for (auto& prefix : prefixes) {
+ if (name.find(prefix) == 0 && name.size() > 3 && name[3] != '.') {
+ old_style_section_names.push_back(name);
+ }
+ }
+ }
+ if (!old_style_section_names.empty()) {
+ os << "ERROR! old-style section name(s) found: ";
+ std::copy(std::begin(old_style_section_names),
+ std::end(old_style_section_names),
+ std::experimental::make_ostream_joiner(os, ", "));
+ os << ". Please use the new style section names that include a period.";
+ }
+}
+
std::ostream &operator<<(std::ostream &oss, const ConfFile &cf)
{
for (auto& [name, section] : cf) {