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:
- 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 ...]]");