19 #include <uuid/console.h>
31 #if !defined(__cpp_lib_make_unique) && !defined(DOXYGEN)
34 template<
typename _Tp,
typename... _Args>
35 inline unique_ptr<_Tp> make_unique(_Args&&... __args) {
36 return unique_ptr<_Tp>(
new _Tp(std::forward<_Args>(__args)...));
52 add_command(0, 0, 0, name, arguments,
function,
nullptr);
57 add_command(0, 0, 0, name, arguments,
function, arg_function);
67 add_command(context, 0, 0, name, arguments,
function,
nullptr);
73 add_command(context, 0, 0, name, arguments,
function, arg_function);
84 add_command(context, flags, 0, name, arguments,
function,
nullptr);
90 add_command(context, flags, 0, name, arguments,
function, arg_function);
101 add_command(context, flags, not_flags, name, arguments,
function,
nullptr);
107 commands_.emplace(std::piecewise_construct, std::forward_as_tuple(context),
108 std::forward_as_tuple(flags, not_flags, name, arguments,
function, arg_function));
113 auto longest = commands.exact.crbegin();
116 result.
error =
nullptr;
118 if (commands.exact.empty()) {
119 result.
error = F(
"Command not found");
120 }
else if (commands.exact.count(longest->first) == 1) {
121 auto &command = longest->second;
122 std::vector<std::string> arguments;
124 for (
auto it = std::next(command_line->cbegin(), command->name_.size()); it != command_line->cend(); it++) {
125 arguments.push_back(std::move(*it));
127 command_line.reset();
129 if (commands.partial.upper_bound(longest->first) != commands.partial.end() && !arguments.empty()) {
130 result.
error = F(
"Command not found");
131 }
else if (arguments.size() < command->minimum_arguments()) {
132 result.
error = F(
"Not enough arguments for command");
133 }
else if (arguments.size() > command->maximum_arguments()) {
134 result.
error = F(
"Too many arguments for command");
136 command->function_(shell, arguments);
139 result.
error = F(
"Fatal error (multiple commands found)");
146 size_t component_prefix = 0;
147 size_t shortest_match = commands.begin()->first;
149 longest_name.reserve(shortest_match);
153 auto &first = commands.begin()->second->name_;
154 bool all_match =
true;
156 for (
size_t length = 0; all_match && length < shortest_match; length++) {
157 for (
auto command_it = std::next(commands.begin()); command_it != commands.end(); command_it++) {
165 component_prefix = length + 1;
169 auto name_it = first.begin();
170 for (
size_t i = 0; i < component_prefix; i++) {
176 if (component_prefix < shortest_match) {
178 auto first = *std::next(commands.begin()->second->name_.begin(), component_prefix);
179 bool all_match =
true;
180 size_t chars_prefix = 0;
182 for (
size_t length = 0; all_match; length++) {
183 for (
auto command_it = std::next(commands.begin()); command_it != commands.end(); command_it++) {
186 if (pgm_read_byte(
reinterpret_cast<PGM_P
>(first) + length)
187 != pgm_read_byte(
reinterpret_cast<PGM_P
>(*std::next(command_it->second->name_.begin(), component_prefix)) + length)) {
194 chars_prefix = length + 1;
198 if (chars_prefix > 0) {
199 longest_name.push_back(std::move(
read_flash_string(first).substr(0, chars_prefix)));
208 auto& first = *arguments.begin();
209 bool all_match =
true;
210 size_t chars_prefix = 0;
212 for (
size_t length = 0; all_match; length++) {
213 for (
auto argument_it = std::next(arguments.begin()); argument_it != arguments.end(); argument_it++) {
216 if (first[length] != (*argument_it)[length]) {
223 chars_prefix = length + 1;
227 return arguments.begin()->substr(0, chars_prefix);
234 auto match = commands.partial.begin();
236 bool multiple_matches;
237 if (match != commands.partial.end()) {
238 count = commands.partial.count(match->first);
239 multiple_matches = count > 1 || commands.partial.size() > count
240 || (!commands.exact.empty() && commands.exact.rbegin()->first >= command_line.
total_size());
241 }
else if (!commands.exact.empty()) {
243 match = std::prev(commands.exact.end());
244 count = commands.exact.count(match->first);
245 multiple_matches =
false;
250 std::unique_ptr<Command> temp_command;
251 std::vector<std::string> temp_command_name;
252 std::multimap<size_t,const Command*>::iterator temp_command_it;
254 if (multiple_matches && (commands.exact.empty() || command_line.
total_size() > commands.exact.begin()->second->name_.size())) {
259 if (!temp_command_name.empty() && command_line.
total_size() <= temp_command_name.size()) {
262 match = commands.partial.end();
265 for (
auto &name : temp_command_name) {
271 if (count == 1 && !multiple_matches) {
273 auto &matching_command = match->second;
275 for (
auto &name : matching_command->name_) {
279 if (command_line.
total_size() > result.
replacement->size() && command_line.
total_size() <= matching_command->name_.size() + matching_command->maximum_arguments()) {
281 std::vector<std::string> arguments{std::next(command_line->cbegin(), result.
replacement->size()), command_line->cend()};
286 auto current_args_count = arguments.size();
287 std::string last_argument;
291 last_argument = std::move(result.
replacement->back());
293 if (!arguments.empty()) {
294 arguments.pop_back();
295 current_args_count--;
299 auto potential_arguments = matching_command->arg_function_
300 ? matching_command->arg_function_(shell, arguments, last_argument)
301 : std::vector<std::string>{};
305 for (
auto it = potential_arguments.begin(); it != potential_arguments.end(); ) {
306 if (it->rfind(last_argument, 0) == std::string::npos) {
307 it = potential_arguments.erase(it);
317 if (potential_arguments.size() == 1) {
318 if (last_argument == *potential_arguments.begin()) {
319 if (result.
replacement->size() + 1 < matching_command->name_.size() + matching_command->maximum_arguments()) {
325 last_argument = *potential_arguments.begin();
326 potential_arguments.clear();
329 current_args_count++;
330 }
else if (potential_arguments.size() > 1) {
337 result.
replacement->push_back(std::move(last_argument));
342 if (!potential_arguments.empty()) {
344 current_args_count++;
347 if (current_args_count < matching_command->maximum_arguments()) {
350 for (
auto it = std::next(matching_command->arguments_.cbegin(), current_args_count); it != matching_command->arguments_.cend(); it++) {
355 if (potential_arguments.empty()) {
356 if (!remaining_help->empty()) {
357 result.
help.push_back(std::move(remaining_help));
360 for (
auto potential_argument : potential_arguments) {
363 help->emplace_back(potential_argument);
365 if (!remaining_help->empty()) {
367 help->insert(help->end(), remaining_help->begin(), remaining_help->end());
370 result.
help.push_back(std::move(help));
373 }
else if (result.
replacement->size() < matching_command->name_.size() + matching_command->maximum_arguments()) {
377 }
else if (count != 0) {
379 for (
auto command_it = commands.all.begin(); command_it != commands.all.end(); command_it++) {
382 auto line_it = command_line->cbegin();
383 auto flash_name_it = (*command_it)->name_.cbegin();
387 size_t skip = temp_command_name.size();
393 if (flash_name_it + skip > (*command_it)->name_.cend()) {
397 flash_name_it += skip;
398 while (line_it != command_line->cend()) {
403 for (; flash_name_it != (*command_it)->name_.cend(); flash_name_it++) {
407 if (line_it != command_line->cend()) {
408 if (name == *line_it++) {
411 line_it = command_line->cend();
415 help->emplace_back(name);
420 for (
auto argument : (*command_it)->arguments_) {
422 if (line_it != command_line->cend()) {
430 result.
help.push_back(std::move(help));
436 auto longest = commands.exact.crbegin();
438 if (commands.exact.count(longest->first) == 1) {
439 for (
auto &name : longest->second->name_) {
460 for (
auto it = context_commands.first; it != context_commands.second; it++) {
461 auto& command = it->second;
465 if (!shell.
has_flags(command.flags_, command.not_flags_)) {
469 auto name_it = command.name_.cbegin();
470 auto line_it = command_line->cbegin();
472 for (; name_it != command.name_.cend() && line_it != command_line->cend(); name_it++, line_it++) {
474 size_t found = name.rfind(*line_it, 0);
476 if (found == std::string::npos) {
479 }
else if (line_it->length() != name.length()) {
480 for (
auto line_check_it = std::next(line_it); line_check_it != command_line->cend(); line_check_it++) {
481 if (!line_check_it->empty()) {
497 if (name_it != command.name_.cend()) {
503 commands.
exact.emplace(command.name_.size(), &command);
505 commands.
partial.emplace(command.name_.size(), &command);
507 commands.
all.push_back(&command);
517 : flags_(flags), not_flags_(not_flags), name_(name), arguments_(arguments),
518 function_(function), arg_function_(arg_function) {
522 Commands::Command::~Command() {
527 return std::count_if(arguments_.cbegin(), arguments_.cend(), [] (
const __FlashStringHelper *argument) { return pgm_read_byte(argument) ==
'<'; });