(5 seconds ago)commit 81d366f: removed janky one time list, and replaced with generic vector implementation
| 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
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