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:
- 20:53f0b5dc30f9
- Parent:
- 19:bf5f5ea4e762
- Child:
- 21:5d7ac1f0b842
--- 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