Simple embedded shell with runtime pluggable commands.

Dependents:   DataBus2018

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

Committer:
shimniok
Date:
Fri Dec 28 20:34:58 2018 +0000
Revision:
34:afe994ca0e49
Parent:
33:84dc443909a0
Child:
35:1a8c5fce8895
implemented dirname

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shimniok 21:5d7ac1f0b842 1 #include "SimpleShell.h"
shimniok 21:5d7ac1f0b842 2 #include <ctype.h>
shimniok 21:5d7ac1f0b842 3 #include <string>
shimniok 28:753db82debb1 4 #include <list>
shimniok 21:5d7ac1f0b842 5
shimniok 21:5d7ac1f0b842 6 #define ESC 0x1b
shimniok 21:5d7ac1f0b842 7 #define UP 0x41
shimniok 21:5d7ac1f0b842 8 #define DOWN 0x42
shimniok 21:5d7ac1f0b842 9 #define RIGHT 0x43
shimniok 21:5d7ac1f0b842 10 #define LEFT 0x44
shimniok 21:5d7ac1f0b842 11 #define HOME 0x31
shimniok 21:5d7ac1f0b842 12 #define INS 0x32
shimniok 21:5d7ac1f0b842 13 #define DEL 0x33
shimniok 21:5d7ac1f0b842 14 #define PGUP 0x35
shimniok 21:5d7ac1f0b842 15 #define PGDN 0x36
shimniok 21:5d7ac1f0b842 16 #define TAIL 0x7e
shimniok 21:5d7ac1f0b842 17
shimniok 21:5d7ac1f0b842 18
shimniok 29:8d4132274445 19 SimpleShell::SimpleShell(char *home)
shimniok 28:753db82debb1 20 {
shimniok 28:753db82debb1 21 lookupEnd = 0;
shimniok 28:753db82debb1 22
shimniok 29:8d4132274445 23 // Set home directory
shimniok 29:8d4132274445 24 strncpy(_home, canon(home), MAXBUF);
shimniok 29:8d4132274445 25
shimniok 29:8d4132274445 26 // Set current working directory
shimniok 29:8d4132274445 27 strncpy(_cwd, _home, MAXBUF);
shimniok 29:8d4132274445 28
shimniok 28:753db82debb1 29 // Built-in shell commands
shimniok 28:753db82debb1 30 command(callback(this, &SimpleShell::help), "help");
shimniok 28:753db82debb1 31 command(callback(this, &SimpleShell::pwd), "pwd");
shimniok 28:753db82debb1 32 command(callback(this, &SimpleShell::cat), "cat");
shimniok 28:753db82debb1 33 command(callback(this, &SimpleShell::cd), "cd");
shimniok 28:753db82debb1 34 command(callback(this, &SimpleShell::rm), "rm");
shimniok 28:753db82debb1 35 command(callback(this, &SimpleShell::touch), "touch");
shimniok 28:753db82debb1 36 command(callback(this, &SimpleShell::ls), "ls");
shimniok 28:753db82debb1 37 command(callback(this, &SimpleShell::send), "send");
shimniok 28:753db82debb1 38 }
shimniok 28:753db82debb1 39
shimniok 28:753db82debb1 40
shimniok 31:27e8130a0d8f 41 bool SimpleShell::haswildcard(char *s) {
shimniok 31:27e8130a0d8f 42 bool result = \
shimniok 31:27e8130a0d8f 43 strchr(s, '*') != NULL || strchr(s, '?') != NULL ||
shimniok 31:27e8130a0d8f 44 (strchr(s, '[') != NULL && strchr(s, ']') != NULL);
shimniok 31:27e8130a0d8f 45 return result;
shimniok 31:27e8130a0d8f 46 }
shimniok 31:27e8130a0d8f 47
shimniok 31:27e8130a0d8f 48
shimniok 28:753db82debb1 49 /// Path stack representation
shimniok 28:753db82debb1 50 typedef std::list<char*> path_t;
shimniok 28:753db82debb1 51
shimniok 21:5d7ac1f0b842 52 char *SimpleShell::canon(char *path) {
shimniok 28:753db82debb1 53 path_t pstack;
shimniok 28:753db82debb1 54 static char tmp[MAXBUF*2];
shimniok 28:753db82debb1 55 char *e;
shimniok 21:5d7ac1f0b842 56
shimniok 28:753db82debb1 57 // if we're passed empty/null string, just send back cwd so nothing breaks
shimniok 28:753db82debb1 58 if (path == NULL || strlen(path) == 0) {
shimniok 28:753db82debb1 59 strcpy(tmp, _cwd);
shimniok 28:753db82debb1 60 return tmp;
shimniok 28:753db82debb1 61 }
shimniok 28:753db82debb1 62
shimniok 28:753db82debb1 63 // relative path? add current working directory to path stack
shimniok 21:5d7ac1f0b842 64 if (path[0] != '/') {
shimniok 28:753db82debb1 65 strcpy(tmp, _cwd);
shimniok 28:753db82debb1 66 strcat(tmp, "/");
shimniok 28:753db82debb1 67 strcat(tmp, path);
shimniok 28:753db82debb1 68 } else {
shimniok 28:753db82debb1 69 strcpy(tmp, path);
shimniok 21:5d7ac1f0b842 70 }
shimniok 28:753db82debb1 71
shimniok 28:753db82debb1 72 // now canonicalize the path spec
shimniok 28:753db82debb1 73 e = strtok(tmp+1, "/");
shimniok 28:753db82debb1 74 while (e) {
shimniok 28:753db82debb1 75 //printf("e = <%s>\n", e);
shimniok 28:753db82debb1 76 if (strcmp("..", e) == 0) {
shimniok 28:753db82debb1 77 // pop most recent directory
shimniok 28:753db82debb1 78 if (!pstack.empty())
shimniok 28:753db82debb1 79 pstack.pop_back();
shimniok 28:753db82debb1 80 } else if (strcmp(".", e) != 0) {
shimniok 28:753db82debb1 81 // push this dir onto path
shimniok 28:753db82debb1 82 if (strlen(e) > 0)
shimniok 28:753db82debb1 83 pstack.push_back(e);
shimniok 28:753db82debb1 84 }
shimniok 28:753db82debb1 85 e = strtok(NULL, "/");
shimniok 28:753db82debb1 86 }
shimniok 21:5d7ac1f0b842 87
shimniok 28:753db82debb1 88 static std::string result;
shimniok 28:753db82debb1 89 result = "";
shimniok 28:753db82debb1 90
shimniok 28:753db82debb1 91 for (path_t::iterator it = pstack.begin(); it != pstack.end(); it++) {
shimniok 28:753db82debb1 92 result.append("/");
shimniok 28:753db82debb1 93 result.append(*it);
shimniok 28:753db82debb1 94 }
shimniok 28:753db82debb1 95
shimniok 28:753db82debb1 96 // if empty, add a /
shimniok 28:753db82debb1 97 if (result.size() < 2) {
shimniok 28:753db82debb1 98 result.append("/");
shimniok 28:753db82debb1 99 }
shimniok 28:753db82debb1 100
shimniok 28:753db82debb1 101 strcpy(tmp, result.c_str());
shimniok 28:753db82debb1 102
shimniok 28:753db82debb1 103 return tmp;
shimniok 21:5d7ac1f0b842 104 }
shimniok 21:5d7ac1f0b842 105
shimniok 21:5d7ac1f0b842 106
shimniok 23:b1e49cfcaef6 107 char *SimpleShell::basename(char *path) {
shimniok 33:84dc443909a0 108 char *result = strrchr(path, '/');
shimniok 24:004e33abce37 109
shimniok 33:84dc443909a0 110 if (result == NULL) {
shimniok 33:84dc443909a0 111 result = path;
shimniok 33:84dc443909a0 112 } else {
shimniok 33:84dc443909a0 113 if (result[0] == '/') result++;
shimniok 24:004e33abce37 114 }
shimniok 24:004e33abce37 115
shimniok 24:004e33abce37 116 return result;
shimniok 23:b1e49cfcaef6 117 }
shimniok 23:b1e49cfcaef6 118
shimniok 23:b1e49cfcaef6 119
shimniok 21:5d7ac1f0b842 120 void SimpleShell::help(int argc, char **argv)
shimniok 21:5d7ac1f0b842 121 {
shimniok 21:5d7ac1f0b842 122 printf("Available commands: ");
shimniok 21:5d7ac1f0b842 123 for (int i=0; i < lookupEnd; i++) {
shimniok 21:5d7ac1f0b842 124 printf("%s ", lookup[i].command);
shimniok 21:5d7ac1f0b842 125 }
shimniok 21:5d7ac1f0b842 126 printf("\n\n");
shimniok 21:5d7ac1f0b842 127 }
shimniok 21:5d7ac1f0b842 128
shimniok 21:5d7ac1f0b842 129
shimniok 21:5d7ac1f0b842 130 void SimpleShell::cd(int argc, char **argv)
shimniok 21:5d7ac1f0b842 131 {
shimniok 29:8d4132274445 132 if (argc == 1) {
shimniok 29:8d4132274445 133 strncpy(_cwd, _home, MAXBUF);
shimniok 29:8d4132274445 134 } else if (argc == 2) {
shimniok 28:753db82debb1 135 strncpy(_cwd, canon(argv[1]), MAXBUF);
shimniok 21:5d7ac1f0b842 136 } else {
shimniok 21:5d7ac1f0b842 137 puts("usage: cd directory");
shimniok 21:5d7ac1f0b842 138 }
shimniok 21:5d7ac1f0b842 139 return;
shimniok 21:5d7ac1f0b842 140 }
shimniok 21:5d7ac1f0b842 141
shimniok 21:5d7ac1f0b842 142
shimniok 21:5d7ac1f0b842 143 void SimpleShell::pwd(int argc, char **argv)
shimniok 21:5d7ac1f0b842 144 {
shimniok 21:5d7ac1f0b842 145 puts(_cwd);
shimniok 21:5d7ac1f0b842 146 return;
shimniok 21:5d7ac1f0b842 147 }
shimniok 21:5d7ac1f0b842 148
shimniok 21:5d7ac1f0b842 149
shimniok 21:5d7ac1f0b842 150 void SimpleShell::ls(int argc, char **argv)
shimniok 21:5d7ac1f0b842 151 {
shimniok 21:5d7ac1f0b842 152 DIR *d;
shimniok 21:5d7ac1f0b842 153 struct dirent *p;
shimniok 21:5d7ac1f0b842 154 char *path;
shimniok 21:5d7ac1f0b842 155
shimniok 21:5d7ac1f0b842 156 if (argc == 1) {
shimniok 21:5d7ac1f0b842 157 path = _cwd;
shimniok 21:5d7ac1f0b842 158 } else if (argc == 2) {
shimniok 28:753db82debb1 159 path = canon(argv[1]);
shimniok 21:5d7ac1f0b842 160 } else {
shimniok 21:5d7ac1f0b842 161 puts("usage: ls [directory]");
shimniok 21:5d7ac1f0b842 162 return;
shimniok 21:5d7ac1f0b842 163 }
shimniok 21:5d7ac1f0b842 164
shimniok 21:5d7ac1f0b842 165 int cols=0;
shimniok 21:5d7ac1f0b842 166 if ((d = opendir(path)) != NULL) {
shimniok 21:5d7ac1f0b842 167 while ((p = readdir(d)) != NULL) {
shimniok 21:5d7ac1f0b842 168 if (p->d_name && p->d_name[0] != 0xff) {
shimniok 21:5d7ac1f0b842 169 if (cols++ > 3) {
shimniok 21:5d7ac1f0b842 170 putc('\n', stdout);
shimniok 21:5d7ac1f0b842 171 cols = 0;
shimniok 21:5d7ac1f0b842 172 }
shimniok 21:5d7ac1f0b842 173 printf("%-15s ", p->d_name);
shimniok 21:5d7ac1f0b842 174 }
shimniok 21:5d7ac1f0b842 175 }
shimniok 21:5d7ac1f0b842 176 putc('\n', stdout);
shimniok 21:5d7ac1f0b842 177 if (cols < 3)
shimniok 21:5d7ac1f0b842 178 putc('\n', stdout);
shimniok 21:5d7ac1f0b842 179 closedir(d);
shimniok 21:5d7ac1f0b842 180 } else {
shimniok 21:5d7ac1f0b842 181 puts(path);
shimniok 21:5d7ac1f0b842 182 puts(": No such directory\n");
shimniok 21:5d7ac1f0b842 183 }
shimniok 21:5d7ac1f0b842 184
shimniok 21:5d7ac1f0b842 185 return;
shimniok 21:5d7ac1f0b842 186 }
shimniok 21:5d7ac1f0b842 187
shimniok 34:afe994ca0e49 188
shimniok 34:afe994ca0e49 189 typedef struct {
shimniok 34:afe994ca0e49 190 char *dir;
shimniok 34:afe994ca0e49 191 char *base;
shimniok 34:afe994ca0e49 192 } filespec_t;
shimniok 34:afe994ca0e49 193
shimniok 34:afe994ca0e49 194
shimniok 34:afe994ca0e49 195 char *dirname(char *path)
shimniok 34:afe994ca0e49 196 {
shimniok 34:afe994ca0e49 197 char *found = strrchr(path, '/');
shimniok 34:afe994ca0e49 198 char *result = new char[sizeof(path)];
shimniok 34:afe994ca0e49 199
shimniok 34:afe994ca0e49 200 char *s = result;
shimniok 34:afe994ca0e49 201 char *t = path;
shimniok 34:afe994ca0e49 202 while (t < found) {
shimniok 34:afe994ca0e49 203 *s++ = *t++;
shimniok 34:afe994ca0e49 204 }
shimniok 34:afe994ca0e49 205 *s = 0;
shimniok 34:afe994ca0e49 206
shimniok 34:afe994ca0e49 207 return result;
shimniok 34:afe994ca0e49 208 }
shimniok 34:afe994ca0e49 209
shimniok 34:afe994ca0e49 210
shimniok 32:fc09f0eb1e8a 211 #include "fnmatch.h"
shimniok 32:fc09f0eb1e8a 212
shimniok 32:fc09f0eb1e8a 213 list<char*> *scandir(char *pattern, char *path)
shimniok 32:fc09f0eb1e8a 214 {
shimniok 32:fc09f0eb1e8a 215 DIR *d;
shimniok 32:fc09f0eb1e8a 216 list<char*> *listp;
shimniok 32:fc09f0eb1e8a 217
shimniok 32:fc09f0eb1e8a 218 struct dirent *p;
shimniok 32:fc09f0eb1e8a 219 if ((d = opendir(path)) != NULL) {
shimniok 32:fc09f0eb1e8a 220 listp = new list<char*>;
shimniok 32:fc09f0eb1e8a 221 while ((p = readdir(d)) != NULL) {
shimniok 32:fc09f0eb1e8a 222 if (fnmatch(pattern, p->d_name, FNM_PATHNAME|FNM_CASEFOLD) != FNM_NOMATCH) {
shimniok 32:fc09f0eb1e8a 223 char *s = new char[sizeof(p->d_name)];
shimniok 32:fc09f0eb1e8a 224 strcpy(s, p->d_name);
shimniok 32:fc09f0eb1e8a 225 listp->push_back(s);
shimniok 32:fc09f0eb1e8a 226 }
shimniok 32:fc09f0eb1e8a 227 }
shimniok 32:fc09f0eb1e8a 228 closedir(d);
shimniok 32:fc09f0eb1e8a 229 }
shimniok 32:fc09f0eb1e8a 230 return listp;
shimniok 32:fc09f0eb1e8a 231 }
shimniok 32:fc09f0eb1e8a 232
shimniok 21:5d7ac1f0b842 233
shimniok 21:5d7ac1f0b842 234 void SimpleShell::rm(int argc, char **argv)
shimniok 21:5d7ac1f0b842 235 {
shimniok 21:5d7ac1f0b842 236 if (argc >= 2) {
shimniok 21:5d7ac1f0b842 237 for (int i=1; i < argc; i++) {
shimniok 33:84dc443909a0 238 char *arg = canon(argv[i]);
shimniok 33:84dc443909a0 239 char *base = basename(arg);
shimniok 34:afe994ca0e49 240 char *dir = dirname(arg);
shimniok 34:afe994ca0e49 241
shimniok 34:afe994ca0e49 242 printf("arg=<%s>\nbase=<%s>\ndir=<%s>\n", arg, base, dir);
shimniok 33:84dc443909a0 243
shimniok 34:afe994ca0e49 244 // wildcards only valid in basename for now
shimniok 34:afe994ca0e49 245 if (haswildcard(base)) {
shimniok 34:afe994ca0e49 246 list<char*> *fl = scandir(base, dir);
shimniok 32:fc09f0eb1e8a 247 char *s;
shimniok 32:fc09f0eb1e8a 248 while (!fl->empty()) {
shimniok 32:fc09f0eb1e8a 249 s = fl->front();
shimniok 32:fc09f0eb1e8a 250 printf("<%s>\n", s);
shimniok 32:fc09f0eb1e8a 251 fl->pop_front();
shimniok 34:afe994ca0e49 252 delete[] s;
shimniok 32:fc09f0eb1e8a 253 }
shimniok 34:afe994ca0e49 254 delete fl;
shimniok 32:fc09f0eb1e8a 255 } else {
shimniok 32:fc09f0eb1e8a 256 if (remove(canon(argv[i]))) {
shimniok 32:fc09f0eb1e8a 257 printf("%s: cannot remove\n", argv[i]);
shimniok 32:fc09f0eb1e8a 258 }
shimniok 21:5d7ac1f0b842 259 }
shimniok 34:afe994ca0e49 260
shimniok 34:afe994ca0e49 261 delete[] dir;
shimniok 34:afe994ca0e49 262 }
shimniok 21:5d7ac1f0b842 263 } else {
shimniok 21:5d7ac1f0b842 264 puts("usage: rm [file1 [file2 ...]]");
shimniok 21:5d7ac1f0b842 265 }
shimniok 21:5d7ac1f0b842 266 }
shimniok 21:5d7ac1f0b842 267
shimniok 21:5d7ac1f0b842 268
shimniok 21:5d7ac1f0b842 269 void SimpleShell::touch(int argc, char **argv)
shimniok 21:5d7ac1f0b842 270 {
shimniok 21:5d7ac1f0b842 271 FILE *fp;
shimniok 21:5d7ac1f0b842 272
shimniok 21:5d7ac1f0b842 273 if (argc >= 2) {
shimniok 21:5d7ac1f0b842 274 for (int i=1; i < argc; i++) {
shimniok 21:5d7ac1f0b842 275 if ((fp = fopen(canon(argv[i]), "w")) != NULL) {
shimniok 21:5d7ac1f0b842 276 fclose(fp);
shimniok 21:5d7ac1f0b842 277 } else {
shimniok 21:5d7ac1f0b842 278 printf("%s: cannot touch\n", argv[1]);
shimniok 21:5d7ac1f0b842 279 }
shimniok 21:5d7ac1f0b842 280 }
shimniok 21:5d7ac1f0b842 281 } else {
shimniok 21:5d7ac1f0b842 282 puts("usage: touch [file1 [file2 ...]]");
shimniok 21:5d7ac1f0b842 283 }
shimniok 21:5d7ac1f0b842 284 }
shimniok 21:5d7ac1f0b842 285
shimniok 21:5d7ac1f0b842 286
shimniok 21:5d7ac1f0b842 287 void SimpleShell::cat(int argc, char **argv)
shimniok 21:5d7ac1f0b842 288 {
shimniok 21:5d7ac1f0b842 289 FILE *fp;
shimniok 21:5d7ac1f0b842 290 //int status=0;
shimniok 21:5d7ac1f0b842 291 char *buf = new char[MAXBUF];
shimniok 21:5d7ac1f0b842 292
shimniok 21:5d7ac1f0b842 293 for (int i=1; i < argc; i++) {
shimniok 21:5d7ac1f0b842 294 //resolveDirectory(path, arg);
shimniok 21:5d7ac1f0b842 295 if ((fp = fopen(canon(argv[i]), "r")) != NULL) {
shimniok 21:5d7ac1f0b842 296 while (!feof(fp)) {
shimniok 21:5d7ac1f0b842 297 fgets(buf, MAXBUF-1, fp);
shimniok 21:5d7ac1f0b842 298 fputs(buf, stdout);
shimniok 21:5d7ac1f0b842 299 }
shimniok 21:5d7ac1f0b842 300 fclose(fp);
shimniok 21:5d7ac1f0b842 301 } else {
shimniok 21:5d7ac1f0b842 302 fputs(argv[i], stdout);
shimniok 21:5d7ac1f0b842 303 fputs(": No such file\n", stdout);
shimniok 21:5d7ac1f0b842 304 //status = 1;
shimniok 21:5d7ac1f0b842 305 }
shimniok 21:5d7ac1f0b842 306 }
shimniok 21:5d7ac1f0b842 307 delete[] buf;
shimniok 21:5d7ac1f0b842 308
shimniok 21:5d7ac1f0b842 309 return;
shimniok 21:5d7ac1f0b842 310 }
shimniok 21:5d7ac1f0b842 311
shimniok 21:5d7ac1f0b842 312
shimniok 23:b1e49cfcaef6 313 void SimpleShell::send(int argc, char **argv)
shimniok 23:b1e49cfcaef6 314 {
shimniok 23:b1e49cfcaef6 315 const char SOF=0x01;
shimniok 23:b1e49cfcaef6 316 const char ETX=0x03;
shimniok 23:b1e49cfcaef6 317 const char EOT=0x04;
shimniok 23:b1e49cfcaef6 318 const char ACK=0x07;
shimniok 23:b1e49cfcaef6 319 const char NACK=0x18;
shimniok 24:004e33abce37 320 char buf[1024];
shimniok 23:b1e49cfcaef6 321 FILE *fp;
shimniok 24:004e33abce37 322 char c;
shimniok 23:b1e49cfcaef6 323
shimniok 23:b1e49cfcaef6 324 int i = 1;
shimniok 23:b1e49cfcaef6 325 if (argc >= 2) {
shimniok 23:b1e49cfcaef6 326 if ((fp = fopen(canon(argv[i]), "r")) == 0) {
shimniok 23:b1e49cfcaef6 327 printf("%s: can't open file\n", basename(argv[i]));
shimniok 23:b1e49cfcaef6 328 } else {
shimniok 24:004e33abce37 329 puts("Ready; initiate receive on client.");
shimniok 24:004e33abce37 330 c = getchar();
shimniok 24:004e33abce37 331 if (c == SOF) {
shimniok 24:004e33abce37 332 puts(basename(argv[i]));
shimniok 24:004e33abce37 333 c = getchar();
shimniok 24:004e33abce37 334 if (c == ACK) {
shimniok 24:004e33abce37 335 while (!feof(fp)) {
shimniok 24:004e33abce37 336 fgets(buf, 1024, fp);
shimniok 24:004e33abce37 337 fputs(buf, stdout);
shimniok 24:004e33abce37 338 }
shimniok 24:004e33abce37 339 putchar(EOT);
shimniok 24:004e33abce37 340 } else if (c == NACK) {
shimniok 24:004e33abce37 341 puts("client error.");
shimniok 24:004e33abce37 342 } else {
shimniok 24:004e33abce37 343 puts("ACK/NACK expected");
shimniok 24:004e33abce37 344 }
shimniok 24:004e33abce37 345 } else if (c == NACK) {
shimniok 24:004e33abce37 346 puts("server cancelled.");
shimniok 24:004e33abce37 347 } else {
shimniok 24:004e33abce37 348 puts("SOF/NACK expected.");
shimniok 24:004e33abce37 349 }
shimniok 24:004e33abce37 350 fclose(fp);
shimniok 23:b1e49cfcaef6 351 }
shimniok 23:b1e49cfcaef6 352 } else {
shimniok 23:b1e49cfcaef6 353 puts("usage: send file1 [file2 ...]");
shimniok 23:b1e49cfcaef6 354 }
shimniok 23:b1e49cfcaef6 355 }
shimniok 23:b1e49cfcaef6 356
shimniok 23:b1e49cfcaef6 357
shimniok 21:5d7ac1f0b842 358 void SimpleShell::run()
shimniok 21:5d7ac1f0b842 359 {
shimniok 21:5d7ac1f0b842 360 bool done=false;
shimniok 21:5d7ac1f0b842 361 callback_t cb;
shimniok 21:5d7ac1f0b842 362 //int status; // TODO implement command status return
shimniok 21:5d7ac1f0b842 363 std::string x;
shimniok 21:5d7ac1f0b842 364
shimniok 21:5d7ac1f0b842 365 printf("Type help for assistance.\n");
shimniok 21:5d7ac1f0b842 366 help(0, NULL);
shimniok 21:5d7ac1f0b842 367 while (!done) {
shimniok 21:5d7ac1f0b842 368 printPrompt();
shimniok 21:5d7ac1f0b842 369 readCommand();
shimniok 21:5d7ac1f0b842 370 if (argv[0]) { // skip blank command
shimniok 21:5d7ac1f0b842 371 if (cb = findCommand()) {
shimniok 21:5d7ac1f0b842 372 cb.call(argc, argv);
shimniok 21:5d7ac1f0b842 373 } else {
shimniok 21:5d7ac1f0b842 374 printf("command <%s> not found\n", argv[0]);
shimniok 21:5d7ac1f0b842 375 }
shimniok 21:5d7ac1f0b842 376 }
shimniok 21:5d7ac1f0b842 377 }
shimniok 21:5d7ac1f0b842 378 puts("exiting shell\n");
shimniok 21:5d7ac1f0b842 379
shimniok 21:5d7ac1f0b842 380 return;
shimniok 21:5d7ac1f0b842 381 }
shimniok 21:5d7ac1f0b842 382
shimniok 21:5d7ac1f0b842 383
shimniok 28:753db82debb1 384 void SimpleShell::command(callback_t cb, char *command)
shimniok 21:5d7ac1f0b842 385 {
shimniok 21:5d7ac1f0b842 386 if (lookupEnd < MAXLOOKUP) {
shimniok 21:5d7ac1f0b842 387 lookup[lookupEnd].cb = cb;
shimniok 21:5d7ac1f0b842 388 lookup[lookupEnd].command = command;
shimniok 21:5d7ac1f0b842 389 lookupEnd++;
shimniok 21:5d7ac1f0b842 390 }
shimniok 21:5d7ac1f0b842 391
shimniok 21:5d7ac1f0b842 392 return;
shimniok 21:5d7ac1f0b842 393 }
shimniok 21:5d7ac1f0b842 394
shimniok 21:5d7ac1f0b842 395
shimniok 21:5d7ac1f0b842 396 SimpleShell::callback_t SimpleShell::findCommand()
shimniok 21:5d7ac1f0b842 397 {
shimniok 21:5d7ac1f0b842 398 SimpleShell::callback_t cb=NULL;
shimniok 21:5d7ac1f0b842 399
shimniok 21:5d7ac1f0b842 400 for (int i=0; i < lookupEnd; i++) {
shimniok 21:5d7ac1f0b842 401 if (strncmp(argv[0], lookup[i].command, MAXBUF) == 0) {
shimniok 21:5d7ac1f0b842 402 cb = lookup[i].cb;
shimniok 21:5d7ac1f0b842 403 break;
shimniok 21:5d7ac1f0b842 404 }
shimniok 21:5d7ac1f0b842 405 }
shimniok 21:5d7ac1f0b842 406
shimniok 21:5d7ac1f0b842 407 return cb;
shimniok 21:5d7ac1f0b842 408 }
shimniok 21:5d7ac1f0b842 409
shimniok 21:5d7ac1f0b842 410
shimniok 21:5d7ac1f0b842 411 void SimpleShell::printPrompt()
shimniok 21:5d7ac1f0b842 412 {
shimniok 21:5d7ac1f0b842 413 fputc('(', stdout);
shimniok 21:5d7ac1f0b842 414 fputs(_cwd, stdout);
shimniok 21:5d7ac1f0b842 415 fputs(")# ", stdout);
shimniok 21:5d7ac1f0b842 416
shimniok 21:5d7ac1f0b842 417 return;
shimniok 21:5d7ac1f0b842 418 }
shimniok 21:5d7ac1f0b842 419
shimniok 21:5d7ac1f0b842 420
shimniok 21:5d7ac1f0b842 421 void SimpleShell::readCommand()
shimniok 21:5d7ac1f0b842 422 {
shimniok 21:5d7ac1f0b842 423 int i=0;
shimniok 21:5d7ac1f0b842 424 char c;
shimniok 21:5d7ac1f0b842 425 bool done = false;
shimniok 21:5d7ac1f0b842 426 static char cmd[MAXBUF];
shimniok 21:5d7ac1f0b842 427
shimniok 21:5d7ac1f0b842 428 memset(cmd, 0, MAXBUF);
shimniok 21:5d7ac1f0b842 429 do {
shimniok 21:5d7ac1f0b842 430 cmd[i] = 0;
shimniok 21:5d7ac1f0b842 431 c = fgetc(stdin);
shimniok 21:5d7ac1f0b842 432 if (c == '\r') { // if return is hit, we're done, don't add \r to cmd
shimniok 21:5d7ac1f0b842 433 done = true;
shimniok 21:5d7ac1f0b842 434 } else if (c == ESC) { // keyboard escape codes (arrow keys, etc)
shimniok 21:5d7ac1f0b842 435 int c2 = getchar();
shimniok 21:5d7ac1f0b842 436 int c3 = getchar();
shimniok 21:5d7ac1f0b842 437
shimniok 21:5d7ac1f0b842 438 if (c2 == 0x4f && c3 == 0x46) {
shimniok 21:5d7ac1f0b842 439 printf("<END>");
shimniok 21:5d7ac1f0b842 440 } else if (c2 == 0x5b) {
shimniok 21:5d7ac1f0b842 441
shimniok 21:5d7ac1f0b842 442 if (c3 == UP) {
shimniok 21:5d7ac1f0b842 443 printf("<UP>");
shimniok 21:5d7ac1f0b842 444 } else if (c3 == DOWN) {
shimniok 21:5d7ac1f0b842 445 printf("<DOWN>");
shimniok 21:5d7ac1f0b842 446 } else if (c3 == RIGHT) {
shimniok 21:5d7ac1f0b842 447 printf("<RIGHT>");
shimniok 21:5d7ac1f0b842 448 } else if (c3 == LEFT) {
shimniok 21:5d7ac1f0b842 449 printf("<LEFT>");
shimniok 21:5d7ac1f0b842 450 } else if (c3 == HOME || c3 == INS || c3 == DEL ||
shimniok 21:5d7ac1f0b842 451 c3 == PGUP || c3 == PGDN) {
shimniok 21:5d7ac1f0b842 452 char c4 = getchar();
shimniok 21:5d7ac1f0b842 453 if (c4 == TAIL) {
shimniok 21:5d7ac1f0b842 454 if (c4 == HOME) {
shimniok 21:5d7ac1f0b842 455 printf("<HOME>");
shimniok 21:5d7ac1f0b842 456 } else if (c4 == INS) {
shimniok 21:5d7ac1f0b842 457 printf("<INS>");
shimniok 21:5d7ac1f0b842 458 } else if (c4 == DEL) {
shimniok 21:5d7ac1f0b842 459 printf("<DEL>");
shimniok 21:5d7ac1f0b842 460 } else if (c4 == PGUP) {
shimniok 21:5d7ac1f0b842 461 printf("<PGUP>");
shimniok 21:5d7ac1f0b842 462 } else if (c4 == PGDN) {
shimniok 21:5d7ac1f0b842 463 printf("<PGDN>");
shimniok 21:5d7ac1f0b842 464 }//if
shimniok 21:5d7ac1f0b842 465 }//if
shimniok 21:5d7ac1f0b842 466 }//if
shimniok 21:5d7ac1f0b842 467 }//if
shimniok 21:5d7ac1f0b842 468 //printf("\n");
shimniok 21:5d7ac1f0b842 469 } else if (i < MAXBUF-1) {
shimniok 21:5d7ac1f0b842 470 if (c == 0x7f || c == '\b') { // backspace or delete
shimniok 21:5d7ac1f0b842 471 if (i > 0) { // if we're at the beginning, do nothing
shimniok 21:5d7ac1f0b842 472 i--;
shimniok 21:5d7ac1f0b842 473 fputs("\b \b", stdout);
shimniok 21:5d7ac1f0b842 474 }
shimniok 21:5d7ac1f0b842 475 } else {
shimniok 21:5d7ac1f0b842 476 if (isprint(c))
shimniok 21:5d7ac1f0b842 477 fputc(c, stdout);
shimniok 21:5d7ac1f0b842 478 cmd[i++] = c;
shimniok 21:5d7ac1f0b842 479 }
shimniok 21:5d7ac1f0b842 480 }
shimniok 21:5d7ac1f0b842 481
shimniok 21:5d7ac1f0b842 482 } while (!done);
shimniok 21:5d7ac1f0b842 483 fputc('\n', stdout);
shimniok 21:5d7ac1f0b842 484
shimniok 21:5d7ac1f0b842 485 // remove leading/trailing whitespace
shimniok 21:5d7ac1f0b842 486 char *s = cmd;
shimniok 21:5d7ac1f0b842 487 while (isspace(*s)) {
shimniok 21:5d7ac1f0b842 488 s++;
shimniok 21:5d7ac1f0b842 489 }
shimniok 21:5d7ac1f0b842 490 for (int j=i; j >= 0 && isspace(cmd[j]); j--) {
shimniok 21:5d7ac1f0b842 491 cmd[j] = '\0';
shimniok 21:5d7ac1f0b842 492 }
shimniok 21:5d7ac1f0b842 493
shimniok 21:5d7ac1f0b842 494 // split into command and arguments
shimniok 21:5d7ac1f0b842 495 argc = 0;
shimniok 21:5d7ac1f0b842 496 char *t;
shimniok 21:5d7ac1f0b842 497
shimniok 21:5d7ac1f0b842 498 for (int i=0; i < MAXARGS; i++) {
shimniok 21:5d7ac1f0b842 499 argv[i] = NULL;
shimniok 21:5d7ac1f0b842 500 }
shimniok 21:5d7ac1f0b842 501 t = strtok(s, " ");
shimniok 30:35522ea06236 502 while (t && argc < MAXARGS) {
shimniok 21:5d7ac1f0b842 503 argv[argc++] = t;
shimniok 21:5d7ac1f0b842 504 t = strtok(NULL, " ");
shimniok 21:5d7ac1f0b842 505 }
shimniok 21:5d7ac1f0b842 506
shimniok 21:5d7ac1f0b842 507 return;
shimniok 21:5d7ac1f0b842 508 }