bool ConfigGroup::validate(ConfigNode node) { if(!node.IsMap()) { if(m_name.length() > 0) { config_log.error() << "Section '" << m_path << "' has key/value config variables.\n"; } else { config_log.error() << "Config sections must be at root of config file.\n"; } return false; } bool ok = true; for(auto it = node.begin(); it != node.end(); ++it) { string key = it->first.as<std::string>(); auto found_var = m_variables.find(key); if(found_var != m_variables.end()) { rtest r = found_var->second; if(!r(node)) { config_log.info() << "In Section '" << m_path << "', attribute '" << key << "' did not match constraint (see error).\n"; ok = false; } continue; } auto found_grp = m_children.find(key); if(found_grp != m_children.end()) { if(!found_grp->second->validate(node[key])) { ok = false; } continue; } if(m_name.length() > 0) { config_log.error() << "Section '" << m_path << "' has no attribute named '" << key << "'.\n"; } else { config_log.error() << "Section '" << key << "' is not a valid config category.\n"; } ok = false; } return ok; }
/** overrides already processed config in-place. */ ConfigNode overrideConfig(ConfigNode const& in, ConfigPath const& replaceAt, ConfigNode const& substituteAtPath, unsigned replaceAtI) { if (replaceAtI >= replaceAt.size()) return substituteAtPath; using namespace std; string const& key = replaceAt[replaceAtI]; ConfigNode out; if (!is_null(in)) { if (!in.IsMap()) SDL_THROW_LOG(Config, ConfigException, "attempting to override config at path " << graehl::to_string_sep(replaceAt, ".") << " - parent was not a map node when descending to '" << key << "'"); for (YAML::const_iterator i = in.begin(), e = in.end(); i != e; ++i) { std::string const& iKey = i->first.Scalar(); if (iKey != key) out[iKey] = i->second; } } out[key] = overrideConfig(in[key], replaceAt, substituteAtPath, replaceAtI + 1); return out; }
void print(const ConfigNode& in, const std::string& indent, std::ostream& os, bool longMap, bool newlines, unsigned maxDepth) { if (maxDepth == 0) { os << "..."; return; } if (in.IsScalar()) { os << indent << in.as<std::string>(); return; } std::string deeperIndent; if (newlines) { deeperIndent = indent; deeperIndent.push_back(' '); deeperIndent.push_back(' '); } bool const sequence = in.IsSequence(); bool const map = in.IsMap(); if (!(sequence || map)) return; YAML::const_iterator i = in.begin(), end = in.end(); if (sequence) { if (newlines && !sequenceAllScalar(in.begin(), in.end())) { for (; i != end; ++i) { os << indent << "- "; ConfigNode node = *i; if (node.IsScalar()) os << node.as<std::string>(); else print(*i, deeperIndent, os, longMap, newlines, --maxDepth); os << '\n'; } } else { os << indent << "[ "; bool first = true; for (; i != end; ++i) { ConfigNode node = *i; if (!first) os << ", "; if (node.IsScalar()) os << node.as<std::string>(); else if (node.IsMap()) print(node, "", os, longMap, newlines, --maxDepth); else if (node.IsSequence()) print(node, "", os, longMap, newlines, --maxDepth); first = false; } os << " ]"; } } else { assert(map); if (!longMap && !newlines) longMap = true; if (longMap) { os << " { "; } if (newlines) os << '\n'; bool first = true; for (; i != end; ++i) { std::string const& key = i->first.as<std::string>(); ConfigNode val = i->second; if (!val.IsNull()) { if (!first) { if (longMap) os << ", "; if (newlines) os << '\n'; } os << (newlines && longMap ? deeperIndent : indent) << key << ": "; if (val.IsScalar()) os << val.as<std::string>(); else print(val, deeperIndent, os, longMap, newlines, --maxDepth); } first = false; } if (longMap) { if (newlines) { os << '\n'; os << indent << "}"; } else os << indent << " }"; } } }