Ignore:
Timestamp:
Nov 23, 2012 10:30:55 AM (11 years ago)
Author:
riza
Message:

Re #1098: Additional implementation to command parsing, telnet front end, console front end

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/cli/pjlib-util/src/pjlib-util/cli_console.c

    r3231 r4299  
    2828#include <pjlib-util/errno.h> 
    2929 
     30#if defined(PJ_LINUX) && PJ_LINUX != 0 || \ 
     31    defined(PJ_DARWINOS) && PJ_DARWINOS != 0 
     32#include <termios.h> 
     33 
     34static struct termios old, new; 
     35 
     36/* Initialize new terminal i/o settings */ 
     37void initTermios(int echo)  
     38{ 
     39    tcgetattr(0, &old);  
     40    new = old;  
     41    new.c_lflag &= ~ICANON;  
     42    new.c_lflag &= echo ? ECHO : ~ECHO;  
     43    tcsetattr(0, TCSANOW, &new);  
     44} 
     45 
     46/* Restore old terminal i/o settings */ 
     47void resetTermios(void)  
     48{ 
     49    tcsetattr(0, TCSANOW, &old); 
     50} 
     51 
     52/* Read 1 character - echo defines echo mode */ 
     53char getch_(int echo)  
     54{ 
     55    char ch; 
     56    initTermios(echo); 
     57    ch = getchar(); 
     58    resetTermios(); 
     59    return ch; 
     60} 
     61 
     62/* Read 1 character without echo */ 
     63char getch(void)  
     64{ 
     65    return getch_(0); 
     66} 
     67 
     68#endif 
     69 
     70/** 
     71 * This specify the state of input character parsing. 
     72 */ 
     73typedef enum cmd_parse_state 
     74{ 
     75    ST_NORMAL, 
     76    ST_SCANMODE, 
     77    ST_ESC, 
     78    ST_ARROWMODE 
     79} cmd_parse_state; 
     80 
     81/** 
     82 * This structure contains the command line shown to the user.   
     83 */ 
     84typedef struct console_recv_buf { 
     85    /** 
     86     * Buffer containing the characters, NULL terminated. 
     87     */ 
     88    unsigned char           rbuf[PJ_CLI_MAX_CMDBUF]; 
     89 
     90    /** 
     91     * Current length of the command line. 
     92     */ 
     93    unsigned                len; 
     94 
     95    /** 
     96     * Current cursor position. 
     97     */ 
     98    unsigned                cur_pos; 
     99} console_recv_buf; 
     100 
     101typedef struct cmd_history 
     102{ 
     103    PJ_DECL_LIST_MEMBER(struct cmd_history); 
     104    pj_str_t command; 
     105} cmd_history; 
     106 
    30107struct cli_console_fe 
    31108{ 
     
    35112    pj_thread_t        *input_thread; 
    36113    pj_bool_t           thread_quit; 
    37     pj_sem_t           *thread_sem; 
     114    pj_sem_t           *thread_sem;    
     115    pj_cli_console_cfg  cfg; 
    38116 
    39117    struct async_input_t 
    40     { 
    41         char       *buf; 
    42         unsigned    maxlen; 
    43         pj_sem_t   *sem; 
     118    {         
     119        console_recv_buf    recv_buf;         
     120        pj_sem_t           *sem; 
    44121    } input; 
     122 
     123    cmd_history             *history; 
     124    cmd_history             *active_history; 
    45125}; 
     126 
     127static unsigned recv_buf_right_len(console_recv_buf *recv_buf) 
     128{ 
     129    return (recv_buf->len - recv_buf->cur_pos); 
     130} 
     131 
     132static pj_bool_t recv_buf_insert(console_recv_buf *recv_buf,  
     133                                 unsigned char *data)  
     134{     
     135    if (recv_buf->len+1 >= PJ_CLI_MAX_CMDBUF) { 
     136        return PJ_FALSE; 
     137    } else {     
     138        if (*data == '\t' || *data == '?' || *data == '\r') { 
     139            /* Always insert to the end of line */ 
     140            recv_buf->rbuf[recv_buf->len] = *data; 
     141        } else { 
     142            /* Insert based on the current cursor pos */ 
     143            unsigned cur_pos = recv_buf->cur_pos; 
     144            unsigned rlen = recv_buf_right_len(recv_buf);            
     145            if (rlen > 0) {                  
     146                /* Shift right characters */ 
     147                pj_memmove(&recv_buf->rbuf[cur_pos+1],  
     148                           &recv_buf->rbuf[cur_pos],  
     149                           rlen+1); 
     150            }  
     151            recv_buf->rbuf[cur_pos] = *data; 
     152        } 
     153        ++recv_buf->cur_pos; 
     154        ++recv_buf->len; 
     155        recv_buf->rbuf[recv_buf->len] = 0; 
     156    } 
     157    return PJ_TRUE; 
     158} 
     159 
     160static pj_bool_t recv_buf_backspace(console_recv_buf *recv_buf) 
     161{ 
     162    if ((recv_buf->cur_pos == 0) || (recv_buf->len == 0)) { 
     163        return PJ_FALSE; 
     164    } else { 
     165        unsigned rlen = recv_buf_right_len(recv_buf); 
     166        if (rlen) { 
     167            unsigned cur_pos = recv_buf->cur_pos; 
     168            pj_memmove(&recv_buf->rbuf[cur_pos-1], &recv_buf->rbuf[cur_pos],  
     169                       rlen); 
     170        } 
     171        --recv_buf->cur_pos; 
     172        --recv_buf->len; 
     173        recv_buf->rbuf[recv_buf->len] = 0; 
     174    }     
     175    return PJ_TRUE; 
     176} 
    46177 
    47178static void cli_console_write_log(pj_cli_front_end *fe, int level, 
     
    87218    pj_assert(param); 
    88219 
    89     param->log_level = PJ_CLI_CONSOLE_LOG_LEVEL; 
     220    param->log_level = PJ_CLI_CONSOLE_LOG_LEVEL;     
    90221} 
    91222 
     
    109240    sess = PJ_POOL_ZALLOC_T(pool, pj_cli_sess); 
    110241    fe = PJ_POOL_ZALLOC_T(pool, struct cli_console_fe); 
     242    fe->history = PJ_POOL_ZALLOC_T(pool, struct cmd_history); 
     243    pj_list_init(fe->history); 
     244    fe->active_history = fe->history; 
    111245 
    112246    if (!param) { 
     
    129263    pj_cli_register_front_end(cli, &fe->base); 
    130264 
     265    if (fe->cfg.prompt_str.slen == 0) {  
     266        pj_str_t prompt_sign = pj_str(">>> "); 
     267        char *prompt_data = pj_pool_alloc(fe->pool, 5);  
     268        fe->cfg.prompt_str.ptr = prompt_data;    
     269 
     270        pj_strcpy(&fe->cfg.prompt_str, &prompt_sign); 
     271        prompt_data[4] = 0; 
     272    } 
     273 
    131274    *p_sess = sess; 
    132275    if (p_fe) 
     
    136279} 
    137280 
    138 static int readline_thread(void * p) 
    139 { 
     281static void send_prompt_str(pj_cli_sess *sess) 
     282{ 
     283    pj_str_t send_data; 
     284    char data_str[128]; 
     285    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     286 
     287    send_data.ptr = &data_str[0]; 
     288    send_data.slen = 0; 
     289     
     290    pj_strcat(&send_data, &fe->cfg.prompt_str); 
     291    send_data.ptr[send_data.slen] = 0; 
     292 
     293    printf("%s", send_data.ptr); 
     294} 
     295 
     296static void send_err_arg(pj_cli_sess *sess,  
     297                         const pj_cli_exec_info *info,  
     298                         const pj_str_t *msg, 
     299                         pj_bool_t with_return, 
     300                         pj_bool_t with_last_cmd) 
     301{ 
     302    pj_str_t send_data; 
     303    char data_str[256]; 
     304    unsigned len; 
     305    unsigned i; 
     306    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     307    console_recv_buf *recv_buf = &fe->input.recv_buf; 
     308 
     309    send_data.ptr = &data_str[0]; 
     310    send_data.slen = 0; 
     311 
     312    if (with_return) 
     313        pj_strcat2(&send_data, "\r\n"); 
     314 
     315    len = fe->cfg.prompt_str.slen + info->err_pos; 
     316 
     317    for (i=0;i<len;++i) { 
     318        pj_strcat2(&send_data, " "); 
     319    } 
     320    pj_strcat2(&send_data, "^"); 
     321    pj_strcat2(&send_data, "\r\n"); 
     322    pj_strcat(&send_data, msg); 
     323    pj_strcat(&send_data, &fe->cfg.prompt_str); 
     324    if (with_last_cmd) 
     325        pj_strcat2(&send_data, (char *)&recv_buf->rbuf[0]); 
     326 
     327    send_data.ptr[send_data.slen] = 0; 
     328    printf("%s", send_data.ptr); 
     329} 
     330 
     331static void send_return_key(pj_cli_sess *sess)  
     332{     
     333    PJ_UNUSED_ARG(sess); 
     334    printf("\r\n");     
     335} 
     336 
     337static void send_inv_arg(pj_cli_sess *sess,  
     338                         const pj_cli_exec_info *info, 
     339                         pj_bool_t with_return, 
     340                         pj_bool_t with_last_cmd) 
     341{ 
     342    static const pj_str_t ERR_MSG = {"%Error : Invalid Arguments\r\n", 28}; 
     343    send_err_arg(sess, info, &ERR_MSG, with_return, with_last_cmd); 
     344} 
     345 
     346static void send_too_many_arg(pj_cli_sess *sess,  
     347                              const pj_cli_exec_info *info, 
     348                              pj_bool_t with_return, 
     349                              pj_bool_t with_last_cmd) 
     350{ 
     351    static const pj_str_t ERR_MSG = {"%Error : Too Many Arguments\r\n", 29}; 
     352    send_err_arg(sess, info, &ERR_MSG, with_return, with_last_cmd); 
     353} 
     354 
     355static void send_ambi_arg(pj_cli_sess *sess,  
     356                          const pj_cli_exec_info *info, 
     357                          pj_bool_t with_return, 
     358                          pj_bool_t with_last_cmd) 
     359{ 
     360    unsigned i; 
     361    pj_ssize_t j; 
     362    unsigned len; 
     363    pj_str_t send_data; 
     364    char data[1028]; 
     365    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     366    console_recv_buf *recv_buf = &fe->input.recv_buf; 
     367    const pj_cli_hint_info *hint = info->hint; 
     368    pj_bool_t is_process_sc = PJ_FALSE; 
     369    pj_bool_t valid_type = PJ_FALSE; 
     370    pj_ssize_t max_length = 0; 
     371    const pj_str_t sc_type = pj_str("SC"); 
     372    send_data.ptr = &data[0]; 
     373    send_data.slen = 0; 
     374     
     375    if (with_return) 
     376        pj_strcat2(&send_data, "\r\n"); 
     377 
     378    len = fe->cfg.prompt_str.slen + info->err_pos; 
     379 
     380    for (i=0;i<len;++i) { 
     381        pj_strcat2(&send_data, " "); 
     382    } 
     383    pj_strcat2(&send_data, "^");         
     384 
     385    /* Get the max length of the command name */ 
     386    for (i=0;i<info->hint_cnt;++i) { 
     387        if (hint[i].name.slen > max_length) { 
     388            max_length = hint[i].name.slen; 
     389        } 
     390    } 
     391 
     392    for (i=0;i<info->hint_cnt;++i) {     
     393        if ((&hint[i].type) && (hint[i].type.slen > 0)) { 
     394            valid_type = PJ_TRUE; 
     395            if (pj_stricmp(&hint[i].type, &sc_type) == 0) { 
     396                if (is_process_sc) { 
     397                    pj_strcat2(&send_data, ", "); 
     398                } else { 
     399                    pj_strcat2(&send_data, "\r\n\t Shorcut: "); 
     400                    is_process_sc = PJ_TRUE; 
     401                } 
     402                pj_strcat(&send_data, &hint[i].name); 
     403            } else { 
     404                is_process_sc = PJ_FALSE; 
     405            } 
     406        } else {             
     407            valid_type = PJ_FALSE; 
     408            is_process_sc = PJ_FALSE; 
     409        } 
     410 
     411        if (!is_process_sc) { 
     412            pj_strcat2(&send_data, "\r\n\t"); 
     413 
     414            if (valid_type) { 
     415                pj_strcat2(&send_data, "<"); 
     416                pj_strcat(&send_data, &hint[i].type); 
     417                pj_strcat2(&send_data, ">");     
     418            } else { 
     419                pj_strcat(&send_data, &hint[i].name);        
     420            } 
     421         
     422            if ((&hint[i].desc) && (hint[i].desc.slen > 0)) { 
     423                if (!valid_type) { 
     424                    for (j=0;j<(max_length-hint[i].name.slen);++j) { 
     425                        pj_strcat2(&send_data, " "); 
     426                    } 
     427                } 
     428                pj_strcat2(&send_data, "\t"); 
     429                pj_strcat(&send_data, &hint[i].desc);        
     430            } 
     431        } 
     432    }         
     433    pj_strcat2(&send_data, "\r\n"); 
     434    pj_strcat(&send_data, &fe->cfg.prompt_str); 
     435    if (with_last_cmd) 
     436        pj_strcat2(&send_data, (char *)&recv_buf->rbuf[0]); 
     437 
     438    send_data.ptr[send_data.slen] = 0; 
     439    printf("%s", send_data.ptr); 
     440} 
     441 
     442static void send_comp_arg(pj_cli_exec_info *info) 
     443{ 
     444    pj_str_t send_data; 
     445    char data[128]; 
     446 
     447    pj_strcat2(&info->hint[0].name, " "); 
     448 
     449    send_data.ptr = &data[0]; 
     450    send_data.slen = 0; 
     451 
     452    pj_strcat(&send_data, &info->hint[0].name);         
     453 
     454    send_data.ptr[send_data.slen] = 0; 
     455    printf("%s", send_data.ptr); 
     456} 
     457 
     458static int compare_str(void *value, const pj_list_type *nd) 
     459{ 
     460    cmd_history *node = (cmd_history*)nd; 
     461    return (pj_strcmp((pj_str_t *)value, &node->command)); 
     462} 
     463 
     464static pj_status_t insert_history(pj_cli_sess *sess,                              
     465                                  char *cmd_val) 
     466{ 
     467    cmd_history *in_history; 
     468    pj_str_t cmd; 
     469    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe;     
     470    cmd.ptr = cmd_val; 
     471    cmd.slen = pj_ansi_strlen(cmd_val)-1; 
     472 
     473    if (cmd.slen == 0) 
     474        return PJ_SUCCESS; 
     475 
     476    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     477 
     478    /* Find matching history */ 
     479    in_history = pj_list_search(fe->history, (void*)&cmd, compare_str); 
     480    if (!in_history) { 
     481        if (pj_list_size(fe->history) < PJ_CLI_MAX_CMD_HISTORY) {            
     482            char *data_history; 
     483            in_history = PJ_POOL_ZALLOC_T(fe->pool, cmd_history); 
     484            pj_list_init(in_history); 
     485            data_history = (char *)pj_pool_calloc(fe->pool,  
     486                           sizeof(char), PJ_CLI_MAX_CMDBUF); 
     487            in_history->command.ptr = data_history; 
     488            in_history->command.slen = 0; 
     489        } else { 
     490            /* Get the oldest history */ 
     491            in_history = fe->history->prev; 
     492        }            
     493    } else { 
     494        pj_list_insert_nodes_after(in_history->prev, in_history->next); 
     495    } 
     496    pj_strcpy(&in_history->command, pj_strtrim(&cmd)); 
     497    pj_list_push_front(fe->history, in_history); 
     498    fe->active_history = fe->history; 
     499 
     500    return PJ_SUCCESS; 
     501} 
     502 
     503static pj_str_t* get_prev_history(pj_cli_sess *sess, pj_bool_t is_forward) 
     504{ 
     505    pj_str_t *retval; 
     506    pj_size_t history_size; 
     507    cmd_history *node; 
     508    cmd_history *root; 
     509    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     510 
     511    PJ_ASSERT_RETURN(sess && fe, NULL); 
     512 
     513    node = fe->active_history; 
     514    root = fe->history; 
     515    history_size = pj_list_size(fe->history); 
     516 
     517    if (history_size == 0) { 
     518        return NULL; 
     519    } else { 
     520        if (is_forward) {            
     521            node = (node->next==root)?node->next->next:node->next;           
     522        } else { 
     523            node = (node->prev==root)?node->prev->prev:node->prev;           
     524        } 
     525        retval = &node->command; 
     526        fe->active_history = node; 
     527    } 
     528    return retval; 
     529} 
     530 
     531static pj_bool_t handle_alfa_num(console_recv_buf *recv_buf,  
     532                                 unsigned char *cdata) 
     533{         
     534    if (recv_buf_right_len(recv_buf) > 0) { 
     535        char out_str[255];       
     536        pj_memset(&out_str[0], 0, 255); 
     537        out_str[0] = *cdata; 
     538        pj_memcpy(&out_str[1], &recv_buf->rbuf[recv_buf->cur_pos],  
     539                  recv_buf_right_len(recv_buf)); 
     540        pj_memset(&out_str[recv_buf_right_len(recv_buf)+1], '\b',  
     541                  recv_buf_right_len(recv_buf));         
     542        printf("%s", out_str);  
     543    } else {     
     544        printf("%c", *cdata); 
     545    }     
     546    return PJ_TRUE; 
     547} 
     548 
     549static pj_bool_t handle_backspace(console_recv_buf *recv_buf) 
     550{     
     551    if (recv_buf_backspace(recv_buf)) { 
     552        if(recv_buf_right_len(recv_buf) > 0) { 
     553            char out_str[255]; 
     554            pj_memset(&out_str[0], 0, 255); 
     555            out_str[0] = '\b'; 
     556            pj_memcpy(&out_str[1], &recv_buf->rbuf[recv_buf->cur_pos],  
     557                recv_buf_right_len(recv_buf)); 
     558            out_str[recv_buf_right_len(recv_buf)+1] = ' ';  
     559            pj_memset(&out_str[recv_buf_right_len(recv_buf)+2], '\b',  
     560                recv_buf_right_len(recv_buf)+1); 
     561            printf("%s", out_str); 
     562        } else { 
     563            char out_str[4]; 
     564            out_str[0] = '\b'; 
     565            out_str[1] = ' '; 
     566            out_str[2] = '\b'; 
     567            out_str[3] = 0; 
     568            printf("%s", out_str); 
     569        } 
     570        return PJ_TRUE; 
     571    } 
     572    return PJ_FALSE; 
     573} 
     574 
     575static pj_bool_t handle_tab(pj_cli_sess *sess) 
     576{ 
     577    pj_status_t status; 
     578    pj_bool_t retval = PJ_TRUE; 
     579    unsigned len; 
     580     
     581    pj_pool_t *pool; 
     582    pj_cli_cmd_val *cmd_val; 
     583    pj_cli_exec_info info; 
     584    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     585    console_recv_buf *recv_buf = &fe->input.recv_buf; 
     586    pj_cli_t *cli = sess->fe->cli; 
     587 
     588    pool = pj_pool_create(pj_cli_get_param(cli)->pf, "handle_tab", 
     589                          PJ_CLI_CONSOLE_POOL_SIZE, PJ_CLI_CONSOLE_POOL_INC, 
     590                          NULL); 
     591 
     592    cmd_val = PJ_POOL_ZALLOC_T(pool, pj_cli_cmd_val); 
     593     
     594    status = pj_cli_sess_parse(sess, (char *)recv_buf->rbuf, cmd_val,  
     595                               pool, &info);     
     596 
     597    len = pj_ansi_strlen((char *)recv_buf->rbuf); 
     598 
     599    switch (status) { 
     600    case PJ_CLI_EINVARG: 
     601        send_inv_arg(sess, &info, PJ_TRUE, PJ_TRUE);             
     602        break; 
     603    case PJ_CLI_ETOOMANYARGS: 
     604        send_too_many_arg(sess, &info, PJ_TRUE, PJ_TRUE); 
     605        break; 
     606    case PJ_CLI_EMISSINGARG: 
     607    case PJ_CLI_EAMBIGUOUS: 
     608        send_ambi_arg(sess, &info, PJ_TRUE, PJ_TRUE); 
     609        break; 
     610    case PJ_SUCCESS: 
     611        if (len > recv_buf->cur_pos) 
     612        { 
     613            /* Send the cursor to EOL */ 
     614            unsigned char *data_sent = &recv_buf->rbuf[recv_buf->cur_pos-1]; 
     615            printf("%s", data_sent);         
     616        } 
     617        if (info.hint_cnt > 0) {         
     618            /* Compelete command */ 
     619            send_comp_arg(&info); 
     620 
     621            pj_memcpy(&recv_buf->rbuf[len],   
     622                      &info.hint[0].name.ptr[0], info.hint[0].name.slen); 
     623 
     624            len += info.hint[0].name.slen; 
     625            recv_buf->rbuf[len] = 0;                 
     626        } else { 
     627            retval = PJ_FALSE; 
     628        } 
     629        break; 
     630    } 
     631    recv_buf->len = len; 
     632    recv_buf->cur_pos = len; 
     633 
     634    pj_pool_release(pool);       
     635    return retval;  
     636} 
     637 
     638static pj_bool_t handle_return(pj_cli_sess *sess) 
     639{ 
     640    pj_status_t status; 
     641    pj_bool_t retval = PJ_TRUE; 
     642     
     643    pj_pool_t *pool;     
     644    pj_cli_exec_info info; 
     645    pj_cli_t *cli = sess->fe->cli; 
     646    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     647    console_recv_buf *recv_buf = &fe->input.recv_buf; 
     648     
     649    send_return_key(sess);     
     650    insert_history(sess, (char *)&recv_buf->rbuf[0]); 
     651 
     652    pool = pj_pool_create(pj_cli_get_param(cli)->pf, "handle_return", 
     653                          PJ_CLI_CONSOLE_POOL_SIZE, PJ_CLI_CONSOLE_POOL_INC, 
     654                          NULL);     
     655     
     656    status = pj_cli_sess_exec(sess, (char *)&recv_buf->rbuf[0],  
     657                              pool, &info); 
     658 
     659    switch (status) { 
     660    case PJ_CLI_EINVARG: 
     661        send_inv_arg(sess, &info, PJ_FALSE, PJ_FALSE);   
     662        break; 
     663    case PJ_CLI_ETOOMANYARGS: 
     664        send_too_many_arg(sess, &info, PJ_FALSE, PJ_FALSE); 
     665        break; 
     666    case PJ_CLI_EAMBIGUOUS: 
     667    case PJ_CLI_EMISSINGARG: 
     668        send_ambi_arg(sess, &info, PJ_FALSE, PJ_FALSE); 
     669        break; 
     670    case PJ_CLI_EEXIT: 
     671        retval = PJ_FALSE; 
     672        break; 
     673    case PJ_SUCCESS: 
     674        send_prompt_str(sess); 
     675        break; 
     676    }     
     677    if (retval) { 
     678        recv_buf->rbuf[0] = 0; 
     679        recv_buf->len = 0; 
     680        recv_buf->cur_pos = 0; 
     681    } 
     682 
     683    pj_pool_release(pool);       
     684    return retval;  
     685} 
     686 
     687static pj_bool_t handle_up_down(pj_cli_sess *sess, pj_bool_t is_up) 
     688{ 
     689    pj_str_t *history; 
     690    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
     691    console_recv_buf *recv_buf = &fe->input.recv_buf; 
     692 
     693    PJ_ASSERT_RETURN(sess && fe, PJ_FALSE); 
     694 
     695    history = get_prev_history(sess, is_up); 
     696    if (history) { 
     697        pj_str_t send_data; 
     698        char str[PJ_CLI_MAX_CMDBUF]; 
     699        send_data.ptr = &str[0]; 
     700        send_data.slen = 0; 
     701 
     702        if (recv_buf->cur_pos > 0) { 
     703            pj_memset(send_data.ptr, 0x08, recv_buf->cur_pos); 
     704            send_data.slen = recv_buf->cur_pos; 
     705        } 
     706 
     707        if (recv_buf->len > (unsigned)history->slen) { 
     708            unsigned buf_len = recv_buf->len; 
     709            pj_memset(&send_data.ptr[send_data.slen], 0x20, buf_len); 
     710            send_data.slen += buf_len; 
     711            pj_memset(&send_data.ptr[send_data.slen], 0x08, buf_len); 
     712            send_data.slen += buf_len; 
     713        }  
     714        /* Send data */ 
     715        pj_strcat(&send_data, history);  
     716        send_data.ptr[send_data.slen] = 0; 
     717        printf("%s", send_data.ptr); 
     718        pj_ansi_strncpy((char*)&recv_buf->rbuf, history->ptr, history->slen); 
     719        recv_buf->rbuf[history->slen] = 0; 
     720        recv_buf->len = history->slen; 
     721        recv_buf->cur_pos = recv_buf->len; 
     722        return PJ_TRUE; 
     723    } 
     724    return PJ_FALSE; 
     725} 
     726 
     727static pj_bool_t handle_left_key(console_recv_buf *recv_buf) 
     728{ 
     729    const static unsigned char BACK_SPACE = 0x08; 
     730    if (recv_buf->cur_pos) { 
     731        printf("%c", BACK_SPACE); 
     732        --recv_buf->cur_pos; 
     733        return PJ_TRUE; 
     734    } 
     735    return PJ_FALSE; 
     736} 
     737 
     738static pj_bool_t handle_right_key(console_recv_buf *recv_buf) 
     739{ 
     740    if (recv_buf_right_len(recv_buf)) { 
     741        unsigned char *data = &recv_buf->rbuf[recv_buf->cur_pos++]; 
     742        printf("%c", *data); 
     743        return PJ_TRUE; 
     744    } 
     745    return PJ_FALSE; 
     746} 
     747 
     748static int readchar_thread(void * p) 
     749{     
    140750    struct cli_console_fe * fe = (struct cli_console_fe *)p; 
    141     int i; 
     751    cmd_parse_state parse_state = ST_NORMAL; 
     752 
     753    printf("%s", fe->cfg.prompt_str.ptr); 
    142754 
    143755    while (!fe->thread_quit) { 
    144         fgets(fe->input.buf, fe->input.maxlen, stdin); 
    145         for (i = pj_ansi_strlen(fe->input.buf) - 1; i >= 0; i--) { 
    146             if (fe->input.buf[i] == '\n' || fe->input.buf[i] == '\r') 
    147                 fe->input.buf[i] = 0; 
    148             else 
    149                 break; 
    150         } 
    151         pj_sem_post(fe->input.sem); 
    152         /* Sleep until the next call of pj_cli_console_readline() */ 
     756        unsigned char cdata; 
     757        console_recv_buf *recv_buf = &fe->input.recv_buf; 
     758        pj_bool_t is_valid = PJ_TRUE; 
     759 
     760        cdata = (unsigned char)getch(); 
     761 
     762        switch (parse_state) { 
     763        case ST_NORMAL: 
     764            if (cdata == '\b') { 
     765                is_valid = handle_backspace(recv_buf); 
     766            } else if (cdata == 224) {       
     767                parse_state = ST_SCANMODE; 
     768            } else if (cdata == 27) {        
     769                parse_state = ST_ESC; 
     770            } else { 
     771                if (cdata == '\n') 
     772                    cdata = '\r'; 
     773                if (recv_buf_insert(recv_buf, &cdata)) { 
     774                    if (cdata == '\r') { 
     775                        is_valid = handle_return(fe->sess); 
     776                    } else if ((cdata == '\t') || (cdata == '?')) { 
     777                        is_valid = handle_tab(fe->sess); 
     778                    } else if (cdata > 31 && cdata < 127) { 
     779                        is_valid = handle_alfa_num(recv_buf, &cdata);                    
     780                    } 
     781                } else { 
     782                    is_valid = PJ_FALSE; 
     783                } 
     784            }        
     785            break; 
     786        case ST_SCANMODE: 
     787            switch (cdata) { 
     788            case 72: 
     789                //UP 
     790            case 80: 
     791                //DOwN 
     792                is_valid = handle_up_down(fe->sess, (cdata==72)); 
     793                break; 
     794            case 75: 
     795                is_valid = handle_left_key(recv_buf); 
     796                //LEFT 
     797                break; 
     798            case 77: 
     799                is_valid = handle_right_key(recv_buf); 
     800                //RIGHT 
     801                break; 
     802            }; 
     803            parse_state = ST_NORMAL; 
     804            break; 
     805        case ST_ESC: 
     806            parse_state = (cdata == 91)?ST_ARROWMODE:ST_NORMAL; 
     807            break; 
     808        case ST_ARROWMODE: 
     809            switch (cdata) { 
     810            case 65: 
     811                //UP 
     812            case 66: 
     813                //DOwN 
     814                is_valid = handle_up_down(fe->sess, (cdata==65)); 
     815                break; 
     816            case 68: 
     817                is_valid = handle_left_key(recv_buf); 
     818                //LEFT 
     819                break; 
     820            case 67: 
     821                is_valid = handle_right_key(recv_buf); 
     822                //RIGHT 
     823                break; 
     824            }; 
     825            parse_state = ST_NORMAL;         
     826            break; 
     827        }; 
     828 
     829        pj_sem_post(fe->input.sem);         
    153830        pj_sem_wait(fe->thread_sem); 
    154831    } 
     
    158835} 
    159836 
    160 PJ_DEF(pj_status_t) pj_cli_console_readline(pj_cli_sess *sess, 
    161                                             char *buf, 
    162                                             unsigned maxlen) 
     837PJ_DEF(pj_status_t) pj_cli_console_process(pj_cli_sess *sess) 
    163838{ 
    164839    struct cli_console_fe *fe = (struct cli_console_fe *)sess->fe; 
    165840 
    166     PJ_ASSERT_RETURN(sess && buf, PJ_EINVAL); 
    167  
    168     fe->input.buf = buf; 
    169     fe->input.maxlen = maxlen; 
     841    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    170842 
    171843    if (!fe->input_thread) { 
    172844        pj_status_t status; 
    173845 
    174         status = pj_thread_create(fe->pool, NULL, &readline_thread, fe, 
     846        status = pj_thread_create(fe->pool, NULL, &readchar_thread, fe, 
    175847                                  0, 0, &fe->input_thread); 
    176848        if (status != PJ_SUCCESS) 
    177849            return status; 
    178850    } else { 
    179         /* Wake up readline thread */ 
     851        /* Wake up readchar thread */ 
    180852        pj_sem_post(fe->thread_sem); 
    181853    } 
Note: See TracChangeset for help on using the changeset viewer.