ESH

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

AuthorJakob Wakeling <[email protected]>
Date2023-12-28 01:17:38
Commit59a2eecffbf9c4899c9539de4938ffe8f3932b49
Parent1e336bf413a12ed3c021cd24e982c973ff68a00e

Add basic builtin functionality

Diffstat

A src/bltn.c | 30 ++++++++++++++++++++++++++++++
A src/bltn.h | 11 +++++++++++
A src/builtin/cd.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/exec.c | 8 +++++++-
M src/main.c | 16 ++++++++--------

5 files changed, 111 insertions, 9 deletions

diff --git a/src/bltn.c b/src/bltn.c
new file mode 100644
index 0000000..e8def8d
--- /dev/null
+++ b/src/bltn.c
@@ -0,0 +1,30 @@
+// Copyright (C) 2023, Jakob Wakeling
+// All rights reserved.
+
+#include "bltn.h"
+#include "util/util.h"
+
+#include <stdio.h>
+
+extern const char *const version; /* main.c */
+extern bool _loop; /* main.c */
+extern s32 _ret; /* exec.c */
+
+static int bltn_exit(int, char *[]) { _loop = false; return 0; }
+static int bltn_false(int, char *[]) { return 1; }
+static int bltn_help(int, char *[]) { fputs(version, stdout); return 0; }
+static int bltn_true(int, char *[]) { return 0; }
+
+extern int bltn_cd(int, char *[]);
+
+static int getret(int, char *[]) { printf("%d\n", _ret); return 0; }
+
+bltn bltns[] = {
+	{ "cd",    &bltn_cd    },
+	{ "exit",  &bltn_exit  },
+	{ "false", &bltn_false },
+	{ "help",  &bltn_help  },
+	{ "true",  &bltn_true  },
+	{ "ret",   &getret     },
+	{ NULL, NULL }
+};
diff --git a/src/bltn.h b/src/bltn.h
new file mode 100644
index 0000000..5e8c3b3
--- /dev/null
+++ b/src/bltn.h
@@ -0,0 +1,11 @@
+// Copyright (C) 2023, Jakob Wakeling
+// All rights reserved.
+
+#ifndef ESH_BUILTIN_H_2C7ANH8K
+#define ESH_BUILTIN_H_2C7ANH8K
+
+typedef struct { const char *name; int (*fn)(int, char *[]); } bltn;
+
+extern bltn bltns[];
+
+#endif // ESH_BUILTIN_H_2C7ANH8K
diff --git a/src/builtin/cd.c b/src/builtin/cd.c
new file mode 100644
index 0000000..32fda42
--- /dev/null
+++ b/src/builtin/cd.c
@@ -0,0 +1,55 @@
+// Copyright (C) 2023, Jakob Wakeling
+// All rights reserved.
+
+#include "../util/optget.h"
+#include "../util/util.h"
+
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char *const help;
+extern const char *const version; /* main.c */
+
+int bltn_cd(int, char *av[]) {
+	struct opt opt = OPTGET_INIT; opt.str = "LP"; opt.lops = (struct lop[]){
+		{ "help",    ARG_NUL, 256 },
+		{ "version", ARG_NUL, 257 },
+		{ NULL, 0, 0 },
+	};
+	
+	struct { s32 mode; } args = {};
+	
+	for (int c; (c = optget(&opt, av, 1)) != -1;) {
+		switch (c) {
+			case 'L': { args.mode = 0; } break;
+			case 'P': { args.mode = 1; } break;
+			case 256: { fputs(help, stdout);    } return 0;
+			case 257: { fputs(version, stdout); } return 0;
+			default: {} return -1;
+		}
+	}
+	
+	char *path = av[opt.ind] ? av[opt.ind] : getenv("HOME");
+	if (chdir(path)) {
+		fprintf(stderr, "%s: %s: %s\n", av[0], path, strerror(errno));
+		errno = 0; return -1;
+	}
+	
+	path = getcwd(NULL, 0); setenv("PWD", path, 1);
+	
+	free(path); return 0;
+}
+
+static const char *const help =
+	"cd - change directory\n"
+	"Usage:\n"
+	"  cd [-L|-P] [directory]\n"
+	"Options:\n"
+	"  -L         Handle the operand dot-dot logically\n"
+	"  -P         Handle the operand dot-dot physically\n"
+	"  --help     Display help information\n"
+;
diff --git a/src/exec.c b/src/exec.c
index a6e144c..50ff146 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,6 +1,7 @@
 // Copyright (C) 2023, Jakob Wakeling
 // All rights reserved.
 
+#include "bltn.h"
 #include "exec.h"
 #include "parse.h"
 #include "util/log.h"
@@ -34,7 +35,12 @@ static s32 execute_comm(ast *a, int fdi, int fd[2]) {
 	/* If the command is null, then do nothing */
 	if (!a->s) { return _ret; }
 
-	/* TODO handle builtins */
+	/* Handle builtins */
+	for (bltn *b = bltns; b->name; b += 1) {
+		if (strcmp(a->s, b->name) == 0) {
+			return b->fn(a->c.al - 1, a->c.a);
+		}
+	}
 
 	pid_t pid; int status, rin = -1, rout = -1, rerr = -1;
 
diff --git a/src/main.c b/src/main.c
index b0a9221..93ac722 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,10 +17,11 @@
 static void reset(int);
 
 static const char *const help;
-static const char *const version;
+const char *const version;
 
 static jmp_buf jmp;
 static sig_atomic_t jmpflag = false;
+bool _loop = true;
 
 int main(int, char *av[]) {
 	struct opt opt = OPTGET_INIT; opt.str = "Ep"; opt.lops = (struct lop[]){
@@ -39,7 +40,7 @@ int main(int, char *av[]) {
 			case 258: { __debug = true; } break;
 			case 256: { fputs(help, stdout);    } return 0;
 			case 257: { fputs(version, stdout); } return 0;
-			default: { return -1; }
+			default: {} return -1;
 		}
 	}
 
@@ -53,7 +54,7 @@ int main(int, char *av[]) {
 		if (!line) { if (errno) { log_warn("lineread: %s", strerror(errno)); } break; }
 
 		eval(line, strlen(line)); free(line);
-	} while (true);
+	} while (_loop);
 
 	return __warned;
 }
@@ -67,14 +68,14 @@ static const char *const help =
 	"Usage:\n"
 	"  esh [--debug]\n"
 	"Options:\n"
-	"  --help     Display help information\n"
-	"  --version  Display version information\n"
-	"  --debug    Enable debug logging\n"
 	"  -E         Output lexer tokens\n"
 	"  -p         Output parser AST \n"
+	"  --debug    Enable debug logging\n"
+	"  --help     Display help information\n"
+	"  --version  Display version information\n"
 ;
 
-static const char *const version =
+const char *const version =
 	"ESH, version " PROJECT_VERSION "\n"
 	"Copyright (C) 2023, Jakob Wakeling\n"
 	"All rights reserved.\n"