Split up main.c while keeping a single compilation unit
This commit is contained in:
93
src/library.c
Normal file
93
src/library.c
Normal file
@@ -0,0 +1,93 @@
|
||||
typedef struct {
|
||||
bool is_dir;
|
||||
SV name;
|
||||
SV full_path;
|
||||
struct tm modified_at;
|
||||
} Library_Entry;
|
||||
|
||||
typedef struct {
|
||||
Library_Entry *elems;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} Library_Entries;
|
||||
|
||||
/*
|
||||
* Helper to format an entry's last modified date into a temporary buffer.
|
||||
* The same buffer will be reused the next time this function is called.
|
||||
*/
|
||||
static char *format_time(Library_Entry entry) {
|
||||
static char time_buffer[32];
|
||||
strftime((char*)&time_buffer, 32, "%Y-%m-%dT%H:%M:%S.0000000Z", &entry.modified_at);
|
||||
return (char*)time_buffer;
|
||||
}
|
||||
|
||||
static int compare_library_entries(const void *a, const void *b) {
|
||||
Library_Entry lea = *(Library_Entry*)a;
|
||||
Library_Entry leb = *(Library_Entry*)b;
|
||||
|
||||
if (lea.is_dir && !leb.is_dir) return -1;
|
||||
if (!lea.is_dir && leb.is_dir) return 1;
|
||||
|
||||
return noh_sv_compare(lea.name, leb.name);
|
||||
}
|
||||
|
||||
static 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};
|
||||
}
|
||||
}
|
||||
|
||||
#define build_path(url, first, ...) build_path_((url), (first), __VA_ARGS__, NULL)
|
||||
static Noh_String build_path_(bool url, SV *first, ...) {
|
||||
va_list args;
|
||||
SV *elem_ = first;
|
||||
va_start(args, first);
|
||||
bool start = true;
|
||||
Noh_String result = {0};
|
||||
if (url) noh_string_append_cstr(&result, "/");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Library entry from a dirent structure.
|
||||
*/
|
||||
static 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(false, &parent_path_sv, &name);
|
||||
int type = dir_entry->d_type;
|
||||
|
||||
// Check if the entry is relevant.
|
||||
if (type != DT_DIR && type != DT_REG) return false;
|
||||
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;
|
||||
|
||||
// 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);
|
||||
set_modified_time(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user