summaryrefslogtreecommitdiff
path: root/src/user/app/shell
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/app/shell')
-rw-r--r--src/user/app/shell/parser.c64
-rw-r--r--src/user/app/shell/shell.c98
-rw-r--r--src/user/app/shell/shell.h4
3 files changed, 108 insertions, 58 deletions
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 <stdbool.h>
+#include <string.h>
+
+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 <camellia/syscalls.h>
#include <errno.h>
#include <stdbool.h>
@@ -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 <stddef.h>
+
+int parse(char *str, char **argv, size_t argvlen, char **redir);