ESH

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

AuthorJamozed <[email protected]>
Date2021-09-11 11:19:36
Commitde472f3d6ef1bb1c9594755d2c900bc95d959912
Parent30bbeefe64d845ddc2dadda0fbe7dac5aed33a01

Reimplement command evaluation

Diffstat

M src/alias.c | 2 +-
M src/alias.h | 2 +-
M src/bltn.c | 26 +++++++++++++++-----------
M src/bltn.h | 2 +-
M src/bltns/cd.c | 8 +++-----
A src/bltns/eval.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/bltns/pwd.c | 10 ++++------
M src/bltns/set.c | 4 +---
M src/esh.h | 18 ++++++++++++------
A src/eval.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/exec.c | 16 +++++++++-------
M src/main.c | 34 ++++++++++++----------------------
M src/parse.c | 24 ++++++++++++------------

13 files changed, 229 insertions, 75 deletions

diff --git a/src/alias.c b/src/alias.c
index ffddd28..a518672 100644
--- a/src/alias.c
+++ b/src/alias.c
@@ -60,7 +60,7 @@ void pushalias(akas_t *akas, aka_t aka) {
 	return;
 }
 
-int bltn_alias(char *argv[]) {
+int bltn_alias(int ac, char *argv[]) {
 	if (!argv[1]) { for (aka_t *a = akas.dat; a->str; ++a) {
 		printf("alias %s='%s'\n", a->str, a->com);
 	} return 0; }
diff --git a/src/alias.h b/src/alias.h
index 9e5a8a6..c18eabe 100644
--- a/src/alias.h
+++ b/src/alias.h
@@ -43,6 +43,6 @@ extern void initalias(void);
 extern void freealias(void);
 extern void pushalias(akas_t *akas, aka_t aka);
 
-extern int bltn_alias(char *argv[]);
+extern int bltn_alias(int ac, char *argv[]);
 
 #endif // ESH_ALIAS_H_0BXOPDLM
diff --git a/src/bltn.c b/src/bltn.c
index f5d8688..c854294 100644
--- a/src/bltn.c
+++ b/src/bltn.c
@@ -39,17 +39,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 #include <stdio.h>
 
-static int bltn_eval(char *av[]) { warn("eval: Unimplemented"); return -1; }
-static int bltn_exit(char *av[]) { (void)(av); _loop = 0; return 0; }
-static int bltn_false(char *av[]) { (void)(av); return 1; }
-static int bltn_help(char *av[]);
-static int bltn_true(char *av[]) { (void)(av); return 0; }
+static int bltn_exit(int ac, char *av[]) { _loop = 0; return 0; }
+static int bltn_false(int ac, char *av[]) { return 1; }
+static int bltn_help(int ac, char *av[]);
+static int bltn_true(int ac, char *av[]) { return 0; }
 
-extern int bltn_cd(char *av[]);
-extern int bltn_pwd(char *av[]);
-extern int bltn_set(char *av[]);
+extern int bltn_cd(int ac, char *av[]);
+extern int bltn_eval(int ac, char *av[]);
+extern int bltn_pwd(int ac, char *av[]);
+extern int bltn_set(int ac, char *av[]);
 
-static int getret(char *av[]) { printf("%i\n", _ret); return 0; }
+static int getret(int ac, char *av[]) { printf("%i\n", _ret); return 0; }
 
 struct bltn bltns[] = {
 	{"alias", &bltn_alias},
@@ -65,6 +65,10 @@ struct bltn bltns[] = {
 	{NULL, NULL}
 };
 
-static int bltn_help(char *av[]) { (void)(av);
-	puts("ESH, version " PROJECT_VERSION); return 0;
+static int bltn_help(int ac, char *av[]) {
+	puts("ESH, version " PROJECT_VERSION);
+	puts("Copyright (C) 2020, Jakob Wakeling");
+	puts("All rights reserved.");
+	puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");
+	return 0;
 }
diff --git a/src/bltn.h b/src/bltn.h
index 3c461ca..4e811dc 100644
--- a/src/bltn.h
+++ b/src/bltn.h
@@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 #ifndef OMKOV_ESH_BLTN_H_XQ5D812A
 #define OMKOV_ESH_BLTN_H_XQ5D812A
 
-struct bltn { const char *s; int (*f)(char *[]); };
+struct bltn { const char *s; int (*f)(int, char *[]); };
 extern struct bltn bltns[];
 
 #endif // OMKOV_ESH_BLTN_H_XQ5D812A
diff --git a/src/bltns/cd.c b/src/bltns/cd.c
index 1d35d99..3c20798 100644
--- a/src/bltns/cd.c
+++ b/src/bltns/cd.c
@@ -1,4 +1,4 @@
-// cd.c, version 0.1.1
+// cd.c
 // cd builtin source file for ESH
 // Copyright (C) 2020, Jakob Wakeling
 // All rights reserved.
@@ -39,8 +39,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 #include <stdlib.h>
 #include <string.h>
 
-#define VERSION "0.1.1"
-
 static struct lop lops[] = {
 	{ "help",    ARG_NUL, 256 },
 	{ "version", ARG_NUL, 257 },
@@ -52,7 +50,7 @@ static int mode = 0;
 static void hlp(void);
 static void ver(void);
 
-int bltn_cd(char *av[]) {
+int bltn_cd(int ac, char *av[]) {
 	struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = lops;
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
 	case 'L': { mode = 0; break; }
@@ -85,7 +83,7 @@ static void hlp(void) {
 }
 
 static void ver(void) {
-	puts("ESH cd, version " VERSION);
+	puts("ESH, version " PROJECT_VERSION);
 	puts("Copyright (C) 2020, Jakob Wakeling");
 	puts("All rights reserved.");
 	puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");
diff --git a/src/bltns/eval.c b/src/bltns/eval.c
new file mode 100644
index 0000000..778bf7e
--- /dev/null
+++ b/src/bltns/eval.c
@@ -0,0 +1,87 @@
+// eval.c
+// eval builtin source file for ESH
+// Copyright (C) 2020, Jakob Wakeling
+// All rights reserved.
+
+/*
+OMKOV Permissive Licence, version 1.0
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimers.
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimers in the documentation and/or
+  other materials provided with the distribution.
+* Neither the names of the copyright holders, nor the names of its contributors
+  may be used to endorse or promote products derived from this Software without
+  specific prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
+HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+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.
+*/
+
+#include "../esh.h"
+#include "../util/util.h"
+
+#include "../cll/optget.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static struct lop lops[] = {
+	{ "help",     ARG_NUL, 256 },
+	{ "version",  ARG_NUL, 257 },
+	{ NULL, 0, 0 }
+};
+
+static void hlp(void);
+static void ver(void);
+
+int bltn_eval(int ac, char *av[]) {
+	struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
+	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
+	case 256: { hlp(); return 0; }
+	case 257: { ver(); return 0; }
+	default: { return 1; }
+	}
+	
+	u8 *args, *dest; UINT size = 0;
+	
+	for (UINT i = 0; i != ac - opt.ind; i += 1) {
+		size += (strlen(av[opt.ind + i]) + 1);
+	}
+	
+	args = assert_calloc(size, sizeof (*args)); dest = args;
+	
+	for (UINT i = 0; i != ac - opt.ind; i += 1) {
+		if (i != 0) { strncat((char *)dest, " ", 1); dest += 1; }
+		strcat((char *)dest, av[opt.ind + i]); dest += strlen(av[opt.ind + i]);
+	}
+	
+	eval(args, size); return 0;
+}
+
+static void hlp(void) {
+	puts("eval - Execute arguments as a command\n");
+	puts("Usage: eval [argument...]\n");
+	puts("Options:");
+	puts("  --help     Display help information");
+	puts("  --version  Display version information");
+}
+
+static void ver(void) {
+	puts("ESH, version " PROJECT_VERSION);
+	puts("Copyright (C) 2020, Jakob Wakeling");
+	puts("All rights reserved.");
+	puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");
+}
diff --git a/src/bltns/pwd.c b/src/bltns/pwd.c
index 615e9e3..6ae9fe9 100644
--- a/src/bltns/pwd.c
+++ b/src/bltns/pwd.c
@@ -1,5 +1,5 @@
-// pwd.c, version 1.0.1b
-// OMKOV coreutils pwd adapted as an ESH builtin
+// pwd.c
+// pwd builtin source file for ESH
 // Copyright (C) 2020, Jakob Wakeling
 // All rights reserved.
 
@@ -37,8 +37,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 #include <stdio.h>
 #include <stdlib.h>
 
-#define VERSION "1.0.1b"
-
 static struct lop lops[] = {
 	{ "help",    ARG_NUL, 256 },
 	{ "version", ARG_NUL, 257 },
@@ -50,7 +48,7 @@ static int mode = 0;
 static void hlp(void);
 static void ver(void);
 
-int bltn_pwd(char *av[]) {
+int bltn_pwd(int ac, char *av[]) {
 	struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = lops;
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
 	case 'L': { mode = 0; break; }
@@ -82,7 +80,7 @@ static void hlp(void) {
 }
 
 static void ver(void) {
-	puts("OMKOV coreutils pwd, version " VERSION);
+	puts("ESH, version " PROJECT_VERSION);
 	puts("Copyright (C) 2020, Jakob Wakeling");
 	puts("All rights reserved.");
 	puts("OMKOV Permissive Licence (https://www.omkov.net/OLPE)");
diff --git a/src/bltns/set.c b/src/bltns/set.c
index 48fffbf..36ec030 100644
--- a/src/bltns/set.c
+++ b/src/bltns/set.c
@@ -46,12 +46,10 @@ static struct lop lops[] = {
 	{ NULL, 0, 0 }
 };
 
-static int mode = 0;
-
 static void hlp(void);
 static void ver(void);
 
-int bltn_set(char *av[]) {
+int bltn_set(int ac, char *av[]) {
 	struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
 	case 256: { hlp(); return 0; }
diff --git a/src/esh.h b/src/esh.h
index 86d0dd9..592fd5d 100644
--- a/src/esh.h
+++ b/src/esh.h
@@ -43,11 +43,14 @@ typedef enum {
 
 typedef enum { AK_NULL, AK_COMP, AK_COMM } ast_k;
 
+typedef struct ast_ *ast;
+
 typedef struct { tok_k k; u8 *s; } tok;
 typedef struct { u8 *s; UINT sp, sl; tok t; } lex;
 
-typedef struct { ast_k k; u8 *s; array c; } ast;
+struct ast_ { ast_k k; u8 *s; array c; };
 
+extern bool Lflag, Pflag;
 extern int _loop, _ret;
 
 extern u8 *tok_ks[];
@@ -57,14 +60,17 @@ extern lex lex_init(u8 *src, UINT len);
 extern tok lex_next(lex *l);
 extern tok lex_peek(lex *l);
 
-extern ast *ast_init(void);
-extern void ast_free(ast *a);
+extern ast ast_init(void);
+extern void ast_free(ast a);
+
+extern ast parse(lex *l);
 
-extern ast *parse(lex *l);
+extern int execute(ast a);
 
-extern int execute(ast *a);
+extern void eval(u8 *src, UINT len);
+extern void eval_file(const u8 *file);
 
 extern void lex_debug(lex *l);
-extern void ast_debug(ast *a);
+extern void ast_debug(ast a);
 
 #endif // ESH_ESH_H_SAZDXXFN
diff --git a/src/eval.c b/src/eval.c
new file mode 100644
index 0000000..eadaca0
--- /dev/null
+++ b/src/eval.c
@@ -0,0 +1,71 @@
+// eval.c
+// Evaluation source file for ESH
+// Copyright (C) 2020, Jakob Wakeling
+// All rights reserved.
+
+/*
+OMKOV Permissive Licence, version 1.0
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimers.
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimers in the documentation and/or
+  other materials provided with the distribution.
+* Neither the names of the copyright holders, nor the names of its contributors
+  may be used to endorse or promote products derived from this Software without
+  specific prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
+HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+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.
+*/
+
+#include "esh.h"
+#include "util/util.h"
+
+#include "cll/error.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Evaluate a string. */
+extern void eval(u8 *src, UINT len) {
+	lex l = lex_init(src, len);
+	if (Lflag) { lex_debug(&l); goto ret; }
+	
+	ast a = parse(&l); if (!a) { goto ret; }
+	if (Pflag) { ast_debug(a); goto ret; }
+	
+	_ret = WEXITSTATUS(execute(a));
+	
+ret:;
+	ast_free(a);
+}
+
+/* Evaluate a file. */
+extern void eval_file(const u8 *file) {
+	FILE *fi; u8 *fb; size_t fl;
+	
+	if (!(fi = fopen((char *)file, "r"))) {
+		warn("%s: %s", file, serr());
+		_ret = WEXITSTATUS(-1); return;
+	}
+	
+	fseek(fi, 0, SEEK_END); fl = ftell(fi); rewind(fi);
+	
+	fb = assert_malloc((fl + 1) * sizeof (*fb));
+	fread(fb, 1, fl, fi); fb[fl] = 0; fclose(fi);
+	
+	eval(fb, fl); free(fb); return;
+}
diff --git a/src/exec.c b/src/exec.c
index 7e42746..bfea0ce 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,5 +1,5 @@
 // exec.c
-// Exec source file for ESH
+// Execution source file for ESH
 // Copyright (C) 2020, Jakob Wakeling
 // All rights reserved.
 
@@ -44,13 +44,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 #include <stdlib.h>
 #include <string.h>
 
-static int execute_comp(ast *a);
-static int execute_comm(ast *a);
+static int execute_comp(ast a);
+static int execute_comm(ast a);
 
 static int launch(u8 *av[]);
 
 /* Execute a program. */
-int execute(ast *a) {
+int execute(ast a) {
 	switch (a->k) {
 	case AK_COMP: { return execute_comp(a); }
 	case AK_COMM: { return execute_comm(a); }
@@ -59,7 +59,7 @@ int execute(ast *a) {
 }
 
 /* Execute a compound statement. */
-static int execute_comp(ast *a) {
+static int execute_comp(ast a) {
 	register int ret = 0;
 
 	for (UINT i = 0; i != a->c->size; i += 1) {
@@ -70,11 +70,13 @@ static int execute_comp(ast *a) {
 }
 
 /* Execute a command statement. */
-static int execute_comm(ast *a) {
+static int execute_comm(ast a) {
 	if (!a->s) { return _ret; } /* What does this achieve? */
 
 	for (struct bltn *b = bltns; b->s; b += 1) {
-		if (strcmp((char *)a->s, b->s) == 0) { return b->f((char **)a->c->data); }
+		if (strcmp((char *)a->s, b->s) == 0) {
+			return b->f(a->c->size - 1, (char **)a->c->data);
+		}
 	}
 
 	return launch((u8 **)a->c->data);
diff --git a/src/main.c b/src/main.c
index ee6bfb1..e60db54 100644
--- a/src/main.c
+++ b/src/main.c
@@ -45,13 +45,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 #include <string.h>
 
 static struct lop lops[] = {
-	{ "help",    ARG_NUL, 256 },
-	{ "version", ARG_NUL, 257 },
+	{ "help",        ARG_NUL, 256 },
+	{ "version",     ARG_NUL, 257 },
+	{ "debug-lex",   ARG_NUL, 258 },
+	{ "debug-parse", ARG_NUL, 259 },
 	{ NULL, 0, 0 }
 };
 
-static bool Lflag = false, Pflag = false;
-
+bool Lflag = false, Pflag = false;
 int _loop = 1, _ret;
 
 static jmp_buf jmp;
@@ -63,12 +64,12 @@ static void hlp(void);
 static void ver(void);
 
 int main(int ac, char *av[]) { (void)(ac); A0 = av[0];
-	struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = lops;
+	struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
-	case 'L': { Lflag = true; } break;
-	case 'P': { Pflag = true; } break;
 	case 256: { hlp(); return 0; }
 	case 257: { ver(); return 0; }
+	case 258: { Lflag = true; } break;
+	case 259: { Pflag = true; } break;
 	default: { return 1; }
 	}
 
@@ -81,16 +82,7 @@ int main(int ac, char *av[]) { (void)(ac); A0 = av[0];
 		u8 *line = lineread();
 		if (!line) { if (errno) { warn("%s, %d", serr(), errno); } break; }
 
-		lex l = lex_init(line, strlen((char *)line));
-		if (Lflag) { lex_debug(&l); goto loop; }
-		
-		ast *a = parse(&l); if (!a) { goto loop; }
-		if (Pflag) { ast_debug(a); goto loop; }
-		
-		_ret = WEXITSTATUS(execute(a));
-		
-loop:;
-		ast_free(a); free(line);
+		eval(line, strlen((char *)line)); free(line);
 	} while (_loop);
 
 	linefree(); return warned;
@@ -102,12 +94,10 @@ static void reset(int signo) { (void)(signo);
 
 static void hlp(void) {
 	puts("ESH - Executive Shell\n");
-	puts("Usage: esh [-LP]\n");
+	puts("Usage: esh\n");
 	puts("Options:");
-	puts("  -L         Print lexer debug output");
-	puts("  -P         Print parser debug output");
-	puts("  --help     Display help information");
-	puts("  --version  Display version information");
+	puts("  --help         Display help information");
+	puts("  --version      Display version information");
 	return;
 }
 
diff --git a/src/parse.c b/src/parse.c
index 46900c4..c4f731f 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -41,29 +41,29 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 u8 *ast_ks[] = { (u8 *)"NULL", (u8 *)"COMP", (u8 *)"COMM" };
 
-static ast *parse_comp(lex *l);
-static ast *parse_comm(lex *l);
+static ast parse_comp(lex *l);
+static ast parse_comm(lex *l);
 
 /* Initialise an AST node. */
-ast *ast_init(void) {
-	return assert_calloc(1, sizeof (ast));
+ast ast_init(void) {
+	return assert_calloc(1, sizeof (struct ast_));
 }
 
 /* Uninitialise an AST node. */
-void ast_free(ast *a) {
+void ast_free(ast a) {
 	if (a) { array_free(a->c); free(a); }
 }
 
 /* Parse a program. */
-ast *parse(lex *l) {
+ast parse(lex *l) {
 	if (lex_peek(l).k == LK_EOF) { return NULL; }
 
 	return parse_comp(l);
 }
 
 /* Parse a comound statement. */
-static ast *parse_comp(lex *l) {
-	ast *a = ast_init(); a->k = AK_COMP;
+static ast parse_comp(lex *l) {
+	ast a = ast_init(); a->k = AK_COMP;
 	a->c = array_init((void (*)(ptr))&ast_free);
 
 	/* Push each command onto the array */
@@ -73,8 +73,8 @@ static ast *parse_comp(lex *l) {
 }
 
 /* Parse a command statement. */
-static ast *parse_comm(lex *l) {
-	ast *a = ast_init(); a->k = AK_COMM;
+static ast parse_comm(lex *l) {
+	ast a = ast_init(); a->k = AK_COMM;
 	a->c = array_init(NULL);
 
 	/* Push each command argument onto the array. */
@@ -85,7 +85,7 @@ static ast *parse_comm(lex *l) {
 }
 
 /* Print parser debug output with an indent. */
-static void ast_debug_indent(ast *a, UINT i) {
+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);
 
@@ -108,4 +108,4 @@ static void ast_debug_indent(ast *a, UINT i) {
 }
 
 /* Print parser debug output. */
-void ast_debug(ast *a) { ast_debug_indent(a, 0); }
+void ast_debug(ast a) { ast_debug_indent(a, 0); }