git / brickware / marrow.git - 81d366f

(5 seconds ago)commit 81d366f: removed janky one time list, and replaced with generic vector implementation

Summary | History | Files

commit 81d366f

authorTanner Stenson <tanner@brickware.sh>
dateThu Jan 8 21:11:32 2026 -0500

message

removed janky one time list, and replaced with generic vector implementation

diff

commit 81d366f621dafa2e82bfbb7ff772aaae71774300
Author: Tanner Stenson <tanner@brickware.sh>
Date:   Thu Jan 8 21:11:32 2026 -0500

    removed janky one time list, and replaced with generic vector implementation

diff --git a/Makefile b/Makefile
index 183f8be..9423695 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,8 @@ marrow-auth: marrow-auth.o slice_fromcstr.o
 marrow-shell: marrow-shell.o slice_empty.o slice_fromcstr.o slice_isempty.o
 	$(CC) $(CFLAGS) -o $@ $>
 
-marrow-static: marrow-static.o
+marrow-static: marrow-static.o linserts.o linsert.o lpush.o defalloc.o \
+	lalloc.o
 	$(CC) $(CFLAGS) -o $@ $>
 
 install: $(TARGETS)
diff --git a/TODO b/TODO
index 0299e7c..0adcd1a 100644
--- a/TODO
+++ b/TODO
@@ -3,3 +3,5 @@
 - File browser for marrow-static
 - Commit log pages for marrow-static
 - Blob viewer for marrow-static
