2 ** Simple ("tiny") shell to test filename and directory functions.
3 ** Copyright (c) 2013,2016 Christian Groessler, chris@groessler.org
6 #define VERSION_ASC "0.91"
9 #define UPPERCASE /* define (e.g. for Atari) to convert filenames etc. to upper case */
21 #define KEYB_BUFSZ 127
31 #include <sys/param.h>
36 #include <sys/types.h>
41 extern unsigned int getsp(void); /* comes from getsp.s */
57 #define CMD_VERBOSE 13
60 static unsigned char verbose;
61 static unsigned char terminate;
62 static unsigned char cmd;
63 static unsigned char *cmd_asc, *arg1, *arg2, *arg3, *args; /* 'args': everything after command */
64 static unsigned char keyb_buf[KEYB_BUFSZ + 1];
65 static unsigned char keyb_buf2[KEYB_BUFSZ + 1];
66 static size_t cpbuf_sz = 4096;
80 { "mkdir", CMD_MKDIR },
82 { "rmdir", CMD_RMDIR },
84 { "chdir", CMD_CHDIR },
91 { "ren", CMD_RENAME },
97 { "verbose", CMD_VERBOSE },
101 static void banner(void)
103 puts("\"tiny\" command line shell, v" VERSION_ASC);
104 puts("written by chris@groessler.org");
105 puts("type 'help' for help\n");
108 static void get_command(void)
113 static char firstcall = 1;
114 static unsigned int good_sp;
117 sp = good_sp = getsp();
122 printf("SP: 0x%04X ***MISMATCH*** 0x%04X\n", sp, good_sp);
125 printf("SP: 0x%04X\n", sp);
128 arg1 = arg2 = arg3 = NULL;
133 /* get input from the user */
134 if (! fgets(keyb_buf, KEYB_BUFSZ, stdin)) {
140 /* put everything after first string into 'args' */
142 strcpy(keyb_buf2, keyb_buf); /* use a backup copy for 'args' */
144 /* skip over the first non-whitespace item */
145 cmd_asc = strtok(keyb_buf2, " \t\n");
147 args = strtok(NULL, ""); /* get everything */
149 *args = 0; /* no arguments */
151 /* split input into cmd, arg1, arg2, arg3 */
153 /* get and parse command */
154 cmd_asc = strtok(keyb_buf, " \t\n");
160 while (cmd_table[i].name) {
161 if (! strcmp(cmd_table[i].name, cmd_asc)) {
162 cmd = cmd_table[i].code;
169 arg1 = strtok(NULL, " \t\n");
172 arg2 = strtok(NULL, " \t\n");
175 arg3 = strtok(NULL, " \t\n");
178 static void cmd_help(void)
180 puts("quit, exit - exit shell");
181 puts("ls, dir - display current directory");
182 puts(" and drive contents");
183 puts("rm, del - delete file");
184 puts("cp, copy - copy file");
185 puts("mv, ren - rename file");
186 puts("cd, chdir - change directory or drive");
187 puts("md, mkdir - make directory or drive");
188 puts("rd, rmdir - remove directory or drive");
189 puts("exec - run program");
191 puts("cls - clear screen");
193 puts("verbose - set verbosity level");
196 static void cmd_ls(void)
200 struct dirent *dirent;
206 puts("usage: ls [dir]");
210 /* print directory listing */
216 /* not sure if this shouldn't be done by the runtime lib */
217 if (*(arg1 + strlen(arg1) - 1) == ':' || *(arg1 + strlen(arg1) - 1) == '>') {
218 arg = malloc(strlen(arg1) + 4);
220 printf("malloc failed: %s", strerror(errno));
224 memcpy(arg, arg1, strlen(arg1) + 1);
235 printf("Buffer addr: %p\n", arg);
238 if (need_free) free(arg);
241 puts("opendir failed");
245 while (dirent = readdir(dir))
246 puts(dirent->d_name);
251 static void cmd_rm(void)
254 puts("usage: rm <file>");
263 printf("remove failed: %s\n", strerror(errno));
268 static void cmd_mkdir(void)
271 puts("usage: mkdir <dir>");
279 if (mkdir(arg1, 0777))
280 printf("mkdir failed: %s\n", strerror(errno));
283 static void cmd_rmdir(void)
286 puts("usage: rmdir <dir>");
295 printf("rmdir failed: %s\n", strerror(errno));
298 static void cmd_chdir(void)
301 puts("usage: cddir <dir>");
310 printf("chdir failed: %s\n", strerror(errno));
313 static void cmd_pwd(void)
322 buf = malloc(MAXPATHLEN);
324 printf("malloc %u bytes failed: %s\n", MAXPATHLEN, strerror(errno));
328 printf("Buffer addr: %p\n", buf);
329 if (!getcwd(buf, MAXPATHLEN)) {
330 printf("getcwd failed: %s\n", strerror(errno));
339 #endif /* #ifdef HAVE_SUBDIRS */
341 static void cmd_rename(void)
344 puts("usage: mv <oldname> <newname>");
353 if (rename(arg1, arg2))
354 printf("rename failed: %s\n", strerror(errno));
357 static void cmd_exec(void)
359 unsigned char *progname, *arguments;
361 progname = strtok(args, " \t\n");
363 puts("usage: exec <progname> [arguments]");
366 arguments = strtok(NULL, "");
368 /*printf("exec: %s %s\n", progname, arguments ? arguments : "");*/
369 (void)exec(progname, arguments);
370 printf("exec error: %s\n", strerror(errno));
373 static void cmd_copy(void)
375 int srcfd = -1, dstfd = -1;
380 puts("usage: cp <src> <dest>");
389 buf = malloc(cpbuf_sz);
391 printf("malloc %u bytes failed: %s\n", cpbuf_sz, strerror(errno));
395 printf("Buffer addr: %p\n", buf);
399 srcfd = open(arg1, O_RDONLY);
401 printf("open(%s) failed: %s\n", arg1, strerror(errno));
406 readsz = read(srcfd, buf, cpbuf_sz);
408 printf("read error: %s\n", strerror(errno));
415 dstfd = open(arg2, O_WRONLY | O_CREAT | O_TRUNC, 0777);
417 printf("open(%s) failed: %s\n", arg2, strerror(errno));
422 writesz = write(dstfd, buf, readsz);
423 if (writesz < 0 || writesz != readsz) {
424 printf("write error: %s\n", strerror(errno));
427 if (readsz != cpbuf_sz)
432 if (srcfd >= 0) close(srcfd);
433 if (dstfd >= 0) close(dstfd);
437 static void cmd_cls(void)
443 static void cmd_verbose(void)
449 puts("usage: verbose <level>");
453 verb = strtoul(arg1, &endptr, 10);
454 if (verb > 255 || *endptr) {
455 puts("invalid verbosity level");
460 printf("verbosity level set to %d\n", verbose);
463 static void run_command(void)
466 default: puts("internal error"); return;
467 case CMD_NOTHING: return;
468 case CMD_INVALID: puts("invalid command"); return;
469 case CMD_HELP: cmd_help(); return;
470 case CMD_QUIT: terminate = 1; return;
471 case CMD_LS: cmd_ls(); return;
472 case CMD_RM: cmd_rm(); return;
474 case CMD_CHDIR: cmd_chdir(); return;
475 case CMD_MKDIR: cmd_mkdir(); return;
476 case CMD_RMDIR: cmd_rmdir(); return;
477 case CMD_PWD: cmd_pwd(); return;
479 case CMD_EXEC: cmd_exec(); return;
480 case CMD_RENAME: cmd_rename(); return;
481 case CMD_COPY: cmd_copy(); return;
483 case CMD_CLS: cmd_cls(); return;
485 case CMD_VERBOSE: cmd_verbose(); return;
493 while (! terminate) {
500 /* Local Variables: */
501 /* c-file-style: "cpg" */
502 /* c-basic-offset: 4 */