#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; 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; inext) { 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; iargc; 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; iargc; 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;ihistory[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