The CommandProcessor is the interface to install a run-time menu into an embedded system.

Dependents:   A_CANAdapter USB2I2C

Committer:
WiredHome
Date:
Thu Nov 08 12:49:56 2012 +0000
Revision:
17:abba63b079fb
Parent:
16:4ce4f55213ac
Minor tweak for compatibility with mbed lib v43

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 7:0f058d664b21 1 /// @file CommandProcessor.c is a simple interface to an interactive
WiredHome 7:0f058d664b21 2 /// command set of user defined commands.
WiredHome 0:198f53da1bc8 3 ///
WiredHome 7:0f058d664b21 4 /// With this, you can create functions that are exposed to a console
WiredHome 7:0f058d664b21 5 /// interface. Each command may have 0 or more parameters.
WiredHome 7:0f058d664b21 6 /// Typing the command, or at least the set of characters that make
WiredHome 7:0f058d664b21 7 /// it unique from all other commands is enough to activate the command.
WiredHome 7:0f058d664b21 8 ///
WiredHome 7:0f058d664b21 9 /// Even though it is a c interface, it is somewhat object oriented.
WiredHome 0:198f53da1bc8 10 ///
WiredHome 12:a8c56bf811b9 11 /// @note Copyright &copr; 2011 by Smartware Computing, all rights reserved.
WiredHome 12:a8c56bf811b9 12 /// Individuals may use this application for evaluation or non-commercial
WiredHome 12:a8c56bf811b9 13 /// purposes. Within this restriction, changes may be made to this application
WiredHome 12:a8c56bf811b9 14 /// as long as this copyright notice is retained. The user shall make
WiredHome 12:a8c56bf811b9 15 /// clear that their work is a derived work, and not the original.
WiredHome 12:a8c56bf811b9 16 /// Users of this application and sources accept this application "as is" and
WiredHome 12:a8c56bf811b9 17 /// shall hold harmless Smartware Computing, for any undesired results while
WiredHome 12:a8c56bf811b9 18 /// using this application - whether real or imagined.
WiredHome 0:198f53da1bc8 19 ///
WiredHome 12:a8c56bf811b9 20 /// @author David Smart, Smartware Computing
WiredHome 12:a8c56bf811b9 21 ///
WiredHome 12:a8c56bf811b9 22
WiredHome 0:198f53da1bc8 23 #include "stdio.h"
WiredHome 0:198f53da1bc8 24 #include "string.h"
WiredHome 0:198f53da1bc8 25 #include "stdlib.h"
WiredHome 0:198f53da1bc8 26 #ifdef WIN32
WiredHome 0:198f53da1bc8 27 #include "windows.h"
WiredHome 0:198f53da1bc8 28 #pragma warning (disable: 4996)
WiredHome 0:198f53da1bc8 29 #endif
WiredHome 0:198f53da1bc8 30
WiredHome 0:198f53da1bc8 31 #include "CommandProcessor.h"
WiredHome 0:198f53da1bc8 32
WiredHome 0:198f53da1bc8 33 /// This holds the single linked list of commands
WiredHome 11:4a3cd3f2183b 34 /// @verbatim
WiredHome 7:0f058d664b21 35 /// +-- Head->next
WiredHome 7:0f058d664b21 36 /// v
WiredHome 7:0f058d664b21 37 /// +-- p +-- n
WiredHome 7:0f058d664b21 38 /// v v
WiredHome 7:0f058d664b21 39 /// |menu|-------------------------------->|"Command" |
WiredHome 7:0f058d664b21 40 /// |next|->0 |menu|---->|"Help" |"Help" |
WiredHome 7:0f058d664b21 41 /// |next|->0 |"..." |*(callback)|
WiredHome 7:0f058d664b21 42 /// |*(callback) |visible |
WiredHome 7:0f058d664b21 43 /// |visible
WiredHome 11:4a3cd3f2183b 44 /// @endverbatim
WiredHome 0:198f53da1bc8 45 ///
WiredHome 7:0f058d664b21 46 typedef struct CMDLINK_T {
WiredHome 0:198f53da1bc8 47 CMD_T * menu; // handle to the menu item
WiredHome 0:198f53da1bc8 48 struct CMDLINK_T * next; // handle to the next link
WiredHome 0:198f53da1bc8 49 } CMDLINK_T;
WiredHome 0:198f53da1bc8 50
WiredHome 0:198f53da1bc8 51 static CMDLINK_T * head = NULL;
WiredHome 0:198f53da1bc8 52
WiredHome 0:198f53da1bc8 53 static char *buffer; // buffer space must be allocated based on the longest command
WiredHome 15:5f30da93e3e2 54 static char *historyBuffer; // keeps the history of commands for recall
WiredHome 15:5f30da93e3e2 55 static int historyCount = 0; // and the count of
WiredHome 14:7971c8bd3f11 56 static int historyDepth = 0;
WiredHome 13:e1880be590c4 57 static size_t longestCommand = 0;
WiredHome 12:a8c56bf811b9 58
WiredHome 7:0f058d664b21 59 static struct {
WiredHome 15:5f30da93e3e2 60 CMD_T *SignOnBanner;
WiredHome 15:5f30da93e3e2 61 int showSignOnBanner; // Shows the sign-on banner at startup
WiredHome 0:198f53da1bc8 62 int caseinsensitive; // FALSE=casesensitive, TRUE=insensitive
WiredHome 6:1a0512faa75d 63 int echo; // TRUE=echo on, FALSE=echo off
WiredHome 14:7971c8bd3f11 64 int bufferSize; // size of the command buffer
WiredHome 0:198f53da1bc8 65 int (*kbhit)(void);
WiredHome 0:198f53da1bc8 66 int (*getch)(void);
WiredHome 0:198f53da1bc8 67 int (*putch)(int ch);
WiredHome 0:198f53da1bc8 68 int (*puts)(const char * s);
WiredHome 0:198f53da1bc8 69 } cfg;
WiredHome 0:198f53da1bc8 70
WiredHome 0:198f53da1bc8 71 static INITRESULT_T CommandProcessor_Init(
WiredHome 10:9e52bd1a4a71 72 CMD_T *SignOnBanner,
WiredHome 15:5f30da93e3e2 73 CONFIG_T config,
WiredHome 7:0f058d664b21 74 int maxCmdLen,
WiredHome 15:5f30da93e3e2 75 int historyCount,
WiredHome 0:198f53da1bc8 76 int (*kbhit)(void),
WiredHome 0:198f53da1bc8 77 int (*getch)(void),
WiredHome 0:198f53da1bc8 78 int (*putch)(int ch),
WiredHome 0:198f53da1bc8 79 int (*puts)(const char * s)
WiredHome 7:0f058d664b21 80 );
WiredHome 15:5f30da93e3e2 81
WiredHome 15:5f30da93e3e2 82 // Used when processing characters
WiredHome 15:5f30da93e3e2 83 static int keycount = 0; // how full?
WiredHome 15:5f30da93e3e2 84 static int leadinChar = 0;
WiredHome 15:5f30da93e3e2 85 static int whereInHistory = 0; // navigates history
WiredHome 15:5f30da93e3e2 86 static int showPrompt = TRUE;
WiredHome 15:5f30da93e3e2 87
WiredHome 15:5f30da93e3e2 88
WiredHome 0:198f53da1bc8 89 static ADDRESULT_T CommandProcessor_Add(CMD_T *m);
WiredHome 0:198f53da1bc8 90 static RUNRESULT_T CommandProcessor_Run(void);
WiredHome 0:198f53da1bc8 91 static RUNRESULT_T CommandProcessor_End(void);
WiredHome 6:1a0512faa75d 92 static RUNRESULT_T CommandProcessor_Echo(int echo);
WiredHome 14:7971c8bd3f11 93 static void EraseChars(int keycount);
WiredHome 14:7971c8bd3f11 94 static void EchoString(char * p);
WiredHome 0:198f53da1bc8 95
WiredHome 7:0f058d664b21 96 // helper functions
WiredHome 7:0f058d664b21 97 static int myisprint(int c);
WiredHome 7:0f058d664b21 98 static void mystrcat(char *dst, char *src);
WiredHome 7:0f058d664b21 99 static char mytolower(char a);
WiredHome 13:e1880be590c4 100 static int mystrnicmp(const char *l, const char *r, size_t n);
WiredHome 7:0f058d664b21 101
WiredHome 7:0f058d664b21 102 static CMDP_T CommandProcessor = {
WiredHome 0:198f53da1bc8 103 CommandProcessor_Init,
WiredHome 0:198f53da1bc8 104 CommandProcessor_Add,
WiredHome 0:198f53da1bc8 105 CommandProcessor_Run,
WiredHome 6:1a0512faa75d 106 CommandProcessor_Echo,
WiredHome 0:198f53da1bc8 107 CommandProcessor_End
WiredHome 0:198f53da1bc8 108 };
WiredHome 0:198f53da1bc8 109
WiredHome 0:198f53da1bc8 110 static RUNRESULT_T Help(char *p);
WiredHome 14:7971c8bd3f11 111 static RUNRESULT_T History(char *p);
WiredHome 6:1a0512faa75d 112 static RUNRESULT_T Echo(char *p);
WiredHome 0:198f53da1bc8 113 static RUNRESULT_T Exit(char *p);
WiredHome 10:9e52bd1a4a71 114 //static RUNRESULT_T About(char *p);
WiredHome 0:198f53da1bc8 115
WiredHome 9:41046d2fd8e7 116 static CMD_T HelpMenu = {"Help", "Help or '?' shows this help, 'Help ?' shows more details.", Help, visible};
WiredHome 9:41046d2fd8e7 117 static CMD_T QuestionMenu = {"?", "Shows this help, '? ?' shows more details.", Help, invisible};
WiredHome 14:7971c8bd3f11 118 static CMD_T HistoryMenu = {"History", "Show command history", History, visible};
WiredHome 6:1a0512faa75d 119 static CMD_T EchoMenu = {"Echo", "Echo [1|on|0|off] turns echo on or off.", Echo, visible};
WiredHome 0:198f53da1bc8 120 static CMD_T ExitMenu = {"Exit", "Exits the program", Exit, visible};
WiredHome 0:198f53da1bc8 121
WiredHome 0:198f53da1bc8 122 /// Gets a handle to the CommandProcessor
WiredHome 0:198f53da1bc8 123 ///
WiredHome 7:0f058d664b21 124 /// This returns a handle to the CommandProcessor, which then permits
WiredHome 7:0f058d664b21 125 /// access to the CommandProcessor functions.
WiredHome 0:198f53da1bc8 126 ///
WiredHome 7:0f058d664b21 127 /// @returns handle to the CommandProcessor
WiredHome 0:198f53da1bc8 128 ///
WiredHome 7:0f058d664b21 129 CMDP_T * GetCommandProcessor(void) {
WiredHome 0:198f53da1bc8 130 return &CommandProcessor;
WiredHome 0:198f53da1bc8 131 }
WiredHome 0:198f53da1bc8 132
WiredHome 0:198f53da1bc8 133
WiredHome 14:7971c8bd3f11 134 /// History shows the command history
WiredHome 7:0f058d664b21 135 ///
WiredHome 14:7971c8bd3f11 136 /// @param p is a pointer to a string that is ignored
WiredHome 7:0f058d664b21 137 /// @returns runok
WiredHome 7:0f058d664b21 138 ///
WiredHome 14:7971c8bd3f11 139 static RUNRESULT_T History(char *p) {
WiredHome 15:5f30da93e3e2 140 int whereInHistory = 0;
WiredHome 15:5f30da93e3e2 141 char buf[100];
WiredHome 14:7971c8bd3f11 142
WiredHome 15:5f30da93e3e2 143 cfg.puts("");
WiredHome 15:5f30da93e3e2 144 for (whereInHistory = 0; whereInHistory < historyCount; whereInHistory++) {
WiredHome 15:5f30da93e3e2 145 sprintf(buf, " %2i: %s", whereInHistory - historyCount, &historyBuffer[whereInHistory * cfg.bufferSize]);
WiredHome 15:5f30da93e3e2 146 cfg.puts(buf);
WiredHome 15:5f30da93e3e2 147 }
WiredHome 15:5f30da93e3e2 148 sprintf(buf, " %2i: %s", 0, buffer);
WiredHome 15:5f30da93e3e2 149 cfg.puts(buf);
WiredHome 15:5f30da93e3e2 150 return runok;
WiredHome 0:198f53da1bc8 151 }
WiredHome 0:198f53da1bc8 152
WiredHome 7:0f058d664b21 153 /// Turns command prompt echo on and off
WiredHome 7:0f058d664b21 154 ///
WiredHome 7:0f058d664b21 155 /// This command is used to turn the command prompt on and off. When
WiredHome 7:0f058d664b21 156 /// running in an interactive mode, it is best to have this one.
WiredHome 7:0f058d664b21 157 /// When driven by another program, off may be the best choice.
WiredHome 7:0f058d664b21 158 ///
WiredHome 7:0f058d664b21 159 /// This command also displays the current state of the echo mode.
WiredHome 7:0f058d664b21 160 ///
WiredHome 7:0f058d664b21 161 /// @param p is a pointer to a string "on" | "1" | "off" | "0"
WiredHome 7:0f058d664b21 162 /// @returns runok
WiredHome 7:0f058d664b21 163 ///
WiredHome 6:1a0512faa75d 164 static RUNRESULT_T Echo(char *p) {
WiredHome 6:1a0512faa75d 165 if (*p) {
WiredHome 6:1a0512faa75d 166 if (*p == '1' || mystrnicmp(p, "on", 2) == 0)
WiredHome 6:1a0512faa75d 167 CommandProcessor_Echo(1);
WiredHome 6:1a0512faa75d 168 if (*p == '0' || mystrnicmp(p, "off", 3) == 0)
WiredHome 6:1a0512faa75d 169 CommandProcessor_Echo(0);
WiredHome 6:1a0512faa75d 170 }
WiredHome 6:1a0512faa75d 171 if (cfg.echo)
WiredHome 6:1a0512faa75d 172 cfg.puts("\r\nEcho is on");
WiredHome 6:1a0512faa75d 173 else
WiredHome 6:1a0512faa75d 174 cfg.puts("\r\nEcho is off");
WiredHome 6:1a0512faa75d 175 return runok;
WiredHome 6:1a0512faa75d 176 }
WiredHome 6:1a0512faa75d 177
WiredHome 7:0f058d664b21 178 static RUNRESULT_T Exit(char *p) {
WiredHome 0:198f53da1bc8 179 (void)p;
WiredHome 0:198f53da1bc8 180 cfg.puts("\r\nbye.");
WiredHome 0:198f53da1bc8 181 return runexit;
WiredHome 0:198f53da1bc8 182 }
WiredHome 0:198f53da1bc8 183
WiredHome 7:0f058d664b21 184 static RUNRESULT_T Help(char *p) {
WiredHome 0:198f53da1bc8 185 CMDLINK_T *link = head;
WiredHome 0:198f53da1bc8 186 char buffer[100];
WiredHome 0:198f53da1bc8 187 cfg.puts("\r\n");
WiredHome 10:9e52bd1a4a71 188 //sprintf(buffer, " %-10s: %s", "Command", "Description");
WiredHome 10:9e52bd1a4a71 189 //cfg.puts(buffer);
WiredHome 7:0f058d664b21 190 while (link && link->menu) {
WiredHome 7:0f058d664b21 191 if (link->menu->visible) {
WiredHome 7:0f058d664b21 192 if (strlen(link->menu->command) + strlen(link->menu->helptext) + 5 < sizeof(buffer)) {
WiredHome 12:a8c56bf811b9 193 sprintf(buffer, " %-*s: %s", longestCommand, link->menu->command, link->menu->helptext);
WiredHome 0:198f53da1bc8 194 cfg.puts(buffer);
WiredHome 0:198f53da1bc8 195 }
WiredHome 0:198f53da1bc8 196 }
WiredHome 0:198f53da1bc8 197 link = link->next;
WiredHome 0:198f53da1bc8 198 }
WiredHome 0:198f53da1bc8 199 cfg.puts("");
WiredHome 7:0f058d664b21 200 if (*p == '?') {
WiredHome 10:9e52bd1a4a71 201 cfg.puts("\r\n Extended Help:\r\n"
WiredHome 7:0f058d664b21 202 " The general form for entering commands is:\r\n"
WiredHome 7:0f058d664b21 203 " >command option1 option2 ...\r\n"
WiredHome 10:9e52bd1a4a71 204 " [note that not all commands support optional parameters]\r\n"
WiredHome 7:0f058d664b21 205 " * Abbreviations of commands may be entered so long as there\r\n"
WiredHome 7:0f058d664b21 206 " is exactly one match in the list of commands. For example,\r\n"
WiredHome 7:0f058d664b21 207 " 'he' is the same as 'help', if there is no other command \r\n"
WiredHome 7:0f058d664b21 208 " that starts with 'he'.\r\n"
WiredHome 7:0f058d664b21 209 " * <bs> can be used to erase previously entered information.\r\n"
WiredHome 7:0f058d664b21 210 " * <esc> can be used to cancel a command.\r\n"
WiredHome 7:0f058d664b21 211 " * <tab> can be used to complete the entry of a partial command.\r\n"
WiredHome 7:0f058d664b21 212 "");
WiredHome 15:5f30da93e3e2 213 cfg.puts("\r\n About this CommandProcessor: (v" VERSION ")\r\n"
WiredHome 15:5f30da93e3e2 214 " This CommandProcessor provides an easy facility for creating an\r\n"
WiredHome 15:5f30da93e3e2 215 " interactive runtime interpreter in an embedded system.\r\n"
WiredHome 15:5f30da93e3e2 216 " Copyright (c) 2011 by Smartware Computing, all rights reserved.\r\n"
WiredHome 15:5f30da93e3e2 217 " Author: David Smart, Smartware Computing\r\n");
WiredHome 0:198f53da1bc8 218 }
WiredHome 0:198f53da1bc8 219 return runok;
WiredHome 0:198f53da1bc8 220 }
WiredHome 0:198f53da1bc8 221
WiredHome 14:7971c8bd3f11 222
WiredHome 7:0f058d664b21 223 /// CommandMatches is the function that determines if the user is entering a valid
WiredHome 7:0f058d664b21 224 /// command
WiredHome 7:0f058d664b21 225 ///
WiredHome 7:0f058d664b21 226 /// This function gets called whenever the user types a printable character or when
WiredHome 7:0f058d664b21 227 /// they press \<enter\>.
WiredHome 7:0f058d664b21 228 /// The buffer of user input is evaluated to determine if the command is legitimate.
WiredHome 7:0f058d664b21 229 /// It also determines if they want to execute the command, or simply evaluate it.
WiredHome 7:0f058d664b21 230 /// Finally, it identifies writes to user provided pointers, the menu item that
WiredHome 7:0f058d664b21 231 /// matches and a pointer to any parameters that the user entered.
WiredHome 7:0f058d664b21 232 ///
WiredHome 7:0f058d664b21 233 /// @param buffer is the buffer that the user has entered commands into
WiredHome 7:0f058d664b21 234 /// @param exec indicates the intention to execute the command, if found
WiredHome 7:0f058d664b21 235 /// @param menu is a pointer to a pointer to a menu structure, which is updated based on the command
WiredHome 7:0f058d664b21 236 /// @param params is a pointer to a pointer to the user entered parameters
WiredHome 7:0f058d664b21 237 /// @returns the number of menu picks that match the user entered command
WiredHome 7:0f058d664b21 238 ///
WiredHome 7:0f058d664b21 239 static int CommandMatches(char * buffer, int exec, CMD_T **menu, char **params) {
WiredHome 7:0f058d664b21 240 char *space;
WiredHome 7:0f058d664b21 241 int compareLength;
WiredHome 7:0f058d664b21 242 int foundCount = 0;
WiredHome 7:0f058d664b21 243 CMDLINK_T *link = head;
WiredHome 15:5f30da93e3e2 244 char * alternateBuffer;
WiredHome 7:0f058d664b21 245
WiredHome 7:0f058d664b21 246 if (strlen(buffer)) { // simple sanity check
WiredHome 7:0f058d664b21 247 // Try to process the buffer. A command could be "Help", or it could be "Test1 123 abc"
WiredHome 7:0f058d664b21 248 space = strchr(buffer, ' '); // if the command has parameters, find the delimiter
WiredHome 7:0f058d664b21 249 if (space) {
WiredHome 7:0f058d664b21 250 compareLength = space - buffer;
WiredHome 16:4ce4f55213ac 251 space++; // advance to the char after the space (where the params may start)
WiredHome 7:0f058d664b21 252 } else {
WiredHome 7:0f058d664b21 253 compareLength = strlen(buffer);
WiredHome 16:4ce4f55213ac 254 space = buffer + compareLength; // points to the NULL terminator
WiredHome 7:0f058d664b21 255 }
WiredHome 7:0f058d664b21 256 while (link && link->menu) {
WiredHome 7:0f058d664b21 257 int cmpResult;
WiredHome 7:0f058d664b21 258
WiredHome 7:0f058d664b21 259 if (cfg.caseinsensitive) {
WiredHome 7:0f058d664b21 260 cmpResult = mystrnicmp(buffer, link->menu->command, compareLength);
WiredHome 7:0f058d664b21 261 } else
WiredHome 7:0f058d664b21 262 cmpResult = strncmp(buffer, link->menu->command, compareLength);
WiredHome 7:0f058d664b21 263 if (0 == cmpResult) { // A match to what they typed
WiredHome 7:0f058d664b21 264 if (menu) { // yes, we have a callback
WiredHome 7:0f058d664b21 265 *menu = link->menu; // accessor to the command they want to execute
WiredHome 7:0f058d664b21 266 *params = space;
WiredHome 7:0f058d664b21 267 }
WiredHome 7:0f058d664b21 268 foundCount++; // how many command match what they typed so far
WiredHome 7:0f058d664b21 269 }
WiredHome 7:0f058d664b21 270 link = link->next; // follow the link to the next command
WiredHome 7:0f058d664b21 271 }
WiredHome 7:0f058d664b21 272 if (foundCount == 1) {
WiredHome 7:0f058d664b21 273 // If we found exactly one and they expressed an intent to execute that command
WiredHome 7:0f058d664b21 274 // then we'll rewrite the command to be fully qualified
WiredHome 7:0f058d664b21 275 if (exec) { // command wants to execute it, not just validate the command syntax
WiredHome 7:0f058d664b21 276 // If they type "He 1234 5678", we backup and rewrite as "Help 1234 5678"
WiredHome 7:0f058d664b21 277 int diff = strlen((*menu)->command) - compareLength; // e.g. 5 - 3
WiredHome 7:0f058d664b21 278
WiredHome 15:5f30da93e3e2 279 // or if they entered it in a case that doesn't match the command exactly
WiredHome 14:7971c8bd3f11 280 if (diff > 0 || 0 != strncmp(buffer, (*menu)->command, compareLength)) {
WiredHome 14:7971c8bd3f11 281 char *p = buffer;
WiredHome 15:5f30da93e3e2 282 alternateBuffer = (char *)malloc(cfg.bufferSize);
WiredHome 15:5f30da93e3e2 283 strcpy(alternateBuffer, (*menu)->command);
WiredHome 15:5f30da93e3e2 284 strcat(alternateBuffer, " ");
WiredHome 15:5f30da93e3e2 285 strcat(alternateBuffer, space);
WiredHome 15:5f30da93e3e2 286 EraseChars(strlen(buffer));
WiredHome 15:5f30da93e3e2 287 strcpy(buffer, alternateBuffer);
WiredHome 15:5f30da93e3e2 288 free(alternateBuffer);
WiredHome 15:5f30da93e3e2 289 EchoString(p);
WiredHome 16:4ce4f55213ac 290 *params = strchr(buffer, ' '); // if the command has parameters, find the delimiter
WiredHome 16:4ce4f55213ac 291 if (*params) {
WiredHome 16:4ce4f55213ac 292 (*params)++; // advance to the char after the space (where the params may start)
WiredHome 16:4ce4f55213ac 293 } else {
WiredHome 16:4ce4f55213ac 294 compareLength = strlen(buffer);
WiredHome 16:4ce4f55213ac 295 *params = buffer + compareLength; // points to the NULL terminator
WiredHome 16:4ce4f55213ac 296 }
WiredHome 7:0f058d664b21 297 }
WiredHome 7:0f058d664b21 298 }
WiredHome 7:0f058d664b21 299 }
WiredHome 7:0f058d664b21 300 }
WiredHome 7:0f058d664b21 301 return foundCount;
WiredHome 7:0f058d664b21 302 }
WiredHome 7:0f058d664b21 303
WiredHome 14:7971c8bd3f11 304
WiredHome 10:9e52bd1a4a71 305 /// Init is the first function to call to configure the CommandProcessor.
WiredHome 7:0f058d664b21 306 ///
WiredHome 15:5f30da93e3e2 307 /// This function has a number of parameters, which make the CommandProcessor
WiredHome 10:9e52bd1a4a71 308 /// quite flexible.
WiredHome 7:0f058d664b21 309 ///
WiredHome 10:9e52bd1a4a71 310 /// @param SignOnBanner function, which is used as a signon banner
WiredHome 10:9e52bd1a4a71 311 /// @param config enables various default menu items, based on the bit values, combine the following:
WiredHome 10:9e52bd1a4a71 312 /// \li CFG_ENABLE_TERMINATE - enables the Exit command
WiredHome 10:9e52bd1a4a71 313 /// \li CFG_ENABLE_SYSTEM - enables system commands Echo, Help, etc.
WiredHome 10:9e52bd1a4a71 314 /// \li CFG_ECHO_ON - initialize with echo on
WiredHome 10:9e52bd1a4a71 315 /// \li CFG_CASE_INSENSITIVE - Command Parser is case insensitive
WiredHome 10:9e52bd1a4a71 316 /// @param maxCmdLen sizes the buffer, and is the maximum number of characters in a single
WiredHome 10:9e52bd1a4a71 317 /// command, including all command arguments
WiredHome 10:9e52bd1a4a71 318 /// @param kbhit is a user provided function to detect if a character is available for the CommandProcessor,
WiredHome 10:9e52bd1a4a71 319 /// and when using standard io, you can typically use kbhit, or _kbhit as your system provides.
WiredHome 10:9e52bd1a4a71 320 /// @param getch is a user provided function that provides a single character to the CommandProcessor
WiredHome 10:9e52bd1a4a71 321 /// @param putch is a user provided function that permits the CommandProcessor to output a character
WiredHome 10:9e52bd1a4a71 322 /// @param puts is a user provided function that permits the CommandProcessor to output a string
WiredHome 10:9e52bd1a4a71 323 /// to which is automatically appended a \\n
WiredHome 10:9e52bd1a4a71 324 /// @returns INITRESULT_T to indicate if the init was successful or failed
WiredHome 7:0f058d664b21 325 ///
WiredHome 7:0f058d664b21 326 INITRESULT_T CommandProcessor_Init(
WiredHome 10:9e52bd1a4a71 327 CMD_T (*SignOnBanner),
WiredHome 10:9e52bd1a4a71 328 CONFIG_T config,
WiredHome 7:0f058d664b21 329 int maxCmdLen,
WiredHome 15:5f30da93e3e2 330 int numInHistory,
WiredHome 7:0f058d664b21 331 int (*kbhit)(void),
WiredHome 7:0f058d664b21 332 int (*getch)(void),
WiredHome 7:0f058d664b21 333 int (*putch)(int ch),
WiredHome 7:0f058d664b21 334 int (*puts)(const char * s)
WiredHome 7:0f058d664b21 335 ) {
WiredHome 15:5f30da93e3e2 336 if (SignOnBanner) {
WiredHome 15:5f30da93e3e2 337 CommandProcessor.Add(SignOnBanner);
WiredHome 15:5f30da93e3e2 338 cfg.SignOnBanner = SignOnBanner;
WiredHome 15:5f30da93e3e2 339 cfg.showSignOnBanner = 1;
WiredHome 15:5f30da93e3e2 340 }
WiredHome 7:0f058d664b21 341 if (maxCmdLen < 6)
WiredHome 7:0f058d664b21 342 maxCmdLen = 6;
WiredHome 15:5f30da93e3e2 343 buffer = (char *)malloc(maxCmdLen); // users often error by one, so we'll be generous
WiredHome 15:5f30da93e3e2 344 historyDepth = numInHistory;
WiredHome 15:5f30da93e3e2 345 historyBuffer = (char *)malloc(historyDepth * maxCmdLen);
WiredHome 7:0f058d664b21 346 cfg.bufferSize = maxCmdLen;
WiredHome 14:7971c8bd3f11 347 if (buffer && historyBuffer) {
WiredHome 15:5f30da93e3e2 348 if (config & CFG_ENABLE_SYSTEM) {
WiredHome 7:0f058d664b21 349 CommandProcessor.Add(&QuestionMenu);
WiredHome 7:0f058d664b21 350 CommandProcessor.Add(&HelpMenu);
WiredHome 15:5f30da93e3e2 351 CommandProcessor.Add(&HistoryMenu);
WiredHome 7:0f058d664b21 352 CommandProcessor.Add(&EchoMenu);
WiredHome 15:5f30da93e3e2 353 }
WiredHome 10:9e52bd1a4a71 354 if (config & CFG_ENABLE_TERMINATE)
WiredHome 7:0f058d664b21 355 CommandProcessor.Add(&ExitMenu);
WiredHome 10:9e52bd1a4a71 356 //if (addDefaultMenu & 0x0002)
WiredHome 10:9e52bd1a4a71 357 // CommandProcessor.Add(&AboutMenu);
WiredHome 10:9e52bd1a4a71 358 cfg.caseinsensitive = (config & CFG_CASE_INSENSITIVE) ? 1 : 0;
WiredHome 10:9e52bd1a4a71 359 cfg.echo = (config & CFG_ECHO_ON) ? 1 : 0;
WiredHome 7:0f058d664b21 360 cfg.kbhit = kbhit;
WiredHome 7:0f058d664b21 361 cfg.getch = getch;
WiredHome 7:0f058d664b21 362 cfg.putch = putch;
WiredHome 7:0f058d664b21 363 cfg.puts = puts;
WiredHome 7:0f058d664b21 364 return initok;
WiredHome 7:0f058d664b21 365 } else
WiredHome 7:0f058d664b21 366 return initfailed;
WiredHome 7:0f058d664b21 367 }
WiredHome 7:0f058d664b21 368
WiredHome 14:7971c8bd3f11 369
WiredHome 7:0f058d664b21 370 /// Add a command to the CommandProcessor
WiredHome 7:0f058d664b21 371 ///
WiredHome 7:0f058d664b21 372 /// This adds a command to the CommandProcessor. A command has several components
WiredHome 7:0f058d664b21 373 /// to it, including the command name, a brief description, the function to
WiredHome 7:0f058d664b21 374 /// activate when the command is entered, and a flag indicating if the command
WiredHome 7:0f058d664b21 375 /// should show up in the built-in help.
WiredHome 7:0f058d664b21 376 ///
WiredHome 7:0f058d664b21 377 /// @param menu is the menu to add to the CommandProcessor
WiredHome 7:0f058d664b21 378 /// @returns addok if the command was added
WiredHome 7:0f058d664b21 379 /// @returns addfail if the command could not be added (failure to allocate memory for the linked list)
WiredHome 7:0f058d664b21 380 ///
WiredHome 7:0f058d664b21 381 ADDRESULT_T CommandProcessor_Add(CMD_T * menu) {
WiredHome 7:0f058d664b21 382 CMDLINK_T *ptr;
WiredHome 7:0f058d664b21 383 CMDLINK_T *prev;
WiredHome 7:0f058d664b21 384 CMDLINK_T *temp;
WiredHome 7:0f058d664b21 385
WiredHome 12:a8c56bf811b9 386 if (strlen(menu->command) > longestCommand)
WiredHome 12:a8c56bf811b9 387 longestCommand = strlen(menu->command);
WiredHome 15:5f30da93e3e2 388
WiredHome 7:0f058d664b21 389 // Allocate the storage for this menu item
WiredHome 7:0f058d664b21 390 temp = (CMDLINK_T *)malloc(sizeof(CMDLINK_T));
WiredHome 7:0f058d664b21 391 if (!temp)
WiredHome 8:25581f24f7f9 392 return addfailed; // something went really bad
WiredHome 7:0f058d664b21 393 temp->menu = menu;
WiredHome 7:0f058d664b21 394 temp->next = NULL;
WiredHome 7:0f058d664b21 395
WiredHome 7:0f058d664b21 396 prev = ptr = head;
WiredHome 7:0f058d664b21 397 if (!ptr) {
WiredHome 8:25581f24f7f9 398 head = temp; // This installs the very first item
WiredHome 7:0f058d664b21 399 return addok;
WiredHome 7:0f058d664b21 400 }
WiredHome 7:0f058d664b21 401 // Search alphabetically for the insertion point
WiredHome 7:0f058d664b21 402 while (ptr && mystrnicmp(ptr->menu->command, menu->command, strlen(menu->command)) < 0) {
WiredHome 7:0f058d664b21 403 prev = ptr;
WiredHome 7:0f058d664b21 404 ptr = ptr->next;
WiredHome 7:0f058d664b21 405 }
WiredHome 15:5f30da93e3e2 406 if (prev == head) {
WiredHome 15:5f30da93e3e2 407 head = temp;
WiredHome 15:5f30da93e3e2 408 head->next = prev;
WiredHome 15:5f30da93e3e2 409 } else {
WiredHome 15:5f30da93e3e2 410 prev->next = temp;
WiredHome 15:5f30da93e3e2 411 prev = temp;
WiredHome 15:5f30da93e3e2 412 prev->next = ptr;
WiredHome 15:5f30da93e3e2 413 }
WiredHome 7:0f058d664b21 414 return addok;
WiredHome 7:0f058d664b21 415 }
WiredHome 7:0f058d664b21 416
WiredHome 14:7971c8bd3f11 417 static void EchoString(char *p) {
WiredHome 15:5f30da93e3e2 418 while (*p)
WiredHome 15:5f30da93e3e2 419 cfg.putch(*p++);
WiredHome 14:7971c8bd3f11 420 }
WiredHome 14:7971c8bd3f11 421
WiredHome 14:7971c8bd3f11 422 static void EraseChars(int keycount) {
WiredHome 14:7971c8bd3f11 423 while (keycount--) {
WiredHome 14:7971c8bd3f11 424 cfg.putch(0x08); // <bs>
WiredHome 14:7971c8bd3f11 425 cfg.putch(' ');
WiredHome 14:7971c8bd3f11 426 cfg.putch(0x08);
WiredHome 14:7971c8bd3f11 427 }
WiredHome 14:7971c8bd3f11 428 }
WiredHome 14:7971c8bd3f11 429
WiredHome 14:7971c8bd3f11 430
WiredHome 15:5f30da93e3e2 431 static int ProcessComplexSequence(int c) {
WiredHome 15:5f30da93e3e2 432 switch (c) {
WiredHome 15:5f30da93e3e2 433 case 0x42:
WiredHome 15:5f30da93e3e2 434 case 0x50: // down arrow - toward the newest (forward in time)
WiredHome 15:5f30da93e3e2 435 // if there is anything in the history, copy it out
WiredHome 15:5f30da93e3e2 436 if (historyCount && whereInHistory < historyCount) {
WiredHome 15:5f30da93e3e2 437 char *p;
WiredHome 15:5f30da93e3e2 438
WiredHome 15:5f30da93e3e2 439 EraseChars(keycount);
WiredHome 15:5f30da93e3e2 440 p = strcpy(buffer, &historyBuffer[whereInHistory * cfg.bufferSize]);
WiredHome 15:5f30da93e3e2 441 EchoString(p);
WiredHome 15:5f30da93e3e2 442 keycount = strlen(buffer);
WiredHome 15:5f30da93e3e2 443 whereInHistory++;
WiredHome 15:5f30da93e3e2 444 }
WiredHome 15:5f30da93e3e2 445 c = 0;
WiredHome 15:5f30da93e3e2 446 break;
WiredHome 15:5f30da93e3e2 447 case 0x41:
WiredHome 15:5f30da93e3e2 448 case 0x48: // up arrow - from newest to oldest (backward in time)
WiredHome 15:5f30da93e3e2 449 // same as escape
WiredHome 15:5f30da93e3e2 450 if (historyCount && --whereInHistory >= 0) {
WiredHome 15:5f30da93e3e2 451 char *p;
WiredHome 15:5f30da93e3e2 452
WiredHome 15:5f30da93e3e2 453 EraseChars(keycount);
WiredHome 15:5f30da93e3e2 454 p = strcpy(buffer, &historyBuffer[whereInHistory * cfg.bufferSize]);
WiredHome 15:5f30da93e3e2 455 EchoString(p);
WiredHome 15:5f30da93e3e2 456 keycount = strlen(buffer);
WiredHome 15:5f30da93e3e2 457 c = 0;
WiredHome 15:5f30da93e3e2 458 } else {
WiredHome 15:5f30da93e3e2 459 whereInHistory = 0;
WiredHome 15:5f30da93e3e2 460 c = 0x1B;
WiredHome 15:5f30da93e3e2 461 }
WiredHome 15:5f30da93e3e2 462 break;
WiredHome 15:5f30da93e3e2 463 default:
WiredHome 15:5f30da93e3e2 464 // ignore this char
WiredHome 15:5f30da93e3e2 465 c = 0;
WiredHome 15:5f30da93e3e2 466 break;
WiredHome 15:5f30da93e3e2 467 }
WiredHome 15:5f30da93e3e2 468 leadinChar = 0;
WiredHome 15:5f30da93e3e2 469 return c;
WiredHome 15:5f30da93e3e2 470 }
WiredHome 15:5f30da93e3e2 471
WiredHome 15:5f30da93e3e2 472
WiredHome 15:5f30da93e3e2 473 static RUNRESULT_T ProcessStandardSequence(int c) {
WiredHome 15:5f30da93e3e2 474 int foundCount = 0;
WiredHome 15:5f30da93e3e2 475 CMD_T *cbk = NULL;
WiredHome 15:5f30da93e3e2 476 char * params = NULL;
WiredHome 15:5f30da93e3e2 477 RUNRESULT_T val = runok;
WiredHome 15:5f30da93e3e2 478
WiredHome 15:5f30da93e3e2 479 // Process Character
WiredHome 15:5f30da93e3e2 480 switch (c) {
WiredHome 15:5f30da93e3e2 481 case 0:
WiredHome 15:5f30da93e3e2 482 // null - do nothing
WiredHome 15:5f30da93e3e2 483 break;
WiredHome 15:5f30da93e3e2 484 case 0x5B:
WiredHome 15:5f30da93e3e2 485 // ANSI (VT100) sequence
WiredHome 15:5f30da93e3e2 486 // <ESC>[A is up
WiredHome 15:5f30da93e3e2 487 // <ESC>[B is down
WiredHome 15:5f30da93e3e2 488 // <ESC>[C is right
WiredHome 15:5f30da93e3e2 489 // <ESC>[D is left
WiredHome 15:5f30da93e3e2 490 leadinChar = 1;
WiredHome 15:5f30da93e3e2 491 break;
WiredHome 15:5f30da93e3e2 492 case 0xE0:
WiredHome 15:5f30da93e3e2 493 // Windows Command Shell (DOS box)
WiredHome 15:5f30da93e3e2 494 // Lead-in char
WiredHome 15:5f30da93e3e2 495 // 0xE0 0x48 is up arrow
WiredHome 15:5f30da93e3e2 496 // 0xE0 0x50 is down arrow
WiredHome 15:5f30da93e3e2 497 // 0xE0 0x4B is left arrow
WiredHome 15:5f30da93e3e2 498 // 0xE0 0x4D is right arrow
WiredHome 15:5f30da93e3e2 499 leadinChar = 1;
WiredHome 15:5f30da93e3e2 500 break;
WiredHome 15:5f30da93e3e2 501 case 0x09: // <TAB> to request command completion
WiredHome 15:5f30da93e3e2 502 if (1 == CommandMatches(buffer, FALSE, &cbk, &params)) {
WiredHome 15:5f30da93e3e2 503 size_t n;
WiredHome 15:5f30da93e3e2 504 char *p = strchr(buffer, ' ');
WiredHome 15:5f30da93e3e2 505 if (p)
WiredHome 15:5f30da93e3e2 506 n = p - buffer;
WiredHome 15:5f30da93e3e2 507 else
WiredHome 15:5f30da93e3e2 508 n = strlen(buffer);
WiredHome 15:5f30da93e3e2 509 if (n < strlen(cbk->command)) {
WiredHome 15:5f30da93e3e2 510 p = cbk->command + strlen(buffer);
WiredHome 15:5f30da93e3e2 511 mystrcat(buffer, p);
WiredHome 15:5f30da93e3e2 512 keycount = strlen(buffer);
WiredHome 15:5f30da93e3e2 513 EchoString(p);
WiredHome 15:5f30da93e3e2 514 //cfg.printf("%s", p);
WiredHome 15:5f30da93e3e2 515 }
WiredHome 15:5f30da93e3e2 516 }
WiredHome 15:5f30da93e3e2 517 break;
WiredHome 15:5f30da93e3e2 518 case 0x1b: // <ESC> to empty the command buffer
WiredHome 15:5f30da93e3e2 519 EraseChars(keycount);
WiredHome 15:5f30da93e3e2 520 keycount = 0;
WiredHome 15:5f30da93e3e2 521 buffer[keycount] = '\0';
WiredHome 15:5f30da93e3e2 522 break;
WiredHome 15:5f30da93e3e2 523 case '\x08': // <bs>
WiredHome 15:5f30da93e3e2 524 if (keycount) {
WiredHome 15:5f30da93e3e2 525 buffer[--keycount] = '\0';
WiredHome 15:5f30da93e3e2 526 EraseChars(1);
WiredHome 15:5f30da93e3e2 527 } else
WiredHome 15:5f30da93e3e2 528 cfg.putch(0x07); // bell
WiredHome 15:5f30da93e3e2 529 break;
WiredHome 15:5f30da93e3e2 530 case '\r':
WiredHome 15:5f30da93e3e2 531 case '\n':
WiredHome 15:5f30da93e3e2 532 if (strlen(buffer)) {
WiredHome 15:5f30da93e3e2 533 foundCount = CommandMatches(buffer, TRUE, &cbk, &params);
WiredHome 15:5f30da93e3e2 534 if (foundCount == 1) {
WiredHome 15:5f30da93e3e2 535 val = (*cbk->callback)(params); // Execute the command
WiredHome 15:5f30da93e3e2 536 if (mystrnicmp(buffer, (const char *)&historyBuffer[(historyCount-1) * cfg.bufferSize], strlen(&historyBuffer[(historyCount-1) * cfg.bufferSize])) != 0) {
WiredHome 15:5f30da93e3e2 537 // not repeating the last command, so enter into the history
WiredHome 15:5f30da93e3e2 538 if (historyCount == historyDepth) {
WiredHome 15:5f30da93e3e2 539 int i;
WiredHome 15:5f30da93e3e2 540 historyCount--;
WiredHome 15:5f30da93e3e2 541 for (i=0; i<historyCount; i++)
WiredHome 15:5f30da93e3e2 542 strcpy(&historyBuffer[i * cfg.bufferSize], &historyBuffer[(i+1) * cfg.bufferSize]);
WiredHome 15:5f30da93e3e2 543 }
WiredHome 15:5f30da93e3e2 544 strcpy(&historyBuffer[historyCount * cfg.bufferSize], buffer);
WiredHome 15:5f30da93e3e2 545 whereInHistory = historyCount;
WiredHome 15:5f30da93e3e2 546 historyCount++;
WiredHome 15:5f30da93e3e2 547 }
WiredHome 15:5f30da93e3e2 548 } else if (foundCount > 1)
WiredHome 15:5f30da93e3e2 549 cfg.puts(" *** non-unique command ignored try 'Help' ***");
WiredHome 15:5f30da93e3e2 550 else if (foundCount == 0)
WiredHome 15:5f30da93e3e2 551 cfg.puts(" *** huh? try 'Help' ***");
WiredHome 15:5f30da93e3e2 552 } else
WiredHome 15:5f30da93e3e2 553 cfg.puts("");
WiredHome 15:5f30da93e3e2 554 keycount = 0;
WiredHome 15:5f30da93e3e2 555 buffer[keycount] = '\0';
WiredHome 15:5f30da93e3e2 556 showPrompt = TRUE; // forces the prompt
WiredHome 15:5f30da93e3e2 557 break;
WiredHome 15:5f30da93e3e2 558 default:
WiredHome 15:5f30da93e3e2 559 // any other character is assumed to be part of the command
WiredHome 15:5f30da93e3e2 560 if (myisprint(c) && keycount < cfg.bufferSize) {
WiredHome 15:5f30da93e3e2 561 buffer[keycount++] = (char)c;
WiredHome 15:5f30da93e3e2 562 buffer[keycount] = '\0';
WiredHome 15:5f30da93e3e2 563 if (CommandMatches(buffer, FALSE, &cbk, &params))
WiredHome 15:5f30da93e3e2 564 cfg.putch(c);
WiredHome 15:5f30da93e3e2 565 else {
WiredHome 15:5f30da93e3e2 566 buffer[--keycount] = '\0';
WiredHome 15:5f30da93e3e2 567 cfg.putch(0x07); // bell
WiredHome 15:5f30da93e3e2 568 }
WiredHome 15:5f30da93e3e2 569 } else
WiredHome 15:5f30da93e3e2 570 cfg.putch(0x07); // bell
WiredHome 15:5f30da93e3e2 571 break;
WiredHome 15:5f30da93e3e2 572 }
WiredHome 15:5f30da93e3e2 573 return val;
WiredHome 15:5f30da93e3e2 574 }
WiredHome 15:5f30da93e3e2 575
WiredHome 15:5f30da93e3e2 576
WiredHome 15:5f30da93e3e2 577 #if 0
WiredHome 15:5f30da93e3e2 578 static void PutCharToHex(int c) {
WiredHome 15:5f30da93e3e2 579 int upper = c >> 4;
WiredHome 15:5f30da93e3e2 580 int lower = c & 0x0F;
WiredHome 15:5f30da93e3e2 581
WiredHome 15:5f30da93e3e2 582 cfg.putch('[');
WiredHome 15:5f30da93e3e2 583 if (upper >= 10)
WiredHome 15:5f30da93e3e2 584 cfg.putch(upper - 10 + 'A');
WiredHome 15:5f30da93e3e2 585 else
WiredHome 15:5f30da93e3e2 586 cfg.putch(upper + '0');
WiredHome 15:5f30da93e3e2 587 if (lower >= 10)
WiredHome 15:5f30da93e3e2 588 cfg.putch(lower - 10 + 'A');
WiredHome 15:5f30da93e3e2 589 else
WiredHome 15:5f30da93e3e2 590 cfg.putch(lower + '0');
WiredHome 15:5f30da93e3e2 591 cfg.putch(']');
WiredHome 15:5f30da93e3e2 592 }
WiredHome 15:5f30da93e3e2 593 #endif
WiredHome 15:5f30da93e3e2 594
WiredHome 7:0f058d664b21 595 /// Run the CommandProcessor
WiredHome 7:0f058d664b21 596 ///
WiredHome 7:0f058d664b21 597 /// This will peek to see if there is a keystroke ready. It will pull that into a
WiredHome 7:0f058d664b21 598 /// buffer if it is part of a valid command in the command set. You may then enter
WiredHome 7:0f058d664b21 599 /// arguments to the command to be run.
WiredHome 7:0f058d664b21 600 ///
WiredHome 7:0f058d664b21 601 /// Primitive editing is permitted with <bs>.
WiredHome 7:0f058d664b21 602 ///
WiredHome 7:0f058d664b21 603 /// When you press <enter> it will evaluate the command and execute the command
WiredHome 7:0f058d664b21 604 /// passing it the parameter string.
WiredHome 7:0f058d664b21 605 ///
WiredHome 7:0f058d664b21 606 /// @returns runok if the command that was run allows continuation of the CommandProcessor
WiredHome 7:0f058d664b21 607 /// @returns runfail if the command that was run is asking the CommandProcessor to exit
WiredHome 7:0f058d664b21 608 ///
WiredHome 7:0f058d664b21 609 RUNRESULT_T CommandProcessor_Run(void) {
WiredHome 7:0f058d664b21 610 RUNRESULT_T val = runok; // return true when happy, false to exit the prog
WiredHome 7:0f058d664b21 611
WiredHome 15:5f30da93e3e2 612 if (cfg.showSignOnBanner) {
WiredHome 15:5f30da93e3e2 613 cfg.SignOnBanner->callback("");
WiredHome 15:5f30da93e3e2 614 cfg.showSignOnBanner = 0;
WiredHome 15:5f30da93e3e2 615 }
WiredHome 7:0f058d664b21 616 if (showPrompt && cfg.echo) {
WiredHome 7:0f058d664b21 617 cfg.putch('>');
WiredHome 7:0f058d664b21 618 showPrompt = FALSE;
WiredHome 7:0f058d664b21 619 }
WiredHome 7:0f058d664b21 620 if (cfg.kbhit()) {
WiredHome 7:0f058d664b21 621 int c = cfg.getch();
WiredHome 15:5f30da93e3e2 622 //PutCharToHex(c); // a debug utility
WiredHome 15:5f30da93e3e2 623 if (leadinChar) {
WiredHome 15:5f30da93e3e2 624 // some previous character was a lead-in to a more complex sequence
WiredHome 15:5f30da93e3e2 625 // to be processed
WiredHome 15:5f30da93e3e2 626 c = ProcessComplexSequence(c);
WiredHome 7:0f058d664b21 627 }
WiredHome 15:5f30da93e3e2 628 ProcessStandardSequence(c);
WiredHome 7:0f058d664b21 629 }
WiredHome 7:0f058d664b21 630 return val;
WiredHome 7:0f058d664b21 631 }
WiredHome 7:0f058d664b21 632
WiredHome 7:0f058d664b21 633 static RUNRESULT_T CommandProcessor_Echo(int echo) {
WiredHome 7:0f058d664b21 634 cfg.echo = echo;
WiredHome 7:0f058d664b21 635 return runok;
WiredHome 7:0f058d664b21 636 }
WiredHome 7:0f058d664b21 637
WiredHome 7:0f058d664b21 638 /// End the CommandProcessor by freeing all the memory that was allocated
WiredHome 7:0f058d664b21 639 ///
WiredHome 7:0f058d664b21 640 /// @returns runok
WiredHome 7:0f058d664b21 641 ///
WiredHome 7:0f058d664b21 642 RUNRESULT_T CommandProcessor_End(void) {
WiredHome 7:0f058d664b21 643 CMDLINK_T *p = head;
WiredHome 7:0f058d664b21 644 CMDLINK_T *n;
WiredHome 7:0f058d664b21 645
WiredHome 7:0f058d664b21 646 do {
WiredHome 7:0f058d664b21 647 n = p->next;
WiredHome 7:0f058d664b21 648 free(p); // free each of the allocated links to menu items.
WiredHome 7:0f058d664b21 649 p = n;
WiredHome 7:0f058d664b21 650 } while (n);
WiredHome 7:0f058d664b21 651 free(buffer); // finally, free the command buffer
WiredHome 7:0f058d664b21 652 buffer = NULL; // flag it as deallocated
WiredHome 7:0f058d664b21 653 return runok;
WiredHome 7:0f058d664b21 654 }
WiredHome 7:0f058d664b21 655
WiredHome 7:0f058d664b21 656
WiredHome 7:0f058d664b21 657 // Helper functions follow. These functions may exist in some environments and
WiredHome 7:0f058d664b21 658 // not in other combinations of libraries and compilers, so private versions
WiredHome 7:0f058d664b21 659 // are here to ensure consistent behavior.
WiredHome 7:0f058d664b21 660
WiredHome 0:198f53da1bc8 661 /// mytolower exists because not all compiler libraries have this function
WiredHome 0:198f53da1bc8 662 ///
WiredHome 0:198f53da1bc8 663 /// This takes a character and if it is upper-case, it converts it to
WiredHome 0:198f53da1bc8 664 /// lower-case and returns it.
WiredHome 0:198f53da1bc8 665 ///
WiredHome 7:0f058d664b21 666 /// @param a is the character to convert
WiredHome 0:198f53da1bc8 667 /// @returns the lower case equivalent to a
WiredHome 0:198f53da1bc8 668 ///
WiredHome 7:0f058d664b21 669 static char mytolower(char a) {
WiredHome 0:198f53da1bc8 670 if (a >= 'A' && a <= 'Z')
WiredHome 0:198f53da1bc8 671 return (a - 'A' + 'a');
WiredHome 0:198f53da1bc8 672 else
WiredHome 0:198f53da1bc8 673 return a;
WiredHome 0:198f53da1bc8 674 }
WiredHome 0:198f53da1bc8 675
WiredHome 0:198f53da1bc8 676 /// mystrnicmp exists because not all compiler libraries have this function.
WiredHome 0:198f53da1bc8 677 ///
WiredHome 0:198f53da1bc8 678 /// Some have strnicmp, others _strnicmp, and others have C++ methods, which
WiredHome 0:198f53da1bc8 679 /// is outside the scope of this C-portable set of functions.
WiredHome 0:198f53da1bc8 680 ///
WiredHome 7:0f058d664b21 681 /// @param l is a pointer to the string on the left
WiredHome 0:198f53da1bc8 682 /// @param r is a pointer to the string on the right
WiredHome 0:198f53da1bc8 683 /// @param n is the number of characters to compare
WiredHome 0:198f53da1bc8 684 /// @returns -1 if l < r
WiredHome 0:198f53da1bc8 685 /// @returns 0 if l == r
WiredHome 0:198f53da1bc8 686 /// @returns +1 if l > r
WiredHome 0:198f53da1bc8 687 ///
WiredHome 8:25581f24f7f9 688 static int mystrnicmp(const char *l, const char *r, size_t n) {
WiredHome 0:198f53da1bc8 689 int result = 0;
WiredHome 0:198f53da1bc8 690
WiredHome 7:0f058d664b21 691 if (n != 0) {
WiredHome 0:198f53da1bc8 692 do {
WiredHome 0:198f53da1bc8 693 result = mytolower(*l++) - mytolower(*r++);
WiredHome 0:198f53da1bc8 694 } while ((result == 0) && (*l != '\0') && (--n > 0));
WiredHome 0:198f53da1bc8 695 }
WiredHome 0:198f53da1bc8 696 if (result < -1)
WiredHome 0:198f53da1bc8 697 result = -1;
WiredHome 0:198f53da1bc8 698 else if (result > 1)
WiredHome 0:198f53da1bc8 699 result = 1;
WiredHome 0:198f53da1bc8 700 return result;
WiredHome 0:198f53da1bc8 701 }
WiredHome 0:198f53da1bc8 702
WiredHome 0:198f53da1bc8 703 /// mystrcat exists because not all compiler libraries have this function
WiredHome 0:198f53da1bc8 704 ///
WiredHome 7:0f058d664b21 705 /// This function concatinates one string onto another. It is generally
WiredHome 0:198f53da1bc8 706 /// considered unsafe, because of the potential for buffer overflow.
WiredHome 0:198f53da1bc8 707 /// Some libraries offer a strcat_s as the safe version, and others may have
WiredHome 0:198f53da1bc8 708 /// _strcat. Because this is needed only internal to the CommandProcessor,
WiredHome 0:198f53da1bc8 709 /// this version was created.
WiredHome 0:198f53da1bc8 710 ///
WiredHome 7:0f058d664b21 711 /// @param dst is a pointer to the destination string
WiredHome 0:198f53da1bc8 712 /// @param src is a pointer to the source string
WiredHome 0:198f53da1bc8 713 /// @returns nothing
WiredHome 0:198f53da1bc8 714 ///
WiredHome 7:0f058d664b21 715 static void mystrcat(char *dst, char *src) {
WiredHome 0:198f53da1bc8 716 while (*dst)
WiredHome 0:198f53da1bc8 717 dst++;
WiredHome 7:0f058d664b21 718 do
WiredHome 0:198f53da1bc8 719 *dst++ = *src;
WiredHome 0:198f53da1bc8 720 while (*src++);
WiredHome 0:198f53da1bc8 721 }
WiredHome 0:198f53da1bc8 722
WiredHome 0:198f53da1bc8 723 /// myisprint exists because not all compiler libraries have this function
WiredHome 0:198f53da1bc8 724 ///
WiredHome 0:198f53da1bc8 725 /// This function tests a character to see if it is printable (a member
WiredHome 0:198f53da1bc8 726 /// of the standard ASCII set).
WiredHome 0:198f53da1bc8 727 ///
WiredHome 0:198f53da1bc8 728 /// @param c is the character to test
WiredHome 0:198f53da1bc8 729 /// @returns TRUE if the character is printable
WiredHome 0:198f53da1bc8 730 /// @returns FALSE if the character is not printable
WiredHome 0:198f53da1bc8 731 ///
WiredHome 7:0f058d664b21 732 static int myisprint(int c) {
WiredHome 0:198f53da1bc8 733 if (c >= ' ' && c <= '~')
WiredHome 0:198f53da1bc8 734 return TRUE;
WiredHome 0:198f53da1bc8 735 else
WiredHome 0:198f53da1bc8 736 return FALSE;
WiredHome 0:198f53da1bc8 737 }