Vinicius Teshima 3 ヶ月 前
コミット
43ce79742c
4 ファイル変更470 行追加102 行削除
  1. 4 2
      Makefile
  2. 4 1
      build.sh
  3. 62 17
      first.c
  4. 400 82
      src/lib.h

+ 4 - 2
Makefile

@@ -1,9 +1,11 @@
 .PHONY: all
 all:
-	@echo 'Running build.sh'
-	@./build.sh
+	@./first
 	@ctags --recurse
 
+#@echo 'Running build.sh'
+#@./build.sh
+
 #SRCS=$(shell find ./src -name '*.c' -type f)
 #OBJS=$(patsubst %.c, %.o, ${SRCS})
 #DEPS=$(patsubst %.c, %.d, ${SRCS})

+ 4 - 1
build.sh

@@ -5,7 +5,8 @@ CFLAGS='-std=gnu99 -m64 -Og -ggdb
 -Wcast-align -Wunused -Wconversion -Wmisleading-indentation
 -Wdouble-promotion -Wformat=2 -Wbad-function-cast
 -Wmissing-declarations
--Wmissing-prototypes -Wnested-externs -Werror'
+-Wmissing-prototypes -Wnested-externs -Werror
+-Wno-override-init'
 
 LDFLAGS='-fsanitize=address'
 
@@ -20,6 +21,8 @@ do
             && extras="${extra} -I./raylib-5.5_linux_amd64/include
                                 -L./raylib-5.5_linux_amd64/lib -lraylib
                                 -Wl,-rpath=./raylib-5.5_linux_amd64/lib"
+        set -x
         gcc $CFLAGS $LDFLAGS $extras "$file" -o "$out_file"
+        set +x
         echo "------------------------------------"
 done

+ 62 - 17
first.c

@@ -1,10 +1,13 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <stdarg.h>
+#include <dirent.h>
 
 #include <sys/wait.h>
 #include <sys/stat.h>
 
+#include <errno.h>
+
 /* #define STR_SIZE_LIMIT 65536 */
 #define STR_SIZE_LIMIT 5458264
 
