From 1a92ed5075aba4b41fe34422d21a2c66cdf1d4c9 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 24 May 2024 17:47:00 +0200 Subject: WIP `send` command --- client/CMakeLists.txt | 1 + client/cmd.cpp | 58 ++++++++++++++++++++++++++++++++++++++------------- client/cmd.h | 10 ++++----- client/parse.cpp | 32 ++++++++++++++++++++++++++++ client/parse.h | 38 +++++++++++++++++++++++++++++++++ client/rl.cpp | 47 ++++++++++++++++++++++------------------- 6 files changed, 145 insertions(+), 41 deletions(-) create mode 100644 client/parse.cpp create mode 100644 client/parse.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c526345..35a55b6 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(pbc rl.cpp sock.cpp cmd.cpp + parse.cpp ) target_link_libraries(pbc diff --git a/client/cmd.cpp b/client/cmd.cpp index 0a73dad..4a2c8a3 100644 --- a/client/cmd.cpp +++ b/client/cmd.cpp @@ -4,6 +4,12 @@ #include "cmd.h" #include "sock.h" +#include "parse.h" + +char* consume_token(char* input, const char* ifs) { + strtok(input, ifs); + return strtok(NULL, "\0"); +} void cmd_exit(char*) { exit(EXIT_SUCCESS); @@ -11,22 +17,46 @@ void cmd_exit(char*) { void cmd_test(char*) { const char* data = "Hello world!"; - i2c_send(0x39, (char*) data, strlen(data)); + i2c_send(0x39, data, strlen(data)); } void cmd_help(char*) { - printf("List of available commands:\n"); - for (size_t i = 0; i < cmds_length; i++) { - struct cmd cmd = cmds[i]; - printf(" %-*s", 10, cmd.name); - if (cmd.info != NULL) - printf(" %s", cmd.info); - printf("\n"); - } - - printf( - "\n" - "You can also use the TAB key to autocomplete commands\n" - ); + printf("List of available commands:\n"); + for (size_t i = 0; i < cmds_length; i++) { + struct cmd cmd = cmds[i]; + printf(" %-*s", 10, cmd.name); + if (cmd.info != NULL) + printf(" %s", cmd.info); + printf("\n"); + } + + printf( + "\n" + "You can also use the TAB key to autocomplete commands\n" + ); +} + +void cmd_send(char* addr_str) { + char* data_str = consume_token(addr_str, IFS); + + char* end; + uint16_t addr = strtol(addr_str, &end, 0); + if (addr_str + strlen(addr_str) != end) { + printf("address format error\n"); + return; + } + + char* data; + size_t data_size; + if (strtodata(data_str, &data, &data_size)) { + printf("data format error at index %d:\n%s\n%*s^\n", + (int) data_size, data_str, (int) data_size, ""); + return; + } + + // printf("(0x%02x) -> \"%.*s\"\n", addr, data_size, data); + i2c_send(addr, data, data_size); + + free(data); } diff --git a/client/cmd.h b/client/cmd.h index 7ec67fc..9d20328 100644 --- a/client/cmd.h +++ b/client/cmd.h @@ -35,11 +35,11 @@ static const struct cmd cmds[] = { .name = "help", .info = "show this help", }, - // { - // .handle = cmd_send, - // .name = "send", - // .info = "[debug] send raw message", - // }, + { + .handle = cmd_send, + .name = "send", + .info = "[debug] send raw message", + }, // { // .handle = cmd_status, // .name = "status", diff --git a/client/parse.cpp b/client/parse.cpp new file mode 100644 index 0000000..d15207c --- /dev/null +++ b/client/parse.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include "parse.h" + +static unsigned ifsrun(const char* input, const char* ift) { + unsigned i; + for (i = 0; input[i] != '\0' && strchr(ift, input[i]); i++); + return i; +} + +int strtodata(const char* str, char** data, size_t* size) { + const char* ifs = IFS; + *size = 0; + size_t i; + size_t str_len = strlen(str); + + // TODO: finish this parser + // for (i = 0; i < str_len; i++) { + // unsigned ifs_run = ifsrun(&str[i], ifs); + // + // } + + *size = str_len; + + *data = (char*) malloc(*size); + + memcpy(*data, str, *size); + + return 0; +} + diff --git a/client/parse.h b/client/parse.h new file mode 100644 index 0000000..ac06446 --- /dev/null +++ b/client/parse.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#define IFS " \t\n" + +/** + * \brief modify \p token to point to the first token when broken up on \p ifs + * and return the remaining data + * + * \p token will be null-terminated to indicate the end of the first token. A + * pointer to the remaining line after the NULL byte is returned, or NULL when + * the end of the string has been reached. + * + * \param token input string + * \param ifs string containing field separators + * + * \return the remaining data after \p token and the first \p ifs + */ +char* consume_token(char* token, const char* ifs); + +/** + * \brief convert string with literals into raw data + * + * \param str input string containing literals + * \param data pointer to \c char* that will store the resulting data + * \param size size of \p data + * + * \return 0 if the string was parsed succesfully, or 1 if the string could not + * be parsed succesfully + * + * \note The pointer that \p data refers to will not be initialized by this + * function if parsing fails + * \note \p size will contain the index of \p str where the first invalid data + * was found if parsing fails + */ +int strtodata(const char* str, char** data, size_t* size); + diff --git a/client/rl.cpp b/client/rl.cpp index 6073500..3f93e99 100644 --- a/client/rl.cpp +++ b/client/rl.cpp @@ -8,13 +8,14 @@ #include "rl.h" #include "cmd.h" +#include "parse.h" void rl_printf(const char *fmt, ...) { // save line char* saved_line = rl_copy_text(0, rl_end); int saved_point = rl_point; int saved_end = rl_end; - + // clear line rl_save_prompt(); rl_replace_line("", 0); @@ -36,34 +37,38 @@ void rl_printf(const char *fmt, ...) { free(saved_line); } -static bool cli_cmd(char* line) { - char* cmd = strtok(line, " \t\n"); +static void cli_cmd(char* cmd) { + char* line = consume_token(cmd, IFS); + for (size_t i = 0; i < cmds_length; i++) { - if (strncmp(cmds[i].name, cmd, strlen(cmd)) != 0) continue; + if (strncmp(cmds[i].name, cmd, strlen(cmd)) != 0) + continue; + cmds[i].handle(line); - return true; + return; } - return false; + + printf("unknown command!\n"); } static char* rl_completion_entries(const char *text, int state) { - static size_t i = 0; - if (state == 0) i = 0; - - while (i < cmds_length) { - struct cmd cmd = cmds[i]; - i++; - if (strncmp(text, cmd.name, strlen(text)) == 0) { - return strdup(cmd.name); - } - } - - return NULL; + static size_t i = 0; + if (state == 0) i = 0; + + while (i < cmds_length) { + struct cmd cmd = cmds[i]; + i++; + if (strncmp(text, cmd.name, strlen(text)) == 0) { + return strdup(cmd.name); + } + } + + return NULL; } int cli_main() { char* input = NULL; - rl_completion_entry_function = rl_completion_entries; + rl_completion_entry_function = rl_completion_entries; while (1) { if (input != NULL) free(input); @@ -73,9 +78,7 @@ int cli_main() { if (*input == '\0') continue; // ignore empty lines add_history(input); - if (cli_cmd(input)) continue; - - printf("unknown command!\n"); + cli_cmd(input); } return EXIT_SUCCESS; -- cgit v1.2.3