Fully implement building entries

Including name and full path
This commit is contained in:
2026-05-15 15:18:14 +02:00
parent 7491ca9877
commit 5b7d9f7b2b

View File

@@ -50,11 +50,57 @@ int compare_library_entries(const void *a, const void *b) {
return noh_sv_compare(lea.name, leb.name);
}
#define build_path(first, ...) build_path_((first), __VA_ARGS__, NULL)
Noh_String build_path_(SV *first, ...) {
va_list args;
SV *elem_ = first;
va_start(args, first);
bool start = true;
Noh_String result = {0};
while (elem_ != NULL) {
SV elem = *elem_;
while (elem.count > 0) {
SV component = noh_sv_chop_by_delim(&elem, '/');
if (noh_sv_eq(component, sv(".."))) continue;
if (component.count > 0) {
if (start) start = false; else noh_string_append_cstr(&result, "/");
noh_string_append_sv(&result, component);
}
}
elem_ = va_arg(args, SV *);
}
va_end(args);
return result;
}
SV path_to_name(SV path) {
while (true) {
SV component = noh_sv_chop_by_delim(&path, '/');
if (path.count == 0) return component;
}
}
void set_modified_time(Library_Entry *entry) {
struct stat attr;
if (stat(noh_arena_sprintf(&temp, Nsv_Fmt, entry->full_path), &attr) == 0) {
struct tm *timeinfo = localtime(&attr.st_mtime);
entry->modified_at = *timeinfo;
} else {
entry->modified_at = (struct tm){0};
}
}
/**
* Creates a Library entry from a dirent structure.
*/
bool create_entry(struct dirent *dir_entry, const char *parent_path, Library_Entry *result) {
SV name = sv(dir_entry->d_name);
SV parent_path_sv = sv(parent_path);
Noh_String full_path = build_path(&parent_path_sv, &name);
int type = dir_entry->d_type;
// Check if the entry is relevant.
@@ -62,24 +108,17 @@ bool create_entry(struct dirent *dir_entry, const char *parent_path, Library_Ent
if (noh_sv_eq(name, sv(".")) || noh_sv_eq(name, sv(".."))) return false;
if (type == DT_REG && !noh_sv_ends_with_ci(name, sv(".epub"))) return false;
// Allocate and populate library entry.
// Set entry data.
result->is_dir = type == DT_DIR;
result->full_path = noh_sv_from_string(&full_path);
result->name = noh_sv_copy_cstr(&temp, dir_entry->d_name);
// Load modified time.
struct stat attr;
if (stat(noh_arena_sprintf(&temp, "%s/"Nsv_Fmt, parent_path, Nsv_Arg(name)), &attr) == 0) {
struct tm *timeinfo = localtime(&attr.st_mtime);
result->modified_at = *timeinfo;
} else {
result->modified_at = (struct tm){0};
}
set_modified_time(result);
return true;
}
char *format_library_entry(Library_Entry entry, char time_buffer[80]) {
strftime(time_buffer, 80, "%Y-%m-%d %H:%M:%S", &entry.modified_at);
strftime(time_buffer, 80, "%Y-%m-%d %H.%M.%S", &entry.modified_at);
return noh_arena_sprintf(
&temp,
@@ -121,29 +160,23 @@ static Noh_String create_feed_response(Library_Entry self_path, Library_Entries
}
static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV base_path, SV username) {
Noh_String fs_path = {0};
noh_string_append_sv(&fs_path, base_path);
noh_string_append_cstr(&fs_path, "/");
noh_string_append_sv(&fs_path, username);
noh_string_append_cstr(&fs_path, "/");
noh_string_append_sv(&fs_path, url);
noh_string_append_null(&fs_path);
noh_arena_save(&temp);
Noh_String fs_path = build_path(&base_path, &username, &url);
Library_Entry self_entry = {
.is_dir = true,
.full_path = noh_sv_from_string(&fs_path),
.name = path_to_name(noh_sv_from_string(&fs_path)),
.modified_at = {0},
};
(void)self_entry;
noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(self_entry.name));
set_modified_time(&self_entry);
noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(self_entry.full_path));
DIR *dir = opendir(fs_path.elems);
if (dir) {
Library_Entries list = {0};
// Build up list of entries.
noh_arena_save(&temp);
struct dirent *entry = noh_arena_alloc(&temp, sizeof(struct dirent));
while ((entry = readdir(dir)) != NULL) {
Library_Entry result = {0};
@@ -167,10 +200,12 @@ static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV
} else if (errno == ENOENT) {
closedir(dir);
noh_arena_reset(&temp);
return send_response(connection, 404, sv(""), false);
} else {
noh_log(NOH_ERROR, "Opening directory failed.");
noh_arena_reset(&temp);
return send_response(connection, 500, sv(""), false);
}
}