@@ -45,23 +48,65 @@ main(int argc, char *argv[])
 {
     enum err err = ERR_OK;
 
-    struct cmd cmd = {0};
+    GO_REBUILD_YOURSELF(
+        .debug=true,
+        .deps=CSTR_ARRAY("./src/lib.h")
+    );
 
-    /*
-    struct procs procs = {0};
-    */
+    printf("-------------------------\n");
+
+    struct dir dir = {0};
+    struct dirs dirs = {0};
+    dirs = dir_list_cstr("./src", &err, .stat=true, .recurse=true);
 
-    GO_REBUILD_YOURSELF();
+    if ( err == ERR_OK ) DA_FOREACH(dirs, it) {
+        if ( ! cstr_endswith(CSTR_WITH_SIZE(it->path, &err), ".c", 2, &err) )
+            continue;
+        if ( it->stat.st_mtime > dir.stat.st_mtime ) {
+            dir = *it;
+        }
+    }
 
+    struct str exec = {0};
 
-    cmd = cmd_create_ns("ls", &err);
+    {
+        struct str tmp = {0};
+        struct str last = {0};
 
-    cmd_append_args_cstrs(&cmd, &err, "-lh", "first.c", "first");
+        struct str_tokenizer tkn = {0};
+        tkn = str_tokenize(
+            str_from_cstr_ns(dir.path, NULL), '/'
+        );
 
-    cmd_exec(&cmd, &err);
+        tmp = str_tokenizer_next(&tkn);
+        while ( tmp.size != (u64) -1 ) {
+            last = tmp;
+            tmp = str_tokenizer_next(&tkn);
+        }
 
+        tkn = str_tokenize(last, '.');
+        last = str_tokenizer_next(&tkn);
+        exec = str_dup(last);
+    }
+
+    struct cmd cmd = cmd_create_ns(CC, &err);
+    cmd_append_args_cstrs(
+        &cmd, &err,
+        CC_FLAGS, dir.path, "-o", exec.data
+    );
+    cmd_exec(&cmd, &err);
     cmd_destroy(&cmd, &err);
 
+    free((void *)exec.data);
+
+    dir_list_destroy(&dirs, &err);
+
+    if ( err != ERR_OK ) {
+        fprintf(stderr, "Failed doing something: %s\n", err2cstr(err));
+        exit(EXIT_FAILURE);
+    }
+    printf("-------------------------\n");
+
     /*
     bool was_rebuild = false;
     struct dyn_arr dirs = {0};
@@ -195,7 +240,7 @@ main2(int argc, char *argv[])
     do {
         if ( err != ERR_OK ) {
             fprintf(stderr, "ERROR: Failed tokenizing `%.*s`: %s\n",
-                    (int) src_path.size, src_path.data, err_to_name[err]);
+                    (int) src_path.size, src_path.data, err2cstr(err));
             goto error_exit;
         }
         switch ( tk.type ) {
@@ -221,7 +266,7 @@ main2(int argc, char *argv[])
         tk = tokenizer_next_token(&tkn, &err);
     } while ( tk.type != TK_EOF );
 
-    printf("%s\n", err_to_name[err]);
+    printf("%s\n", err2cstr(err));
 
 error_exit:
     if ( f.data != NULL ) free(f.data);
@@ -252,7 +297,7 @@ tkn_expect(struct tokenizer *tkn, enum token_type type, struct token *out_tk,
         tk = tokenizer_next_token(tkn, perr);
         if ( err != ERR_OK ) {
             fprintf(stderr, "Failed to get next token: %s\n",
-                    err_to_name[err]);
+                    err2cstr(err));
             return false;
         }
         fprintf(stderr, "%s ERRRO: Got wrong token, expected: %s, got: %s\n",
@@ -280,7 +325,7 @@ tkn_expect_id(struct tokenizer *tkn, const char *cstr, struct token *out_tk,
         tk = tokenizer_next_token(tkn, &err);
         if ( err != ERR_OK ) {
             fprintf(stderr, "Failed to get next token: %s\n",
-                    err_to_name[err]);
+                    err2cstr(err));
             return false;
         }
         if ( tk.type != TK_ID ) {
@@ -316,7 +361,7 @@ tkn_parse_pp_directive(struct tokenizer *tkn, struct token *out_tk,
 
     tk = tokenizer_next_token(tkn, perr);
     if ( *perr != ERR_OK ) {
-        fprintf(stderr, "Failed to get next token: %s\n", err_to_name[*perr]);
+        fprintf(stderr, "Failed to get next token: %s\n", err2cstr(*perr));
         return false;
     }
 
@@ -346,7 +391,7 @@ tkn_parse_pp_directive(struct tokenizer *tkn, struct token *out_tk,
         tk = tokenizer_next_token(tkn, &err);
         if ( err != ERR_OK ) {
             fprintf(stderr, "Failed to get next token: %s\n",
-                    err_to_name[err]);
+                    err2cstr(err));
             goto def_exit_err;
         }
 
@@ -393,7 +438,7 @@ def_exit_err:
         tk = tokenizer_next_token(tkn, &err);
         if ( err != ERR_OK ) {
             fprintf(stderr, "Failed to get next token: %s\n",
-                    err_to_name[err]);
+                    err2cstr(err));
             return false;
         }
 
@@ -611,7 +656,7 @@ struct func_decl {
 
         } break;
     case TK_INVALID:
-        fprintf(stderr, "Failed to get next token: %s\n", err_to_name[*perr]);
+        fprintf(stderr, "Failed to get next token: %s\n", err2cstr(*perr));
         return false;
     default:
         fprintf(stderr,
@@ -625,7 +670,7 @@ struct func_decl {
 /*
     tk = tokenizer_next_token(tkn, perr);
     if ( *perr != ERR_OK ) {
-        fprintf(stderr, "Failed to get next token: %s\n", err_to_name[*perr]);
+        fprintf(stderr, "Failed to get next token: %s\n", err2cstr(*perr));
         return false;
     }
 

+ 400 - 82
src/lib.h

@@ -22,7 +22,6 @@
 #  define NULL ((void *) 0)
 # endif /* NULL */
 
-
 # ifndef _STDBOOL_H
 #  define LIB_H_STDBOOL
 
@@ -61,6 +60,9 @@ enum err {
     ERR_FAILED_WRITE,
     ERR_FAILED_FORK,
     ERR_FAILED_WAITPID,
+    ERR_FAILED_STAT,
+    ERR_FAILED_OPENDIR,
+    ERR_FAILED_READDIR,
     ERR_WROTE_WRONG_AMOUNT,
     ERR_FAILED_ALLOC,
     ERR_FAILED_REALLOC,
@@ -75,34 +77,48 @@ enum err {
     ERR_SGFX_POS_OUTSIDE_CANVAS
 };
 
-const char *err_to_name[] = {
-    "ERR_GENERAL_ERROR",
-    "ERR_OK",
-    "ERR_NOT_INT",
-    "ERR_TOO_BIG",
-    "ERR_NULL_ARG",
-    "ERR_INVALID_ARG",
-    "ERR_NOT_FOUND",
-    "ERR_INDEX_TOO_LARGE",
-    "ERR_FAILED_OPEN",
-    "ERR_FAILED_CLOSE",
-    "ERR_FAILED_READ",
-    "ERR_FAILED_WRITE",
-    "ERR_FAILED_FORK",
-    "ERR_FAILED_WAITPID",
-    "ERR_WROTE_WRONG_AMOUNT",
-    "ERR_FAILED_ALLOC",
-    "ERR_FAILED_REALLOC",
-    "ERR_MKDIR_FAILED",
-    "ERR_FAILED_HASHING",
-    "ERR_STR_EMPTY",
-    "ERR_PATH_EMPTY",
-    "ERR_PATH_INVALID",
-    "ERR_PATH_FILE_EMPTY",
-    "ERR_PATH_FILE_FAILED_SEEK",
-    "ERR_CMD_NON_ZERO_EXIT_CODE",
-    "ERR_SGFX_POS_OUTSIDE_CANVAS",
-};
+const char *err2cstr(enum err err);
+
+# if defined(IMP) || defined(IMP_LIB)
+
+const char *
+err2cstr(enum err err)
+{
+    switch ( err ) {
+    case ERR_GENERAL_ERROR: return "ERR_GENERAL_ERROR";
+    case ERR_OK: return "ERR_OK";
+    case ERR_NOT_INT: return "ERR_NOT_INT";
+    case ERR_TOO_BIG: return "ERR_TOO_BIG";
+    case ERR_NULL_ARG: return "ERR_NULL_ARG";
+    case ERR_INVALID_ARG: return "ERR_INVALID_ARG";
+    case ERR_NOT_FOUND: return "ERR_NOT_FOUND";
+    case ERR_INDEX_TOO_LARGE: return "ERR_INDEX_TOO_LARGE";
+    case ERR_FAILED_OPEN: return "ERR_FAILED_OPEN";
+    case ERR_FAILED_CLOSE: return "ERR_FAILED_CLOSE";
+    case ERR_FAILED_READ: return "ERR_FAILED_READ";
+    case ERR_FAILED_WRITE: return "ERR_FAILED_WRITE";
+    case ERR_FAILED_FORK: return "ERR_FAILED_FORK";
+    case ERR_FAILED_WAITPID: return "ERR_FAILED_WAITPID";
+    case ERR_FAILED_STAT: return "ERR_FAILED_STAT";
+    case ERR_FAILED_OPENDIR: return "ERR_FAILED_OPENDIR";
+    case ERR_FAILED_READDIR: return "ERR_FAILED_READDIR";
+    case ERR_WROTE_WRONG_AMOUNT: return "ERR_WROTE_WRONG_AMOUNT";
+    case ERR_FAILED_ALLOC: return "ERR_FAILED_ALLOC";
+    case ERR_FAILED_REALLOC: return "ERR_FAILED_REALLOC";
+    case ERR_MKDIR_FAILED: return "ERR_MKDIR_FAILED";
+    case ERR_FAILED_HASHING: return "ERR_FAILED_HASHING";
+    case ERR_STR_EMPTY: return "ERR_STR_EMPTY";
+    case ERR_PATH_EMPTY: return "ERR_PATH_EMPTY";
+    case ERR_PATH_INVALID: return "ERR_PATH_INVALID";
+    case ERR_PATH_FILE_EMPTY: return "ERR_PATH_FILE_EMPTY";
+    case ERR_PATH_FILE_FAILED_SEEK: return "ERR_PATH_FILE_FAILED_SEEK";
+    case ERR_CMD_NON_ZERO_EXIT_CODE: return "ERR_CMD_NON_ZERO_EXIT_CODE";
+    case ERR_SGFX_POS_OUTSIDE_CANVAS: return "ERR_SGFX_POS_OUTSIDE_CANVAS";
+    default: return "UNKNOWN_ERR";
+    }
+}
+
+# endif /* defined(IMP) || defined(IMP_LIB) */
 
 /* ---------------------------- END GLOBAL DEF ----------------------------- */
 
@@ -146,6 +162,14 @@ int fork(void);
 #  error "Must import <stdarg.h> before lib.h!"
 # endif
 
+# ifndef _DIRENT_H
+#  error "Must import <dirent.h> before lib.h!"
+# endif
+
+# ifndef _ERRNO_H
+#  error "Must import <errno.h> before lib.h!"
+# endif
+
 /* ----------------------------- START LIB DEF ----------------------------- */
 
 # define TODO(msg) \
@@ -279,9 +303,167 @@ _VEC2_STRUCT_DEF(u8);
 
 # if defined(WANT_CSTR) || defined(WANT_ALL)
 
+#  ifndef CSTR_SIZE_LIMIT
+#   define CSTR_SIZE_LIMIT 1028
+#  endif /* CSTR_SIZE_LIMIT */
+
+#  define CSTR_ARRAY(...) (const char *[]){__VA_ARGS__, NULL}
+
 u64 cstr_len_max(const char *cstr, u64 max, bool *out_hit_max,
                  enum err *out_err);
 
+struct __cstr_len_args {
+    bool has_max;
+    u64 max;
+    bool *out_hit_max;
+};
+#  define cstr_len(Cstr, OutErr, ...) \
+    _cstr_len( \
+        (Cstr), \
+        (struct __cstr_len_args) { \
+            .has_max=false, \
+            __VA_ARGS__ \
+        }, \
+        (OutErr) \
+    )
+u64 _cstr_len(const char *cstr, struct __cstr_len_args args,
+              enum err *out_err);
+
+const char *cstr_dup(const char *cstr, enum err *out_err);
+
+#  define CSTR_WITH_SIZE(Cstr, OutErr, ...) \
+    (Cstr), cstr_len((Cstr), (OutErr), __VA_ARGS__)
+
+bool cstr_eq(const char *_r_ cstr1, u64 size1,
+             const char *_r_ cstr2, u64 size2, enum err *_r_ out_err);
+
+bool cstr_endswith(const char *_r_ cstr, u64 size,
+                   const char *_r_ end, u64 end_size, enum err *_r_ out_err);
+
+#  if defined(IMP_CSTR) || defined(IMP)
+
+u64
+cstr_len_max(const char *cstr, u64 max, bool *out_hit_max, enum err *out_err)
+{
+    u64 ret = 0;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, 0);
+    LIB_ARG_MUST_NOT_BE_NULL(cstr, out_err, 0);
+
+_loop:
+    if ( ret >= max ) {
+        LIB_SET_IF_NOT_NULL(out_hit_max, true);
+        goto _loop_end;
+    }
+    if ( cstr[ret] == '\0' ) {
+        LIB_SET_IF_NOT_NULL(out_hit_max, false);
+        goto _loop_end;
+    }
+
+    ++ret;
+    goto _loop;
+_loop_end:
+
+    LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
+    return ret;
+}
+
+u64
+_cstr_len(const char *cstr, struct __cstr_len_args args, enum err *out_err)
+{
+    u64 ret = 0;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, 0);
+    LIB_ARG_MUST_NOT_BE_NULL(cstr, out_err, 0);
+
+_loop:
+    if ( args.has_max == true && ret >= args.max ) {
+        LIB_SET_IF_NOT_NULL(args.out_hit_max, true);
+        goto _loop_end;
+    }
+    if ( cstr[ret] == '\0' ) {
+        LIB_SET_IF_NOT_NULL(args.out_hit_max, false);
+        goto _loop_end;
+    }
+
+    ++ret;
+    goto _loop;
+_loop_end:
+
+    LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
+    return ret;
+}
+
+const char *
+cstr_dup(const char *cstr, enum err *out_err)
+{
+    char *ret = NULL;
+    u64 size = 0;
+    bool hit_limit = false;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, NULL);
+    LIB_ARG_MUST_NOT_BE_NULL(cstr, out_err, NULL);
+
+    size = cstr_len_max(cstr, CSTR_SIZE_LIMIT, &hit_limit, NULL);
+    if ( hit_limit == true ) {
+        LIB_SET_IF_NOT_NULL(out_err, ERR_TOO_BIG);
+        goto exit_err;
+    }
+
+    ret = malloc(size + 1);
+    if ( ret == NULL ) {
+        LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC);
+        goto exit_err;
+    }
+    memset(ret, 0, size + 1);
+
+    memcpy(ret, cstr, size);
+
+    return (const char *) ret;
+exit_err:
+    LIB_FREE(ret);
+    return NULL;
+}
+
+bool
+cstr_eq(const char *_r_ cstr1, u64 size1,
+        const char *_r_ cstr2, u64 size2, enum err *_r_ out_err)
+{
+    LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, false);
+    LIB_ARG_MUST_NOT_BE_NULL(cstr1, out_err, false);
+    LIB_ARG_MUST_NOT_BE_NULL(cstr2, out_err, false);
+
+    if ( size1 != size2 ) return false;
+
+    for ( u64 i = 0; i < size1; ++i ) {
+        if ( cstr1[i] != cstr2[i] ) return false;
+    }
+
+    return true;
+}
+
+bool
+cstr_endswith(const char *_r_ cstr, u64 size,
+              const char *_r_ end, u64 end_size, enum err *_r_ out_err)
+{
+    LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, false);
+    LIB_ARG_MUST_NOT_BE_NULL(cstr, out_err, false);
+    LIB_ARG_MUST_NOT_BE_NULL(end, out_err, false);
+
+    if ( size < end_size ) return false;
+
+    u64 i = size - 1;
+    u64 j = end_size - 1;
+_loop:
+    if ( cstr[i] != end[j] ) return false;
+    if ( j == 0 ) return true;
+    --i;
+    --j;
+    goto _loop;
+}
+
+#  endif /* defined(IMP_CSTR) || defined(IMP) */
+
 # endif /* defined(WANT_CSTR) || defined(WANT_ALL) */
 
 /* ----------------------------- END CSTR DEF ------------------------------ */
