Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
ns_cmdline.c
00001 /* 00002 * Copyright (c) 2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include <stdio.h> 00018 #include <stdarg.h> 00019 #include <stdlib.h> 00020 #include <string.h> 00021 #include <ctype.h> 00022 00023 #if defined(_WIN32) || defined(__unix__) || defined(__unix) || defined(unix) || defined(MBED_CONF_RTOS_PRESENT) || defined(__APPLE__) 00024 #include <stdlib.h> //malloc 00025 #ifndef MEM_ALLOC 00026 #define MEM_ALLOC malloc 00027 #endif 00028 #ifndef MEM_FREE 00029 #define MEM_FREE free 00030 #endif 00031 #else 00032 #include "nsdynmemLIB.h" 00033 #ifndef MEM_ALLOC 00034 #define MEM_ALLOC ns_dyn_mem_temporary_alloc 00035 #endif 00036 #ifndef MEM_FREE 00037 #define MEM_FREE ns_dyn_mem_free 00038 #endif 00039 #endif 00040 00041 // force traces for this module 00042 //#define FEA_TRACE_SUPPORT 00043 00044 00045 #ifdef YOTTA_CFG 00046 #include "ns_list_internal/ns_list.h" 00047 #include "mbed-client-cli/ns_cmdline.h" 00048 #else 00049 #include "ns_list.h" 00050 #include "ns_cmdline.h" 00051 #endif 00052 #include "mbed-trace/mbed_trace.h" 00053 00054 //#define TRACE_DEEP 00055 //#define TRACE_PRINTF 00056 00057 #ifdef TRACE_PRINTF 00058 #undef tr_debug 00059 #define tr_debug(...) printf( __VA_ARGS__);printf("\r\n") 00060 #endif 00061 00062 // #define MBED_CLIENT_CLI_TRACE_ENABLE 00063 // MBED_CLIENT_CLI_TRACE_ENABLE is to enable the traces for debugging, 00064 // By default all debug traces are disabled. 00065 #ifndef MBED_CLIENT_CLI_TRACE_ENABLE 00066 #undef tr_error 00067 #define tr_error(...) 00068 #undef tr_warn 00069 #define tr_warn(...) 00070 #undef tr_debug 00071 #define tr_debug(...) 00072 #undef tr_info 00073 #define tr_info(...) 00074 #endif 00075 00076 #ifdef TRACE_DEEP 00077 #define tr_deep tr_debug 00078 #else 00079 #define tr_deep(...) 00080 #endif 00081 00082 #define TRACE_GROUP "cmdL" 00083 00084 #ifndef MBED_CMDLINE_BOOT_MESSAGE 00085 #define MBED_CMDLINE_BOOT_MESSAGE "ARM Ltd\r\n" 00086 #endif 00087 #define ESCAPE(x) "\x1b" x 00088 #define CR_S "\r" 00089 #define LF_S "\n" 00090 #define CLEAR_ENTIRE_LINE ESCAPE("[2K") 00091 #define CLEAR_ENTIRE_SCREEN ESCAPE("[2J") 00092 #define ENABLE_AUTO_WRAP_MODE ESCAPE("[7h") 00093 #define MOVE_CURSOR_LEFT_N_CHAR ESCAPE("[%dD") 00094 00095 #define SET_TOP_AND_BOTTOM_LINES ESCAPE("[;r") 00096 #define MOVE_CURSOR_TO_BOTTOM_RIGHT ESCAPE("[999;999H") 00097 #define STORE_CURSOR_POS ESCAPE("7") 00098 #define RESTORE_CURSOR_POS ESCAPE("8") 00099 #define GET_CURSOR_POSITION ESCAPE("[6n") 00100 00101 #define REQUEST_SCREEN_SIZE STORE_CURSOR_POS SET_TOP_AND_BOTTOM_LINES MOVE_CURSOR_TO_BOTTOM_RIGHT GET_CURSOR_POSITION RESTORE_CURSOR_POS 00102 00103 /*ASCII defines*/ 00104 #define ESC 0x1B 00105 #define DEL 0x7F 00106 #define BS 0x08 00107 #define ETX 0x03 00108 #define ETB 0x17 00109 #define TAB 0x09 00110 #define CAN 0x18 00111 00112 #define DEFAULT_RETFMT "retcode: %i\r\n" 00113 #define DEFAULT_PROMPT "/>" 00114 #define VAR_PROMPT "PS1" 00115 #define VAR_RETFMT "RETFMT" 00116 00117 // Maximum length of input line 00118 #ifdef MBED_CMDLINE_MAX_LINE_LENGTH 00119 #define MAX_LINE MBED_CMDLINE_MAX_LINE_LENGTH 00120 #else 00121 #define MAX_LINE 2000 00122 #endif 00123 // Maximum number of arguments in a single command 00124 #ifdef MBED_CMDLINE_ARGUMENTS_MAX_COUNT 00125 #define MAX_ARGUMENTS MBED_CMDLINE_ARGUMENTS_MAX_COUNT 00126 #else 00127 #define MAX_ARGUMENTS 30 00128 #endif 00129 // Maximum number of commands saved in history 00130 #ifdef MBED_CMDLINE_HISTORY_MAX_COUNT 00131 #define HISTORY_MAX_COUNT MBED_CMDLINE_HISTORY_MAX_COUNT 00132 #else 00133 #define HISTORY_MAX_COUNT 32 00134 #endif 00135 //include manuals or not (save memory a little when not include) 00136 #ifndef MBED_CMDLINE_INCLUDE_MAN 00137 #define MBED_CMDLINE_INCLUDE_MAN 1 00138 #endif 00139 00140 00141 typedef struct cmd_history_s { 00142 char *command_ptr; 00143 ns_list_link_t link; 00144 } cmd_history_t; 00145 00146 typedef struct cmd_command_s { 00147 const char *name_ptr; 00148 const char *info_ptr; 00149 const char *man_ptr; 00150 cmd_run_cb *run_cb; 00151 bool busy; 00152 ns_list_link_t link; 00153 } cmd_command_t; 00154 00155 typedef struct cmd_alias_s { 00156 char *name_ptr; 00157 char *value_ptr; 00158 ns_list_link_t link; 00159 } cmd_alias_t; 00160 00161 union Data { 00162 char *ptr; 00163 int i; 00164 }; 00165 typedef enum value_type_s { 00166 VALUE_TYPE_STR, 00167 VALUE_TYPE_INT 00168 } value_type_t; 00169 00170 typedef struct cmd_variable_s { 00171 char *name_ptr; 00172 union Data value; 00173 value_type_t type; 00174 ns_list_link_t link; 00175 } cmd_variable_t; 00176 00177 typedef enum operator_s { 00178 OPERATOR_SEMI_COLON, //default 00179 OPERATOR_AND, 00180 OPERATOR_OR, 00181 OPERATOR_BACKGROUND, 00182 OPERATOR_PIPE 00183 } operator_t; 00184 typedef struct cmd_exe_s { 00185 char *cmd_s; 00186 operator_t operator; 00187 ns_list_link_t link; 00188 } cmd_exe_t; 00189 typedef NS_LIST_HEAD (cmd_exe_t, link) cmd_list_t; 00190 typedef NS_LIST_HEAD (cmd_history_t, link) history_list_t; 00191 typedef NS_LIST_HEAD (cmd_command_t, link) command_list_t; 00192 typedef NS_LIST_HEAD (cmd_alias_t, link) alias_list_t; 00193 typedef NS_LIST_HEAD (cmd_variable_t, link) variable_list_t; 00194 00195 typedef struct cmd_class_s { 00196 char input[MAX_LINE]; // input data 00197 char escape[10]; // escape data 00198 int16_t history; // history position 00199 int16_t cursor; // cursor position 00200 int16_t escape_index; // escape index 00201 history_list_t history_list; // input history 00202 uint8_t history_max_count; // history max size 00203 command_list_t command_list; // commands list 00204 alias_list_t alias_list; // alias list 00205 variable_list_t variable_list; // variables list 00206 bool vt100_on; // control characters 00207 bool init; // true when lists are initialized already 00208 bool escaping; // escaping input 00209 bool insert; // insert enabled 00210 int tab_lookup; // originally lookup characters count 00211 int tab_lookup_cmd_n; // index in command list 00212 int tab_lookup_n; // 00213 bool prev_cr; // indicate if cr was last char 00214 bool echo; // echo inputs 00215 cmd_ready_cb_f *ready_cb; // ready cb function 00216 cmd_list_t cmd_buffer; 00217 cmd_exe_t *cmd_buffer_ptr; 00218 cmd_command_t *cmd_ptr; 00219 int8_t tasklet_id; 00220 int8_t network_tasklet_id; 00221 bool idle; 00222 00223 cmd_print_t *out; // print cb function 00224 void (*ctrl_fnc)(uint8_t c); // control cb function 00225 void (*mutex_wait_fnc)(void); // mutex wait cb function 00226 void (*mutex_release_fnc)(void); // mutex release cb function 00227 input_passthrough_func_t passthrough_fnc; // input passthrough cb function 00228 } cmd_class_t; 00229 00230 cmd_class_t cmd = { 00231 .init = false, 00232 .cmd_ptr = NULL, 00233 .mutex_wait_fnc = NULL, 00234 .mutex_release_fnc = NULL, 00235 .passthrough_fnc = NULL 00236 }; 00237 00238 /* Function prototypes 00239 */ 00240 static void cmd_init_base_commands(void); 00241 static void cmd_replace_alias(char *input); 00242 static void cmd_replace_variables(char *input); 00243 static int cmd_parse_argv(char *string_ptr, char **argv); 00244 static void cmd_execute(void); 00245 static void cmd_line_clear(int from); 00246 static void cmd_history_save(int16_t index); 00247 static void cmd_history_get(uint16_t index); 00248 static void cmd_history_clean_overflow(void); 00249 static void cmd_history_clean(void); 00250 static void cmd_echo(bool on); 00251 static cmd_history_t *cmd_history_find(int16_t index); 00252 static bool cmd_tab_lookup(void); 00253 static void cmd_clear_last_word(void); 00254 static void cmd_move_cursor_to_last_space(void); 00255 static void cmd_move_cursor_to_next_space(void); 00256 static const char *cmd_input_lookup(char *name, int namelength, int n); 00257 static char *cmd_input_lookup_var(char *name, int namelength, int n); 00258 static cmd_command_t *cmd_find(const char *name); 00259 static cmd_command_t *cmd_find_n(char *name, int nameLength, int n); 00260 static cmd_alias_t *alias_find(const char *alias); 00261 static cmd_alias_t *alias_find_n(char *alias, int aliaslength, int n); 00262 static cmd_variable_t *variable_find(char *variable); 00263 static cmd_variable_t *variable_find_n(char *variable, int length, int n); 00264 static void cmd_print_man(cmd_command_t *command_ptr); 00265 static void goto_end_of_history(void); 00266 static void goto_beginning_of_history(void); 00267 static void cmd_set_input(const char *str, int cur); 00268 static char *next_command(char *string_ptr, operator_t *mode); 00269 /** Run single command through cmd intepreter 00270 * \param string_ptr command string with parameters 00271 * \ret command return code (CMDLINE_RETCODE_*) 00272 */ 00273 static int cmd_run(char *string_ptr); 00274 static cmd_exe_t *cmd_next_ptr(int retcode); 00275 static void cmd_split(char *string_ptr); 00276 static void cmd_push(char *cmd_str, operator_t oper); 00277 00278 /*internal shell commands 00279 */ 00280 int true_command(int argc, char *argv[]); 00281 int false_command(int argc, char *argv[]); 00282 int echo_command(int argc, char *argv[]); 00283 int alias_command(int argc, char *argv[]); 00284 int unset_command(int argc, char *argv[]); 00285 int set_command(int argc, char *argv[]); 00286 int clear_command(int argc, char *argv[]); 00287 int help_command(int argc, char *argv[]); 00288 int history_command(int argc, char *argv[]); 00289 00290 /** Internal helper functions 00291 */ 00292 static const char *find_last_space(const char *from, const char *to); 00293 static int replace_string( 00294 char *str, int str_len, 00295 const char *old_str, const char *new_str); 00296 00297 void default_cmd_response_out(const char *fmt, va_list ap) 00298 { 00299 vprintf(fmt, ap); 00300 fflush(stdout); 00301 } 00302 void cmd_printf(const char *fmt, ...) 00303 { 00304 va_list ap; 00305 va_start(ap, fmt); 00306 cmd_vprintf(fmt, ap); 00307 va_end(ap); 00308 } 00309 void cmd_vprintf(const char *fmt, va_list ap) 00310 { 00311 if (cmd.mutex_wait_fnc) { 00312 cmd.mutex_wait_fnc(); 00313 } 00314 cmd.out(fmt, ap); 00315 if (cmd.mutex_release_fnc) { 00316 cmd.mutex_release_fnc(); 00317 } 00318 } 00319 /* Function definitions 00320 */ 00321 void cmd_init(cmd_print_t *outf) 00322 { 00323 if (!cmd.init) { 00324 ns_list_init(&cmd.alias_list); 00325 ns_list_init(&cmd.history_list); 00326 ns_list_init(&cmd.command_list); 00327 ns_list_init(&cmd.variable_list); 00328 ns_list_init(&cmd.cmd_buffer); 00329 cmd.init = true; 00330 } 00331 cmd.out = outf ? outf : default_cmd_response_out; 00332 cmd.ctrl_fnc = NULL; 00333 cmd.echo = true; 00334 cmd.escaping = false; 00335 cmd.insert = true; 00336 cmd.cursor = 0; 00337 cmd.prev_cr = false; 00338 cmd.vt100_on = true; 00339 cmd.history_max_count = HISTORY_MAX_COUNT; 00340 cmd.tab_lookup = 0; 00341 cmd.tab_lookup_cmd_n = 0; 00342 cmd.tab_lookup_n = 0; 00343 cmd.cmd_buffer_ptr = 0; 00344 cmd.idle = true; 00345 cmd.ready_cb = cmd_next; 00346 cmd.passthrough_fnc = NULL; 00347 cmd_variable_add(VAR_PROMPT, DEFAULT_PROMPT); 00348 cmd_variable_add_int("?", 0); 00349 //cmd_alias_add("auto-on", "set PS1=\r\nretcode=$?\r\n&&echo off"); 00350 //cmd_alias_add("auto-off", "set PS1="DEFAULT_PROMPT"&&echo on"); 00351 cmd_line_clear(0); // clear line 00352 cmd_history_save(0); // the current line is the 0 item 00353 cmd_init_base_commands(); 00354 cmd_init_screen(); 00355 return; 00356 } 00357 void cmd_request_screen_size(void) 00358 { 00359 cmd_printf(REQUEST_SCREEN_SIZE); 00360 } 00361 00362 const char *cmdline_get_prompt(void) 00363 { 00364 cmd_variable_t *var_ptr = variable_find(VAR_PROMPT); 00365 return var_ptr && var_ptr->type == VALUE_TYPE_STR ? var_ptr->value.ptr : ""; 00366 } 00367 const char *cmd_get_retfmt(void) 00368 { 00369 cmd_variable_t *var_ptr = variable_find(VAR_RETFMT); 00370 return var_ptr && var_ptr->type == VALUE_TYPE_STR ? var_ptr->value.ptr : 0; 00371 } 00372 00373 #if MBED_CMDLINE_INCLUDE_MAN == 1 00374 #define MAN_ECHO "Displays messages, or turns command echoing on or off\r\n"\ 00375 "echo <data_to_be_print>\r\n"\ 00376 "some special parameters:\r\n"\ 00377 "<bool> On/Off echo input characters\r\n" 00378 #define MAN_ALIAS "alias <theAlias> <command (parameters)>\r\n" 00379 #define MAN_UNSET "unset <var_name>\r\n" 00380 #define MAN_SET "set <var_name> <value>\r\n"\ 00381 "some special parameters\r\n"\ 00382 "--vt100 <bool> On/Off vt100 controls\r\n"\ 00383 "--retcode <bool> On/Off retcode print after execution\r\n"\ 00384 "--retfmt <format> Return print format. Default: \"retcode: %i\\n\"\r\n" 00385 00386 #define MAN_CLEAR "Clears the display" 00387 #define MAN_HISTORY "Show commands history\r\n"\ 00388 "history (<optio>)\r\n"\ 00389 "clear Clear history\r\n" 00390 #else 00391 #define MAN_ECHO NULL 00392 #define MAN_ALIAS NULL 00393 #define MAN_SET NULL 00394 #define MAN_CLEAR NULL 00395 #define MAN_HISTORY NULL 00396 #endif 00397 00398 static void cmd_init_base_commands(void) 00399 { 00400 cmd_add("help", help_command, "This help", NULL); 00401 cmd_add("echo", echo_command, "Echo controlling", MAN_ECHO); 00402 cmd_add("alias", alias_command, "Handle aliases", MAN_ALIAS); 00403 cmd_add("unset", unset_command, "unset variables", MAN_UNSET); 00404 cmd_add("set", set_command, "print or set variables", MAN_SET); 00405 cmd_add("clear", clear_command, "Clears the display", MAN_CLEAR); 00406 cmd_add("history", history_command, "View your command Line History", MAN_HISTORY); 00407 cmd_add("true", true_command, 0, 0); 00408 cmd_add("false", false_command, 0, 0); 00409 } 00410 void cmd_reset(void) 00411 { 00412 cmd_free(); 00413 cmd_init_base_commands(); 00414 } 00415 void cmd_free(void) 00416 { 00417 ns_list_foreach_safe(cmd_command_t, cur_ptr, &cmd.command_list) { 00418 cmd_delete(cur_ptr->name_ptr); 00419 } 00420 ns_list_foreach_safe(cmd_alias_t, cur_ptr, &cmd.alias_list) { 00421 cmd_alias_add(cur_ptr->name_ptr, NULL); 00422 } 00423 ns_list_foreach_safe(cmd_variable_t, cur_ptr, &cmd.variable_list) { 00424 if (cur_ptr->type == VALUE_TYPE_STR) { 00425 cmd_variable_add(cur_ptr->value.ptr, NULL); 00426 } 00427 } 00428 ns_list_foreach_safe(cmd_history_t, cur_ptr, &cmd.history_list) { 00429 MEM_FREE(cur_ptr->command_ptr); 00430 ns_list_remove(&cmd.history_list, cur_ptr); 00431 MEM_FREE(cur_ptr); 00432 } 00433 cmd.mutex_wait_fnc = NULL; 00434 cmd.mutex_release_fnc = NULL; 00435 } 00436 00437 void cmd_input_passthrough_func(input_passthrough_func_t passthrough_fnc) 00438 { 00439 cmd.passthrough_fnc = passthrough_fnc; 00440 } 00441 00442 void cmd_exe(char *str) 00443 { 00444 cmd_split(str); 00445 if (cmd.cmd_buffer_ptr == 0) { 00446 //execution buffer is empty 00447 cmd.idle = false; //not really, but fake it 00448 cmd_ready(CMDLINE_RETCODE_SUCCESS); 00449 } else { 00450 tr_debug("previous cmd is still in progress"); 00451 } 00452 } 00453 void cmd_set_ready_cb(cmd_ready_cb_f *cb) 00454 { 00455 cmd.ready_cb = cb; 00456 } 00457 void cmd_ready(int retcode) 00458 { 00459 if (cmd.cmd_ptr && cmd.cmd_ptr->busy) { 00460 //execution finished 00461 cmd.cmd_ptr->busy = false; 00462 } 00463 if (!cmd.idle) { 00464 if (cmd.cmd_buffer_ptr == NULL) { 00465 tr_debug("goto next command"); 00466 } else { 00467 tr_debug("cmd '%s' executed with retcode: %i", cmd.cmd_buffer_ptr->cmd_s, retcode); 00468 } 00469 if (cmd.ready_cb == NULL) { 00470 tr_warn("Missing ready_cb! use cmd_set_ready_cb()"); 00471 } else { 00472 cmd.ready_cb(retcode); 00473 } 00474 } else { 00475 tr_warn("Someone call cmd_ready(%i) even there shouldn't be any running cmd", retcode); 00476 if (cmd.echo) { 00477 cmd_output(); //refresh if this happens 00478 } 00479 } 00480 } 00481 void cmd_next(int retcode) 00482 { 00483 cmd.idle = true; 00484 //figure out next command 00485 cmd.cmd_buffer_ptr = cmd_next_ptr(retcode); 00486 if (cmd.cmd_buffer_ptr) { 00487 cmd.idle = false; 00488 //yep there was some -> lets execute it 00489 retcode = cmd_run(cmd.cmd_buffer_ptr->cmd_s); 00490 //check if execution goes to the backend or not 00491 if (retcode == CMDLINE_RETCODE_EXCUTING_CONTINUE) { 00492 if ((NULL != cmd.cmd_buffer_ptr) && cmd.cmd_buffer_ptr->operator == OPERATOR_BACKGROUND) { 00493 //execution continue in background, but operator say that it's "ready" 00494 cmd_ready(CMDLINE_RETCODE_SUCCESS); 00495 } else { 00496 //command execution phase continuous in background 00497 tr_debug("Command execution continuous in background.."); 00498 } 00499 } else { 00500 //execution finished -> call ready function with retcode 00501 cmd_ready(retcode); 00502 } 00503 } else { 00504 const char *retfmt = cmd_get_retfmt(); 00505 if (retfmt) { 00506 cmd_printf(retfmt, retcode); 00507 } 00508 cmd_line_clear(0); 00509 if (cmd.echo) { 00510 cmd_output(); //ready 00511 } 00512 } 00513 } 00514 static cmd_exe_t *cmd_pop(void) 00515 { 00516 cmd_exe_t *cmd_ptr = ns_list_get_first(&cmd.cmd_buffer), 00517 *next_cmd = ns_list_get_next(&cmd.cmd_buffer, cmd_ptr); 00518 00519 if (cmd.cmd_buffer_ptr == 0) { 00520 //was first in bool 00521 next_cmd = ns_list_get_first(&cmd.cmd_buffer); 00522 } else { 00523 MEM_FREE(cmd_ptr->cmd_s); 00524 ns_list_remove(&cmd.cmd_buffer, cmd_ptr); 00525 MEM_FREE(cmd_ptr); 00526 } 00527 return next_cmd; 00528 } 00529 00530 static cmd_exe_t *cmd_next_ptr(int retcode) 00531 { 00532 cmd_exe_t *next_cmd = cmd.cmd_buffer_ptr; 00533 if (ns_list_is_empty(&cmd.cmd_buffer)) { 00534 return NULL; 00535 } 00536 if (cmd.cmd_buffer_ptr == NULL) { 00537 return cmd_pop(); 00538 } 00539 switch (cmd.cmd_buffer_ptr->operator) { 00540 case (OPERATOR_AND): 00541 if (retcode != CMDLINE_RETCODE_SUCCESS) { 00542 //if fails, go to next command, which not have AND operator 00543 while ((next_cmd->operator == OPERATOR_AND) && ((next_cmd = cmd_pop()) != 0)); 00544 } else { 00545 next_cmd = cmd_pop(); 00546 } 00547 break; 00548 case (OPERATOR_OR): 00549 if (retcode == CMDLINE_RETCODE_SUCCESS) { 00550 //if fails, go to next command, which not have OR operator 00551 while ((next_cmd->operator == OPERATOR_OR) && ((next_cmd = cmd_pop()) != 0)); 00552 } else { 00553 next_cmd = cmd_pop(); 00554 } 00555 break; 00556 case (OPERATOR_BACKGROUND): 00557 next_cmd = cmd_pop(); 00558 break; 00559 case (OPERATOR_PIPE): 00560 cmd_printf("pipe is not supported\r\n"); 00561 while ((next_cmd = cmd_pop()) != 0); 00562 break; 00563 case (OPERATOR_SEMI_COLON): 00564 default: 00565 //get next command to be execute (might be null if there is no more) 00566 next_cmd = cmd_pop(); 00567 break; 00568 } 00569 00570 //return next command if any 00571 return next_cmd; 00572 } 00573 static void cmd_split(char *string_ptr) 00574 { 00575 char *ptr = string_ptr, *next; 00576 operator_t oper = OPERATOR_SEMI_COLON; 00577 do { 00578 next = next_command(ptr, &oper); 00579 cmd_push(ptr, oper); 00580 ptr = next; 00581 if (next && !*next) { 00582 break; 00583 } 00584 } while (ptr != 0); 00585 } 00586 00587 static void cmd_push(char *cmd_str, operator_t oper) 00588 { 00589 //store this command to the stack 00590 cmd_exe_t *cmd_ptr = MEM_ALLOC(sizeof(cmd_exe_t)); 00591 if (cmd_ptr == NULL) { 00592 tr_error("mem alloc failed in cmd_push"); 00593 return; 00594 } 00595 cmd_ptr->cmd_s = MEM_ALLOC(strlen(cmd_str) + 1); 00596 if (cmd_ptr->cmd_s == NULL) { 00597 MEM_FREE(cmd_ptr); 00598 tr_error("mem alloc failed in cmd_push cmd_s"); 00599 return; 00600 } 00601 strcpy(cmd_ptr->cmd_s, cmd_str); 00602 cmd_ptr->operator = oper; 00603 ns_list_add_to_end(&cmd.cmd_buffer, cmd_ptr); 00604 } 00605 void cmd_out_func(cmd_print_t *outf) 00606 { 00607 cmd.out = outf; 00608 } 00609 void cmd_ctrl_func(void (*sohf)(uint8_t c)) 00610 { 00611 cmd.ctrl_fnc = sohf; 00612 } 00613 00614 void cmd_mutex_wait_func(void (*mutex_wait_f)(void)) 00615 { 00616 cmd.mutex_wait_fnc = mutex_wait_f; 00617 } 00618 void cmd_mutex_release_func(void (*mutex_release_f)(void)) 00619 { 00620 cmd.mutex_release_fnc = mutex_release_f; 00621 } 00622 00623 void cmd_mutex_lock() 00624 { 00625 if (cmd.mutex_wait_fnc) { 00626 cmd.mutex_wait_fnc(); 00627 } 00628 } 00629 00630 void cmd_mutex_unlock() 00631 { 00632 if (cmd.mutex_release_fnc) { 00633 cmd.mutex_release_fnc(); 00634 } 00635 } 00636 void cmd_init_screen() 00637 { 00638 if (cmd.vt100_on) { 00639 cmd_printf(CR_S CLEAR_ENTIRE_SCREEN); /* Clear screen */ 00640 cmd_printf(ENABLE_AUTO_WRAP_MODE); /* enable line wrap */ 00641 } 00642 cmd_printf(MBED_CMDLINE_BOOT_MESSAGE); 00643 cmd_output(); 00644 } 00645 uint8_t cmd_history_size(uint8_t max) 00646 { 00647 if (max > 0) { 00648 cmd.history_max_count = max; 00649 cmd_history_clean_overflow(); 00650 } 00651 return cmd.history_max_count; 00652 } 00653 static void cmd_echo(bool on) 00654 { 00655 cmd.echo = on; 00656 } 00657 bool cmd_echo_state(void) 00658 { 00659 return cmd.echo; 00660 } 00661 static cmd_command_t *cmd_find_n(char *name, int nameLength, int n) 00662 { 00663 cmd_command_t *cmd_ptr = NULL; 00664 if (name != NULL && nameLength != 0) { 00665 int i = 0; 00666 ns_list_foreach(cmd_command_t, cur_ptr, &cmd.command_list) { 00667 if (strncmp(name, cur_ptr->name_ptr, nameLength) == 0) { 00668 if (i == n) { 00669 cmd_ptr = cur_ptr; 00670 break; 00671 } 00672 i++; 00673 } 00674 } 00675 } 00676 return cmd_ptr; 00677 } 00678 static const char *cmd_input_lookup(char *name, int namelength, int n) 00679 { 00680 const char *str = NULL; 00681 cmd_command_t *cmd_ptr = cmd_find_n(name, namelength, n); 00682 if (cmd_ptr) { 00683 str = cmd_ptr->name_ptr; 00684 cmd.tab_lookup_n = n + 1; 00685 } else { 00686 n -= cmd.tab_lookup_n; 00687 cmd_alias_t *alias = alias_find_n(name, namelength, n); 00688 if (alias) { 00689 str = (const char *)alias->name_ptr; 00690 } 00691 } 00692 00693 return str; 00694 } 00695 static char *cmd_input_lookup_var(char *name, int namelength, int n) 00696 { 00697 char *str = NULL; 00698 cmd_variable_t *var = variable_find_n(name, namelength, n); 00699 if (var) { 00700 str = var->name_ptr; 00701 } 00702 return str; 00703 } 00704 static cmd_command_t *cmd_find(const char *name) 00705 { 00706 cmd_command_t *cmd_ptr = NULL; 00707 if (name == NULL || strlen(name) == 0) { 00708 tr_error("cmd_find invalid parameters"); 00709 return NULL; 00710 } 00711 00712 ns_list_foreach(cmd_command_t, cur_ptr, &cmd.command_list) { 00713 if (strcmp(name, cur_ptr->name_ptr) == 0) { 00714 cmd_ptr = cur_ptr; 00715 break; 00716 } 00717 } 00718 return cmd_ptr; 00719 } 00720 00721 void cmd_add(const char *name, cmd_run_cb *callback, const char *info, const char *man) 00722 { 00723 cmd_command_t *cmd_ptr; 00724 00725 if (name == NULL || callback == NULL || strlen(name) == 0) { 00726 tr_warn("cmd_add invalid parameters"); 00727 return; 00728 } 00729 cmd_ptr = (cmd_command_t *)MEM_ALLOC(sizeof(cmd_command_t)); 00730 if (cmd_ptr == NULL) { 00731 tr_error("mem alloc failed in cmd_add"); 00732 return; 00733 } 00734 cmd_ptr->name_ptr = name; 00735 cmd_ptr->info_ptr = info; 00736 #if MBED_CMDLINE_INCLUDE_MAN == 1 00737 cmd_ptr->man_ptr = man; 00738 #else 00739 cmd_ptr->man_ptr = 0; 00740 #endif 00741 cmd_ptr->run_cb = callback; 00742 cmd_ptr->busy = false; 00743 ns_list_add_to_end(&cmd.command_list, cmd_ptr); 00744 return; 00745 } 00746 00747 void cmd_delete(const char *name) 00748 { 00749 cmd_command_t *cmd_ptr; 00750 cmd_ptr = cmd_find(name); 00751 if (cmd_ptr == NULL) { 00752 return; 00753 } 00754 ns_list_remove(&cmd.command_list, cmd_ptr); 00755 MEM_FREE(cmd_ptr); 00756 return; 00757 } 00758 static void replace_escapes(char *string_ptr) 00759 { 00760 while ((string_ptr = strchr(string_ptr, '\\')) != NULL) { 00761 memmove(string_ptr, string_ptr + 1, strlen(string_ptr + 1) + 1); 00762 string_ptr++; 00763 } 00764 } 00765 static int cmd_parse_argv(char *string_ptr, char **argv) 00766 { 00767 tr_deep("cmd_parse_argv(%s, ..)\r\n", string_ptr); 00768 int argc = 0; 00769 char *str_ptr, *end_quote_ptr = NULL; 00770 00771 if (string_ptr == NULL || strlen(string_ptr) == 0) { 00772 tr_error("Invalid parameters"); 00773 return 0; 00774 } 00775 str_ptr = string_ptr; 00776 do { 00777 argv[argc] = str_ptr; 00778 // tr_deep("parsing.. argv[%d]: %s\r\n", argc, str_ptr); 00779 if (*str_ptr != '\\') { 00780 if (*str_ptr == '"') { 00781 // check if end quote 00782 end_quote_ptr = str_ptr; 00783 do { 00784 end_quote_ptr = strchr(end_quote_ptr + 1, '\"'); 00785 if (end_quote_ptr == NULL) { 00786 break; 00787 } 00788 } while (*(end_quote_ptr - 1) == '\\'); 00789 if (end_quote_ptr != NULL) { 00790 // remove quotes give as one parameter 00791 argv[argc]++; 00792 str_ptr = end_quote_ptr; 00793 } else { 00794 str_ptr = strchr(str_ptr, ' '); 00795 } 00796 } else { 00797 str_ptr = strchr(str_ptr, ' '); 00798 } 00799 } else { 00800 str_ptr = strchr(str_ptr, ' '); 00801 } 00802 argc++; // one argument parsed 00803 if (str_ptr == NULL) { 00804 break; 00805 } 00806 if (argc > MAX_ARGUMENTS) { 00807 tr_warn("Maximum arguments (%d) reached", MAX_ARGUMENTS); 00808 break; 00809 } 00810 *str_ptr++ = 0; 00811 replace_escapes(argv[argc - 1]); 00812 // tr_deep("parsed argv[%d]: %s\r\n", argc-1, argv[argc-1]); 00813 while (*str_ptr == ' ') { 00814 str_ptr++; // skip spaces 00815 }; 00816 } while (*str_ptr != 0); 00817 return argc; 00818 } 00819 static void cmd_print_man(cmd_command_t *command_ptr) 00820 { 00821 if (command_ptr->man_ptr) { 00822 cmd_printf("%s\r\n", command_ptr->man_ptr); 00823 } 00824 } 00825 static void cmd_set_input(const char *str, int cur) 00826 { 00827 cmd_line_clear(cur); 00828 strcpy(cmd.input + cur, str); 00829 cmd.cursor = strlen(cmd.input); 00830 } 00831 /** 00832 * If oper is not null, function set null pointers 00833 */ 00834 static char *next_command(char *string_ptr, operator_t *oper) 00835 { 00836 char *ptr = string_ptr; 00837 bool quote = false; 00838 while (*ptr != 0) { 00839 if (quote) { 00840 if (*ptr == '"') { 00841 quote = false; 00842 } 00843 } else { 00844 //skip if previous character is '\' 00845 if ((ptr == string_ptr) || (*(ptr - 1) != '\\')) { 00846 switch (*ptr) { 00847 case ('"'): { 00848 quote = true; 00849 break; 00850 } 00851 case (';'): //default operator 00852 if (oper) { 00853 *oper = OPERATOR_SEMI_COLON; 00854 *ptr = 0; 00855 } 00856 return ptr + 1; 00857 case ('&'): 00858 if (ptr[1] == '&') { 00859 if (oper) { 00860 *oper = OPERATOR_AND; 00861 *ptr = 0; 00862 } 00863 return ptr + 2; 00864 } else { 00865 if (oper) { 00866 *oper = OPERATOR_BACKGROUND; 00867 *ptr = 0; 00868 } 00869 return ptr + 1; 00870 } 00871 case ('|'): 00872 if (ptr[1] == '|') { 00873 if (oper) { 00874 *oper = OPERATOR_OR; 00875 *ptr = 0; 00876 } 00877 return ptr + 2; 00878 } else { 00879 tr_warn("pipe operator not supported"); 00880 if (oper) { 00881 *oper = OPERATOR_PIPE; 00882 *ptr = 0; 00883 } 00884 return ptr + 1; 00885 } 00886 default: 00887 break; 00888 } 00889 } 00890 } 00891 ptr++; 00892 } 00893 return 0; 00894 } 00895 static int cmd_run(char *string_ptr) 00896 { 00897 char *argv[MAX_ARGUMENTS]; 00898 int argc, ret; 00899 00900 tr_info("Executing cmd: '%s'", string_ptr); 00901 char *command_str = MEM_ALLOC(MAX_LINE); 00902 if (command_str == NULL) { 00903 tr_error("mem alloc failed in cmd_run"); 00904 return CMDLINE_RETCODE_FAIL; 00905 } 00906 while (isspace((unsigned char) *string_ptr) && 00907 *string_ptr != '\n' && 00908 *string_ptr != 0) { 00909 string_ptr++; //skip white spaces 00910 } 00911 strcpy(command_str, string_ptr); 00912 tr_deep("cmd_run('%s') ", command_str); 00913 cmd_replace_alias(command_str); 00914 cmd_replace_variables(command_str); 00915 tr_debug("Parsed cmd: '%s'", command_str); 00916 00917 argc = cmd_parse_argv(command_str, argv); 00918 00919 cmd.cmd_ptr = cmd_find(argv[0]); 00920 00921 if (cmd.cmd_ptr == NULL) { 00922 cmd_printf("Command '%s' not found.\r\n", argv[0]); 00923 MEM_FREE(command_str); 00924 return CMDLINE_RETCODE_COMMAND_NOT_FOUND; 00925 } 00926 if (cmd.cmd_ptr->run_cb == NULL) { 00927 tr_error("Command callback missing"); 00928 MEM_FREE(command_str); 00929 return CMDLINE_RETCODE_COMMAND_CB_MISSING; 00930 } 00931 00932 if (argc == 2 && 00933 (cmd_has_option(argc, argv, "h") || cmd_parameter_index(argc, argv, "--help") > 0)) { 00934 MEM_FREE(command_str); 00935 cmd_print_man(cmd.cmd_ptr); 00936 return CMDLINE_RETCODE_SUCCESS; 00937 } 00938 00939 if (cmd.cmd_ptr->busy) { 00940 MEM_FREE(command_str); 00941 return CMDLINE_RETCODE_COMMAND_BUSY; 00942 } 00943 00944 // Run the actual callback 00945 cmd.cmd_ptr->busy = true; 00946 ret = cmd.cmd_ptr->run_cb(argc, argv); 00947 cmd_variable_add_int("?", ret); 00948 cmd_alias_add("_", string_ptr); // last executed command 00949 MEM_FREE(command_str); 00950 switch (ret) { 00951 case (CMDLINE_RETCODE_COMMAND_NOT_IMPLEMENTED): 00952 tr_warn("Command not implemented"); 00953 break; 00954 case (CMDLINE_RETCODE_INVALID_PARAMETERS): 00955 tr_warn("Command parameter was incorrect"); 00956 cmd_printf("Invalid parameters!\r\n"); 00957 cmd_print_man(cmd.cmd_ptr); 00958 break; 00959 default: 00960 break; 00961 } 00962 return ret; 00963 } 00964 void cmd_escape_start(void) 00965 { 00966 cmd.escaping = true; 00967 memset(cmd.escape, 0, sizeof(cmd.escape)); 00968 cmd.escape_index = 0; 00969 } 00970 static void cmd_arrow_right() 00971 { 00972 /* @todo handle shift 00973 if(strncmp(cmd.escape+1, "1;2", 3) == 0) { 00974 tr_debug("Shift pressed"); 00975 shift = true; 00976 } 00977 */ 00978 if ((cmd.escape_index == 1 && cmd.escape[0] == 'O') || 00979 (cmd.escape_index == 4 && strncmp(cmd.escape + 1, "1;5", 3) == 0)) { 00980 cmd_move_cursor_to_next_space(); 00981 } else { 00982 cmd.cursor ++; 00983 } 00984 if ((int)cmd.cursor > (int)strlen(cmd.input)) { 00985 cmd.cursor = strlen(cmd.input); 00986 } 00987 } 00988 static void cmd_arrow_left() 00989 { 00990 /* @todo handle shift 00991 if(strncmp(cmd.escape+1, "1;2", 3) == 0) { 00992 tr_debug("Shift pressed"); 00993 shift = true; 00994 } 00995 */ 00996 if ((cmd.escape_index == 1 && cmd.escape[0] == 'O') || 00997 (cmd.escape_index == 4 && strncmp(cmd.escape + 1, "1;5", 3) == 0)) { 00998 cmd_move_cursor_to_last_space(); 00999 } else { 01000 cmd.cursor --; 01001 } 01002 if (cmd.cursor < 0) { 01003 cmd.cursor = 0; 01004 } 01005 } 01006 static void cmd_arrow_up() 01007 { 01008 int16_t old_entry = cmd.history++; 01009 if (NULL == cmd_history_find(cmd.history)) { 01010 cmd.history = old_entry; 01011 } 01012 if (old_entry != cmd.history) { 01013 cmd_history_save(old_entry); 01014 cmd_history_get(cmd.history); 01015 } 01016 } 01017 static void cmd_arrow_down(void) 01018 { 01019 int16_t old_entry = cmd.history--; 01020 if (cmd.history < 0) { 01021 cmd.history = 0; 01022 } 01023 01024 if (old_entry != cmd.history) { 01025 cmd_history_save(old_entry); 01026 cmd_history_get(cmd.history); 01027 } 01028 } 01029 void cmd_escape_read(int16_t u_data) 01030 { 01031 tr_debug("cmd_escape_read: %02x '%c' escape_index: %d: %s", 01032 u_data, 01033 (isprint(u_data) ? u_data : '?'), 01034 cmd.escape_index, 01035 cmd.escape); 01036 01037 if (u_data == 'D') { 01038 cmd_arrow_left(); 01039 } else if (u_data == 'C') { 01040 cmd_arrow_right(); 01041 } else if (u_data == 'A') { 01042 cmd_arrow_up(); 01043 } else if (u_data == 'B') { 01044 cmd_arrow_down(); 01045 } else if (u_data == 'Z') { 01046 // Shift+TAB 01047 if (cmd.tab_lookup > 0) { 01048 cmd.cursor = cmd.tab_lookup; 01049 cmd.input[cmd.tab_lookup] = 0; 01050 if (cmd.tab_lookup_cmd_n > 0) { 01051 cmd.tab_lookup_cmd_n--; 01052 } 01053 } 01054 cmd_tab_lookup(); 01055 } else if (u_data == 'b') { 01056 cmd_move_cursor_to_last_space(); 01057 } else if (u_data == 'f') { 01058 cmd_move_cursor_to_next_space(); 01059 } else if (u_data == 'n') { 01060 if (cmd.escape[1] == '5') { 01061 // Device status report 01062 // Response: terminal is OK 01063 cmd_printf("%c0n", ESC); 01064 } else if (cmd.escape[1] == '6') { 01065 // Get cursor position 01066 cmd_printf(ESCAPE("%d%d"), 0, cmd.cursor); 01067 } 01068 } else if (u_data == 'R') { 01069 // response for Get cursor position (<esc>[6n) 01070 // <esc>[<lines>;<cols>R 01071 char *ptr; 01072 int lines = strtol(cmd.escape + 1, &ptr, 10); 01073 if (ptr == NULL) { 01074 tr_warn("Invalid response: <esc>%s%c", cmd.escape, u_data); 01075 } else { 01076 int cols = strtol(ptr + 1, 0, 10); 01077 tr_debug("Lines: %d, cols: %d", lines, cols); 01078 cmd_variable_add_int("LINES", lines); 01079 cmd_variable_add_int("COLUMNS", cols); 01080 } 01081 } else if (u_data == 'H') { 01082 // Xterm support 01083 cmd.cursor = 0; 01084 } else if (u_data == 'F') { 01085 // Xterm support 01086 cmd.cursor = strlen(cmd.input); 01087 } else if (isdigit((int)cmd.escape[cmd.escape_index - 1]) && u_data == '~') { 01088 switch (cmd.escape[cmd.escape_index - 1]) { 01089 case ('1'): //beginning-of-line # Home key 01090 cmd.cursor = 0; 01091 break; 01092 case ('2'): //quoted-insert # Insert key 01093 cmd.insert = !cmd.insert; 01094 break; 01095 case ('3'): //delete-char # Delete key 01096 if ((int)strlen(cmd.input) > (int)cmd.cursor) { 01097 memmove(&cmd.input[cmd.cursor], &cmd.input[cmd.cursor + 1], strlen(&cmd.input[cmd.cursor + 1]) + 1); 01098 } 01099 break; 01100 case ('4'): //end-of-line # End key 01101 cmd.cursor = strlen(cmd.input); 01102 break; 01103 case ('5'): //beginning-of-history # PageUp key 01104 goto_end_of_history(); 01105 break; 01106 case ('6'): //end-of-history # PageDown key 01107 goto_beginning_of_history(); 01108 break; 01109 default: 01110 break; 01111 } 01112 } else if (isprint(u_data)) { //IS_NUMBER || IS_CONTROL 01113 cmd.escape[cmd.escape_index++] = u_data; 01114 return; 01115 } 01116 cmd_output(); 01117 cmd.escaping = false; 01118 return; 01119 } 01120 static void goto_end_of_history(void) 01121 { 01122 // handle new input if any and verify that 01123 // it is not already in beginning of history or current position 01124 bool allowStore = strlen(cmd.input) != 0; //avoid store empty lines to history 01125 cmd_history_t *entry_ptr; 01126 if (cmd.history > 0 && allowStore) { 01127 entry_ptr = cmd_history_find(cmd.history); 01128 if (entry_ptr) { 01129 if (strcmp(entry_ptr->command_ptr, cmd.input) == 0) { 01130 // current history contains contains same text as input 01131 allowStore = false; 01132 } 01133 } 01134 } else if (allowStore && (entry_ptr = cmd_history_find(0)) != NULL) { 01135 if (strcmp(entry_ptr->command_ptr, cmd.input) == 0) { 01136 //beginning of history was same text as input 01137 allowStore = false; 01138 } 01139 } 01140 if (allowStore) { 01141 cmd_history_save(0); // new is saved to place 0 01142 cmd_history_save(-1); // new is created to the current one 01143 } 01144 01145 cmd_history_t *cmd_ptr = ns_list_get_last(&cmd.history_list); 01146 cmd_set_input(cmd_ptr->command_ptr, 0); 01147 cmd.history = ns_list_count(&cmd.history_list) - 1; 01148 } 01149 static void goto_beginning_of_history(void) 01150 { 01151 cmd_history_t *cmd_ptr = ns_list_get_first(&cmd.history_list); 01152 cmd_set_input(cmd_ptr->command_ptr, 0); 01153 cmd.history = 0; 01154 } 01155 static void cmd_reset_tab(void) 01156 { 01157 cmd.tab_lookup = 0; 01158 cmd.tab_lookup_cmd_n = 0; 01159 cmd.tab_lookup_n = 0; 01160 } 01161 void cmd_char_input(int16_t u_data) 01162 { 01163 if (cmd.prev_cr && u_data == '\n') { 01164 // ignore \n if previous character was \r -> 01165 // that triggers execute so \n does not need to anymore 01166 cmd.prev_cr = false; // unset to ensure we doesn't go here anymore 01167 return; 01168 } 01169 /*Handle passthrough*/ 01170 if (cmd.passthrough_fnc != NULL) { 01171 cmd.passthrough_fnc(u_data); 01172 return; 01173 } 01174 /*handle ecape command*/ 01175 if (cmd.escaping == true) { 01176 cmd_escape_read(u_data); 01177 return; 01178 } 01179 01180 tr_debug("input char: %02x '%c', cursor: %i, input: \"%s\"", u_data, (isprint(u_data) ? u_data : ' '), cmd.cursor, cmd.input); 01181 01182 /*Normal character input*/ 01183 if (u_data == '\r' || u_data == '\n') { 01184 cmd.prev_cr = u_data == '\r'; 01185 cmd_reset_tab(); 01186 if (strlen(cmd.input) == 0) { 01187 if (cmd.echo) { 01188 cmd_printf("\r\n"); 01189 cmd_output(); 01190 } 01191 } else { 01192 if (cmd.echo) { 01193 cmd_printf("\r\n"); 01194 } 01195 cmd_execute(); 01196 } 01197 } else if (u_data == ESC) { 01198 cmd_escape_start(); 01199 } else if (u_data == BS || u_data == DEL) { 01200 cmd_reset_tab(); 01201 cmd.cursor--; 01202 if (cmd.cursor < 0) { 01203 cmd.cursor = 0; 01204 return; 01205 } 01206 memmove(&cmd.input[cmd.cursor], &cmd.input[cmd.cursor + 1], strlen(&cmd.input[cmd.cursor + 1]) + 1); 01207 if (cmd.echo) { 01208 cmd_output(); 01209 } 01210 } else if (u_data == ETX || u_data == CAN) { 01211 //ctrl+c (End of text) or ctrl+x (cancel) 01212 cmd_reset_tab(); 01213 cmd_line_clear(0); 01214 if (!cmd.idle) { 01215 cmd_ready(CMDLINE_RETCODE_FAIL); 01216 } 01217 if (cmd.echo) { 01218 cmd_output(); 01219 } 01220 } else if (u_data == ETB) { 01221 //ctrl+w (End of xmit block) 01222 tr_debug("ctrl+w - remove last word to cursor"); 01223 cmd_clear_last_word(); 01224 if (cmd.echo) { 01225 cmd_output(); 01226 } 01227 } else if (u_data == TAB) { 01228 bool inc = false; 01229 if (cmd.tab_lookup > 0) { 01230 cmd.cursor = cmd.tab_lookup; 01231 cmd.input[cmd.tab_lookup] = 0; 01232 cmd.tab_lookup_cmd_n++; 01233 inc = true; 01234 } else { 01235 cmd.tab_lookup = strlen(cmd.input); 01236 } 01237 01238 if (!cmd_tab_lookup()) { 01239 if (inc) { 01240 cmd.tab_lookup_cmd_n--; 01241 } 01242 memset(cmd.input + cmd.tab_lookup, 0, MAX_LINE - cmd.tab_lookup); 01243 } 01244 if (cmd.echo) { 01245 cmd_output(); 01246 } 01247 01248 } else if (iscntrl(u_data)) { 01249 if (cmd.ctrl_fnc) { 01250 cmd.ctrl_fnc(u_data); 01251 } 01252 } else { 01253 cmd_reset_tab(); 01254 tr_deep("cursor: %d, inputlen: %lu, u_data: %c\r\n", cmd.cursor, strlen(cmd.input), u_data); 01255 if ((strlen(cmd.input) >= MAX_LINE - 1) || (cmd.cursor >= MAX_LINE - 1)) { 01256 tr_warn("input buffer full"); 01257 if (cmd.echo) { 01258 cmd_output(); 01259 } 01260 return; 01261 } 01262 if (cmd.insert) { 01263 memmove(&cmd.input[cmd.cursor + 1], &cmd.input[cmd.cursor], strlen(&cmd.input[cmd.cursor]) + 1); 01264 } 01265 cmd.input[cmd.cursor++] = u_data; 01266 if (cmd.echo) { 01267 cmd_output(); 01268 } 01269 } 01270 } 01271 static int check_variable_keylookup_size(char **key, int *keysize) 01272 { 01273 if (cmd.cursor > 0 && cmd.tab_lookup > 0) { 01274 //printf("tab_lookup: %i\r\n", cmd.tab_lookup); 01275 char *ptr = cmd.input + cmd.tab_lookup; 01276 do { 01277 //printf("varkey lookup: %c\r\n", *ptr); 01278 if (*ptr == ' ') { 01279 return 0; 01280 } 01281 if (*ptr == '$') { 01282 int varlen = cmd.tab_lookup - (ptr - cmd.input) - 1; 01283 *key = ptr; 01284 *keysize = varlen; 01285 //printf("varkey size: %i\r\n", varlen); 01286 return (ptr - cmd.input); 01287 } 01288 ptr--; 01289 } while (ptr > cmd.input); 01290 } 01291 return 0; 01292 } 01293 bool cmd_tab_lookup(void) 01294 { 01295 int len = strlen(cmd.input); 01296 if (len == 0) { 01297 return false; 01298 } 01299 char *variable_keypart; 01300 int lookupSize; 01301 int varpos = check_variable_keylookup_size(&variable_keypart, &lookupSize); 01302 01303 const char *str = NULL; 01304 if (varpos) { 01305 str = cmd_input_lookup_var(variable_keypart + 1, lookupSize, cmd.tab_lookup_cmd_n); 01306 if (str) { 01307 cmd_set_input(str, varpos + 1); 01308 return true; 01309 } 01310 } else { 01311 str = cmd_input_lookup(cmd.input, len, cmd.tab_lookup_cmd_n); 01312 if (str != NULL) { 01313 cmd_set_input(str, 0); 01314 return true; 01315 } 01316 } 01317 return false; 01318 } 01319 static void cmd_move_cursor_to_last_space(void) 01320 { 01321 if (cmd.cursor) { 01322 cmd.cursor--; 01323 } else { 01324 return; 01325 } 01326 const char *last_space = find_last_space(cmd.input + cmd.cursor, cmd.input); 01327 if (last_space) { 01328 cmd.cursor = last_space - cmd.input; 01329 } else { 01330 cmd.cursor = 0; 01331 } 01332 } 01333 static void cmd_move_cursor_to_next_space(void) 01334 { 01335 while (cmd.input[cmd.cursor] == ' ') { 01336 cmd.cursor++; 01337 } 01338 const char *next_space = strchr(cmd.input + cmd.cursor, ' '); 01339 if (next_space) { 01340 cmd.cursor = next_space - cmd.input; 01341 } else { 01342 cmd.cursor = (int)strlen(cmd.input); 01343 } 01344 } 01345 static void cmd_clear_last_word() 01346 { 01347 if (!cmd.cursor) { 01348 return; 01349 } 01350 char *ptr = cmd.input + cmd.cursor - 1; 01351 while (*ptr == ' ' && ptr >= cmd.input) { 01352 ptr--; 01353 } 01354 const char *last_space = find_last_space(ptr, cmd.input); 01355 if (last_space) { 01356 memmove((void *)last_space, &cmd.input[cmd.cursor], strlen(cmd.input + cmd.cursor) + 1); 01357 cmd.cursor = last_space - cmd.input; 01358 } else { 01359 memmove((void *)cmd.input, &cmd.input[cmd.cursor], strlen(cmd.input + cmd.cursor) + 1); 01360 cmd.cursor = 0; 01361 } 01362 } 01363 void cmd_output(void) 01364 { 01365 if (cmd.vt100_on && cmd.idle) { 01366 int curpos = (int)strlen(cmd.input) - cmd.cursor + 1; 01367 cmd_printf(CR_S CLEAR_ENTIRE_LINE "%s%s " MOVE_CURSOR_LEFT_N_CHAR, 01368 cmdline_get_prompt(), cmd.input, curpos); 01369 } 01370 } 01371 void cmd_echo_off(void) 01372 { 01373 cmd_echo(false); 01374 } 01375 void cmd_echo_on(void) 01376 { 01377 cmd_echo(true); 01378 } 01379 // alias 01380 int replace_alias(char *str, const char *old_str, const char *new_str) 01381 { 01382 int old_len = strlen(old_str), 01383 new_len = strlen(new_str); 01384 if ((strncmp(str, old_str, old_len) == 0) && 01385 ((str[ old_len ] == ' ') || (str[ old_len ] == 0) || 01386 (str[ old_len ] == ';') || (str[ old_len ] == '&'))) { 01387 memmove(str + new_len, str + old_len, strlen(str + old_len) + 1); 01388 memcpy(str, new_str, new_len); 01389 return new_len - old_len; 01390 } 01391 return 0; 01392 } 01393 static void cmd_replace_alias(char *input) 01394 { 01395 ns_list_foreach(cmd_alias_t, cur_ptr, &cmd.alias_list) { 01396 replace_alias(input, cur_ptr->name_ptr, cur_ptr->value_ptr); 01397 } 01398 } 01399 //variable 01400 static void replace_variable(char *str, cmd_variable_t *variable_ptr) 01401 { 01402 const char *name = variable_ptr->name_ptr; 01403 int name_len = strlen(variable_ptr->name_ptr); 01404 char *value; 01405 char valueLocal[11]; 01406 if (variable_ptr->type == VALUE_TYPE_STR) { 01407 value = variable_ptr->value.ptr; 01408 } else { 01409 value = valueLocal; 01410 snprintf(value, 11, "%d", variable_ptr->value.i); 01411 } 01412 char *tmp = MEM_ALLOC(name_len + 2); 01413 if (tmp == NULL) { 01414 tr_error("mem alloc failed in replace_variable"); 01415 return; 01416 } 01417 tmp[0] = '$'; 01418 strcpy(tmp + 1, name); 01419 replace_string(str, MAX_LINE, tmp, value); 01420 MEM_FREE(tmp); 01421 } 01422 static void cmd_replace_variables(char *input) 01423 { 01424 ns_list_foreach(cmd_variable_t, cur_ptr, &cmd.variable_list) { 01425 replace_variable(input, cur_ptr); 01426 } 01427 } 01428 //history 01429 static void cmd_history_item_delete(cmd_history_t *entry_ptr) 01430 { 01431 ns_list_remove(&cmd.history_list, entry_ptr); 01432 MEM_FREE(entry_ptr->command_ptr); 01433 MEM_FREE(entry_ptr); 01434 } 01435 01436 static cmd_history_t *cmd_history_find(int16_t index) 01437 { 01438 cmd_history_t *entry_ptr = NULL; 01439 int16_t count = 0; 01440 ns_list_foreach(cmd_history_t, cur_ptr, &cmd.history_list) { 01441 if (count == index) { 01442 entry_ptr = cur_ptr; 01443 break; 01444 } 01445 count++; 01446 } 01447 return entry_ptr; 01448 } 01449 01450 static void cmd_history_clean_overflow(void) 01451 { 01452 while (ns_list_count(&cmd.history_list) > cmd.history_max_count) { 01453 cmd_history_t *cmd_ptr = ns_list_get_last(&cmd.history_list); 01454 tr_debug("removing older history (%s)", cmd_ptr->command_ptr); 01455 cmd_history_item_delete(cmd_ptr); 01456 } 01457 } 01458 static void cmd_history_clean(void) 01459 { 01460 while (ns_list_count(&cmd.history_list) > 0) { 01461 tr_debug("removing older history"); 01462 cmd_history_item_delete(ns_list_get_last(&cmd.history_list)); 01463 } 01464 } 01465 static void cmd_history_save(int16_t index) 01466 { 01467 /*if entry true save it to first item which is the one currently edited*/ 01468 cmd_history_t *entry_ptr; 01469 int16_t len; 01470 01471 len = strlen(cmd.input); 01472 01473 tr_debug("saving history item %d", index); 01474 entry_ptr = cmd_history_find(index); 01475 01476 if (entry_ptr == NULL) { 01477 /*new entry*/ 01478 entry_ptr = (cmd_history_t *)MEM_ALLOC(sizeof(cmd_history_t)); 01479 if (entry_ptr == NULL) { 01480 tr_error("mem alloc failed in cmd_history_save"); 01481 return; 01482 } 01483 entry_ptr->command_ptr = NULL; 01484 ns_list_add_to_start(&cmd.history_list, entry_ptr); 01485 } 01486 01487 if (entry_ptr->command_ptr != NULL) { 01488 MEM_FREE(entry_ptr->command_ptr); 01489 } 01490 entry_ptr->command_ptr = (char *)MEM_ALLOC(len + 1); 01491 if (entry_ptr->command_ptr == NULL) { 01492 tr_error("mem alloc failed in cmd_history_save command_ptr"); 01493 cmd_history_item_delete(entry_ptr); 01494 return; 01495 } 01496 strcpy(entry_ptr->command_ptr, cmd.input); 01497 01498 cmd_history_clean_overflow(); 01499 } 01500 static void cmd_history_get(uint16_t index) 01501 { 01502 cmd_history_t *entry_ptr; 01503 01504 tr_debug("getting history item %d", index); 01505 01506 entry_ptr = cmd_history_find(index); 01507 01508 if (entry_ptr != NULL) { 01509 memset(cmd.input, 0, MAX_LINE); 01510 cmd_set_input(entry_ptr->command_ptr, 0); 01511 } 01512 } 01513 01514 static void cmd_line_clear(int from) 01515 { 01516 memset(cmd.input + from, 0, MAX_LINE - from); 01517 cmd.cursor = from; 01518 } 01519 01520 static void cmd_execute(void) 01521 { 01522 if (strlen(cmd.input) != 0) { 01523 bool noduplicates = true; 01524 cmd_history_t *entry_ptr = cmd_history_find(0); 01525 if (entry_ptr) { 01526 if (strcmp(entry_ptr->command_ptr, cmd.input) == 0) { 01527 noduplicates = false; 01528 } 01529 } 01530 if (noduplicates) { 01531 cmd_history_save(0); // new is saved to place 0 01532 cmd_history_save(-1); // new is created to the current one 01533 } 01534 } 01535 cmd.history = 0; 01536 01537 tr_deep("cmd_execute('%s') ", cmd.input); 01538 cmd_exe(cmd.input); 01539 cmd_line_clear(0); 01540 } 01541 01542 01543 static cmd_alias_t *alias_find(const char *alias) 01544 { 01545 cmd_alias_t *alias_ptr = NULL; 01546 if (alias == NULL || strlen(alias) == 0) { 01547 tr_error("alias_find invalid parameters"); 01548 return NULL; 01549 } 01550 01551 ns_list_foreach(cmd_alias_t, cur_ptr, &cmd.alias_list) { 01552 if (strcmp(alias, cur_ptr->name_ptr) == 0) { 01553 alias_ptr = cur_ptr; 01554 break; 01555 } 01556 } 01557 return alias_ptr; 01558 } 01559 01560 static cmd_alias_t *alias_find_n(char *alias, int aliaslength, int n) 01561 { 01562 cmd_alias_t *alias_ptr = NULL; 01563 int i = 0; 01564 if (alias == NULL || strlen(alias) == 0) { 01565 tr_error("alias_find invalid parameters"); 01566 return NULL; 01567 } 01568 01569 ns_list_foreach(cmd_alias_t, cur_ptr, &cmd.alias_list) { 01570 if (strncmp(alias, cur_ptr->name_ptr, aliaslength) == 0) { 01571 if (i == n) { 01572 alias_ptr = cur_ptr; 01573 break; 01574 } 01575 i++; 01576 } 01577 } 01578 return alias_ptr; 01579 } 01580 static cmd_variable_t *variable_find(char *variable) 01581 { 01582 cmd_variable_t *variable_ptr = NULL; 01583 if (variable == NULL || strlen(variable) == 0) { 01584 tr_error("variable_find invalid parameters"); 01585 return NULL; 01586 } 01587 01588 ns_list_foreach(cmd_variable_t, cur_ptr, &cmd.variable_list) { 01589 if (strcmp(variable, cur_ptr->name_ptr) == 0) { 01590 variable_ptr = cur_ptr; 01591 break; 01592 } 01593 } 01594 return variable_ptr; 01595 } 01596 static cmd_variable_t *variable_find_n(char *variable, int length, int n) 01597 { 01598 cmd_variable_t *variable_ptr = NULL; 01599 if (variable == NULL || strlen(variable) == 0) { 01600 tr_error("variable_find invalid parameters"); 01601 return NULL; 01602 } 01603 int i = 0; 01604 ns_list_foreach(cmd_variable_t, cur_ptr, &cmd.variable_list) { 01605 if (strncmp(variable, cur_ptr->name_ptr, length) == 0) { 01606 if (i == n) { 01607 variable_ptr = cur_ptr; 01608 break; 01609 } 01610 i++; 01611 } 01612 } 01613 return variable_ptr; 01614 } 01615 static void cmd_alias_print_all(void) 01616 { 01617 ns_list_foreach(cmd_alias_t, cur_ptr, &cmd.alias_list) { 01618 if (cur_ptr->name_ptr != NULL) { 01619 cmd_printf("%-18s'%s'\r\n", cur_ptr->name_ptr, cur_ptr->value_ptr ? cur_ptr->value_ptr : ""); 01620 } 01621 } 01622 return; 01623 } 01624 static void cmd_variable_print_all(void) 01625 { 01626 ns_list_foreach(cmd_variable_t, cur_ptr, &cmd.variable_list) { 01627 if (cur_ptr->type == VALUE_TYPE_STR) { 01628 cmd_printf("%s='%s'\r\n", cur_ptr->name_ptr, cur_ptr->value.ptr ? cur_ptr->value.ptr : ""); 01629 } else if (cur_ptr->type == VALUE_TYPE_INT) { 01630 cmd_printf("%s=%d\r\n", cur_ptr->name_ptr, cur_ptr->value.i); 01631 } 01632 } 01633 return; 01634 } 01635 01636 void cmd_alias_add(const char *alias, const char *value) 01637 { 01638 cmd_alias_t *alias_ptr; 01639 if (alias == NULL || strlen(alias) == 0) { 01640 tr_warn("cmd_alias_add invalid parameters"); 01641 return; 01642 } 01643 alias_ptr = alias_find(alias); 01644 if (alias_ptr == NULL) { 01645 if (value == NULL) { 01646 return; // no need to add new null one 01647 } 01648 if (strlen(value) == 0) { 01649 return; // no need to add new empty one 01650 } 01651 alias_ptr = (cmd_alias_t *)MEM_ALLOC(sizeof(cmd_alias_t)); 01652 if (alias_ptr == NULL) { 01653 tr_error("Mem alloc fail in cmd_alias_add"); 01654 return; 01655 } 01656 alias_ptr->name_ptr = (char *)MEM_ALLOC(strlen(alias) + 1); 01657 if (alias_ptr->name_ptr == NULL) { 01658 MEM_FREE(alias_ptr); 01659 tr_error("Mem alloc fail in cmd_alias_add name_ptr"); 01660 return; 01661 } 01662 ns_list_add_to_end(&cmd.alias_list, alias_ptr); 01663 strcpy(alias_ptr->name_ptr, alias); 01664 alias_ptr->value_ptr = NULL; 01665 } 01666 if (value == NULL || strlen(value) == 0) { 01667 // delete this one 01668 ns_list_remove(&cmd.alias_list, alias_ptr); 01669 MEM_FREE(alias_ptr->name_ptr); 01670 MEM_FREE(alias_ptr->value_ptr); 01671 MEM_FREE(alias_ptr); 01672 } else { 01673 // add new or modify 01674 if (alias_ptr->value_ptr != NULL) { 01675 MEM_FREE(alias_ptr->value_ptr); 01676 } 01677 alias_ptr->value_ptr = (char *)MEM_ALLOC(strlen(value) + 1); 01678 if (alias_ptr->value_ptr == NULL) { 01679 cmd_alias_add(alias, NULL); 01680 tr_error("Mem alloc fail in cmd_alias_add value_ptr"); 01681 return; 01682 } 01683 strcpy(alias_ptr->value_ptr, value); 01684 } 01685 return; 01686 } 01687 static cmd_variable_t *cmd_variable_add_prepare(char *variable, char *value) 01688 { 01689 if (variable == NULL || strlen(variable) == 0) { 01690 tr_warn("cmd_variable_add invalid parameters"); 01691 return NULL; 01692 } 01693 cmd_variable_t *variable_ptr = variable_find(variable); 01694 if (variable_ptr == NULL) { 01695 if (value == NULL) { 01696 return NULL; // adding null variable 01697 } 01698 if (strlen(value) == 0) { 01699 return NULL; // no need to add new empty one 01700 } 01701 variable_ptr = (cmd_variable_t *)MEM_ALLOC(sizeof(cmd_variable_t)); 01702 if (variable_ptr == NULL) { 01703 tr_error("Mem alloc failed cmd_variable_add"); 01704 return NULL; 01705 } 01706 variable_ptr->name_ptr = (char *)MEM_ALLOC(strlen(variable) + 1); 01707 if (variable_ptr->name_ptr == NULL) { 01708 MEM_FREE(variable_ptr); 01709 tr_error("Mem alloc failed cmd_variable_add name_ptr"); 01710 return NULL; 01711 } 01712 01713 ns_list_add_to_end(&cmd.variable_list, variable_ptr); 01714 strcpy(variable_ptr->name_ptr, variable); 01715 variable_ptr->value.ptr = NULL; 01716 } 01717 if (value == NULL || strlen(value) == 0) { 01718 // delete this one 01719 tr_debug("Remove variable: %s", variable); 01720 ns_list_remove(&cmd.variable_list, variable_ptr); 01721 MEM_FREE(variable_ptr->name_ptr); 01722 if (variable_ptr->type == VALUE_TYPE_STR) { 01723 MEM_FREE(variable_ptr->value.ptr); 01724 } 01725 MEM_FREE(variable_ptr); 01726 return NULL; 01727 } 01728 return variable_ptr; 01729 } 01730 void cmd_variable_add_int(char *variable, int value) 01731 { 01732 cmd_variable_t *variable_ptr = cmd_variable_add_prepare(variable, " "); 01733 if (variable_ptr == NULL) { 01734 return; 01735 } 01736 if (variable_ptr->value.ptr != NULL && 01737 variable_ptr->type == VALUE_TYPE_STR) { 01738 // free memory 01739 MEM_FREE(variable_ptr->value.ptr); 01740 } 01741 variable_ptr->type = VALUE_TYPE_INT; 01742 variable_ptr->value.i = value; 01743 } 01744 void cmd_variable_add(char *variable, char *value) 01745 { 01746 cmd_variable_t *variable_ptr = cmd_variable_add_prepare(variable, value); 01747 if (variable_ptr == NULL) { 01748 return; 01749 } 01750 int value_len = strlen(value); 01751 replace_string(value, value_len, "\\n", "\n"); 01752 replace_string(value, value_len, "\\r", "\r"); 01753 01754 // add new or modify 01755 int new_len = strlen(value) + 1; 01756 int old_len = 0; 01757 if (variable_ptr->value.ptr != NULL && 01758 variable_ptr->type == VALUE_TYPE_STR) { 01759 // free memory if required 01760 old_len = strlen(variable_ptr->value.ptr) + 1; 01761 if (old_len != new_len) { 01762 MEM_FREE(variable_ptr->value.ptr); 01763 } 01764 } 01765 if (old_len != new_len) { 01766 variable_ptr->value.ptr = (char *)MEM_ALLOC(new_len); 01767 if (variable_ptr->value.ptr == NULL) { 01768 cmd_variable_add(variable, NULL); 01769 tr_error("Mem alloc failed cmd_variable_add value_ptr"); 01770 return; 01771 } 01772 } 01773 variable_ptr->type = VALUE_TYPE_STR; 01774 strcpy(variable_ptr->value.ptr, value); 01775 return; 01776 } 01777 01778 static bool is_cmdline_commands(char *command) 01779 { 01780 if ((strncmp(command, "alias", 5) == 0) || 01781 (strcmp(command, "echo") == 0) || 01782 (strcmp(command, "set") == 0) || 01783 (strcmp(command, "clear") == 0) || 01784 (strcmp(command, "help") == 0)) { 01785 return true; 01786 } 01787 return false; 01788 } 01789 /*Basic commands for cmd line 01790 * alias 01791 * echo 01792 * set 01793 * clear 01794 * help 01795 */ 01796 int alias_command(int argc, char *argv[]) 01797 { 01798 if (argc == 1) { 01799 // print all alias 01800 cmd_printf("alias:\r\n"); 01801 cmd_alias_print_all(); 01802 } else if (argc == 2) { 01803 // print alias 01804 if (is_cmdline_commands(argv[1])) { 01805 cmd_printf("Cannot overwrite default commands with alias\r\n"); 01806 return -1; 01807 } 01808 tr_debug("Deleting alias %s", argv[1]); 01809 cmd_alias_add(argv[1], NULL); 01810 } else { 01811 // set alias 01812 tr_debug("Setting alias %s = %s", argv[1], argv[2]); 01813 cmd_alias_add(argv[1], argv[2]); 01814 } 01815 return 0; 01816 } 01817 int unset_command(int argc, char *argv[]) 01818 { 01819 if (argc != 2) { 01820 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01821 } 01822 tr_debug("Deleting variable %s", argv[1]); 01823 cmd_variable_add(argv[1], NULL); 01824 return 0; 01825 } 01826 int set_command(int argc, char *argv[]) 01827 { 01828 if (argc == 1) { 01829 // print all alias 01830 cmd_printf("variables:\r\n"); 01831 cmd_variable_print_all(); 01832 } else if (argc == 2) { 01833 char *separator_ptr = strchr(argv[1], '='); 01834 if (!separator_ptr) { 01835 return CMDLINE_RETCODE_INVALID_PARAMETERS; 01836 } 01837 *separator_ptr = 0; 01838 cmd_variable_add(argv[1], separator_ptr + 1); 01839 } else { 01840 // set alias 01841 tr_debug("Setting variable %s = %s", argv[1], argv[2]); 01842 //handle special cases: vt100 on|off 01843 bool state; 01844 if (cmd_parameter_bool(argc, argv, "--vt100", &state)) { 01845 cmd.vt100_on = state; 01846 return 0; 01847 } 01848 if (cmd_parameter_bool(argc, argv, "--retcode", &state)) { 01849 cmd_variable_add(VAR_RETFMT, state ? DEFAULT_RETFMT : NULL); 01850 return 0; 01851 } 01852 char *str; 01853 if (cmd_parameter_val(argc, argv, "--retfmt", &str)) { 01854 cmd_variable_add(VAR_RETFMT, str); 01855 return 0; 01856 } 01857 cmd_variable_add(argv[1], argv[2]); 01858 } 01859 return 0; 01860 } 01861 int echo_command(int argc, char *argv[]) 01862 { 01863 bool printEcho = false; 01864 if (argc == 1) { 01865 printEcho = true; 01866 } else if (argc == 2) { 01867 if (strcmp(argv[1], "off") == 0) { 01868 cmd_echo(false); 01869 printEcho = true; 01870 } else if (strcmp(argv[1], "on") == 0) { 01871 cmd_echo(true); 01872 printEcho = true; 01873 } 01874 } 01875 if (printEcho) { 01876 cmd_printf("ECHO is %s\r\n", cmd.echo ? "on" : "off"); 01877 } else { 01878 for (int n = 1; n < argc; n++) { 01879 tr_deep("ECHO: %s\r\n", argv[n]); 01880 cmd_printf("%s ", argv[n]); 01881 } 01882 cmd_printf("\r\n"); 01883 } 01884 return 0; 01885 } 01886 01887 int clear_command(int argc, char *argv[]) 01888 { 01889 (void)argc; 01890 (void)argv; 01891 cmd_echo(true); 01892 cmd_init_screen(); 01893 return 0; 01894 } 01895 int help_command(int argc, char *argv[]) 01896 { 01897 cmd_printf("Commands:\r\n"); 01898 if (argc == 1) { 01899 ns_list_foreach(cmd_command_t, cur_ptr, &cmd.command_list) { 01900 cmd_printf("%-16s%s\r\n", cur_ptr->name_ptr, (cur_ptr->info_ptr ? cur_ptr->info_ptr : "")); 01901 } 01902 } else if (argc == 2) { 01903 cmd_command_t *cmd_ptr = cmd_find(argv[1]); 01904 if (cmd_ptr) { 01905 cmd_printf("Command: %s\r\n", cmd_ptr->name_ptr); 01906 if (cmd_ptr->man_ptr) { 01907 cmd_printf("%s\r\n", cmd_ptr->man_ptr); 01908 } else if (cmd_ptr->info_ptr) { 01909 cmd_printf("%s\r\n", cmd_ptr->info_ptr); 01910 } 01911 } else { 01912 cmd_printf("Command '%s' not found", argv[1]); 01913 } 01914 } 01915 return 0; 01916 } 01917 int true_command(int argc, char *argv[]) 01918 { 01919 (void)argc; 01920 (void)argv; 01921 return CMDLINE_RETCODE_SUCCESS; 01922 } 01923 int false_command(int argc, char *argv[]) 01924 { 01925 (void)argc; 01926 (void)argv; 01927 return CMDLINE_RETCODE_FAIL; 01928 } 01929 int history_command(int argc, char *argv[]) 01930 { 01931 if (argc == 1) { 01932 int history_size = (int)ns_list_count(&cmd.history_list); 01933 cmd_printf("History [%i/%i]:\r\n", history_size - 1, cmd.history_max_count - 1); 01934 int i = 0; 01935 ns_list_foreach_reverse(cmd_history_t, cur_ptr, &cmd.history_list) { 01936 if (i != history_size - 1) { 01937 cmd_printf("[%i]: %s\r\n", i++, cur_ptr->command_ptr); 01938 } 01939 } 01940 } else if (argc == 2) { 01941 if (strcmp(argv[1], "clear") == 0) { 01942 cmd_history_clean(); 01943 } else { 01944 cmd_history_size(strtoul(argv[1], 0, 10)); 01945 } 01946 } 01947 return 0; 01948 } 01949 01950 /** Parameter helping functions 01951 */ 01952 int cmd_parameter_index(int argc, char *argv[], const char *key) 01953 { 01954 int i = 0; 01955 for (i = 1; i < argc; i++) { 01956 if (strcmp(argv[i], key) == 0) { 01957 return i; 01958 } 01959 } 01960 return -1; 01961 } 01962 bool cmd_has_option(int argc, char *argv[], const char *key) 01963 { 01964 int i = 0; 01965 for (i = 1; i < argc; i++) { 01966 if (argv[i][0] == '-' && argv[i][1] != '-') { 01967 if (strstr(argv[i], key) != 0) { 01968 return true; 01969 } 01970 } 01971 } 01972 return false; 01973 } 01974 bool cmd_parameter_bool(int argc, char *argv[], const char *key, bool *value) 01975 { 01976 int i = cmd_parameter_index(argc, argv, key); 01977 if (i > 0) { 01978 if (argc > (i + 1)) { 01979 if (strcmp(argv[i + 1], "on") == 0 || 01980 strcmp(argv[i + 1], "1") == 0 || 01981 strcmp(argv[i + 1], "true") == 0 || 01982 strcmp(argv[i + 1], "enable") == 0 || 01983 strcmp(argv[i + 1], "allow") == 0) { 01984 *value = true; 01985 } else { 01986 *value = false; 01987 } 01988 return true; 01989 } 01990 } 01991 return false; 01992 } 01993 bool cmd_parameter_val(int argc, char *argv[], const char *key, char **value) 01994 { 01995 int i = cmd_parameter_index(argc, argv, key); 01996 if (i > 0) { 01997 if (argc > (i + 1)) { 01998 *value = argv[i + 1]; 01999 return true; 02000 } 02001 } 02002 return false; 02003 } 02004 bool cmd_parameter_int(int argc, char *argv[], const char *key, int32_t *value) 02005 { 02006 int i = cmd_parameter_index(argc, argv, key); 02007 char *tailptr; 02008 if (i > 0) { 02009 if (argc > (i + 1)) { 02010 *value = strtol(argv[i + 1], &tailptr, 10); 02011 if (0 == *tailptr) { 02012 return true; 02013 } 02014 if (!isspace((unsigned char) *tailptr)) { 02015 return false; 02016 } else { 02017 return true; 02018 } 02019 } 02020 } 02021 return false; 02022 } 02023 bool cmd_parameter_float(int argc, char *argv[], const char *key, float *value) 02024 { 02025 int i = cmd_parameter_index(argc, argv, key); 02026 char *tailptr; 02027 if (i > 0) { 02028 if (argc > (i + 1)) { 02029 *value = strtof(argv[i + 1], &tailptr); 02030 if (0 == *tailptr) { 02031 return true; //Should be correct read always 02032 } 02033 if (!isspace((unsigned char) *tailptr)) { 02034 return false; //Garbage in tailptr 02035 } else { 02036 return true; //Spaces are fine after float 02037 } 02038 } 02039 } 02040 return false; 02041 } 02042 // convert hex string (eg. "76 ab ff") to binary array 02043 static int string_to_bytes(const char *str, uint8_t *buf, int bytes) 02044 { 02045 int len = strlen(str); 02046 if (len <= (3 * bytes - 1)) { 02047 int i; 02048 for (i = 0; i < bytes; i++) { 02049 if (i * 3 < len) { 02050 buf[i] = (uint8_t)strtoul(str + i * 3, 0, 16); 02051 } else { 02052 buf[i] = 0; 02053 } 02054 } 02055 return 0; 02056 } 02057 return -1; 02058 } 02059 02060 static uint64_t read_64_bit(const uint8_t data_buf[__static 8]) 02061 { 02062 uint64_t temp_64; 02063 temp_64 = (uint64_t)(*data_buf++) << 56; 02064 temp_64 += (uint64_t)(*data_buf++) << 48; 02065 temp_64 += (uint64_t)(*data_buf++) << 40; 02066 temp_64 += (uint64_t)(*data_buf++) << 32; 02067 temp_64 += (uint64_t)(*data_buf++) << 24; 02068 temp_64 += (uint64_t)(*data_buf++) << 16; 02069 temp_64 += (uint64_t)(*data_buf++) << 8; 02070 temp_64 += *data_buf++; 02071 return temp_64; 02072 } 02073 02074 bool cmd_parameter_timestamp(int argc, char *argv[], const char *key, int64_t *value) 02075 { 02076 int i = cmd_parameter_index(argc, argv, key); 02077 if (i > 0) { 02078 if (argc > (i + 1)) { 02079 if (strchr(argv[i + 1], ',') != 0) { 02080 // Format seconds,tics 02081 const char splitValue[] = ", "; 02082 char *token; 02083 token = strtok(argv[i + 1], splitValue); 02084 if (token) { 02085 *value = (int64_t)strtoul(token, 0, 10) << 16; 02086 } 02087 token = strtok(NULL, splitValue); 02088 if (token) { 02089 *value |= (0xffff & strtoul(token, 0, 10)); 02090 } 02091 } else if (strchr(argv[i + 1], ':') != 0) { 02092 // Format 00:00:00:00:00:00:00:00 02093 uint8_t buf[8]; 02094 if (string_to_bytes(argv[i + 1], buf, 8) == 0) { 02095 *value = read_64_bit(buf); 02096 } else { 02097 cmd_printf("timestamp should be 8 bytes long\r\n"); 02098 } 02099 } else { 02100 // Format uint64 02101 *value = strtol(argv[i + 1], 0, 10); 02102 } 02103 return true; 02104 } 02105 } 02106 return false; 02107 } 02108 char *cmd_parameter_last(int argc, char *argv[]) 02109 { 02110 if (argc > 1) { 02111 return argv[ argc - 1 ]; 02112 } 02113 return NULL; 02114 } 02115 /** 02116 * find last space but ignore nulls and first spaces. 02117 * used only internally to find out previous word 02118 * e.g. 02119 * const char str[] = "aaaab aa bbb\0\0"; 02120 * const char* tmp = last_space(str+strlen(str), str); 02121 * printf(tmp); // prints "bbb" 02122 */ 02123 static const char *find_last_space(const char *from, const char *to) 02124 { 02125 if (from <= to) { 02126 return 0; 02127 } 02128 while ((from > to) && ((*from == 0) || (*from == ' '))) { 02129 from--; 02130 } 02131 while (from > to) { 02132 if (*from == ' ') { 02133 return from + 1; 02134 } 02135 from--; 02136 } 02137 return 0; 02138 } 02139 static int replace_string( 02140 char *str, int str_len, 02141 const char *old_str, const char *new_str) 02142 { 02143 char *ptr = str; 02144 char *end = str + str_len; 02145 int old_len = strlen(old_str); 02146 int new_len = strlen(new_str); 02147 if (old_len > 0) { 02148 tr_deep("find: '%s'\r\n", old_str); 02149 while ((ptr = strstr(ptr, old_str)) != 0) { 02150 if (ptr + new_len > end) { 02151 tr_warn("Buffer was not enough for replacing\r\n"); 02152 return 1; 02153 } 02154 tr_warn("old_str found\r\n"); 02155 if (old_len != new_len) { 02156 tr_warn("memmove\r\n"); 02157 memmove(ptr + new_len, ptr + old_len, strlen(ptr + old_len) + 1); 02158 } 02159 memcpy(ptr, new_str, new_len); 02160 ptr += new_len; 02161 } 02162 } 02163 return 0; 02164 }
Generated on Tue Jul 12 2022 13:54:38 by
