summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--b.c52
l---------[-rw-r--r--]src/b.h904
2 files changed, 27 insertions, 929 deletions
diff --git a/b.c b/b.c
index f0303bd..8151705 100644
--- a/b.c
+++ b/b.c
@@ -5,12 +5,12 @@
#define BUILD_DIR "build/"
#define TEMPLATE_DIR BUILD_DIR"templates/"
-int debug_level = 3;
+int debug_level = 0;
bool force = false;
bool tests = false;
void
-debug_or_release(B_Cmd* cmd)
+debug_or_release(b_cmd* cmd)
{
if (debug_level == 0)
b_cmd_append(cmd, "-O3", "-s", "-DNDEBUG");
@@ -27,13 +27,13 @@ debug_or_release(B_Cmd* cmd)
}
void
-inlcude_dirs(B_Cmd* cmd)
+inlcude_dirs(b_cmd* cmd)
{
b_cmd_append(cmd, "-I./src/", "-I./"TEMPLATE_DIR);
}
void
-cflags_common(B_Cmd* cmd)
+cflags_common(b_cmd* cmd)
{
b_cmd_append(cmd, "-Wall", "-Wextra");
@@ -44,7 +44,7 @@ cflags_common(B_Cmd* cmd)
}
void
-synth_libs(B_Cmd *cmd)
+synth_libs(b_cmd *cmd)
{
b_cmd_append(cmd, "-lportaudio", "-lrt", "-lasound", "-lraylib", "-lportmidi",
"-lfftw3f", "-lsndfile", "-lconfig", "-lpthread",
@@ -54,21 +54,21 @@ synth_libs(B_Cmd *cmd)
}
void
-sequencer_libs(B_Cmd *cmd)
+sequencer_libs(b_cmd *cmd)
{
b_cmd_append(cmd, "-lportaudio", "-lportmidi", "-lrt", "-lraylib", "-lpthread");
inlcude_dirs(cmd);
}
-void cc(B_Cmd *cmd)
+void cc(b_cmd *cmd)
{
b_cmd_append(cmd, "clang");
cflags_common(cmd);
}
bool
-build_c(B_Cmd* cmd,
+build_c(b_cmd* cmd,
const char** input_paths,
size_t input_paths_len,
const char** dep_paths,
@@ -76,12 +76,12 @@ build_c(B_Cmd* cmd,
const char* output_path)
{
int rebuild_is_needed =
- b_needs_rebuild(B_COMPILE, output_path, input_paths, input_paths_len);
+ b_needs_rebuild(output_path, input_paths, input_paths_len);
int dep_rebuild = 0;
if (rebuild_is_needed == 0)
dep_rebuild =
- b_needs_rebuild(B_COMPILE, output_path, dep_paths, dep_paths_len);
+ b_needs_rebuild(output_path, dep_paths, dep_paths_len);
if (rebuild_is_needed < 0 || dep_rebuild < 0) return false;
@@ -90,19 +90,19 @@ build_c(B_Cmd* cmd,
cmd->count = 0;
cc(cmd);
b_cmd_append(cmd, "-o", output_path);
- b_da_append_many(cmd, input_paths, input_paths_len);
+ array_append_many(cmd, input_paths, input_paths_len);
if (0 == strcmp(output_path, BUILD_DIR"synth"))
synth_libs(cmd);
if (0 == strcmp(output_path, BUILD_DIR"sequencer"))
sequencer_libs(cmd);
- return b_cmd_run_sync(*cmd);
+ return b_cmd_run(cmd);
}
b_log(B_INFO, "%s is up-to-date", output_path);
return true;
}
-bool build_templates(B_Cmd *cmd, const char **templates, size_t len) {
+bool build_templates(b_cmd *cmd, const char **templates, size_t len) {
char dest[1024] = "";
for (size_t i = 0; i < len; i++) {
cmd->count = 0;
@@ -110,7 +110,7 @@ bool build_templates(B_Cmd *cmd, const char **templates, size_t len) {
strcpy(dest, TEMPLATE_DIR);
strcat(dest, basename(base));
strcat(dest, ".h");
- if (b_needs_rebuild1(B_TEMPLATE, dest, templates[i]) == 0 &&
+ if (b_needs_rebuild1(dest, templates[i]) == 0 &&
force == false) {
b_log(B_INFO, "%s is up-to-date", dest);
continue;
@@ -121,15 +121,15 @@ bool build_templates(B_Cmd *cmd, const char **templates, size_t len) {
strcat(tmp, " > ");
strcat(tmp, dest);
b_cmd_append(cmd, "bash", "-c", tmp);
- b_cmd_run_sync(*cmd);
+ b_cmd_run(cmd);
}
return true;
}
bool
-build_tests(B_Cmd *cmd, const char * output_path) {
+build_tests(b_cmd *cmd, const char * output_path) {
int rebuild_is_needed =
- b_needs_rebuild1(B_COMPILE, output_path, "tests/example_test.c");
+ b_needs_rebuild1(output_path, "tests/example_test.c");
/* int dep_rebuild = 0; */
/* if (rebuild_is_needed == 0) */
@@ -147,7 +147,7 @@ build_tests(B_Cmd *cmd, const char * output_path) {
b_cmd_append(cmd, "-l", "check");
b_cmd_append(cmd, "tests/example_test.c");
synth_libs(cmd);
- return b_cmd_run_sync(*cmd);
+ return b_cmd_run(cmd);
}
b_log(B_INFO, "%s is up-to-date", output_path);
@@ -240,24 +240,24 @@ main(int argc, char *argv[])
"tmpl/index.html"
};
- B_Cmd cmd = {0};
+ b_cmd cmd = {0};
- b_mkdir_if_not_exists(BUILD_DIR);
- b_mkdir_if_not_exists(TEMPLATE_DIR);
+ b_mkdir(BUILD_DIR);
+ b_mkdir(TEMPLATE_DIR);
if (!build_c(&cmd, (const char *[]){"src/tt.c"}, 1, NULL, 0,
BUILD_DIR "tt"))
return 1;
- if (!build_templates(&cmd, templates, B_ARRAY_LEN(templates)))
+ if (!build_templates(&cmd, templates, ARRAY_LENGTH(templates)))
return 1;
- if (!build_c(&cmd, synth_paths, B_ARRAY_LEN(synth_paths), synth_deps,
- B_ARRAY_LEN(synth_deps), BUILD_DIR "synth"))
+ if (!build_c(&cmd, synth_paths, ARRAY_LENGTH(synth_paths), synth_deps,
+ ARRAY_LENGTH(synth_deps), BUILD_DIR "synth"))
return 1;
- if (!build_c(&cmd, sequencer_paths, B_ARRAY_LEN(sequencer_paths), sequencer_deps,
- B_ARRAY_LEN(sequencer_deps), BUILD_DIR "sequencer"))
+ if (!build_c(&cmd, sequencer_paths, ARRAY_LENGTH(sequencer_paths), sequencer_deps,
+ ARRAY_LENGTH(sequencer_deps), BUILD_DIR "sequencer"))
return 1;
if (tests && !build_tests(&cmd, BUILD_DIR "test"))
diff --git a/src/b.h b/src/b.h
index a6dba68..f09dfb8 100644..120000
--- a/src/b.h
+++ b/src/b.h
@@ -1,903 +1 @@
-// This is an attempt on build library for building C with C akin to nob.h from
-// tsoding which is itself based on https://github.com/tsoding/nobuild
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-#ifndef B_H_
-#define B_H_
-
-#define B_ASSERT assert
-#define B_REALLOC realloc
-#define B_FREE free
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#define B_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
-#define B_ARRAY_GET(array, index) \
- (B_ASSERT(index >= 0), B_ASSERT(index < B_ARRAY_LEN(array)), array[index])
-
-typedef enum {
- B_INFO,
- B_CMD,
- B_COMPILE,
- B_TEMPLATE,
- B_CHANGE,
- B_WARNING,
- B_ERROR,
-} B_Log_Level;
-
-void b_log(B_Log_Level level, const char *fmt, ...);
-
-// It is an equivalent of shift command from bash. It basically pops a command line
-// argument from the beginning.
-char *b_shift_args(int *argc, char ***argv);
-
-typedef struct {
- const char **items;
- size_t count;
- size_t capacity;
-} B_File_Paths;
-
-typedef enum {
- B_FILE_REGULAR = 0,
- B_FILE_DIRECTORY,
- B_FILE_SYMLINK,
- B_FILE_OTHER,
-} B_File_Type;
-
-bool b_mkdir_if_not_exists(const char *path);
-bool b_copy_file(const char *src_path, const char *dst_path);
-bool b_copy_directory_recursively(const char *src_path, const char *dst_path);
-bool b_read_entire_dir(const char *parent, B_File_Paths *children);
-bool b_write_entire_file(const char *path, const void *data, size_t size);
-B_File_Type b_get_file_type(const char *path);
-
-#define b_return_defer(value) do { result = (value); goto defer; } while(0)
-
-// Initial capacity of a dynamic array
-#define B_DA_INIT_CAP 256
-
-// Append an item to a dynamic array
-#define b_da_append(da, item) \
- do { \
- if ((da)->count >= (da)->capacity) { \
- (da)->capacity = (da)->capacity == 0 ? B_DA_INIT_CAP : (da)->capacity*2; \
- (da)->items = B_REALLOC((da)->items, (da)->capacity*sizeof(*(da)->items)); \
- B_ASSERT((da)->items != NULL && "Buy more RAM lol"); \
- } \
- \
- (da)->items[(da)->count++] = (item); \
- } while (0)
-
-#define b_da_free(da) B_FREE((da).items)
-
-// Append several items to a dynamic array
-#define b_da_append_many(da, new_items, new_items_count) \
- do { \
- if ((da)->count + (new_items_count) > (da)->capacity) { \
- if ((da)->capacity == 0) { \
- (da)->capacity = B_DA_INIT_CAP; \
- } \
- while ((da)->count + (new_items_count) > (da)->capacity) { \
- (da)->capacity *= 2; \
- } \
- (da)->items = B_REALLOC((da)->items, (da)->capacity*sizeof(*(da)->items)); \
- B_ASSERT((da)->items != NULL && "Buy more RAM lol"); \
- } \
- memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
- (da)->count += (new_items_count); \
- } while (0)
-
-typedef struct {
- char *items;
- size_t count;
- size_t capacity;
-} B_String_Builder;
-
-bool b_read_entire_file(const char *path, B_String_Builder *sb);
-
-// Append a sized buffer to a string builder
-#define b_sb_append_buf(sb, buf, size) b_da_append_many(sb, buf, size)
-
-// Append a NULL-terminated string to a string builder
-#define b_sb_append_cstr(sb, cstr) \
- do { \
- const char *s = (cstr); \
- size_t n = strlen(s); \
- b_da_append_many(sb, s, n); \
- } while (0)
-
-// Append a single NULL character at the end of a string builder. So then you can
-// use it a NULL-terminated C string
-#define b_sb_append_null(sb) b_da_append_many(sb, "", 1)
-
-// Free the memory allocated by a string builder
-#define b_sb_free(sb) B_FREE((sb).items)
-
-// Process handle
-typedef int B_Proc;
-#define B_INVALID_PROC (-1)
-
-typedef struct {
- B_Proc *items;
- size_t count;
- size_t capacity;
-} B_Procs;
-
-bool b_procs_wait(B_Procs procs);
-
-// Wait until the process has finished
-bool b_proc_wait(B_Proc proc);
-
-// A command - the main workhorse of B. B is all about building commands an running them
-typedef struct {
- const char **items;
- size_t count;
- size_t capacity;
-} B_Cmd;
-
-// Render a string representation of a command into a string builder. Keep in mind the the
-// string builder is not NULL-terminated by default. Use b_sb_append_null if you plan to
-// use it as a C string.
-void b_cmd_render(B_Cmd cmd, B_String_Builder *render);
-
-#define b_cmd_append(cmd, ...) \
- b_da_append_many(cmd, ((const char*[]){__VA_ARGS__}), (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*)))
-
-// Free all the memory allocated by command arguments
-#define b_cmd_free(cmd) B_FREE(cmd.items)
-
-// Run command asynchronously
-B_Proc b_cmd_run_async(B_Cmd cmd);
-
-// Run command synchronously
-bool b_cmd_run_sync(B_Cmd cmd);
-
-#ifndef B_TEMP_CAPACITY
-#define B_TEMP_CAPACITY (8*1024*1024)
-#endif // B_TEMP_CAPACITY
-char *b_temp_strdup(const char *cstr);
-void *b_temp_alloc(size_t size);
-char *b_temp_sprintf(const char *format, ...);
-void b_temp_reset(void);
-size_t b_temp_save(void);
-void b_temp_rewind(size_t checkpoint);
-
-int is_path1_modified_after_path2(const char *path1, const char *path2);
-bool b_rename(const char *old_path, const char *new_path);
-int b_needs_rebuild(B_Log_Level log, const char *output_path, const char **input_paths, size_t input_paths_count);
-int b_needs_rebuild1(B_Log_Level log, const char *output_path, const char *input_path);
-int b_file_exists(const char *file_path);
-
-// TODO: add MinGW support for Go Rebuild Urself™ Technology
-#ifndef B_REBUILD_URSELF
-# if _WIN32
-# if defined(__GNUC__)
-# define B_REBUILD_URSELF(binary_path, source_path) "gcc", "-o", binary_path, source_path
-# elif defined(__clang__)
-# define B_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
-# elif defined(_MSC_VER)
-# define B_REBUILD_URSELF(binary_path, source_path) "cl.exe", b_temp_sprintf("/Fe:%s", (binary_path)), source_path
-# endif
-# else
-# if defined(__clang__)
-# define B_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
-# else
-# define B_REBUILD_URSELF(binary_path, source_path) "cc", "-o", binary_path, source_path
-# endif
-# endif
-#endif
-
-// Go Rebuild Urself™ Technology
-//
-// How to use it:
-// int main(int argc, char** argv) {
-// GO_REBUILD_URSELF(argc, argv);
-// // actual work
-// return 0;
-// }
-//
-// After your added this macro every time you run ./build it will detect
-// that you modified its original source code and will try to rebuild itself
-// before doing any actual work. So you only need to bootstrap your build system
-// once.
-//
-// The modification is detected by comparing the last modified times of the executable
-// and its source code. The same way the make utility usually does it.
-//
-// The rebuilding is done by using the REBUILD_URSELF macro which you can redefine
-// if you need a special way of bootstraping your build system. (which I personally
-// do not recommend since the whole idea of build is to keep the process of bootstrapping
-// as simple as possible and doing all of the actual work inside of the build)
-//
-#define B_GO_REBUILD_URSELF(argc, argv) \
- do { \
- const char *source_path = __FILE__; \
- assert(argc >= 1); \
- const char *binary_path = argv[0]; \
- \
- int rebuild_is_needed = b_needs_rebuild(B_COMPILE, binary_path, &source_path, 1); \
- if (rebuild_is_needed < 0) exit(1); \
- if (rebuild_is_needed) { \
- B_String_Builder sb = {0}; \
- b_sb_append_cstr(&sb, binary_path); \
- b_sb_append_cstr(&sb, ".old"); \
- b_sb_append_null(&sb); \
- \
- if (!b_rename(binary_path, sb.items)) exit(1); \
- B_Cmd rebuild = {0}; \
- b_cmd_append(&rebuild, B_REBUILD_URSELF(binary_path, source_path)); \
- bool rebuild_succeeded = b_cmd_run_sync(rebuild); \
- b_cmd_free(rebuild); \
- if (!rebuild_succeeded) { \
- b_rename(sb.items, binary_path); \
- exit(1); \
- } \
- \
- B_Cmd cmd = {0}; \
- b_da_append_many(&cmd, argv, argc); \
- if (!b_cmd_run_sync(cmd)) exit(1); \
- exit(0); \
- } \
- } while(0)
-// The implementation idea is stolen from https://github.com/zhiayang/nabs
-
-typedef struct {
- size_t count;
- const char *data;
-} B_String_View;
-
-const char *b_temp_sv_to_cstr(B_String_View sv);
-
-B_String_View b_sv_chop_by_delim(B_String_View *sv, char delim);
-B_String_View b_sv_trim(B_String_View sv);
-bool b_sv_eq(B_String_View a, B_String_View b);
-B_String_View b_sv_from_cstr(const char *cstr);
-B_String_View b_sv_from_parts(const char *data, size_t count);
-
-// printf macros for String_View
-#ifndef SV_Fmt
-#define SV_Fmt "%.*s"
-#endif // SV_Fmt
-#ifndef SV_Arg
-#define SV_Arg(sv) (int) (sv).count, (sv).data
-#endif // SV_Arg
-// USAGE:
-// String_View name = ...;
-// printf("Name: "SV_Fmt"\n", SV_Arg(name));
-
-/* file.c */
-/* file.h + */
-/* -------- */
-/* file.o */
-
-/* temlp.h */
-/* f1.c */
-/* f2.c */
-/* f3.c + */
-/* ------ */
-/* templ.o */
-
-/* prog.c */
-/* obj1.o */
-/* obj2.o + */
-/* -------- */
-/* prog */
-
-
-
-#endif // B_H_
-
-#ifdef B_IMPLEMENTATION
-
-static size_t b_temp_size = 0;
-static char b_temp[B_TEMP_CAPACITY] = {0};
-
-bool b_mkdir_if_not_exists(const char *path)
-{
- int result = mkdir(path, 0755);
- if (result < 0) {
- if (errno == EEXIST) {
- //b_log(B_INFO, "directory `%s` already exists", path);
- return true;
- }
- b_log(B_ERROR, "could not create directory `%s`: %s", path, strerror(errno));
- return false;
- }
-
- b_log(B_INFO, "created directory `%s`", path);
- return true;
-}
-
-bool b_copy_file(const char *src_path, const char *dst_path)
-{
- b_log(B_INFO, "copying %s -> %s", src_path, dst_path);
-
- int src_fd = -1;
- int dst_fd = -1;
- size_t buf_size = 32*1024;
- char *buf = B_REALLOC(NULL, buf_size);
- B_ASSERT(buf != NULL && "Buy more RAM lol!!");
- bool result = true;
-
- src_fd = open(src_path, O_RDONLY);
- if (src_fd < 0) {
- b_log(B_ERROR, "Could not open file %s: %s", src_path, strerror(errno));
- b_return_defer(false);
- }
-
- struct stat src_stat;
- if (fstat(src_fd, &src_stat) < 0) {
- b_log(B_ERROR, "Could not get mode of file %s: %s", src_path, strerror(errno));
- b_return_defer(false);
- }
-
- dst_fd = open(dst_path, O_CREAT | O_TRUNC | O_WRONLY, src_stat.st_mode);
- if (dst_fd < 0) {
- b_log(B_ERROR, "Could not create file %s: %s", dst_path, strerror(errno));
- b_return_defer(false);
- }
-
- for (;;) {
- ssize_t n = read(src_fd, buf, buf_size);
- if (n == 0) break;
- if (n < 0) {
- b_log(B_ERROR, "Could not read from file %s: %s", src_path, strerror(errno));
- b_return_defer(false);
- }
- char *buf2 = buf;
- while (n > 0) {
- ssize_t m = write(dst_fd, buf2, n);
- if (m < 0) {
- b_log(B_ERROR, "Could not write to file %s: %s", dst_path, strerror(errno));
- b_return_defer(false);
- }
- n -= m;
- buf2 += m;
- }
- }
-
-defer:
- free(buf);
- close(src_fd);
- close(dst_fd);
- return result;
-}
-
-void b_cmd_render(B_Cmd cmd, B_String_Builder *render)
-{
- for (size_t i = 0; i < cmd.count; ++i) {
- const char *arg = cmd.items[i];
- if (arg == NULL) break;
- if (i > 0) b_sb_append_cstr(render, " ");
- if (!strchr(arg, ' ')) {
- b_sb_append_cstr(render, arg);
- } else {
- b_da_append(render, '\'');
- b_sb_append_cstr(render, arg);
- b_da_append(render, '\'');
- }
- }
-}
-
-B_Proc b_cmd_run_async(B_Cmd cmd)
-{
- if (cmd.count < 1) {
- b_log(B_ERROR, "Could not run empty command");
- return B_INVALID_PROC;
- }
-
- B_String_Builder sb = {0};
- b_cmd_render(cmd, &sb);
- b_sb_append_null(&sb);
- b_log(B_CMD, "%s", sb.items);
- b_sb_free(sb);
- memset(&sb, 0, sizeof(sb));
-
- pid_t cpid = fork();
- if (cpid < 0) {
- b_log(B_ERROR, "Could not fork child process: %s", strerror(errno));
- return B_INVALID_PROC;
- }
-
- if (cpid == 0) {
- // NOTE: This leaks a bit of memory in the child process.
- // But do we actually care? It's a one off leak anyway...
- B_Cmd cmd_null = {0};
- b_da_append_many(&cmd_null, cmd.items, cmd.count);
- b_cmd_append(&cmd_null, NULL);
-
- if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) {
- b_log(B_ERROR, "Could not exec child process: %s", strerror(errno));
- exit(1);
- }
- B_ASSERT(0 && "unreachable");
- }
-
- return cpid;
-}
-
-bool b_procs_wait(B_Procs procs)
-{
- bool success = true;
- for (size_t i = 0; i < procs.count; ++i) {
- success = b_proc_wait(procs.items[i]) && success;
- }
- return success;
-}
-
-bool b_proc_wait(B_Proc proc)
-{
- if (proc == B_INVALID_PROC) return false;
-
- for (;;) {
- int wstatus = 0;
- if (waitpid(proc, &wstatus, 0) < 0) {
- b_log(B_ERROR, "could not wait on command (pid %d): %s", proc, strerror(errno));
- return false;
- }
-
- if (WIFEXITED(wstatus)) {
- int exit_status = WEXITSTATUS(wstatus);
- if (exit_status != 0) {
- b_log(B_ERROR, "command exited with exit code %d", exit_status);
- return false;
- }
-
- break;
- }
-
- if (WIFSIGNALED(wstatus)) {
- b_log(B_ERROR, "command process was terminated by %s", strsignal(WTERMSIG(wstatus)));
- return false;
- }
- }
-
- return true;
-}
-
-bool b_cmd_run_sync(B_Cmd cmd)
-{
- B_Proc p = b_cmd_run_async(cmd);
- if (p == B_INVALID_PROC) return false;
- return b_proc_wait(p);
-}
-
-char *b_shift_args(int *argc, char ***argv)
-{
- B_ASSERT(*argc > 0);
- char *result = **argv;
- (*argv) += 1;
- (*argc) -= 1;
- return result;
-}
-
-void b_log(B_Log_Level level, const char *fmt, ...)
-{
- switch (level) {
- case B_INFO:
- fprintf(stderr, " [INFO] ");
- break;
- case B_CMD:
- fprintf(stderr, " [CMD] ");
- break;
- case B_COMPILE:
- fprintf(stderr, " [COMPILE] ");
- break;
- case B_TEMPLATE:
- fprintf(stderr, "[TEMPLATE] ");
- break;
- case B_CHANGE:
- fprintf(stderr, " [CHANGE] ");
- break;
- case B_WARNING:
- fprintf(stderr, " [WARNING] ");
- break;
- case B_ERROR:
- fprintf(stderr, " [ERROR] ");
- break;
- default:
- B_ASSERT(0 && "unreachable");
- }
-
- va_list args;
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- fprintf(stderr, "\n");
-}
-
-bool b_read_entire_dir(const char *parent, B_File_Paths *children)
-{
- bool result = true;
- DIR *dir = NULL;
-
- dir = opendir(parent);
- if (dir == NULL) {
- b_log(B_ERROR, "Could not open directory %s: %s", parent, strerror(errno));
- b_return_defer(false);
- }
-
- errno = 0;
- struct dirent *ent = readdir(dir);
- while (ent != NULL) {
- b_da_append(children, b_temp_strdup(ent->d_name));
- ent = readdir(dir);
- }
-
- if (errno != 0) {
- b_log(B_ERROR, "Could not read directory %s: %s", parent, strerror(errno));
- b_return_defer(false);
- }
-
-defer:
- if (dir) closedir(dir);
- return result;
-}
-
-bool b_write_entire_file(const char *path, const void *data, size_t size)
-{
- bool result = true;
-
- FILE *f = fopen(path, "wb");
- if (f == NULL) {
- b_log(B_ERROR, "Could not open file %s for writing: %s\n", path, strerror(errno));
- b_return_defer(false);
- }
-
- // len
- // v
- // aaaaaaaaaa
- // ^
- // data
-
- const char *buf = data;
- while (size > 0) {
- size_t n = fwrite(buf, 1, size, f);
- if (ferror(f)) {
- b_log(B_ERROR, "Could not write into file %s: %s\n", path, strerror(errno));
- b_return_defer(false);
- }
- size -= n;
- buf += n;
- }
-
-defer:
- if (f) fclose(f);
- return result;
-}
-
-B_File_Type b_get_file_type(const char *path)
-{
- struct stat statbuf;
- if (stat(path, &statbuf) < 0) {
- b_log(B_ERROR, "Could not get stat of %s: %s", path, strerror(errno));
- return -1;
- }
-
- switch (statbuf.st_mode & S_IFMT) {
- case S_IFDIR: return B_FILE_DIRECTORY;
- case S_IFREG: return B_FILE_REGULAR;
- case S_IFLNK: return B_FILE_SYMLINK;
- default: return B_FILE_OTHER;
- }
-}
-
-bool b_copy_directory_recursively(const char *src_path, const char *dst_path)
-{
- bool result = true;
- B_File_Paths children = {0};
- B_String_Builder src_sb = {0};
- B_String_Builder dst_sb = {0};
- size_t temp_checkpoint = b_temp_save();
-
- B_File_Type type = b_get_file_type(src_path);
- if (type < 0) return false;
-
- switch (type) {
- case B_FILE_DIRECTORY: {
- if (!b_mkdir_if_not_exists(dst_path)) b_return_defer(false);
- if (!b_read_entire_dir(src_path, &children)) b_return_defer(false);
-
- for (size_t i = 0; i < children.count; ++i) {
- if (strcmp(children.items[i], ".") == 0) continue;
- if (strcmp(children.items[i], "..") == 0) continue;
-
- src_sb.count = 0;
- b_sb_append_cstr(&src_sb, src_path);
- b_sb_append_cstr(&src_sb, "/");
- b_sb_append_cstr(&src_sb, children.items[i]);
- b_sb_append_null(&src_sb);
-
- dst_sb.count = 0;
- b_sb_append_cstr(&dst_sb, dst_path);
- b_sb_append_cstr(&dst_sb, "/");
- b_sb_append_cstr(&dst_sb, children.items[i]);
- b_sb_append_null(&dst_sb);
-
- if (!b_copy_directory_recursively(src_sb.items, dst_sb.items)) {
- b_return_defer(false);
- }
- }
- } break;
-
- case B_FILE_REGULAR: {
- if (!b_copy_file(src_path, dst_path)) {
- b_return_defer(false);
- }
- } break;
-
- case B_FILE_SYMLINK: {
- b_log(B_WARNING, "TODO: Copying symlinks is not supported yet");
- } break;
-
- case B_FILE_OTHER: {
- b_log(B_ERROR, "Unsupported type of file %s", src_path);
- b_return_defer(false);
- } break;
-
- default: B_ASSERT(0 && "unreachable");
- }
-
-defer:
- b_temp_rewind(temp_checkpoint);
- b_da_free(src_sb);
- b_da_free(dst_sb);
- b_da_free(children);
- return result;
-}
-
-char *b_temp_strdup(const char *cstr)
-{
- size_t n = strlen(cstr);
- char *result = b_temp_alloc(n + 1);
- B_ASSERT(result != NULL && "Increase B_TEMP_CAPACITY");
- memcpy(result, cstr, n);
- result[n] = '\0';
- return result;
-}
-
-void *b_temp_alloc(size_t size)
-{
- if (b_temp_size + size > B_TEMP_CAPACITY) return NULL;
- void *result = &b_temp[b_temp_size];
- b_temp_size += size;
- return result;
-}
-
-char *b_temp_sprintf(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- int n = vsnprintf(NULL, 0, format, args);
- va_end(args);
-
- B_ASSERT(n >= 0);
- char *result = b_temp_alloc(n + 1);
- B_ASSERT(result != NULL && "Extend the size of the temporary allocator");
- // TODO: use proper arenas for the temporary allocator;
- va_start(args, format);
- vsnprintf(result, n + 1, format, args);
- va_end(args);
-
- return result;
-}
-
-void b_temp_reset(void)
-{
- b_temp_size = 0;
-}
-
-size_t b_temp_save(void)
-{
- return b_temp_size;
-}
-
-void b_temp_rewind(size_t checkpoint)
-{
- b_temp_size = checkpoint;
-}
-
-const char *b_temp_sv_to_cstr(B_String_View sv)
-{
- char *result = b_temp_alloc(sv.count + 1);
- B_ASSERT(result != NULL && "Extend the size of the temporary allocator");
- memcpy(result, sv.data, sv.count);
- result[sv.count] = '\0';
- return result;
-}
-
-int b_needs_rebuild(B_Log_Level log, const char *output_path, const char **input_paths, size_t input_paths_count)
-{
- struct stat statbuf = {0};
-
- if (stat(output_path, &statbuf) < 0) {
- // NOTE: if output does not exist it 100% must be rebuilt
- if (errno == ENOENT) {
- b_log(log, "%s", output_path);
- return 1;
- }
- b_log(B_ERROR, "could not stat %s: %s", output_path, strerror(errno));
- return -1;
- }
- int output_path_time = statbuf.st_mtime;
-
- for (size_t i = 0; i < input_paths_count; ++i) {
- const char *input_path = input_paths[i];
- if (stat(input_path, &statbuf) < 0) {
- // NOTE: non-existing input is an error cause it is needed for building in the first place
- b_log(B_ERROR, "could not stat %s: %s", input_path, strerror(errno));
- return -1;
- }
- int input_path_time = statbuf.st_mtime;
- // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild
- if (input_path_time > output_path_time) {
- b_log(B_CHANGE, "%s", input_path);
- b_log(log, "%s", output_path);
- return 1;
- }
- }
-
- return 0;
-}
-
-int b_needs_rebuild1(B_Log_Level log, const char *output_path, const char *input_path)
-{
- return b_needs_rebuild(log, output_path, &input_path, 1);
-}
-
-bool b_rename(const char *old_path, const char *new_path)
-{
- b_log(B_INFO, "renaming %s -> %s", old_path, new_path);
- if (rename(old_path, new_path) < 0) {
- b_log(B_ERROR, "could not rename %s to %s: %s", old_path, new_path, strerror(errno));
- return false;
- }
- return true;
-}
-
-bool b_read_entire_file(const char *path, B_String_Builder *sb)
-{
- bool result = true;
-
- FILE *f = fopen(path, "rb");
- if (f == NULL) b_return_defer(false);
- if (fseek(f, 0, SEEK_END) < 0) b_return_defer(false);
- long m = ftell(f);
- if (m < 0) b_return_defer(false);
- if (fseek(f, 0, SEEK_SET) < 0) b_return_defer(false);
-
- size_t new_count = sb->count + m;
- if (new_count > sb->capacity) {
- sb->items = realloc(sb->items, new_count);
- B_ASSERT(sb->items != NULL && "Buy more RAM lool!!");
- sb->capacity = new_count;
- }
-
- fread(sb->items + sb->count, m, 1, f);
- if (ferror(f)) {
- // TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case.
- b_return_defer(false);
- }
- sb->count = new_count;
-
-defer:
- if (!result) b_log(B_ERROR, "Could not read file %s: %s", path, strerror(errno));
- if (f) fclose(f);
- return result;
-}
-
-B_String_View b_sv_chop_by_delim(B_String_View *sv, char delim)
-{
- size_t i = 0;
- while (i < sv->count && sv->data[i] != delim) {
- i += 1;
- }
-
- B_String_View result = b_sv_from_parts(sv->data, i);
-
- if (i < sv->count) {
- sv->count -= i + 1;
- sv->data += i + 1;
- } else {
- sv->count -= i;
- sv->data += i;
- }
-
- return result;
-}
-
-B_String_View b_sv_from_parts(const char *data, size_t count)
-{
- B_String_View sv;
- sv.count = count;
- sv.data = data;
- return sv;
-}
-
-B_String_View b_sv_trim_left(B_String_View sv)
-{
- size_t i = 0;
- while (i < sv.count && isspace(sv.data[i])) {
- i += 1;
- }
-
- return b_sv_from_parts(sv.data + i, sv.count - i);
-}
-
-B_String_View b_sv_trim_right(B_String_View sv)
-{
- size_t i = 0;
- while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) {
- i += 1;
- }
-
- return b_sv_from_parts(sv.data, sv.count - i);
-}
-
-B_String_View b_sv_trim(B_String_View sv)
-{
- return b_sv_trim_right(b_sv_trim_left(sv));
-}
-
-B_String_View b_sv_from_cstr(const char *cstr)
-{
- return b_sv_from_parts(cstr, strlen(cstr));
-}
-
-bool b_sv_eq(B_String_View a, B_String_View b)
-{
- if (a.count != b.count) {
- return false;
- } else {
- return memcmp(a.data, b.data, a.count) == 0;
- }
-}
-
-// RETURNS:
-// 0 - file does not exists
-// 1 - file exists
-// -1 - error while checking if file exists. The error is logged
-int b_file_exists(const char *file_path)
-{
- struct stat statbuf;
- if (stat(file_path, &statbuf) < 0) {
- if (errno == ENOENT) return 0;
- b_log(B_ERROR, "Could not check if file %s exists: %s", file_path, strerror(errno));
- return -1;
- }
- return 1;
-}
-
-#endif
+../../b/b.h \ No newline at end of file