Simple embedded shell with runtime pluggable commands.

Dependents:   DataBus2018

Implements a simple unix-like shell for embedded systems with a pluggable command architecture.

Files at this revision

API Documentation at this revision

Comitter:
shimniok
Date:
Wed Dec 26 15:51:42 2018 +0000
Parent:
27:51120f1cec44
Child:
29:8d4132274445
Commit message:
added complete path canonicalization

Changed in this revision

SimpleShell.cpp Show annotated file Show diff for this revision Revisions of this file
SimpleShell.h Show annotated file Show diff for this revision Revisions of this file
--- 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;
--- a/SimpleShell.h	Mon Dec 24 20:15:29 2018 +0000
+++ b/SimpleShell.h	Wed Dec 26 15:51:42 2018 +0000
@@ -33,7 +33,7 @@
 
     /// Callback type used for shell commands.
     typedef Callback<void(int,char**)> callback_t;
-
+    
     /// Create a new shell instance.
     SimpleShell();