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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cmdb.cpp Source File

cmdb.cpp

00001 /*
00002 _____________________________________________________________________________
00003 
00004    Project:     mBed Command Interpreter
00005    Filename:    cmdb.h
00006    Version:     0.80
00007 _____________________________________________________________________________
00008    Date         Comment
00009    -------- --------------------------------------------------------------
00010    10022011 -Rewritten into C++ class.
00011             -Pass Serial into constructor for printf, putc and getc.
00012             -CID_<subsystem> must be handled internally.
00013             -Fixed a number of old Index/Id conflicts.
00014             -Got a working version. Much work to be done though.
00015             -Handle CID_HELP internally (like all system commands (IDLE/MACRO etc).
00016             -Handle subsystems internally.
00017             -Removed CMD_TBL_LEN.
00018             -CID_LAST is now defined as CID_HELP+1.
00019    11022011 -Added Documentation.
00020             -Added code to take number limits from the C++ Runtime instead of hard defined values.
00021             -Renamed id to cid in cmd.
00022             -Added MAX_LONG and MIN_LONG (long==int on mbed).
00023             -Removed cmdb_ prefix from members.
00024             -Tested Macro Support and added it to the Demo.
00025             -Added CID_COMMANDS.
00026             -Fixed a small bug in parse.
00027             -v0.76
00028    24032011 -Fixed some left-over bugs caused by index/id mixup.
00029    09052011 -Added present(), replace() and indexof() methods.
00030              replace() can be used to replace the complete command vector
00031              by a changed done. Inserting directly into cmdb's copy fails
00032              somehow.
00033    19092011 -Added PrintSection(), PrintValue() and PrintValuef() for
00034              easier Windows Ini File style output. As I use it to transfer
00035              data back to the PC (Easy parsing AND you can add/remove
00036              debug information without breaking PC code).
00037    20092011 -Breaking change, Made all cmd object static const like:
00038 
00039              static const cmd HELP = {"Help",GLOBALCMD,CID_HELP,"%s","Help"};
00040 
00041              this saves just to much ram memory on the heap.
00042              Thanks to Igor Skochinsky.
00043 
00044             -Made some more const string static.
00045             -v0.80
00046 
00047    20092011 -Corrected Comment Alignment.
00048             -v0.81
00049    -------- --------------------------------------------------------------
00050    TODO's
00051    10022011 -Tweak and Review Documentation.
00052    11022011 -Check & Test **PARM masks.
00053             -Remove prefix from class members?
00054    -------- --------------------------------------------------------------
00055 _____________________________________________________________________________
00056 */
00057 
00058 #include <vector>
00059 #include <stdlib.h>
00060 //#include <stdio.h>
00061 #include <stdarg.h>
00062 #include <ctype.h>
00063 #include <string.h>
00064 
00065 #include "cmdb.h"
00066 #include "mbed.h"
00067 
00068 //------------------------------------------------------------------------------
00069 
00070 Cmdb::Cmdb(const RawSerial& _serial, std::vector<cmd>& _cmds, void (*_callback)(Cmdb&,int)) :
00071         serial(_serial), cmds(_cmds) {
00072     echo = true;
00073     bold = true;
00074 
00075     NoComment = NULL;
00076     DefComPos = 72;
00077 
00078     subsystem = -1;
00079 
00080     user_callback = _callback;
00081 
00082     init(true);
00083 }
00084 
00085 const char* Cmdb::NoComment;
00086 
00087 int Cmdb::DefComPos;
00088 
00089 //------------------------------------------------------------------------------
00090 // Public Stuff.
00091 //------------------------------------------------------------------------------
00092 
00093 bool  Cmdb::macro_hasnext() {
00094     return macro_ptr!=-1 && macro_ptr<MAX_CMD_LEN && macro_buf[macro_ptr];
00095 }
00096 
00097 char Cmdb::macro_next() {
00098     char ch = macro_buf[macro_ptr++];
00099 
00100     if (macro_ptr==MAX_CMD_LEN) {
00101         macro_reset();
00102     }
00103 
00104     //Translate Special Characters Back
00105     switch (ch) {
00106         case '|':
00107             return cr;
00108         case '_':
00109             return sp;
00110         default:
00111             return ch;
00112     }
00113 }
00114 
00115 char  Cmdb::macro_peek() {
00116     return macro_buf[macro_ptr];
00117 }
00118 
00119 void  Cmdb::macro_reset() {
00120     macro_ptr         = -1;
00121     macro_buf[0]     = '\0';
00122 }
00123 
00124 //------------------------------------------------------------------------------
00125 
00126 bool  Cmdb::hasnext() {
00127     return serial.readable()==1;
00128 }
00129 
00130 char  Cmdb::next() {
00131     return serial.getc();
00132 }
00133 
00134 //------------------------------------------------------------------------------
00135 
00136 bool  Cmdb::scan(const char c) {
00137     int i;
00138 
00139     //See http://www.interfacebus.com/ASCII_Table.html
00140 
00141     if (c == '\r') {                                // cr?
00142         print(crlf);                           // Output it and ...
00143         if (cmdndx) {
00144             strncpy(lstbuf,cmdbuf,cmdndx);
00145             lstbuf[cmdndx]='\0';
00146 
00147             cmd_dispatcher(cmdbuf);
00148         }
00149         init(false);
00150         prompt();
00151 
00152         return true;
00153     }
00154 
00155     //TODO BACKSPACE NOT CORRECT FOR TELNET!
00156 
00157     if (c == '\b') {                                // Backspace
00158         if (cmdndx != 0) {
00159             print(bs);
00160             cmdbuf [--cmdndx] = '\0';
00161         } else {
00162             printch(bell);                     // Output Error
00163         }
00164         return false;
00165     }
00166 
00167     if (c == '\177') {                              // Delete
00168         while (cmdndx>0) {
00169             print(bs);
00170             cmdbuf [--cmdndx] = '\0';
00171         }
00172         return false;
00173     }
00174 
00175     //Reset Escape Buffer.
00176     if (c == '\033') {
00177         if (escndx!=0) {
00178             //_putchar(bell);                       // Output Error
00179             //printf("%s\r\n",escbuf);
00180         }
00181         escndx = 0;
00182         escbuf [escndx] = '\0';                     // NULL-Terminate buffer
00183     }
00184 
00185     //Extract Escape Sequence.
00186     if (c == '\033' || escndx ) {                   // Wait for escape
00187         escbuf [escndx++] = (unsigned char) c;      // Add to the buffer
00188         escbuf [escndx]   = '\0';                   // NULL-Terminate buffer
00189         if (isalpha(c)) {
00190             switch (escid_search(escbuf)) {
00191                 case EID_CURSOR_LEFT    : {
00192                     if (cmdndx != 0) {   // Backspace?
00193                         print(bs);
00194                         cmdbuf [--cmdndx] = '\0';
00195                     } else {
00196                         printch(bell);             // Output char
00197                     }
00198                     break;
00199                 }
00200                 case EID_CURSOR_UP    : {
00201                     for (i=0; i<cmdndx; i++) {
00202                         print(bs);
00203                     }
00204                     cmdndx=strlen(lstbuf);
00205                     strncpy(cmdbuf,lstbuf,cmdndx);
00206                     cmdbuf[cmdndx]='\0';
00207                     printf("%s",cmdbuf);
00208                     break;
00209                 }
00210                 case EID_CURSOR_RIGHT:
00211                     break;
00212                 case EID_CURSOR_DOWN    :
00213                     break;
00214                 case EID_LAST            :
00215                     break;
00216                 default                     :
00217                     printch(bell);
00218                     break;
00219             }
00220             escndx=0;
00221             escbuf [escndx]   = '\0';               // NULL-Terminate buffer
00222         }
00223         return false;
00224     }
00225 
00226     if (c=='\n') {                                  // LF
00227         return false;                               // Dump it
00228     }
00229 
00230     if (!isprint (c)) {                             // Printable character?
00231         printch(bell);
00232         return false;
00233     }
00234 
00235     if (cmdndx >= MAX_CMD_LEN) {                    // Past buffer length?
00236         printch(bell);
00237         return false;
00238     }
00239 
00240     cmdbuf [cmdndx++] = (unsigned char) c;          // Add to the buffer
00241     cmdbuf [cmdndx]   = '\0';                       // NULL-Terminate buffer
00242 
00243     if (echo) {
00244         printch(c);                            // Output char
00245     }
00246 
00247     return false;
00248 }
00249 
00250 //------------------------------------------------------------------------------
00251 
00252 int   Cmdb::printf(const char *format, ...) {
00253     int cnt;
00254 
00255     va_list args;
00256     char buf[1024];
00257 
00258     memset(buf,'\0',sizeof(buf));
00259 
00260     va_start(args, format);
00261     cnt = vsnprintf(buf, sizeof(buf), format, args);
00262     if (cnt==-1) {
00263         //Error
00264     }
00265     va_end(args);
00266 
00267     return print(buf);
00268 }
00269 
00270 int   Cmdb::print(const char *msg) {
00271     return serial.printf(msg);
00272 }
00273 
00274 int   Cmdb::println(const char *msg) {
00275     return serial.printf("%s\r\n", msg);
00276 }
00277 
00278 int   Cmdb::printsection(const char *section) {
00279     return printf("[%s]\r\n", section);
00280 }
00281 
00282 int   Cmdb::printmsg(const char *msg) {
00283     return printf("Msg=%s\r\n", msg);
00284 }
00285 
00286 int   Cmdb::printerror(const char *errormsg) {
00287     int a = printsection("Error");
00288     return a==0?a:a+printmsg(errormsg);
00289 }
00290 
00291 int   Cmdb::printerrorf(const char *format, ...) {
00292     char buf[256];
00293 
00294     int a = printsection("Error");
00295     
00296     va_list args;
00297     va_start(args, format);
00298 
00299     vsnprintf(buf, sizeof(buf), format, args);
00300 
00301     va_end(args);
00302 
00303     return a +  printf("Msg=%s\r\n", buf);
00304 }
00305 
00306 int   Cmdb::printvaluef(const char *key, const char *format, ...) {
00307     char buf[256];
00308 
00309     va_list args;
00310     va_start(args, format);
00311 
00312     vsnprintf(buf, sizeof(buf), format, args);
00313 
00314     va_end(args);
00315 
00316     return printf("%s=%s\r\n",key, buf);
00317 }
00318 
00319 int   Cmdb::printvaluef(const char *key, const int width, const char *comment, const char *format, ...) {
00320     char buf[256];
00321     
00322     int  cnt = printf("%s=",key);
00323 
00324     va_list args;
00325     va_start(args, format);
00326 
00327     vsnprintf(buf, sizeof(buf), format, args);
00328    
00329     va_end(args);
00330 
00331     if (comment!=NULL) {
00332         cnt += printf("%s", buf);
00333 
00334         if (cnt<width) {
00335             cnt += printf("%-*s ; %s\r\n", width - cnt - 1, "", comment);
00336         } else {
00337             cnt += printf("%s ; %s\r\n", "", comment);
00338         }
00339     } else {
00340         cnt += printf("%s\r\n",buf);
00341     }
00342 
00343     return cnt;
00344 }
00345 
00346 int   Cmdb::printvalue(const char *key, const char *value, const char *comment, const int width) {
00347     if (comment) {
00348         char buf[256];
00349         int  cnt = 0;
00350 
00351         memset(buf,'\0',sizeof(buf));
00352 
00353         cnt = snprintf(buf, sizeof(buf), "%s=%s", key, value);
00354 
00355         if (cnt<=width) {
00356             return printf("%-*s ; %s\r\n", width - cnt + 1, buf, comment);
00357         } else {
00358             return printf("%s ; %s\r\n", buf, comment);
00359         }
00360     } else {
00361         return printf("%s=%s\r\n", key, value);
00362     }
00363 }
00364 
00365 int   Cmdb::printcomment(const char *comment, const int width) {
00366     return printf("%-*s; %s\r\n", width, "", comment); 
00367 }
00368 
00369 char  Cmdb::printch(const char ch) {
00370     return serial.putc(ch);
00371 }
00372 
00373 //Mode=1               ; Profile Position Mode
00374 //1234567890123456789012
00375 
00376 //------------------------------------------------------------------------------
00377 
00378 void  Cmdb::init(const char full) {
00379     if (full) {
00380         echo = true;
00381         bold = true;
00382 
00383         subsystem = -1;
00384 
00385         lstbuf [cmdndx] = '\0';
00386 
00387         macro_reset();
00388 
00389         prompt();
00390     }
00391 
00392     cmdndx = 0;
00393     cmdbuf [cmdndx] = '\0';
00394 
00395     escndx = 0;
00396     escbuf [escndx] = '\0';
00397 }
00398 
00399 //------------------------------------------------------------------------------
00400 //Private Stuff.
00401 //------------------------------------------------------------------------------
00402 
00403 int  Cmdb::escid_search(char *escstr) {
00404     for (int i=0; i<ESC_TBL_LEN; i++) {
00405         if (strcmp (esc_tbl[i].escstr, escstr) == 0)
00406             return (esc_tbl[i].id);
00407     }
00408 
00409     return (EID_LAST);
00410 }
00411 
00412 int  Cmdb::cmdid_search(char *cmdstr) {
00413     //Warning, we return the ID but somewhere assume it's equal to the array index!
00414     for (int i=0; i<cmds.size(); i++) {
00415         if ((stricmp((char*)cmds[i].cmdstr, cmdstr) == 0) && ((cmds[i].subs == subsystem) || (cmds[i].subs<0)))
00416             return (cmds[i].cid);
00417     }
00418 
00419     return CID_LAST;
00420 }
00421 
00422 int  Cmdb::cmdid_index(int cmdid) {
00423     for (int i=0; i<cmds.size(); i++) {
00424         if (cmds[i].cid==cmdid)
00425             return i;
00426     }
00427 
00428     return -1;
00429 }
00430 
00431 //------------------------------------------------------------------------------
00432 
00433 int Cmdb::parse(char *cmd) {
00434     //Command
00435     char cmdstr_buf [1 + MAX_CMD_LEN];
00436 
00437     //Parameters
00438     char argstr_buf [1 + MAX_CMD_LEN];
00439     char *argsep;
00440 
00441     char prmstr_buf [1 + MAX_CMD_LEN];                          //copy of sscanf pattern
00442     char *tok;                                                  //current token
00443     void *toks[MAX_ARGS];                                       //pointers to string tokens IN commandline (argstr_buf)
00444     char *prms[MAX_ARGS];                                       //patterns IN copy of sscanf string (*parms)
00445 
00446     char typ = '\0';                                            //Var type
00447     char mod = '\0';                                            //Var modifier      (for cardinal types)
00448     unsigned int base;                                          //Var number base (8,10,16)
00449     //unsigned int bytes;                                       //Var size in bytes (used for malloc)
00450 
00451     float f;                                                    //Temp var for conversion, 4 bytes
00452     //unsigned char b;                                          //Temp var for conversion, 1 byte
00453     //char c;                                                    //Temp var for conversion, 1 byte
00454     //short h;                                                  //Temp var for conversion, 2 bytes
00455     //int k;                                                    //Temp var for conversion, 2 bytes
00456     long l;                                                     //Temp var for conversion, 4 bytes
00457 
00458     char* endptr;                                               //strtoXX() Error detection
00459 
00460     int cid = -1;                                               //Signals empty string...
00461     int ndx = -1;
00462 
00463     //Init (global) variables.
00464     argfnd=0;
00465     argcnt=0;
00466     error =0;
00467 
00468     //Zero the two string buffers for splitting cmd string into.
00469     zeromemory((char*)cmdstr_buf,sizeof(cmdstr_buf));
00470     zeromemory(argstr_buf,sizeof(argstr_buf));
00471 
00472     //Make it worse in Lint
00473     for (int i=0; i<MAX_ARGS; i++) {
00474         parms[i].type=PARM_UNUSED;
00475         zeromemory((char*)&(parms[i].val),sizeof(parms[i].val));
00476     }
00477 
00478     /*------------------------------------------------
00479     First, copy the command and convert it to all
00480     uppercase.
00481     ------------------------------------------------*/
00482 
00483     strncpy(cmdstr_buf, cmd, sizeof (cmdstr_buf) - 1);
00484     cmdstr_buf [sizeof (cmdstr_buf) - 1] = '\0';
00485 
00486     /*------------------------------------------------
00487     Next, find the end of the first thing in the
00488     buffer.  Since the command ends with a space,
00489     we'll look for that.  NULL-Terminate the command
00490     and keep a pointer to the arguments.
00491     ------------------------------------------------*/
00492 
00493     argsep = strchr(cmdstr_buf, ' ');
00494 
00495     if (argsep == NULL) {
00496         argstr_buf [0] = '\0';
00497     } else {
00498         strcpy (argstr_buf, argsep + 1);
00499         *argsep = '\0';
00500     }
00501 
00502     /*------------------------------------------------
00503     Search for a command ID, then switch on it.
00504     ------------------------------------------------*/
00505 
00506     //1) Find the Command Id
00507     cid = cmdid_search(cmdstr_buf);
00508 
00509     if (cid!=CID_LAST) {
00510         //2) Tokenize a copy of the parms from the cmd_tbl.
00511 
00512         ndx = cmdid_index(cid);
00513 
00514         //Get Format patterns from cmd_tbl[id].parms.
00515         //note: strtok inserts \0 into the original string. Hence the copy.
00516         zeromemory((char *)(&prmstr_buf),sizeof(prmstr_buf));
00517 
00518         strncpy (prmstr_buf, cmds[ndx].parms, sizeof (prmstr_buf) - 1);
00519 
00520         argcnt=0;
00521         tok = strtok(prmstr_buf, " ");
00522         while (tok != NULL) {
00523             //Store Pointers
00524             prms[argcnt++] = tok;
00525 
00526             //printf("prm_%2.2d='%s'\r\n",argcnt, tok);
00527 
00528             tok = strtok(NULL, " ");
00529         }
00530 
00531         //3) Tokenize the commandline.
00532 
00533         //Get Tokens from arguments.
00534         //Note: strtok inserts \0 into the original string. Won't harm here as we do not re-use it.
00535 
00536         argfnd=0;
00537 
00538         if (strlen(argstr_buf)!=0) {
00539             tok = strtok(argstr_buf, " ");
00540         } else {
00541             tok=NULL;
00542         }
00543 
00544         while (tok != NULL) {
00545             //Store Pointers
00546             toks[argfnd++]=tok;
00547 
00548             //printf("tok_%2.2d='%s'\r\n",argfnd, tok);
00549 
00550             tok = strtok(NULL, " ");
00551         }
00552 
00553         if (argfnd==argcnt || (cid==CID_HELP && argfnd==0)) {
00554 
00555             error = 0;
00556 
00557             for (int i=0; i<argcnt; i++) {
00558                 //printf("prm_%2.2d=%s\r\n",i, prms[i]);
00559 
00560                 switch (strlen(prms[i])) {
00561                     case 0:
00562                         break;
00563                     case 1:
00564                         break;
00565                     case 2: //Simple pattern, no modifier
00566                         mod='\0';
00567                         typ=prms[i][1];
00568 
00569                         break;
00570                     case 3: //pattern with Modifier.
00571                         mod=prms[i][1];
00572                         typ=prms[i][2];
00573 
00574                         break;
00575                     default:
00576                         break;
00577                 }
00578 
00579                 switch (typ) {
00580                     case 'o' :
00581                         base=8;
00582                         break;
00583                     case 'x' :
00584                         base=16;
00585                         break;
00586                     default:
00587                         base=10;
00588                         break;
00589                 }
00590 
00591                 endptr = (char*)toks[i];
00592 
00593                 switch (typ) {
00594                     //Signed Cardinal Types
00595                     case 'd' :  //Check mod
00596                     case 'i' :  //Check mod
00597                         switch (mod) {
00598                             case 'b' : //char
00599                                 //test range
00600                                 l=strtol((char*)toks[i], &endptr, base);
00601                                 if (l>=MIN_CHAR && l<=MAX_CHAR) {
00602                                     parms[i].type=PARM_CHAR;
00603                                     parms[i].val.uc =(unsigned char)l;
00604                                 } else {
00605                                     error = i+1;
00606                                 }
00607 
00608                                 break;
00609                             case 'h' : //short
00610                                 l=strtol((char*)toks[i], &endptr, base);
00611                                 if (l>=MIN_SHORT && l<=MAX_SHORT) {
00612                                     parms[i].type=PARM_SHORT;
00613                                     parms[i].val.w=(short)l;
00614                                 } else {
00615                                     error = i+1;
00616                                 }
00617 
00618                                 break;
00619                             case 'l' : //long
00620                                 l=strtol((char*)toks[i], &endptr, base);
00621                                 parms[i].type=PARM_LONG;
00622                                 parms[i].val.l=l;
00623 
00624                                 break;
00625                             default: //int
00626                                 l=strtol((char*)toks[i], &endptr, base);
00627                                 if (l>=MIN_INT && l<=MAX_INT) {
00628                                     parms[i].type=PARM_INT;
00629                                     parms[i].val.l=(int)l;
00630                                 } else {
00631                                     error = i+1;
00632                                 }
00633                                 break;
00634                         }
00635 
00636                         if (error==0 &&
00637                                 (endptr==toks[i]    //No Conversion at all.
00638                                  || *endptr)) {       //Incomplete conversion.
00639                             error = i+1;
00640                         }
00641 
00642                         break;
00643 
00644                     //Unsigned Cardinal Types
00645                     case 'u' :  //Check mod
00646                     case 'o' :  //Check mod
00647                     case 'x' :  //Check mod
00648                         switch (mod) {
00649                             case 'b' : //char
00650                                 //test range
00651                                 l=strtol((char*)toks[i], &endptr, base);
00652                                 if (l>=MIN_BYTE && l<=MAX_BYTE) {
00653                                     parms[i].type=PARM_CHAR;
00654                                     parms[i].val.uc =(unsigned char)l;
00655                                 } else {
00656                                     error = i+1;
00657                                 }
00658 
00659                                 break;
00660                             case 'h' : //short
00661                                 l=strtol((char*)toks[i], &endptr, base);
00662                                 if (l>=MIN_USHORT && l<=MAX_USHORT) {
00663                                     parms[i].type=PARM_SHORT;
00664                                     parms[i].val.w=(short)l;
00665                                 } else {
00666                                     error = i+1;
00667                                 }
00668 
00669                                 break;
00670                             case 'l' : //long
00671                                 l=strtol((char*)toks[i], &endptr, base);
00672                                 parms[i].type=PARM_LONG;
00673                                 parms[i].val.l=l;
00674 
00675                                 break;
00676                             default: //int
00677                                 l=strtol((char*)toks[i], &endptr, base);
00678                                 if (l>=MIN_UINT && l<=MAX_UINT) {
00679                                     parms[i].type=PARM_INT;
00680                                     parms[i].val.l=(int)l;
00681                                 } else {
00682                                     error = i+1;
00683                                 }
00684                                 break;
00685                         }
00686 
00687                         if (error==0 &&
00688                                 (endptr==toks[i]    //No Conversion at all.
00689                                  || *endptr)) {       //Incomplete conversion.
00690                             error = i+1;
00691                         }
00692 
00693                         break;
00694                 }
00695 
00696                 //Floating Point Types
00697                 switch (typ) {
00698                     case 'e' :
00699                     case 'f' :
00700                     case 'g' :
00701                         f = strtod((char*)toks[i], &endptr);
00702 
00703                         parms[i].type=PARM_FLOAT;
00704                         parms[i].val.f=f;
00705 
00706                         if (error==0 &&
00707                                 (endptr==toks[i]    //No Conversion at all.
00708                                  || *endptr)) {       //Incomplete conversion.
00709                             error = i;
00710                         }
00711 
00712                         break;
00713                 }
00714 
00715                 //String types
00716                 switch (typ) {
00717                     case 'c' :
00718                         parms[i].type=PARM_CHAR;
00719                         parms[i].val.c=((char*)toks[i])[0];
00720 
00721                         if (error==0 && strlen((char*)toks[i])!=1) {  //Incomplete conversion.
00722                             error = i;
00723                         }
00724 
00725                         break;
00726 
00727                     case 's' :
00728                         parms[i].type=PARM_STRING;
00729                         strncpy(parms[i].val.s,(char*)toks[i], strlen((char*)toks[i]));
00730 
00731                         break;
00732                 }
00733             }
00734         } else {
00735             //cid=CID_LAST;
00736         }
00737     }
00738 
00739     return cid;
00740 }
00741 
00742 //------------------------------------------------------------------------------
00743 
00744 void  Cmdb::cmd_dispatcher(char *cmd) {
00745     int  cid;
00746     int  ndx;
00747 
00748     cid = parse(cmd);
00749     ndx = cmdid_index(cid);
00750 
00751     if (cid!=-1) {
00752         //printf("cmds[%d]=%d\r\n",ndx, cid);
00753 
00754         /*------------------------------------------------
00755         Process the command and it's arguments that are
00756         found. id contains the command id and argcnt &
00757         argfnd the number of found and expected paramaters
00758         parms contains the parsed argument values and their
00759         types.
00760         ------------------------------------------------*/
00761 
00762         //printf("cmds[%d]=%d\r\n",ndx, cid);
00763 
00764         if (cid==CID_LAST) {
00765             print("Unknown command, type 'Help' for a list of available commands.\r\n");
00766         } else {
00767             //printf("cmds[%d]=%d [%s]\r\n",ndx, cid, cmds[ndx].cmdstr);
00768 
00769             //Test for more commandline than allowed too.
00770             //i.e. run 1 is wrong.
00771 
00772             if (argcnt==0 && argfnd==0 && error==0 && ndx!=-1 && cmds[ndx].subs==SUBSYSTEM) {
00773                 //Handle all SubSystems.
00774                 subsystem=cid;
00775             } else if ( ((cid==CID_HELP) || (argcnt==argfnd)) && error==0 ) {
00776                 switch (cid) {
00777 
00778 #ifdef ENABLEMACROS
00779                         /////// GLOBAL MACRO COMMANDS ///////
00780 
00781                         //Define Macro from commandline
00782                     case CID_MACRO:
00783                         macro_ptr=-1;
00784 
00785                         zeromemory((char*)macro_buf, sizeof(macro_buf));
00786                         strncpy(macro_buf, STRINGPARM(0), sizeof(macro_buf) - 1);
00787 
00788                         //DEBUG
00789                         printf("Macro=%s\r\n",macro_buf);
00790                         break;
00791 
00792                         //Run Macro
00793                     case CID_RUN:
00794                         macro_ptr=0;
00795                         break;
00796 
00797                         //List Macro's
00798                     case CID_MACROS:
00799                         print("[Macro]\r\n");
00800                         if (macro_buf[0]!='\0') {
00801                             printf("Value=%s\r\n",macro_buf);
00802                         } else {
00803                             printf(";No Macro Defined\r\n");
00804                         }
00805                         break;
00806 
00807 #endif //ENABLEMACROS
00808 
00809 #ifdef STATEMACHINE
00810                         /////// GLOBAL STATEMACHINE COMMANDS ///////
00811 
00812                         //Start State Machine
00813                     case CID_STATE:
00814                         statemachine(BYTEPARM(0));
00815 
00816                         break;
00817 #endif
00818 
00819                         /////// GLOBAL COMMANDS ///////
00820                     case CID_COMMANDS:
00821                         cmd_dump();
00822                         break;
00823 
00824                         //Echo
00825                     case CID_ECHO:
00826                         echo = BOOLPARM(0);
00827                         break;
00828 
00829                         //Bold
00830                     case CID_BOLD:
00831                         bold = BOOLPARM(0);
00832                         break;
00833 
00834                         //Warm Boot
00835                     case CID_BOOT:
00836                         mbed_reset();
00837                         break;
00838 
00839                         //Sends an ANSI escape code to clear the screen.
00840                     case CID_CLS:
00841                         print(cls);
00842                         break;
00843 
00844                         //Returns to CMD> prompt where most commands are disabled.
00845                     case CID_IDLE:
00846                         subsystem=-1;
00847                         break;
00848 
00849                         //Help
00850                     case CID_HELP: {
00851                         print("\r\n");
00852 
00853                         if (argfnd>0) {
00854                             cid = cmdid_search(STRINGPARM(0));
00855                         } else {
00856                             cid=CID_LAST;
00857                         }
00858 
00859                         if (argfnd>0 && cid!=CID_LAST) {
00860 
00861                             //Help with a valid command as first parameter
00862                             ndx = cmdid_index(cid);
00863 
00864                             switch (cmds[ndx].subs) {
00865                                 case SUBSYSTEM: { //Dump whole subsystem
00866                                     printf("%s subsystem commands:\r\n\r\n",cmds[ndx].cmdstr);
00867 
00868                                     //Count SubSystem Commands.
00869                                     int subcmds =0;
00870                                     for (int i=0; i<cmds.size(); i++) {
00871                                         if (cmds[i].subs==cid) {
00872                                             subcmds++;
00873                                         }
00874                                     }
00875 
00876                                     //Print SubSystem Commands.
00877                                     for (int i=0; i<cmds.size()-1; i++) {
00878                                         if (cmds[i].subs==cid) {
00879                                             subcmds--;
00880                                             if (subcmds!=0) {
00881                                                 cmd_help("",i,",\r\n");
00882                                             } else {
00883                                                 cmd_help("",i,".\r\n");
00884                                             }
00885                                         }
00886                                     }
00887                                 }
00888                                 break;
00889 
00890                                 case GLOBALCMD: //Dump command only
00891                                     //print("Global command:\r\n\r\n",cmd_tbl[cmd_tbl[ndx].subs].cmdstr);
00892                                     cmd_help("Syntax: ",ndx,".\r\n");
00893 
00894                                     break;
00895 
00896                                 default: {      //Dump one subsystem command
00897                                     int sndx = cmdid_index(cmds[ndx].subs);
00898 
00899                                     printf("%s subsystem command:\r\n\r\n",cmds[sndx].cmdstr);
00900 
00901                                     cmd_help("Syntax: ",ndx,".\r\n");
00902                                 }
00903                                 break;
00904                             }
00905                         } else {
00906                             if (argfnd>0) {
00907                                 //Help with invalid command as first parameter
00908                                 print("Unknown command, type 'Help' for a list of available commands.\r\n");
00909                             } else {
00910                                 //Help
00911 
00912                                 //Dump Active Subsystem, Global & Other (dormant) Subsystems
00913                                 //-1 because we want comma's and for the last a .
00914                                 for (int i=0; i<cmds.size()-1; i++) {
00915                                     if ((cmds[i].subs<0) || (cmds[i].subs==subsystem)) {
00916                                         cmd_help("",i,",\r\n");
00917                                     }
00918                                 }
00919                                 cmd_help("",cmds.size()-1,".\r\n");
00920                             }
00921                         }
00922                         print("\r\n");
00923                         break;
00924                     } //CID_HELP
00925 
00926                     default : {
00927                         // Do a Call to the Application's Command Dispatcher.
00928                         (*user_callback)(*this, cid);
00929                     }
00930                 }
00931             } else {
00932                 cmd_help("Syntax: ",ndx,".\r\n");
00933             }
00934 
00935         }
00936 
00937     } else {
00938         //cid==-1
00939     }
00940 }
00941 
00942 //------------------------------------------------------------------------------
00943 //----Dump commands table as a ini file.
00944 //------------------------------------------------------------------------------
00945 
00946 void Cmdb::cmd_dump() {
00947     int  ndx;
00948     int  j;
00949     int  k;
00950     int  lastmod;
00951 
00952     k = 0;
00953     lastmod = 0;
00954 
00955     for (ndx=0; ndx<cmds.size(); ndx++) {
00956 
00957 #ifndef SHOWHIDDEN
00958         if (cmds[ndx].subs==HIDDENSUB) {
00959             continue;
00960         }
00961 #endif
00962 
00963         switch (cmds[ndx].subs) {
00964             case SUBSYSTEM :
00965                 printf("[command%2.2d]\r\n",ndx+1);
00966                 print("type=Subsystem\r\n");
00967                 print("subsystem=Global\r\n");
00968                 break;
00969             case HIDDENSUB :
00970 #ifdef SHOWHIDDEN
00971                 printf("[command%2.2d]\r\n",ndx+1);
00972                 print("type=HiddenSubystem\r\n");
00973                 print("subsystem=Global\r\n");
00974 #endif
00975                 break;
00976             case GLOBALCMD :
00977                 printf("[command%2.2d]\r\n",ndx+1);
00978                 print("type=GlobalCommand\r\n");
00979                 print("subsystem=Global\r\n");
00980                 break;
00981             default        :
00982                 int sndx = cmdid_index(cmds[ndx].subs);
00983 
00984                 if (cmds[sndx].subs==HIDDENSUB) {
00985 #ifdef SHOWHIDDEN
00986                     printf("[command%2.2d]\r\n",ndx+1);
00987                     print("type=HiddenCommand\r\n");
00988                     print("subsystem=HiddenSubystem\r\n");
00989 #endif
00990                     continue;
00991                 }
00992 
00993                 printf("[command%2.2d]\r\n",ndx+1);
00994                 print("type=Command\r\n");
00995                 printf("subsystem=%s\r\n",cmds[sndx].cmdstr);
00996         }
00997 
00998         if (cmds[ndx].subs==HIDDENSUB) {
00999             continue;
01000         }
01001 
01002         printf("command=%s\r\n",cmds[ndx].cmdstr);
01003         printf("helpmsg=%s\r\n",cmds[ndx].cmddescr);
01004         print("parameters=");
01005         for (j=0; j<strlen(cmds[ndx].parms); j++) {
01006             switch (cmds[ndx].parms[j]) {
01007                 case '%' :
01008                     lastmod=0;
01009                     break;
01010 
01011                 case 'b' :
01012                     lastmod=8;
01013                     break;
01014                 case 'h' :
01015                     lastmod=16;
01016                     break;
01017                 case 'l' :
01018                     lastmod=32;
01019                     break;
01020 
01021                 case 'd' :
01022                 case 'i' :     {
01023                     switch (lastmod) {
01024                         case  0 :
01025                         case 16 :
01026                             print("int");
01027                             k+=3;
01028                             break;
01029                         case  8 :
01030                             print("shortint");
01031                             k+=8;
01032                             break;
01033                         case 32:
01034                             print("longint");
01035                             k+=7;
01036                             break;
01037                     }
01038                     break;
01039                 }
01040 
01041                 case 'u' :
01042                 case 'o' :
01043                 case 'x' :     {
01044                     switch (lastmod) {
01045                         case  0 :
01046                         case 16 :
01047                             print("word");
01048                             k+=4;
01049                             break;
01050                         case  8 :
01051                             print("byte");
01052                             k+=4;
01053                             break;
01054                         case 32 :
01055                             print("dword");
01056                             k+=5;
01057                             break;
01058                     }
01059 
01060                     switch (cmds[ndx].parms[j]) {
01061                         case 'o' :
01062                             print("[o]");
01063                             k+=3;
01064                             break;
01065                         case 'x' :
01066                             print("[h]");
01067                             k+=3;
01068                             break;
01069                     }
01070 
01071                     break;
01072                 }
01073 
01074                 case 'e' :
01075                 case 'f' :
01076                 case 'g' :
01077                     print("float");
01078                     k+=5;
01079                     break;
01080 
01081                 case 'c' :
01082                     print("char");
01083                     k+=4;
01084                     break;
01085 
01086                 case 's' :
01087                     print("string");
01088                     k+=6;
01089                     break;
01090 
01091                 case ' ' :
01092                     printch(sp);
01093                     k++;
01094                     break;
01095             }
01096         }
01097         print("\r\n");
01098         printf("syntax=%s\r\n",cmds[ndx].parmdescr);
01099     }
01100 }
01101 
01102 void  Cmdb::prompt(void) {
01103 #ifdef SUBSYSTEMPROMPTS
01104     if (subsystem!=-1) {
01105         int ndx = cmdid_index(subsystem);
01106 
01107         printf("%s>",cmds[ndx].cmdstr);
01108 
01109         return;
01110     }
01111 #endif //SUBSYSTEMPROMPTS
01112 
01113     printf(PROMPT);
01114 }
01115 
01116 void  Cmdb::cmd_help(char *pre, int ndx, char *post) {
01117     int  j;
01118     int  k;
01119     int  lastmod;
01120 
01121     k=0;
01122     lastmod=0;
01123 
01124     switch (cmds[ndx].subs) {
01125         case SUBSYSTEM :
01126             break;
01127         case GLOBALCMD :
01128             break;
01129         case HIDDENSUB :
01130             return;
01131         default        :
01132             if (strlen(pre)==0 && bold) {
01133                 print(boldon);
01134             }
01135             break;
01136     }
01137 
01138     print(pre);
01139     k+=strlen(pre);
01140 
01141     if (k==0) {
01142         printf("%12s",cmds[ndx].cmdstr);
01143         k+=12;
01144     } else {
01145         if (strlen(pre)>0 && bold) {
01146             print(boldon);
01147         }
01148 
01149         printf("%s",cmds[ndx].cmdstr);
01150         k+=strlen(cmds[ndx].cmdstr);
01151 
01152         if (strlen(pre)>0 && bold) {
01153             print(boldoff);
01154         }
01155     }
01156 
01157     if (strlen(cmds[ndx].parms)) {
01158         printch(sp);
01159         k++;
01160     }
01161 
01162     for (j=0; j<strlen(cmds[ndx].parms); j++) {
01163         switch (cmds[ndx].parms[j]) {
01164             case '%' :
01165                 lastmod=0;
01166                 break;
01167 
01168             case 'b' :
01169                 lastmod=8;
01170                 break;
01171             case 'h' :
01172                 lastmod=16;
01173                 break;
01174             case 'l' :
01175                 lastmod=32;
01176                 break;
01177 
01178             case 'd' :
01179             case 'i' :     {
01180                 switch (lastmod) {
01181                     case  0 :
01182                     case 16 :
01183                         print("int");
01184                         k+=3;
01185                         break;
01186                     case  8 :
01187                         print("shortint");
01188                         k+=8;
01189                         break;
01190                     case 32:
01191                         print("longint");
01192                         k+=7;
01193                         break;
01194                 }
01195                 break;
01196             }
01197 
01198             case 'u' :
01199             case 'o' :
01200             case 'x' :     {
01201                 switch (lastmod) {
01202                     case  0 :
01203                     case 16 :
01204                         print("word");
01205                         k+=4;
01206                         break;
01207                     case  8 :
01208                         print("byte");
01209                         k+=4;
01210                         break;
01211                     case 32 :
01212                         print("dword");
01213                         k+=5;
01214                         break;
01215                 }
01216 
01217                 switch (cmds[ndx].parms[j]) {
01218                     case 'o' :
01219                         print("[o]");
01220                         k+=3;
01221                         break;
01222                     case 'x' :
01223                         print("[h]");
01224                         k+=3;
01225                         break;
01226                 }
01227 
01228                 break;
01229             }
01230 
01231             case 'e' :
01232             case 'f' :
01233             case 'g' :
01234                 print("float");
01235                 k+=5;
01236                 break;
01237 
01238             case 'c' :
01239                 print("char");
01240                 k+=4;
01241                 break;
01242 
01243             case 's' :
01244                 print("string");
01245                 k+=6;
01246                 break;
01247 
01248             case ' ' :
01249                 printch(sp);
01250                 k++;
01251                 break;
01252         }
01253     }
01254 
01255     for (j=k; j<40; j++) printch(sp);
01256 
01257     switch (cmds[ndx].subs) {
01258         case SUBSYSTEM :
01259             if (ndx==subsystem) {
01260                 printf("- %s (active subsystem)%s",cmds[ndx].cmddescr,post);
01261             } else {
01262                 printf("- %s (dormant subsystem)%s",cmds[ndx].cmddescr,post);
01263             }
01264             break;
01265         case HIDDENSUB :
01266             break;
01267         case GLOBALCMD :
01268             printf("- %s (global command)%s",cmds[ndx].cmddescr,post);
01269             break;
01270         default        :
01271             printf("- %s%s",cmds[ndx].cmddescr,post);
01272             if (strlen(pre)==0 && bold) {
01273                 print(boldoff);
01274             }
01275             break;
01276     }
01277 
01278     if (strlen(pre)>0 && strlen(cmds[ndx].parmdescr)) {
01279         printf("Params: %s",cmds[ndx].parmdescr);
01280         print("\r\n");
01281     }
01282 }
01283 
01284 //------------------------------------------------------------------------------
01285 //----Wrappers
01286 //------------------------------------------------------------------------------
01287 
01288 void  Cmdb::zeromemory(char *p,unsigned int siz) {
01289     memset(p,'\0',siz);
01290 }
01291 
01292 int  Cmdb::stricmp (char *s1, char *s2) {
01293     int  i;
01294     int  len1,len2;
01295 
01296     len1=strlen(s1);
01297     len2=strlen(s2);
01298 
01299     for (i = 0; (i<len1) && (i<len2); i++) {
01300         if ( toupper (s1[i])<toupper(s2[i]) ) return (-1);
01301         if ( toupper (s1[i])>toupper(s2[i]) ) return (+1);
01302     }
01303 
01304     if (len1<len2) return (-1);
01305     if (len1>len2) return (+1);
01306 
01307     return (0);
01308 }
01309 
01310 //------------------------------------------------------------------------------