AceUtils  0.6.0
Useful Arduino utilties which are too small as separate libraries, but complex enough to be shared among multiple projects, and often have external dependencies to other libraries.
CommandDispatcher.cpp
1 /*
2 MIT License
3 
4 Copyright (c) 2018 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 /*
26  * Most of these methods are in the .cpp file instead of remaining in the .h
27  * file because they use the F() macro, which used to cause problems for ESP8266
28  * if they are used in an inline context. That was fixed in one of the
29  * ESP8266-Arduino releases.
30  */
31 
32 #include "CommandDispatcher.h"
33 
34 namespace ace_utils {
35 namespace cli {
36 
37 // Same whitespace characters used by isspace() in the standard C99 library.
38 const char CommandDispatcher::DELIMS[] = " \f\r\n\t\v";
39 
40 void CommandDispatcher::helpCommandHandler(
41  Print& printer, int argc, const char* const* argv) const {
42  if (argc == 2) {
43  const char* cmd = argv[1];
44 
45  // check for "help help"
46  if (strcmp(cmd, "help") == 0) {
47  printer.println(F("Usage: help [command]"));
48  return;
49  }
50 
51  bool found = helpSpecific(printer, cmd);
52  if (found) return;
53  printer.print(F("Unknown command: '"));
54  printer.print(cmd);
55  printer.println('\'');
56  } else {
57  printer.println(F("Commands:"));
58  printer.println(F(" help [command]"));
59  helpAll(printer);
60  }
61 }
62 
63 void CommandDispatcher::helpAll(Print& printer) const {
64  for (uint8_t i = 0; i < mNumCommands; i++) {
65  const CommandHandler* command = mCommands[i];
66  printer.print(" ");
67  printHelp(printer, command);
68  }
69 }
70 
71 bool CommandDispatcher::helpSpecific(Print& printer, const char* cmd) const {
72  const CommandHandler* command = findCommand(cmd);
73  if (command != nullptr) {
74  printer.print(F("Usage: "));
75  printHelp(printer, command);
76  return true;
77  }
78  return false;
79 }
80 
81 void CommandDispatcher::printHelp(
82  Print& printer, const CommandHandler* command) {
83  command->getName().printTo(printer);
84  if (!command->getHelpString().isNull()) {
85  printer.print(' ');
86  command->getHelpString().printTo(printer);
87  printer.println();
88  } else {
89  printer.println();
90  }
91 }
92 
93 void CommandDispatcher::runCommand(Print& printer, char* line) const {
94  // Tokenize the line.
95  int argc = tokenize(line, mArgv, mArgvSize);
96  if (argc == 0) return;
97  const char* cmd = mArgv[0];
98 
99  // Handle the built-in 'help' command.
100  if (strcmp(cmd, "help") == 0) {
101  helpCommandHandler(printer, argc, mArgv);
102  return;
103  }
104 
105  findAndRunCommand(printer, cmd, argc, mArgv);
106 }
107 
108 void CommandDispatcher::findAndRunCommand(
109  Print& printer, const char* cmd, int argc, const char* const* argv) const {
110  const CommandHandler* command = findCommand(cmd);
111  if (command != nullptr) {
112  command->run(printer, argc, argv);
113  return;
114  }
115 
116  printer.print(F("Unknown command: '"));
117  printer.print(cmd);
118  printer.println('\'');
119 }
120 
121 } // cli
122 } // ace_utils
static uint8_t tokenize(char *line, const char **argv, uint8_t argvSize)
Tokenize the line, separating tokens delimited by whitespace (space, formfeed, carriage return,...
const CommandHandler * findCommand(const char *cmd) const
Find the CommandHandler of the given command name.
void runCommand(Print &printer, char *line) const
Tokenize the given 'line', run the matching command handler, and send output to the 'printer'.
Signature for a command handler.
virtual void run(Print &printer, int argc, const char *const *argv) const =0
Run the command.