Here I present sample arduino micro-application with
Shell really is tiny and used only ~850 bytes of microcontroller code. Shell don't use malloc and use line parsing “in-place”.
Well, if in truth, I wrote this code for the toys of my youngest son
We can add own function call. The agreement about the called functions is very simple:
uint8_t*
int16_t
The syntax of the shell is also simple:
command [arg [arg]];
where arg can be string or signed/unsigned integer. There is nothing difficult to add your types. To do this, you need to write the translation functions that are called inside the command handler function.
The argument delimiter is a space, the command terminator is a semicolon ;.
#include <stdbool.h> #include <stdint.h> #include <stdio.h> #define MAX_LINE_LEN 128 bool str_cmp(uint8_t * str1, uint8_t * str2) { uint8_t i = 0; while (str1[i] != 0 && str2[i] != 0) { if ((str1[i] != str2[i]) || (str1[i + 1] != str2[i + 1])) return false; i++; } return true; } uint8_t *ltrim(uint8_t ** headp, uint8_t c, uint8_t t) { while ((*headp)[0] == c || (*headp)[0] == t) { (*headp)++; } return (*headp); } bool gettseq(uint8_t ** headp, uint8_t ** tailp, uint8_t c, uint8_t t) { if ((*headp)[0] == 0) return false; while ((*headp)[0] == c || (*headp)[0] == t) (*headp)++; if ((*headp)[0] == 0) return false; (*tailp) = (*headp); while ((*tailp)[0] != t && (*tailp)[0] != 0) { (*tailp)++; } if ((*tailp)[0] != t) return false; (*tailp)[0] = 0; (*tailp)++; return true; } bool getcseq(uint8_t ** headp, uint8_t ** tailp, uint8_t ** endp, const uint8_t c) { while ((*headp)[0] == c && (*headp)[0] != 0) (*headp)++; if ((*headp)[0] == 0) return false; (*tailp) = (*headp); while ((*tailp)[0] != c && (*tailp)[0] != 0) { (*tailp)++; } if ((*tailp) >= (*endp)) return false; (*tailp)[0] = 0; (*tailp)++; return true; } #define MAX_ARGC 4 typedef struct cmd { uint8_t *arg[MAX_ARGC]; uint8_t argc; } cmd_t; typedef void (*funcp_t) (); typedef struct cdef { uint8_t *name; funcp_t func; uint8_t argc; } cdef_t; void cmd_hello0(void) { printf("Hello!\n"); } void cmd_hello1(uint8_t *str) { printf("Hello, %s!", str); } void shell (uint8_t *str) { uint8_t space = ' ', semic = ';', null = 0, newl = '\n'; uint8_t *head = str; uint8_t *tail; while (gettseq(&head, &tail, space, semic)) { uint8_t *cmdhead = head; uint8_t *cmdtail; cmd_t cmd = { }; cmd.argc = 0; while (getcseq(&cmdhead, &cmdtail, &tail, space) && (cmd.argc < MAX_ARGC)) { cmd.arg[cmd.argc] = cmdhead; cmd.argc++; cmdhead = cmdtail; }; uint8_t i = 0, n = sizeof(cmdl) / sizeof(cdef_t), m = 0; while (i < n) { if (str_cmp(cmd.arg[0], cmdl[i].name)) { if (cmd.argc < cmdl[i].argc) break; switch (cmdl[i].argc) { case 0: (cmdl[i].func) (); break; case 1: (cmdl[i].func) (cmd.arg[1]); break; case 2: break; }; break; } i++; } head = tail; } } cdef_t cmdl[] = { {"hello0", &cmd_hello0, 0}, {"hello1", &cmd_hello1, 1}, }; int main(void) { uint8_t str[164] = "hello0 Body ; hello1 Body ; dummy comm;"; shell(str); } //EOF