AceRoutine  1.0.1
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
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 causes problems for ESP8266 if
28  * they are used in an inline context.
29  */
30 
31 #include "CommandDispatcher.h"
32 
33 namespace ace_routine {
34 namespace cli {
35 
36 // Same whitespace characters used by isspace() in the standard C99 library.
37 const char CommandDispatcher::DELIMS[] = " \f\r\n\t\v";
38 
39 void CommandDispatcher::printLineError(const char* line, uint8_t statusCode)
40  const {
41  if (statusCode == STATUS_BUFFER_OVERFLOW) {
42  mPrinter.print(F("BufferOverflow: "));
43  mPrinter.println(line);
44  } else if (statusCode == STATUS_FLUSH_TO_EOL) {
45  mPrinter.print(F("FlushToEOL: "));
46  mPrinter.println(line);
47  } else {
48  mPrinter.print(F("UnknownError: "));
49  mPrinter.print(statusCode);
50  mPrinter.print(F(": "));
51  mPrinter.println(line);
52  }
53 }
54 
56  Print& printer, int argc, const char* const* argv) const {
57  if (argc == 2) {
58  const char* cmd = argv[1];
59 
60  // check for "help help"
61  if (strcmp(cmd, "help") == 0) {
62  printer.println(F("Usage: help [command]"));
63  return;
64  }
65 
66  bool found = helpSpecific(printer, cmd);
67  if (found) return;
68  printer.print(F("Unknown command: "));
69  printer.println(cmd);
70  } else {
71  printer.println(F("Commands:"));
72  printer.println(F(" help [command]"));
73  helpAll(printer);
74  }
75 }
76 
77 void CommandDispatcher::helpAll(Print& printer) const {
78  for (uint8_t i = 0; i < mNumCommands; i++) {
79  const CommandHandler* command = mCommands[i];
80  printer.print(" ");
81  printHelp(printer, command);
82  }
83 }
84 
85 bool CommandDispatcher::helpSpecific(Print& printer, const char* cmd) const {
86  const CommandHandler* command = findCommand(cmd);
87  if (command != nullptr) {
88  printer.print(F("Usage: "));
89  printHelp(printer, command);
90  return true;
91  }
92  return false;
93 }
94 
96  Print& printer, const CommandHandler* command) {
97  command->getName().printTo(printer);
98  if (!command->getHelpString().isNull()) {
99  printer.print(' ');
100  command->getHelpString().printTo(printer);
101  printer.println();
102  } else {
103  printer.println();
104  }
105 }
106 
107 void CommandDispatcher::runCommand(char* line) const {
108  // Tokenize the line.
109  int argc = tokenize(line, mArgv, mArgvSize);
110  if (argc == 0) return;
111  const char* cmd = mArgv[0];
112 
113  // Handle the built-in 'help' command.
114  if (strcmp(cmd, "help") == 0) {
115  helpCommandHandler(mPrinter, argc, mArgv);
116  return;
117  }
118 
119  findAndRunCommand(cmd, argc, mArgv);
120 }
121 
123  const char* cmd, int argc, const char* const* argv) const {
124  const CommandHandler* command = findCommand(cmd);
125  if (command != nullptr) {
126  command->run(mPrinter, argc, argv);
127  return;
128  }
129 
130  mPrinter.print(F("Unknown command: "));
131  mPrinter.println(cmd);
132 }
133 
134 }
135 }
ace_routine::cli::CommandDispatcher::helpAll
void helpAll(Print &printer) const
Print help on all commands.
Definition: CommandDispatcher.cpp:77
ace_routine::cli::CommandDispatcher::tokenize
static uint8_t tokenize(char *line, const char **argv, uint8_t argvSize)
Tokenize the line, separating tokens delimited by whitespace (space, formfeed, carriage return,...
Definition: CommandDispatcher.h:95
ace_routine::cli::CommandDispatcher::findAndRunCommand
void findAndRunCommand(const char *cmd, int argc, const char *const *argv) const
Find and run the given command.
Definition: CommandDispatcher.cpp:122
ace_routine::cli::CommandDispatcher::printHelp
static void printHelp(Print &printer, const CommandHandler *command)
Print help string for the given command.
Definition: CommandDispatcher.cpp:95
ace_routine::cli::CommandDispatcher::printLineError
void printLineError(const char *line, uint8_t statusCode) const
Print the input line that caused an error along with its status code.
Definition: CommandDispatcher.cpp:39
ace_routine::cli::CommandDispatcher::runCommand
void runCommand(char *line) const
Tokenize the given line and run the command handler.
Definition: CommandDispatcher.cpp:107
ace_routine::cli::CommandHandler::run
virtual void run(Print &printer, int argc, const char *const *argv) const =0
Run the command.
ace_routine::FCString::printTo
size_t printTo(Print &printer) const
Convenience method for printing an FCString to printer.
Definition: FCString.cpp:35
ace_routine::cli::CommandHandler
Signature for a command handler.
Definition: CommandHandler.h:47
ace_routine::cli::CommandDispatcher::helpSpecific
bool helpSpecific(Print &printer, const char *cmd) const
Print helpString of specific cmd.
Definition: CommandDispatcher.cpp:85
ace_routine::cli::CommandDispatcher::findCommand
const CommandHandler * findCommand(const char *cmd) const
Find the CommandHandler of the given command name.
Definition: CommandDispatcher.h:135
ace_routine::cli::CommandDispatcher::helpCommandHandler
void helpCommandHandler(Print &printer, int argc, const char *const *argv) const
Handle the 'help' command.
Definition: CommandDispatcher.cpp:55
ace_routine::FCString::isNull
bool isNull() const
Return if this is a null string.
Definition: FCString.h:67
ace_routine::cli::CommandHandler::getName
FCString getName() const
Return the name of the command.
Definition: CommandHandler.h:68
ace_routine::cli::CommandHandler::getHelpString
FCString getHelpString() const
Return the help string of the command.
Definition: CommandHandler.h:71