Code for our FYDP -only one IMU works right now -RTOS is working
Embed:
(wiki syntax)
Show/hide line numbers
tinysh.c
00001 /* 00002 * tinysh.c 00003 * 00004 * Minimal portable shell 00005 * 00006 * Copyright (C) 2001 Michel Gutierrez <mig@nerim.net> 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free 00020 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 */ 00022 00023 #include "tinysh.h" 00024 00025 #ifndef BUFFER_SIZE 00026 #define BUFFER_SIZE 64 00027 #endif 00028 #ifndef HISTORY_DEPTH 00029 #define HISTORY_DEPTH 3 00030 #endif 00031 #ifndef MAX_ARGS 00032 #define MAX_ARGS 4 00033 #endif 00034 #ifndef PROMPT_SIZE 00035 #define PROMPT_SIZE 4 00036 #endif 00037 #ifndef TOPCHAR 00038 #define TOPCHAR '/' 00039 #endif 00040 00041 00042 typedef unsigned char uchar; 00043 /* redefine some useful and maybe missing utilities to avoid conflicts */ 00044 #define strlen tinysh_strlen 00045 #define puts tinysh_puts 00046 #define putchar tinysh_char_out 00047 00048 static void help_fnt(int argc, char **argv); 00049 00050 static tinysh_cmd_t help_cmd={ 00051 0,"help","display help","<cr>",help_fnt,0,0,0 }; 00052 00053 static uchar input_buffers[HISTORY_DEPTH][BUFFER_SIZE+1]={0}; 00054 static uchar trash_buffer[BUFFER_SIZE+1]={0}; 00055 static int cur_buf_index=0; 00056 static uchar context_buffer[BUFFER_SIZE+1]={0}; 00057 static int cur_context=0; 00058 static int cur_index=0; 00059 int echo=1; 00060 static char prompt[PROMPT_SIZE+1]="$ "; 00061 static tinysh_cmd_t *root_cmd=&help_cmd; 00062 static tinysh_cmd_t *cur_cmd_ctx=0; 00063 static void *tinysh_arg=0; 00064 00065 /* few useful utilities that may be missing */ 00066 00067 static int strlen(uchar *s) 00068 { 00069 int i; 00070 for(i=0;*s;s++,i++); 00071 return i; 00072 } 00073 00074 static void puts(char *s) 00075 { 00076 while(*s) 00077 putchar(*s++); 00078 } 00079 00080 /* callback for help function 00081 */ 00082 static void help_fnt(int argc, char **argv) 00083 { 00084 puts("? display help on given or available commands\r\n"); 00085 puts("<TAB> auto-completion\r\n"); 00086 puts("<cr> execute command line\r\n"); 00087 puts("CTRL-P recall previous input line\r\n"); 00088 puts("CTRL-N recall next input line\r\n"); 00089 puts("<any> treat as input character\r\n"); 00090 } 00091 00092 /* 00093 */ 00094 00095 enum { NULLMATCH,FULLMATCH,PARTMATCH,UNMATCH,MATCH,AMBIG }; 00096 00097 /* verify if the non-spaced part of s2 is included at the begining 00098 * of s1. 00099 * return FULLMATCH if s2 equal to s1, PARTMATCH if s1 starts with s2 00100 * but there are remaining chars in s1, UNMATCH if s1 does not start with 00101 * s2 00102 */ 00103 int strstart(uchar *s1, uchar *s2) 00104 { 00105 while(*s1 && *s1==*s2) { s1++; s2++; } 00106 00107 if(*s2==' ' || *s2==0) 00108 { 00109 if(*s1==0) 00110 return FULLMATCH; /* full match */ 00111 else 00112 return PARTMATCH; /* partial match */ 00113 } 00114 else 00115 return UNMATCH; /* no match */ 00116 } 00117 00118 /* 00119 * check commands at given level with input string. 00120 * _cmd: point to first command at this level, return matched cmd 00121 * _str: point to current unprocessed input, return next unprocessed 00122 */ 00123 static int parse_command(tinysh_cmd_t **_cmd, uchar **_str) 00124 { 00125 uchar *str=*_str; 00126 tinysh_cmd_t *cmd; 00127 int matched_len=0; 00128 tinysh_cmd_t *matched_cmd=0; 00129 00130 /* first eliminate first blanks */ 00131 while(*str==' ') str++; 00132 if(!*str) 00133 { 00134 *_str=str; 00135 return NULLMATCH; /* end of input */ 00136 } 00137 00138 /* first pass: count matches */ 00139 for(cmd=*_cmd;cmd;cmd=cmd->next) 00140 { 00141 int ret=strstart(cmd->name,str); 00142 00143 if(ret==FULLMATCH) 00144 { 00145 /* found full match */ 00146 while(*str && *str!=' ') str++; 00147 while(*str==' ') str++; 00148 *_str=str; 00149 *_cmd=cmd; 00150 return MATCH; 00151 } 00152 else if (ret==PARTMATCH) 00153 { 00154 if(matched_cmd) 00155 { 00156 *_cmd=matched_cmd; 00157 return AMBIG; 00158 } 00159 else 00160 { 00161 matched_cmd=cmd; 00162 } 00163 } 00164 else /* UNMATCH */ 00165 { 00166 } 00167 } 00168 if(matched_cmd) 00169 { 00170 while(*str && *str!=' ') str++; 00171 while(*str==' ') str++; 00172 *_cmd=matched_cmd; 00173 *_str=str; 00174 return MATCH; 00175 } 00176 else 00177 return UNMATCH; 00178 } 00179 00180 /* create a context from current input line 00181 */ 00182 static void do_context(tinysh_cmd_t *cmd, uchar *str) 00183 { 00184 while(*str) 00185 context_buffer[cur_context++]=*str++; 00186 context_buffer[cur_context]=0; 00187 cur_cmd_ctx=cmd; 00188 } 00189 00190 /* execute the given command by calling callback with appropriate 00191 * arguments 00192 */ 00193 static void exec_command(tinysh_cmd_t *cmd, uchar *str) 00194 { 00195 char *argv[MAX_ARGS]; 00196 int argc=0; 00197 int i; 00198 00199 /* copy command line to preserve it for history */ 00200 for(i=0;i<BUFFER_SIZE;i++) 00201 trash_buffer[i]=str[i]; 00202 str=trash_buffer; 00203 00204 /* cut into arguments */ 00205 argv[argc++]=cmd->name; 00206 while(*str && argc<MAX_ARGS) 00207 { 00208 while(*str==' ') str++; 00209 if(*str==0) 00210 break; 00211 argv[argc++]=str; 00212 while(*str!=' ' && *str) str++; 00213 if(!*str) break; 00214 *str++=0; 00215 } 00216 /* call command function if present */ 00217 if(cmd->function) 00218 { 00219 tinysh_arg=cmd->arg; 00220 cmd->function(argc,&argv[0]); 00221 } 00222 } 00223 00224 /* try to execute the current command line 00225 */ 00226 static int exec_command_line(tinysh_cmd_t *cmd, uchar *_str) 00227 { 00228 uchar *str=_str; 00229 00230 while(1) 00231 { 00232 int ret; 00233 ret=parse_command(&cmd,&str); 00234 if(ret==MATCH) /* found unique match */ 00235 { 00236 if(cmd) 00237 { 00238 if(!cmd->child) /* no sub-command, execute */ 00239 { 00240 exec_command(cmd,str); 00241 return 0; 00242 } 00243 else 00244 { 00245 if(*str==0) /* no more input, this is a context */ 00246 { 00247 do_context(cmd,_str); 00248 return 0; 00249 } 00250 else /* process next command word */ 00251 { 00252 cmd=cmd->child; 00253 } 00254 } 00255 } 00256 else /* cmd == 0 */ 00257 { 00258 return 0; 00259 } 00260 } 00261 else if(ret==AMBIG) 00262 { 00263 puts("ambiguity: "); 00264 puts(str); 00265 puts("\r\n"); 00266 return 0; 00267 } 00268 else if(ret==UNMATCH) /* UNMATCH */ 00269 { 00270 puts("no match: "); 00271 puts(str); 00272 puts("\r\n"); 00273 return 0; 00274 } 00275 else /* NULLMATCH */ 00276 return 0; 00277 } 00278 } 00279 00280 /* display help for list of commands 00281 */ 00282 static void display_child_help(tinysh_cmd_t *cmd) 00283 { 00284 tinysh_cmd_t *cm; 00285 int len=0; 00286 00287 puts("\r\n"); 00288 for(cm=cmd;cm;cm=cm->next) 00289 if(len<strlen(cm->name)) 00290 len=strlen(cm->name); 00291 for(cm=cmd;cm;cm=cm->next) 00292 if(cm->help) 00293 { 00294 int i; 00295 puts(cm->name); 00296 for(i=strlen(cm->name);i<len+2;i++) 00297 putchar(' '); 00298 puts(cm->help); 00299 puts("\r\n"); 00300 } 00301 } 00302 00303 /* try to display help for current comand line 00304 */ 00305 static int help_command_line(tinysh_cmd_t *cmd, uchar *_str) 00306 { 00307 uchar *str=_str; 00308 00309 while(1) 00310 { 00311 int ret; 00312 ret=parse_command(&cmd,&str); 00313 if(ret==MATCH && *str==0) /* found unique match or empty line */ 00314 { 00315 tinysh_cmd_t *cm; 00316 int len=0; 00317 00318 if(cmd->child) /* display sub-commands help */ 00319 { 00320 display_child_help(cmd->child); 00321 return 0; 00322 } 00323 else /* no sub-command, show single help */ 00324 { 00325 if(*(str-1)!=' ') 00326 putchar(' '); 00327 if(cmd->usage) 00328 puts(cmd->usage); 00329 puts(": "); 00330 if(cmd->help) 00331 puts(cmd->help); 00332 else 00333 puts("no help available"); 00334 puts("\r\n"); 00335 } 00336 return 0; 00337 } 00338 else if(ret==MATCH && *str) 00339 { /* continue processing the line */ 00340 cmd=cmd->child; 00341 } 00342 else if(ret==AMBIG) 00343 { 00344 puts("\r\nambiguity: "); 00345 puts(str); 00346 puts("\r\n"); 00347 return 0; 00348 } 00349 else if(ret==UNMATCH) 00350 { 00351 puts("\r\nno match: "); 00352 puts(str); 00353 puts("\r\n"); 00354 return 0; 00355 } 00356 else /* NULLMATCH */ 00357 { 00358 if(cur_cmd_ctx) 00359 display_child_help(cur_cmd_ctx->child); 00360 else 00361 display_child_help(root_cmd); 00362 return 0; 00363 } 00364 } 00365 } 00366 00367 /* try to complete current command line 00368 */ 00369 static int complete_command_line(tinysh_cmd_t *cmd, uchar *_str) 00370 { 00371 uchar *str=_str; 00372 00373 while(1) 00374 { 00375 int ret; 00376 int common_len=BUFFER_SIZE; 00377 int _str_len; 00378 int i; 00379 uchar *__str=str; 00380 00381 tinysh_cmd_t *_cmd=cmd; 00382 ret=parse_command(&cmd,&str); 00383 for(_str_len=0;__str[_str_len]&&__str[_str_len]!=' ';_str_len++); 00384 if(ret==MATCH && *str) 00385 { 00386 cmd=cmd->child; 00387 } 00388 else if(ret==AMBIG || ret==MATCH || ret==NULLMATCH) 00389 { 00390 tinysh_cmd_t *cm; 00391 tinysh_cmd_t *matched_cmd=0; 00392 int nb_match=0; 00393 00394 for(cm=cmd;cm;cm=cm->next) 00395 { 00396 int r=strstart(cm->name,__str); 00397 if(r==FULLMATCH) 00398 { 00399 for(i=_str_len;cmd->name[i];i++) 00400 tinysh_char_in(cmd->name[i]); 00401 if(*(str-1)!=' ') 00402 tinysh_char_in(' '); 00403 if(!cmd->child) 00404 { 00405 if(cmd->usage) 00406 { 00407 puts(cmd->usage); 00408 putchar('\n'); 00409 return 1; 00410 } 00411 else 00412 return 0; 00413 } 00414 else 00415 { 00416 cmd=cmd->child; 00417 break; 00418 } 00419 } 00420 else if(r==PARTMATCH) 00421 { 00422 nb_match++; 00423 if(!matched_cmd) 00424 { 00425 matched_cmd=cm; 00426 common_len=strlen(cm->name); 00427 } 00428 else 00429 { 00430 for(i=_str_len;cm->name[i] && i<common_len && 00431 cm->name[i]==matched_cmd->name[i];i++); 00432 if(i<common_len) 00433 common_len=i; 00434 } 00435 } 00436 } 00437 if(cm) 00438 continue; 00439 if(matched_cmd) 00440 { 00441 if(_str_len==common_len) 00442 { 00443 puts("\r\n"); 00444 for(cm=cmd;cm;cm=cm->next) 00445 { 00446 int r=strstart(cm->name,__str); 00447 if(r==FULLMATCH || r==PARTMATCH) 00448 { 00449 puts(cm->name); 00450 puts("\r\n"); 00451 } 00452 } 00453 return 1; 00454 } 00455 else 00456 { 00457 for(i=_str_len;i<common_len;i++) 00458 tinysh_char_in(matched_cmd->name[i]); 00459 if(nb_match==1) 00460 tinysh_char_in(' '); 00461 } 00462 } 00463 return 0; 00464 } 00465 else /* UNMATCH */ 00466 { 00467 return 0; 00468 } 00469 } 00470 } 00471 00472 /* start a new line 00473 */ 00474 static void start_of_line() 00475 { 00476 /* display start of new line */ 00477 puts(prompt); 00478 if(cur_context) 00479 { 00480 puts(context_buffer); 00481 puts("> "); 00482 } 00483 cur_index=0; 00484 } 00485 00486 /* character input 00487 */ 00488 static void _tinysh_char_in(uchar c) 00489 { 00490 uchar *line=input_buffers[cur_buf_index]; 00491 00492 if(c=='\n' || c=='\r') /* validate command */ 00493 { 00494 tinysh_cmd_t *cmd; 00495 int context=0; 00496 00497 /* first, echo the newline */ 00498 if(echo) 00499 putchar(c); 00500 00501 while(*line && *line==' ') line++; 00502 if(*line) /* not empty line */ 00503 { 00504 cmd=cur_cmd_ctx?cur_cmd_ctx->child:root_cmd; 00505 exec_command_line(cmd,line); 00506 cur_buf_index=(cur_buf_index+1)%HISTORY_DEPTH; 00507 cur_index=0; 00508 input_buffers[cur_buf_index][0]=0; 00509 } 00510 start_of_line(); 00511 } 00512 else if(c==TOPCHAR) /* return to top level */ 00513 { 00514 if(echo) 00515 putchar(c); 00516 00517 cur_context=0; 00518 cur_cmd_ctx=0; 00519 00520 } 00521 else if(c==8 || c==127) /* backspace */ 00522 { 00523 if(cur_index>0) 00524 { 00525 puts("\b \b"); 00526 cur_index--; 00527 line[cur_index]=0; 00528 } 00529 } 00530 else if(c==16) /* CTRL-P: back in history */ 00531 { 00532 int prevline=(cur_buf_index+HISTORY_DEPTH-1)%HISTORY_DEPTH; 00533 00534 if(input_buffers[prevline][0]) 00535 { 00536 line=input_buffers[prevline]; 00537 /* fill the rest of the line with spaces */ 00538 while(cur_index-->strlen(line)) 00539 puts("\b \b"); 00540 putchar('\r'); 00541 start_of_line(); 00542 puts(line); 00543 cur_index=strlen(line); 00544 cur_buf_index=prevline; 00545 } 00546 } 00547 else if(c==14) /* CTRL-N: next in history */ 00548 { 00549 int nextline=(cur_buf_index+1)%HISTORY_DEPTH; 00550 00551 if(input_buffers[nextline][0]) 00552 { 00553 line=input_buffers[nextline]; 00554 /* fill the rest of the line with spaces */ 00555 while(cur_index-->strlen(line)) 00556 puts("\b \b"); 00557 putchar('\r'); 00558 start_of_line(); 00559 puts(line); 00560 cur_index=strlen(line); 00561 cur_buf_index=nextline; 00562 } 00563 } 00564 else if(c=='?') /* display help */ 00565 { 00566 tinysh_cmd_t *cmd; 00567 cmd=cur_cmd_ctx?cur_cmd_ctx->child:root_cmd; 00568 help_command_line(cmd,line); 00569 start_of_line(); 00570 puts(line); 00571 cur_index=strlen(line); 00572 } 00573 else if(c==9 || c=='!') /* TAB: autocompletion */ 00574 { 00575 tinysh_cmd_t *cmd; 00576 cmd=cur_cmd_ctx?cur_cmd_ctx->child:root_cmd; 00577 if(complete_command_line(cmd,line)) 00578 { 00579 start_of_line(); 00580 puts(line); 00581 } 00582 cur_index=strlen(line); 00583 } 00584 else /* any input character */ 00585 { 00586 if(cur_index<BUFFER_SIZE) 00587 { 00588 if(echo) 00589 putchar(c); 00590 line[cur_index++]=c; 00591 line[cur_index]=0; 00592 } 00593 } 00594 } 00595 00596 /* new character input */ 00597 void tinysh_char_in(uchar c) 00598 { 00599 /* 00600 * filter characters here 00601 */ 00602 _tinysh_char_in(c); 00603 } 00604 00605 /* add a new command */ 00606 void tinysh_add_command(tinysh_cmd_t *cmd) 00607 { 00608 tinysh_cmd_t *cm; 00609 00610 if(cmd->parent) 00611 { 00612 cm=cmd->parent->child; 00613 if(!cm) 00614 { 00615 cmd->parent->child=cmd; 00616 } 00617 else 00618 { 00619 while(cm->next) cm=cm->next; 00620 cm->next=cmd; 00621 } 00622 } 00623 else if(!root_cmd) 00624 { 00625 root_cmd=cmd; 00626 } 00627 else 00628 { 00629 cm=root_cmd; 00630 while(cm->next) cm=cm->next; 00631 cm->next=cmd; 00632 } 00633 } 00634 00635 /* modify shell prompt 00636 */ 00637 void tinysh_set_prompt(char *str) 00638 { 00639 int i; 00640 for(i=0;str[i] && i<PROMPT_SIZE;i++) 00641 prompt[i]=str[i]; 00642 prompt[i]=0; 00643 /* force prompt display by generating empty command */ 00644 tinysh_char_in('\r'); 00645 } 00646 00647 /* return current command argument 00648 */ 00649 void *tinysh_get_arg() 00650 { 00651 return tinysh_arg; 00652 } 00653 00654 /* string to decimal/hexadecimal conversion 00655 */ 00656 unsigned long tinysh_atoxi(char *s) 00657 { 00658 int ishex=0; 00659 unsigned long res=0; 00660 int sign = 1; 00661 00662 if(*s==0) return 0; 00663 00664 if(*s=='0' && *(s+1)=='x') 00665 { 00666 ishex=1; 00667 s+=2; 00668 } 00669 00670 while(*s) 00671 { 00672 if(ishex) 00673 res*=16; 00674 else 00675 res*=10; 00676 00677 if(*s>='0' && *s<='9') 00678 res+=*s-'0'; 00679 else if(ishex && *s>='a' && *s<='f') 00680 res+=*s+10-'a'; 00681 else if(ishex && *s>='A' && *s<='F') 00682 res+=*s+10-'A'; 00683 else if(*s=='-') 00684 sign=-1; 00685 else 00686 break; 00687 00688 s++; 00689 } 00690 00691 return sign*res; 00692 } 00693
Generated on Wed Jul 13 2022 10:32:23 by 1.7.2