tools: nfdc command line parser
refs #3749
Change-Id: Ief301152212a6d501f0396b2c9834e860ddaf6c5
diff --git a/tools/nfdc/command-parser.cpp b/tools/nfdc/command-parser.cpp
new file mode 100644
index 0000000..d91cbc3
--- /dev/null
+++ b/tools/nfdc/command-parser.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "command-parser.hpp"
+#include <ndn-cxx/util/logger.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+NDN_LOG_INIT(CommandParser);
+
+std::ostream&
+operator<<(std::ostream& os, AvailableIn modes)
+{
+ int count = 0;
+
+#define PRINT_BIT(bit, str) \
+ if ((modes & bit) != 0) { \
+ if (++count > 1) { \
+ os << '|'; \
+ } \
+ os << str; \
+ }
+
+ PRINT_BIT(AVAILABLE_IN_ONE_SHOT, "one-shot")
+ PRINT_BIT(AVAILABLE_IN_BATCH, "batch")
+
+#undef PRINT_BIT
+
+ if (count == 0) {
+ os << "none";
+ }
+ return os;
+}
+
+std::ostream&
+operator<<(std::ostream& os, ParseMode mode)
+{
+ switch (mode) {
+ case ParseMode::ONE_SHOT:
+ return os << "one-shot";
+ case ParseMode::BATCH:
+ return os << "batch";
+ }
+ return os << static_cast<int>(mode);
+}
+
+CommandParser&
+CommandParser::addCommand(const CommandDefinition& def, const Execute& execute, AvailableIn modes)
+{
+ BOOST_ASSERT(modes != AVAILABLE_IN_NONE);
+ m_commands[{def.getNoun(), def.getVerb()}].reset(new Command{def, execute, modes});
+ return *this;
+}
+
+CommandParser&
+CommandParser::addAlias(const std::string& noun, const std::string& verb, const std::string& verb2)
+{
+ m_commands[{noun, verb2}] = m_commands.at({noun, verb});
+ return *this;
+}
+
+std::tuple<CommandParser::Execute*, CommandArguments>
+CommandParser::parse(const std::vector<std::string>& tokens, ParseMode mode) const
+{
+ BOOST_ASSERT(mode == ParseMode::ONE_SHOT);
+
+ const std::string& noun = tokens.size() > 0 ? tokens[0] : "";
+ const std::string& verb = tokens.size() > 1 ? tokens[1] : "";
+ size_t nameLen = std::min<size_t>(2, tokens.size());
+
+ auto i = m_commands.find({noun, verb});
+ if (i == m_commands.end()) {
+ if (verb.empty()) {
+ i = m_commands.find({noun, "list"});
+ }
+ else {
+ // help, exit, quit, legacy nfdc commands
+ i = m_commands.find({noun, ""});
+ }
+ nameLen = std::min<size_t>(1, tokens.size());
+ }
+ if (i == m_commands.end() || (i->second->modes & static_cast<AvailableIn>(mode)) == 0) {
+ BOOST_THROW_EXCEPTION(Error("no such command: " + noun + " " + verb));
+ }
+
+ const CommandDefinition& def = i->second->def;
+ NDN_LOG_TRACE("found command " << def.getNoun() << " " << def.getVerb());
+
+ return std::make_tuple(&i->second->execute, def.parse(tokens, nameLen));
+}
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd