Step 7 of 7
Challenge: load a config
Now put the pieces together in the kind of code every service has: a config loader. It must report precise errors, because "invalid config" with no line number wastes everyone's time. Good error messages say where and what.
Here's a smaller loader for a shopping list with item: qty lines, using the same techniques you'll need:
#include <iostream>
#include <map>
#include <sstream>
#include <string>
struct ListResult {
std::map<std::string, int> items;
std::string error; // empty means success
};
ListResult load_list(const std::string& text) {
ListResult r;
std::istringstream in(text);
std::string line;
int n = 0;
while (std::getline(in, line)) {
n++; // count every line, even skipped ones
if (line.empty()) continue;
auto colon = line.find(':');
if (colon == std::string::npos) {
r.error = "line " + std::to_string(n) + ": missing :";
return r;
}
std::string item = line.substr(0, colon);
if (r.items.contains(item)) {
r.error = "line " + std::to_string(n) + ": " + item + " listed twice";
return r;
}
r.items[item] = std::stoi(line.substr(colon + 1));
}
return r;
}
int main() {
ListResult ok = load_list("eggs: 12\n\nmilk: 2\n");
std::cout << ok.items.size() << " items, eggs " << ok.items["eggs"] << "\n";
std::cout << load_list("eggs: 12\nmilk 2\n").error << "\n";
std::cout << load_list("tea: 1\n\ntea: 3\n").error << "\n";
}
2 items, eggs 12
line 2: missing :
line 3: tea listed twice
Details that matter
- The line counter increases for every line, including skipped blank ones. Otherwise the reported number wouldn't match what the user sees in their editor. The third example reports line 3, not 2.
- The function stops at the first error and returns. Carrying on after a broken line tends to produce confusing follow-up errors.
- The error text is built with
std::to_string(n)and string concatenation.
Your task's extra rules
Your loader also skips lines starting with # (check line[0] == '#' after the empty check, so you never index an empty string), and rejects an empty key, which is what you get for a line like =value (the = is at index 0). Check the rules in the order listed.
Your turn: write ConfigResult load_config(const std::string& text). The text has one key=value per line:
- blank lines and lines starting with
#are skipped - a line with no
=fails with"line N: missing =" - an empty key fails with
"line N: empty key" - a key seen twice fails with
"line N: duplicate key KEY" - otherwise every pair goes into
values
Lines are numbered from 1. Stop at the first error.