Add working prototype

This commit is contained in:
Tilen Majerle 2021-04-07 23:58:58 +02:00
parent a8d60f1159
commit f5265fa1ff
4 changed files with 238 additions and 10 deletions

View File

@ -3,8 +3,35 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
int int32_t
main(void) { addint_cmd(int32_t argc, char** argv) {
printf("ADDINT CMD, args: %d\r\n", argc);
for (size_t i = 0; i < argc; ++i) {
printf("Arg %d: %s\r\n", (int)i, argv[i]);
}
return 0;
}
int
main(void) {
lwshell_init();
lwshell_register_cmd("addint", addint_cmd, "Adds int between 2 arguments");
/* User input to process every character */
printf("Start entering your text and press enter...\r\n");
while (1) {
char c = getch();
if (c == '\b') {
printf("\b \b");
} else {
printf("%c", c);
}
if (c == '\r') {
printf("\n");
}
/* Now insert input */
lwshell_input(&c, 1);
}
return 0; return 0;
} }

View File

@ -59,20 +59,29 @@ extern "C" {
*/ */
typedef enum { typedef enum {
lwshellOK = 0x00, /*!< Everything OK */ lwshellOK = 0x00, /*!< Everything OK */
lwshellERRPAR, /*!< Parameter error */
lwshellERRMEM, /*!< Memory error */
} lwshellr_t; } lwshellr_t;
/** /**
* *
*/ */
typedef int32_t(*lwshell_cmd_fn)(int32_t argc, const char** argv); typedef int32_t(*lwshell_cmd_fn)(int32_t argc, char** argv);
/** /**
* \brief LwSHELL main structure * \brief LwSHELL main structure
*/ */
typedef struct lwshell { typedef struct lwshell {
uint8_t res; char buff[LWSHELL_CFG_MAX_INPUT_LEN + 1]; /*!< Shell command input buffer */
size_t buff_ptr; /*!< Buffer pointer for input */
int32_t argc; /*!< Number of arguments parsed in command */
char* argv[LWSHELL_CFG_MAX_CMD_ARGS]; /*!< Array of all arguments */
} lwshell_t; } lwshell_t;
lwshellr_t lwshell_init(void);
lwshellr_t lwshell_register_cmd(const char* cmd_name, lwshell_cmd_fn cmd_fn, const char* desc);
lwshellr_t lwshell_input(const void* in_data, size_t len);
/** /**
* \} * \}
*/ */

View File

@ -61,13 +61,13 @@ extern "C" {
#endif #endif
/** /**
* \brief Maximum characters for command line length. * \brief Maximum characters for command line input
* *
* This includes new line character and trailing zero. * This includes new line character and trailing zero.
* Commands longer than this are automatically discarded * Commands longer than this are automatically discarded
*/ */
#ifndef LWSHELL_CFG_MAX_CMD_LEN #ifndef LWSHELL_CFG_MAX_INPUT_LEN
#define LWSHELL_CFG_MAX_CMD_LEN 128 #define LWSHELL_CFG_MAX_INPUT_LEN 128
#endif #endif
/** /**

View File

@ -32,16 +32,208 @@
* Version: $_version_$ * Version: $_version_$
*/ */
#include <string.h> #include <string.h>
#include <stdio.h>
#include "lwshell/lwshell.h" #include "lwshell/lwshell.h"
/* Default characters */
#define LWSHELL_ASCII_NULL 0x00 /*!< Null character */
#define LWSHELL_ASCII_BELL 0x07 /*!< Bell (\a) */
#define LWSHELL_ASCII_BACKSPACE 0x08 /*!< Backspace */
#define LWSHELL_ASCII_TAB 0x09 /*!< Horizontal tab */
#define LWSHELL_ASCII_LF 0x0A /*!< Line feed */
#define LWSHELL_ASCII_CR 0x0D /*!< Carriage return */
#define LWSHELL_ASCII_ESC 0x1B /*!< Escape */
#define LWSHELL_ASCII_DEL 0x7F /*!< Delete character */
#define LWSHELL_ASCII_US 0x1F /*!< Unit separator */
#define LWSHELL_ASCII_SPACE 0x20 /*!< Space character */
/** /**
* \brief Shell command structure * \brief Shell command structure
*/ */
typedef struct { typedef struct {
lwshell_cmd_fn cmd_fn; /*!< Command function to call on match */ lwshell_cmd_fn fn; /*!< Command function to call on match */
char cmd_name[LWSHELL_CFG_MAX_CMD_NAME_LEN + 1]; /*!< Command name to search for match */ const char* name; /*!< Command name to search for match */
const char* desc; /*!< Command description for help */
#if 0
char cmd_name[LWSHELL_CFG_MAX_CMD_NAME_LEN + 1];
#endif /* 0 */
} lwshell_cmd_t; } lwshell_cmd_t;
/* Array of all commands */ /* Array of all commands */
static lwshell_cmd_t cmds[LWSHELL_CFG_MAX_CMDS]; static lwshell_cmd_t cmds[LWSHELL_CFG_MAX_CMDS];
static size_t cmds_cnt; static size_t cmds_cnt;
static lwshell_t shell;
/**
* \brief Get shell from input
*/
#define LWSHELL_GET_LW(lw) ((lw) != NULL ? (lw) : (&shell))
#define LWSHELL_ADD_CH(lw, ch) do { \
if ((lw)->buff_ptr < (LWSHELL_ARRAYSIZE(lw->buff) - 1)) { \
(lw)->buff[(lw)->buff_ptr] = ch; \
(lw)->buff[++(lw)->buff_ptr] = '\0'; \
} \
} while (0)
#define LWSHELL_RESET_BUFF(lw) do { \
memset((lw)->buff, 0x00, sizeof((lw)->buff)); \
memset((lw)->argv, 0x00, sizeof((lw)->argv)); \
(lw)->buff_ptr = 0; \
} while (0)
/**
* \brief Parse input string
* \param[in] lw: LwSHELL instance
*/
static void
prv_parse_input(lwshell_t* lw) {
size_t s_len;
char ch, prev_ch;
char* str;
lw = LWSHELL_GET_LW(lw);
/* Check string length and compare */
s_len = strlen(lw->buff);
if (lw->buff_ptr != s_len) {
return;
}
/* Must be more than `1` character since we have to include end of line */
if (lw->buff_ptr > 0) {
uint8_t in_quote = 0;
/* Set default values */
lw->argc = 0;
lw->argv[0] = lw->buff;
/* Process complete input */
prev_ch = '\0';
str = lw->buff;
/* Process complete string */
lw->argc = 0;
while (*str != '\0') {
while (*str == ' ' && ++str) {} /* Remove leading spaces */
if (*str == '\0') {
break;
}
/* Check if it starts with quote to handle escapes */
if (*str == '"') {
++str;
lw->argv[lw->argc++] = str; /* Set start of argument after quotes */
/* Process until end of quote */
while (*str != '\0') {
if (*str == '\\') {
++str;
if (*str == '"') {
++str;
}
} else if (*str == '"') {
*str = '\0';
++str;
break;
} else {
++str;
}
}
} else {
lw->argv[lw->argc++] = str; /* Set start of argument directly on character */
while ((*str != ' ' && *str != '\0') && ++str) {}
*str = '\0';
++str;
}
/* Check for number of arguments */
if (lw->argc == LWSHELL_ARRAYSIZE(lw->argv)) {
break;
}
}
/* Check for command */
if (lw->argc > 0 && cmds_cnt > 0) {
/* Process all commands */
for (size_t i = 0; i < cmds_cnt; ++i) {
if (strcmp(cmds[i].name, lw->argv[0]) == 0) {
cmds[i].fn(lw->argc, lw->argv);
}
}
}
} else {
printf("Invalid input\r\n");
}
}
/**
* \brief Initialize shell interface
* \return \ref lwshellOK on success, member of \ref lwshellr_t otherwise
*/
lwshellr_t
lwshell_init(void) {
lwshell_t* lw = LWSHELL_GET_LW(NULL);
memset(lw, 0x00, sizeof(*lw));
return lwshellOK;
}
lwshellr_t
lwshell_register_cmd(const char* cmd_name, lwshell_cmd_fn cmd_fn, const char* desc) {
/* Check for memory available */
if (cmds_cnt < LWSHELL_ARRAYSIZE(cmds)) {
cmds[cmds_cnt].name = cmd_name;
cmds[cmds_cnt].fn = cmd_fn;
cmds[cmds_cnt].desc = desc;
++cmds_cnt;
return lwshellOK;
}
return lwshellERRMEM;
}
/**
* \brief Input data to shell processing
* \param[in] in_data: Input data to process
* \param[in] len: Length of data for input
* \return \ref lwshellOK on success, member of \ref lwshellr_t otherwise
*/
lwshellr_t
lwshell_input(const void* in_data, size_t len) {
const char* d = in_data;
lwshell_t* lw = LWSHELL_GET_LW(NULL);
if (in_data == NULL || len == 0) {
return lwshellERRPAR;
}
/* Process all bytes */
for (size_t i = 0; i < len; ++i) {
switch (d[i]) {
case LWSHELL_ASCII_CR: {
prv_parse_input(lw);
LWSHELL_RESET_BUFF(lw);
break;
}
case LWSHELL_ASCII_LF: {
prv_parse_input(lw);
LWSHELL_RESET_BUFF(lw);
break;
}
case LWSHELL_ASCII_BACKSPACE: {
/* Try to delete character from buffer */
if (lw->buff_ptr > 0) {
lw->buff[lw->buff_ptr] = '\0';
--lw->buff_ptr;
}
break;
}
default: {
if (d[i] >= 0x20 && d[i] < 0x7F) {
LWSHELL_ADD_CH(lw, d[i]);
}
}
}
}
return lwshellOK;
}