blob: ebe9d3c03053046cb96a7c7b5c4d40de8b58da0f [file] [log] [blame]
Junxiao Shid243d712016-08-19 06:45:31 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa997d292017-08-24 20:16:59 -04002/*
Alexander Afanasyevc414ca52021-06-09 12:15:19 -04003 * Copyright (c) 2014-2021, Regents of the University of California,
Junxiao Shid243d712016-08-19 06:45:31 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
Junxiao Shi64567bb2016-09-04 16:00:27 +000026#include "available-commands.hpp"
Junxiao Shid243d712016-08-19 06:45:31 +000027#include "core/version.hpp"
Alexander Afanasyevc414ca52021-06-09 12:15:19 -040028#include "help.hpp"
Junxiao Shid243d712016-08-19 06:45:31 +000029
Alexander Afanasyevc414ca52021-06-09 12:15:19 -040030#include <boost/tokenizer.hpp>
31#include <fstream>
Davide Pesaventoa997d292017-08-24 20:16:59 -040032#include <iostream>
33
Junxiao Shid243d712016-08-19 06:45:31 +000034namespace nfd {
35namespace tools {
36namespace nfdc {
37
Junxiao Shid243d712016-08-19 06:45:31 +000038static int
39main(int argc, char** argv)
40{
Junxiao Shi64567bb2016-09-04 16:00:27 +000041 std::vector<std::string> args(argv + 1, argv + argc);
42
Junxiao Shi6c135622016-11-21 14:30:33 +000043 CommandParser parser;
44 registerCommands(parser);
45
Davide Pesavento2a588152018-02-19 18:10:03 -050046 if (args.empty()) {
Junxiao Shi6c135622016-11-21 14:30:33 +000047 helpList(std::cout, parser);
Junxiao Shid243d712016-08-19 06:45:31 +000048 return 0;
49 }
50
Davide Pesaventoe0bae0f2018-02-17 22:07:52 -050051 if (args[0] == "-V" || args[0] == "--version") {
Junxiao Shid243d712016-08-19 06:45:31 +000052 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
53 return 0;
54 }
55
Alexander Afanasyevc414ca52021-06-09 12:15:19 -040056 struct Command
57 {
58 std::string noun, verb;
59 CommandArguments ca;
60 ExecuteCommand execute;
61 };
62
63 auto processLine = [&parser] (const std::vector<std::string>& line) -> Command {
64 try {
65 Command cmd;
66 std::tie(cmd.noun, cmd.verb, cmd.ca, cmd.execute) = parser.parse(line, ParseMode::ONE_SHOT);
67 return cmd;
68 }
69 catch (const std::invalid_argument& e) {
70 int ret = help(std::cout, parser, line);
71 if (ret == 2)
72 std::cerr << e.what() << std::endl;
73 return {"", "", {}, nullptr};
74 }
75 };
76
77 std::list<Command> commands;
78
79 if (args[0] == "-f" || args[0] == "--batch") {
80 if (args.size() != 2) {
81 std::cerr << "ERROR: Invalid command line arguments: " << args[0] << " should follow with batch-file."
82 << " Use -h for more detail." << std::endl;
83 return 2;
84 }
85
86 auto processIstream = [&commands,&processLine] (std::istream& is, const std::string& inputFile) {
87 std::string line;
88 size_t lineCounter = 0;
89 while (std::getline(is, line)) {
90 ++lineCounter;
91
92 auto hasEscapeSlash = [] (const std::string& str) {
93 auto count = std::count(str.rbegin(), str.rend(), '\\');
94 return (count % 2) == 1;
95 };
96 while (!line.empty() && hasEscapeSlash(line)) {
97 std::string extraLine;
98 const auto& hasMore = std::getline(is, extraLine);
99 ++lineCounter;
100 line = line.substr(0, line.size() - 1) + extraLine;
101 if (!hasMore) {
102 break;
103 }
104 }
105 boost::tokenizer<boost::escaped_list_separator<char>> tokenizer(
106 line,
107 boost::escaped_list_separator<char>("\\", " \t", "\"'"));
108
109 auto firstNonEmptyToken = tokenizer.begin();
110 while (firstNonEmptyToken != tokenizer.end() && firstNonEmptyToken->empty()) {
111 ++firstNonEmptyToken;
112 }
113
114 // Ignore empty lines (or lines with just spaces) and lines that start with #
115 // Non empty lines with trailing comment are not allowed and may trigger syntax error
116 if (firstNonEmptyToken == tokenizer.end() || (*firstNonEmptyToken)[0] == '#') {
117 continue;
118 }
119
120 std::vector<std::string> lineArgs;
121 std::copy_if(firstNonEmptyToken, tokenizer.end(),
122 std::back_inserter<std::vector<std::string>>(lineArgs),
123 [] (const std::string& t) { return !t.empty(); });
124
125 auto cmd = processLine(lineArgs);
126 if (cmd.noun.empty()) {
127 std::cerr << " >> Syntax error on line " << lineCounter << " of the batch in "
128 << inputFile << std::endl;
129 return 2; // not exactly correct, but should be indication of an error, which already shown
130 }
131 commands.push_back(std::move(cmd));
132 }
133 return 0;
134 };
135
136 if (args[1] == "-") {
137 auto retval = processIstream(std::cin, "standard input");
138 if (retval != 0) {
139 return retval;
140 }
141 }
142 else {
143 std::ifstream iff(args[1]);
144 if (!iff) {
145 std::cerr << "ERROR: Could not open `" << args[1] << "` batch file "
146 << "(" << strerror(errno) << ")" << std::endl;
147 return 2;
148 }
149 auto retval = processIstream(iff, args[1]);
150 if (retval != 0) {
151 return retval;
152 }
153 }
Junxiao Shi64567bb2016-09-04 16:00:27 +0000154 }
Alexander Afanasyevc414ca52021-06-09 12:15:19 -0400155 else {
156 commands.push_back(processLine(args));
Junxiao Shi331ade72016-08-19 14:07:19 +0000157 }
158
Junxiao Shi737c43c2016-09-14 02:51:44 +0000159 try {
Junxiao Shi1f481fa2017-01-26 15:14:43 +0000160 Face face;
161 KeyChain keyChain;
162 Controller controller(face, keyChain);
Alexander Afanasyevc414ca52021-06-09 12:15:19 -0400163 size_t commandCounter = 0;
164 for (auto& command : commands) {
165 ++commandCounter;
166 ExecuteContext ctx{command.noun, command.verb, command.ca, 0,
167 std::cout, std::cerr, face, keyChain, controller};
168 command.execute(ctx);
169
170 if (ctx.exitCode != 0) {
171 if (commands.size() > 1) {
172 std::cerr << " >> Failed to execute command on line " << commandCounter
173 << " of the batch file " << args[1] << std::endl;
174 std::cerr << " Note that nfdc has executed all commands on previous lines and "
175 << "stopped processing at this line" << std::endl;
176 }
177
178 return ctx.exitCode;
179 }
180 }
181 return 0;
Junxiao Shi737c43c2016-09-14 02:51:44 +0000182 }
183 catch (const std::exception& e) {
184 std::cerr << e.what() << std::endl;
185 return 1;
186 }
Junxiao Shid243d712016-08-19 06:45:31 +0000187}
188
189} // namespace nfdc
190} // namespace tools
191} // namespace nfd
192
193int
194main(int argc, char** argv)
195{
196 return nfd::tools::nfdc::main(argc, argv);
197}