From 5fe78f574bab097c32738c6abad812f7ec25e79f Mon Sep 17 00:00:00 2001
From: Thomas Voss <mail@thomasvoss.com>
Date: Tue, 13 Feb 2024 17:22:42 +0100
Subject: Begin work on the Ahoy emulator

---
 .gitignore      |  1 +
 make.c          | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/ahoy/main.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 src/ahoy/main.c

diff --git a/.gitignore b/.gitignore
index 239b64f..c3cee9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ compile_commands.json
 test.s
 
 # Compilation Output
+ahoy
 c8asm
 !src/*
 make
diff --git a/make.c b/make.c
index d9161fb..14c536f 100644
--- a/make.c
+++ b/make.c
@@ -42,6 +42,7 @@
 #define CMDPRC(c)  _CMDPRC(c, cmdput)
 #define CMDPRC2(c) _CMDPRC(c, cmdput2)
 
+static void build_ahoy(void);
 static void build_c8asm(void);
 static void build_common(void);
 static void build_librune(void);
@@ -88,6 +89,7 @@ main(int argc, char **argv)
 	if (argc == 0) {
 		build_common();
 		build_c8asm();
+		build_ahoy();
 	} else if (streq(*argv, "clean")) {
 		cmd_t c = {0};
 		cmdadd(&c, "find", ".", "-type", "f", "(", "-name", "*.[ao]", "-or",
@@ -146,6 +148,68 @@ build_common(void)
 		free(objs[i]);
 }
 
+void
+build_ahoy(void)
+{
+	glob_t g;
+	char **objs;
+	cmd_t c = {0};
+	struct strv sv = {0};
+
+	if (glob("src/ahoy/*.c", 0, globerr, &g))
+		die("glob");
+
+	objs = bufalloc(nullptr, g.gl_pathc, sizeof(*objs));
+	for (size_t i = 0; i < g.gl_pathc; i++) {
+		char *s = strdup(g.gl_pathv[i]);
+		if (!s)
+			die("strdup");
+		s[strlen(s) - 1] = 'o';
+		objs[i] = s;
+	}
+
+	env_or_default(&sv, "CC", CC);
+	if (FLAGSET('r'))
+		env_or_default(&sv, "CFLAGS", CFLAGS_RLS);
+	else
+		env_or_default(&sv, "CFLAGS", CFLAGS_DBG);
+
+	for (size_t i = 0; i < g.gl_pathc; i++) {
+		if (!FLAGSET('f') && !foutdated(objs[i], g.gl_pathv[i]))
+			continue;
+
+		c.dst = objs[i];
+		cmdaddv(&c, sv.buf, sv.len);
+		if (FLAGSET('l'))
+			cmdadd(&c, "-flto");
+		cmdadd(&c, "-Isrc/common", "-Ivendor/da", "-Ivendor/librune/include");
+		cmdadd(&c, "-c", g.gl_pathv[i], "-o", objs[i]);
+		CMDPRC2(c);
+	}
+
+	if (!FLAGSET('f') && !foutdatedv("ahoy", (const char **)objs, g.gl_pathc))
+		goto out;
+
+	strvfree(&sv);
+	env_or_default(&sv, "CC", CC);
+	env_or_default(&sv, "LDFLAGS", nullptr);
+
+	c.dst = "ahoy";
+	cmdaddv(&c, sv.buf, sv.len);
+	if (FLAGSET('l'))
+		cmdadd(&c, "-flto");
+	cmdadd(&c, "-o", c.dst);
+	cmdaddv(&c, objs, g.gl_pathc);
+	cmdadd(&c, "src/common/cerr.o");
+	CMDPRC2(c);
+
+out:
+	globfree(&g);
+	strvfree(&sv);
+	for (size_t i = 0; i < g.gl_pathc; i++)
+		free(objs[i]);
+}
+
 void
 build_c8asm(void)
 {
diff --git a/src/ahoy/main.c b/src/ahoy/main.c
new file mode 100644
index 0000000..8cc7106
--- /dev/null
+++ b/src/ahoy/main.c
@@ -0,0 +1,57 @@
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cerr.h"
+#include "macros.h"
+
+static void run(int, const char *);
+
+int
+main(int argc, char **argv)
+{
+	int opt;
+	const struct option longopts[] = {
+		{"help",  no_argument, nullptr, 'h'},
+		{nullptr, no_argument, nullptr, 0  },
+	};
+
+	cerrinit(*argv);
+	while ((opt = getopt_long(argc, argv, "h", longopts, nullptr)) != -1) {
+		switch (opt) {
+		case 'h':
+			execlp("man", "man", "1", argv[0], nullptr);
+			die("execlp: man 1 %s", argv[0]);
+		default:
+			fprintf(stderr, "Usage: %s [file ...]\n", argv[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (!argc)
+		run(STDIN_FILENO, "-");
+	for (int i = 0; i < argc; i++) {
+		if (streq("-", argv[i]))
+			run(STDIN_FILENO, "-");
+		else {
+			int fd;
+			if ((fd = open(argv[i], O_RDONLY)) == -1)
+				die("open: %s", argv[i]);
+			run(fd, argv[i]);
+			close(fd);
+		}
+	}
+
+	return EXIT_SUCCESS;
+}
+
+void
+run([[maybe_unused]] int fd, [[maybe_unused]] const char *fn)
+{
+}
-- 
cgit v1.2.3