From e02d0df8f635130d143688ddad8f51f018b2aece Mon Sep 17 00:00:00 2001 From: Riza Sulistyo Date: Wed, 28 Nov 2012 03:02:01 +0000 Subject: [PATCH] Re #1098: Modify help screen, change backspace input character, fix static and dynamic choice type argument handling git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/cli@4302 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/src/pjlib-util/cli.c | 49 ++++++++++----- pjlib-util/src/pjlib-util/cli_console.c | 81 +++++++++++++----------- pjlib-util/src/pjlib-util/cli_telnet.c | 83 ++++++++++++++----------- pjsip-apps/src/samples/clidemo.c | 20 +++++- pjsip-apps/src/samples/debug.c | 2 +- 5 files changed, 145 insertions(+), 90 deletions(-) diff --git a/pjlib-util/src/pjlib-util/cli.c b/pjlib-util/src/pjlib-util/cli.c index 498008c91..0466d463c 100644 --- a/pjlib-util/src/pjlib-util/cli.c +++ b/pjlib-util/src/pjlib-util/cli.c @@ -560,7 +560,8 @@ static pj_status_t pj_cli_add_choice_node(pj_cli_t *cli, pj_strassign(&choice_val->value, &choice_attr->value); } else if (!pj_stricmp2(&choice_attr->name, "desc")) { pj_strassign(&choice_val->desc, &choice_attr->value); - } + } + choice_attr = choice_attr->next; } ++(arg->stat_choice_cnt); choice_node = choice_node->next; @@ -608,7 +609,7 @@ static pj_status_t pj_cli_add_arg_node(pj_cli_t *cli, arg->type = PJ_CLI_ARG_TEXT; } else if (!pj_stricmp2(&attr->value, "int")) { arg->type = PJ_CLI_ARG_INT; - } else if (!pj_stricmp2(&attr->value, "CHOICE")) { + } else if (!pj_stricmp2(&attr->value, "choice")) { /* Get choice value */ pj_cli_add_choice_node(cli, xml_node, arg, get_choice); } @@ -732,11 +733,18 @@ static pj_status_t pj_cli_add_cmd_node(pj_cli_t *cli, cmd->arg = (pj_cli_arg_spec *)pj_pool_zalloc(cli->pool, cmd->arg_cnt * sizeof(pj_cli_arg_spec)); + for (i = 0; i < cmd->arg_cnt; i++) { + unsigned j; + pj_strdup(cli->pool, &cmd->arg[i].name, &args[i].name); pj_strdup(cli->pool, &cmd->arg[i].desc, &args[i].desc); + cmd->arg[i].id = args[i].id; cmd->arg[i].type = args[i].type; cmd->arg[i].optional = args[i].optional; + cmd->arg[i].get_dyn_choice = args[i].get_dyn_choice; + cmd->arg[i].stat_choice_cnt = args[i].stat_choice_cnt; + cmd->arg[i].stat_choice_val = args[i].stat_choice_val; } } @@ -1063,8 +1071,7 @@ static pj_status_t get_match_args(pj_cli_sess *sess, arg = &cmd->arg[argc-1]; PJ_ASSERT_RETURN(arg, PJ_EINVAL); if (arg->type == PJ_CLI_ARG_CHOICE) { - unsigned j; - pj_cli_dyn_choice_param dyn_choice_param; + unsigned j; for (j=0; j < arg->stat_choice_cnt; ++j) { pj_cli_arg_choice_val *choice_val = &arg->stat_choice_val[j]; @@ -1080,20 +1087,28 @@ static pj_status_t get_match_args(pj_cli_sess *sess, return status; } } - /* Get the dynamic choice values */ - dyn_choice_param.sess = sess; - dyn_choice_param.cmd = cmd; - dyn_choice_param.arg_id = arg->id; - dyn_choice_param.max_cnt = PJ_CLI_MAX_CHOICE_VAL; - dyn_choice_param.pool = pool; - dyn_choice_param.cnt = 0; + if (arg->get_dyn_choice) { + pj_cli_dyn_choice_param dyn_choice_param; + static const pj_str_t choice_str = {"choice", 6}; - (*arg->get_dyn_choice)(&dyn_choice_param); - for (j=0; j < dyn_choice_param.cnt; ++j) { - pj_cli_arg_choice_val *choice = &dyn_choice_param.choice[j]; - pj_strassign(&info->hint[info->hint_cnt].name, &choice->value); - pj_strassign(&info->hint[info->hint_cnt].desc, &choice->desc); - ++info->hint_cnt; + /* Get the dynamic choice values */ + dyn_choice_param.sess = sess; + dyn_choice_param.cmd = cmd; + dyn_choice_param.arg_id = arg->id; + dyn_choice_param.max_cnt = PJ_CLI_MAX_CHOICE_VAL; + dyn_choice_param.pool = pool; + dyn_choice_param.cnt = 0; + + (*arg->get_dyn_choice)(&dyn_choice_param); + for (j=0; j < dyn_choice_param.cnt; ++j) { + pj_cli_arg_choice_val *choice = &dyn_choice_param.choice[j]; + if (!pj_strnicmp(&choice->value, cmd_val, cmd_val->slen)) { + pj_strassign(&info->hint[info->hint_cnt].name, &choice->value); + pj_strassign(&info->hint[info->hint_cnt].type, &choice_str); + pj_strassign(&info->hint[info->hint_cnt].desc, &choice->desc); + ++info->hint_cnt; + } + } } } else { if (cmd_val->slen == 0) { diff --git a/pjlib-util/src/pjlib-util/cli_console.c b/pjlib-util/src/pjlib-util/cli_console.c index c798a7a3c..1bd4eb220 100644 --- a/pjlib-util/src/pjlib-util/cli_console.c +++ b/pjlib-util/src/pjlib-util/cli_console.c @@ -78,6 +78,17 @@ typedef enum cmd_parse_state ST_ARROWMODE } cmd_parse_state; +/** + * This specify the state of output character parsing. + */ +typedef enum out_parse_state +{ + OP_NORMAL, + OP_TYPE, + OP_SHORTCUT, + OP_CHOICE +} out_parse_state; + /** * This structure contains the command line shown to the user. */ @@ -365,10 +376,10 @@ static void send_ambi_arg(pj_cli_sess *sess, struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; console_recv_buf *recv_buf = &fe->input.recv_buf; const pj_cli_hint_info *hint = info->hint; - pj_bool_t is_process_sc = PJ_FALSE; - pj_bool_t valid_type = PJ_FALSE; + out_parse_state parse_state = OP_NORMAL; pj_ssize_t max_length = 0; - const pj_str_t sc_type = pj_str("SC"); + static const pj_str_t sc_type = {"sc", 2}; + static const pj_str_t choice_type = {"choice", 6}; send_data.ptr = &data[0]; send_data.slen = 0; @@ -390,46 +401,46 @@ static void send_ambi_arg(pj_cli_sess *sess, } for (i=0;ihint_cnt;++i) { - if ((&hint[i].type) && (hint[i].type.slen > 0)) { - valid_type = PJ_TRUE; + pj_strcat2(&send_data, "\r\n "); + + if ((&hint[i].type) && (hint[i].type.slen > 0)) { if (pj_stricmp(&hint[i].type, &sc_type) == 0) { - if (is_process_sc) { - pj_strcat2(&send_data, ", "); - } else { - pj_strcat2(&send_data, "\r\n\t Shorcut: "); - is_process_sc = PJ_TRUE; - } - pj_strcat(&send_data, &hint[i].name); + parse_state = OP_SHORTCUT; + } else if (pj_stricmp(&hint[i].type, &choice_type) == 0) { + parse_state = OP_CHOICE; } else { - is_process_sc = PJ_FALSE; + parse_state = OP_TYPE; } - } else { - valid_type = PJ_FALSE; - is_process_sc = PJ_FALSE; + } else { + parse_state = OP_NORMAL; + } + + switch (parse_state) { + case OP_CHOICE: + pj_strcat2(&send_data, "["); + pj_strcat(&send_data, &hint[i].name); + pj_strcat2(&send_data, "]"); + break; + case OP_TYPE: + pj_strcat2(&send_data, "<"); + pj_strcat(&send_data, &hint[i].type); + pj_strcat2(&send_data, ">"); + break; + default: + pj_strcat(&send_data, &hint[i].name); + break; } - - if (!is_process_sc) { - pj_strcat2(&send_data, "\r\n\t"); - - if (valid_type) { - pj_strcat2(&send_data, "<"); - pj_strcat(&send_data, &hint[i].type); - pj_strcat2(&send_data, ">"); - } else { - pj_strcat(&send_data, &hint[i].name); - } - if ((&hint[i].desc) && (hint[i].desc.slen > 0)) { - if (!valid_type) { - for (j=0;j<(max_length-hint[i].name.slen);++j) { - pj_strcat2(&send_data, " "); - } + if ((&hint[i].desc) && (hint[i].desc.slen > 0)) { + if (parse_state != OP_TYPE) { + for (j=0;j<(max_length-hint[i].name.slen);++j) { + pj_strcat2(&send_data, " "); } - pj_strcat2(&send_data, "\t"); - pj_strcat(&send_data, &hint[i].desc); } + pj_strcat2(&send_data, " "); + pj_strcat(&send_data, &hint[i].desc); } - } + } pj_strcat2(&send_data, "\r\n"); pj_strcat(&send_data, &fe->cfg.prompt_str); if (with_last_cmd) diff --git a/pjlib-util/src/pjlib-util/cli_telnet.c b/pjlib-util/src/pjlib-util/cli_telnet.c index 8f5b678c8..f8b524856 100644 --- a/pjlib-util/src/pjlib-util/cli_telnet.c +++ b/pjlib-util/src/pjlib-util/cli_telnet.c @@ -196,6 +196,17 @@ enum terminal_cmd TC_DEL = 127 }; +/** + * This specify the state of output character parsing. + */ +typedef enum out_parse_state +{ + OP_NORMAL, + OP_TYPE, + OP_SHORTCUT, + OP_CHOICE +} out_parse_state; + /** * This structure contains the command line shown to the user. */ @@ -754,10 +765,10 @@ static void send_ambi_arg(cli_telnet_sess *sess, char data[1028]; struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe; const pj_cli_hint_info *hint = info->hint; - pj_bool_t is_process_sc = PJ_FALSE; - pj_bool_t valid_type = PJ_FALSE; + out_parse_state parse_state = OP_NORMAL; pj_ssize_t max_length = 0; - const pj_str_t sc_type = pj_str("SC"); + static const pj_str_t sc_type = {"sc", 2}; + static const pj_str_t choice_type = {"choice", 6}; send_data.ptr = &data[0]; send_data.slen = 0; @@ -778,46 +789,46 @@ static void send_ambi_arg(cli_telnet_sess *sess, } for (i=0;ihint_cnt;++i) { - if ((&hint[i].type) && (hint[i].type.slen > 0)) { - valid_type = PJ_TRUE; + pj_strcat2(&send_data, "\r\n "); + + if ((&hint[i].type) && (hint[i].type.slen > 0)) { if (pj_stricmp(&hint[i].type, &sc_type) == 0) { - if (is_process_sc) { - pj_strcat2(&send_data, ", "); - } else { - pj_strcat2(&send_data, "\r\n\t Shorcut: "); - is_process_sc = PJ_TRUE; - } - pj_strcat(&send_data, &hint[i].name); + parse_state = OP_SHORTCUT; + } else if (pj_stricmp(&hint[i].type, &choice_type) == 0) { + parse_state = OP_CHOICE; } else { - is_process_sc = PJ_FALSE; + parse_state = OP_TYPE; } - } else { - valid_type = PJ_FALSE; - is_process_sc = PJ_FALSE; + } else { + parse_state = OP_NORMAL; + } + + switch (parse_state) { + case OP_CHOICE: + pj_strcat2(&send_data, "["); + pj_strcat(&send_data, &hint[i].name); + pj_strcat2(&send_data, "]"); + break; + case OP_TYPE: + pj_strcat2(&send_data, "<"); + pj_strcat(&send_data, &hint[i].name); + pj_strcat2(&send_data, ">"); + break; + default: + pj_strcat(&send_data, &hint[i].name); + break; } - - if (!is_process_sc) { - pj_strcat2(&send_data, "\r\n\t"); - - if (valid_type) { - pj_strcat2(&send_data, "<"); - pj_strcat(&send_data, &hint[i].type); - pj_strcat2(&send_data, ">"); - } else { - pj_strcat(&send_data, &hint[i].name); - } - if ((&hint[i].desc) && (hint[i].desc.slen > 0)) { - if (!valid_type) { - for (j=0;j<(max_length-hint[i].name.slen);++j) { - pj_strcat2(&send_data, " "); - } + if ((&hint[i].desc) && (hint[i].desc.slen > 0)) { + if (parse_state != OP_TYPE) { + for (j=0;j<(max_length-hint[i].name.slen);++j) { + pj_strcat2(&send_data, " "); } - pj_strcat2(&send_data, "\t"); - pj_strcat(&send_data, &hint[i].desc); } + pj_strcat2(&send_data, " "); + pj_strcat(&send_data, &hint[i].desc); } - } + } pj_strcat2(&send_data, "\r\n"); pj_strcat(&send_data, &fe->cfg.prompt_str); if (with_last_cmd) @@ -1290,7 +1301,7 @@ static pj_bool_t telnet_sess_on_data_read(pj_activesock_t *asock, case ST_NORMAL: if (*cdata == IAC) { sess->parse_state = ST_IAC; - } else if (*cdata == '\b') { + } else if (*cdata == 127) { is_valid = handle_backspace(sess, cdata); } else if (*cdata == 27) { sess->parse_state = ST_ESC; diff --git a/pjsip-apps/src/samples/clidemo.c b/pjsip-apps/src/samples/clidemo.c index 70a353578..2d68af772 100644 --- a/pjsip-apps/src/samples/clidemo.c +++ b/pjsip-apps/src/samples/clidemo.c @@ -89,6 +89,17 @@ static pj_status_t quit_app(pj_cli_cmd_val *cval) return PJ_CLI_EEXIT; } +static void get_codec_list(pj_cli_dyn_choice_param *param) +{ + if (param->arg_id == 3) { + param->cnt = 2; + pj_strdup2(param->pool, ¶m->choice[0].value, "iLbc"); + pj_strdup2(param->pool, ¶m->choice[0].desc, "iLbc Codec"); + pj_strdup2(param->pool, ¶m->choice[1].value, "g729"); + pj_strdup2(param->pool, ¶m->choice[1].desc, "g729 Codec"); + } +} + static struct cmd_xml_t cmd_xmls[] = { {"" " " @@ -116,6 +127,13 @@ static struct cmd_xml_t cmd_xmls[] = { " " "", NULL}, + {"" + " " + " " + " " + " " + "", + NULL}, {"" "", &quit_app}, @@ -158,7 +176,7 @@ int main() for (i = 0; i < sizeof(cmd_xmls)/sizeof(cmd_xmls[0]); i++) { xml = pj_str(cmd_xmls[i].xml); status = pj_cli_add_cmd_from_xml(cli, NULL, &xml, - cmd_xmls[i].handler, NULL, NULL); + cmd_xmls[i].handler, NULL, get_codec_list); if (status != PJ_SUCCESS) goto on_return; } diff --git a/pjsip-apps/src/samples/debug.c b/pjsip-apps/src/samples/debug.c index b4e9d44eb..5417a79aa 100644 --- a/pjsip-apps/src/samples/debug.c +++ b/pjsip-apps/src/samples/debug.c @@ -28,5 +28,5 @@ * E.g.: * #include "playfile.c" */ -#include "clidemo.c" +#include "icedemo.c"