Simple embedded shell with runtime pluggable commands.

Dependents:   DataBus2018

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

SimpleShell.cpp

Committer:
shimniok
Date:
2018-12-13
Revision:
11:23f61057d877
Parent:
10:c3faa7ffd23b
Parent:
8:41b7274a9753
Child:
12:ecf3fc049bca

File content as of revision 11:23f61057d877:

#include "SimpleShell.h"
#include <ctype.h>

#define ESC 0x1b

SimpleShell::SimpleShell()
{
    lookupEnd = 0;
    // Built-in shell commands
    attach(callback(this, &SimpleShell::help), "help");
    // TODO: cd
}


void SimpleShell::help()
{
    printf("Available commands: ");
    for (int i=0; i < lookupEnd; i++) {
        printf("%s ", lookup[i].command);
    }
    printf("\n\n");
}


void SimpleShell::run()
{
    bool done=false;
    Callback<void()> cb;
    int status; // TODO implement command status return
    
    strcpy(_cwd, "/log");

    printf("Type help for assistance.\n");
    help();   
    while (!done) {
        printPrompt();
        readCommand();
        if (cmd[0]) { // skip blank command
            if (cb = findCommand()) {
                cb.call();
            } else {
                printf("command <%s> not found\n", cmd);
            }
        }
    }
    puts("exiting shell\n");

    return;
}


void SimpleShell::attach(Callback<void()> cb, char *command) 
{  
    if (lookupEnd < MAXLOOKUP) {
        lookup[lookupEnd].cb = cb;
        lookup[lookupEnd].command = command;
        lookupEnd++;
    }
        
    return;
}


Callback<void()> SimpleShell::findCommand()
{
    Callback<void()> cb=NULL;
    
    for (int i=0; i < lookupEnd; i++) {
        if (strncmp(cmd, 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;
    
    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)
            char c2 = getchar();
            char c3 = getchar();

            if (c2 == 0x4f && c3 == 0x46) {
                printf("<END>");
            } else if (c2 == 0x5b) {
                switch (c3) {
                case 0x41 : // up
                    printf("<UP>");
                    break;
                case 0x42 : // down
                    printf("<DOWN>");
                    break;
                case 0x43 : // right
                    printf("<RIGHT>");
                    break;
                case 0x44 : // left
                    printf("<LEFT>");
                    break;
                case 0x31 : // home
                case 0x32 : // ins
                case 0x33: // del
                case 0x35: // pgup
                case 0x36: // pgdn
                    char c4 = getchar();
                    if (c4 == 0x7e) {
                        switch (c3) {
                        case 0x31 :
                            printf("<HOME>");
                            break;
                        case 0x32 : // ins
                            printf("<INS>");
                            break;
                        case 0x33: // del
                            printf("<DEL>");
                            break;                
                        case 0x35: // pgup
                            printf("<PGUP>");
                            break;
                        case 0x36: // pgdn
                            printf("<PGDN>");
                            break;
                        default:
                            break;
                        }//switch
                    }//if
                default:
                    //printf("<0x%02x>", c3);
                    break;
                }//switch
            }//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);

    // chomp
    for (int j=i; j >= 0; j--) {
        if (isspace(cmd[j])) {
            cmd[j] = '\0';
        }
    }

    return;
}