@@ -1224,8 +1406,6 @@ bool path_mkdir(struct path path, u32 mode, bool do_create_parents,
 bool path_touch(struct path path, int (*open)(const char *, int),
         enum err *out_err);
 
-
-
 struct file {
     u8 *data;
     u64 size;
@@ -1235,8 +1415,136 @@ struct file path_file_read_all(const struct path *path, enum err *out_err);
 enum err path_file_save(const struct path *path, const struct file *file,
                 enum err *out_err);
 
+struct dir {
+    const char *path;
+    struct stat stat;
+};
+
+struct dirs {
+    struct dir *data;
+    u64 size;
+    u64 cap;
+};
+
+struct __dir_list_args {
+    bool stat;
+    bool recurse;
+    bool with_self;
+    bool with_previous;
+};
+#  define dir_list_cstr(Path, OutErr, ...) \
+    _dir_list_cstr( \
+        (Path), \
+        (struct __dir_list_args) {.stat=true, __VA_ARGS__}, \
+        (OutErr) \
+    )
+struct dirs _dir_list_cstr(const char *path, struct __dir_list_args args,
+                           enum err *out_err);
+
+enum err dir_list_destroy(struct dirs *dirs, enum err *out_err);
+
 #  if defined(IMP_PATH) || defined(IMP)
 
+struct dirs
+_dir_list_cstr(const char *path, struct __dir_list_args args,
+               enum err *out_err)
+{
+    enum err err = ERR_OK;
+    enum err *perr = &err;
+
+    struct dirs empty = {0};
+    struct dirs dirs = {0};
+
+    DIR *d = NULL;
+    struct dirent *de = NULL;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty);
+    LIB_ARG_MUST_NOT_BE_NULL(path, out_err, empty);
+
+    if ( out_err != NULL ) perr = out_err;
+
+    d = opendir(path);
+    if ( d == NULL ) {
+        *perr = ERR_FAILED_OPENDIR;
+        goto exit_err;
+    }
+
+    errno = 0;
+    de = readdir(d);
+    while ( de != NULL ) {
+        struct dir dir = {0};
+
+        if ( args.with_self == false ) {
+            if ( cstr_eq(CSTR_WITH_SIZE(de->d_name, perr), ".", 1, perr) ) {
+                goto _continue;
+            }
+        }
+
+        if ( args.with_previous == false ) {
+            if ( cstr_eq(CSTR_WITH_SIZE(de->d_name, perr), "..", 2, perr) ) {
+                goto _continue;
+            }
+        }
+
+        if ( args.recurse == true ) {
+        }
+
+        dir.path = cstr_dup(
+            temp_sprintf("%s/%s", path, de->d_name),
+            perr
+        );
+        if ( *perr != ERR_OK ) goto exit_err;
+
+        if ( args.stat == true ) {
+            *perr = stat(dir.path, &dir.stat);
+            if ( *perr != ERR_OK ) {
+                *perr = ERR_FAILED_STAT;
+                goto exit_err;
+            }
+        }
+
+        DA_APPEND(dirs, dir, perr);
+        if ( *perr != ERR_OK ) goto exit_err;
+
+    _continue:
+        de = readdir(d);
+    }
+
+    if ( errno != 0 ) {
+        *perr = ERR_FAILED_READDIR;
+        goto exit_err;
+    }
+
+    closedir(d);
+
+    *perr = ERR_OK;
+    return dirs;
+exit_err:
+    if ( d != NULL ) closedir(d);
+    dir_list_destroy(&dirs, NULL);
+    return empty;
+}
+
+enum err
+dir_list_destroy(struct dirs *_r_ dirs, enum err *_r_ out_err)
+{
+    LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(dirs, out_err);
+
+    if ( dirs->data != NULL ) {
+        DA_FOREACH(*dirs, it) {
+            LIB_FREE(it->path);
+        }
+    }
+    LIB_FREE(dirs->data);
+
+    dirs->data = NULL;
+    dirs->size = 0;
+    dirs->cap = 0;
+
+    LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
+    return ERR_OK;
+}
 
 #  endif /* defined(IMP_PATH) || defined(IMP) */
 
@@ -1960,6 +2268,12 @@ tokenizer_is_str_lit(struct tokenizer *tkn, struct str str)
 
 #  ifdef unix
 #   define CC "cc"
+#   define CC_FLAGS "-std=gnu99", "-m64", "-O2", "-pedantic", \
+    "-Wall", "-Wextra", "-Wshadow", "-Wcast-align", "-Wunused", \
+    "-Wconversion", "-Wmisleading-indentation", "-Wdouble-promotion", \
+    "-Wformat=2", "-Wbad-function-cast", "-Wmissing-declarations", \
+    "-Wmissing-prototypes", "-Wnested-externs", "-Werror", \
+    "-Wno-override-init"
 #  else
 #   error "No CC for this platform"
 #  endif
@@ -2033,10 +2347,10 @@ enum err cmd_set_exe(struct cmd *_r_ cmd, struct str exe,
 enum err cmd_append_arg(struct cmd *_r_ cmd, struct str arg,
                         enum err *_r_ out_err);
 
-#  define cmd_append_args_cstrs(Cmd, OutErr, Arg, ...) \
+#  define cmd_append_args_cstrs(Cmd, OutErr, ...) \
     _cmd_append_args_cstrs( \
         (Cmd), \
-        (const char *[]){(Arg), __VA_ARGS__, NULL}, \
+        (const char *[]){__VA_ARGS__, NULL}, \
         (OutErr) \
     )
 enum err _cmd_append_args_cstrs(struct cmd *_r_ cmd, const char **args,
@@ -2075,8 +2389,20 @@ enum err _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
 enum err cmd_clear_args(struct cmd *cmd, enum err *out_err);
 enum err cmd_destroy(struct cmd *cmd, enum err *out_err);
 
-#  define GO_REBUILD_YOURSELF() _cmd_go_rebuild_yourself(__FILE__, argv)
-void _cmd_go_rebuild_yourself(const char *src, char **argv);
+struct __cmd_go_rebuild_yourself_args {
+    const char **deps;
+    const char **opts;
+    bool debug;
+};
+
+#  define GO_REBUILD_YOURSELF(...) \
+    _cmd_go_rebuild_yourself( \
+        __FILE__, \
+        argv, \
+        (struct __cmd_go_rebuild_yourself_args){.debug=false, __VA_ARGS__} \
+    )
+void _cmd_go_rebuild_yourself(const char *src, char **argv,
+                              struct __cmd_go_rebuild_yourself_args args);
 
 
 #  if defined(IMP_CMD) || defined(IMP)
@@ -2384,7 +2710,8 @@ cmd_destroy(struct cmd *cmd, enum err *out_err)
 
 #   ifdef _SYS_STAT_H
 void
-_cmd_go_rebuild_yourself(const char *src, char **argv)
+_cmd_go_rebuild_yourself(const char *src, char **argv,
+                         struct __cmd_go_rebuild_yourself_args args)
 {
     enum err err = ERR_OK;
     struct stat src_stat = {0};
@@ -2393,16 +2720,43 @@ _cmd_go_rebuild_yourself(const char *src, char **argv)
     if ( err == ERR_OK ) err = stat(src, &src_stat);
     if ( err == ERR_OK ) err = stat(argv[0] , &exec_stat);
 
+    if ( err == ERR_OK ) if ( args.deps != NULL ) {
+        while ( *args.deps != NULL ) {
+            struct stat tmp_stat = {0};
+            err = stat(*args.deps++, &tmp_stat);
+            if ( err != ERR_OK ) break;
+            if ( tmp_stat.st_mtime > src_stat.st_mtime ) {
+                src_stat = tmp_stat;
+            }
+        }
+    }
+
     if ( err == ERR_OK ) do {
         if ( src_stat.st_mtime > exec_stat.st_mtime ) {
-            err = rename(argv[0], temp_sprintf("%s.old", argv[0]));
-
             struct cmd cmd = cmd_create_ns(CC, &err);
-            cmd_append_arg_ns(&cmd, src, &err);
-            cmd_append_arg_ns(&cmd, "-o", &err);
-            cmd_append_arg_ns(&cmd, argv[0], &err);
+
+            cmd_append_args_cstrs(&cmd, &err, CC_FLAGS);
+
+            if ( args.debug == true ) {
+                cmd_append_args_cstrs(
+                    &cmd, &err,
+                    "-O0", "-ggdb", "-fsanitize=address"
+                );
+            }
+
+            if ( args.opts != NULL ) {
+                _cmd_append_args_cstrs(&cmd, args.opts, &err);
+            }
+
+            cmd_append_args_cstrs(
+                &cmd, &err,
+                src, "-o", temp_sprintf("%s.new", argv[0])
+            );
             cmd_exec(&cmd, &err);
             cmd_destroy(&cmd, &err);
+            if ( err == ERR_OK ) err = rename(
+                temp_sprintf("%s.new", argv[0]), argv[0]
+            );
 
             if ( err == ERR_OK ) execv(argv[0], argv);
             if ( err == ERR_OK ) exit(0);
@@ -2410,7 +2764,7 @@ _cmd_go_rebuild_yourself(const char *src, char **argv)
     } while(0);
 
     if ( err != ERR_OK ) {
-        fprintf(stderr, "Failed recompiling myself: %s\n", err_to_name[err]);
+        fprintf(stderr, "Failed recompiling myself: %s\n", err2cstr(err));
         exit(1);
     }
 }
@@ -2760,43 +3114,6 @@ _str_memcpy(void *dest, const void *src, u64 n)
 
 /* ------------------------------ END LIB IMP ------------------------------ */
 
-/* ---------------------------- START CSTR IMP ----------------------------- */
-
-#  if defined(WANT_CSTR) || defined(WANT_ALL)
-
-u64
-cstr_len_max(const char *cstr, u64 max, bool *out_hit_max, enum err *out_err)
-{
-    u64 ret = 0;
-
-    _ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, 0);
-
-    if ( cstr == NULL ) {
-        _SET_IF_NOT_NULL(out_err, ERR_NULL_ARG);
-        return 0;
-    }
-
-_loop:
-    if ( ret >= max ) {
-        _SET_IF_NOT_NULL(out_hit_max, true);
-        goto _loop_end;
-    }
-    if ( cstr[ret] == '\0' ) {
-        goto _loop_end;
-    }
-
-    ++ret;
-    goto _loop;
-_loop_end:
-
-    _SET_IF_NOT_NULL(out_err, ERR_OK);
-    return ret;
-}
-
-#  endif /* defined(WANT_CSTR) || defined(WANT_ALL) */
-
-/* ----------------------------- END CSTR IMP ------------------------------ */
-
 /* ---------------------------- START STR DEF ------------------------------ */
 
 #  if defined(WANT_STR) || defined(WANT_ALL)
@@ -2942,7 +3259,8 @@ str_dup(struct str str)
 {
     struct str ret = str;
 
-    ret.data = malloc(ret.size * sizeof(*ret.data));
+    ret.data = malloc((ret.size * sizeof(*ret.data)) + 1);
+    memset((void *)ret.data, 0, (ret.size * sizeof(*ret.data)) + 1);
 
     memcpy((char *)ret.data, str.data, str.size);
 
@@ -3263,7 +3581,7 @@ getenv_as_path(const char *name, enum err *out_err)
 {
     struct path empty = {0};
     struct str str = {0};
-    enum err err;
+    enum err err = ERR_OK;
 
     LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty);
 
@@ -3307,7 +3625,7 @@ path_from_str(struct str str, enum err *out_err)
 struct path
 path_from_cstr(const char *cstr, u64 cstr_size, enum err *out_err)
 {
-    enum err err;
+    enum err err = ERR_OK;
     struct str str;
     struct path path = {0};