Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SimpleShell.cpp
00001 #include "SimpleShell.h" 00002 #include "ff.h" 00003 #include <ctype.h> 00004 #include <string> 00005 #include <list> 00006 00007 #define ESC 0x1b 00008 #define UP 0x41 00009 #define DOWN 0x42 00010 #define RIGHT 0x43 00011 #define LEFT 0x44 00012 #define HOME 0x31 00013 #define INS 0x32 00014 #define DEL 0x33 00015 #define PGUP 0x35 00016 #define PGDN 0x36 00017 #define TAIL 0x7e 00018 00019 00020 SimpleShell::SimpleShell(char *home) 00021 { 00022 lookupEnd = 0; 00023 00024 // Set home directory 00025 strncpy(_home, canon(home), MAXBUF); 00026 00027 // Set current working directory 00028 strncpy(_cwd, _home, MAXBUF); 00029 00030 // Built-in shell commands 00031 command(callback(this, &SimpleShell::help), "help"); 00032 command(callback(this, &SimpleShell::pwd), "pwd"); 00033 command(callback(this, &SimpleShell::cat), "cat"); 00034 command(callback(this, &SimpleShell::cd), "cd"); 00035 command(callback(this, &SimpleShell::rm), "rm"); 00036 command(callback(this, &SimpleShell::touch), "touch"); 00037 command(callback(this, &SimpleShell::ls), "ls"); 00038 command(callback(this, &SimpleShell::send), "send"); 00039 } 00040 00041 00042 bool SimpleShell::haswildcard(char *s) { 00043 bool result = strchr(s, '*') != NULL; 00044 return result; 00045 } 00046 00047 00048 /// Path stack representation 00049 typedef std::list<char*> path_t; 00050 00051 char *SimpleShell::canon(char *path) { 00052 path_t pstack; 00053 static char tmp[MAXBUF*2]; 00054 char *e; 00055 00056 // if we're passed empty/null string, just send back cwd so nothing breaks 00057 if (path == NULL || strlen(path) == 0) { 00058 strcpy(tmp, _cwd); 00059 return tmp; 00060 } 00061 00062 // relative path? add current working directory to path stack 00063 if (path[0] != '/') { 00064 strcpy(tmp, _cwd); 00065 strcat(tmp, "/"); 00066 strcat(tmp, path); 00067 } else { 00068 strcpy(tmp, path); 00069 } 00070 00071 // now canonicalize the path spec 00072 e = strtok(tmp+1, "/"); 00073 while (e) { 00074 //printf("e = <%s>\n", e); 00075 if (strcmp("..", e) == 0) { 00076 // pop most recent directory 00077 if (!pstack.empty()) 00078 pstack.pop_back(); 00079 } else if (strcmp(".", e) != 0) { 00080 // push this dir onto path 00081 if (strlen(e) > 0) 00082 pstack.push_back(e); 00083 } 00084 e = strtok(NULL, "/"); 00085 } 00086 00087 static std::string result; 00088 result = ""; 00089 00090 for (path_t::iterator it = pstack.begin(); it != pstack.end(); it++) { 00091 result.append("/"); 00092 result.append(*it); 00093 } 00094 00095 // if empty, add a / 00096 if (result.size() < 2) { 00097 result.append("/"); 00098 } 00099 00100 strcpy(tmp, result.c_str()); 00101 00102 return tmp; 00103 } 00104 00105 00106 char *SimpleShell::basename(char *path) { 00107 char *result = strrchr(path, '/'); 00108 00109 if (result == NULL) { 00110 result = path; 00111 } else { 00112 if (result[0] == '/') result++; 00113 } 00114 00115 return result; 00116 } 00117 00118 00119 void SimpleShell::help(int argc, char **argv) 00120 { 00121 printf("Available commands: "); 00122 for (int i=0; i < lookupEnd; i++) { 00123 printf("%s ", lookup[i].command); 00124 } 00125 printf("\n\n"); 00126 } 00127 00128 00129 void SimpleShell::cd(int argc, char **argv) 00130 { 00131 if (argc == 1) { 00132 strncpy(_cwd, _home, MAXBUF); 00133 } else if (argc == 2) { 00134 strncpy(_cwd, canon(argv[1]), MAXBUF); 00135 } else { 00136 puts("usage: cd directory"); 00137 } 00138 return; 00139 } 00140 00141 00142 void SimpleShell::pwd(int argc, char **argv) 00143 { 00144 puts(_cwd); 00145 return; 00146 } 00147 00148 00149 void SimpleShell::ls(int argc, char **argv) 00150 { 00151 DIR *d; 00152 struct dirent *p; 00153 char *path; 00154 00155 if (argc == 1) { 00156 path = _cwd; 00157 } else if (argc == 2) { 00158 path = canon(argv[1]); 00159 } else { 00160 puts("usage: ls [directory]"); 00161 return; 00162 } 00163 00164 int cols=0; 00165 if ((d = opendir(path)) != NULL) { 00166 while ((p = readdir(d)) != NULL) { 00167 if (p->d_name && p->d_name[0] != 0xff) { 00168 if (cols++ > 3) { 00169 putc('\n', stdout); 00170 cols = 0; 00171 } 00172 printf("%-15s ", p->d_name); 00173 } 00174 } 00175 putc('\n', stdout); 00176 if (cols < 3) 00177 putc('\n', stdout); 00178 closedir(d); 00179 } else { 00180 puts(path); 00181 puts(": No such directory\n"); 00182 } 00183 00184 return; 00185 } 00186 00187 00188 char *SimpleShell::dirname(char *path) 00189 { 00190 char *found = strrchr(path, '/'); 00191 char *result = new char[sizeof(path)]; 00192 00193 char *s = result; 00194 char *t = path; 00195 while (t < found) { 00196 *s++ = *t++; 00197 } 00198 *s = 0; 00199 00200 return result; 00201 } 00202 00203 00204 /** Attempts to match filename pattern and name. 00205 * @param pattern is a pattern containing one '*' 00206 * @param name is the name to check for a match to the pattern 00207 * @returns 1 if match found, 0 if no match or bad pattern 00208 */ 00209 int fnmatch(char *pattern, char *name) 00210 { 00211 char *p; 00212 char *n; 00213 int c; 00214 00215 // only one * allowed 00216 p = pattern; 00217 c = 0; 00218 p = strchr(p, '*'); 00219 while (p) { 00220 c++; 00221 p = strchr(p+1, '*'); 00222 } 00223 if (c != 1) return 0; 00224 00225 // match first part 00226 //puts("first"); 00227 p = pattern; 00228 n = name; 00229 char *s = strchr(pattern, '*'); 00230 while (p != s) { 00231 // mismatch before *? 00232 if (toupper(*p) != toupper(*n)) { 00233 return 0; 00234 } 00235 p++; 00236 n++; 00237 } 00238 // match last part in reverse 00239 //puts("second"); 00240 p = strchr(pattern, 0)-1; 00241 n = strchr(name, 0)-1; 00242 while (p != s) { 00243 // mismatch before *? 00244 //printf("%c %c\n", *p, *n); 00245 if (toupper(*p) != toupper(*n)) { 00246 return 0; 00247 } 00248 p--; 00249 n--; 00250 } 00251 00252 return 1; 00253 } 00254 00255 00256 // Run the specified callback on each matching filename 00257 char *SimpleShell::foreach(char *pattern) 00258 { 00259 DIR *d = 0; 00260 char *base; 00261 char *path; 00262 struct dirent *p; 00263 00264 base = basename(pattern); 00265 path = dirname(pattern); 00266 printf("dir:<%s> base:<%s>\n", path, base); 00267 if ((d = opendir(path)) != NULL) { 00268 while ((p = readdir(d)) != NULL) { 00269 //printf("pattern:<%s> file:<%s>\n", base, p->d_name); 00270 if (fnmatch(base, p->d_name) == 1) { 00271 char *next = new char[sizeof(base) + sizeof(p->d_name) + 2]; 00272 sprintf(next, "%s/%s", path, p->d_name); 00273 printf("Removing %s...\n", next); 00274 int stat = remove(next); 00275 //int stat = f_unlink(next); 00276 if (stat) { 00277 printf("%s: could not remove. Error %d\n", next, stat); 00278 } 00279 delete[] next; 00280 }//if 00281 }//while 00282 closedir(d); 00283 } else { 00284 printf("%s: no such directory\n", path); 00285 } 00286 00287 return 0; 00288 } 00289 00290 00291 void SimpleShell::rm(int argc, char **argv) 00292 { 00293 char *arg; 00294 00295 if (argc >= 2) { 00296 for (int i=1; i < argc; i++) { 00297 arg = canon(argv[i]); 00298 if (haswildcard(argv[i])) { 00299 foreach(arg); 00300 } else if (remove(canon(argv[i]))) { 00301 printf("%s: cannot remove. Error %d\n", argv[i], errno); 00302 } 00303 } 00304 } else { 00305 puts("usage: rm [file1 [file2 ...]]"); 00306 } 00307 } 00308 00309 00310 void SimpleShell::touch(int argc, char **argv) 00311 { 00312 FILE *fp; 00313 00314 if (argc >= 2) { 00315 for (int i=1; i < argc; i++) { 00316 if ((fp = fopen(canon(argv[i]), "w")) != NULL) { 00317 fclose(fp); 00318 } else { 00319 printf("%s: cannot touch\n", argv[1]); 00320 } 00321 } 00322 } else { 00323 puts("usage: touch [file1 [file2 ...]]"); 00324 } 00325 } 00326 00327 00328 void SimpleShell::cat(int argc, char **argv) 00329 { 00330 FILE *fp; 00331 //int status=0; 00332 char *buf = new char[MAXBUF]; 00333 00334 for (int i=1; i < argc; i++) { 00335 //resolveDirectory(path, arg); 00336 if ((fp = fopen(canon(argv[i]), "r")) != NULL) { 00337 while (!feof(fp)) { 00338 fgets(buf, MAXBUF-1, fp); 00339 fputs(buf, stdout); 00340 } 00341 fclose(fp); 00342 } else { 00343 fputs(argv[i], stdout); 00344 fputs(": No such file\n", stdout); 00345 //status = 1; 00346 } 00347 } 00348 delete[] buf; 00349 00350 return; 00351 } 00352 00353 00354 void SimpleShell::send(int argc, char **argv) 00355 { 00356 const char SOF=0x01; 00357 const char ETX=0x03; 00358 const char EOT=0x04; 00359 const char ACK=0x07; 00360 const char NACK=0x18; 00361 char buf[1024]; 00362 FILE *fp; 00363 char c; 00364 00365 int i = 1; 00366 if (argc >= 2) { 00367 if ((fp = fopen(canon(argv[i]), "r")) == 0) { 00368 printf("%s: can't open file\n", basename(argv[i])); 00369 } else { 00370 puts("Ready; initiate receive on client."); 00371 c = getchar(); 00372 if (c == SOF) { 00373 puts(basename(argv[i])); 00374 c = getchar(); 00375 if (c == ACK) { 00376 while (!feof(fp)) { 00377 fgets(buf, 1024, fp); 00378 fputs(buf, stdout); 00379 } 00380 putchar(EOT); 00381 } else if (c == NACK) { 00382 puts("client error."); 00383 } else { 00384 puts("ACK/NACK expected"); 00385 } 00386 } else if (c == NACK) { 00387 puts("server cancelled."); 00388 } else { 00389 puts("SOF/NACK expected."); 00390 } 00391 fclose(fp); 00392 } 00393 } else { 00394 puts("usage: send file1 [file2 ...]"); 00395 } 00396 } 00397 00398 00399 void SimpleShell::run() 00400 { 00401 bool done=false; 00402 callback_t cb; 00403 //int status; // TODO implement command status return 00404 std::string x; 00405 00406 printf("Type help for assistance.\n"); 00407 help(0, NULL); 00408 while (!done) { 00409 printPrompt(); 00410 readCommand(); 00411 if (argv[0]) { // skip blank command 00412 if (cb = findCommand()) { 00413 cb.call(argc, argv); 00414 } else { 00415 printf("command <%s> not found\n", argv[0]); 00416 } 00417 } 00418 } 00419 puts("exiting shell\n"); 00420 00421 return; 00422 } 00423 00424 00425 void SimpleShell::command(callback_t cb, char *command) 00426 { 00427 if (lookupEnd < MAXLOOKUP) { 00428 lookup[lookupEnd].cb = cb; 00429 lookup[lookupEnd].command = command; 00430 lookupEnd++; 00431 } 00432 00433 return; 00434 } 00435 00436 00437 SimpleShell::callback_t SimpleShell::findCommand() 00438 { 00439 SimpleShell::callback_t cb=NULL; 00440 00441 for (int i=0; i < lookupEnd; i++) { 00442 if (strncmp(argv[0], lookup[i].command, MAXBUF) == 0) { 00443 cb = lookup[i].cb; 00444 break; 00445 } 00446 } 00447 00448 return cb; 00449 } 00450 00451 00452 void SimpleShell::printPrompt() 00453 { 00454 fputc('(', stdout); 00455 fputs(_cwd, stdout); 00456 fputs(")# ", stdout); 00457 00458 return; 00459 } 00460 00461 00462 void SimpleShell::readCommand() 00463 { 00464 int i=0; 00465 char c; 00466 bool done = false; 00467 static char cmd[MAXBUF]; 00468 00469 memset(cmd, 0, MAXBUF); 00470 do { 00471 cmd[i] = 0; 00472 c = fgetc(stdin); 00473 if (c == '\r') { // if return is hit, we're done, don't add \r to cmd 00474 done = true; 00475 } else if (c == ESC) { // keyboard escape codes (arrow keys, etc) 00476 int c2 = getchar(); 00477 int c3 = getchar(); 00478 00479 if (c2 == 0x4f && c3 == 0x46) { 00480 printf("<END>"); 00481 } else if (c2 == 0x5b) { 00482 00483 if (c3 == UP) { 00484 printf("<UP>"); 00485 } else if (c3 == DOWN) { 00486 printf("<DOWN>"); 00487 } else if (c3 == RIGHT) { 00488 printf("<RIGHT>"); 00489 } else if (c3 == LEFT) { 00490 printf("<LEFT>"); 00491 } else if (c3 == HOME || c3 == INS || c3 == DEL || 00492 c3 == PGUP || c3 == PGDN) { 00493 char c4 = getchar(); 00494 if (c4 == TAIL) { 00495 if (c4 == HOME) { 00496 printf("<HOME>"); 00497 } else if (c4 == INS) { 00498 printf("<INS>"); 00499 } else if (c4 == DEL) { 00500 printf("<DEL>"); 00501 } else if (c4 == PGUP) { 00502 printf("<PGUP>"); 00503 } else if (c4 == PGDN) { 00504 printf("<PGDN>"); 00505 }//if 00506 }//if 00507 }//if 00508 }//if 00509 //printf("\n"); 00510 } else if (i < MAXBUF-1) { 00511 if (c == 0x7f || c == '\b') { // backspace or delete 00512 if (i > 0) { // if we're at the beginning, do nothing 00513 i--; 00514 fputs("\b \b", stdout); 00515 } 00516 } else { 00517 if (isprint(c)) 00518 fputc(c, stdout); 00519 cmd[i++] = c; 00520 } 00521 } 00522 00523 } while (!done); 00524 fputc('\n', stdout); 00525 00526 // remove leading/trailing whitespace 00527 char *s = cmd; 00528 while (isspace(*s)) { 00529 s++; 00530 } 00531 for (int j=i; j >= 0 && isspace(cmd[j]); j--) { 00532 cmd[j] = '\0'; 00533 } 00534 00535 // split into command and arguments 00536 argc = 0; 00537 char *t; 00538 00539 for (int i=0; i < MAXARGS; i++) { 00540 argv[i] = NULL; 00541 } 00542 t = strtok(s, " "); 00543 while (t && argc < MAXARGS) { 00544 argv[argc++] = t; 00545 t = strtok(NULL, " "); 00546 } 00547 00548 return; 00549 }
Generated on Wed Jul 13 2022 20:07:23 by
1.7.2