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:
Wed Dec 26 15:51:42 2018 +0000
Revision:
28:753db82debb1
Parent:
24:004e33abce37
Child:
29:8d4132274445
added complete path canonicalization

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