ESH

Executive Shell
git clone http://git.omkov.net/ESH
Log | Tree | Refs | README | Download

AuthorJamozed <[email protected]>
Date2021-11-15 13:42:57
Commit671f3cde5f8d27a2be3828b1b123b34218f4813c
Parentbe40c3ece09a28e9a5a7ce4d4f5bf674bdcd1217

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;
 	}