Author | Jamozed <[email protected]> |
Date | 2021-11-15 13:42:57 |
Commit | 671f3cde5f8d27a2be3828b1b123b34218f4813c |
Parent | be40c3ece09a28e9a5a7ce4d4f5bf674bdcd1217 |
Implement pipe parsing and execution
Diffstat
M | src/esh.h | | | 2 | +- |
M | src/eval.c | | | 2 | +- |
M | src/exec.c | | | 43 | ++++++++++++++++++++++++++++++++++++------- |
M | src/main.c | | | 7 | +++++++ |
M | src/parse.c | | | 37 | ++++++++++++++++++++++++++----------- |
5 files changed, 71 insertions, 20 deletions
diff --git a/src/esh.h b/src/esh.h index c6d9db9..34d2578 100644 --- a/src/esh.h +++ b/src/esh.h @@ -39,7 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. extern bool Lflag, Pflag; extern int _loop, _ret; -extern int execute(ast a); +extern int execute(ast a, int fdi, int fd[2]); extern void eval(char *src, UINT len); extern void eval_file(const char *file); diff --git a/src/eval.c b/src/eval.c index df9db90..28acf83 100644 --- a/src/eval.c +++ b/src/eval.c @@ -48,7 +48,7 @@ extern void eval(char *src, UINT len) { ast a = parse(&l); if (!a) { goto ret; } if (Pflag) { ast_debug(a); goto ret; } - _ret = execute(a); + _ret = execute(a, fileno(stdin), NULL); ret:; ast_free(a); diff --git a/src/exec.c b/src/exec.c index 9b41634..7bb29e3 100644 --- a/src/exec.c +++ b/src/exec.c @@ -45,15 +45,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. #include <string.h> static int execute_comp(ast a); -static int execute_comm(ast a); +static int execute_comm(ast a, int fdi, int fd[2]); +static int execute_pipe(ast a, int fdi); static int launch(u8 *av[]); /* Execute a program. */ -int execute(ast a) { +int execute(ast a, int fdi, int fd[2]) { switch (a->k) { case AK_COMP: { return execute_comp(a); } - case AK_COMM: { return execute_comm(a); } + case AK_COMM: { return execute_comm(a, fdi, fd); } + case AK_PIPE: { return execute_pipe(a, fdi); } default: { error(-1, "%s: Unimplemented AST", ast_ks[a->k]); } } } @@ -63,15 +65,15 @@ static int execute_comp(ast a) { register int ret = 0; for (UINT i = 0; i != a->c.al; i += 1) { - ret = execute(((ast *)a->c.a)[i]); + ret = execute(((ast *)a->c.a)[i], fileno(stdin), NULL); } return ret; } /* Execute a command statement. */ -static int execute_comm(ast a) { - if (!a->s) { return _ret; } /* What does this achieve? */ +static int execute_comm(ast a, int fdi, int fd[2]) { + if (!a->s) { printf("WDTA?\n"); return _ret; } /* What does this achieve? */ for (struct bltn *b = bltns; b->s; b += 1) { if (strcmp((char *)a->s, b->s) == 0) { @@ -79,7 +81,34 @@ static int execute_comm(ast a) { } } - return WEXITSTATUS(launch(a->c.a)); + pid_t pid; int status; char **av = a->c.a; + + if ((pid = fork()) == 0) { + signal(SIGINT, SIG_DFL); + + dup2(fdi, fileno(stdin)); + + if (fd) { close(fd[0]); dup2(fd[1], fileno(stdout)); } + + if (execvp((char *)av[0], (char **)av) == -1) { + if (errno == ENOENT) { warn("%s: Command not found", av[0]); } + else { perror((char *)av[0]); } exit(1); + } + } + else if (pid == -1) { perror((char *)av[0]); } + else { + /* Wait for the child to die unless its output is piped */ + if (fd) { if (fdi != fileno(stdin)) { close(fdi); } close(fd[1]); } + else { waitpid(pid, &status, 0); } + } + + return WEXITSTATUS(status); +} + +/* Execute a pipe statement. */ +static int execute_pipe(ast a, int fdi) { + int fd[2]; if (pipe(fd) == -1) { warn("PIPE: %s", serr()); return -1; } + execute(a->lc, fdi, fd); return execute(a->rc, fd[0], NULL); } /* Fork and execute an executable. */ diff --git a/src/main.c b/src/main.c index 34bdcac..cdcca1a 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,13 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. */ +/* + FIXME command history is always inserted, even when modifying previous + command, or running an empty command, which results in blank history + entries. + TODO investigate builtins and their functionality with regards to pipes. +*/ + #include "conf.h" #include "esh.h" #include "lineread.h" diff --git a/src/parse.c b/src/parse.c index dea7238..55c38e1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -50,7 +50,7 @@ char *ast_ks[] = { static ast parse_comp(lex *l); static ast parse_comm(lex *l); -static ast parse_pipe(lex *l); +static ast parse_pipe(lex *l, ast lc); static ast parse_rdin(lex *l); static ast parse_rout(lex *l); static ast parse_rerr(lex *l); @@ -65,15 +65,24 @@ void ast_free(ast a) { if (a) { ast_free(a->lc); ast_free(a->rc); free(a); }; } ast parse(lex *l) { if (lex_peek(l).k == TK_EOF) { return NULL; } - return parse_comp(l); + /* TODO assert that the token is a WORD? */ + ast lhs = parse_comm(l); + + switch (lex_next(l).k) { + case TK_PIPE: { return parse_pipe(l, lhs); } + case TK_RDIN: { return lhs; } + case TK_ROUT: { return lhs; } + case TK_RERR: { return lhs; } + default: { return lhs; } + } } -/* Parse a comound statement. */ +/* Parse a compound statement. */ static ast parse_comp(lex *l) { ast a = ast_init(); a->k = AK_COMP; a->c = stack_init((void (*)(void *))&ast_free); - /* Push each command onto the array */ + /* Push each command onto the child stack */ for (; lex_peek(l).k != TK_EOF;) { stack_push(&a->c, parse_comm(l)); } return a; @@ -84,16 +93,17 @@ static ast parse_comm(lex *l) { ast a = ast_init(); a->k = AK_COMM; a->c = stack_init(&free); - /* Push each command argument onto the array. */ + /* Push each command argument onto the child stack */ stack_push(&a->c, (a->s = lex_next(l).s)); - for (tok t; (t = lex_next(l)).k == TK_WORD;) { stack_push(&a->c, t.s); } + for (; lex_peek(l).k == TK_WORD;) { stack_push(&a->c, lex_next(l).s); } stack_push(&a->c, NULL); return a; } /* Parse a pipe statement. */ -static ast parse_pipe(lex *l) { - +static ast parse_pipe(lex *l, ast lc) { + ast a = ast_init(); a->k = AK_PIPE; + a->lc = lc; a->rc = parse(l); return a; } /* Parse a redirect stdin statement. */ @@ -117,7 +127,7 @@ static void ast_debug_indent(ast a, UINT i) { for (UINT j = 0; j != i; ++j) { printf("\t"); } printf("%s: %s", ast_ks[a->k], a->s); - /* Print children if present. */ + /* Print children if present */ switch (a->k) { case AK_COMP: { printf("\n"); @@ -127,9 +137,14 @@ static void ast_debug_indent(ast a, UINT i) { } } break; case AK_COMM: { - for (UINT j = 0; j != a->c.al - 1; j += 1) { + for (UINT j = 1; j != a->c.al - 1; j += 1) { printf(" %s", ((char **)a->c.a)[j]); - } + } printf("\n"); + } break; + case AK_PIPE: { + printf("\n"); + ast_debug_indent(a->lc, i + 1); + ast_debug_indent(a->rc, i + 1); } break; default: { warn("%s: Unimplemented AST (debug)", ast_ks[a->k]); } break; }