X-Git-Url: https://git.cryptolib.org/?a=blobdiff_plain;f=test_src%2Fcli.c;h=95b027215edaf495ce724af25af67eb0894544e4;hb=55961d766375e8415baf7bc1e74fe9ba087e18ad;hp=f01547d03ddf07200e9d0f5c9f7db005530437b6;hpb=3a571bf2d55c87a3d08641f7df7681c923717eb1;p=avr-crypto-lib.git diff --git a/test_src/cli.c b/test_src/cli.c index f01547d..95b0272 100644 --- a/test_src/cli.c +++ b/test_src/cli.c @@ -1,6 +1,6 @@ /* cli.c */ /* - This file is part of the Crypto-avr-lib/microcrypt-lib. + This file is part of the AVR-Crypto-Lib. Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) This program is free software: you can redistribute it and/or modify @@ -26,68 +26,405 @@ * **/ +#include #include +#include #include #include +#include "string-extras.h" +#include "cli.h" #include "config.h" +#include "hexdigit_tab.h" -int16_t findstring_d0(const char* str, const char* v){ - uint8_t i=0; - while(*v){ - if(!strcmp(str, v)){ - return i; +cli_rx_fpt cli_rx = NULL; +cli_tx_fpt cli_tx = NULL; +uint8_t cli_echo=1; + +/** + * \brief output a character to the console + * + */ + +void cli_putc(char c){ + if(cli_tx) + cli_tx(c); +} + +/** + * \brief get a character from the console + * Gets a character from the console input and blocks + * until a character is recieved + */ +uint16_t cli_getc(void){ + if(cli_rx) + return cli_rx(); + return ((uint16_t)-1); +} + +/** + * \brief get a character from the console + * Gets a char from the console input (like cli_getc()) + * and echos it back to the console if echo is enabled. + */ +uint16_t cli_getc_cecho(void){ + char c; + if(cli_rx){ + c = cli_rx(); + if(cli_tx && cli_echo) + cli_tx(c); + return c; + } + return ((uint16_t)-1); +} + +/** + * \brief ouputs a zero-terminated string from ram to the console + */ +void cli_putstr(const char* s){ + if(!cli_tx) + return; + while(*s) + cli_tx(*s++); +} + + +/** + * \brief ouputs a zero-terminated string from flash to the console + */ +void cli_putstr_P(PGM_P s){ + char c; + if(!cli_tx) + return; + for(;;){ + c = pgm_read_byte(s++); + if(!c) + return; + cli_tx(c); + } +} + +/** + * \brief reads a line or max n characters from the console + * Writes characters from the console into the supplyed buffer until a '\r' + * character is recieved or until n character a read (whatever happens first). + * The string will always be terminated by a '\0' character, so the buffer + * should have at least a size of n+1. + */ +uint8_t cli_getsn(char* s, uint16_t n){ + char c; + if(n==0) + return 2; + while((c=cli_getc_cecho())!='\0' && c!='\r' && n--){ + *s++=c; + } + *s='\0'; + return (c=='\r')?0:1; +} + +/** + * \brief dumps the contents of a buffer to the console + * Dumps length bytes from data to the console ouput. The dump + * will have 2*n continous hexadecimal characters. + */ +void cli_hexdump(const void* data, uint16_t length){ + if(!cli_tx) + return; + while(length--){ + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))>>4))); + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))&0xf))); + data = (uint8_t*)data +1; + } +} + +/** + * \brief dumps the contents of a buffer to the console + * This function behaves like cli_hexdump except that the + * bytes are dumped in reverse order. This is usefull to dump + * integers which ar e in little endian order. + */ +void cli_hexdump_rev(const void* data, uint16_t length){ + if(!cli_tx) + return; + data = (uint8_t*)data + length -1; + while(length--){ + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))>>4))); + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))&0xf))); + data = (uint8_t*)data -1; + } +} + +/** + * \brief dumps the contents of a buffer to the console + * Like cli_hexdump but bytes are seperated with a single space + * on the console output. + */ +void cli_hexdump2(const void* data, uint16_t length){ + if(!cli_tx) + return; + while(length--){ + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))>>4))); + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))&0xf))); + cli_tx(' '); + data = (uint8_t*)data +1; + } +} + +/** + * \brief dumps the contents of a buffer to the console + * Like cli_hexdump but bytes are seperated with a single space + * on the console output. + */ +void cli_hexdump_block(const void* data, uint16_t length, uint8_t indent, uint8_t width){ + uint16_t i; + uint8_t j; + if(!cli_tx) + return; + for(i=0; i>4))); + cli_tx(pgm_read_byte(hexdigit_tab_P +((*((uint8_t*)data))&0xf))); + cli_tx(' '); + data = (uint8_t*)data +1; } - return -1; } - -int16_t findstring_d0_P(const char* str, PGM_P v){ - uint8_t i=0; - while(pgm_read_byte(v)){ - if(!strcmp_P(str, v)){ - return i; + +static +void cli_auto_help(uint16_t maxcmdlength, PGM_VOID_P cmdlist){ + cmdlist_entry_t item; + uint16_t i; + if(!cli_tx) + return; + + cli_putstr_P(PSTR("\r\n[auto help] available commands:\r\n" + " - -
\r\n")); + for(;;){ + item.cmd_name = (void*)pgm_read_word(cmdlist+0); + item.cmd_param_str = (void*)pgm_read_word(cmdlist+2); + item.cmd_function = (void_fpt)pgm_read_word(cmdlist+4); + cmdlist = (uint8_t*)cmdlist+CMDLIST_ENTRY_SIZE; + if(item.cmd_name==NULL){ + return; + } + cli_tx(' '); + cli_putstr_P(item.cmd_name); + i=maxcmdlength-strlen_P(item.cmd_name); + while(i--) + cli_tx(' '); + cli_putstr_P(PSTR(" - ")); + if(item.cmd_param_str==NULL){ + cli_putstr_P(PSTR("none \t- 0x")); + } else { + if(item.cmd_param_str==(void*)1){ + cli_putstr_P(PSTR("yes \t- 0x")); + } else { + cli_putstr_P(item.cmd_param_str); + cli_putstr_P(PSTR(" \t- 0x")); + } } - while(pgm_read_byte(v++)) /* go to the next string */ - ; - ++i; + cli_hexdump_rev(&item.cmd_function, 2); + cli_putstr_P(PSTR("\r\n")); } - return -1; -} +} -#ifdef CLI_AUTO_HELP -#include "uart.h" +void echo_ctrl(char* s){ + s = strstrip(s); + if(s==NULL || *s=='\0'){ + cli_putstr_P(PSTR("\r\necho is ")); + cli_putstr_P(cli_echo?PSTR("on"):PSTR("off")); + cli_putstr_P(PSTR("\r\n")); + } + strlwr(s); + if(!strcmp_P(s, PSTR("true")) || !strcmp_P(s, PSTR("on")) || *s=='1'){ + cli_echo=1; + } + if(!strcmp_P(s, PSTR("false")) || !strcmp_P(s, PSTR("off")) || *s=='0'){ + cli_echo=0; + } +} -void cli_auto_help_P(PGM_P dbzstr){ - char c; - uart_putstr_P(PSTR("\r\n[auto help] available commands are:\r\n\t")); +typedef void(*str_fpt)(char*); +#define CLI_ENTER 13 +#define CLI_BACKSPACE 8 +#define CLI_TABULATOR 9 + +int8_t search_and_call(char* cmd, uint16_t maxcmdlength, PGM_VOID_P cmdlist){ + PGM_VOID_P cmdlist_orig = cmdlist; + if(*cmd=='\0' || *cmd=='#') + return 1; + if(!strcmp_P(cmd, PSTR("exit"))) + return 0; + if((!strcmp_P(cmd, PSTR("help"))) || (!strcmp_P(cmd, PSTR("?")))){ + cli_auto_help(maxcmdlength, cmdlist); + return 1; + } + uint16_t fwlength=firstword_length(cmd); + char fw[fwlength+1]; + memcpy(fw, cmd, fwlength); + fw[fwlength] = '\0'; + cmdlist_entry_t item; do{ - while((c=pgm_read_byte(dbzstr++))!=0){ - uart_putc(c); - } - uart_putstr_P(PSTR("\r\n\t")); - }while((c=pgm_read_byte(dbzstr))!=0); - uart_putstr_P(PSTR("\r\n")); + item.cmd_name = (void*)pgm_read_word(cmdlist+0); + item.cmd_param_str = (void*)pgm_read_word(cmdlist+2); + item.cmd_function = (void_fpt)pgm_read_word(cmdlist+4); + cmdlist = (uint8_t*)cmdlist+CMDLIST_ENTRY_SIZE; + }while(item.cmd_name!=NULL && strcmp_P(fw, item.cmd_name)); + if(item.cmd_name==NULL){ + cli_auto_help(maxcmdlength, cmdlist_orig); + } else { + if(item.cmd_function==NULL) + return 2; + switch((uint16_t)item.cmd_param_str){ + case 0: + item.cmd_function(); + break; + case 1: + if(cmd[fwlength]=='\0'){ + ((str_fpt)item.cmd_function)(cmd+fwlength); + } else { + ((str_fpt)item.cmd_function)(cmd+fwlength+1); + } + break; + default: + cli_putstr_P(PSTR("\r\nparam parsing currently not implemented!\r\n")); + break; + } + + } + return 1; } -#endif +uint16_t max_cmd_length(PGM_VOID_P cmdlist){ + uint16_t t,ret=0; + char* str; + for(;;){ + str = (char*)pgm_read_word(cmdlist); + cmdlist = (uint8_t*)cmdlist + CMDLIST_ENTRY_SIZE; + if(str==NULL) + return ret; + t = strlen_P(str); + if(t>ret) + ret=t; + } +} -int16_t execcommand_d0_P(const char* str, PGM_P v, void(*fpt[])(void) ){ +uint8_t cli_completion(char* buffer, uint16_t maxcmdlength, PGM_VOID_P cmdlist){ uint8_t i=0; - PGM_P commands=v; - while(pgm_read_byte(v)){ - if(!strcmp_P(str, v)){ - (fpt[i])(); - return i; + char ref[maxcmdlength+1]; + char* itemstr; + ref[0]='\0'; + /* check if we are behind the first word */ + while(buffer[i]){ + if(!isgraph(buffer[i++])) + return 0; + } + for(;;){ + itemstr = (char*)pgm_read_word(cmdlist); + if(itemstr==NULL) + break; + cmdlist = (uint8_t*)cmdlist +CMDLIST_ENTRY_SIZE; + if(!strncmp_P(buffer, itemstr, i)){ + if(!ref[0]){ + strcpy_P(ref, itemstr); + }else{ + ref[stridentcnt_P(ref, itemstr)]='\0'; + } } - while(pgm_read_byte(v++)) /* go to the next string */ - ; - ++i; } - cli_auto_help_P(commands); - return -1; + i = strcmp(buffer, ref); + if(i) + strcpy(buffer, ref); + return ~i; } +void cli_option_listing(char* buffer, PGM_VOID_P cmdlist){ + char* itemstr; + uint16_t len=strlen(buffer); + for(;;){ + itemstr = (char*)pgm_read_word(cmdlist); + if(itemstr==NULL){ + cli_putstr_P(PSTR("\r\n>")); + cli_putstr(buffer); + return; + } + cmdlist = (uint8_t*)cmdlist +CMDLIST_ENTRY_SIZE; + if(!strncmp_P(buffer, itemstr, len)){ + cli_putstr_P(PSTR("\r\n ")); + cli_putstr_P(itemstr); + } + } +} +int8_t cmd_interface(PGM_VOID_P cmd_desc){ + uint16_t cli_buffer_size; + uint16_t cli_buffer_index; + int8_t exit_code; + uint8_t completion_failed=0; + char* cli_buffer; + char c; + uint16_t maxcmdlength = max_cmd_length(cmd_desc); + cli_buffer = calloc(1,cli_buffer_size=maxcmdlength+2); + cli_buffer_index=0; + if(!cli_rx) + return -1; + if(cli_tx) + cli_tx('>'); + for(;;){ + c = cli_rx(); + switch (c){ + case CLI_ENTER: + if((exit_code=search_and_call(cli_buffer, maxcmdlength, cmd_desc))<=0){ + free(cli_buffer); + return exit_code; + } + memset(cli_buffer, 0, cli_buffer_size); + cli_buffer_index=0; + cli_putstr_P(PSTR("\r\n>")); + completion_failed=0; + break; + case CLI_BACKSPACE: + completion_failed=0; + if(cli_buffer_index==0) + break; + cli_buffer_index--; + cli_buffer[cli_buffer_index] = '\0'; + if(cli_echo && cli_tx){ + cli_tx(c); + } + break; + case CLI_TABULATOR: + if(completion_failed || cli_buffer_index==0){ + if(cli_tx) + cli_option_listing(cli_buffer, cmd_desc); + } else { + uint16_t old_idx = cli_buffer_index; + completion_failed = + ~cli_completion(cli_buffer, maxcmdlength, cmd_desc); + cli_buffer_index = strlen(cli_buffer); + if(cli_echo && cli_tx){ + while(old_idx