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:
Mon Dec 24 04:31:43 2018 +0000
Parent:
19:bf5f5ea4e762
Child:
21:5d7ac1f0b842
Commit message:
Implement simple ascii file download protocol for downloading logfiles

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	Sat Dec 22 20:27:54 2018 +0000
+++ b/SimpleShell.cpp	Mon Dec 24 04:31:43 2018 +0000
@@ -1,324 +0,0 @@
-#include "SimpleShell.h"
-#include <ctype.h>
-#include <string>
-
-#define ESC     0x1b
-#define UP      0x41
-#define DOWN    0x42
-#define RIGHT   0x43
-#define LEFT    0x44
-#define HOME    0x31
-#define INS     0x32
-#define DEL     0x33
-#define PGUP    0x35
-#define PGDN    0x36
-#define TAIL    0x7e
-
-
-char *SimpleShell::canon(char *path) {
-    static char result[MAXBUF];
-    
-    if (path[0] != '/') {
-        strncpy(result, _cwd, MAXBUF);
-        strcat(result, "/");
-    }
-    strcat(result, path);
-    
-    return result;
-}
-
-
-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");
-}
-
-
-void SimpleShell::help(int argc, char **argv)
-{
-    printf("Available commands: ");
-    for (int i=0; i < lookupEnd; i++) {
-        printf("%s ", lookup[i].command);
-    }
-    printf("\n\n");
-}
-
-
-void SimpleShell::cd(int argc, char **argv) 
-{
-    if (argc == 2) {
-        strncpy(_cwd, argv[1], MAXBUF);
-    } else {
-        puts("usage: cd directory");
-    }
-    return;
-}
-
-
-void SimpleShell::pwd(int argc, char **argv)
-{
-    puts(_cwd);
-    return;
-}
-
-
-void SimpleShell::ls(int argc, char **argv)
-{
-    DIR *d;
-    struct dirent *p;
-    char *path;
-
-    if (argc == 1) {
-        path = _cwd;
-    } else if (argc == 2) {
-        path = argv[1];
-    } else {
-        puts("usage: ls [directory]");
-        return;
-    }
-    
-    int cols=0;
-    if ((d = opendir(path)) != NULL) {
-        while ((p = readdir(d)) != NULL) {
-            if (p->d_name && p->d_name[0] != 0xff) {
-                if (cols++ > 3) {
-                    putc('\n', stdout);
-                    cols = 0;
-                }
-                printf("%-15s  ", p->d_name);
-            }
-        }
-        putc('\n', stdout);
-        if (cols < 3)
-            putc('\n', stdout);
-        closedir(d);
-    } else {
-        puts(path);
-        puts(": No such directory\n");
-    }
-
-    return;
-}
-
-
-void SimpleShell::rm(int argc, char **argv)
-{
-    if (argc >= 2) {
-        for (int i=1; i < argc; i++) {
-            if (remove(canon(argv[i]))) {
-                printf("%s: cannot remove\n", argv[i]);
-            }
-        }
-    } else {
-        puts("usage: rm [file1 [file2 ...]]");
-    }
-}
-
-
-void SimpleShell::touch(int argc, char **argv)
-{
-    FILE *fp;
-
-    if (argc >= 2) {
-        for (int i=1; i < argc; i++) {
-            if ((fp = fopen(canon(argv[i]), "w")) != NULL) {
-                fclose(fp);
-            } else {
-                printf("%s: cannot touch\n", argv[1]);
-            }
-        }
-    } else {
-        puts("usage: touch [file1 [file2 ...]]");
-    }
-}
-
-
-void SimpleShell::cat(int argc, char **argv)
-{
-    FILE *fp;
-    //int status=0;
-    char *buf = new char[MAXBUF];
-    
-    for (int i=1; i < argc; i++) {
-        //resolveDirectory(path, arg);
-        if ((fp = fopen(canon(argv[i]), "r")) != NULL) {
-            while (!feof(fp)) {
-                fgets(buf, MAXBUF-1, fp);
-                fputs(buf, stdout);
-            }
-            fclose(fp);
-        } else {
-            fputs(argv[i], stdout);
-            fputs(": No such file\n", stdout);
-            //status = 1;
-        }
-    }
-    delete[] buf;
-
-    return;
-}
-
-
-void SimpleShell::run()
-{
-    bool done=false;
-    callback_t cb;
-    //int status; // TODO implement command status return
-    std::string x;
-    
-    // Set current working directory
-    strncpy(_cwd, "/etc", MAXBUF);
-
-    printf("Type help for assistance.\n");
-    help(0, NULL);   
-    while (!done) {
-        printPrompt();
-        readCommand();
-        if (argv[0]) { // skip blank command
-            if (cb = findCommand()) {
-                cb.call(argc, argv);
-            } else {
-                printf("command <%s> not found\n", argv[0]);
-            }
-        }
-    }
-    puts("exiting shell\n");
-
-    return;
-}
-
-
-void SimpleShell::attach(callback_t cb, char *command) 
-{  
-    if (lookupEnd < MAXLOOKUP) {
-        lookup[lookupEnd].cb = cb;
-        lookup[lookupEnd].command = command;
-        lookupEnd++;
-    }
-        
-    return;
-}
-
-
-SimpleShell::callback_t SimpleShell::findCommand()
-{
-    SimpleShell::callback_t cb=NULL;
-    
-    for (int i=0; i < lookupEnd; i++) {
-        if (strncmp(argv[0], lookup[i].command, MAXBUF) == 0) {
-            cb = lookup[i].cb;
-            break;
-        }
-    }
-    
-    return cb;
-}
-
-
-void SimpleShell::printPrompt()
-{
-    fputc('(', stdout);
-    fputs(_cwd, stdout);
-    fputs(")# ", stdout);
-    
-    return;
-}
-
-
-void SimpleShell::readCommand()
-{
-    int i=0;
-    char c;
-    bool done = false;
-    static char cmd[MAXBUF];
-    
-    memset(cmd, 0, MAXBUF);
-    do {
-        cmd[i] = 0;
-        c = fgetc(stdin);
-        if (c == '\r') { // if return is hit, we're done, don't add \r to cmd
-            done = true;
-        } else if (c == ESC) { // keyboard escape codes (arrow keys, etc)
-            int c2 = getchar();
-            int c3 = getchar();
-
-            if (c2 == 0x4f && c3 == 0x46) {
-                printf("<END>");
-            } else if (c2 == 0x5b) {
-
-                if (c3 == UP) {
-                    printf("<UP>");
-                } else if (c3 == DOWN) {
-                    printf("<DOWN>");
-                } else if (c3 == RIGHT) {
-                    printf("<RIGHT>");
-                } else if (c3 == LEFT) {
-                    printf("<LEFT>");
-                } else if (c3 == HOME || c3 == INS || c3 == DEL ||
-                           c3 == PGUP || c3 == PGDN) {
-                    char c4 = getchar();
-                    if (c4 == TAIL) {
-                        if (c4 == HOME) {
-                            printf("<HOME>");
-                        } else if (c4 == INS) {
-                            printf("<INS>");
-                        } else if (c4 == DEL) {
-                            printf("<DEL>");
-                        } else if (c4 == PGUP) {
-                            printf("<PGUP>");
-                        } else if (c4 == PGDN) {
-                            printf("<PGDN>");
-                        }//if
-                    }//if
-                }//if
-            }//if            
-            //printf("\n");
-        } else if (i < MAXBUF-1) {
-            if (c == 0x7f || c == '\b') { // backspace or delete
-                if (i > 0) { // if we're at the beginning, do nothing
-                    i--;
-                    fputs("\b \b", stdout);
-                }
-            } else {
-                if (isprint(c))
-                    fputc(c, stdout);
-                cmd[i++] = c;
-            }
-        }
-
-    } while (!done);
-    fputc('\n', stdout);
-
-    // remove leading/trailing whitespace
-    char *s = cmd;
-    while (isspace(*s)) {
-        s++;
-    }
-    for (int j=i; j >= 0 && isspace(cmd[j]); j--) {
-        cmd[j] = '\0';
-    }
-
-    // split into command and arguments
-    argc = 0;
-    char *t;
-    
-    for (int i=0; i < MAXARGS; i++) {
-        argv[i] = NULL;
-    }    
-    t = strtok(s, " ");
-    while (t && argc < 10) {
-        argv[argc++] = t;
-        t = strtok(NULL, " ");
-    }
-
-    return;
-}
\ No newline at end of file
--- a/SimpleShell.h	Sat Dec 22 20:27:54 2018 +0000
+++ b/SimpleShell.h	Mon Dec 24 04:31:43 2018 +0000
@@ -1,121 +0,0 @@
-#ifndef __SIMPLESHELL_H
-#define __SIMPLESHELL_H
-
-#include "mbed.h"
-
-/** SimpleShell
- * A simple, flexible, embedded shell with dynamically added shell commands.
- * Shell commands must be void().
- * @code 
- * #include "SimpleShell.h"
- *
- * void helloworld() { printf("Hello world!\n"); }
- *
- * int main() {
- *   SimpleShell sh;
- *   sh.attach(helloworld, "test");
- *   sh.run();
- * }
- * @endcode
- */
-class SimpleShell {
-public:  
-
-    /// Callback type used for shell commands
-    typedef Callback<void(int, char**)> callback_t;
-
-    /// Create a new shell instance
-    SimpleShell();
-
-    /** Call this to run the shell.
-     * @note The shell can be run in a new thread.
-     * @code 
-     * SimpleShell sh;
-     * sh.run();
-     * thread.start(callback(&sh, &SimpleShell::run));
-     * @endcode
-     */
-    void run();
-
-    /** Attaches a shell command
-     * @param cb is the callback function that implements the command
-     * @param command is the string used to invoke the command in the shell
-     * @code
-     * sh.attach(helloworld, "test");
-     * @endcode
-     */
-    void attach(callback_t cb, char *command);
-
-    
-private:
-    /// Maximum number of commands
-    static const int MAXLOOKUP=16;
-
-    /// Maximum command line buffer size
-    static const int MAXBUF=64;
-
-    /// internal struct to contain a single command
-    typedef struct {
-        char *command;
-        callback_t cb;
-    } command_entry_t;
-
-    /// canonicalize path
-    char *canon(char *path);
-
-    /** finds and eturns the callback for a command
-     * @return Callback to a function returning void
-     */
-    callback_t findCommand();  
-    
-    /// Built-in shell command to display list of commands
-    void help(int argc, char **argv);
-
-    /// Change current directory
-    void cd(int argc, char **argv);
-
-    /// Built-in shell command to print working directory
-    void pwd(int argc, char **argv);
-
-    /// Built-in shell command to list files in directory
-    void ls(int argc, char **argv);
-    
-    /// Built-in shell command to remove a file
-    void rm(int argc, char **argv);
-    
-    /// Built-in shell command to create a file
-    void touch(int argc, char **argv);
-
-    /// Built-in shell command to display contents of file
-    void cat(int argc, char **argv);
-
-    /// Prints command prompt
-    void printPrompt(void);
-    
-    /// Reads a command from the prompt (with editing)
-    void readCommand();
-    
-    /// Command lookup table
-    command_entry_t lookup[MAXLOOKUP];
-
-    /// Current end of lookup table
-    int lookupEnd;
-    
-    /// Maximum number of arguments
-    static const int MAXARGS=3;
-    
-    /// Command and arguments
-    char *argv[MAXARGS];
-        
-    /// Size of argv
-    int argc;
-    
-    /// Current working directory
-    char _cwd[MAXBUF];
-    
-    /// shell command history
-    
-    
-}; // class
-
-#endif
\ No newline at end of file