Simple embedded shell with runtime pluggable commands.
Implements a simple unix-like shell for embedded systems with a pluggable command architecture.
Diff: SimpleShell.cpp
- Revision:
- 28:753db82debb1
- Parent:
- 24:004e33abce37
- Child:
- 29:8d4132274445
--- a/SimpleShell.cpp Mon Dec 24 20:15:29 2018 +0000 +++ b/SimpleShell.cpp Wed Dec 26 15:51:42 2018 +0000 @@ -1,6 +1,7 @@ #include "SimpleShell.h" #include <ctype.h> #include <string> +#include <list> #define ESC 0x1b #define UP 0x41 @@ -15,16 +16,77 @@ #define TAIL 0x7e +SimpleShell::SimpleShell() +{ + lookupEnd = 0; + + // Built-in shell commands + command(callback(this, &SimpleShell::help), "help"); + command(callback(this, &SimpleShell::pwd), "pwd"); + command(callback(this, &SimpleShell::cat), "cat"); + command(callback(this, &SimpleShell::cd), "cd"); + command(callback(this, &SimpleShell::rm), "rm"); + command(callback(this, &SimpleShell::touch), "touch"); + command(callback(this, &SimpleShell::ls), "ls"); + command(callback(this, &SimpleShell::send), "send"); +} + + +/// Path stack representation +typedef std::list<char*> path_t; + char *SimpleShell::canon(char *path) { - static char result[MAXBUF]; + path_t pstack; + static char tmp[MAXBUF*2]; + char *e; + // if we're passed empty/null string, just send back cwd so nothing breaks + if (path == NULL || strlen(path) == 0) { + strcpy(tmp, _cwd); + return tmp; + } + + // relative path? add current working directory to path stack if (path[0] != '/') { - strncpy(result, _cwd, MAXBUF); - strcat(result, "/"); + strcpy(tmp, _cwd); + strcat(tmp, "/"); + strcat(tmp, path); + } else { + strcpy(tmp, path); } - strcat(result, path); + + // now canonicalize the path spec + e = strtok(tmp+1, "/"); + while (e) { + //printf("e = <%s>\n", e); + if (strcmp("..", e) == 0) { + // pop most recent directory + if (!pstack.empty()) + pstack.pop_back(); + } else if (strcmp(".", e) != 0) { + // push this dir onto path + if (strlen(e) > 0) + pstack.push_back(e); + } + e = strtok(NULL, "/"); + } - return result; + static std::string result; + result = ""; + + for (path_t::iterator it = pstack.begin(); it != pstack.end(); it++) { + result.append("/"); + result.append(*it); + } + + // if empty, add a / + if (result.size() < 2) { + result.append("/"); + } + + strcpy(tmp, result.c_str()); + + return tmp; } @@ -43,23 +105,6 @@ } - -SimpleShell::SimpleShell() -{ - lookupEnd = 0; - - // Built-in shell commands - attach(callback(this, &SimpleShell::help), "help"); - attach(callback(this, &SimpleShell::pwd), "pwd"); - attach(callback(this, &SimpleShell::cat), "cat"); - attach(callback(this, &SimpleShell::cd), "cd"); - attach(callback(this, &SimpleShell::rm), "rm"); - attach(callback(this, &SimpleShell::touch), "touch"); - attach(callback(this, &SimpleShell::ls), "ls"); - attach(callback(this, &SimpleShell::send), "send"); -} - - void SimpleShell::help(int argc, char **argv) { printf("Available commands: "); @@ -73,7 +118,7 @@ void SimpleShell::cd(int argc, char **argv) { if (argc == 2) { - strncpy(_cwd, argv[1], MAXBUF); + strncpy(_cwd, canon(argv[1]), MAXBUF); } else { puts("usage: cd directory"); } @@ -97,7 +142,7 @@ if (argc == 1) { path = _cwd; } else if (argc == 2) { - path = argv[1]; + path = canon(argv[1]); } else { puts("usage: ls [directory]"); return; @@ -259,7 +304,7 @@ } -void SimpleShell::attach(callback_t cb, char *command) +void SimpleShell::command(callback_t cb, char *command) { if (lookupEnd < MAXLOOKUP) { lookup[lookupEnd].cb = cb;