diff --git a/testcode/lib/tinyshell.c b/testcode/lib/tinyshell.c new file mode 100644 index 000000000..f4a18126b --- /dev/null +++ b/testcode/lib/tinyshell.c @@ -0,0 +1,385 @@ +/* + * Simple ("tiny") shell to test filename and directory functions. + * Copyright (c) 2013, Christian Groessler, chris@groessler.org + */ + +#define VERSION_ASC "0.90" + +#define KEYB_BUFSZ 80 +#define PROMPT ">>> " +#ifdef __ATARI__ +#define UPPERCASE /* define (e.g. for Atari) to convert filenames etc. to upper case */ +#endif + +#include +#include +#include +#include +#include +#ifndef __CC65__ +#include +#include +#else +#define MAXPATHLEN 64 +#endif +#include +#include +#include + +#define CMD_NOTHING 0 +#define CMD_INVALID 1 +#define CMD_HELP 2 +#define CMD_QUIT 3 +#define CMD_LS 4 +#define CMD_MKDIR 5 +#define CMD_RMDIR 6 +#define CMD_CHDIR 7 +#define CMD_RM 8 +#define CMD_RENAME 9 +#define CMD_COPY 10 +#define CMD_PWD 11 + +static unsigned char terminate; +static unsigned char cmd; +static unsigned char *cmd_asc, *arg1, *arg2, *arg3; +static unsigned char keyb_buf[KEYB_BUFSZ]; +static size_t cpbuf_sz = 4096; + +struct cmd_table { + unsigned char *name; + unsigned char code; +} cmd_table[] = { + { "help", CMD_HELP }, + { "quit", CMD_QUIT }, + { "q", CMD_QUIT }, + { "exit", CMD_QUIT }, + { "ls", CMD_LS }, + { "dir", CMD_LS }, + { "md", CMD_MKDIR }, + { "mkdir", CMD_MKDIR }, + { "rd", CMD_RMDIR }, + { "rmdir", CMD_RMDIR }, + { "cd", CMD_CHDIR }, + { "chdir", CMD_CHDIR }, + { "rm", CMD_RM }, + { "del", CMD_RM }, + { "cp", CMD_COPY }, + { "copy", CMD_COPY }, + { "mv", CMD_RENAME }, + { "ren", CMD_RENAME }, + { "pwd", CMD_PWD }, + { NULL, 0 } +}; + +static void banner(void) +{ + puts("\"tiny\" command line shell, v" VERSION_ASC); + puts("written by chris@groessler.org"); + puts("type 'help' for help\n"); +} + +static void get_command(void) +{ + unsigned char i = 0; + + arg1 = arg2 = arg3 = NULL; + + /* issue prompt */ + printf(PROMPT); + + /* get input from the user */ + if (! fgets(keyb_buf, KEYB_BUFSZ, stdin)) { + puts(""); + cmd = CMD_QUIT; + return; + } + + /* split input into cmd, arg1, arg2, arg3 */ + + /* get and parse command */ + cmd_asc = strtok(keyb_buf, " \t\n"); + if (! cmd_asc) { + cmd = CMD_NOTHING; + return; + } + cmd = CMD_INVALID; + while (cmd_table[i].name) { + if (! strcmp(cmd_table[i].name, cmd_asc)) { + cmd = cmd_table[i].code; + break; + } + i++; + } + + /* get arguments */ + arg1 = strtok(NULL, " \t\n"); + if (! arg1) + return; + arg2 = strtok(NULL, " \t\n"); + if (! arg2) + return; + arg3 = strtok(NULL, " \t\n"); +} + +static void cmd_help(void) +{ + puts("quit, exit - exit shell"); + puts("ls, dir - display current directory"); + puts(" and drive contents"); + puts("rm, del - delete file"); + puts("cp, copy - copy file"); + puts("mv, ren - rename file"); + puts("cd, chdir - change directory or drive"); + puts("md, mkdir - make directory or drive"); + puts("rd, rmdir - remove directory or drive"); + puts("sorry, you cannot start programs here"); +} + +static void cmd_ls(void) +{ + DIR *dir; + unsigned char *arg; + struct dirent *dirent; +#ifdef __ATARI__ + char need_free = 0; +#endif + + if (arg2) { + puts("usage: ls [dir]"); + return; + } + + /* print directory listing */ + if (arg1) { +#ifdef UPPERCASE + strupr(arg1); +#endif +#ifdef __ATARI__ + /* not sure if this shouldn't be done by the runtime lib */ + if (*(arg1 + strlen(arg1) - 1) == ':' || *(arg1 + strlen(arg1) - 1) == '>') { + arg = malloc(strlen(arg1) + 4); + if (! arg) { + printf("malloc failed: %s", strerror(errno)); + return; + } + need_free = 1; + memcpy(arg, arg1, strlen(arg1) + 1); + strcat(arg, "*.*"); + } + else +#endif + arg = arg1; + } + else + arg = "."; + + dir = opendir(arg); +#ifdef __ATARI__ + if (need_free) free(arg); +#endif + if (! dir) { + puts("opendir failed"); + return; + } + + while (dirent = readdir(dir)) + puts(dirent->d_name); + + closedir(dir); +} + +static void cmd_rm(void) +{ + if (!arg1 || arg2) { + puts("usage: rm "); + return; + } + +#ifdef UPPERCASE + strupr(arg1); +#endif + + if (unlink(arg1)) + printf("remove failed: %s\n", strerror(errno)); +} + +static void cmd_mkdir(void) +{ + if (!arg1 || arg2) { + puts("usage: mkdir "); + return; + } + +#ifdef UPPERCASE + strupr(arg1); +#endif + + if (mkdir(arg1, 0777)) + printf("mkdir failed: %s\n", strerror(errno)); +} + +static void cmd_rmdir(void) +{ + if (!arg1 || arg2) { + puts("usage: rmdir "); + return; + } + +#ifdef UPPERCASE + strupr(arg1); +#endif + + if (rmdir(arg1)) + printf("rmdir failed: %s\n", strerror(errno)); +} + +static void cmd_chdir(void) +{ + if (!arg1 || arg2) { + puts("usage: cddir "); + return; + } + +#ifdef UPPERCASE + strupr(arg1); +#endif + + if (chdir(arg1)) + printf("chdir failed: %s\n", strerror(errno)); +} + +static void cmd_pwd(void) +{ + char *buf; + + if (arg1) { + puts("usage: pwd"); + return; + } + + buf = malloc(MAXPATHLEN); + if (! buf) { + printf("malloc %u bytes failed: %s\n", MAXPATHLEN, strerror(errno)); + return; + } + if (!getcwd(buf, MAXPATHLEN)) { + printf("getcwd failed: %s\n", strerror(errno)); + free(buf); + return; + } + + puts(buf); + free(buf); +} + +static void cmd_rename(void) +{ + if (!arg2 || arg3) { + puts("usage: mv "); + return; + } + +#ifdef UPPERCASE + strupr(arg1); + strupr(arg2); +#endif + + if (rename(arg1, arg2)) + printf("rename failed: %s\n", strerror(errno)); +} + +static void cmd_copy(void) +{ + int srcfd = -1, dstfd = -1; + unsigned char *buf; + int readsz, writesz; + + if (!arg2 || arg3) { + puts("usage: cp "); + return; + } + +#ifdef UPPERCASE + strupr(arg1); + strupr(arg2); +#endif + + buf = malloc(cpbuf_sz); + if (! buf) { + printf("malloc %u bytes failed: %s\n", cpbuf_sz, strerror(errno)); + return; + } + + while (1) { + if (srcfd == -1) { + srcfd = open(arg1, O_RDONLY); + if (srcfd < 0) { + printf("open(%s) failed: %s\n", arg1, strerror(errno)); + break; + } + } + + readsz = read(srcfd, buf, cpbuf_sz); + if (readsz < 0) { + printf("read error: %s\n", strerror(errno)); + break; + } + if (! readsz) + break; + + if (dstfd == -1) { + dstfd = open(arg2, O_WRONLY | O_CREAT | O_TRUNC, 0777); + if (dstfd < 0) { + printf("open(%s) failed: %s\n", arg2, strerror(errno)); + break; + } + } + + writesz = write(dstfd, buf, readsz); + if (writesz < 0 || writesz != readsz) { + printf("write error: %s\n", strerror(errno)); + break; + } + if (readsz != cpbuf_sz) + break; + } + + free(buf); + if (srcfd >= 0) close(srcfd); + if (dstfd >= 0) close(dstfd); +} + +static void run_command(void) +{ + switch (cmd) { + default: puts("internal error"); return; + case CMD_NOTHING: return; + case CMD_INVALID: puts("invalid command"); return; + case CMD_HELP: cmd_help(); return; + case CMD_QUIT: terminate = 1; return; + case CMD_LS: cmd_ls(); return; + case CMD_RM: cmd_rm(); return; + case CMD_CHDIR: cmd_chdir(); return; + case CMD_MKDIR: cmd_mkdir(); return; + case CMD_RMDIR: cmd_rmdir(); return; + case CMD_PWD: cmd_pwd(); return; + case CMD_RENAME: cmd_rename(); return; + case CMD_COPY: cmd_copy(); return; + } +} + +int main(void) +{ + banner(); + + while (! terminate) { + get_command(); + run_command(); + } + return 0; +} + +/* Local Variables: */ +/* c-file-style: "cpg" */ +/* c-basic-offset: 4 */ +/* End: */