The CommandProcessor is the interface to install a run-time menu into an embedded system.
Dependents: A_CANAdapter USB2I2C
Diff: CommandProcessor.c
- Revision:
- 7:0f058d664b21
- Parent:
- 6:1a0512faa75d
- Child:
- 8:25581f24f7f9
diff -r 1a0512faa75d -r 0f058d664b21 CommandProcessor.c --- a/CommandProcessor.c Sat Apr 02 17:12:39 2011 +0000 +++ b/CommandProcessor.c Sun Apr 03 21:36:22 2011 +0000 @@ -1,12 +1,12 @@ -/// @file CommandProcessor.c is a simple interface to an interactive -/// command set of user defined commands. +/// @file CommandProcessor.c is a simple interface to an interactive +/// command set of user defined commands. /// -/// With this, you can create functions that are exposed to a console -/// interface. Each command may have 0 or more parameters. -/// Typing the command, or at least the set of characters that make -/// it unique from all other commands is enough to activate the command. -/// -/// Even though it is a c interface, it is somewhat object oriented. +/// With this, you can create functions that are exposed to a console +/// interface. Each command may have 0 or more parameters. +/// Typing the command, or at least the set of characters that make +/// it unique from all other commands is enough to activate the command. +/// +/// Even though it is a c interface, it is somewhat object oriented. /// /// @version 1.0 /// @@ -26,9 +26,17 @@ #include "CommandProcessor.h" /// This holds the single linked list of commands +/// +-- Head->next +/// v +/// +-- p +-- n +/// v v +/// |menu|-------------------------------->|"Command" | +/// |next|->0 |menu|---->|"Help" |"Help" | +/// |next|->0 |"..." |*(callback)| +/// |*(callback) |visible | +/// |visible /// -typedef struct CMDLINK_T -{ +typedef struct CMDLINK_T { CMD_T * menu; // handle to the menu item struct CMDLINK_T * next; // handle to the next link } CMDLINK_T; @@ -37,8 +45,7 @@ static char *buffer; // buffer space must be allocated based on the longest command -static struct -{ +static struct { int caseinsensitive; // FALSE=casesensitive, TRUE=insensitive int echo; // TRUE=echo on, FALSE=echo off int bufferSize; // size of the buffer @@ -52,19 +59,24 @@ int defaultMenu, int caseinsensitive, int echo, - int maxCmdLen, + int maxCmdLen, int (*kbhit)(void), int (*getch)(void), int (*putch)(int ch), int (*puts)(const char * s) - ); +); static ADDRESULT_T CommandProcessor_Add(CMD_T *m); static RUNRESULT_T CommandProcessor_Run(void); static RUNRESULT_T CommandProcessor_End(void); static RUNRESULT_T CommandProcessor_Echo(int echo); -static CMDP_T CommandProcessor = -{ +// helper functions +static int myisprint(int c); +static void mystrcat(char *dst, char *src); +static char mytolower(char a); +int mystrnicmp(const char *l, const char *r, size_t n); + +static CMDP_T CommandProcessor = { CommandProcessor_Init, CommandProcessor_Add, CommandProcessor_Run, @@ -85,27 +97,43 @@ /// Gets a handle to the CommandProcessor /// -/// This returns a handle to the CommandProcessor, which then permits -/// access to the CommandProcessor functions. +/// This returns a handle to the CommandProcessor, which then permits +/// access to the CommandProcessor functions. /// -/// @returns handle to the CommandProcessor +/// @returns handle to the CommandProcessor /// -CMDP_T * GetCommandProcessor(void) -{ +CMDP_T * GetCommandProcessor(void) { return &CommandProcessor; } -static RUNRESULT_T About(char *p) -{ +/// Information about this command processor +/// +/// @param p is a pointer to command line arguments, of which there is +/// none for this function. +/// @returns runok +/// +static RUNRESULT_T About(char *p) { cfg.puts("\r\n About this CommandProcessor:\r\n" - " This CommandProcessor provides easy facility for creating a\r\n" - " runtime CommandProcessor in an embedded systems.\r\n" - " author: David Smart, Smartware Computing\r\n" - ); + " This CommandProcessor provides an easy facility for creating a\r\n" + " runtime interactive interpreter in an embedded system.\r\n" + " Copyright (c) 2011 by Smartware Computing, all rights reserved.\r\n" + " Author: David Smart, Smartware Computing\r\n" + ); return runok; } +/// Turns command prompt echo on and off +/// +/// This command is used to turn the command prompt on and off. When +/// running in an interactive mode, it is best to have this one. +/// When driven by another program, off may be the best choice. +/// +/// This command also displays the current state of the echo mode. +/// +/// @param p is a pointer to a string "on" | "1" | "off" | "0" +/// @returns runok +/// static RUNRESULT_T Echo(char *p) { if (*p) { if (*p == '1' || mystrnicmp(p, "on", 2) == 0) @@ -120,28 +148,21 @@ return runok; } -static RUNRESULT_T Exit(char *p) -{ +static RUNRESULT_T Exit(char *p) { (void)p; - cfg.puts("\r\nbye."); return runexit; } -static RUNRESULT_T Help(char *p) -{ +static RUNRESULT_T Help(char *p) { CMDLINK_T *link = head; char buffer[100]; - cfg.puts("\r\n"); sprintf(buffer, " %-10s: %s", "Command", "Description"); cfg.puts(buffer); - while (link && link->menu) - { - if (link->menu->visible) - { - if (strlen(link->menu->command) + strlen(link->menu->helptext) + 5 < sizeof(buffer)) - { + while (link && link->menu) { + if (link->menu->visible) { + if (strlen(link->menu->command) + strlen(link->menu->helptext) + 5 < sizeof(buffer)) { sprintf(buffer, " %-10s: %s", link->menu->command, link->menu->helptext); cfg.puts(buffer); } @@ -149,34 +170,326 @@ link = link->next; } cfg.puts(""); - if (*p == '?') - { + if (*p == '?') { cfg.puts("\r\n Extended Help\r\n" - " The general form for entering commands is:\r\n" - " >command option1 option2 ...\r\n" - " [note that note all commands support optional parameters]\r\n" - " * Abbreviations of commands may be entered so long as there\r\n" - " is exactly one match in the list of commands. For example,\r\n" - " 'he' is the same as 'help', if there is no other command \r\n" - " that starts with 'he'.\r\n" - " * <bs> can be used to erase previously entered information.\r\n" - " * <esc> can be used to cancel a command.\r\n" - " * <tab> can be used to complete the entry of a partial command.\r\n" - ""); + " The general form for entering commands is:\r\n" + " >command option1 option2 ...\r\n" + " [note that note all commands support optional parameters]\r\n" + " * Abbreviations of commands may be entered so long as there\r\n" + " is exactly one match in the list of commands. For example,\r\n" + " 'he' is the same as 'help', if there is no other command \r\n" + " that starts with 'he'.\r\n" + " * <bs> can be used to erase previously entered information.\r\n" + " * <esc> can be used to cancel a command.\r\n" + " * <tab> can be used to complete the entry of a partial command.\r\n" + ""); } return runok; } +/// CommandMatches is the function that determines if the user is entering a valid +/// command +/// +/// This function gets called whenever the user types a printable character or when +/// they press \<enter\>. +/// The buffer of user input is evaluated to determine if the command is legitimate. +/// It also determines if they want to execute the command, or simply evaluate it. +/// Finally, it identifies writes to user provided pointers, the menu item that +/// matches and a pointer to any parameters that the user entered. +/// +/// @param buffer is the buffer that the user has entered commands into +/// @param exec indicates the intention to execute the command, if found +/// @param menu is a pointer to a pointer to a menu structure, which is updated based on the command +/// @param params is a pointer to a pointer to the user entered parameters +/// @returns the number of menu picks that match the user entered command +/// +static int CommandMatches(char * buffer, int exec, CMD_T **menu, char **params) { + char *space; + int compareLength; + int foundCount = 0; + CMDLINK_T *link = head; + + if (strlen(buffer)) { // simple sanity check + // Try to process the buffer. A command could be "Help", or it could be "Test1 123 abc" + space = strchr(buffer, ' '); // if the command has parameters, find the delimiter + if (space) { + compareLength = space - buffer; + space++; // char after the space + } else { + compareLength = strlen(buffer); + space = buffer + compareLength; + } + while (link && link->menu) { + int cmpResult; + + if (cfg.caseinsensitive) { + cmpResult = mystrnicmp(buffer, link->menu->command, compareLength); + } else + cmpResult = strncmp(buffer, link->menu->command, compareLength); + if (0 == cmpResult) { // A match to what they typed + if (menu) { // yes, we have a callback + *menu = link->menu; // accessor to the command they want to execute + *params = space; + } + foundCount++; // how many command match what they typed so far + } + link = link->next; // follow the link to the next command + } + if (foundCount == 1) { + // If we found exactly one and they expressed an intent to execute that command + // then we'll rewrite the command to be fully qualified + if (exec) { // command wants to execute it, not just validate the command syntax + // If they type "He 1234 5678", we backup and rewrite as "Help 1234 5678" + int diff = strlen((*menu)->command) - compareLength; // e.g. 5 - 3 + + if (diff > 0) { + int back = 0; + char *p; + if (strlen(space)) + back = strlen(space) + 1; + + while (back--) + cfg.putch(0x08); + p = (*menu)->command + compareLength; + while (*p) + cfg.putch(*p++); + cfg.putch(' '); + p = space; + while (*p) + cfg.putch(*p++); + //cfg.printf("%s %s", link->menu->command + compareLength, space); + } + } + } + } + return foundCount; +} + +/// Initialize the CommandProcessor +/// +/// This initializes the CommandProcessor by adding the built-in menus +/// +/// @param addDefaultMenu configures it to add the Help, About, and Exit menus +/// @param bufSize configures the size of the longest command, which must be +/// greater than 6 (the size of "About\0"). +/// @returns initok if it successfully initialized the CommandProcessor +/// @returns initfailed if it could not allocate memory +/// +INITRESULT_T CommandProcessor_Init( + int addDefaultMenu, + int caseinsensitive, + int echo, + int maxCmdLen, + int (*kbhit)(void), + int (*getch)(void), + int (*putch)(int ch), + int (*puts)(const char * s) +) { + if (maxCmdLen < 6) + maxCmdLen = 6; + buffer = (char *)malloc(maxCmdLen+1); + cfg.bufferSize = maxCmdLen; + if (buffer) { + if (addDefaultMenu & 0x0008) + CommandProcessor.Add(&QuestionMenu); + if (addDefaultMenu & 0x0008) + CommandProcessor.Add(&HelpMenu); + if (addDefaultMenu & 0x0004) + CommandProcessor.Add(&EchoMenu); + if (addDefaultMenu & 0x0002) + CommandProcessor.Add(&AboutMenu); + if (addDefaultMenu & 0x0001) + CommandProcessor.Add(&ExitMenu); + cfg.caseinsensitive = caseinsensitive; + cfg.echo = echo; + cfg.kbhit = kbhit; + cfg.getch = getch; + cfg.putch = putch; + cfg.puts = puts; + return initok; + } else + return initfailed; +} + +/// Add a command to the CommandProcessor +/// +/// This adds a command to the CommandProcessor. A command has several components +/// to it, including the command name, a brief description, the function to +/// activate when the command is entered, and a flag indicating if the command +/// should show up in the built-in help. +/// +/// @param menu is the menu to add to the CommandProcessor +/// @returns addok if the command was added +/// @returns addfail if the command could not be added (failure to allocate memory for the linked list) +/// +ADDRESULT_T CommandProcessor_Add(CMD_T * menu) { + CMDLINK_T *ptr; + CMDLINK_T *prev; + CMDLINK_T *temp; + + // Allocate the storage for this menu item + temp = (CMDLINK_T *)malloc(sizeof(CMDLINK_T)); + if (!temp) + return addfailed; // something went really bad + temp->menu = menu; + temp->next = NULL; + + prev = ptr = head; + if (!ptr) { + head = temp; // This installs the very first item + return addok; + } + // Search alphabetically for the insertion point + while (ptr && mystrnicmp(ptr->menu->command, menu->command, strlen(menu->command)) < 0) { + prev = ptr; + ptr = ptr->next; + } + prev->next = temp; + prev = temp; + prev->next = ptr; + return addok; +} + +/// Run the CommandProcessor +/// +/// This will peek to see if there is a keystroke ready. It will pull that into a +/// buffer if it is part of a valid command in the command set. You may then enter +/// arguments to the command to be run. +/// +/// Primitive editing is permitted with <bs>. +/// +/// When you press <enter> it will evaluate the command and execute the command +/// passing it the parameter string. +/// +/// @returns runok if the command that was run allows continuation of the CommandProcessor +/// @returns runfail if the command that was run is asking the CommandProcessor to exit +/// +RUNRESULT_T CommandProcessor_Run(void) { + static int showPrompt = TRUE; + static int keycount = 0; // how full? + RUNRESULT_T val = runok; // return true when happy, false to exit the prog + CMD_T *cbk = NULL; + char * params = NULL; + + if (showPrompt && cfg.echo) { + cfg.putch('>'); + showPrompt = FALSE; + } + if (cfg.kbhit()) { + int c = cfg.getch(); + + switch (c) { + case 0x09: // <TAB> to request command completion + if (1 == CommandMatches(buffer, FALSE, &cbk, ¶ms)) { + size_t n; + char *p = strchr(buffer, ' '); + if (p) + n = p - buffer; + else + n = strlen(buffer); + if (n < strlen(cbk->command)) { + p = cbk->command + strlen(buffer); + mystrcat(buffer, p); + keycount = strlen(buffer); + while (*p) + cfg.putch(*p++); + //cfg.printf("%s", p); + } + } + break; + case 0x1b: // <ESC> to empty the command buffer + while (keycount--) { + cfg.putch(0x08); // <bs> + cfg.putch(' '); + cfg.putch(0x08); + } + keycount = 0; + buffer[keycount] = '\0'; + break; + case '\x08': // <bs> + if (keycount) { + buffer[--keycount] = '\0'; + cfg.putch(0x08); + cfg.putch(' '); + cfg.putch(0x08); + } else + cfg.putch(0x07); // bell + break; + case '\r': + case '\n': { + int foundCount = 0; + + if (strlen(buffer)) { + foundCount = CommandMatches(buffer, TRUE, &cbk, ¶ms); + if (foundCount == 1) { + val = (*cbk->callback)(params); // Execute the command + } else if (foundCount > 1) + cfg.puts(" *** non-unique command ignored try 'Help' ***"); + else if (foundCount == 0) + cfg.puts(" *** huh? try 'Help' ***"); + } else + cfg.puts(""); + keycount = 0; + buffer[keycount] = '\0'; + showPrompt = TRUE; // forces the prompt + } + break; + default: + if (myisprint(c) && keycount < cfg.bufferSize) { + buffer[keycount++] = c; + buffer[keycount] = '\0'; + if (CommandMatches(buffer, FALSE, &cbk, ¶ms)) + cfg.putch(c); + else { + buffer[--keycount] = '\0'; + cfg.putch(0x07); // bell + } + } else + cfg.putch(0x07); // bell + break; + } + } + return val; +} + + +static RUNRESULT_T CommandProcessor_Echo(int echo) { + cfg.echo = echo; + return runok; +} + +/// End the CommandProcessor by freeing all the memory that was allocated +/// +/// @returns runok +/// +RUNRESULT_T CommandProcessor_End(void) { + CMDLINK_T *p = head; + CMDLINK_T *n; + + do { + n = p->next; + free(p); // free each of the allocated links to menu items. + p = n; + } while (n); + free(buffer); // finally, free the command buffer + buffer = NULL; // flag it as deallocated + return runok; +} + + +// Helper functions follow. These functions may exist in some environments and +// not in other combinations of libraries and compilers, so private versions +// are here to ensure consistent behavior. + /// mytolower exists because not all compiler libraries have this function /// /// This takes a character and if it is upper-case, it converts it to /// lower-case and returns it. /// -/// @param a is the character to convert +/// @param a is the character to convert /// @returns the lower case equivalent to a /// -char mytolower(char a) -{ +static char mytolower(char a) { if (a >= 'A' && a <= 'Z') return (a - 'A' + 'a'); else @@ -188,19 +501,17 @@ /// Some have strnicmp, others _strnicmp, and others have C++ methods, which /// is outside the scope of this C-portable set of functions. /// -/// @param l is a pointer to the string on the left +/// @param l is a pointer to the string on the left /// @param r is a pointer to the string on the right /// @param n is the number of characters to compare /// @returns -1 if l < r /// @returns 0 if l == r /// @returns +1 if l > r /// -int mystrnicmp(const char *l, const char *r, size_t n) -{ +int mystrnicmp(const char *l, const char *r, size_t n) { int result = 0; - if (n != 0) - { + if (n != 0) { do { result = mytolower(*l++) - mytolower(*r++); } while ((result == 0) && (*l != '\0') && (--n > 0)); @@ -214,21 +525,20 @@ /// mystrcat exists because not all compiler libraries have this function /// -/// This function concatinates one string onto another. It is generally +/// This function concatinates one string onto another. It is generally /// considered unsafe, because of the potential for buffer overflow. /// Some libraries offer a strcat_s as the safe version, and others may have /// _strcat. Because this is needed only internal to the CommandProcessor, /// this version was created. /// -/// @param dst is a pointer to the destination string +/// @param dst is a pointer to the destination string /// @param src is a pointer to the source string /// @returns nothing /// -void mystrcat(char *dst, char *src) -{ +static void mystrcat(char *dst, char *src) { while (*dst) dst++; - do + do *dst++ = *src; while (*src++); } @@ -242,337 +552,10 @@ /// @returns TRUE if the character is printable /// @returns FALSE if the character is not printable /// -static int myisprint(int c) -{ +static int myisprint(int c) { if (c >= ' ' && c <= '~') return TRUE; else return FALSE; } - -/// CommandMatches is the function that determines if the user is entering a valid -/// command -/// -/// This function gets called whenever the user types a printable character or when -/// they press \<enter\>. -/// The buffer of user input is evaluated to determine if the command is legitimate. -/// It also determines if they want to execute the command, or simply evaluate it. -/// Finally, it identifies writes to user provided pointers, the menu item that -/// matches and a pointer to any parameters that the user entered. -/// -/// @param buffer is the buffer that the user has entered commands into -/// @param exec indicates the intention to execute the command, if found -/// @param menu is a pointer to a pointer to a menu structure, which is updated based on the command -/// @param params is a pointer to a pointer to the user entered parameters -/// @returns the number of menu picks that match the user entered command -/// -static int CommandMatches(char * buffer, int exec, CMD_T **menu, char ** params) -{ - char *space; - int compareLength; - int foundCount = 0; - CMDLINK_T *link = head; - - if (strlen(buffer)) // simple sanity check - { - // Try to process the buffer. A command could be "Help", or it could be "Test1 123 abc" - space = strchr(buffer, ' '); // if the command has parameters, find the delimiter - if (space) - { - compareLength = space - buffer; - space++; // char after the space - } - else - { - compareLength = strlen(buffer); - space = buffer + compareLength; - } - while (link && link->menu) - { - int cmpResult; - - if (cfg.caseinsensitive) - { - cmpResult = mystrnicmp(buffer, link->menu->command, compareLength); - } - else - cmpResult = strncmp(buffer, link->menu->command, compareLength); - if (0 == cmpResult) // A match to what they typed - { - if (menu) // yes, we have a callback - { - if (exec) // command wants to execute it, not just validate the command syntax - { - // If they type "He 1234 5678", we backup and rewrite as "Help 1234 5678" - int diff = strlen(link->menu->command) - compareLength; // e.g. 5 - 3 - - if (diff > 0) - { - int back = 0; - char *p; - if (strlen(space)) - back = strlen(space) + 1; - - while (back--) - cfg.putch(0x08); - p = link->menu->command + compareLength; - while (*p) - cfg.putch(*p++); - cfg.putch(' '); - p = space; - while (*p) - cfg.putch(*p++); - //cfg.printf("%s %s", link->menu->command + compareLength, space); - } - } - *menu = link->menu; // accessor to the command they want to execute - *params = space; - } - foundCount++; // how many command match what they typed so far - } - link = link->next; // follow the link to the next command - } - } - return foundCount; -} - -/// Initialize the CommandProcessor -/// -/// This initializes the CommandProcessor by adding the built-in menus -/// -/// @param addDefaultMenu configures it to add the Help, About, and Exit menus -/// @param bufSize configures the size of the longest command, which must be -/// greater than 6 (the size of "About\0"). -/// @returns initok if it successfully initialized the CommandProcessor -/// @returns initfailed if it could not allocate memory -/// -INITRESULT_T CommandProcessor_Init( - int addDefaultMenu, - int caseinsensitive, - int echo, - int maxCmdLen, - int (*kbhit)(void), - int (*getch)(void), - int (*putch)(int ch), - int (*puts)(const char * s) - ) -{ - if (maxCmdLen < 6) - maxCmdLen = 6; - buffer = (char *)malloc(maxCmdLen+1); - cfg.bufferSize = maxCmdLen; - if (buffer) - { - if (addDefaultMenu & 0x0008) - CommandProcessor.Add(&QuestionMenu); - if (addDefaultMenu & 0x0008) - CommandProcessor.Add(&HelpMenu); - if (addDefaultMenu & 0x0004) - CommandProcessor.Add(&EchoMenu); - if (addDefaultMenu & 0x0002) - CommandProcessor.Add(&AboutMenu); - if (addDefaultMenu & 0x0001) - CommandProcessor.Add(&ExitMenu); - cfg.caseinsensitive = caseinsensitive; - cfg.echo = echo; - cfg.kbhit = kbhit; - cfg.getch = getch; - cfg.putch = putch; - cfg.puts = puts; - return initok; - } - else - return initfailed; -} - -/// Add a command to the CommandProcessor -/// -/// This adds a command to the CommandProcessor. A command has several components -/// to it, including the command name, a brief description, the function to -/// activate when the command is entered, and a flag indicating if the command -/// should show up in the built-in help. -/// -/// @todo sort them when adding a menu item -/// -/// @param m is the menu to add to the CommandProcessor -/// @returns addok if the command was added -/// @returns addfail if the command could not be added (failure to allocate memory for the linked list) -/// -ADDRESULT_T CommandProcessor_Add(CMD_T * m) -{ - CMDLINK_T *p; - - if (head == NULL) - { - head = (CMDLINK_T *)malloc(sizeof(CMDLINK_T)); - if (!head) - return addfailed; - head->menu = NULL; - head->next = NULL; - } - p = head; - while (p->next) - p = p->next; - if (p->menu == NULL) - { - p->menu = m; - return addok; - } - else if (p->next == NULL) - { - p->next = (CMDLINK_T *)malloc(sizeof(CMDLINK_T)); - if (!p->next) - return addfailed; - p = p->next; - p->menu = m; - p->next = NULL; - return addok; - } - return addfailed; -} - -/// Run the CommandProcessor -/// -/// This will peek to see if there is a keystroke ready. It will pull that into a -/// buffer if it is part of a valid command in the command set. You may then enter -/// arguments to the command to be run. -/// -/// Primitive editing is permitted with <bs>. -/// -/// When you press <enter> it will evaluate the command and execute the command -/// passing it the parameter string. -/// -/// @returns runok if the command that was run allows continuation of the CommandProcessor -/// @returns runfail if the command that was run is asking the CommandProcessor to exit -/// -RUNRESULT_T CommandProcessor_Run(void) -{ - static int showPrompt = TRUE; - static int keycount = 0; // how full? - RUNRESULT_T val = runok; // return true when happy, false to exit the prog - CMD_T *cbk = NULL; - char * params = NULL; - - if (showPrompt && cfg.echo) - { - cfg.putch('>'); - showPrompt = FALSE; - } - if (cfg.kbhit()) - { - int c = cfg.getch(); - - switch (c) - { - case 0x09: // <TAB> to request command completion - if (1 == CommandMatches(buffer, FALSE, &cbk, ¶ms)) - { - size_t n; - char *p = strchr(buffer, ' '); - if (p) - n = p - buffer; - else - n = strlen(buffer); - if (n < strlen(cbk->command)) - { - p = cbk->command + strlen(buffer); - mystrcat(buffer, p); - keycount = strlen(buffer); - while (*p) - cfg.putch(*p++); - //cfg.printf("%s", p); - } - } - break; - case 0x1b: // <ESC> to empty the command buffer - while (keycount--) - { - cfg.putch(0x08); // <bs> - cfg.putch(' '); - cfg.putch(0x08); - } - keycount = 0; - buffer[keycount] = '\0'; - break; - case '\x08': // <bs> - if (keycount) - { - buffer[--keycount] = '\0'; - cfg.putch(0x08); - cfg.putch(' '); - cfg.putch(0x08); - } - else - cfg.putch(0x07); // bell - break; - case '\r': - case '\n': - { - int foundCount = 0; - - if (strlen(buffer)) - { - foundCount = CommandMatches(buffer, TRUE, &cbk, ¶ms); - if (foundCount == 1) - { - val = (*cbk->callback)(params); // Execute the command - } - else if (foundCount > 1) - cfg.puts(" *** non-unique command ignored try 'Help' ***"); - else if (foundCount == 0) - cfg.puts(" *** huh? try 'Help' ***"); - } - else - cfg.puts(""); - keycount = 0; - buffer[keycount] = '\0'; - showPrompt = TRUE; // forces the prompt - } - break; - default: - if (myisprint(c) && keycount < cfg.bufferSize) - { - buffer[keycount++] = c; - buffer[keycount] = '\0'; - if (CommandMatches(buffer, FALSE, &cbk, ¶ms)) - cfg.putch(c); - else - { - buffer[--keycount] = '\0'; - cfg.putch(0x07); // bell - } - } - else - cfg.putch(0x07); // bell - break; - } - } - return val; -} - - -static RUNRESULT_T CommandProcessor_Echo(int echo) { - cfg.echo = echo; - return runok; -} - -/// End the CommandProcessor by freeing all the memory that was allocated -/// -/// returns runok -/// -RUNRESULT_T CommandProcessor_End(void) -{ - CMDLINK_T *p = head; - CMDLINK_T *n; - - do - { - n = p->next; - free(p); // free each of the allocated links to menu items. - p = n; - } while (n); - free(buffer); // finally, free the command buffer - buffer = NULL; // flag it as deallocated - return runok; -}