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:
Mon Dec 31 23:34:17 2018 +0000
Revision:
35:1a8c5fce8895
Parent:
34:afe994ca0e49
trying wildcards still.

Who changed what in which revision?

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