diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/.bop/posthook.sh | 1 | ||||
| -rw-r--r-- | core/bop.c | 122 | ||||
| -rw-r--r-- | core/build.c | 184 | ||||
| -rw-r--r-- | core/hook.c | 51 |
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(¶ms, sizeof(params)); + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') { + continue; + } + + error = compile(dirpath, dirent, ¶ms); + 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; +} |
