From 67718cbcda566127b8c5b38ecda83cbd469dbc3f Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 27 Jul 2022 20:02:50 +0200 Subject: user/shell: actual parsing, multiple argument support --- src/user/app/shell/parser.c | 64 +++++++++++++++++++++++++++++ src/user/app/shell/shell.c | 98 ++++++++++++++++++--------------------------- src/user/app/shell/shell.h | 4 ++ 3 files changed, 108 insertions(+), 58 deletions(-) create mode 100644 src/user/app/shell/parser.c create mode 100644 src/user/app/shell/shell.h (limited to 'src') diff --git a/src/user/app/shell/parser.c b/src/user/app/shell/parser.c new file mode 100644 index 0000000..bd70350 --- /dev/null +++ b/src/user/app/shell/parser.c @@ -0,0 +1,64 @@ +#include "shell.h" +#include +#include + +static bool isspace(char c) { + return c == ' ' || c == '\t' || c == '\n'; +} + +static char skipspace(char **sp) { + char *s = *sp; + while (*s && isspace(*s)) s++; + *sp = s; + return *s; +} + +static char *parg(char **sp) { + char *s = *sp; + char *res = NULL; + + if (skipspace(&s)) { + switch (*s) { + case '"': + s++; + res = s; + while (*s && *s != '"') + s++; + break; + default: + res = s; + while (*s && !isspace(*s) && *s != '>') + s++; + break; + } + if (*s) *s++ = '\0'; + } + + *sp = s; + return res; +} + +int parse(char *s, char **argv, size_t argvlen, char **redir) { + if (argvlen == 0) return -1; + size_t argc = 0; + char *arg; + + *argv = NULL; + *redir = NULL; + + while (skipspace(&s)) { + switch (*s) { + case '>': + s++; + *redir = parg(&s); + break; + default: + arg = parg(&s); + argv[argc++] = arg; + if (argc >= argvlen) + return -1; + } + } + argv[argc] = NULL; + return argc; +} diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c index 0196d5b..f99f27e 100644 --- a/src/user/app/shell/shell.c +++ b/src/user/app/shell/shell.c @@ -1,4 +1,5 @@ #include "builtins.h" +#include "shell.h" #include #include #include @@ -9,33 +10,6 @@ int main(); -static bool isspace(char c) { - return c == ' ' || c == '\t' || c == '\n'; -} - -static char *strsplit(char *base, char delim) { - if (!base) return NULL; - while (*base) { - if (delim ? *base == delim : isspace(*base)) { - *base++ = '\0'; - return base; - } - base++; - } - return NULL; -} - -static char *strtrim(char *s) { - char *end; - if (!s) return NULL; - while (isspace(*s)) s++; - end = s + strlen(s); - while (end > s && isspace(end[-1])) end--; - *end = '\0'; - return s; -} - - // TODO fgets static int readline(char *buf, size_t max) { char c = '\0'; @@ -46,42 +20,46 @@ static int readline(char *buf, size_t max) { return pos; } -static void execp(const char *cmd) { - if (*cmd == '/') { - execv(cmd, NULL); +static void execp(char **argv) { + if (!argv || !*argv) return; + if (argv[0][0] == '/') { + execv(argv[0], argv); return; } - size_t cmdlen = strlen(cmd); + size_t cmdlen = strlen(argv[0]); char *s = malloc(cmdlen); if (!s) { printf("sh: out of memory.\n"); exit(1); } memcpy(s, "/bin/", 5); - memcpy(s + 5, cmd, cmdlen + 1); - - char *argv[] = {(char*)cmd, NULL}; + memcpy(s + 5, argv[0], cmdlen + 1); + argv[0] = s; execv(s, argv); free(s); } static void run(char *cmd) { - char *args, *redir; - cmd = strtrim(cmd); - if (!*cmd) return; + #define ARGV_MAX 16 + char *argv[ARGV_MAX]; + char *redir; + + int ret = parse(cmd, argv, ARGV_MAX, &redir); + if (ret < 0) { + printf("sh: error parsing command\n"); + return; + } - redir = strtrim(strsplit(cmd, '>')); - cmd = strtrim(cmd); - args = strtrim(strsplit(cmd, 0)); + if (!*argv) return; /* "special" commands that can't be handled in a subprocess */ - if (!strcmp(cmd, "shadow")) { + if (!strcmp(argv[0], "shadow")) { // TODO process groups - _syscall_mount(-1, args, strlen(args)); + _syscall_mount(-1, argv[1], strlen(argv[1])); return; - } else if (!strcmp(cmd, "exit")) { + } else if (!strcmp(argv[0], "exit")) { exit(0); } @@ -95,17 +73,21 @@ static void run(char *cmd) { exit(0); } - if (!strcmp(cmd, "echo")) { - printf("%s\n", args); - } else if (!strcmp(cmd, "fork")) { + if (!strcmp(argv[0], "echo")) { + printf("%s", argv[1]); + for (int i = 2; argv[i]; i++) + printf(" %s", argv[1]); + printf("\n"); + } else if (!strcmp(argv[0], "fork")) { main(); - } else if (!strcmp(cmd, "cat")) { - cmd_cat_ls(args, false); - } else if (!strcmp(cmd, "ls")) { - cmd_cat_ls(args, true); - } else if (!strcmp(cmd, "hexdump")) { - cmd_hexdump(args); - } else if (!strcmp(cmd, "catall")) { + } else if (!strcmp(argv[0], "cat")) { + // TODO better argv handling + cmd_cat_ls(argv[1], false); + } else if (!strcmp(argv[0], "ls")) { + cmd_cat_ls(argv[1], true); + } else if (!strcmp(argv[0], "hexdump")) { + cmd_hexdump(argv[1]); + } else if (!strcmp(argv[0], "catall")) { const char *files[] = { "/init/fake.txt", "/init/1.txt", "/init/2.txt", @@ -115,14 +97,14 @@ static void run(char *cmd) { cmd_cat_ls(files[i], false); printf("\n"); } - } else if (!strcmp(cmd, "touch")) { - cmd_touch(args); + } else if (!strcmp(argv[0], "touch")) { + cmd_touch(argv[1]); } else { - execp(cmd); + execp(argv); if (errno == EINVAL) { - printf("%s isn't a valid executable\n", cmd); + printf("%s isn't a valid executable\n", argv[0]); } else { - printf("unknown command: %s\n", cmd); + printf("unknown command: %s\n", argv[0]); } } exit(0); /* kills the subprocess */ diff --git a/src/user/app/shell/shell.h b/src/user/app/shell/shell.h new file mode 100644 index 0000000..986ce22 --- /dev/null +++ b/src/user/app/shell/shell.h @@ -0,0 +1,4 @@ +#pragma once +#include + +int parse(char *str, char **argv, size_t argvlen, char **redir); -- cgit v1.2.3