summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/.bop/posthook.sh1
-rw-r--r--core/bop.c122
-rw-r--r--core/build.c184
-rw-r--r--core/hook.c51
4 files changed, 358 insertions, 0 deletions
diff --git a/core/.bop/posthook.sh b/core/.bop/posthook.sh
new file mode 100644
index 0000000..05f3860
--- /dev/null
+++ b/core/.bop/posthook.sh
@@ -0,0 +1 @@
+clang $BOP_PROJECT_ROOT/core/*.o -o bop
diff --git a/core/bop.c b/core/bop.c
new file mode 100644
index 0000000..02c0324
--- /dev/null
+++ b/core/bop.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2026, Chloe M., et al.
+ * Provided under the BSD-3 clause.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "bop/common.h"
+#include "bop/hook.h"
+#include "bop/build.h"
+
+static void
+version(void)
+{
+ printf("Version: %s\n", BOP_VERSION);
+}
+
+static void
+help(void)
+{
+ printf("usage: %s=<dir> ./bop [flags] [build_op]\n", BOP_BUILD_ENV);
+ printf("-- flags --\n");
+ printf("[-h] Display this help menu\n");
+ printf("[-v] Display the version\n");
+ printf("-- build operations\n");
+ printf("[build] Build the directory specified by %s\n", BOP_BUILD_ENV);
+}
+
+/*
+ * Discover any possible hooks to be ran in the desired build directory and
+ * begin the build process.
+ */
+static int
+run_build(void)
+{
+ char pathbuf[256];
+ char *build_dir;
+ int error;
+
+ build_dir = getenv(BOP_BUILD_ENV);
+ if (build_dir == NULL) {
+ printf("fatal: build directory not specified in %s\n", BOP_BUILD_ENV);
+ return -1;
+ }
+
+ /*
+ * There is a pre-build hook to be located within the [BUILD_DIR]/.bop/prehook.sh which
+ * is simply a shell script to be executed.
+ */
+ snprintf(pathbuf, sizeof(pathbuf), "%s/.bop/prehook.sh", build_dir);
+ if (access(pathbuf, F_OK) == 0) {
+ bop_shell_hook(pathbuf);
+ }
+
+ error = bop_build_dir(build_dir);
+ if (error < 0) {
+ printf("fatal: failed to build '%s'\n", build_dir);
+ return error;
+ }
+
+ /* Run the post hook if we can */
+ snprintf(pathbuf, sizeof(pathbuf), "%s/.bop/posthook.sh", build_dir);
+ if (access(pathbuf, F_OK) == 0) {
+ bop_shell_hook(pathbuf);
+ }
+
+ return 0;
+}
+
+static int
+do_build_op(const char *op)
+{
+ if (op == NULL) {
+ return -1;
+ }
+
+ switch (*op) {
+ case 'b':
+ if (strcmp(op, "build") == 0) {
+ return run_build();
+ }
+
+ break;
+ }
+
+ return -1;
+}
+
+int
+main(int argc, char **argv)
+{
+ int opt;
+ char *build_opt;
+
+ if (argc < 2) {
+ printf("fatal: too few arguments\n");
+ help();
+ return -1;
+ }
+
+ while ((opt = getopt(argc, argv, "hv")) != -1) {
+ switch (opt) {
+ case 'h':
+ help();
+ return -1;
+ case 'v':
+ version();
+ return -1;
+ }
+ }
+
+ if (optind >= argc) {
+ printf("fatal: please specify a build operation\n");
+ help();
+ return -1;
+ }
+
+ build_opt = argv[optind++];
+ return do_build_op(build_opt);
+}
diff --git a/core/build.c b/core/build.c
new file mode 100644
index 0000000..78ad65a
--- /dev/null
+++ b/core/build.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2026, Chloe M., et al.
+ * Provided under the BSD-3 clause.
+ */
+
+#include <sys/wait.h>
+#include <dirent.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <strings.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include "bop/common.h"
+#include "bop/build.h"
+
+/*
+ * Build parameters
+ *
+ * @cflags: List of CFLAGS
+ *
+ * TODO: Use this instead of BOP_DEFAULT_CFLAGS and similar
+ */
+struct build_params {
+ char **cflags;
+};
+
+/*
+ * Obtain the file extension of a file
+ *
+ * @filename: Filename to obtain extension of
+ */
+static const char *
+get_extension(const char *filename)
+{
+ const char *p;
+ bool have_dot = false;
+
+ if (filename == NULL) {
+ return NULL;
+ }
+
+ p = filename;
+ while (*p != '\0') {
+ if (*p == '.') {
+ have_dot = true;
+ } else if (have_dot) {
+ --p;
+ return p;
+ }
+ ++p;
+ }
+
+ return NULL;
+}
+
+/*
+ * Truncate a file extension
+ *
+ * @filename: Filename to truncate file extension from
+ *
+ * XXX: Returns memory allocated with strdup(), remember to free!
+ */
+static char *
+trunc_extension(const char *filename)
+{
+ char *p, *p1;
+
+ if ((p = strdup(filename)) == NULL) {
+ return NULL;
+ }
+
+ p1 = p;
+ while (*p1 != '\0') {
+ if (*p1 == '.') {
+ *p1 = '\0';
+ return p;
+ }
+ ++p1;
+ }
+
+ free(p);
+ return NULL;
+}
+
+static int
+invoke_cc(const char *cfile_path, struct build_params *params)
+{
+ pid_t child;
+ int status;
+ char *trunc_ext;
+ char outpath[256];
+
+ if (cfile_path == NULL || params == NULL) {
+ return -1;
+ }
+
+ trunc_ext = trunc_extension(cfile_path);
+ if (trunc_ext == NULL) {
+ return -1;
+ }
+
+ snprintf(outpath, sizeof(outpath), "%s.o", trunc_ext);
+ child = fork();
+ if (child == 0) {
+ execl(BOP_CC, BOP_CC, "-c", cfile_path, "-o", outpath, BOP_DEFAULT_CFLAGS, NULL);
+ } else {
+ waitpid(child, &status, 0);
+ free(trunc_ext);
+ return status;
+ }
+
+ return -1;
+}
+
+static int
+compile(const char *dirpath, struct dirent *dirent, struct build_params *params)
+{
+ const char *filename, *ext;
+ char pathbuf[256];
+ int error;
+
+ if (dirpath == NULL || dirent == NULL) {
+ return -1;
+ }
+
+ /* Ignore non regulars */
+ if (dirent->d_type != DT_REG) {
+ return 0;
+ }
+
+ filename = dirent->d_name;
+ ext = get_extension(filename);
+
+ /* Ignore files with no extensions */
+ if (ext == NULL) {
+ return 0;
+ }
+
+ snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dirpath, filename);
+
+ /* Build all CFILES */
+ if (strcmp(ext, ".c") == 0) {
+ error = invoke_cc(pathbuf, params);
+ if (error < 0)
+ printf("fatal: cc invocation failure\n");
+ return error;
+ }
+
+ return 0;
+
+}
+
+int
+bop_build_dir(const char *dirpath)
+{
+ struct build_params params;
+ struct dirent *dirent;
+ DIR *dir;
+ int error;
+
+ dir = opendir(dirpath);
+ if (dir == NULL) {
+ perror("opendir");
+ return -1;
+ }
+
+ bzero(&params, sizeof(params));
+ while ((dirent = readdir(dir)) != NULL) {
+ if (dirent->d_name[0] == '.') {
+ continue;
+ }
+
+ error = compile(dirpath, dirent, &params);
+ if (error < 0) {
+ printf("fatal: failed to build '%s'\n", dirent->d_name);
+ return error;
+ }
+ }
+
+ return 0;
+}
diff --git a/core/hook.c b/core/hook.c
new file mode 100644
index 0000000..b915901
--- /dev/null
+++ b/core/hook.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2026, Chloe M., et al.
+ * Provided under the BSD-3 clause.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include "bop/hook.h"
+
+/* Shell we use by default */
+#define DEFAULT_SHELL_PATH "/bin/sh"
+
+/*
+ * Execute the shell for a specific shell script
+ *
+ * @script_path: Path of shell script
+ */
+static void
+exec_shell_for(const char *script_path)
+{
+ if (script_path == NULL) {
+ return;
+ }
+
+ execl(DEFAULT_SHELL_PATH, DEFAULT_SHELL_PATH, script_path, NULL);
+}
+
+/*
+ * Run a shell hook with POSIX sh
+ *
+ * XXX: Maybe support '#!/bin/xxx'?
+ */
+int
+bop_shell_hook(const char *hook_path)
+{
+ pid_t child;
+ int status;
+
+ if (hook_path == NULL) {
+ return -1;
+ }
+
+ child = fork();
+ if (child == 0) {
+ exec_shell_for(hook_path);
+ } else {
+ waitpid(child, &status, 0);
+ }
+
+ return 0;
+}