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 24 18:52:57 2018 +0000
Revision:
24:004e33abce37
Parent:
23:b1e49cfcaef6
Child:
28:753db82debb1
Implemented file send

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