Skip to content

Instantly share code, notes, and snippets.

@ugovaretto
Last active October 12, 2020 05:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ugovaretto/826c04b4a8d3f0b617dcf77cf6f1ddb1 to your computer and use it in GitHub Desktop.
Save ugovaretto/826c04b4a8d3f0b617dcf77cf6f1ddb1 to your computer and use it in GitHub Desktop.
Parse TOML files using only C++ standard regex module
// Parse TOML file with standard regex module, no validation
// Author: Ugo Varetto
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
#include <unordered_map>
using namespace std;
using Dict = unordered_map<std::string, std::string>;
using Toml = unordered_map<std::string, Dict>;
namespace {
void Trim(string& s) {
auto i = s.find("#");
if (i != string::npos) s.erase(i);
i = s.find_last_not_of(" \r\n\t");
if(i != string::npos) s.erase(++i);
}
} // namespace
Toml ParseTomlFile(const string& filename) {
ifstream is(filename);
if (!is) {
throw std::invalid_argument("Cannot open file " + filename);
return {};
}
string line;
const string section = "^\\s*\\[\\s*([^\\]]+)\\]\\s*$";
int lineCount = 0;
string curSection;
Toml toml;
Dict curSectionData;
string lastKey;
while (getline(is, line)) {
++lineCount;
if (line.size() == 0 || regex_search(line, regex{"^\\s*#"})) {
continue;
}
smatch sm;
if (regex_search(line, sm, regex{section})) {
if (curSection.size() != 0) {
toml[curSection] = curSectionData;
curSectionData.clear();
lastKey.clear();
}
curSection = sm[1];
} else {
smatch sm;
if (regex_search(line, sm, regex{"\\s*(\\w+)\\s*=\\s*(.*)"})) {
string value = sm[2];
Trim(value);
curSectionData[sm[1]] = value;
lastKey = sm[1];
} else {
if (lastKey.empty()) {
throw std::runtime_error("Toml parsing error, line " +
to_string(lineCount));
}
if (line.size() == 0) continue;
Trim(line);
curSectionData[lastKey] += line;
}
}
}
if (toml.find(curSection) == toml.end()) {
toml[curSection] = curSectionData;
}
return toml;
}
int main(int argc, char const* argv[]) {
if (argc != 2) {
cerr << "usage: " << argv[0] << " toml filename" << endl;
return 1;
}
auto toml = ParseTomlFile(argv[1]);
for (auto kv : toml) {
cout << "[" << kv.first << "]" << endl;
for (auto i : kv.second) {
cout << "\t" << i.first << ": " << i.second << endl;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment