Replace dynamic allocations with fixed-size buffers and add module extension filtering

- Use fixed STK_PATH_MAX and STK_MOD_ID_BUFFER throughout for predictable memory
- Filter by platform-specific extensions (.so/.dll/.dylib) with compile-time length
- Add RELOAD event detection and is_module_loaded() helper
- Maintain feature parity across all platforms
This commit is contained in:
2026-01-17 19:52:42 +01:00
parent e2e49e605c
commit 38469a358f
4 changed files with 365 additions and 333 deletions
+4 -2
View File
@@ -4,8 +4,10 @@
#include "stk_version.h" #include "stk_version.h"
#include <stdlib.h> #include <stdlib.h>
#define MOD_DIR_BUFFER_SIZE 32 #define STK_MOD_DIR_BUFFER 256
#define PATH_BUFFER_SIZE 1024 #define STK_MOD_ID_BUFFER 64
#define STK_PATH_MAX 256
#define STK_PATH_MAX_OS 4096
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
+44 -43
View File
@@ -8,39 +8,23 @@ void *platform_get_symbol(void *handle, const char *symbol);
typedef void (*stk_module_func)(void); typedef void (*stk_module_func)(void);
char **stk_module_ids = NULL; char (*stk_module_ids)[STK_MOD_ID_BUFFER] = NULL;
static void **stk_handles = NULL; void **stk_handles = NULL;
static stk_module_func *stk_inits = NULL; stk_module_func *stk_inits = NULL;
static stk_module_func *stk_shutdowns = NULL; stk_module_func *stk_shutdowns = NULL;
size_t module_count = 0; size_t module_count = 0;
size_t stk_module_count(void) { return module_count; } size_t stk_module_count(void) { return module_count; }
char *extract_module_id(const char *path) int stk_module_load(const char *path, int index)
{
char *id, *dot;
const char *basename = strrchr(path, '/');
if (!basename)
basename = path;
else
basename++;
id = malloc(strlen(basename) + 1);
strcpy(id, basename);
dot = strrchr(id, '.');
if (dot)
*dot = '\0';
return id;
}
int stk_module_load(const char *path)
{ {
void *handle; void *handle;
stk_module_func init_func; stk_module_func init_func;
stk_module_func shutdown_func; stk_module_func shutdown_func;
const char *basename;
char *dot;
char module_id[STK_MOD_ID_BUFFER];
handle = platform_load_library(path); handle = platform_load_library(path);
if (!handle) if (!handle)
@@ -56,32 +40,49 @@ int stk_module_load(const char *path)
return -2; return -2;
} }
stk_module_ids[module_count] = extract_module_id(path); if (index == -1)
stk_handles[module_count] = handle; index = module_count;
stk_inits[module_count] = init_func;
stk_shutdowns[module_count] = shutdown_func;
init_func(); basename = strrchr(path, '/');
if (!basename)
basename = path;
else
basename++;
strncpy(module_id, basename, STK_MOD_ID_BUFFER - 1);
module_id[STK_MOD_ID_BUFFER - 1] = '\0';
dot = strrchr(module_id, '.');
if (dot)
*dot = '\0';
strncpy(stk_module_ids[index], module_id, STK_MOD_ID_BUFFER - 1);
stk_module_ids[index][STK_MOD_ID_BUFFER - 1] = '\0';
stk_handles[index] = handle;
stk_inits[index] = init_func;
stk_shutdowns[index] = shutdown_func;
init_func(); /* TODO eventually, this should have some sort of check */
++module_count;
return 0; return 0;
} }
int stk_module_load_init(const char *path, int index)
{
int result;
result = stk_module_load(path, index);
if (result == 0)
++module_count;
return result;
}
void stk_module_unload(size_t index) void stk_module_unload(size_t index)
{ {
size_t i;
stk_shutdowns[index](); stk_shutdowns[index]();
platform_unload_library(stk_handles[index]); platform_unload_library(stk_handles[index]);
for (i = index; i < module_count - 1; ++i) {
stk_module_ids[i] = stk_module_ids[i + 1];
stk_handles[i] = stk_handles[i + 1];
stk_inits[i] = stk_inits[i + 1];
stk_shutdowns[i] = stk_shutdowns[i + 1];
}
--module_count;
} }
void stk_module_free_memory(void) void stk_module_free_memory(void)
@@ -99,12 +100,12 @@ void stk_module_free_memory(void)
int stk_module_init_memory(size_t capacity) int stk_module_init_memory(size_t capacity)
{ {
stk_module_ids = malloc(capacity * sizeof(char *)); stk_module_ids = malloc(capacity * sizeof(*stk_module_ids));
stk_handles = malloc(capacity * sizeof(void *)); stk_handles = malloc(capacity * sizeof(void *));
stk_inits = malloc(capacity * sizeof(stk_module_func)); stk_inits = malloc(capacity * sizeof(stk_module_func));
stk_shutdowns = malloc(capacity * sizeof(stk_module_func)); stk_shutdowns = malloc(capacity * sizeof(stk_module_func));
if (!stk_handles || !stk_inits || !stk_shutdowns) { if (!stk_module_ids || !stk_handles || !stk_inits || !stk_shutdowns) {
stk_module_free_memory(); stk_module_free_memory();
return -1; return -1;
} }
+288 -251
View File
@@ -22,93 +22,104 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#define EVENT_BUFFER_SIZE 4096 #if defined(__linux__) || defined(_WIN32)
#define STK_EVENT_BUFFER 4096
#endif
#if !defined(_WIN32) #if defined(_WIN32)
static char **scan_directory(const char *path, size_t *out_count) #define STK_MODULE_EXT ".dll"
#elif defined(__APPLE__)
#define STK_MODULE_EXT ".dylib"
#else
#define STK_MODULE_EXT ".so"
#endif
#define STK_MODULE_EXT_LEN (sizeof(STK_MODULE_EXT) - 1)
static uint8_t is_valid_module_file(const char *filename)
{ {
DIR *dir; const char *ext;
struct dirent *entry; size_t name_len;
struct stat file_stat;
char full_path[PATH_BUFFER_SIZE];
char **file_list = NULL;
size_t count = 0, index = 0;
dir = opendir(path); if (!filename)
if (!dir) { return 0;
mkdir(path, 0755);
*out_count = 0;
return NULL;
}
while ((entry = readdir(dir)) != NULL) { name_len = strlen(filename);
sprintf(full_path, "%s/%s", path, entry->d_name);
if (stat(full_path, &file_stat) == 0 &&
S_ISREG(file_stat.st_mode))
count++;
}
if (count == 0) { if (name_len <= STK_MODULE_EXT_LEN)
closedir(dir); return 0;
*out_count = 0;
return NULL;
}
rewinddir(dir); ext = filename + (name_len - STK_MODULE_EXT_LEN);
return strcmp(ext, STK_MODULE_EXT) == 0;
file_list = (char **)malloc(count * sizeof(char *));
if (!file_list) {
closedir(dir);
*out_count = 0;
return NULL;
}
while ((entry = readdir(dir)) != NULL && index < count) {
sprintf(full_path, "%s/%s", path, entry->d_name);
if (stat(full_path, &file_stat) != 0 ||
!S_ISREG(file_stat.st_mode))
continue;
file_list[index] = (char *)malloc(strlen(entry->d_name) + 1);
if (file_list[index]) {
strcpy(file_list[index], entry->d_name);
index++;
}
}
closedir(dir);
*out_count = index;
return file_list;
} }
static uint8_t is_module_loaded(const char *filename,
char (*loaded_module_ids)[STK_MOD_ID_BUFFER],
size_t loaded_count)
{
char module_id[STK_MOD_ID_BUFFER];
const char *basename;
char *dot;
size_t i;
basename = strrchr(filename, '/');
#ifdef _WIN32
if (!basename)
basename = strrchr(filename, '\\');
#endif #endif
if (!basename)
basename = filename;
else
basename++;
strncpy(module_id, basename, STK_MOD_ID_BUFFER - 1);
module_id[STK_MOD_ID_BUFFER - 1] = '\0';
dot = strrchr(module_id, '.');
if (dot)
*dot = '\0';
for (i = 0; i < loaded_count; i++)
if (strcmp(loaded_module_ids[i], module_id) == 0)
return 1;
return 0;
}
#if !defined(__linux__) && !defined(_WIN32) #if !defined(__linux__) && !defined(_WIN32)
typedef struct { typedef struct {
char *filename; char filename[STK_PATH_MAX];
time_t mtime; time_t mtime;
} file_snapshot_t; } file_snapshot_t;
typedef struct { typedef struct {
int kq; int kq;
int dir_fd; int dir_fd;
char path[PATH_BUFFER_SIZE]; char path[STK_PATH_MAX];
file_snapshot_t *snapshots; file_snapshot_t *snapshots;
size_t snapshot_count; size_t snapshot_count;
size_t snapshot_capacity;
} kqueue_watch_context_t; } kqueue_watch_context_t;
static file_snapshot_t *create_snapshot(const char *path, size_t *out_count) static file_snapshot_t *create_snapshot(const char *path, size_t *out_count,
size_t *out_capacity)
{ {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
struct stat file_stat; struct stat file_stat;
char full_path[PATH_BUFFER_SIZE]; char work_path[STK_PATH_MAX_OS];
file_snapshot_t *snapshots = NULL; file_snapshot_t *snapshots;
size_t count = 0, index = 0; size_t count, capacity, index;
snapshots = NULL;
count = 0;
capacity = 0;
index = 0;
dir = opendir(path); dir = opendir(path);
if (!dir) { if (!dir) {
*out_count = 0; *out_count = 0;
*out_capacity = 0;
return NULL; return NULL;
} }
@@ -116,9 +127,12 @@ static file_snapshot_t *create_snapshot(const char *path, size_t *out_count)
if (strcmp(entry->d_name, ".") == 0 || if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0) strcmp(entry->d_name, "..") == 0)
continue; continue;
snprintf(full_path, sizeof(full_path), "%s/%s", path,
entry->d_name); if (!is_valid_module_file(entry->d_name))
if (stat(full_path, &file_stat) == 0 && continue;
sprintf(work_path, "%s/%s", path, entry->d_name);
if (stat(work_path, &file_stat) == 0 &&
S_ISREG(file_stat.st_mode)) S_ISREG(file_stat.st_mode))
count++; count++;
} }
@@ -126,13 +140,16 @@ static file_snapshot_t *create_snapshot(const char *path, size_t *out_count)
if (count == 0) { if (count == 0) {
closedir(dir); closedir(dir);
*out_count = 0; *out_count = 0;
*out_capacity = 0;
return NULL; return NULL;
} }
snapshots = malloc(count * sizeof(file_snapshot_t)); capacity = count + 8;
snapshots = malloc(capacity * sizeof(file_snapshot_t));
if (!snapshots) { if (!snapshots) {
closedir(dir); closedir(dir);
*out_count = 0; *out_count = 0;
*out_capacity = 0;
return NULL; return NULL;
} }
@@ -142,47 +159,39 @@ static file_snapshot_t *create_snapshot(const char *path, size_t *out_count)
if (strcmp(entry->d_name, ".") == 0 || if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0) strcmp(entry->d_name, "..") == 0)
continue; continue;
snprintf(full_path, sizeof(full_path), "%s/%s", path,
entry->d_name); if (!is_valid_module_file(entry->d_name))
if (stat(full_path, &file_stat) != 0 || continue;
sprintf(work_path, "%s/%s", path, entry->d_name);
if (stat(work_path, &file_stat) != 0 ||
!S_ISREG(file_stat.st_mode)) !S_ISREG(file_stat.st_mode))
continue; continue;
snapshots[index].filename = malloc(strlen(entry->d_name) + 1); strncpy(snapshots[index].filename, entry->d_name,
if (snapshots[index].filename) { STK_PATH_MAX - 1);
strcpy(snapshots[index].filename, entry->d_name); snapshots[index].filename[STK_PATH_MAX - 1] = '\0';
snapshots[index].mtime = file_stat.st_mtime; snapshots[index].mtime = file_stat.st_mtime;
index++; index++;
}
} }
closedir(dir); closedir(dir);
*out_count = index; *out_count = index;
*out_capacity = capacity;
return snapshots; return snapshots;
} }
static void free_snapshot(file_snapshot_t *snapshots, size_t count)
{
size_t i;
if (!snapshots)
return;
for (i = 0; i < count; i++) {
free(snapshots[i].filename);
}
free(snapshots);
}
static file_snapshot_t *find_in_snapshot(file_snapshot_t *snapshots, static file_snapshot_t *find_in_snapshot(file_snapshot_t *snapshots,
size_t count, const char *filename) size_t count, const char *filename)
{ {
size_t i; size_t i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (strcmp(snapshots[i].filename, filename) == 0) if (strcmp(snapshots[i].filename, filename) == 0) {
return &snapshots[i]; return &snapshots[i];
}
} }
return NULL; return NULL;
} }
#endif #endif
void *platform_load_library(const char *path) void *platform_load_library(const char *path)
@@ -216,60 +225,50 @@ void *platform_directory_watch_start(const char *path)
{ {
#ifdef __linux__ #ifdef __linux__
int fd, wd; int fd, wd;
fd = inotify_init1(IN_NONBLOCK); fd = inotify_init1(IN_NONBLOCK);
if (fd < 0) if (fd < 0)
return NULL; return NULL;
wd = inotify_add_watch( wd = inotify_add_watch(
fd, path, IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_TO | IN_MOVED_FROM); fd, path, IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_TO | IN_MOVED_FROM);
if (wd < 0) { if (wd < 0) {
close(fd); close(fd);
return NULL; return NULL;
} }
return (void *)(long)fd; return (void *)(long)fd;
#elif defined(_WIN32) #elif defined(_WIN32)
HANDLE handle = HANDLE handle =
CreateFileA(path, FILE_LIST_DIRECTORY, CreateFileA(path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
return (handle == INVALID_HANDLE_VALUE) ? NULL : (void *)handle;
if (handle == INVALID_HANDLE_VALUE)
return NULL;
return (void *)handle;
#else #else
struct kevent event; struct kevent event;
kqueue_watch_context_t *ctx = malloc(sizeof(kqueue_watch_context_t)); kqueue_watch_context_t *ctx;
ctx = malloc(sizeof(kqueue_watch_context_t));
if (!ctx) if (!ctx)
return NULL; return NULL;
ctx->kq = kqueue(); ctx->kq = kqueue();
ctx->dir_fd = open(path, O_RDONLY); ctx->dir_fd = open(path, O_RDONLY);
strncpy(ctx->path, path, PATH_BUFFER_SIZE - 1); strncpy(ctx->path, path, STK_PATH_MAX - 1);
ctx->path[PATH_BUFFER_SIZE - 1] = '\0'; ctx->path[STK_PATH_MAX - 1] = '\0';
ctx->snapshots = create_snapshot(path, &ctx->snapshot_count,
ctx->snapshots = create_snapshot(path, &ctx->snapshot_count); &ctx->snapshot_capacity);
if (ctx->kq < 0 || ctx->dir_fd < 0) { if (ctx->kq < 0 || ctx->dir_fd < 0) {
if (ctx->kq >= 0) if (ctx->kq >= 0)
close(ctx->kq); close(ctx->kq);
if (ctx->dir_fd >= 0) if (ctx->dir_fd >= 0)
close(ctx->dir_fd); close(ctx->dir_fd);
free_snapshot(ctx->snapshots, ctx->snapshot_count); free(ctx->snapshots);
free(ctx); free(ctx);
return NULL; return NULL;
} }
EV_SET(&event, ctx->dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, EV_SET(&event, ctx->dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
NOTE_WRITE | NOTE_DELETE | NOTE_RENAME, 0, NULL); NOTE_WRITE | NOTE_DELETE | NOTE_RENAME, 0, NULL);
kevent(ctx->kq, &event, 1, NULL, 0, NULL); kevent(ctx->kq, &event, 1, NULL, 0, NULL);
return (void *)ctx; return (void *)ctx;
#endif #endif
} }
@@ -277,43 +276,42 @@ void *platform_directory_watch_start(const char *path)
void platform_directory_watch_stop(void *handle) void platform_directory_watch_stop(void *handle)
{ {
#ifdef __linux__ #ifdef __linux__
if (!handle) if (handle)
return; close((int)(long)handle);
close((int)(long)handle);
#elif defined(_WIN32) #elif defined(_WIN32)
CloseHandle((HANDLE)handle); if (handle)
CloseHandle((HANDLE)handle);
#else #else
kqueue_watch_context_t *ctx = (kqueue_watch_context_t *)handle; kqueue_watch_context_t *ctx;
ctx = (kqueue_watch_context_t *)handle;
if (!ctx) if (!ctx)
return; return;
if (ctx->dir_fd >= 0) if (ctx->dir_fd >= 0)
close(ctx->dir_fd); close(ctx->dir_fd);
if (ctx->kq >= 0) if (ctx->kq >= 0)
close(ctx->kq); close(ctx->kq);
free_snapshot(ctx->snapshots, ctx->snapshot_count); free(ctx->snapshots);
free(ctx); free(ctx);
#endif #endif
} }
stk_module_event_t *platform_directory_watch_check(void *handle, stk_module_event_t *platform_directory_watch_check(
char ***file_list, void *handle, char (**file_list)[STK_PATH_MAX], size_t *out_count,
size_t *out_count) char (*loaded_module_ids)[STK_MOD_ID_BUFFER], const size_t loaded_count)
{ {
#if defined(__linux__) || defined(_WIN32)
size_t file_count = 0;
#endif
size_t index = 0; size_t index = 0;
stk_module_event_t *events = NULL; stk_module_event_t *events = NULL;
#ifdef __linux__ #ifdef __linux__
char buffer[EVENT_BUFFER_SIZE]; char buffer[STK_EVENT_BUFFER];
ssize_t bytes_read; ssize_t bytes_read;
struct inotify_event *event; struct inotify_event *event;
char *event_ptr; char *event_ptr;
int fd = (int)(long)handle; int fd;
size_t file_count;
fd = (int)(long)handle;
file_count = 0;
bytes_read = read(fd, buffer, sizeof(buffer)); bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read <= 0) { if (bytes_read <= 0) {
@@ -324,7 +322,7 @@ stk_module_event_t *platform_directory_watch_check(void *handle,
event_ptr = buffer; event_ptr = buffer;
while (event_ptr < buffer + bytes_read) { while (event_ptr < buffer + bytes_read) {
event = (struct inotify_event *)event_ptr; event = (struct inotify_event *)event_ptr;
if (event->len > 0) if (event->len > 0 && is_valid_module_file(event->name))
file_count++; file_count++;
event_ptr += sizeof(struct inotify_event) + event->len; event_ptr += sizeof(struct inotify_event) + event->len;
} }
@@ -335,43 +333,46 @@ stk_module_event_t *platform_directory_watch_check(void *handle,
} }
events = malloc(file_count * sizeof(stk_module_event_t)); events = malloc(file_count * sizeof(stk_module_event_t));
*file_list = malloc(file_count * sizeof(char *)); *file_list = malloc(file_count * sizeof(**file_list));
if (!events || !*file_list) {
free(events);
free(*file_list);
*out_count = 0;
return NULL;
}
index = 0; index = 0;
event_ptr = buffer; event_ptr = buffer;
while (event_ptr < buffer + bytes_read) { while (event_ptr < buffer + bytes_read) {
event = (struct inotify_event *)event_ptr; event = (struct inotify_event *)event_ptr;
if (event->len > 0) { if (event->len > 0 && is_valid_module_file(event->name)) {
events[index] = events[index] =
(event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) (event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO))
? STK_MOD_LOAD ? (is_module_loaded(event->name,
loaded_module_ids,
loaded_count)
? STK_MOD_RELOAD
: STK_MOD_LOAD)
: STK_MOD_UNLOAD; : STK_MOD_UNLOAD;
(*file_list)[index] = malloc(strlen(event->name) + 1); strncpy((*file_list)[index], event->name,
if ((*file_list)[index]) { STK_PATH_MAX - 1);
strcpy((*file_list)[index], event->name); (*file_list)[index][STK_PATH_MAX - 1] = '\0';
index++; index++;
}
} }
event_ptr += sizeof(struct inotify_event) + event->len; event_ptr += sizeof(struct inotify_event) + event->len;
} }
#elif defined(_WIN32) #elif defined(_WIN32)
HANDLE h = (HANDLE)handle; HANDLE h;
BYTE buffer[EVENT_BUFFER_SIZE]; BYTE buffer[STK_EVENT_BUFFER];
DWORD bytes_returned; DWORD bytes_returned;
FILE_NOTIFY_INFORMATION *info; FILE_NOTIFY_INFORMATION *info;
BYTE *event_ptr; BYTE *event_ptr;
int char_count; size_t file_count;
char temp_filename[STK_PATH_MAX];
int len;
BOOL result;
BOOL result = ReadDirectoryChangesW(h, buffer, sizeof(buffer), FALSE, h = (HANDLE)handle;
FILE_NOTIFY_CHANGE_FILE_NAME | file_count = 0;
FILE_NOTIFY_CHANGE_LAST_WRITE,
&bytes_returned, NULL, NULL); result = ReadDirectoryChangesW(h, buffer, sizeof(buffer), FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE,
&bytes_returned, NULL, NULL);
if (!result || bytes_returned == 0) { if (!result || bytes_returned == 0) {
*out_count = 0; *out_count = 0;
return NULL; return NULL;
@@ -380,7 +381,15 @@ stk_module_event_t *platform_directory_watch_check(void *handle,
event_ptr = buffer; event_ptr = buffer;
while (1) { while (1) {
info = (FILE_NOTIFY_INFORMATION *)event_ptr; info = (FILE_NOTIFY_INFORMATION *)event_ptr;
file_count++; len = WideCharToMultiByte(CP_UTF8, 0, info->FileName,
info->FileNameLength / sizeof(WCHAR),
temp_filename, STK_PATH_MAX - 1, NULL,
NULL);
if (len > 0) {
temp_filename[len] = '\0';
if (is_valid_module_file(temp_filename))
file_count++;
}
if (info->NextEntryOffset == 0) if (info->NextEntryOffset == 0)
break; break;
event_ptr += info->NextEntryOffset; event_ptr += info->NextEntryOffset;
@@ -392,67 +401,59 @@ stk_module_event_t *platform_directory_watch_check(void *handle,
} }
events = malloc(file_count * sizeof(stk_module_event_t)); events = malloc(file_count * sizeof(stk_module_event_t));
*file_list = malloc(file_count * sizeof(char *)); *file_list = malloc(file_count * sizeof(**file_list));
if (!events || !*file_list) {
free(events);
free(*file_list);
*out_count = 0;
return NULL;
}
index = 0; index = 0;
event_ptr = buffer; event_ptr = buffer;
while (1) { while (1) {
info = (FILE_NOTIFY_INFORMATION *)event_ptr; info = (FILE_NOTIFY_INFORMATION *)event_ptr;
events[index] = (info->Action == FILE_ACTION_ADDED || len = WideCharToMultiByte(CP_UTF8, 0, info->FileName,
info->Action == FILE_ACTION_MODIFIED || info->FileNameLength / sizeof(WCHAR),
info->Action == FILE_ACTION_RENAMED_NEW_NAME) (*file_list)[index], STK_PATH_MAX - 1,
? STK_MOD_LOAD NULL, NULL);
: STK_MOD_UNLOAD; if (len > 0) {
char_count = WideCharToMultiByte( (*file_list)[index][len] = '\0';
CP_UTF8, 0, info->FileName, if (is_valid_module_file((*file_list)[index])) {
info->FileNameLength / sizeof(WCHAR), NULL, 0, NULL, NULL); events[index] =
(info->Action != FILE_ACTION_REMOVED &&
if (char_count > 0) { info->Action !=
(*file_list)[index] = malloc(char_count + 1); FILE_ACTION_RENAMED_OLD_NAME)
if ((*file_list)[index]) { ? (is_module_loaded((*file_list)[index],
WideCharToMultiByte(CP_UTF8, 0, info->FileName, loaded_module_ids,
info->FileNameLength / loaded_count)
sizeof(WCHAR), ? STK_MOD_RELOAD
(*file_list)[index], : STK_MOD_LOAD)
char_count, NULL, NULL); : STK_MOD_UNLOAD;
(*file_list)[index][char_count] = '\0';
index++; index++;
} }
} }
if (info->NextEntryOffset == 0) if (info->NextEntryOffset == 0)
break; break;
event_ptr += info->NextEntryOffset; event_ptr += info->NextEntryOffset;
} }
#else #else
kqueue_watch_context_t *ctx = (kqueue_watch_context_t *)handle; kqueue_watch_context_t *ctx;
struct kevent event; struct kevent event;
struct timespec timeout = {0, 0}; struct timespec timeout;
int nevents; file_snapshot_t *new_snapshots, *old_snap;
file_snapshot_t *new_snapshots, *old_snap, *new_snap; size_t new_count, new_capacity, i, change_count;
size_t new_count, i;
size_t change_count = 0;
nevents = kevent(ctx->kq, NULL, 0, &event, 1, &timeout); ctx = (kqueue_watch_context_t *)handle;
if (nevents <= 0) { timeout.tv_sec = 0;
timeout.tv_nsec = 0;
change_count = 0;
if (kevent(ctx->kq, NULL, 0, &event, 1, &timeout) <= 0) {
*out_count = 0; *out_count = 0;
return NULL; return NULL;
} }
new_snapshots = create_snapshot(ctx->path, &new_count); new_snapshots = create_snapshot(ctx->path, &new_count, &new_capacity);
for (i = 0; i < ctx->snapshot_count; i++) { for (i = 0; i < ctx->snapshot_count; i++)
new_snap = find_in_snapshot(new_snapshots, new_count, if (!find_in_snapshot(new_snapshots, new_count,
ctx->snapshots[i].filename); ctx->snapshots[i].filename))
if (!new_snap)
change_count++; change_count++;
}
for (i = 0; i < new_count; i++) { for (i = 0; i < new_count; i++) {
old_snap = find_in_snapshot(ctx->snapshots, ctx->snapshot_count, old_snap = find_in_snapshot(ctx->snapshots, ctx->snapshot_count,
@@ -462,34 +463,24 @@ stk_module_event_t *platform_directory_watch_check(void *handle,
} }
if (change_count == 0) { if (change_count == 0) {
free_snapshot(new_snapshots, new_count); free(new_snapshots);
*out_count = 0; *out_count = 0;
return NULL; return NULL;
} }
events = malloc(change_count * sizeof(stk_module_event_t)); events = malloc(change_count * sizeof(stk_module_event_t));
*file_list = malloc(change_count * sizeof(char *)); *file_list = malloc(change_count * sizeof(**file_list));
if (!events || !*file_list) {
free(events);
free(*file_list);
free_snapshot(new_snapshots, new_count);
*out_count = 0;
return NULL;
}
index = 0; index = 0;
for (i = 0; i < ctx->snapshot_count && index < change_count; i++) { for (i = 0; i < ctx->snapshot_count && index < change_count; i++) {
new_snap = find_in_snapshot(new_snapshots, new_count, if (!find_in_snapshot(new_snapshots, new_count,
ctx->snapshots[i].filename); ctx->snapshots[i].filename)) {
if (!new_snap) {
events[index] = STK_MOD_UNLOAD; events[index] = STK_MOD_UNLOAD;
(*file_list)[index] = strncpy((*file_list)[index], ctx->snapshots[i].filename,
malloc(strlen(ctx->snapshots[i].filename) + 1); STK_PATH_MAX - 1);
if ((*file_list)[index]) { (*file_list)[index][STK_PATH_MAX - 1] = '\0';
strcpy((*file_list)[index], index++;
ctx->snapshots[i].filename);
index++;
}
} }
} }
@@ -497,49 +488,63 @@ stk_module_event_t *platform_directory_watch_check(void *handle,
old_snap = find_in_snapshot(ctx->snapshots, ctx->snapshot_count, old_snap = find_in_snapshot(ctx->snapshots, ctx->snapshot_count,
new_snapshots[i].filename); new_snapshots[i].filename);
if (!old_snap || old_snap->mtime != new_snapshots[i].mtime) { if (!old_snap || old_snap->mtime != new_snapshots[i].mtime) {
events[index] = STK_MOD_LOAD; events[index] =
(*file_list)[index] = is_module_loaded(new_snapshots[i].filename,
malloc(strlen(new_snapshots[i].filename) + 1); loaded_module_ids, loaded_count)
if ((*file_list)[index]) { ? STK_MOD_RELOAD
strcpy((*file_list)[index], : STK_MOD_LOAD;
new_snapshots[i].filename); strncpy((*file_list)[index], new_snapshots[i].filename,
index++; STK_PATH_MAX - 1);
} (*file_list)[index][STK_PATH_MAX - 1] = '\0';
index++;
} }
} }
free_snapshot(ctx->snapshots, ctx->snapshot_count); free(ctx->snapshots);
ctx->snapshots = new_snapshots; ctx->snapshots = new_snapshots;
ctx->snapshot_count = new_count; ctx->snapshot_count = new_count;
ctx->snapshot_capacity = new_capacity;
#endif #endif
*out_count = index; *out_count = index;
return events; return events;
} }
char **platform_directory_init_scan(const char *path, size_t *out_count) char (*platform_directory_init_scan(const char *mod_dir,
size_t *out_count))[STK_PATH_MAX]
{ {
char(*file_list)[STK_PATH_MAX] = NULL;
char work_path[STK_PATH_MAX_OS];
size_t count = 0, index = 0;
#if defined(_WIN32) #if defined(_WIN32)
WIN32_FIND_DATAW find_data; WIN32_FIND_DATAW find_data;
HANDLE find_handle; HANDLE find_handle;
WCHAR search_path[PATH_BUFFER_SIZE]; WCHAR search_path[STK_PATH_MAX_OS];
char **file_list = NULL; char temp_filename[STK_PATH_MAX];
size_t count = 0, index = 0; int len;
int utf8_len;
swprintf(search_path, PATH_BUFFER_SIZE, L"%S\\*", path);
swprintf(search_path, STK_PATH_MAX_OS, L"%S\\*", mod_dir);
find_handle = FindFirstFileW(search_path, &find_data); find_handle = FindFirstFileW(search_path, &find_data);
if (find_handle == INVALID_HANDLE_VALUE) { if (find_handle == INVALID_HANDLE_VALUE) {
CreateDirectoryA(path, NULL); CreateDirectoryA(mod_dir, NULL);
*out_count = 0; *out_count = 0;
return NULL; return NULL;
} }
do { do {
if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
count++; continue;
} while (FindNextFileW(find_handle, &find_data));
len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, -1,
temp_filename, STK_PATH_MAX - 1, NULL,
NULL);
if (len > 0) {
temp_filename[len] = '\0';
if (is_valid_module_file(temp_filename))
count++;
}
} while (FindNextFileW(find_handle, &find_data));
FindClose(find_handle); FindClose(find_handle);
if (count == 0) { if (count == 0) {
@@ -548,41 +553,73 @@ char **platform_directory_init_scan(const char *path, size_t *out_count)
} }
find_handle = FindFirstFileW(search_path, &find_data); find_handle = FindFirstFileW(search_path, &find_data);
if (find_handle == INVALID_HANDLE_VALUE) { file_list = malloc(count * sizeof(*file_list));
*out_count = 0;
return NULL;
}
file_list = (char **)malloc(count * sizeof(char *));
if (!file_list) {
FindClose(find_handle);
*out_count = 0;
return NULL;
}
do { do {
if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
index < count) { continue;
utf8_len =
WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, -1,
-1, NULL, 0, NULL, NULL); file_list[index], STK_PATH_MAX - 1,
if (utf8_len > 0) { NULL, NULL);
file_list[index] = (char *)malloc(utf8_len); if (len > 0 && index < count) {
if (file_list[index]) { file_list[index][len] = '\0';
WideCharToMultiByte( if (is_valid_module_file(file_list[index]))
CP_UTF8, 0, find_data.cFileName, -1, index++;
file_list[index], utf8_len, NULL,
NULL);
index++;
}
}
} }
} while (FindNextFileW(find_handle, &find_data) && index < count); } while (FindNextFileW(find_handle, &find_data) && index < count);
FindClose(find_handle); FindClose(find_handle);
#else
DIR *dir;
struct dirent *entry;
struct stat file_stat;
dir = opendir(mod_dir);
if (!dir) {
mkdir(mod_dir, 0755);
*out_count = 0;
return NULL;
}
while ((entry = readdir(dir)) != NULL) {
if (!is_valid_module_file(entry->d_name))
continue;
sprintf(work_path, "%s/%s", mod_dir, entry->d_name);
if (stat(work_path, &file_stat) == 0 &&
S_ISREG(file_stat.st_mode))
count++;
}
if (count == 0) {
closedir(dir);
*out_count = 0;
return NULL;
}
rewinddir(dir);
file_list = malloc(count * sizeof(*file_list));
if (!file_list) {
closedir(dir);
*out_count = 0;
return NULL;
}
while ((entry = readdir(dir)) != NULL && index < count) {
if (!is_valid_module_file(entry->d_name))
continue;
sprintf(work_path, "%s/%s", mod_dir, entry->d_name);
if (stat(work_path, &file_stat) != 0 ||
!S_ISREG(file_stat.st_mode))
continue;
strncpy(file_list[index], entry->d_name, STK_PATH_MAX - 1);
file_list[index][STK_PATH_MAX - 1] = '\0';
index++;
}
closedir(dir);
#endif
*out_count = index; *out_count = index;
return file_list; return file_list;
#else
return scan_directory(path, out_count);
#endif
} }
+29 -37
View File
@@ -1,35 +1,45 @@
#include "stk.h" #include "stk.h"
#include "stk_log.h" #include "stk_log.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
extern char **stk_module_ids; typedef void (*stk_module_func)(void);
extern void **stk_handles;
extern stk_module_func *stk_inits;
extern stk_module_func *stk_shutdowns;
extern char (*stk_module_ids)[STK_MOD_ID_BUFFER];
extern size_t module_count; extern size_t module_count;
static char stk_mod_dir[MOD_DIR_BUFFER_SIZE]; static char stk_mod_dir[STK_MOD_DIR_BUFFER];
static void *watch_handle = NULL; static void *watch_handle = NULL;
char **platform_directory_init_scan(const char *path, size_t *out_count); char *extract_module_id(const char *path);
char (*platform_directory_init_scan(const char *path,
size_t *out_count))[STK_PATH_MAX];
void *platform_directory_watch_start(const char *path); void *platform_directory_watch_start(const char *path);
void platform_directory_watch_stop(void *handle); void platform_directory_watch_stop(void *handle);
size_t stk_module_count(void); size_t stk_module_count(void);
int stk_module_load(const char *path); int stk_module_load(const char *path, int index);
int stk_module_load_init(const char *path, int index);
void stk_module_unload(size_t index); void stk_module_unload(size_t index);
void stk_module_unload_all(void); void stk_module_unload_all(void);
int stk_module_init_memory(size_t capacity); int stk_module_init_memory(size_t capacity);
stk_module_event_t *platform_directory_watch_check(void *handle, stk_module_event_t *platform_directory_watch_check(
char ***file_list, void *handle, char (**file_list)[STK_PATH_MAX], size_t *out_count,
size_t *out_count); char (*loaded_module_ids)[STK_MOD_ID_BUFFER], const size_t loaded_count);
int stk_init(const char *mod_dir) int stk_init(const char *mod_dir)
{ {
char **files; char(*files)[STK_PATH_MAX] = NULL;
size_t file_count, i; size_t file_count, i;
char full_path[PATH_BUFFER_SIZE]; char full_path[STK_PATH_MAX_OS];
if (mod_dir) { if (mod_dir) {
strncpy(stk_mod_dir, mod_dir, MOD_DIR_BUFFER_SIZE - 1); strncpy(stk_mod_dir, mod_dir, STK_MOD_DIR_BUFFER - 1);
stk_mod_dir[MOD_DIR_BUFFER_SIZE - 1] = '\0'; stk_mod_dir[STK_MOD_DIR_BUFFER - 1] = '\0';
} else { } else {
strcpy(stk_mod_dir, "mods"); strcpy(stk_mod_dir, "mods");
} }
@@ -44,8 +54,7 @@ int stk_init(const char *mod_dir)
for (i = 0; i < file_count; ++i) { for (i = 0; i < file_count; ++i) {
sprintf(full_path, "%s/%s", stk_mod_dir, files[i]); sprintf(full_path, "%s/%s", stk_mod_dir, files[i]);
stk_module_load(full_path); stk_module_load_init(full_path, i);
free(files[i]);
} }
free(files); free(files);
@@ -72,34 +81,20 @@ void stk_shutdown(void)
size_t stk_poll(void) size_t stk_poll(void)
{ {
char **file_list = NULL; char(*file_list)[STK_PATH_MAX] = NULL;
stk_module_event_t *events = NULL; stk_module_event_t *events = NULL;
size_t file_count; size_t file_count, i;
size_t i;
events = platform_directory_watch_check(watch_handle, &file_list, events = platform_directory_watch_check(watch_handle, &file_list,
&file_count); &file_count, stk_module_ids,
module_count);
if (!events) if (!events)
return 0; return 0;
for (i = 0; i < file_count; ++i) { for (i = 0; i < file_count; ++i) {
char full_path[PATH_BUFFER_SIZE];
char *module_id;
int existing_index = -1;
size_t j = 0;
module_id = file_list[i];
sprintf(full_path, "%s/%s", stk_mod_dir, module_id);
for (j = 0; j < module_count; ++j) {
if (strcmp(module_id, stk_module_ids[j]) != 0)
continue;
existing_index = j;
break;
}
switch (events[i]) { switch (events[i]) {
case STK_MOD_RELOAD:
break;
case STK_MOD_LOAD: case STK_MOD_LOAD:
break; break;
case STK_MOD_UNLOAD: case STK_MOD_UNLOAD:
@@ -107,11 +102,8 @@ size_t stk_poll(void)
} }
} }
for (i = 0; i < file_count; i++)
free(file_list[i]);
free(file_list);
free(events); free(events);
free(file_list);
return file_count; return file_count;
} }