Simple embedded shell with runtime pluggable commands.

Dependents:   DataBus2018

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

Revision:
35:1a8c5fce8895
Parent:
34:afe994ca0e49
--- a/SimpleShell.cpp	Fri Dec 28 20:34:58 2018 +0000
+++ b/SimpleShell.cpp	Mon Dec 31 23:34:17 2018 +0000
@@ -1,4 +1,5 @@
 #include "SimpleShell.h"
+#include "ff.h"
 #include <ctype.h>
 #include <string>
 #include <list>
@@ -39,9 +40,7 @@
 
 
 bool SimpleShell::haswildcard(char *s) {
-    bool result = \
-        strchr(s, '*') != NULL || strchr(s, '?') != NULL ||
-        (strchr(s, '[') != NULL && strchr(s, ']') != NULL);
+    bool result = strchr(s, '*') != NULL;
     return result;
 }
 
@@ -186,13 +185,7 @@
 }
 
 
-typedef struct {
-    char *dir;
-    char *base;
-} filespec_t;
-
-
-char *dirname(char *path)
+char *SimpleShell::dirname(char *path)
 {
     char *found = strrchr(path, '/');
     char *result = new char[sizeof(path)];
@@ -208,57 +201,105 @@
 }    
 
 
-#include "fnmatch.h"
-
-list<char*> *scandir(char *pattern, char *path)
+/** Attempts to match filename pattern and name.
+ * @param pattern is a pattern containing one '*'
+ * @param name is the name to check for a match to the pattern
+ * @returns 1 if match found, 0 if no match or bad pattern
+ */ 
+int fnmatch(char *pattern, char *name)
 {
-    DIR *d;
-    list<char*> *listp;
-    
+    char *p;
+    char *n;
+    int c;
+
+    // only one * allowed
+    p = pattern;
+    c = 0;
+    p = strchr(p, '*');
+    while (p) {
+        c++;
+        p = strchr(p+1, '*');
+    }
+    if (c != 1) return 0;
+
+    // match first part
+    //puts("first");
+    p = pattern;
+    n = name;
+    char *s = strchr(pattern, '*');
+    while (p != s) {
+        // mismatch before *?
+        if (toupper(*p) != toupper(*n)) {
+            return 0;
+        }
+        p++;
+        n++;
+    }
+    // match last part in reverse
+    //puts("second");
+    p = strchr(pattern, 0)-1;
+    n = strchr(name, 0)-1;
+    while (p != s) {
+        // mismatch before *?
+        //printf("%c %c\n", *p, *n);
+        if (toupper(*p) != toupper(*n)) {
+            return 0;
+        }
+        p--;
+        n--;
+    }
+
+    return 1;
+}
+
+
+// Run the specified callback on each matching filename
+char *SimpleShell::foreach(char *pattern)
+{
+    DIR *d = 0;
+    char *base;
+    char *path;
     struct dirent *p;
+
+    base = basename(pattern);
+    path = dirname(pattern);
+    printf("dir:<%s> base:<%s>\n", path, base);
     if ((d = opendir(path)) != NULL) {
-        listp = new list<char*>;
         while ((p = readdir(d)) != NULL) {
-            if (fnmatch(pattern, p->d_name, FNM_PATHNAME|FNM_CASEFOLD) != FNM_NOMATCH) {
-                char *s = new char[sizeof(p->d_name)];
-                strcpy(s, p->d_name);
-                listp->push_back(s);
-            }
-        }
+            //printf("pattern:<%s> file:<%s>\n", base, p->d_name);
+            if (fnmatch(base, p->d_name) == 1) {
+                char *next = new char[sizeof(base) + sizeof(p->d_name) + 2];
+                sprintf(next, "%s/%s", path, p->d_name);
+                printf("Removing %s...\n", next);
+                int stat = remove(next);
+                //int stat = f_unlink(next);
+                if (stat) {
+                    printf("%s: could not remove. Error %d\n", next, stat);
+                }
+                delete[] next;
+            }//if
+        }//while
         closedir(d);
+    } else {
+        printf("%s: no such directory\n", path);
     }
-    return listp;
+       
+    return 0;
 }
 
 
 void SimpleShell::rm(int argc, char **argv)
 {
+    char *arg;
+
     if (argc >= 2) {
         for (int i=1; i < argc; i++) {
-            char *arg = canon(argv[i]);
-            char *base = basename(arg);
-            char *dir = dirname(arg);
-            
-            printf("arg=<%s>\nbase=<%s>\ndir=<%s>\n", arg, base, dir);
-
-            // wildcards only valid in basename for now
-            if (haswildcard(base)) {
-                list<char*> *fl = scandir(base, dir);
-                char *s;
-                while (!fl->empty()) {
-                    s = fl->front();
-                    printf("<%s>\n", s);
-                    fl->pop_front();
-                    delete[] s;
-                }
-                delete fl;
-            } else {
-                if (remove(canon(argv[i]))) {
-                    printf("%s: cannot remove\n", argv[i]);
-                }
+            arg = canon(argv[i]);
+            if (haswildcard(argv[i])) {
+                foreach(arg);
+            } else if (remove(canon(argv[i]))) {
+                printf("%s: cannot remove. Error %d\n", argv[i], errno);
             }
-
-            delete[] dir;
         }
     } else {
         puts("usage: rm [file1 [file2 ...]]");