diff options
Diffstat (limited to 'src/cmd/shell/parser.c')
-rw-r--r-- | src/cmd/shell/parser.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/cmd/shell/parser.c b/src/cmd/shell/parser.c new file mode 100644 index 0000000..ad09348 --- /dev/null +++ b/src/cmd/shell/parser.c @@ -0,0 +1,76 @@ +#include "shell.h" +#include <ctype.h> +#include <stdbool.h> +#include <string.h> + +static char skipspace(char **sp) { + char *s = *sp; + while (*s && isspace(*s)) s++; + *sp = s; + return *s; +} + +static bool isspecial(char c) { + return c == '>' || c == '#'; +} + +static char *parg(char **sp) { + char *s = *sp; + char *res = NULL; + + if (skipspace(&s)) { + // TODO incorrectly handles strings like a"b" + switch (*s) { + case '"': + s++; + res = s; + while (*s && *s != '"') + s++; + break; + default: + res = s; + while (*s && !isspace(*s) && !isspecial(*s)) + s++; + if (*s == '#') { + *s = '\0'; /* end parsing early */ + if (res == s) /* don't output an empty arg */ + res = NULL; + } + break; + } + if (*s) *s++ = '\0'; + } + + *sp = s; + return res; +} + +int parse(char *s, char **argv, size_t argvlen, struct redir *redir) { + if (argvlen == 0) return -1; + size_t argc = 0; + char *arg; + + *argv = NULL; + redir->stdout = NULL; + redir->append = false; + + while (skipspace(&s)) { + switch (*s) { + case '>': + s++; + if (*s == '>') { + s++; + redir->append = true; + } + redir->stdout = parg(&s); + break; + default: + arg = parg(&s); + argv[argc++] = arg; + if (argc >= argvlen) + return -1; + } + } + argv[argc] = NULL; + return argc; +} |