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 }