summaryrefslogtreecommitdiffstats
path: root/src/bin/agent/parser_context.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/agent/parser_context.cc')
-rw-r--r--src/bin/agent/parser_context.cc204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/bin/agent/parser_context.cc b/src/bin/agent/parser_context.cc
new file mode 100644
index 0000000..7c18e03
--- /dev/null
+++ b/src/bin/agent/parser_context.cc
@@ -0,0 +1,204 @@
+// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <agent/parser_context.h>
+#include <agent/agent_parser.h>
+#include <agent/ca_log.h>
+#include <exceptions/exceptions.h>
+#include <cc/dhcp_config_error.h>
+#include <cc/data.h>
+#include <fstream>
+#include <sstream>
+#include <limits>
+
+namespace isc {
+namespace agent {
+
+ParserContext::ParserContext()
+ : sfile_(0), ctx_(NO_KEYWORDS), trace_scanning_(false), trace_parsing_(false)
+{
+}
+
+ParserContext::~ParserContext()
+{
+}
+
+isc::data::ElementPtr
+ParserContext::parseString(const std::string& str, ParserType parser_type)
+{
+ scanStringBegin(str, parser_type);
+ return (parseCommon());
+}
+
+isc::data::ElementPtr
+ParserContext::parseFile(const std::string& filename, ParserType parser_type) {
+ FILE* f = fopen(filename.c_str(), "r");
+ if (!f) {
+ isc_throw(ParseError, "Unable to open file " << filename);
+ }
+ scanFileBegin(f, filename, parser_type);
+ return (parseCommon());
+}
+
+isc::data::ElementPtr
+ParserContext::parseCommon() {
+ isc::agent::AgentParser parser(*this);
+ // Uncomment this to get detailed parser logs.
+ // trace_parsing_ = true;
+ parser.set_debug_level(trace_parsing_);
+ try {
+ int res = parser.parse();
+ if (res != 0) {
+ isc_throw(ParseError, "Parser abort");
+ }
+ scanEnd();
+ }
+ catch (...) {
+ scanEnd();
+ throw;
+ }
+ if (stack_.size() == 1) {
+ return (stack_[0]);
+ } else {
+ isc_throw(ParseError, "Expected exactly one terminal Element expected, found "
+ << stack_.size());
+ }
+}
+
+void
+ParserContext::error(const isc::agent::location& loc,
+ const std::string& what,
+ size_t pos)
+{
+ if (pos == 0) {
+ isc_throw(ParseError, loc << ": " << what);
+ } else {
+ isc_throw(ParseError, loc << " (near " << pos << "): " << what);
+ }
+}
+
+void
+ParserContext::error(const std::string& what)
+{
+ isc_throw(ParseError, what);
+}
+
+void
+ParserContext::fatal(const std::string& what)
+{
+ isc_throw(ParseError, what);
+}
+
+isc::data::Element::Position
+ParserContext::loc2pos(isc::agent::location& loc)
+{
+ const std::string& file = *loc.begin.filename;
+ const uint32_t line = loc.begin.line;
+ const uint32_t pos = loc.begin.column;
+ return (isc::data::Element::Position(file, line, pos));
+}
+
+void
+ParserContext::require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc)
+{
+ ConstElementPtr value = stack_.back()->get(name);
+ if (!value) {
+ isc_throw(ParseError,
+ "missing parameter '" << name << "' ("
+ << stack_.back()->getPosition() << ") ["
+ << contextName() << " map between "
+ << open_loc << " and " << close_loc << "]");
+ }
+}
+
+void
+ParserContext::unique(const std::string& name,
+ isc::data::Element::Position loc)
+{
+ ConstElementPtr value = stack_.back()->get(name);
+ if (value) {
+ if (ctx_ != NO_KEYWORDS) {
+ isc_throw(ParseError, loc << ": duplicate " << name
+ << " entries in " << contextName()
+ << " map (previous at " << value->getPosition() << ")");
+ } else {
+ isc_throw(ParseError, loc << ": duplicate " << name
+ << " entries in JSON"
+ << " map (previous at " << value->getPosition() << ")");
+ }
+ }
+}
+
+void
+ParserContext::enter(const LexerContext& ctx)
+{
+ cstack_.push_back(ctx_);
+ ctx_ = ctx;
+}
+
+void
+ParserContext::leave()
+{
+ if (cstack_.empty()) {
+ fatal("unbalanced syntactic context");
+ }
+ ctx_ = cstack_.back();
+ cstack_.pop_back();
+}
+
+const std::string
+ParserContext::contextName()
+{
+ switch (ctx_) {
+ case NO_KEYWORDS:
+ return ("__no keywords__");
+ case CONFIG:
+ return ("toplevel");
+ case AGENT:
+ return ("Control-agent");
+ case AUTHENTICATION:
+ return ("authentication");
+ case AUTH_TYPE:
+ return ("auth-type");
+ case CLIENTS:
+ return ("clients");
+ case CONTROL_SOCKETS:
+ return ("control-sockets");
+ case SERVER:
+ return ("xxx-server");
+ case SOCKET_TYPE:
+ return ("socket-type");
+ case HOOKS_LIBRARIES:
+ return ("hooks-libraries");
+ case LOGGERS:
+ return ("loggers");
+ case OUTPUT_OPTIONS:
+ return ("output-options");
+ default:
+ return ("__unknown__");
+ }
+}
+
+void
+ParserContext::warning(const isc::agent::location& loc,
+ const std::string& what) {
+ std::ostringstream msg;
+ msg << loc << ": " << what;
+ LOG_WARN(agent_logger, CTRL_AGENT_CONFIG_SYNTAX_WARNING)
+ .arg(msg.str());
+}
+
+void
+ParserContext::warnAboutExtraCommas(const isc::agent::location& loc) {
+ warning(loc, "Extraneous comma. A piece of configuration may have been omitted.");
+}
+
+} // end of isc::eval namespace
+} // end of isc namespace