cli.c
Go to the documentation of this file.
00001 00042 #include "cli.h" 00043 00044 #include "cfg/cfg_parser.h" 00045 #include "cfg/cfg_cli.h" 00046 00047 #define LOG_LEVEL CLI_LOG_LEVEL 00048 #define LOG_FORMAT CLI_LOG_FORMAT 00049 #include <cfg/log.h> 00050 #include <cfg/compiler.h> 00051 #include <cfg/debug.h> 00052 00053 #include <mware/readline.h> 00054 #include <mware/parser.h> 00055 00056 #include <io/kfile.h> 00057 00058 static CLI *local_cli; 00059 00060 /* 00061 * Reply macro. 00062 * Send error message to client. 00063 * 00064 * \a fd kfile handler for serial. 00065 * \a err int error code. 00066 * \a err human-readable description of the error for debug purposes. 00067 */ 00068 INLINE void REPLY(KFile *fd, int err_code, const char *err) 00069 { 00070 #if CLI_LOG_LEVEL == LOG_LVL_INFO 00071 kfile_printf(fd, "%d %s\r\n", err_code, err); 00072 #else 00073 (void)err; 00074 kfile_printf(fd, "%d\r\n", err_code); 00075 #endif 00076 } 00077 00078 /* 00079 * Print args on s, with format specified in t->result_fmt. 00080 * Return number of valid arguments or -1 in case of error. 00081 */ 00082 static bool cli_reply(KFile *fd, const struct CmdTemplate *t, const parms *args) 00083 { 00084 unsigned short offset = strlen(t->arg_fmt) + 1; 00085 unsigned short nres = strlen(t->result_fmt); 00086 00087 for (unsigned short i = 0; i < nres; ++i) 00088 { 00089 if (t->result_fmt[i] == 'd') 00090 { 00091 kfile_printf(fd, " %ld", args[offset+i].l); 00092 } 00093 else if (t->result_fmt[i] == 's') 00094 { 00095 kfile_printf(fd, " %s", args[offset+i].s); 00096 } 00097 else 00098 { 00099 return false; 00100 } 00101 } 00102 00103 kfile_printf(fd, "\r\n"); 00104 return true; 00105 } 00106 00107 static void cli_parse(CLI *cli, const char *buf) 00108 { 00109 const struct CmdTemplate *templ; 00110 00111 /* Command check. */ 00112 templ = parser_get_cmd_template(buf); 00113 if (!templ) 00114 { 00115 REPLY(cli->fd, CLI_INVALID_CMD, "Invalid command."); 00116 return; 00117 } 00118 00119 parms args[CONFIG_PARSER_MAX_ARGS]; 00120 00121 if (!parser_get_cmd_arguments(buf, templ, args)) 00122 { 00123 REPLY(cli->fd, CLI_INVALID_ARGS, "Invalid arguments."); 00124 return; 00125 } 00126 00127 /* Execute. */ 00128 if(!parser_execute_cmd(templ, args)) 00129 { 00130 REPLY(cli->fd, CLI_ERR_EXE_CMD, "Error in executing command."); 00131 } 00132 00133 if (!cli_reply(cli->fd, templ, args)) 00134 { 00135 REPLY(cli->fd, CLI_INVALID_RET_FMT, "Invalid return format."); 00136 } 00137 00138 return; 00139 } 00140 00149 void cli_poll(KFile *fd) 00150 { 00151 /* Check with user function if session was end */ 00152 if (!local_cli->is_new_session && local_cli->check_newSession) 00153 { 00154 if (local_cli->check_newSession(fd)) 00155 local_cli->is_new_session = true; 00156 } 00157 00158 /* Print ready promt at first time that we connect */ 00159 if (local_cli->is_new_session) 00160 { 00161 /* If defined call the custom procedure for new session */ 00162 if (local_cli->handshake) 00163 local_cli->handshake(local_cli->fd); 00164 00165 rl_refresh(&local_cli->rl_ctx); 00166 local_cli->is_new_session = false; 00167 } 00168 00169 const char *buf = rl_readline(&local_cli->rl_ctx); 00170 00171 if((buf == NULL)) 00172 return; 00173 00174 if (buf[0] == '\0') 00175 return; 00176 00177 /* If we enter lines beginning with sharp(#) 00178 they are stripped out from commands */ 00179 if (buf[0] == '#') 00180 { 00181 rl_refresh(&local_cli->rl_ctx); 00182 return; 00183 } 00184 00185 /* Close connetion on exit command */ 00186 if (!strcmp(buf, "exit") || !strcmp(buf, "quit")) 00187 { 00188 rl_clear_history(&local_cli->rl_ctx); 00189 kfile_close(local_cli->fd); 00190 local_cli->is_new_session = true; 00191 } 00192 else 00193 { 00194 cli_parse(local_cli, buf); 00195 rl_refresh(&local_cli->rl_ctx); 00196 } 00197 } 00198 00199 00214 void cli_init(CLI *cli, KFile *ch, cli_t cmds_register, cli_handshake_t handshake, cli_check_t check_newSession) 00215 { 00216 ASSERT(cmds_register); 00217 00218 parser_init(); 00219 cmds_register(); 00220 00221 local_cli = cli; 00222 00223 cli->fd = ch; 00224 cli->handshake = handshake; 00225 cli->check_newSession = check_newSession; 00226 cli->is_new_session = true; 00227 00228 rl_init_ctx(&cli->rl_ctx); 00229 rl_setprompt(&cli->rl_ctx, CONFIG_CLI_PROMT_STR); 00230 rl_sethook_get(&cli->rl_ctx, (getc_hook)kfile_getc, cli->fd); 00231 rl_sethook_put(&cli->rl_ctx, (putc_hook)kfile_putc, cli->fd); 00232 rl_sethook_match(&cli->rl_ctx, parser_rl_match, NULL); 00233 }
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)