diff --git a/include/stk.h b/include/stk.h index 788b67f..46cba71 100644 --- a/include/stk.h +++ b/include/stk.h @@ -4,8 +4,10 @@ #include "stk_version.h" #include -#define MOD_DIR_BUFFER_SIZE 32 -#define PATH_BUFFER_SIZE 1024 +#define STK_MOD_DIR_BUFFER 256 +#define STK_MOD_ID_BUFFER 64 +#define STK_PATH_MAX 256 +#define STK_PATH_MAX_OS 4096 #ifdef __cplusplus extern "C" { diff --git a/src/module.c b/src/module.c index dcd4a4b..b0b59ab 100644 --- a/src/module.c +++ b/src/module.c @@ -8,39 +8,23 @@ void *platform_get_symbol(void *handle, const char *symbol); typedef void (*stk_module_func)(void); -char **stk_module_ids = NULL; -static void **stk_handles = NULL; -static stk_module_func *stk_inits = NULL; -static stk_module_func *stk_shutdowns = NULL; +char (*stk_module_ids)[STK_MOD_ID_BUFFER] = NULL; +void **stk_handles = NULL; +stk_module_func *stk_inits = NULL; +stk_module_func *stk_shutdowns = NULL; size_t module_count = 0; size_t stk_module_count(void) { return module_count; } -char *extract_module_id(const char *path) -{ - 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) +int stk_module_load(const char *path, int index) { void *handle; stk_module_func init_func; stk_module_func shutdown_func; + const char *basename; + char *dot; + char module_id[STK_MOD_ID_BUFFER]; handle = platform_load_library(path); if (!handle) @@ -56,32 +40,49 @@ int stk_module_load(const char *path) return -2; } - stk_module_ids[module_count] = extract_module_id(path); - stk_handles[module_count] = handle; - stk_inits[module_count] = init_func; - stk_shutdowns[module_count] = shutdown_func; + if (index == -1) + index = module_count; - 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; } +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) { - size_t i; - stk_shutdowns[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) @@ -99,12 +100,12 @@ void stk_module_free_memory(void) 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_inits = 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(); return -1; } diff --git a/src/platform.c b/src/platform.c index 9497b50..7ff5657 100644 --- a/src/platform.c +++ b/src/platform.c @@ -22,93 +22,104 @@ #include #endif -#define EVENT_BUFFER_SIZE 4096 +#if defined(__linux__) || defined(_WIN32) +#define STK_EVENT_BUFFER 4096 +#endif -#if !defined(_WIN32) -static char **scan_directory(const char *path, size_t *out_count) +#if defined(_WIN32) +#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; - struct dirent *entry; - struct stat file_stat; - char full_path[PATH_BUFFER_SIZE]; - char **file_list = NULL; - size_t count = 0, index = 0; + const char *ext; + size_t name_len; - dir = opendir(path); - if (!dir) { - mkdir(path, 0755); - *out_count = 0; - return NULL; - } + if (!filename) + return 0; - while ((entry = readdir(dir)) != NULL) { - sprintf(full_path, "%s/%s", path, entry->d_name); - if (stat(full_path, &file_stat) == 0 && - S_ISREG(file_stat.st_mode)) - count++; - } + name_len = strlen(filename); - if (count == 0) { - closedir(dir); - *out_count = 0; - return NULL; - } + if (name_len <= STK_MODULE_EXT_LEN) + return 0; - rewinddir(dir); - - 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; + ext = filename + (name_len - STK_MODULE_EXT_LEN); + return strcmp(ext, STK_MODULE_EXT) == 0; } +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 + 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) typedef struct { - char *filename; + char filename[STK_PATH_MAX]; time_t mtime; } file_snapshot_t; typedef struct { int kq; int dir_fd; - char path[PATH_BUFFER_SIZE]; + char path[STK_PATH_MAX]; file_snapshot_t *snapshots; size_t snapshot_count; + size_t snapshot_capacity; } 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; struct dirent *entry; struct stat file_stat; - char full_path[PATH_BUFFER_SIZE]; - file_snapshot_t *snapshots = NULL; - size_t count = 0, index = 0; + char work_path[STK_PATH_MAX_OS]; + file_snapshot_t *snapshots; + size_t count, capacity, index; + + snapshots = NULL; + count = 0; + capacity = 0; + index = 0; dir = opendir(path); if (!dir) { *out_count = 0; + *out_capacity = 0; 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 || strcmp(entry->d_name, "..") == 0) continue; - snprintf(full_path, sizeof(full_path), "%s/%s", path, - entry->d_name); - if (stat(full_path, &file_stat) == 0 && + + if (!is_valid_module_file(entry->d_name)) + continue; + + sprintf(work_path, "%s/%s", path, entry->d_name); + if (stat(work_path, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) count++; } @@ -126,13 +140,16 @@ static file_snapshot_t *create_snapshot(const char *path, size_t *out_count) if (count == 0) { closedir(dir); *out_count = 0; + *out_capacity = 0; return NULL; } - snapshots = malloc(count * sizeof(file_snapshot_t)); + capacity = count + 8; + snapshots = malloc(capacity * sizeof(file_snapshot_t)); if (!snapshots) { closedir(dir); *out_count = 0; + *out_capacity = 0; 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 || strcmp(entry->d_name, "..") == 0) continue; - snprintf(full_path, sizeof(full_path), "%s/%s", path, - entry->d_name); - if (stat(full_path, &file_stat) != 0 || + + if (!is_valid_module_file(entry->d_name)) + continue; + + sprintf(work_path, "%s/%s", path, entry->d_name); + if (stat(work_path, &file_stat) != 0 || !S_ISREG(file_stat.st_mode)) continue; - snapshots[index].filename = malloc(strlen(entry->d_name) + 1); - if (snapshots[index].filename) { - strcpy(snapshots[index].filename, entry->d_name); - snapshots[index].mtime = file_stat.st_mtime; - index++; - } + strncpy(snapshots[index].filename, entry->d_name, + STK_PATH_MAX - 1); + snapshots[index].filename[STK_PATH_MAX - 1] = '\0'; + snapshots[index].mtime = file_stat.st_mtime; + index++; } closedir(dir); *out_count = index; + *out_capacity = capacity; 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, size_t count, const char *filename) { size_t 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 NULL; } - #endif void *platform_load_library(const char *path) @@ -216,60 +225,50 @@ void *platform_directory_watch_start(const char *path) { #ifdef __linux__ int fd, wd; - fd = inotify_init1(IN_NONBLOCK); if (fd < 0) return NULL; - wd = inotify_add_watch( fd, path, IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_TO | IN_MOVED_FROM); - if (wd < 0) { close(fd); return NULL; } - return (void *)(long)fd; - #elif defined(_WIN32) HANDLE handle = CreateFileA(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - - if (handle == INVALID_HANDLE_VALUE) - return NULL; - - return (void *)handle; - + return (handle == INVALID_HANDLE_VALUE) ? NULL : (void *)handle; #else 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) return NULL; ctx->kq = kqueue(); ctx->dir_fd = open(path, O_RDONLY); - strncpy(ctx->path, path, PATH_BUFFER_SIZE - 1); - ctx->path[PATH_BUFFER_SIZE - 1] = '\0'; - - ctx->snapshots = create_snapshot(path, &ctx->snapshot_count); + strncpy(ctx->path, path, STK_PATH_MAX - 1); + ctx->path[STK_PATH_MAX - 1] = '\0'; + ctx->snapshots = create_snapshot(path, &ctx->snapshot_count, + &ctx->snapshot_capacity); if (ctx->kq < 0 || ctx->dir_fd < 0) { if (ctx->kq >= 0) close(ctx->kq); if (ctx->dir_fd >= 0) close(ctx->dir_fd); - free_snapshot(ctx->snapshots, ctx->snapshot_count); + free(ctx->snapshots); free(ctx); return NULL; } EV_SET(&event, ctx->dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_RENAME, 0, NULL); - kevent(ctx->kq, &event, 1, NULL, 0, NULL); - return (void *)ctx; #endif } @@ -277,43 +276,42 @@ void *platform_directory_watch_start(const char *path) void platform_directory_watch_stop(void *handle) { #ifdef __linux__ - if (!handle) - return; - close((int)(long)handle); - + if (handle) + close((int)(long)handle); #elif defined(_WIN32) - CloseHandle((HANDLE)handle); - + if (handle) + CloseHandle((HANDLE)handle); #else - kqueue_watch_context_t *ctx = (kqueue_watch_context_t *)handle; + kqueue_watch_context_t *ctx; + ctx = (kqueue_watch_context_t *)handle; if (!ctx) return; - if (ctx->dir_fd >= 0) close(ctx->dir_fd); if (ctx->kq >= 0) close(ctx->kq); - free_snapshot(ctx->snapshots, ctx->snapshot_count); + free(ctx->snapshots); free(ctx); #endif } -stk_module_event_t *platform_directory_watch_check(void *handle, - char ***file_list, - size_t *out_count) +stk_module_event_t *platform_directory_watch_check( + void *handle, char (**file_list)[STK_PATH_MAX], 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; stk_module_event_t *events = NULL; #ifdef __linux__ - char buffer[EVENT_BUFFER_SIZE]; + char buffer[STK_EVENT_BUFFER]; ssize_t bytes_read; struct inotify_event *event; 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)); if (bytes_read <= 0) { @@ -324,7 +322,7 @@ stk_module_event_t *platform_directory_watch_check(void *handle, event_ptr = buffer; while (event_ptr < buffer + bytes_read) { event = (struct inotify_event *)event_ptr; - if (event->len > 0) + if (event->len > 0 && is_valid_module_file(event->name)) file_count++; 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)); - *file_list = malloc(file_count * sizeof(char *)); - if (!events || !*file_list) { - free(events); - free(*file_list); - *out_count = 0; - return NULL; - } + *file_list = malloc(file_count * sizeof(**file_list)); index = 0; event_ptr = buffer; while (event_ptr < buffer + bytes_read) { event = (struct inotify_event *)event_ptr; - if (event->len > 0) { + if (event->len > 0 && is_valid_module_file(event->name)) { events[index] = (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; - (*file_list)[index] = malloc(strlen(event->name) + 1); - if ((*file_list)[index]) { - strcpy((*file_list)[index], event->name); - index++; - } + strncpy((*file_list)[index], event->name, + STK_PATH_MAX - 1); + (*file_list)[index][STK_PATH_MAX - 1] = '\0'; + index++; } event_ptr += sizeof(struct inotify_event) + event->len; } #elif defined(_WIN32) - HANDLE h = (HANDLE)handle; - BYTE buffer[EVENT_BUFFER_SIZE]; + HANDLE h; + BYTE buffer[STK_EVENT_BUFFER]; DWORD bytes_returned; FILE_NOTIFY_INFORMATION *info; 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, - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_LAST_WRITE, - &bytes_returned, NULL, NULL); + h = (HANDLE)handle; + file_count = 0; + + 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) { *out_count = 0; return NULL; @@ -380,7 +381,15 @@ stk_module_event_t *platform_directory_watch_check(void *handle, event_ptr = buffer; while (1) { 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) break; 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)); - *file_list = malloc(file_count * sizeof(char *)); - if (!events || !*file_list) { - free(events); - free(*file_list); - *out_count = 0; - return NULL; - } + *file_list = malloc(file_count * sizeof(**file_list)); index = 0; event_ptr = buffer; while (1) { info = (FILE_NOTIFY_INFORMATION *)event_ptr; - events[index] = (info->Action == FILE_ACTION_ADDED || - info->Action == FILE_ACTION_MODIFIED || - info->Action == FILE_ACTION_RENAMED_NEW_NAME) - ? STK_MOD_LOAD - : STK_MOD_UNLOAD; - char_count = WideCharToMultiByte( - CP_UTF8, 0, info->FileName, - info->FileNameLength / sizeof(WCHAR), NULL, 0, NULL, NULL); - - if (char_count > 0) { - (*file_list)[index] = malloc(char_count + 1); - if ((*file_list)[index]) { - WideCharToMultiByte(CP_UTF8, 0, info->FileName, - info->FileNameLength / - sizeof(WCHAR), - (*file_list)[index], - char_count, NULL, NULL); - (*file_list)[index][char_count] = '\0'; + len = WideCharToMultiByte(CP_UTF8, 0, info->FileName, + info->FileNameLength / sizeof(WCHAR), + (*file_list)[index], STK_PATH_MAX - 1, + NULL, NULL); + if (len > 0) { + (*file_list)[index][len] = '\0'; + if (is_valid_module_file((*file_list)[index])) { + events[index] = + (info->Action != FILE_ACTION_REMOVED && + info->Action != + FILE_ACTION_RENAMED_OLD_NAME) + ? (is_module_loaded((*file_list)[index], + loaded_module_ids, + loaded_count) + ? STK_MOD_RELOAD + : STK_MOD_LOAD) + : STK_MOD_UNLOAD; index++; } } - if (info->NextEntryOffset == 0) break; event_ptr += info->NextEntryOffset; } #else - kqueue_watch_context_t *ctx = (kqueue_watch_context_t *)handle; + kqueue_watch_context_t *ctx; struct kevent event; - struct timespec timeout = {0, 0}; - int nevents; - file_snapshot_t *new_snapshots, *old_snap, *new_snap; - size_t new_count, i; - size_t change_count = 0; + struct timespec timeout; + file_snapshot_t *new_snapshots, *old_snap; + size_t new_count, new_capacity, i, change_count; - nevents = kevent(ctx->kq, NULL, 0, &event, 1, &timeout); - if (nevents <= 0) { + ctx = (kqueue_watch_context_t *)handle; + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + change_count = 0; + + if (kevent(ctx->kq, NULL, 0, &event, 1, &timeout) <= 0) { *out_count = 0; 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++) { - new_snap = find_in_snapshot(new_snapshots, new_count, - ctx->snapshots[i].filename); - if (!new_snap) + for (i = 0; i < ctx->snapshot_count; i++) + if (!find_in_snapshot(new_snapshots, new_count, + ctx->snapshots[i].filename)) change_count++; - } for (i = 0; i < new_count; i++) { 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) { - free_snapshot(new_snapshots, new_count); + free(new_snapshots); *out_count = 0; return NULL; } events = malloc(change_count * sizeof(stk_module_event_t)); - *file_list = malloc(change_count * sizeof(char *)); - if (!events || !*file_list) { - free(events); - free(*file_list); - free_snapshot(new_snapshots, new_count); - *out_count = 0; - return NULL; - } + *file_list = malloc(change_count * sizeof(**file_list)); index = 0; + for (i = 0; i < ctx->snapshot_count && index < change_count; i++) { - new_snap = find_in_snapshot(new_snapshots, new_count, - ctx->snapshots[i].filename); - if (!new_snap) { + if (!find_in_snapshot(new_snapshots, new_count, + ctx->snapshots[i].filename)) { events[index] = STK_MOD_UNLOAD; - (*file_list)[index] = - malloc(strlen(ctx->snapshots[i].filename) + 1); - if ((*file_list)[index]) { - strcpy((*file_list)[index], - ctx->snapshots[i].filename); - index++; - } + strncpy((*file_list)[index], ctx->snapshots[i].filename, + STK_PATH_MAX - 1); + (*file_list)[index][STK_PATH_MAX - 1] = '\0'; + 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, new_snapshots[i].filename); if (!old_snap || old_snap->mtime != new_snapshots[i].mtime) { - events[index] = STK_MOD_LOAD; - (*file_list)[index] = - malloc(strlen(new_snapshots[i].filename) + 1); - if ((*file_list)[index]) { - strcpy((*file_list)[index], - new_snapshots[i].filename); - index++; - } + events[index] = + is_module_loaded(new_snapshots[i].filename, + loaded_module_ids, loaded_count) + ? STK_MOD_RELOAD + : STK_MOD_LOAD; + strncpy((*file_list)[index], new_snapshots[i].filename, + 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->snapshot_count = new_count; + ctx->snapshot_capacity = new_capacity; #endif *out_count = index; 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) WIN32_FIND_DATAW find_data; HANDLE find_handle; - WCHAR search_path[PATH_BUFFER_SIZE]; - char **file_list = NULL; - size_t count = 0, index = 0; - int utf8_len; - - swprintf(search_path, PATH_BUFFER_SIZE, L"%S\\*", path); + WCHAR search_path[STK_PATH_MAX_OS]; + char temp_filename[STK_PATH_MAX]; + int len; + swprintf(search_path, STK_PATH_MAX_OS, L"%S\\*", mod_dir); find_handle = FindFirstFileW(search_path, &find_data); + if (find_handle == INVALID_HANDLE_VALUE) { - CreateDirectoryA(path, NULL); + CreateDirectoryA(mod_dir, NULL); *out_count = 0; return NULL; } do { - if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - count++; - } while (FindNextFileW(find_handle, &find_data)); + if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + 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); 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); - if (find_handle == INVALID_HANDLE_VALUE) { - *out_count = 0; - return NULL; - } - - file_list = (char **)malloc(count * sizeof(char *)); - if (!file_list) { - FindClose(find_handle); - *out_count = 0; - return NULL; - } + file_list = malloc(count * sizeof(*file_list)); do { - if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && - index < count) { - utf8_len = - WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, - -1, NULL, 0, NULL, NULL); - if (utf8_len > 0) { - file_list[index] = (char *)malloc(utf8_len); - if (file_list[index]) { - WideCharToMultiByte( - CP_UTF8, 0, find_data.cFileName, -1, - file_list[index], utf8_len, NULL, - NULL); - index++; - } - } + if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + len = WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, -1, + file_list[index], STK_PATH_MAX - 1, + NULL, NULL); + if (len > 0 && index < count) { + file_list[index][len] = '\0'; + if (is_valid_module_file(file_list[index])) + index++; } } while (FindNextFileW(find_handle, &find_data) && index < count); - 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; return file_list; -#else - return scan_directory(path, out_count); -#endif } diff --git a/src/stk.c b/src/stk.c index d902ec1..c9795ae 100644 --- a/src/stk.c +++ b/src/stk.c @@ -1,35 +1,45 @@ #include "stk.h" #include "stk_log.h" #include +#include #include -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; -static char stk_mod_dir[MOD_DIR_BUFFER_SIZE]; +static char stk_mod_dir[STK_MOD_DIR_BUFFER]; 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_stop(void *handle); 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_all(void); int stk_module_init_memory(size_t capacity); -stk_module_event_t *platform_directory_watch_check(void *handle, - char ***file_list, - size_t *out_count); +stk_module_event_t *platform_directory_watch_check( + void *handle, char (**file_list)[STK_PATH_MAX], size_t *out_count, + char (*loaded_module_ids)[STK_MOD_ID_BUFFER], const size_t loaded_count); int stk_init(const char *mod_dir) { - char **files; + char(*files)[STK_PATH_MAX] = NULL; size_t file_count, i; - char full_path[PATH_BUFFER_SIZE]; + char full_path[STK_PATH_MAX_OS]; if (mod_dir) { - strncpy(stk_mod_dir, mod_dir, MOD_DIR_BUFFER_SIZE - 1); - stk_mod_dir[MOD_DIR_BUFFER_SIZE - 1] = '\0'; + strncpy(stk_mod_dir, mod_dir, STK_MOD_DIR_BUFFER - 1); + stk_mod_dir[STK_MOD_DIR_BUFFER - 1] = '\0'; } else { strcpy(stk_mod_dir, "mods"); } @@ -44,8 +54,7 @@ int stk_init(const char *mod_dir) for (i = 0; i < file_count; ++i) { sprintf(full_path, "%s/%s", stk_mod_dir, files[i]); - stk_module_load(full_path); - free(files[i]); + stk_module_load_init(full_path, i); } free(files); @@ -72,34 +81,20 @@ void stk_shutdown(void) size_t stk_poll(void) { - char **file_list = NULL; + char(*file_list)[STK_PATH_MAX] = NULL; stk_module_event_t *events = NULL; - size_t file_count; - size_t i; + size_t file_count, i; events = platform_directory_watch_check(watch_handle, &file_list, - &file_count); + &file_count, stk_module_ids, + module_count); if (!events) return 0; 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]) { + case STK_MOD_RELOAD: + break; case STK_MOD_LOAD: break; 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(file_list); return file_count; }