A Command Interpreter with support for used defined commands, subsystems, macros, help and parameter parsing.

Revision:
3:abbf43fab7d5
Parent:
0:4d95ee0b4c37
Child:
6:76b033971c3c
diff -r 7d00f6d78090 -r abbf43fab7d5 cmdb.cpp
--- a/cmdb.cpp	Thu Feb 10 18:54:17 2011 +0000
+++ b/cmdb.cpp	Thu Feb 10 19:10:42 2011 +0000
@@ -1,883 +1,883 @@
-#include <vector>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cmdb.h"
-#include "mbed.h"
-
-//DONE Pass Serial into constructor for printf, putc and getc.
-//DONE CID_<subsystem> must be handled internally.
-//
-//TODO ADD Documentation.
-//TODO CID_HELP must be handled internally (like all system commands (IDLE/MACRO etc).
-//TODO CID_HELP should be function (so we can call it easier in the switche's else branch).
-//TODO Link CID_LAST to Vector Size.
-
-//Constructor (see http://www.daniweb.com/forums/thread293338.html)
-Cmdb::Cmdb(const Serial serial, const std::vector<cmdb_cmd>& cmds) :  _serial(serial), _cmds(cmds) {
-    echo = true;
-    bold = true;
-    subsystem = -1;
-
-    CID_LAST = _cmds.back().id;
-    CMD_TBL_LEN = cmds.size();
-
-    cmdb_init(true);
-}
-
-//Public
-bool  Cmdb::cmdb_macro_hasnext() {
-    return macro_ptr!=-1 && macro_ptr<MAX_CMD_LEN && macro_buf[macro_ptr];
-}
-
-char Cmdb::cmdb_macro_next() {
-    char ch = macro_buf[macro_ptr++];
-    if (macro_ptr==MAX_CMD_LEN) {
-        cmdb_macro_reset();
-    }
-    return ch;
-}
-
-char  Cmdb::cmdb_macro_peek() {
-    return macro_buf[macro_ptr];
-}
-
-void  Cmdb::cmdb_macro_reset() {
-    macro_ptr         = -1;
-    macro_buf[0]     = '\0';
-}
-
-bool  Cmdb::cmdb_hasnext() {
-    return _serial.readable()==1;
-}
-
-char  Cmdb::cmdb_next() {
-    return _serial.getc();
-}
-
-//Private Utilities #1
-
-int  Cmdb::cmdb_escid_search(char *escstr) {
-    for (int i=0; i<ESC_TBL_LEN; i++) {
-        if (strcmp (esc_tbl[i].escstr, escstr) == 0)
-            return (esc_tbl[i].id);
-    }
-
-    return (EID_LAST);
-}
-
-int  Cmdb::cmdb_cmdid_search(char *cmdstr) {
-    //Warning, we return the ID but somewhere assume it's equal to the array index!
-    for (int i=0; i<CMD_TBL_LEN; i++) {
-        if ((stricmp (_cmds[i].cmdstr, cmdstr) == 0) && ((_cmds[i].subs == subsystem) || (_cmds[i].subs<0)))
-            return (_cmds[i].id);
-    }
-
-    return (CID_LAST);
-}
-
-int  Cmdb::cmdb_cmdid_index(int cmdid) {
-    for (int i=0; i<CMD_TBL_LEN; i++) {
-        if (_cmds[i].id==cmdid)
-            return i;
-    }
-
-    return -1;
-}
-
-int Cmdb::cmdb_parse(char *cmd) {
-    //Command
-    char cmdstr_buf [1 + MAX_CMD_LEN];
-
-    //Parameters
-    char argstr_buf [1 + MAX_CMD_LEN];
-    char *argsep;
-
-    char prmstr_buf [1 + MAX_CMD_LEN];                          //copy of sscanf pattern
-    char *tok;                                                  //current token
-    void *toks[MAX_ARGS];                                       //pointers to string tokens IN commandline (argstr_buf)
-    char *prms[MAX_ARGS];                                       //patterns IN copy of sscanf string (*parms)
-
-    char typ = '\0';                                            //Var type
-    char mod = '\0';                                            //Var modifier      (for cardinal types)
-    unsigned int base;                                          //Var number base (8,10,16)
-    //unsigned int bytes;                                       //Var size in bytes (used for malloc)
-
-    float f;                                                    //Temp var for conversion, 4 bytes
-    //unsigned char b;                                          //Temp var for conversion, 1 byte
-    //char c;                                                    //Temp var for conversion, 1 byte
-    //short h;                                                  //Temp var for conversion, 2 bytes
-    //int k;                                                    //Temp var for conversion, 2 bytes
-    long l;                                                     //Temp var for conversion, 4 bytes
-
-    char* endptr;                                               //strtoXX() Error detection
-
-    signed char id;
-    unsigned int  i;
-
-    //Init (global) variables.
-    argfnd=0;
-    argcnt=0;
-    error =0;
-
-    //Signals empty string...
-    id=-1;
-
-    //Zero the two string buffers for splitting cmd string into.
-    zeromemory((char*)cmdstr_buf,sizeof(cmdstr_buf));
-    zeromemory(argstr_buf,sizeof(argstr_buf));
-
-    //Make it worse in Lint
-    for (i=0;i<MAX_ARGS;i++) {
-        parms[i].type=PARM_UNUSED;
-        zeromemory((char*)&(parms[i].val),sizeof(parms[i].val));
-    }
-
-    /*------------------------------------------------
-    First, copy the command and convert it to all
-    uppercase.
-    ------------------------------------------------*/
-
-    strncpy(cmdstr_buf, cmd, sizeof (cmdstr_buf) - 1);
-    cmdstr_buf [sizeof (cmdstr_buf) - 1] = '\0';
-
-    /*------------------------------------------------
-    Next, find the end of the first thing in the
-    buffer.  Since the command ends with a space,
-    we'll look for that.  NULL-Terminate the command
-    and keep a pointer to the arguments.
-    ------------------------------------------------*/
-
-    argsep = strchr(cmdstr_buf, ' ');
-
-    if (argsep == NULL) {
-        argstr_buf [0] = '\0';
-    } else {
-        strcpy (argstr_buf, argsep + 1);
-        *argsep = '\0';
-    }
-
-    /*------------------------------------------------
-    Search for a command ID, then switch on it.  Note
-    that I removed my action items for each command,
-    but you would invoke each function here.
-    VEG:Watch out ID  not neccesarily equal to Array Index!
-    ------------------------------------------------*/
-
-    //1) Find the Command Id
-    id = cmdb_cmdid_search(cmdstr_buf);
-
-    if (id!=CID_LAST) {
-        //2) Tokenize a copy of the parms from the cmd_tbl.
-
-        //Get Format patterns from cmd_tbl[id].parms.
-        //Note: strtok inserts \0 into the original string. Hence the copy.
-        zeromemory((char *)(&prmstr_buf),sizeof(prmstr_buf));
-
-        strncpy (prmstr_buf, _cmds[id].parms, sizeof (prmstr_buf) - 1);
-
-        argcnt=0;
-        tok = strtok(prmstr_buf, " ");
-        while (tok != NULL) {
-            //Store Pointers
-            prms[argcnt++] = tok;
-
-            //cmdb_printf("prm_%2.2d='%s'\r\n",argcnt, tok);
-
-            tok = strtok(NULL, " ");
-        }
-
-        //3) Tokenize the commandline.
-
-        //Get Tokens from arguments.
-        //Note: strtok inserts \0 into the original string. Won't harm here as we do not re-use it.
-
-        argfnd=0;
-
-        if (strlen(argstr_buf)!=0) {
-            tok = strtok(argstr_buf, " ");
-        } else {
-            tok=NULL;
-        }
-
-        while (tok != NULL) {
-            //Store Pointers
-            toks[argfnd++]=tok;
-
-            //cmdb_printf("tok_%2.2d='%s'\r\n",argfnd, tok);
-
-            tok = strtok(NULL, " ");
-        }
-
-        if (argfnd==argcnt || (id==CID_HELP && argfnd==0)) {
-
-            error = 0;
-
-            for (i=0;i<argcnt;i++) {
-                //cmdb_printf("prm_%2.2d=%s\r\n",i, prms[i]);
-
-                switch (strlen(prms[i])) {
-                    case 0:
-                        break;
-                    case 1:
-                        break;
-                    case 2: //Simple pattern, no modifier
-                        mod='\0';
-                        typ=prms[i][1];
-
-                        break;
-                    case 3: //pattern with Modifier.
-                        mod=prms[i][1];
-                        typ=prms[i][2];
-
-                        break;
-                    default:
-                        break;
-                }
-
-                switch (typ) {
-                    case 'o' :
-                        base=8;
-                        break;
-                    case 'x' :
-                        base=16;
-                        break;
-                    default:
-                        base=10;
-                        break;
-                }
-
-                endptr = (char*)toks[i];
-
-                //Cardinal Types
-                switch (typ) {
-                    case 'd' :  //Check mod
-                    case 'i' :  //Check mod
-                    case 'u' :  //Check mod
-                    case 'o' :  //Check mod
-                    case 'x' :  //Check mod
-                        switch (mod) {
-                            case 'b' : //char
-                                //test range
-                                l=strtol((char*)toks[i], &endptr, base);
-                                if (l>=MIN_BYTE && l<=MAX_BYTE) {
-                                    parms[i].type=PARM_CHAR;
-                                    parms[i].val.uc =(unsigned char)l;
-                                } else {
-                                    error = i+1;
-                                }
-
-                                break;
-                            case 'h' : //short
-                                l=strtol((char*)toks[i], &endptr, base);
-                                if (l>=MIN_SHORT && l<=MAX_SHORT) {
-                                    parms[i].type=PARM_SHORT;
-                                    parms[i].val.w=(short)l;
-                                } else {
-                                    error = i+1;
-                                }
-
-                                break;
-                            case 'l' : //long
-                                l=strtol((char*)toks[i], &endptr, base);
-                                parms[i].type=PARM_LONG;
-                                parms[i].val.l=l;
-
-                                break;
-                            default:
-                                l=strtol((char*)toks[i], &endptr, base);
-                                if (l>=MIN_INT && l<=MAX_INT) {
-                                    parms[i].type=PARM_INT;
-                                    parms[i].val.l=(int)l;
-                                } else {
-                                    error = i+1;
-                                }
-                                break;
-                        }
-
-                        if (error==0 &&
-                                (endptr==toks[i]    //No Conversion at all.
-                                 || *endptr)) {       //Incomplete conversion.
-                            error = i+1;
-                        }
-
-                        break;
-                }
-
-                //Floating Point Types
-                switch (typ) {
-                    case 'e' :
-                    case 'f' :
-                    case 'g' :
-                        f = strtod((char*)toks[i], &endptr);
-
-                        parms[i].type=PARM_FLOAT;
-                        parms[i].val.f=f;
-
-                        if (error==0 &&
-                                (endptr==toks[i]    //No Conversion at all.
-                                 || *endptr)) {       //Incomplete conversion.
-                            error = i;
-                        }
-
-                        break;
-                }
-
-                //String types
-                switch (typ) {
-                    case 'c' :
-                        parms[i].type=PARM_CHAR;
-                        parms[i].val.c=((char*)toks[i])[0];
-
-                        if (error==0 && strlen((char*)toks[i])!=1) {  //Incomplete conversion.
-                            error = i;
-                        }
-
-                        break;
-
-                    case 's' :
-                        parms[i].type=PARM_STRING;
-                        strncpy(parms[i].val.s,(char*)toks[i], strlen((char*)toks[i]));
-
-                        break;
-                }
-            }
-        } else {
-            //id=CID_LAST;
-        }
-    }
-
-    return id;
-}
-
-void  Cmdb::cmdb_cmd_proc(char *cmd) {
-    int  cid;
-    int  ndx;
-
-    cid = cmdb_parse(cmd);
-    ndx = cmdb_cmdid_index(cid);
-
-    if (cid!=-1) {
-
-        /*------------------------------------------------
-        Process the command and it's arguments that are
-        found. id contains the command id and argcnt &
-        argfnd the number of found and expected paramaters
-        parms contains the parsed argument values and their
-        types.
-        ------------------------------------------------*/
-
-        if (cid==CID_LAST) {
-            cmdb_print("Unknown command, type 'Help' for a list of available commands.\r\n");
-        } else {
-
-            //Test for more commandline than allowed too.
-            //i.e. run 1 is wrong.
-
-            //TODO Fix Index/Id problem.
-
-            if (argcnt==0 && argfnd==0 && error==0 && ndx!=-1 && _cmds[ndx].subs==SUBSYSTEM) {
-                subsystem=cid;
-            } else if ( ((cid==CID_HELP) || (argcnt==argfnd)) && error==0 ) {
-                switch (cid) {
-
-                        /////// GLOBAL MACRO COMMANDS ///////
-
-                        //Define Macro from commandline
-                    case CID_MACRO:
-                        macro_ptr=-1;
-                        strncpy(macro_buf, STRINGPARM(0), sizeof(macro_buf) - 1);
-                        break;
-
-                        //Run Macro
-                    case CID_RUN:
-                        macro_ptr=0;
-                        break;
-
-                        //List Macro's
-                    case CID_MACROS:
-                        cmdb_print("[Macro]\r\n");
-                        if (macro_buf[0]) {
-                            cmdb_printf("Value=%s\r\n",macro_buf);
-                        } else {
-                            cmdb_printf(";No Macro Defined\r\n");
-                        }
-                        break;
-
-                        /////// GLOBAL STATEMACHINE COMMANDS ///////
-
-#ifdef STATEMACHINE
-
-                        //Start State Machine
-                    case CID_STATE:
-                        statemachine(BYTEPARM(0));
-
-                        break;
-#endif
-
-                        /////// GLOBAL COMMANDS ///////
-
-                        //Echo
-                    case CID_ECHO:
-                        echo = BOOLPARM(0);
-                        break;
-
-                        //Bold
-                    case CID_BOLD:
-                        bold = BOOLPARM(0);
-                        break;
-
-                        //Warm Boot
-                    case CID_BOOT:
-                        //reset();
-                        break;
-
-                        //Sends an ANSI escape code to clear the screen.
-                    case CID_CLS:
-                        cmdb_print(cls);
-                        break;
-
-                        //Returns to CMD> prompt where most commands are disabled.
-                    case CID_IDLE:
-                        subsystem=-1;
-                        break;
-
-                        //Help
-                    case CID_HELP: {
-
-//TODO Handle Subsystem
-
-//TODO Call command processor callback and if it returns false we supply help.
-
-                        cmdb_print("\r\n");
-
-                        if (argfnd>0) {
-                            cid = cmdb_cmdid_search(STRINGPARM(0));
-                        } else {
-                            cid=CID_LAST;
-                        }
-
-                        if (argfnd>0 && cid!=CID_LAST) {
-
-                            //Help with a valid command as first parameter
-                            ndx = cmdb_cmdid_index(cid);
-
-                            switch (_cmds[ndx].subs) {
-                                case SUBSYSTEM: //Dump whole subsystem
-                                    cmdb_printf("%s subsystem commands:\r\n\r\n",_cmds[ndx].cmdstr);
-
-                                    for (int i=0;i<CMD_TBL_LEN-1;i++) {
-                                        if (_cmds[i].subs==ndx) {
-                                            cmdb_cmdhelp("",i,",\r\n");
-                                        }
-                                    }
-
-                                    break;
-
-                                case GLOBALCMD: //Dump command only
-                                    //cmdb_print("Global command:\r\n\r\n",cmd_tbl[cmd_tbl[ndx].subs].cmdstr);
-                                    cmdb_cmdhelp("Syntax: ",ndx,".\r\n");
-                                    break;
-
-                                default:        //Dump one subsystem command
-                                    cmdb_printf("%s subsystem command:\r\n\r\n",_cmds[_cmds[ndx].subs].cmdstr);
-                                    cmdb_cmdhelp("Syntax: ",ndx,".\r\n");
-                                    break;
-                            }
-                        } else {
-                            if (argfnd>0) {
-                                //Help with invalid command as first parameter
-                                cmdb_print("Unknown command, type 'Help' for a list of available commands.\r\n");
-                            } else {
-                                //Help
-
-                                //Dump Active Subsystem, Global & Other (dormant) Subsystems
-                                for (int i=0;i<CMD_TBL_LEN-1;i++) {
-                                    if ((_cmds[i].subs<0) || (_cmds[i].subs==subsystem)) {
-                                        cmdb_cmdhelp("",i,",\r\n");
-                                    }
-                                }
-                                cmdb_cmdhelp("",CMD_TBL_LEN-1,".\r\n");
-                            }
-                        }
-                        cmdb_print("\r\n");
-                        break;
-                    } //CID_HELP
-                }
-            } else {
-                cmdb_cmdhelp("Syntax: ",ndx,".\r\n");
-            }
-        }
-    }
-}
-
-//Private Utilities #2
-
-void  Cmdb::cmdb_init(const char full) {
-    if (full) {
-        echo = true;
-        bold = true;
-
-        subsystem = -1;
-
-        lstbuf [cmdndx] = '\0';
-
-        cmdb_macro_reset();
-
-        cmdb_prompt();
-    }
-
-    cmdndx = 0;
-    cmdbuf [cmdndx] = '\0';
-
-    escndx = 0;
-    escbuf [escndx] = '\0';
-}
-
-void  Cmdb::cmdb_prompt(void) {
-    if (subsystem!=-1) {
-        cmdb_printf("%s>",_cmds[subsystem].cmdstr);
-    } else {
-        cmdb_print(prompt);
-    }
-}
-
-bool  Cmdb::cmdb_scan(const char c) {
-    int i;
-
-    //See http://www.interfacebus.com/ASCII_Table.html
-
-    if (c == '\r') {                                // cr?
-        cmdb_print(crlf);                           // Output it and ...
-        if (cmdndx) {
-            strncpy(lstbuf,cmdbuf,cmdndx);
-            lstbuf[cmdndx]='\0';
-            cmdb_cmd_proc(cmdbuf);
-        }
-        cmdb_init(false);
-        cmdb_prompt();
-
-        return true;
-    }
-
-    //TODO BACKSPACE NOT CORRECT FOR TELNET!
-
-    if (c == '\b') {                                // Backspace
-        if (cmdndx != 0) {
-            cmdb_print(bs);
-            cmdbuf [--cmdndx] = '\0';
-        } else {
-            cmdb_printch(bell);                     // Output Error
-        }
-        return false;
-    }
-
-    if (c == '\177') {                              // Delete
-        while (cmdndx>0) {
-            cmdb_print(bs);
-            cmdbuf [--cmdndx] = '\0';
-        }
-        return false;
-    }
-
-    //Reset Escape Buffer.
-    if (c == '\033') {
-        if (escndx!=0) {
-            //_putchar(bell);                       // Output Error
-            //printf("%s\r\n",escbuf);
-        }
-        escndx = 0;
-        escbuf [escndx] = '\0';                     // NULL-Terminate buffer
-    }
-
-    //Extract Escape Sequence.
-    if (c == '\033' || escndx ) {                   // Wait for escape
-        escbuf [escndx++] = (unsigned char) c;      // Add to the buffer
-        escbuf [escndx]   = '\0';                   // NULL-Terminate buffer
-        if (isalpha(c)) {
-            switch (cmdb_escid_search(escbuf)) {
-                case EID_CURSOR_LEFT    : {
-                    if (cmdndx != 0) {   // Backspace?
-                        cmdb_print(bs);
-                        cmdbuf [--cmdndx] = '\0';
-                    } else {
-                        cmdb_printch(bell);             // Output char
-                    }
-                    break;
-                }
-                case EID_CURSOR_UP    : {
-                    for (i=0;i<cmdndx;i++) {
-                        cmdb_print(bs);
-                    }
-                    cmdndx=strlen(lstbuf);
-                    strncpy(cmdbuf,lstbuf,cmdndx);
-                    cmdbuf[cmdndx]='\0';
-                    cmdb_printf("%s",cmdbuf);
-                    break;
-                }
-                case EID_CURSOR_RIGHT:
-                    break;
-                case EID_CURSOR_DOWN    :
-                    break;
-                case EID_LAST            :
-                    break;
-                default                     :
-                    cmdb_printch(bell);
-                    break;
-            }
-            escndx=0;
-            escbuf [escndx]   = '\0';               // NULL-Terminate buffer
-        }
-        return false;
-    }
-
-    if (c=='\n') {                                  // LF
-        return false;                               // Dump it
-    }
-
-    if (!isprint (c)) {                             // Printable character?
-        cmdb_printch(bell);
-        return false;
-    }
-
-    if (cmdndx >= MAX_CMD_LEN) {                    // Past buffer length?
-        cmdb_printch(bell);
-        return false;
-    }
-
-    cmdbuf [cmdndx++] = (unsigned char) c;          // Add to the buffer
-    cmdbuf [cmdndx]   = '\0';                       // NULL-Terminate buffer
-
-    if (echo) {
-        cmdb_printch(c);                            // Output char
-    }
-
-    return false;
-}
-
-//Private Utilities #3
-
-int   Cmdb::cmdb_printf(const char *format, ...) {
-    int cnt;
-
-    va_list args;
-    char buf[1024];
-
-    memset(buf,'\0',sizeof(buf));
-
-    va_start(args, format);
-    cnt = vsnprintf(buf, sizeof(buf), format, args);
-    if (cnt==-1) {
-        //Error
-    }
-    va_end(args);
-
-    return cmdb_print(buf);
-}
-
-//Link to outside world.
-int   Cmdb::cmdb_print(const char *msg) {
-    return _serial.printf(msg);
-}
-
-//Link to outside world.
-char  Cmdb::cmdb_printch(const char ch) {
-    return _serial.putc(ch);
-}
-
-void  Cmdb::cmdb_cmdhelp(char *pre, int ndx, char *post) {
-    int  j;
-    int  k;
-    int  lastmod;
-
-    k=0;
-    lastmod=0;
-
-    switch (_cmds[ndx].subs) {
-        case SUBSYSTEM :
-            break;
-        case GLOBALCMD :
-            break;
-        case HIDDENSUB :
-            return;
-        default        :
-            if (strlen(pre)==0 && bold) {
-                cmdb_print(boldon);
-            }
-            break;
-    }
-
-    cmdb_print(pre);
-    k+=strlen(pre);
-
-    if (k==0) {
-        cmdb_printf("%12s",_cmds[ndx].cmdstr);
-        k+=12;
-    } else {
-        if (strlen(pre)>0 && bold) {
-            cmdb_print(boldon);
-        }
-
-        cmdb_printf("%s",_cmds[ndx].cmdstr);
-        k+=strlen(_cmds[ndx].cmdstr);
-
-        if (strlen(pre)>0 && bold) {
-            cmdb_print(boldoff);
-        }
-    }
-
-    if (strlen(_cmds[ndx].parms)) {
-        cmdb_printch(sp);
-        k++;
-    }
-
-    for (j=0;j<strlen(_cmds[ndx].parms);j++) {
-        switch (_cmds[ndx].parms[j]) {
-            case '%' :
-                lastmod=0;
-                break;
-
-            case 'b' :
-                lastmod=8;
-                break;
-            case 'h' :
-                lastmod=16;
-                break;
-            case 'l' :
-                lastmod=32;
-                break;
-
-            case 'd' :
-            case 'i' :     {
-                switch (lastmod) {
-                    case  0 :
-                    case 16 :
-                        cmdb_print("int");
-                        k+=3;
-                        break;
-                    case  8 :
-                        cmdb_print("shortint");
-                        k+=8;
-                        break;
-                    case 32:
-                        cmdb_print("longint");
-                        k+=7;
-                        break;
-                }
-                break;
-            }
-
-            case 'u' :
-            case 'o' :
-            case 'x' :     {
-                switch (lastmod) {
-                    case  0 :
-                    case 16 :
-                        cmdb_print("word");
-                        k+=4;
-                        break;
-                    case  8 :
-                        cmdb_print("byte");
-                        k+=4;
-                        break;
-                    case 32 :
-                        cmdb_print("dword");
-                        k+=5;
-                        break;
-                }
-
-                switch (_cmds[ndx].parms[j]) {
-                    case 'o' :
-                        cmdb_print("[o]");
-                        k+=3;
-                        break;
-                    case 'x' :
-                        cmdb_print("[h]");
-                        k+=3;
-                        break;
-                }
-
-                break;
-            }
-
-            case 'e' :
-            case 'f' :
-            case 'g' :
-                cmdb_print("float");
-                k+=5;
-                break;
-
-            case 'c' :
-                cmdb_print("char");
-                k+=4;
-                break;
-
-            case 's' :
-                cmdb_print("string");
-                k+=6;
-                break;
-
-            case ' ' :
-                cmdb_printch(sp);
-                k++;
-                break;
-        }
-    }
-
-    for (j=k;j<40;j++) cmdb_printch(sp);
-
-    switch (_cmds[ndx].subs) {
-        case SUBSYSTEM :
-            if (ndx==subsystem) {
-                cmdb_printf("- %s (active subsystem)%s",_cmds[ndx].cmddescr,post);
-            } else {
-                cmdb_printf("- %s (dormant subsystem)%s",_cmds[ndx].cmddescr,post);
-            }
-            break;
-        case HIDDENSUB :
-            break;
-        case GLOBALCMD :
-            cmdb_printf("- %s (global command)%s",_cmds[ndx].cmddescr,post);
-            break;
-        default        :
-            cmdb_printf("- %s%s",_cmds[ndx].cmddescr,post);
-            if (strlen(pre)==0 && bold) {
-                cmdb_print(boldoff);
-            }
-            break;
-    }
-
-    if (strlen(pre)>0 && strlen(_cmds[ndx].parmdescr)) {
-        cmdb_printf("Params: %s",_cmds[ndx].parmdescr);
-        cmdb_print("\r\n");
-    }
-}
-
-//------------------------------------------------------------------------------
-//----Wrappers
-//------------------------------------------------------------------------------
-
-void  Cmdb::zeromemory(char *p,unsigned int siz) {
-    memset(p,'\0',siz);
-}
-
-int  Cmdb::stricmp (char *s1, char *s2) {
-    int  i;
-    int  len1,len2;
-
-    len1=strlen(s1);
-    len2=strlen(s2);
-
-    for (i = 0; (i<len1) && (i<len2);i++) {
-        if ( toupper (s1[i])<toupper(s2[i]) ) return (-1);
-        if ( toupper (s1[i])>toupper(s2[i]) ) return (+1);
-    }
-
-    if (len1<len2) return (-1);
-    if (len1>len2) return (+1);
-
-    return (0);
-}
+#include <vector>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "cmdb.h"
+#include "mbed.h"
+
+//DONE Pass Serial into constructor for printf, putc and getc.
+//DONE CID_<subsystem> must be handled internally.
+//
+//TODO ADD Documentation.
+//TODO CID_HELP must be handled internally (like all system commands (IDLE/MACRO etc).
+//TODO CID_HELP should be function (so we can call it easier in the switche's else branch).
+//TODO Link CID_LAST to Vector Size.
+
+//Constructor (see http://www.daniweb.com/forums/thread293338.html)
+Cmdb::Cmdb(const Serial serial, const std::vector<cmdb_cmd>& cmds) :  _serial(serial), _cmds(cmds) {
+    echo = true;
+    bold = true;
+    subsystem = -1;
+
+    CID_LAST = _cmds.back().id;
+    CMD_TBL_LEN = cmds.size();
+
+    cmdb_init(true);
+}
+
+//Public
+bool  Cmdb::cmdb_macro_hasnext() {
+    return macro_ptr!=-1 && macro_ptr<MAX_CMD_LEN && macro_buf[macro_ptr];
+}
+
+char Cmdb::cmdb_macro_next() {
+    char ch = macro_buf[macro_ptr++];
+    if (macro_ptr==MAX_CMD_LEN) {
+        cmdb_macro_reset();
+    }
+    return ch;
+}
+
+char  Cmdb::cmdb_macro_peek() {
+    return macro_buf[macro_ptr];
+}
+
+void  Cmdb::cmdb_macro_reset() {
+    macro_ptr         = -1;
+    macro_buf[0]     = '\0';
+}
+
+bool  Cmdb::cmdb_hasnext() {
+    return _serial.readable()==1;
+}
+
+char  Cmdb::cmdb_next() {
+    return _serial.getc();
+}
+
+//Private Utilities #1
+
+int  Cmdb::cmdb_escid_search(char *escstr) {
+    for (int i=0; i<ESC_TBL_LEN; i++) {
+        if (strcmp (esc_tbl[i].escstr, escstr) == 0)
+            return (esc_tbl[i].id);
+    }
+
+    return (EID_LAST);
+}
+
+int  Cmdb::cmdb_cmdid_search(char *cmdstr) {
+    //Warning, we return the ID but somewhere assume it's equal to the array index!
+    for (int i=0; i<CMD_TBL_LEN; i++) {
+        if ((stricmp (_cmds[i].cmdstr, cmdstr) == 0) && ((_cmds[i].subs == subsystem) || (_cmds[i].subs<0)))
+            return (_cmds[i].id);
+    }
+
+    return (CID_LAST);
+}
+
+int  Cmdb::cmdb_cmdid_index(int cmdid) {
+    for (int i=0; i<CMD_TBL_LEN; i++) {
+        if (_cmds[i].id==cmdid)
+            return i;
+    }
+
+    return -1;
+}
+
+int Cmdb::cmdb_parse(char *cmd) {
+    //Command
+    char cmdstr_buf [1 + MAX_CMD_LEN];
+
+    //Parameters
+    char argstr_buf [1 + MAX_CMD_LEN];
+    char *argsep;
+
+    char prmstr_buf [1 + MAX_CMD_LEN];                          //copy of sscanf pattern
+    char *tok;                                                  //current token
+    void *toks[MAX_ARGS];                                       //pointers to string tokens IN commandline (argstr_buf)
+    char *prms[MAX_ARGS];                                       //patterns IN copy of sscanf string (*parms)
+
+    char typ = '\0';                                            //Var type
+    char mod = '\0';                                            //Var modifier      (for cardinal types)
+    unsigned int base;                                          //Var number base (8,10,16)
+    //unsigned int bytes;                                       //Var size in bytes (used for malloc)
+
+    float f;                                                    //Temp var for conversion, 4 bytes
+    //unsigned char b;                                          //Temp var for conversion, 1 byte
+    //char c;                                                    //Temp var for conversion, 1 byte
+    //short h;                                                  //Temp var for conversion, 2 bytes
+    //int k;                                                    //Temp var for conversion, 2 bytes
+    long l;                                                     //Temp var for conversion, 4 bytes
+
+    char* endptr;                                               //strtoXX() Error detection
+
+    signed char id;
+    unsigned int  i;
+
+    //Init (global) variables.
+    argfnd=0;
+    argcnt=0;
+    error =0;
+
+    //Signals empty string...
+    id=-1;
+
+    //Zero the two string buffers for splitting cmd string into.
+    zeromemory((char*)cmdstr_buf,sizeof(cmdstr_buf));
+    zeromemory(argstr_buf,sizeof(argstr_buf));
+
+    //Make it worse in Lint
+    for (i=0;i<MAX_ARGS;i++) {
+        parms[i].type=PARM_UNUSED;
+        zeromemory((char*)&(parms[i].val),sizeof(parms[i].val));
+    }
+
+    /*------------------------------------------------
+    First, copy the command and convert it to all
+    uppercase.
+    ------------------------------------------------*/
+
+    strncpy(cmdstr_buf, cmd, sizeof (cmdstr_buf) - 1);
+    cmdstr_buf [sizeof (cmdstr_buf) - 1] = '\0';
+
+    /*------------------------------------------------
+    Next, find the end of the first thing in the
+    buffer.  Since the command ends with a space,
+    we'll look for that.  NULL-Terminate the command
+    and keep a pointer to the arguments.
+    ------------------------------------------------*/
+
+    argsep = strchr(cmdstr_buf, ' ');
+
+    if (argsep == NULL) {
+        argstr_buf [0] = '\0';
+    } else {
+        strcpy (argstr_buf, argsep + 1);
+        *argsep = '\0';
+    }
+
+    /*------------------------------------------------
+    Search for a command ID, then switch on it.  Note
+    that I removed my action items for each command,
+    but you would invoke each function here.
+    VEG:Watch out ID  not neccesarily equal to Array Index!
+    ------------------------------------------------*/
+
+    //1) Find the Command Id
+    id = cmdb_cmdid_search(cmdstr_buf);
+
+    if (id!=CID_LAST) {
+        //2) Tokenize a copy of the parms from the cmd_tbl.
+
+        //Get Format patterns from cmd_tbl[id].parms.
+        //Note: strtok inserts \0 into the original string. Hence the copy.
+        zeromemory((char *)(&prmstr_buf),sizeof(prmstr_buf));
+
+        strncpy (prmstr_buf, _cmds[id].parms, sizeof (prmstr_buf) - 1);
+
+        argcnt=0;
+        tok = strtok(prmstr_buf, " ");
+        while (tok != NULL) {
+            //Store Pointers
+            prms[argcnt++] = tok;
+
+            //cmdb_printf("prm_%2.2d='%s'\r\n",argcnt, tok);
+
+            tok = strtok(NULL, " ");
+        }
+
+        //3) Tokenize the commandline.
+
+        //Get Tokens from arguments.
+        //Note: strtok inserts \0 into the original string. Won't harm here as we do not re-use it.
+
+        argfnd=0;
+
+        if (strlen(argstr_buf)!=0) {
+            tok = strtok(argstr_buf, " ");
+        } else {
+            tok=NULL;
+        }
+
+        while (tok != NULL) {
+            //Store Pointers
+            toks[argfnd++]=tok;
+
+            //cmdb_printf("tok_%2.2d='%s'\r\n",argfnd, tok);
+
+            tok = strtok(NULL, " ");
+        }
+
+        if (argfnd==argcnt || (id==CID_HELP && argfnd==0)) {
+
+            error = 0;
+
+            for (i=0;i<argcnt;i++) {
+                //cmdb_printf("prm_%2.2d=%s\r\n",i, prms[i]);
+
+                switch (strlen(prms[i])) {
+                    case 0:
+                        break;
+                    case 1:
+                        break;
+                    case 2: //Simple pattern, no modifier
+                        mod='\0';
+                        typ=prms[i][1];
+
+                        break;
+                    case 3: //pattern with Modifier.
+                        mod=prms[i][1];
+                        typ=prms[i][2];
+
+                        break;
+                    default:
+                        break;
+                }
+
+                switch (typ) {
+                    case 'o' :
+                        base=8;
+                        break;
+                    case 'x' :
+                        base=16;
+                        break;
+                    default:
+                        base=10;
+                        break;
+                }
+
+                endptr = (char*)toks[i];
+
+                //Cardinal Types
+                switch (typ) {
+                    case 'd' :  //Check mod
+                    case 'i' :  //Check mod
+                    case 'u' :  //Check mod
+                    case 'o' :  //Check mod
+                    case 'x' :  //Check mod
+                        switch (mod) {
+                            case 'b' : //char
+                                //test range
+                                l=strtol((char*)toks[i], &endptr, base);
+                                if (l>=MIN_BYTE && l<=MAX_BYTE) {
+                                    parms[i].type=PARM_CHAR;
+                                    parms[i].val.uc =(unsigned char)l;
+                                } else {
+                                    error = i+1;
+                                }
+
+                                break;
+                            case 'h' : //short
+                                l=strtol((char*)toks[i], &endptr, base);
+                                if (l>=MIN_SHORT && l<=MAX_SHORT) {
+                                    parms[i].type=PARM_SHORT;
+                                    parms[i].val.w=(short)l;
+                                } else {
+                                    error = i+1;
+                                }
+
+                                break;
+                            case 'l' : //long
+                                l=strtol((char*)toks[i], &endptr, base);
+                                parms[i].type=PARM_LONG;
+                                parms[i].val.l=l;
+
+                                break;
+                            default:
+                                l=strtol((char*)toks[i], &endptr, base);
+                                if (l>=MIN_INT && l<=MAX_INT) {
+                                    parms[i].type=PARM_INT;
+                                    parms[i].val.l=(int)l;
+                                } else {
+                                    error = i+1;
+                                }
+                                break;
+                        }
+
+                        if (error==0 &&
+                                (endptr==toks[i]    //No Conversion at all.
+                                 || *endptr)) {       //Incomplete conversion.
+                            error = i+1;
+                        }
+
+                        break;
+                }
+
+                //Floating Point Types
+                switch (typ) {
+                    case 'e' :
+                    case 'f' :
+                    case 'g' :
+                        f = strtod((char*)toks[i], &endptr);
+
+                        parms[i].type=PARM_FLOAT;
+                        parms[i].val.f=f;
+
+                        if (error==0 &&
+                                (endptr==toks[i]    //No Conversion at all.
+                                 || *endptr)) {       //Incomplete conversion.
+                            error = i;
+                        }
+
+                        break;
+                }
+
+                //String types
+                switch (typ) {
+                    case 'c' :
+                        parms[i].type=PARM_CHAR;
+                        parms[i].val.c=((char*)toks[i])[0];
+
+                        if (error==0 && strlen((char*)toks[i])!=1) {  //Incomplete conversion.
+                            error = i;
+                        }
+
+                        break;
+
+                    case 's' :
+                        parms[i].type=PARM_STRING;
+                        strncpy(parms[i].val.s,(char*)toks[i], strlen((char*)toks[i]));
+
+                        break;
+                }
+            }
+        } else {
+            //id=CID_LAST;
+        }
+    }
+
+    return id;
+}
+
+void  Cmdb::cmdb_cmd_proc(char *cmd) {
+    int  cid;
+    int  ndx;
+
+    cid = cmdb_parse(cmd);
+    ndx = cmdb_cmdid_index(cid);
+
+    if (cid!=-1) {
+
+        /*------------------------------------------------
+        Process the command and it's arguments that are
+        found. id contains the command id and argcnt &
+        argfnd the number of found and expected paramaters
+        parms contains the parsed argument values and their
+        types.
+        ------------------------------------------------*/
+
+        if (cid==CID_LAST) {
+            cmdb_print("Unknown command, type 'Help' for a list of available commands.\r\n");
+        } else {
+
+            //Test for more commandline than allowed too.
+            //i.e. run 1 is wrong.
+
+            //TODO Fix Index/Id problem.
+
+            if (argcnt==0 && argfnd==0 && error==0 && ndx!=-1 && _cmds[ndx].subs==SUBSYSTEM) {
+                subsystem=cid;
+            } else if ( ((cid==CID_HELP) || (argcnt==argfnd)) && error==0 ) {
+                switch (cid) {
+
+                        /////// GLOBAL MACRO COMMANDS ///////
+
+                        //Define Macro from commandline
+                    case CID_MACRO:
+                        macro_ptr=-1;
+                        strncpy(macro_buf, STRINGPARM(0), sizeof(macro_buf) - 1);
+                        break;
+
+                        //Run Macro
+                    case CID_RUN:
+                        macro_ptr=0;
+                        break;
+
+                        //List Macro's
+                    case CID_MACROS:
+                        cmdb_print("[Macro]\r\n");
+                        if (macro_buf[0]) {
+                            cmdb_printf("Value=%s\r\n",macro_buf);
+                        } else {
+                            cmdb_printf(";No Macro Defined\r\n");
+                        }
+                        break;
+
+                        /////// GLOBAL STATEMACHINE COMMANDS ///////
+
+#ifdef STATEMACHINE
+
+                        //Start State Machine
+                    case CID_STATE:
+                        statemachine(BYTEPARM(0));
+
+                        break;
+#endif
+
+                        /////// GLOBAL COMMANDS ///////
+
+                        //Echo
+                    case CID_ECHO:
+                        echo = BOOLPARM(0);
+                        break;
+
+                        //Bold
+                    case CID_BOLD:
+                        bold = BOOLPARM(0);
+                        break;
+
+                        //Warm Boot
+                    case CID_BOOT:
+                        //reset();
+                        break;
+
+                        //Sends an ANSI escape code to clear the screen.
+                    case CID_CLS:
+                        cmdb_print(cls);
+                        break;
+
+                        //Returns to CMD> prompt where most commands are disabled.
+                    case CID_IDLE:
+                        subsystem=-1;
+                        break;
+
+                        //Help
+                    case CID_HELP: {
+
+//TODO Handle Subsystem
+
+//TODO Call command processor callback and if it returns false we supply help.
+
+                        cmdb_print("\r\n");
+
+                        if (argfnd>0) {
+                            cid = cmdb_cmdid_search(STRINGPARM(0));
+                        } else {
+                            cid=CID_LAST;
+                        }
+
+                        if (argfnd>0 && cid!=CID_LAST) {
+
+                            //Help with a valid command as first parameter
+                            ndx = cmdb_cmdid_index(cid);
+
+                            switch (_cmds[ndx].subs) {
+                                case SUBSYSTEM: //Dump whole subsystem
+                                    cmdb_printf("%s subsystem commands:\r\n\r\n",_cmds[ndx].cmdstr);
+
+                                    for (int i=0;i<CMD_TBL_LEN-1;i++) {
+                                        if (_cmds[i].subs==ndx) {
+                                            cmdb_cmdhelp("",i,",\r\n");
+                                        }
+                                    }
+
+                                    break;
+
+                                case GLOBALCMD: //Dump command only
+                                    //cmdb_print("Global command:\r\n\r\n",cmd_tbl[cmd_tbl[ndx].subs].cmdstr);
+                                    cmdb_cmdhelp("Syntax: ",ndx,".\r\n");
+                                    break;
+
+                                default:        //Dump one subsystem command
+                                    cmdb_printf("%s subsystem command:\r\n\r\n",_cmds[_cmds[ndx].subs].cmdstr);
+                                    cmdb_cmdhelp("Syntax: ",ndx,".\r\n");
+                                    break;
+                            }
+                        } else {
+                            if (argfnd>0) {
+                                //Help with invalid command as first parameter
+                                cmdb_print("Unknown command, type 'Help' for a list of available commands.\r\n");
+                            } else {
+                                //Help
+
+                                //Dump Active Subsystem, Global & Other (dormant) Subsystems
+                                for (int i=0;i<CMD_TBL_LEN-1;i++) {
+                                    if ((_cmds[i].subs<0) || (_cmds[i].subs==subsystem)) {
+                                        cmdb_cmdhelp("",i,",\r\n");
+                                    }
+                                }
+                                cmdb_cmdhelp("",CMD_TBL_LEN-1,".\r\n");
+                            }
+                        }
+                        cmdb_print("\r\n");
+                        break;
+                    } //CID_HELP
+                }
+            } else {
+                cmdb_cmdhelp("Syntax: ",ndx,".\r\n");
+            }
+        }
+    }
+}
+
+//Private Utilities #2
+
+void  Cmdb::cmdb_init(const char full) {
+    if (full) {
+        echo = true;
+        bold = true;
+
+        subsystem = -1;
+
+        lstbuf [cmdndx] = '\0';
+
+        cmdb_macro_reset();
+
+        cmdb_prompt();
+    }
+
+    cmdndx = 0;
+    cmdbuf [cmdndx] = '\0';
+
+    escndx = 0;
+    escbuf [escndx] = '\0';
+}
+
+void  Cmdb::cmdb_prompt(void) {
+    if (subsystem!=-1) {
+        cmdb_printf("%s>",_cmds[subsystem].cmdstr);
+    } else {
+        cmdb_print(prompt);
+    }
+}
+
+bool  Cmdb::cmdb_scan(const char c) {
+    int i;
+
+    //See http://www.interfacebus.com/ASCII_Table.html
+
+    if (c == '\r') {                                // cr?
+        cmdb_print(crlf);                           // Output it and ...
+        if (cmdndx) {
+            strncpy(lstbuf,cmdbuf,cmdndx);
+            lstbuf[cmdndx]='\0';
+            cmdb_cmd_proc(cmdbuf);
+        }
+        cmdb_init(false);
+        cmdb_prompt();
+
+        return true;
+    }
+
+    //TODO BACKSPACE NOT CORRECT FOR TELNET!
+
+    if (c == '\b') {                                // Backspace
+        if (cmdndx != 0) {
+            cmdb_print(bs);
+            cmdbuf [--cmdndx] = '\0';
+        } else {
+            cmdb_printch(bell);                     // Output Error
+        }
+        return false;
+    }
+
+    if (c == '\177') {                              // Delete
+        while (cmdndx>0) {
+            cmdb_print(bs);
+            cmdbuf [--cmdndx] = '\0';
+        }
+        return false;
+    }
+
+    //Reset Escape Buffer.
+    if (c == '\033') {
+        if (escndx!=0) {
+            //_putchar(bell);                       // Output Error
+            //printf("%s\r\n",escbuf);
+        }
+        escndx = 0;
+        escbuf [escndx] = '\0';                     // NULL-Terminate buffer
+    }
+
+    //Extract Escape Sequence.
+    if (c == '\033' || escndx ) {                   // Wait for escape
+        escbuf [escndx++] = (unsigned char) c;      // Add to the buffer
+        escbuf [escndx]   = '\0';                   // NULL-Terminate buffer
+        if (isalpha(c)) {
+            switch (cmdb_escid_search(escbuf)) {
+                case EID_CURSOR_LEFT    : {
+                    if (cmdndx != 0) {   // Backspace?
+                        cmdb_print(bs);
+                        cmdbuf [--cmdndx] = '\0';
+                    } else {
+                        cmdb_printch(bell);             // Output char
+                    }
+                    break;
+                }
+                case EID_CURSOR_UP    : {
+                    for (i=0;i<cmdndx;i++) {
+                        cmdb_print(bs);
+                    }
+                    cmdndx=strlen(lstbuf);
+                    strncpy(cmdbuf,lstbuf,cmdndx);
+                    cmdbuf[cmdndx]='\0';
+                    cmdb_printf("%s",cmdbuf);
+                    break;
+                }
+                case EID_CURSOR_RIGHT:
+                    break;
+                case EID_CURSOR_DOWN    :
+                    break;
+                case EID_LAST            :
+                    break;
+                default                     :
+                    cmdb_printch(bell);
+                    break;
+            }
+            escndx=0;
+            escbuf [escndx]   = '\0';               // NULL-Terminate buffer
+        }
+        return false;
+    }
+
+    if (c=='\n') {                                  // LF
+        return false;                               // Dump it
+    }
+
+    if (!isprint (c)) {                             // Printable character?
+        cmdb_printch(bell);
+        return false;
+    }
+
+    if (cmdndx >= MAX_CMD_LEN) {                    // Past buffer length?
+        cmdb_printch(bell);
+        return false;
+    }
+
+    cmdbuf [cmdndx++] = (unsigned char) c;          // Add to the buffer
+    cmdbuf [cmdndx]   = '\0';                       // NULL-Terminate buffer
+
+    if (echo) {
+        cmdb_printch(c);                            // Output char
+    }
+
+    return false;
+}
+
+//Private Utilities #3
+
+int   Cmdb::cmdb_printf(const char *format, ...) {
+    int cnt;
+
+    va_list args;
+    char buf[1024];
+
+    memset(buf,'\0',sizeof(buf));
+
+    va_start(args, format);
+    cnt = vsnprintf(buf, sizeof(buf), format, args);
+    if (cnt==-1) {
+        //Error
+    }
+    va_end(args);
+
+    return cmdb_print(buf);
+}
+
+//Link to outside world.
+int   Cmdb::cmdb_print(const char *msg) {
+    return _serial.printf(msg);
+}
+
+//Link to outside world.
+char  Cmdb::cmdb_printch(const char ch) {
+    return _serial.putc(ch);
+}
+
+void  Cmdb::cmdb_cmdhelp(char *pre, int ndx, char *post) {
+    int  j;
+    int  k;
+    int  lastmod;
+
+    k=0;
+    lastmod=0;
+
+    switch (_cmds[ndx].subs) {
+        case SUBSYSTEM :
+            break;
+        case GLOBALCMD :
+            break;
+        case HIDDENSUB :
+            return;
+        default        :
+            if (strlen(pre)==0 && bold) {
+                cmdb_print(boldon);
+            }
+            break;
+    }
+
+    cmdb_print(pre);
+    k+=strlen(pre);
+
+    if (k==0) {
+        cmdb_printf("%12s",_cmds[ndx].cmdstr);
+        k+=12;
+    } else {
+        if (strlen(pre)>0 && bold) {
+            cmdb_print(boldon);
+        }
+
+        cmdb_printf("%s",_cmds[ndx].cmdstr);
+        k+=strlen(_cmds[ndx].cmdstr);
+
+        if (strlen(pre)>0 && bold) {
+            cmdb_print(boldoff);
+        }
+    }
+
+    if (strlen(_cmds[ndx].parms)) {
+        cmdb_printch(sp);
+        k++;
+    }
+
+    for (j=0;j<strlen(_cmds[ndx].parms);j++) {
+        switch (_cmds[ndx].parms[j]) {
+            case '%' :
+                lastmod=0;
+                break;
+
+            case 'b' :
+                lastmod=8;
+                break;
+            case 'h' :
+                lastmod=16;
+                break;
+            case 'l' :
+                lastmod=32;
+                break;
+
+            case 'd' :
+            case 'i' :     {
+                switch (lastmod) {
+                    case  0 :
+                    case 16 :
+                        cmdb_print("int");
+                        k+=3;
+                        break;
+                    case  8 :
+                        cmdb_print("shortint");
+                        k+=8;
+                        break;
+                    case 32:
+                        cmdb_print("longint");
+                        k+=7;
+                        break;
+                }
+                break;
+            }
+
+            case 'u' :
+            case 'o' :
+            case 'x' :     {
+                switch (lastmod) {
+                    case  0 :
+                    case 16 :
+                        cmdb_print("word");
+                        k+=4;
+                        break;
+                    case  8 :
+                        cmdb_print("byte");
+                        k+=4;
+                        break;
+                    case 32 :
+                        cmdb_print("dword");
+                        k+=5;
+                        break;
+                }
+
+                switch (_cmds[ndx].parms[j]) {
+                    case 'o' :
+                        cmdb_print("[o]");
+                        k+=3;
+                        break;
+                    case 'x' :
+                        cmdb_print("[h]");
+                        k+=3;
+                        break;
+                }
+
+                break;
+            }
+
+            case 'e' :
+            case 'f' :
+            case 'g' :
+                cmdb_print("float");
+                k+=5;
+                break;
+
+            case 'c' :
+                cmdb_print("char");
+                k+=4;
+                break;
+
+            case 's' :
+                cmdb_print("string");
+                k+=6;
+                break;
+
+            case ' ' :
+                cmdb_printch(sp);
+                k++;
+                break;
+        }
+    }
+
+    for (j=k;j<40;j++) cmdb_printch(sp);
+
+    switch (_cmds[ndx].subs) {
+        case SUBSYSTEM :
+            if (ndx==subsystem) {
+                cmdb_printf("- %s (active subsystem)%s",_cmds[ndx].cmddescr,post);
+            } else {
+                cmdb_printf("- %s (dormant subsystem)%s",_cmds[ndx].cmddescr,post);
+            }
+            break;
+        case HIDDENSUB :
+            break;
+        case GLOBALCMD :
+            cmdb_printf("- %s (global command)%s",_cmds[ndx].cmddescr,post);
+            break;
+        default        :
+            cmdb_printf("- %s%s",_cmds[ndx].cmddescr,post);
+            if (strlen(pre)==0 && bold) {
+                cmdb_print(boldoff);
+            }
+            break;
+    }
+
+    if (strlen(pre)>0 && strlen(_cmds[ndx].parmdescr)) {
+        cmdb_printf("Params: %s",_cmds[ndx].parmdescr);
+        cmdb_print("\r\n");
+    }
+}
+
+//------------------------------------------------------------------------------
+//----Wrappers
+//------------------------------------------------------------------------------
+
+void  Cmdb::zeromemory(char *p,unsigned int siz) {
+    memset(p,'\0',siz);
+}
+
+int  Cmdb::stricmp (char *s1, char *s2) {
+    int  i;
+    int  len1,len2;
+
+    len1=strlen(s1);
+    len2=strlen(s2);
+
+    for (i = 0; (i<len1) && (i<len2);i++) {
+        if ( toupper (s1[i])<toupper(s2[i]) ) return (-1);
+        if ( toupper (s1[i])>toupper(s2[i]) ) return (+1);
+    }
+
+    if (len1<len2) return (-1);
+    if (len1>len2) return (+1);
+
+    return (0);
+}