diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-25 18:24:05 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-25 18:24:05 +0000 |
| commit | e3ab29bb4d7174cae65de2275f19105eb3d93d91 (patch) | |
| tree | 89970111c1be4c3ddd291b720d4fdf496f10b2d5 /ape | |
| parent | 489336b2101bf16edeec7bfc4379408eb19b936e (diff) | |
APE shall never kill APE
Diffstat (limited to 'ape')
| -rw-r--r-- | ape/boot/.args | 23 | ||||
| -rw-r--r-- | ape/boot/Makefile | 14 | ||||
| -rw-r--r-- | ape/boot/boot.zc | 118 | ||||
| -rw-r--r-- | ape/boot/hello.zc | 4 | ||||
| -rw-r--r-- | ape/boot/instructions.txt | 6 | ||||
| -rw-r--r-- | ape/zc_entry.c | 257 |
6 files changed, 422 insertions, 0 deletions
diff --git a/ape/boot/.args b/ape/boot/.args new file mode 100644 index 0000000..797e7cd --- /dev/null +++ b/ape/boot/.args @@ -0,0 +1,23 @@ +... +:: system -c 'mkdir -p usr/bin' +:: system -c 'echo " Downloading into usr/bin"' +:: system -c 'out=usr/bin/unzip; [ -e "$out" ] || curl -o "$out" https://cosmo.zip/pub/cosmos/bin/unzip' +:: system -c 'out=usr/bin/unzip; [ -e "$out" ] && echo " [+] $out: exists"' +:: system -c 'out=usr/bin/zip; [ -e "$out" ] || curl -o "$out" https://cosmo.zip/pub/cosmos/bin/zip' +:: system -c 'out=usr/bin/zip; [ -e "$out" ] && echo " [+] $out: exists"' +:: system -c 'chmod 755 usr/bin/zip' +:: system -c 'chmod 755 usr/bin/unzip' +:: system -c 'out=usr/cosmocc.zip; [ -e "$out" ] || curl -o "$out" https://cosmo.zip/pub/cosmocc/cosmocc.zip' +:: system -c 'out=usr/cosmocc.zip; [ -e "$out" ] && echo " [+] $out: exists"' +:: system -c 'out=usr; [ -e "$out/bin/cosmocc" ] || usr/bin/unzip -d "$out" usr/cosmocc.zip' +:: system -c 'out=usr; [ -e "$out/bin/cosmocc" ] || unzip -d "$out" usr/cosmocc.zip' +:: system -c 'out=usr; [ -e "$out/bin/cosmocc" ] && echo " [+] $out/bin/cosmocc: exists"' +:: system -c 'out=usr/bin/zc.com; [ -e "$out" ] || curl -o "$out" -L https://github.com/OEvgeny/zc-ape/releases/latest/download/zc.com' +:: system -c 'out=usr/bin/zc.com; [ -e "$out" ] && echo " [+] $out: exists"' +:: system -c 'chmod 755 usr/bin/zc.com' +:: system -c 'out=Makefile; [ -e "$out" ] || curl -o "$out" https://raw.githubusercontent.com/OEvgeny/zc-ape/main/zc-boot/Makefile' +:: system -c 'out=Makefile; [ -e "$out" ] && echo " [+] $out: exists"' +:: system -c 'out=hello.zc; [ -e "$out" ] || curl -o "$out" https://raw.githubusercontent.com/OEvgeny/zc-ape/main/zc-boot/hello.zc' +:: system -c 'out=hello.zc; [ -e "$out" ] && echo " [+] $out: exists"' +:: system -c 'echo " Done."' +:: system -c 'cat /zip/instructions.txt'
\ No newline at end of file diff --git a/ape/boot/Makefile b/ape/boot/Makefile new file mode 100644 index 0000000..05f7a36 --- /dev/null +++ b/ape/boot/Makefile @@ -0,0 +1,14 @@ +export PATH := $(realpath usr/bin):$(PATH) +CC=cosmocc +ZC=zc.com + +all: out/hello.com + +out/hello.com: hello.zc + @mkdir -p out + $(ZC) build --cc $(CC) -o $@ $< + +clean: + rm -rf out + +.PHONY: all clean
\ No newline at end of file diff --git a/ape/boot/boot.zc b/ape/boot/boot.zc new file mode 100644 index 0000000..176f668 --- /dev/null +++ b/ape/boot/boot.zc @@ -0,0 +1,118 @@ +#define _COSMO_SOURCE +#include <libc/cosmo.h> +#include <string.h> +#include <stdlib.h> + +raw { + extern char **environ; +} + +fn normalize_wait(ws: int) -> int { + if ws == -1 { return -1 } + if WIFEXITED(ws) { return WEXITSTATUS(ws) } + if WIFSIGNALED(ws) { return 128 + WTERMSIG(ws) } + return -1; +} + +fn run_exec(argv: char**) -> int { + fflush(NULL); + let ws: int = systemvpe(argv[0], argv, environ); + return normalize_wait(ws); +} + +fn needs_quote(s: char*) -> bool { + for (let p = s; *p; ++p) { + if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '"' || *p == '\'' ) + return true; + } + return false; +} + +fn print_quoted(s: char*) { + if !needs_quote(s) { + print f"{s}"; + return; + } + + print f"'"; + for (let p = s; *p; ++p) { + if (*p == '\'') { + print f"'\"'\"'"; + } else { + print f"{*p:c}"; + } + } + print f"'"; +} + +fn log_cmd(argv: char**) { + print f"$ "; + let i = 0; + while argv[i] != NULL { + if i { print f" " } + print_quoted(argv[i]); + i++; + } + print f"\n"; +} + +fn main(argc: int, argv: string*) { + def delim = "::"; + + let newargc: int = cosmo_args("/zip/.args", &argv); + if newargc != -1 { argc = newargc } + + let i = 1; + while i < argc && strcmp(argv[i], delim) { i++ } + + while i < argc { + if strcmp(argv[i], delim) { + f"Expected '{delim}' before each command, got: {argv[i]}"; + return 2; + } + i++; + + let start = i; + while i < argc && strcmp(argv[i], delim) { i++ } + let cmd_argc = i - start; + + if cmd_argc <= 0 { + f"Empty command after '{delim}'"; + return 2; + } + + let rc = 0; + + if !strcmp(argv[start], "system") { + if cmd_argc != 3 { + !"error: system expects 2 arguments, got {cmd_argc}"; + return -4; + } + + if strcmp(argv[start + 1], "-c") { + !"error: system got '{argv[start + 1]}' instead of -c"; + return -5; + } + + "$ {argv[start + 2]}"; + rc = normalize_wait(system(argv[start + 2])); + + if rc { return rc } + + continue; + } + + autofree let cmdv = (char**)malloc((cmd_argc + 1) * sizeof(char*)); + if !cmdv { return 1 } + for (let k = 0; k < cmd_argc; k++) { cmdv[k] = argv[start + k] } + cmdv[cmd_argc] = NULL; + + log_cmd(cmdv); + + rc = run_exec(cmdv); + + if rc { return rc } + } + + return 0; +} diff --git a/ape/boot/hello.zc b/ape/boot/hello.zc new file mode 100644 index 0000000..8d14292 --- /dev/null +++ b/ape/boot/hello.zc @@ -0,0 +1,4 @@ + +fn main() { + "Hello from Zen-C!"; +} diff --git a/ape/boot/instructions.txt b/ape/boot/instructions.txt new file mode 100644 index 0000000..edbe367 --- /dev/null +++ b/ape/boot/instructions.txt @@ -0,0 +1,6 @@ +Run: + +$ usr/bin/make +$ out/hello.com + +To build and run hello world example. diff --git a/ape/zc_entry.c b/ape/zc_entry.c new file mode 100644 index 0000000..5594edf --- /dev/null +++ b/ape/zc_entry.c @@ -0,0 +1,257 @@ +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <libc/cosmo.h> + +int __real_main(int argc, char **argv); + +static bool streq(const char *a, const char *b) +{ + return a && b && !strcmp(a, b); +} + +static bool has_cc_flag(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + const char *a = argv[i]; + if (a && streq(a, "--cc")) + { + return true; + } + } + return false; +} + +static const char *get_cc_value(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + const char *a = argv[i]; + + if (a && streq(a, "--cc")) + { + if (i + 1 < argc) + { + return argv[i + 1]; + } + return NULL; + } + } + return NULL; +} + +static bool cc_is_cosmocc(int argc, char **argv) +{ + const char *cc = get_cc_value(argc, argv); + if (!cc) + { + return false; + } + const char *p = strstr(cc, "cosmocc"); + return p != NULL; +} + +static bool is_cmd(int argc, char **argv, const char *cmd) +{ + // usage: zc [command] [options] <file.zc> + return argc > 1 && streq(argv[1], cmd); +} + +static bool has_o_flag(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + const char *a = argv[i]; + if (!a) + { + continue; + } + if (streq(a, "-o")) + { + return true; + } + if (!strncmp(a, "-o", 2) && a[2]) + { + return true; + } + } + return false; +} + +static const char *get_out_value(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + const char *a = argv[i]; + if (!a) + { + continue; + } + + if (streq(a, "-o")) + { + if (i + 1 < argc) + { + return argv[i + 1]; + } + return NULL; + } + if (!strncmp(a, "-o", 2) && a[2]) + { + return a + 2; + } + } + return NULL; +} + +static void inject_default_out(int *pargc, char ***pargv, const char *out) +{ + int argc = *pargc; + char **argv = *pargv; + + if (!(is_cmd(argc, argv, "run") || is_cmd(argc, argv, "build"))) + { + return; + } + if (has_o_flag(argc, argv)) + { + return; + } + + char **newv = (char **)malloc((size_t)(argc + 2 + 1) * sizeof(char *)); + if (!newv) + { + return; + } + + int k = 0; + newv[k++] = argv[0]; + newv[k++] = argv[1]; + newv[k++] = (char *)"-o"; + newv[k++] = (char *)out; + + for (int i = 2; i < argc; ++i) + { + newv[k++] = argv[i]; + } + newv[k] = NULL; + + *pargc = k; + *pargv = newv; +} + +static void unlink_if_exists(const char *path) +{ + if (!path || !*path) + { + return; + } + int old = errno; + if (unlink(path) == -1) + { + if (errno == ENOENT) + { + errno = old; + } + } + else + { + errno = old; + } +} + +static void cleanup_cosmocc_out(const char *out) +{ + char buf[4096]; + + if (snprintf(buf, sizeof(buf), "%s.dbg", out) < (int)sizeof(buf)) + { + unlink_if_exists(buf); + } + + size_t n = strlen(out); + if (n > 4 && !strcmp(out + (n - 4), ".com")) + { + char base[4096]; + if (n - 4 < sizeof(base)) + { + memcpy(base, out, n - 4); + base[n - 4] = 0; + + if (snprintf(buf, sizeof(buf), "%s.aarch64.elf", base) < (int)sizeof(buf)) + { + unlink_if_exists(buf); + } + } + } +} + +static bool out_exists(const char *out) +{ + char buf[4096]; + if (snprintf(buf, sizeof(buf), "%s.dbg", out) < (int)sizeof(buf)) + { + if (access(buf, F_OK) != -1) + { + return true; + } + } + + char base[4096]; + size_t n = strlen(out); + if (n > 4 && !strcmp(out + (n - 4), ".com")) + { + if (n - 4 < sizeof(base)) + { + memcpy(base, out, n - 4); + base[n - 4] = 0; + if (snprintf(buf, sizeof(buf), "%s.aarch64.elf", base) < (int)sizeof(buf)) + { + if (access(buf, F_OK) != -1) + { + return true; + } + } + } + } + return false; +} + +static void ensure_env(const char *key, const char *val) +{ + const char *cur = getenv(key); + if (cur && *cur) + { + return; + } + setenv(key, val, 0); +} + +int __wrap_main(int argc, char **argv) +{ + ensure_env("ZC_ROOT", "/zip"); + + int newargc = cosmo_args("/zip/.args", &argv); + if (newargc != -1) + { + argc = newargc; + } + + inject_default_out(&argc, &argv, "a.out.com"); + + const char *out = get_out_value(argc, argv); + + bool do_cleanup = is_cmd(argc, argv, "run") && cc_is_cosmocc(argc, argv) && !out_exists(out); + + int rc = __real_main(argc, argv); + + if (do_cleanup) + { + cleanup_cosmocc_out(out); + } + + return rc; +} |