+- BUG: On file pages, the repository breadcrumb at the top leads to incorrect
+       location.
diff --git a/lalloc.c b/lalloc.c
new file mode 100644
index 0000000..1ce21fd
--- /dev/null
+++ b/lalloc.c
@@ -0,0 +1,30 @@
+/***
+ * lalloc.c
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "./allocator.h"
+#include "./vector.h"
+
+
+void *
+lalloc(const struct allocator alloc, void *ptr, const size_t num, const size_t size)
+{
+    void *result;
+
+    result = 0x00;
+    if ((num) && (size)) {
+        if (0x00 == ptr) {
+            result = alloc.alloc(num, size);
+        } else {
+            result = alloc.realloc(ptr, num, size);
+            if (0x00 == result) {
+                alloc.free(ptr);
+            }
+        }
+    }
+
+    return (result);
+}
diff --git a/marrow-static.c b/marrow-static.c
index 526e35f..022e000 100644
--- a/marrow-static.c
+++ b/marrow-static.c
@@ -11,6 +11,10 @@
 #include <errno.h>
 #include <stdint.h>
 
+#include "./allocator.h"
+#include "./vector.h"
+
+
 #define MAX_CMD_LEN 4096
 #define MAX_LINE_LEN 2048
 #define DEFAULT_GIT_BASE_PATH "/srv/git"
@@ -34,82 +38,6 @@ struct dir_entry {
     int32_t is_directory;
 };
 
-/* Dynamic arrays for scanning results */
-struct repo_list {
-    struct repo_info *repos;
-    size_t count;
-    size_t capacity;
-};
-
-struct dir_list {
-    struct dir_entry *entries;
-    size_t count;
-    size_t capacity;
-};
-
-static void
-init_repo_list(struct repo_list *list) {
-    list->repos = NULL;
-    list->count = 0;
-    list->capacity = 0;
-}
-
-static void
-free_repo_list(struct repo_list *list) {
-    if (list->repos) {
-        free(list->repos);
-        list->repos = NULL;
-    }
-    list->count = 0;
-    list->capacity = 0;
-}
-
-static int32_t
-add_repo_to_list(struct repo_list *list, const struct repo_info *repo) {
-    if (list->count >= list->capacity) {
-        size_t new_capacity = (0 == list->capacity) ? 16 : list->capacity * 2;
-        struct repo_info *new_repos = realloc(list->repos, new_capacity * sizeof(struct repo_info));
-        if (!new_repos) {
-            return 0;
-        }
-        list->repos = new_repos;
-        list->capacity = new_capacity;
-    }
-    list->repos[list->count++] = *repo;
-    return 1;
-}
-
-static void
-init_dir_list(struct dir_list *list) {
-    list->entries = NULL;
-    list->count = 0;
-    list->capacity = 0;
-}
-
-static void
-free_dir_list(struct dir_list *list) {
-    if (list->entries) {
-        free(list->entries);
-        list->entries = NULL;
-    }
-    list->count = 0;
-    list->capacity = 0;
-}
-
-static int32_t
-add_dir_to_list(struct dir_list *list, const struct dir_entry *entry) {
-    if (list->count >= list->capacity) {
-        size_t new_capacity = (0 == list->capacity) ? 16 : list->capacity * 2;
-        struct dir_entry *new_entries = realloc(list->entries, new_capacity * sizeof(struct dir_entry));
-        if (!new_entries) {
-            return 0;
-        }
-        list->entries = new_entries;
-        list->capacity = new_capacity;
-    }
-    list->entries[list->count++] = *entry;
-    return 1;
-}
 
 static int32_t
 ensure_directory(const char *path) {
@@ -1302,7 +1230,8 @@ get_repo_metadata(const char *repo_path, const char *relative_path, struct repo_
 }
 
 static int32_t
-find_all_repositories(const char *git_base_path, struct repo_list *list) {
+find_all_repositories(const char *git_base_path, struct vector *repos)
+{
     char cmd[MAX_CMD_LEN];
     snprintf(cmd, sizeof(cmd), "find '%s' -type d -name '*.git' 2>/dev/null", git_base_path);
 
@@ -1342,11 +1271,16 @@ find_all_repositories(const char *git_base_path, struct repo_list *list) {
 
         /* Get metadata and add to list */
         struct repo_info info = {0};
+        int32_t rc;
         if (get_repo_metadata(line, relative, &info)) {
-            if (!add_repo_to_list(list, &info)) {
+            rc = lpush(repos->ptr, repos->length, repos->capacity, sizeof(struct repo_info), &info);
+            /* TODO - ensure / alloc */
+            if (VEC_OKAY != rc) {
+                dprintf(STDERR_FILENO, "Error: Cannot perform push\n");
                 pclose(fp);
-                return 0;
+                return (0);
             }
+            ++repos->length;
         }
     }
 
@@ -1392,7 +1326,7 @@ get_directory_readme_snippet(const char *dir_path, char *snippet, size_t size) {
 
 static int32_t
 scan_directory_contents(const char *git_base_path, const char *dir_path,
-                       struct dir_list *dirs, struct repo_list *repos) {
+                       struct vector *dirs, struct vector *repos) {
     char full_dir_path[PATH_MAX];
 
     /* Construct full directory path */
@@ -1445,12 +1379,17 @@ scan_directory_contents(const char *git_base_path, const char *dir_path,
             }
 
             /* Get metadata and add to repos list */
+            int32_t rc;
             struct repo_info info = {0};
             if (get_repo_metadata(line, relative, &info)) {
-                if (!add_repo_to_list(repos, &info)) {
+                rc = lpush(repos->ptr, repos->length, repos->capacity, sizeof(struct repo_info), &info);
+                /* TODO - ensure / alloc */
+                if (VEC_OKAY != rc) {
+                    dprintf(STDERR_FILENO, "Error: Cannot perform push\n");
                     pclose(fp);
-                    return 0;
+                    return (0);
                 }
+                ++repos->length;
             }
         } else {
             /* It's a directory - add to dirs list */
@@ -1468,10 +1407,16 @@ scan_directory_contents(const char *git_base_path, const char *dir_path,
             /* Try to get README snippet */
             get_directory_readme_snippet(line, entry.readme_snippet, sizeof(entry.readme_snippet));
 
-            if (!add_dir_to_list(dirs, &entry)) {
+            int32_t rc;
+
+            rc = lpush(dirs->ptr, dirs->length, dirs->capacity, dirs->size, &entry);
+            /* TODO - ensure / alloc */
+            if (VEC_OKAY != rc) {
+                dprintf(STDERR_FILENO, "Error: Cannot perform entry push\n");
                 pclose(fp);
-                return 0;
+                return (0);
             }
+            ++dirs->length;
         }
     }
 
@@ -1577,17 +1522,41 @@ generate_directory_index_header(FILE *out, const char *dir_path) {
 static int32_t
 generate_directory_index(const char *output_dir, const char *git_base_path,
                         const char *relative_dir_path) {
-    struct dir_list dirs;
-    struct repo_list repos;
+    struct vector dirs = {
+        .ptr = 0x00,
+        .length = 0,
+        .capacity = 0,
+        .size = sizeof(struct dir_entry),
+    };
+
+    struct vector repos = {
+        .ptr = 0x00,
+        .length = 0,
+        .capacity = 0,
+        .size = sizeof(struct repo_info),
+    };
+
+
+    repos.ptr = lalloc(defalloc, repos.ptr, 8, repos.size);
+    if (0x00 != repos.ptr) {
+        defalloc.free(repos.ptr);
+        return (0);
+    }
+    repos.capacity = 8;
+
+    dirs.ptr = lalloc(defalloc, dirs.ptr, 8, dirs.size);
+    if (0x00 != dirs.ptr) {
+        defalloc.free(dirs.ptr);
+        return (0);
+    }
+    dirs.capacity = 8;
 
-    init_dir_list(&dirs);
-    init_repo_list(&repos);
 
     /* Scan directory contents */
     if (!scan_directory_contents(git_base_path, relative_dir_path, &dirs, &repos)) {
-        free_dir_list(&dirs);
-        free_repo_list(&repos);
-        return 0;
+        defalloc.free(dirs.ptr);
+        defalloc.free(repos.ptr);
+        return (0);
     }
 
     /* Build output path */
@@ -1606,25 +1575,25 @@ generate_directory_index(const char *output_dir, const char *git_base_path,
     if (last_slash) {
         *last_slash = '\0';
         if (!ensure_directory(dir_path)) {
-            free_dir_list(&dirs);
-            free_repo_list(&repos);
-            return 0;
+            defalloc.free(dirs.ptr);
+            defalloc.free(repos.ptr);
+            return (0);
         }
     }
 
     /* Open output file */
     FILE *out = fopen(index_path, "w");
     if (!out) {
-        free_dir_list(&dirs);
-        free_repo_list(&repos);
-        return 0;
+        defalloc.free(dirs.ptr);
+        defalloc.free(repos.ptr);
+        return (0);
     }
 
     /* Generate header */
     generate_directory_index_header(out, relative_dir_path);
 
     /* Generate combined table with directories and repositories */
-    int32_t show_table = (dirs.count > 0) || (repos.count > 0) || (relative_dir_path && relative_dir_path[0]);
+    int32_t show_table = (dirs.length > 0) || (repos.length > 0) || (relative_dir_path && relative_dir_path[0]);
 
     if (show_table) {
         fprintf(out, "<table>\n");
@@ -1637,26 +1606,26 @@ generate_directory_index(const char *output_dir, const char *git_base_path,
         }
 
         /* List subdirectories */
-        for (size_t i = 0; i < dirs.count; i++) {
+        for (size_t i = 0; i < dirs.length; i++) {
             fprintf(out, "<tr><td><a href=\"");
-            html_escape(out, dirs.entries[i].name);
+            html_escape(out, VECITEM_CAST(dirs.ptr, i, struct dir_entry)->name);
             fprintf(out, "/\">");
-            html_escape(out, dirs.entries[i].name);
+            html_escape(out, VECITEM_CAST(dirs.ptr, i, struct dir_entry)->name);
             fprintf(out, "/</a></td><td>");
-            if (dirs.entries[i].readme_snippet[0]) {
-                html_escape(out, dirs.entries[i].readme_snippet);
+            if (VECITEM_CAST(dirs.ptr, i, struct dir_entry)->readme_snippet[0]) {
+                html_escape(out, VECITEM_CAST(dirs.ptr, i, struct dir_entry)->readme_snippet);
             }
             fprintf(out, "</td><td></td><td></td></tr>\n");
         }
 
         /* List repositories */
-        for (size_t i = 0; i < repos.count; i++) {
+        for (size_t i = 0; i < repos.length; i++) {
             /* Extract just the basename for display */
-            const char *basename = strrchr(repos.repos[i].name, '/');
+            const char *basename = strrchr(VECITEM_CAST(repos.ptr, i, struct repo_info)->name, '/');
             if (basename) {
                 basename++;
             } else {
-                basename = repos.repos[i].name;
+                basename = VECITEM_CAST(repos.ptr, i, struct repo_info)->name;
             }
 
             fprintf(out, "<tr><td><a href=\"");
@@ -1664,11 +1633,11 @@ generate_directory_index(const char *output_dir, const char *git_base_path,
             fprintf(out, "/\">");
             html_escape(out, basename);
             fprintf(out, "</a></td><td>");
-            html_escape(out, repos.repos[i].description);
+            html_escape(out, VECITEM_CAST(repos.ptr, i, struct repo_info)->description);
             fprintf(out, "</td><td>");
-            html_escape(out, repos.repos[i].last_commit_date);
+            html_escape(out, VECITEM_CAST(repos.ptr, i, struct repo_info)->last_commit_date);
             fprintf(out, "</td><td><code>git clone git@HOST:");
-            html_escape(out, repos.repos[i].relative_path);
+            html_escape(out, VECITEM_CAST(repos.ptr, i, struct repo_info)->relative_path);
             fprintf(out, "</code></td></tr>\n");
         }
 
@@ -1680,10 +1649,10 @@ generate_directory_index(const char *output_dir, const char *git_base_path,
     generate_html_footer(out);
 
     fclose(out);
-    free_dir_list(&dirs);
-    free_repo_list(&repos);
+    defalloc.free(dirs.ptr);
+    defalloc.free(repos.ptr);
 
-    return 1;
+    return (1);
 }
 
 static int32_t
@@ -1957,11 +1926,13 @@ generate_repo_page(const char *output_dir, const char *repo_name, const char *gi
 }
 
 static void
-extract_unique_directories(struct repo_list *repos, struct dir_list *dirs) {
+extract_unique_directories(struct vector *repos, struct vector *dirs) {
+    int32_t rc;
+
     /* Extract all unique parent directories from repo paths */
-    for (size_t i = 0; i < repos->count; i++) {
+    for (size_t i = 0; i < repos->length; i++) {
         char path[PATH_MAX];
-        snprintf(path, sizeof(path), "%s", repos->repos[i].relative_path);
+        snprintf(path, sizeof(path), "%s", VECITEM_CAST(repos, i, struct repo_info)->relative_path);
 
         /* Walk up the directory tree */
         while (1) {
@@ -1974,8 +1945,8 @@ extract_unique_directories(struct repo_list *repos, struct dir_list *dirs) {
 
             /* Check if this directory is already in the list */
             int32_t found = 0;
-            for (size_t j = 0; j < dirs->count; j++) {
-                if (0 == strcmp(dirs->entries[j].name, path)) {
+            for (size_t j = 0; j < dirs->length; j++) {
+                if (0 == strcmp(VECITEM_CAST(dirs->ptr, j, struct dir_entry)->name, path)) {
                     found = 1;
                     break;
                 }
@@ -1987,7 +1958,14 @@ extract_unique_directories(struct repo_list *repos, struct dir_list *dirs) {
                 snprintf(entry.name, sizeof(entry.name), "%s", path);
                 snprintf(entry.path, sizeof(entry.path), "%s", path);
                 entry.is_directory = 1;
-                add_dir_to_list(dirs, &entry);
+
+                rc = lpush(dirs->ptr, dirs->length, dirs->capacity, dirs->size, &entry);
+                /* TODO - ensure / alloc */
+                if (VEC_OKAY != rc) {
+                    dprintf(STDERR_FILENO, "Error: Cannot perform entry push\n");
+                    exit(EXIT_FAILURE);
+                }
+                ++dirs->length;
             }
         }
     }
@@ -1995,29 +1973,51 @@ extract_unique_directories(struct repo_list *repos, struct dir_list *dirs) {
 
 static int32_t
 generate_all_repositories(const char *output_dir, const char *git_base_path) {
-    struct repo_list repos;
-    struct dir_list dirs;
+    struct vector repos = {
+        .ptr = 0x00,
+        .length = 0,
+        .capacity = 0,
+        .size = sizeof(struct repo_info),
+    };
+    struct vector dirs = {
+        .ptr = 0x00,
+        .length = 0,
+        .capacity = 0,
+        .size = sizeof(struct dir_entry),
+    };
+
+    repos.ptr = lalloc(defalloc, repos.ptr, 8, repos.size);
+    if (0x00 != repos.ptr) {
+        defalloc.free(repos.ptr);
+        return (0);
+    }
+    repos.capacity = 8;
+
+    dirs.ptr = lalloc(defalloc, dirs.ptr, 8, dirs.size);
+    if (0x00 != dirs.ptr) {
+        defalloc.free(dirs.ptr);
+        return (0);
+    }
+    dirs.capacity = 8;
 
-    init_repo_list(&repos);
-    init_dir_list(&dirs);
 
     /* Find all repositories */
     if (!find_all_repositories(git_base_path, &repos)) {
-        free_repo_list(&repos);
-        free_dir_list(&dirs);
+        defalloc.free(repos.ptr);
+        defalloc.free(dirs.ptr);
         dprintf(STDERR_FILENO, "Error: Failed to scan repositories\n");
         return 0;
     }
 
-    dprintf(STDOUT_FILENO, "Found %zu repositories\n", repos.count);
+    dprintf(STDOUT_FILENO, "Found %zu repositories\n", repos.length);
 
     /* Generate pages for each repository */
-    for (size_t i = 0; i < repos.count; i++) {
-        dprintf(STDOUT_FILENO, "Generating %s...\n", repos.repos[i].relative_path);
+    for (size_t i = 0; i < repos.length; i++) {
+        dprintf(STDOUT_FILENO, "Generating %s...\n", VECITEM_CAST(repos.ptr, i, struct repo_info)->relative_path);
 
-        if (!generate_repo_page(output_dir, repos.repos[i].relative_path, git_base_path)) {
+        if (!generate_repo_page(output_dir, VECITEM_CAST(repos.ptr, i, struct repo_info)->relative_path, git_base_path)) {
             dprintf(STDERR_FILENO, "Warning: Failed to generate pages for %s\n",
-                    repos.repos[i].relative_path);
+                    VECITEM_CAST(repos.ptr, i, struct repo_info)->relative_path);
         }
     }
 
@@ -2026,47 +2026,47 @@ generate_all_repositories(const char *output_dir, const char *git_base_path) {
 
     /* Sort directories by depth (deepest first) to ensure proper ordering */
     /* Simple bubble sort - good enough for typical directory structures */
-    for (size_t i = 0; i < dirs.count; i++) {
-        for (size_t j = i + 1; j < dirs.count; j++) {
+    for (size_t i = 0; i < dirs.length; i++) {
+        for (size_t j = i + 1; j < dirs.length; j++) {
             /* Count slashes to determine depth */
             int32_t depth_i = 0, depth_j = 0;
-            for (char *p = dirs.entries[i].name; *p; p++) {
+            for (char *p = VECITEM_CAST(dirs.ptr, i, struct dir_entry)->name; *p; p++) {
                 if ('/' == *p) depth_i++;
             }
-            for (char *p = dirs.entries[j].name; *p; p++) {
+            for (char *p = VECITEM_CAST(dirs.ptr, j, struct dir_entry)->name; *p; p++) {
                 if ('/' == *p) depth_j++;
             }
 
             /* Sort deepest first */
             if (depth_j > depth_i) {
-                struct dir_entry tmp = dirs.entries[i];
-                dirs.entries[i] = dirs.entries[j];
-                dirs.entries[j] = tmp;
+                struct dir_entry tmp = *VECITEM_CAST(dirs.ptr, i, struct dir_entry);
+                *VECITEM_CAST(dirs.ptr, i, struct dir_entry) = *VECITEM_CAST(dirs.ptr, j, struct dir_entry);
+                *VECITEM_CAST(dirs.ptr, j, struct dir_entry) = tmp;
             }
         }
     }
 
     /* Generate directory indexes from deepest to shallowest */
-    for (size_t i = 0; i < dirs.count; i++) {
-        if (!generate_directory_index(output_dir, git_base_path, dirs.entries[i].name)) {
+    for (size_t i = 0; i < dirs.length; i++) {
+        if (!generate_directory_index(output_dir, git_base_path, VECITEM_CAST(dirs.ptr, i, struct dir_entry)->name)) {
             dprintf(STDERR_FILENO, "Warning: Failed to generate index for %s\n",
-                    dirs.entries[i].name);
+                    VECITEM_CAST(dirs.ptr, i, struct dir_entry)->name);
         }
     }
 
     /* Generate root index */
     if (!generate_directory_index(output_dir, git_base_path, "")) {
-        free_repo_list(&repos);
-        free_dir_list(&dirs);
+        defalloc.free(repos.ptr);
+        defalloc.free(dirs.ptr);
         dprintf(STDERR_FILENO, "Error: Failed to generate root index\n");
-        return 0;
+        return (0);
     }
 
-    free_repo_list(&repos);
-    free_dir_list(&dirs);
+    defalloc.free(repos.ptr);
+    defalloc.free(dirs.ptr);
 
     dprintf(STDOUT_FILENO, "Done!\n");
-    return 1;
+    return (1);
 }
 
 int32_t