A Command Interpreter with support for used defined commands, subsystems, macros, help and parameter parsing.
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 //------------------------------------------------------------------------------
Generated on Wed Jul 13 2022 19:03:15 by 1.7.2