diff options
Diffstat (limited to 'cmd/cmd.c')
-rw-r--r-- | cmd/cmd.c | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/cmd/cmd.c b/cmd/cmd.c new file mode 100644 index 0000000..f743a7f --- /dev/null +++ b/cmd/cmd.c @@ -0,0 +1,721 @@ +#include "cmd.h" +#include "cmd_parse.h" + +cmd_tok_t* cmd_tok_create( char *s, char *e, int sz, int type ) +{ + cmd_tok_t *ret = NULL; + + ret = malloc( sizeof(cmd_tok_t) ); + if ( ret == NULL ) + return ret; + + memset( ret, 0, sizeof(cmd_tok_t) ); + + ret->s = s; + ret->e = e; + ret->sz = sz; + ret->type = type; + ret->next = NULL; //no need, but sec programming says we need it + + return ret; +} + + +int cmd_tok_add( cmd_tok_t *tok, cmd_tok_t *next ) +{ + int ret = 0; + + if ( tok == NULL ) + { + return -1; + } + + if ( next == NULL ) + { + return -1; + } + + if ( tok->next != NULL ) + { + printf("next token allready set\n"); + return -1; + } + + tok->next = next; + + return ret; +} + + +int cmd_tok_print( cmd_tok_t *tok ) +{ + int ret = 0; + + printf("TOK %p\n",tok); + if (tok) + { + printf("S:%p E:%p SZ:%d \n", tok->s, tok->e, tok->sz); + printf("TYPE: "); + switch (tok->type) + { + case CMDT_NONE: + printf("NONE"); + break; + case CMDT_INT: + printf("INT"); + break; + case CMDT_HEX: + printf("HEX"); + break; + case CMDT_BIN: + printf("BIN"); + break; + case CMDT_STR: + printf("STR"); + break; + case CMDT_WORD: + printf("WORD"); + break; + case CMDT_SP: + printf("SP"); + break; + case CMDT_FLOAT: + printf("FLOAT"); + break; + default: + printf("UNKNOWN"); + } + printf("\n"); + printf("NEXT: %p\n", tok->next ); + } + + return ret; +} + + +void cmd_tok_destroy( cmd_tok_t *tok ) +{ + cmd_tok_t *t=NULL, *n=NULL; + + if (tok == NULL) + { + return; + } + + if ( tok->next == NULL ) + { + free( tok ); + return; + } + + t = tok; + n = t; + while ( n != NULL) + { + n = t->next; + t->next = NULL; + free(t); + t = n; + } +} + + +int cmd_tok_count( cmd_tok_t *tok ) +{ + int ret = 0; + cmd_tok_t *iter = NULL; + + if (tok == NULL) + return 0; + + iter = tok; + while( iter != NULL ) + { + ret += 1; + iter = iter->next; + } + + return ret; +} + + + +cmd_arg_t* cmd_arg_create( cmd_tok_t *tok ) +{ + cmd_arg_t *ret = NULL; + int argc = -1; + cmd_tok_t *iter = NULL; + int i = 0; + + ret = malloc( sizeof(cmd_arg_t) ); + if ( ret == NULL ) + { + return NULL; + } + memset( ret, 0, sizeof( cmd_arg_t )); + + //get number of arguments in command line + argc = cmd_tok_count( tok ); + ret->argc = argc; + + + //alloc mem for argument string values + ret->argv = malloc( sizeof(int*)*argc ); + if ( ret->argv == NULL ) + { + //printf("ERR:err_malloc_argv\n"); + goto err_malloc_argv; + } + memset( ret->argv, 0, sizeof(int*)*argc ); + + //alloc mem for argument type values + ret->type = malloc( sizeof(int)*argc ); + if ( ret->type == NULL ) + { + //printf("ERR:err_malloc_type\n"); + goto err_malloc_type; + } + memset( ret->type, 0, sizeof(int)*argc ); + + //create for each cmd token string and set type + iter = tok; + for (i=0; i<argc; i++,iter=iter->next) + { + ret->argv[i] = malloc( iter->sz+1 ); + memcpy(ret->argv[i], iter->s, iter->sz ); + ret->argv[i][iter->sz] = 0x0; + ret->type[i] = iter->type; + } + + return ret; + +err_malloc_type: + free( ret->argv ); +err_malloc_argv: + free( ret ); + return NULL; +} + + +cmd_arg_t* cmd_arg_sub( cmd_arg_t *arg ) +{ + cmd_arg_t *ret = NULL; + + int i=0; + + if ( arg == NULL ) + return NULL; + + if ( arg->argc == 1 ) + { + ret = cmd_arg_sub_empty(); + return ret; + } + + ret = malloc( sizeof(cmd_arg_t) ); + + ret->argc = arg->argc-1; + + ret->type = malloc(sizeof(int)*(arg->argc-1)); + memset(ret->type, 0, sizeof(int)*(arg->argc-1) ); + + ret->argv = malloc( sizeof(char*)*(arg->argc-1) ); + memset(ret->argv, 0, sizeof(char*)*(arg->argc-1) ); + + ret->__sub_cmd = 1; + + for (i=0; i<ret->argc; i++) + { + ret->argv[i] = arg->argv[i+1]; + ret->type[i] = arg->type[i+1]; + } + + return ret; +} + + +cmd_arg_t* cmd_arg_sub_empty() +{ + cmd_arg_t *ret = NULL; + + ret = malloc( sizeof(cmd_arg_t) ); + ret->argc = 0; + ret->argv = NULL; + ret->type = NULL; + ret->__sub_cmd = 1; + + return ret; +} + +void cmd_arg_destroy( cmd_arg_t *arg ) +{ + int i; + + if ( arg == NULL ) + return; + + for ( i=0; i<arg->argc; i++) + { + if ( arg->__sub_cmd == 0 ) + free( arg->argv[i] ); + } + + free( arg->argv ); + + free( arg->type ); + + free( arg ); +} + +int cmd_exec( cmd_table_t *tbl, cmd_arg_t *arg ) +{ + int ret = -1; + int fret = 0; + int pret = 0; //pre condition return + int i; + + cmd_arg_t *sub_arg = NULL; + + //there could be 0 arguments + if ( arg->argc < 0 ) + { + printf("Hm ... no arguments\n"); + return -1; + } + + if ( arg->argc == 0 ) + return 0; + + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + //printf("tbl.cmd %s\n", tbl[i].cmd ); + if ((strlen(tbl[i].cmd) == strlen(arg->argv[0])) //if there is 0 args then here could be non-0 and we get troubles + && (strlen(tbl[i].cmd) != 0)) //combo if + if ( strncmp( tbl[i].cmd, arg->argv[0], strlen(arg->argv[0]) ) == 0 ) + { + //never will exec becouse of statment in while + if ( tbl[i].clb == NULL ) + { + printf("Empty callback %s\n", tbl[i].cmd); + ret = -1; + break; + } + + sub_arg = cmd_arg_sub( arg ); + //execute callback preconditions + if (tbl[i].pre != NULL) + { + pret = tbl[i].pre( sub_arg ); + } else { + pret = 0; //no precond just pass + } + if (pret == 0) + { + //execute callback + fret = tbl[i].clb( sub_arg ); + } + + //if command whent wrong or not still clean mem + if ( sub_arg != NULL ) + { + cmd_arg_destroy( sub_arg ); + } + + //command execution precondtions met but wrong execution + if ( pret == 0 ) + { + //command execution whent wrong lets go out + if ( fret != 0 ) + { + printf("Command broken execution\n"); + ret = -1; + break; + } + } + ret = 0; //succesfull execution + break; + } + + i++; + } + + return ret; +} + +int cmd_exec_ev( cmd_table_t *tbl, cmd_arg_t *arg, int event ) +{ + int ret = -1; + int fret = 0; + int i; + + cmd_arg_t *sub_arg = NULL; + + if ( arg->argc < 1 ) + { + printf("Hm ... no arguments\n"); + return -1; + } + + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + //printf("tbl.cmd %s\n", tbl[i].cmd ); + if ((strlen(tbl[i].cmd) == strlen(arg->argv[0])) //if there is 0 args then here could be non-0 and we get troubles + && (strlen(tbl[i].cmd) != 0)) //combo if + if ( strncmp( tbl[i].cmd, arg->argv[0], strlen(arg->argv[0]) ) == 0 ) + { + //never will exec becouse of statment in while + if ( tbl[i].clb == NULL ) + { + printf("Empty callback %s\n", tbl[i].cmd); + ret = -1; + break; + } + + sub_arg = cmd_arg_sub( arg ); + + if ( sub_arg == NULL ) + sub_arg = cmd_arg_sub_empty(); + + fret = tbl[i].clb( sub_arg ); + + //if command whent wrong or not still clean mem + if ( sub_arg != NULL ) + { + cmd_arg_destroy( sub_arg ); + } + + //command execution whent wrong lets go out + if ( fret != 0 ) + { + printf("Command broken execution\n"); + ret = -1; + break; + } + ret = 0; + break; + } + + i++; + } + + + return ret; +} + +/* +For now support only first command autocomplete, and return first cmd +RETURN: string to command, dont modify it +*/ +char* cmd_ac( cmd_table_t *tbl, const char *s ) +{ + char *ret = NULL; + int i = -1; + int idx = -1, match=-1;//best match + int ret_match; + int str_ac_sz = strlen(s); + + + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + ret_match = strncmp_ac( s, tbl[i].cmd, str_ac_sz ); + if (ret_match > 0) + { + if (ret_match == str_ac_sz+1) + { + idx = i; + break; + } else + { + if (ret_match > match) + { + idx = i; + match = ret_match; + } + } + } + i++; + } + + if ( idx >= 0 ) + { + ret = tbl[idx].cmd; + } + + return ret; +} + +struct cmd_acq_head_t* cmd_acq( cmd_table_t *tbl, const char *s ) +{ + struct cmd_acq_head_t *ret = NULL; + + int i = -1; + int ret_match; + int str_ac_sz = strlen(s); + + struct cmd_acq_head_t *ac = malloc(sizeof(struct cmd_acq_t)); + + SLIST_INIT(ac); + i = 0; + while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) + { + ret_match = strncmp_ac( s, tbl[i].cmd, str_ac_sz ); + if (ret_match > 0) + { + //found 100% match + if (ret_match == str_ac_sz+1) + { + PRINT("Unknown state\n"); + break; + //partial match + } else + { + struct cmd_acq_t *acq = malloc(sizeof(struct cmd_acq_t)); + acq->suggestion = tbl[i].cmd; + SLIST_INSERT_HEAD(ac,acq,next_sugg); + } + } + i++; + } + + ret = ac; + + return ret; +} + +void cmd_acq_free( struct cmd_acq_head_t *acq ) +{ + struct cmd_acq_t *iter; + struct cmd_acq_t *prev; + + prev = NULL; + iter = NULL; + SLIST_FOREACH(iter,acq,next_sugg) + { + if ( prev != NULL ) + { + free( prev ); + prev = NULL; + } + prev = iter; + } + + return; +} + +char* cmd_mng_history( cmd_mng_t *cmng, int index ) +{ + int idx; + char *ret=NULL; + + if (cmng == NULL) + { + return NULL; + } + + if (cmng->history_size < CMD_HISTORY_SIZE) + { + if (index < cmng->history_size) + { + ret = cmng->history[index]; + } + } else + { + idx = (cmng->history_size-CMD_HISTORY_SIZE+index)%CMD_HISTORY_SIZE; + ret = cmng->history[idx]; + } + + return ret; +} + +char* cmd_mng_autocomplete( cmd_mng_t *cmng, char *cmd, size_t cmd_sz ) +{ + char *ret=NULL; + + cmd_arg_t *args; + cmd_tok_t tl, *ptr = &tl, *iter = NULL; + cmd_table_t *tab = cmng->table; + struct cmd_acq_t *iter_sugg = NULL; + int ac_sz=0,cnt_sz=0; + char *ac_str; + memset( &tl, 0, sizeof( cmd_tok_t )); + + if ( parse_cmd(ptr, cmd, cmd_sz) == -1) + { + printf("Cmd problems\n"); + return NULL; + } + + iter = ptr->next; + args = cmd_arg_create( iter ); + + //if command not found offer auto complete options + if (args->argc > 0) + { + struct cmd_acq_head_t *ac = cmd_acq(tab,args->argv[0]); + if (ac != NULL) + { + //calculate string str + SLIST_FOREACH(iter_sugg,ac,next_sugg) + { + //printf("%s ", iter_sugg->suggestion); + ac_sz += strlen(iter_sugg->suggestion)+1; //1 for " " + } + ac_sz += 2; //"> " + ac_sz += 1; //"\0" + + ac_str = (char *)malloc(ac_sz); + + memcpy( ac_str, "> ", 2 ); + cnt_sz = 2; + cnt_sz = 0; + SLIST_FOREACH(iter_sugg,ac,next_sugg) + { + //double logical usage + ac_sz = strlen(iter_sugg->suggestion); + memcpy( ac_str+cnt_sz, iter_sugg->suggestion, ac_sz); + cnt_sz += ac_sz; + ac_str[cnt_sz] = ' '; + cnt_sz += 1; + } + ac_str[cnt_sz] = '\0'; + ret = ac_str; + } + cmd_acq_free( ac ); + } + + cmd_tok_destroy( ptr->next ); + ptr->next = NULL; + cmd_arg_destroy( args ); + + return ret; +} + +int cmd_mng_exec( cmd_mng_t *cmng, const char *cmd, size_t sz_cmd ) +{ + int ret = CMD_EOK; + int fret = 0; + cmd_tok_t tl, *ptr_tl = &tl, *iter = NULL; + cmd_arg_t *args = NULL; + + // Init values + memset( &tl, 0, sizeof( cmd_tok_t )); + + fret = parse_cmd( ptr_tl, cmd, sz_cmd ); + if ( fret != 0 ) + { + ret = CMD_EEXE; + goto error_exe; //if err memleak from parse_cmd? + } + + iter = ptr_tl->next; + args = cmd_arg_create( iter ); + cmd_tok_destroy( ptr_tl->next ); + ptr_tl->next = NULL; + + if (cmd_exec(cmng->table, args) != 0) + { + ret = CMD_ECMD; + goto error_cmd; + } + + /* if history is on then manage commands */ + if (cmng->flag_history) + { + /*replace with proper datatype in future*/ + char *p = malloc(sz_cmd); + int idx = (cmng->history_size)%CMD_HISTORY_SIZE; + memcpy(p,cmd,sz_cmd); + if (cmng->history[idx]!=NULL) free(cmng->history[idx]); + cmng->history[idx] = p; + cmng->history_size += 1; //one day there could be overflow after 2^31/2^63 cmds, good luck with this bug + } + + cmd_arg_destroy( args ); + + return ret; +error_cmd: + cmd_arg_destroy( args ); + +error_exe: + + return ret; +} + +int cmd_mng_free( cmd_mng_t *cmng) +{ + int ret=0; + int i; + + for (i=0;i<CMD_HISTORY_SIZE;i++) + { + if (cmng->history[i]) + { + free(cmng->history[i]); + cmng->history[i] = NULL; + } + } + + return ret; +} + +/* +Clothest match function +AA AB = (1) equile <100% +AA AA = (3) equite 100% +AA AAA = (2) equile 100% but there is more +A B = (0) not equile at all +*/ +int strncmp_ac(const char *s1, const char *s2, const int n) +{ + int i=0; + + if (n<0) + { + printf("n<0 wrong argument value\n"); + return 0; + } + + /* not equile at all */ + /* A B */ + if ( s1[0] != s2[0] ) + { + return 0; + } + + i = 0; + while ( (s1[i] == s2[i]) && (i<n)) + { + i++; + } + + //printf("i"); + /* AA AA */ + if ( (s1[i]==0x00) && (s2[i]==0x0) && (i==n) ) + { + //printf("1 "); + return i+1; + /* AA AAA */ + } else if ( (s1[i]==0x0) && (s2[i]!=0x0) && (i==n) ) + { + //printf("2 "); + return i; + /* AAA AA */ + } else if ( (s1[i]!=0x0) && (s2[i]==0x0) && (i<n) ) + { + //printf("3 "); + return -i; + /* AA AB */ + } else if ( (s1[i]!=0x0) && (s2[i]!=0x0) && (s1[i]!=s2[i]) && (i<n) ) + { + //printf("4 "); + return -i; + } else + { + printf("Unknown condition\n"); + } + + return 0; +}
\ No newline at end of file |