tools: legacy nfdc parses command with Boost.Program_options
refs #3749
Change-Id: I5274e0a2594323729834cd8001308ec699fbe6d6
diff --git a/tools/nfdc/legacy-nfdc.cpp b/tools/nfdc/legacy-nfdc.cpp
index 3e4c0e6..5b7ff45 100644
--- a/tools/nfdc/legacy-nfdc.cpp
+++ b/tools/nfdc/legacy-nfdc.cpp
@@ -26,6 +26,7 @@
#include "legacy-nfdc.hpp"
#include "face-id-fetcher.hpp"
+#include <boost/program_options.hpp>
#include <boost/regex.hpp>
namespace nfd {
@@ -52,42 +53,42 @@
LegacyNfdc::dispatch(const std::string& command)
{
if (command == "add-nexthop") {
- if (m_nOptions != 2)
+ if (m_commandLineArguments.size() != 2)
return false;
fibAddNextHop();
}
else if (command == "remove-nexthop") {
- if (m_nOptions != 2)
+ if (m_commandLineArguments.size() != 2)
return false;
fibRemoveNextHop();
}
else if (command == "register") {
- if (m_nOptions != 2)
+ if (m_commandLineArguments.size() != 2)
return false;
ribRegisterPrefix();
}
else if (command == "unregister") {
- if (m_nOptions != 2)
+ if (m_commandLineArguments.size() != 2)
return false;
ribUnregisterPrefix();
}
else if (command == "create") {
- if (m_nOptions != 1)
+ if (m_commandLineArguments.size() != 1)
return false;
faceCreate();
}
else if (command == "destroy") {
- if (m_nOptions != 1)
+ if (m_commandLineArguments.size() != 1)
return false;
faceDestroy();
}
else if (command == "set-strategy") {
- if (m_nOptions != 2)
+ if (m_commandLineArguments.size() != 2)
return false;
strategyChoiceSet();
}
else if (command == "unset-strategy") {
- if (m_nOptions != 1)
+ if (m_commandLineArguments.size() != 1)
return false;
strategyChoiceUnset();
}
@@ -285,6 +286,116 @@
BOOST_THROW_EXCEPTION(Error(os.str()));
}
+void
+legacyNfdcUsage()
+{
+ std::cout << "Usage:\n"
+ "nfdc [-h] [-V] COMMAND [<Command Options>]\n"
+ " -h print usage and exit\n"
+ " -V print version and exit\n"
+ "\n"
+ " COMMAND can be one of the following:\n"
+ " register [-I] [-C] [-c cost] [-e expiration time] [-o origin] name <faceId | faceUri>\n"
+ " register name to the given faceId or faceUri\n"
+ " -I: unset CHILD_INHERIT flag\n"
+ " -C: set CAPTURE flag\n"
+ " -c: specify cost (default 0)\n"
+ " -e: specify expiration time in ms\n"
+ " (by default the entry remains in FIB for the lifetime of the associated face)\n"
+ " -o: specify origin\n"
+ " 0 for Local producer applications, 128 for NLSR, 255(default) for static routes\n"
+ " unregister [-o origin] name <faceId | faceUri>\n"
+ " unregister name from the given faceId\n"
+ " create [-P] <faceUri> \n"
+ " Create a face in one of the following formats:\n"
+ " UDP unicast: udp[4|6]://<remote-IP-or-host>[:<remote-port>]\n"
+ " TCP: tcp[4|6]://<remote-IP-or-host>[:<remote-port>] \n"
+ " -P: create permanent (instead of persistent) face\n"
+ " destroy <faceId | faceUri> \n"
+ " Destroy a face\n"
+ " set-strategy <name> <strategy> \n"
+ " Set the strategy for a namespace \n"
+ " unset-strategy <name> \n"
+ " Unset the strategy for a namespace \n"
+ " add-nexthop [-c <cost>] <name> <faceId | faceUri>\n"
+ " Add a nexthop to a FIB entry\n"
+ " -c: specify cost (default 0)\n"
+ " remove-nexthop <name> <faceId | faceUri> \n"
+ " Remove a nexthop from a FIB entry\n"
+ << std::endl;
+}
+
+int
+legacyNfdcMain(const std::string& subcommand, const std::vector<std::string>& args)
+{
+ ndn::Face face;
+ LegacyNfdc p(face);
+
+ bool wantUnsetChildInherit = false;
+ bool wantCapture = false;
+ bool wantPermanentFace = false;
+ int64_t expires = -1;
+
+ namespace po = boost::program_options;
+ po::options_description options;
+ options.add_options()
+ (",I", po::bool_switch(&wantUnsetChildInherit))
+ (",C", po::bool_switch(&wantCapture))
+ (",c", po::value<uint64_t>(&p.m_cost))
+ (",e", po::value<int64_t>(&expires))
+ (",o", po::value<uint64_t>(&p.m_origin))
+ (",P", po::bool_switch(&wantPermanentFace));
+ po::variables_map vm;
+ std::vector<std::string> unparsed;
+ try {
+ po::parsed_options parsed = po::command_line_parser(args).options(options).allow_unregistered().run();
+ unparsed = po::collect_unrecognized(parsed.options, po::include_positional);
+ po::store(parsed, vm);
+ po::notify(vm);
+ }
+ catch (const po::error& e) {
+ std::cerr << e.what() << std::endl;
+ legacyNfdcUsage();
+ return 1;
+ }
+
+ if (wantUnsetChildInherit) {
+ p.m_flags &= ~(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
+ }
+ if (wantCapture) {
+ p.m_flags |= ndn::nfd::ROUTE_FLAG_CAPTURE;
+ }
+ if (expires >= 0) {
+ // accept negative values as no expiration
+ p.m_expires = time::milliseconds(expires);
+ }
+ if (wantPermanentFace) {
+ p.m_facePersistency = ndn::nfd::FACE_PERSISTENCY_PERMANENT;
+ }
+
+ if (std::any_of(unparsed.begin(), unparsed.end(),
+ [] (const std::string& s) { return s.empty() || s[0] == '-'; })) {
+ // unrecognized -option
+ legacyNfdcUsage();
+ return 1;
+ }
+ p.m_commandLineArguments = unparsed;
+
+ try {
+ bool isOk = p.dispatch(subcommand);
+ if (!isOk) {
+ legacyNfdcUsage();
+ return 1;
+ }
+ face.processEvents();
+ }
+ catch (const std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return 2;
+ }
+ return 0;
+}
+
} // namespace nfdc
} // namespace tools
} // namespace nfd
diff --git a/tools/nfdc/legacy-nfdc.hpp b/tools/nfdc/legacy-nfdc.hpp
index 5a804a1..8828afb 100644
--- a/tools/nfdc/legacy-nfdc.hpp
+++ b/tools/nfdc/legacy-nfdc.hpp
@@ -159,11 +159,7 @@
onObtainFaceIdFailure(const std::string& message);
public:
- const char* m_programName;
-
- // command parameters without leading 'cmd' component
- const char* const* m_commandLineArguments;
- int m_nOptions;
+ std::vector<std::string> m_commandLineArguments; // positional arguments
uint64_t m_flags;
uint64_t m_cost;
uint64_t m_faceId;
@@ -178,6 +174,12 @@
ndn::nfd::Controller m_controller;
};
+void
+legacyNfdcUsage();
+
+int
+legacyNfdcMain(const std::string& subcommand, const std::vector<std::string>& args);
+
} // namespace nfdc
} // namespace tools
} // namespace nfd
diff --git a/tools/nfdc/main.cpp b/tools/nfdc/main.cpp
index 74ef47d..5bc2596 100644
--- a/tools/nfdc/main.cpp
+++ b/tools/nfdc/main.cpp
@@ -27,153 +27,36 @@
#include "status-main.hpp"
#include "core/version.hpp"
-#include <boost/lexical_cast.hpp>
-
namespace nfd {
namespace tools {
namespace nfdc {
-static void
-usage(const char* programName)
-{
- std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
- " -h print usage and exit\n"
- " -V print version and exit\n"
- "\n"
- " COMMAND can be one of the following:\n"
- " register [-I] [-C] [-c cost] [-e expiration time] [-o origin] name <faceId | faceUri>\n"
- " register name to the given faceId or faceUri\n"
- " -I: unset CHILD_INHERIT flag\n"
- " -C: set CAPTURE flag\n"
- " -c: specify cost (default 0)\n"
- " -e: specify expiration time in ms\n"
- " (by default the entry remains in FIB for the lifetime of the associated face)\n"
- " -o: specify origin\n"
- " 0 for Local producer applications, 128 for NLSR, 255(default) for static routes\n"
- " unregister [-o origin] name <faceId | faceUri>\n"
- " unregister name from the given faceId\n"
- " create [-P] <faceUri> \n"
- " Create a face in one of the following formats:\n"
- " UDP unicast: udp[4|6]://<remote-IP-or-host>[:<remote-port>]\n"
- " TCP: tcp[4|6]://<remote-IP-or-host>[:<remote-port>] \n"
- " -P: create permanent (instead of persistent) face\n"
- " destroy <faceId | faceUri> \n"
- " Destroy a face\n"
- " set-strategy <name> <strategy> \n"
- " Set the strategy for a namespace \n"
- " unset-strategy <name> \n"
- " Unset the strategy for a namespace \n"
- " add-nexthop [-c <cost>] <name> <faceId | faceUri>\n"
- " Add a nexthop to a FIB entry\n"
- " -c: specify cost (default 0)\n"
- " remove-nexthop <name> <faceId | faceUri> \n"
- " Remove a nexthop from a FIB entry\n"
- << std::endl;
-}
-
static int
main(int argc, char** argv)
{
- ndn::Face face;
- LegacyNfdc p(face);
-
- p.m_programName = argv[0];
-
if (argc < 2) {
- usage(p.m_programName);
+ legacyNfdcUsage();
return 0;
}
- if (strcmp(argv[1], "-h") == 0) {
- usage(p.m_programName);
+ std::string subcommand(argv[1]);
+ std::vector<std::string> args(argv + 2, argv + argc);
+
+ if (subcommand == "-h") {
+ legacyNfdcUsage();
return 0;
}
- if (strcmp(argv[1], "-V") == 0) {
+ if (subcommand == "-V") {
std::cout << NFD_VERSION_BUILD_STRING << std::endl;
return 0;
}
- if (strcmp(argv[1], "legacy-nfd-status") == 0) {
- return statusMain(argc - 1, argv + 1);
+ if (subcommand == "legacy-nfd-status") {
+ return statusMain(args);
}
- ::optind = 2; //start reading options from 2nd argument i.e. Command
- int opt;
- while ((opt = ::getopt(argc, argv, "ICc:e:o:P")) != -1) {
- switch (opt) {
- case 'I':
- p.m_flags = p.m_flags & ~(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
- break;
-
- case 'C':
- p.m_flags = p.m_flags | ndn::nfd::ROUTE_FLAG_CAPTURE;
- break;
-
- case 'c':
- try {
- p.m_cost = boost::lexical_cast<uint64_t>(::optarg);
- }
- catch (const boost::bad_lexical_cast&) {
- std::cerr << "Error: cost must be in unsigned integer format" << std::endl;
- return 1;
- }
- break;
-
- case 'e':
- uint64_t expires;
- try {
- expires = boost::lexical_cast<uint64_t>(::optarg);
- }
- catch (const boost::bad_lexical_cast&) {
- std::cerr << "Error: expiration time must be in unsigned integer format" << std::endl;
- return 1;
- }
- p.m_expires = ndn::time::milliseconds(expires);
- break;
-
- case 'o':
- try {
- p.m_origin = boost::lexical_cast<uint64_t>(::optarg);
- }
- catch (const boost::bad_lexical_cast&) {
- std::cerr << "Error: origin must be in unsigned integer format" << std::endl;
- return 1;
- }
- break;
-
- case 'P':
- p.m_facePersistency = ndn::nfd::FACE_PERSISTENCY_PERMANENT;
- break;
-
- default:
- usage(p.m_programName);
- return 1;
- }
- }
-
- if (argc == ::optind) {
- usage(p.m_programName);
- return 1;
- }
-
- try {
- p.m_commandLineArguments = argv + ::optind;
- p.m_nOptions = argc - ::optind;
-
- //argv[1] points to the command, so pass it to the dispatch
- bool isOk = p.dispatch(argv[1]);
- if (!isOk) {
- usage(p.m_programName);
- return 1;
- }
- face.processEvents();
- }
- catch (const std::exception& e) {
- std::cerr << "ERROR: " << e.what() << std::endl;
- return 2;
- }
- return 0;
+ return legacyNfdcMain(subcommand, args);
}
} // namespace nfdc
diff --git a/tools/nfdc/status-main.cpp b/tools/nfdc/status-main.cpp
index e268e40..0f87ab1 100644
--- a/tools/nfdc/status-main.cpp
+++ b/tools/nfdc/status-main.cpp
@@ -64,7 +64,7 @@
* otherwise, caller should immediately exit with the specified exit code
*/
static std::tuple<int, Options>
-parseCommandLine(int argc, const char* const* argv)
+parseCommandLine(const std::vector<std::string>& args)
{
Options options;
@@ -82,14 +82,14 @@
("xml,x", "output as XML instead of text (implies -vcfbrs)");
po::variables_map vm;
try {
- po::store(po::parse_command_line(argc, argv, cmdOptions), vm);
+ po::store(po::command_line_parser(args).options(cmdOptions).run(), vm);
+ po::notify(vm);
}
catch (const po::error& e) {
std::cerr << e.what() << "\n";
showUsage(std::cerr, cmdOptions);
return std::make_tuple(2, options);
}
- po::notify(vm);
if (vm.count("help") > 0) {
showUsage(std::cout, cmdOptions);
@@ -114,11 +114,11 @@
}
int
-statusMain(int argc, char** argv)
+statusMain(const std::vector<std::string>& args)
{
int exitCode = -1;
Options options;
- std::tie(exitCode, options) = parseCommandLine(argc, argv);
+ std::tie(exitCode, options) = parseCommandLine(args);
if (exitCode >= 0) {
return exitCode;
}
diff --git a/tools/nfdc/status-main.hpp b/tools/nfdc/status-main.hpp
index 910e4ac..62b58a6 100644
--- a/tools/nfdc/status-main.hpp
+++ b/tools/nfdc/status-main.hpp
@@ -26,12 +26,14 @@
#ifndef NFD_TOOLS_NFDC_STATUS_MAIN_HPP
#define NFD_TOOLS_NFDC_STATUS_MAIN_HPP
+#include "core/common.hpp"
+
namespace nfd {
namespace tools {
namespace nfdc {
int
-statusMain(int argc, char** argv);
+statusMain(const std::vector<std::string>& args);
} // namespace nfdc
} // namespace tools