config_parser: Add type checking to config map

In order to guarantee the output file is consistent, the
constructed values are checked for safety.

Change-Id: Ib70e369471e9f2f47a1cdb5522f4a3bebc37805e
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/config_parser.cpp b/src/config_parser.cpp
index 80f71e7..867d611 100644
--- a/src/config_parser.cpp
+++ b/src/config_parser.cpp
@@ -5,6 +5,7 @@
 
 #include <functional>
 #include <iterator>
+#include <stdexcept>
 #include <stdplus/exception.hpp>
 #include <stdplus/fd/create.hpp>
 #include <stdplus/fd/line.hpp>
@@ -67,7 +68,7 @@
         {
             continue;
         }
-        return &kit->second.back();
+        return &kit->second.back().get();
     }
     return nullptr;
 }
@@ -79,6 +80,42 @@
                      [](const Value& v) { return std::string(v); });
 }
 
+void KeyCheck::operator()(const std::string& s)
+{
+    for (auto c : s)
+    {
+        if (c == '\n' || c == '=')
+        {
+            throw std::invalid_argument(
+                fmt::format(FMT_COMPILE("Invalid Config Key: {}"), s));
+        }
+    }
+}
+
+void SectionCheck::operator()(const std::string& s)
+{
+    for (auto c : s)
+    {
+        if (c == '\n' || c == ']')
+        {
+            throw std::invalid_argument(
+                fmt::format(FMT_COMPILE("Invalid Config Section: {}"), s));
+        }
+    }
+}
+
+void ValueCheck::operator()(const std::string& s)
+{
+    for (auto c : s)
+    {
+        if (c == '\n')
+        {
+            throw std::invalid_argument(
+                fmt::format(FMT_COMPILE("Invalid Config Value: {}"), s));
+        }
+    }
+}
+
 Parser::Parser(const fs::path& filename)
 {
     setFile(filename);
@@ -145,8 +182,8 @@
         auto it = sections.find(s);
         if (it == sections.end())
         {
-            std::tie(it, std::ignore) =
-                sections.emplace(Section(s), KeyValuesMapList{});
+            std::tie(it, std::ignore) = sections.emplace(
+                Section(Section::unchecked(), s), KeyValuesMapList{});
         }
         section = &it->second.emplace_back();
     }
@@ -181,9 +218,10 @@
         auto it = section->find(k);
         if (it == section->end())
         {
-            std::tie(it, std::ignore) = section->emplace(Key(k), ValueList{});
+            std::tie(it, std::ignore) =
+                section->emplace(Key(Key::unchecked(), k), ValueList{});
         }
-        it->second.emplace_back(v);
+        it->second.emplace_back(Value::unchecked(), v);
     }
 
     void pump(std::string_view line)