10 Commits

Author SHA1 Message Date
anth64 345cd35f19 chore: bump version to 0.1.2 2026-02-15 23:05:18 +01:00
anth64 c2b9571c2d fix(platform,core,test): fix Windows compatibility issues
- platform_mkdir now checks if directory exists before creating
- Add FILE_ATTRIBUTE_HIDDEN for dot-prefixed directories on Windows
- Create parent mods directory before temp directory
- Move module unload before copy in reload sequence to fix issue on Windows
- Force CMD shell in test makefile on Windows

Test makefile now uses cmd.exe instead of bash on Windows, fixing
syntax errors when running via build.bat.
2026-02-15 22:53:12 +01:00
anth64 3f7f216c92 chore: bump version to 0.1.1 and update documentation 2026-02-14 17:25:20 +01:00
anth64 70d50dda92 fix(logging): correct log level severity order
Reverse enum so lower values = less severe, higher = more severe.
This makes the filter check (level < min_log_level) work correctly.

- DEBUG (0) - least severe, filtered by default
- INFO (1) - default minimum level
- WARN (2) - warnings and above
- ERROR (3) - most severe, always shown

Fixes incorrect filtering where ERROR/WARN were being blocked.
2026-02-14 17:22:39 +01:00
anth64 70e9ec2fc3 chore: bump version to 0.1.0 and update documentation
- Update stk_version.h: 0.0.4 → 0.1.0
- Add CHANGELOG entry for 0.1.0 release
  - C89 compliance fixes
  - Flags bitfield system
  - Enhanced logging system
- Update README project status and API reference
- Document new logging functions and configuration
2026-02-14 17:06:50 +01:00
anth64 110b7ffca8 feat(logging)!: add enhanced logging system
BREAKING CHANGE: stk_log() signature changed to require log level

- Add log levels (ERROR, WARN, INFO, DEBUG) with runtime filtering
- Add timestamps (yyyy-mm-dd HH:MM:SS.mmm format)
- Add stk_set_log_output(), stk_set_log_prefix(), stk_set_log_level()
- Platform-specific timestamp: GetLocalTime (Windows), gettimeofday (POSIX)
- Consolidate duplicate platform includes into POSIX common block
- Setting log output to NULL disables logging.

Default: INFO level, "stk" prefix, stdout output. All internal messages
use appropriate severity levels. Single byte flag controls enable/disable.
2026-02-14 16:59:56 +01:00
anth64 26fb19a7f5 feat(core): add flags bitfield system
- Replace stk_initialized with stk_flags bitfield
- Add STK_FLAG_INITIALIZED (0x01) and STK_FLAG_LOGGING_ENABLED (0x02)
- Add stk_set_logging_enabled() and stk_is_logging_enabled() API
- Single byte for all boolean state and settings

Logging enabled by default, packs all flags into one byte for efficiency.
2026-02-14 12:39:13 +01:00
anth64 bcb1795218 fix(core)!: enforce strict C89 compliance
BREAKING CHANGE: Public API now uses unsigned char instead of uint8_t

- Remove stdint.h dependency (C99 feature, not C89, I am a fucking idiot)
- Replace uint8_t with unsigned char throughout codebase
- Affects stk_init() return type and internal functions
- Corrects unintended C99 dependency, restoring intended C89 compliance
2026-02-14 11:41:41 +01:00
anth64 fb0d8adb8f chore: bump version to 0.0.4 2026-02-11 00:22:59 +01:00
anth64 2c4d27f915 fix(linux): prevent segfault from invalid module indices during rapid reloads
When spamming file changes rapidly, inotify can report stale UNLOAD/RELOAD
events for modules that were already unloaded by previous events in the same
poll cycle. This caused is_mod_loaded() to return -1, which was then cast to
size_t (18446744073709551615) and used as an array index, causing segfaults.

Additionally, event counts were calculated before validation, causing loops to
run more iterations than valid indices were populated, reading garbage values.

Changes:
- stk.c: Check if is_mod_loaded() returns valid index (>= 0) before adding
  to unload/reload lists
- stk.c: Reset and recalculate counts after populating arrays with only valid
  indices to prevent loop overrun
- Skip processing events for modules that are no longer loaded

This completes the Linux stability fixes started in v0.0.2.
2026-02-11 00:17:33 +01:00
11 changed files with 316 additions and 86 deletions
+66 -1
View File
@@ -7,6 +7,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.1.2] - 2026-02-15
### Fixed
- **Windows**
- Module reload now works correctly, idk how it was broken
- Temp directory creation fixed
- `.tmp` directory now hidden via FILE_ATTRIBUTE_HIDDEN
- Test build fixed
- Force cmd.exe shell in gmake.mk
- Fix bash syntax errors when running build.bat
- **All Platforms**: platform_mkdir now checks if directory exists before creating
## [0.1.1] - 2026-02-14
### Fixed
- **Logging**: Corrected log level severity order in enum
- Reversed order so DEBUG (0) < INFO (1) < WARN (2) < ERROR (3)
- Fixes filtering logic where ERROR/WARN were incorrectly blocked
- Default INFO level now properly shows INFO, WARN, and ERROR while filtering DEBUG
## [0.1.0] - 2026-02-14
### Fixed
- **C89 Compliance**: Removed stdint.h dependency (C99 feature)
- Replaced all uint8_t with unsigned char throughout codebase
- Ensures strict C89 compliance for maximum portability
### Added
- **Flags system**: Centralized bitfield for boolean state and settings
- Replaces stk_initialized with stk_flags for efficient memory usage
- Single byte packs all boolean flags (STK_FLAG_INITIALIZED, STK_FLAG_LOGGING_ENABLED)
- Runtime-changeable logging control via stk_set_logging_enabled()
- **Enhanced logging system**: Complete rewrite with modern features
- Log levels: ERROR, WARN, INFO, DEBUG with runtime filtering
- Timestamps: yyyy-mm-dd HH:MM:SS.mmm format (platform-specific implementation)
- Configurable log output stream (stk_set_log_output)
- Configurable log prefix (stk_set_log_prefix, defaults to "stk")
- Configurable minimum log level (stk_set_log_level, defaults to INFO)
- Platform abstraction for timestamps (GetLocalTime on Windows, gettimeofday on POSIX)
### Changed
- **BREAKING**: stk_log() signature changed from stk_log(FILE *fp, ...) to stk_log(stk_log_level_t level, ...)
- **BREAKING**: All uint8_t types replaced with unsigned char
- All internal STK messages now use appropriate log levels
- Setting log output to NULL disabls logging
### Notes
- This release completes Phase 1 logging improvements
- Dependency management still in progress for Phase 1 completion
## [0.0.4] - 2026-02-11
### Fixed
- **Linux**: Fixed segfault from invalid module indices during extremely rapid file changes
- Added validation check to skip stale UNLOAD/RELOAD events for already-unloaded modules
- Prevents is_mod_loaded() returning -1 from being used as array index (SIZE_MAX)
- Fixed event count mismatch where loops would run more iterations than valid indices populated
- Completes the Linux hot-reload stability fixes from v0.0.2
## [0.0.3] - 2026-02-10
### Fixed
@@ -44,7 +104,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dependency management and versioning not yet implemented
- API is unstable and subject to change in future releases
[Unreleased]: https://github.com/anth64/stk/compare/v0.0.3...HEAD
[Unreleased]: https://github.com/anth64/stk/compare/v0.1.2...HEAD
[0.1.2]: https://github.com/anth64/stk/releases/tag/v0.1.2
[0.1.1]: https://github.com/anth64/stk/releases/tag/v0.1.1
[0.1.1]: https://github.com/anth64/stk/releases/tag/v0.1.1
[0.1.0]: https://github.com/anth64/stk/releases/tag/v0.1.0
[0.0.4]: https://github.com/anth64/stk/releases/tag/v0.0.4
[0.0.3]: https://github.com/anth64/stk/releases/tag/v0.0.3
[0.0.2]: https://github.com/anth64/stk/releases/tag/v0.0.2
[0.0.1]: https://github.com/anth64/stk/releases/tag/v0.0.1
+15 -6
View File
@@ -156,7 +156,7 @@ stk_init();
### API Reference
#### Initialization
- `uint8_t stk_init(void)` - Initialize stk, returns `STK_INIT_SUCCESS` on success
- `unsigned char stk_init(void)` - Initialize stk, returns `STK_INIT_SUCCESS` on success
- `void stk_shutdown(void)` - Shutdown and cleanup all modules
#### Runtime
@@ -169,22 +169,31 @@ stk_init();
- `void stk_set_module_init_fn(const char *name)` - Set module init function name
- `void stk_set_module_shutdown_fn(const char *name)` - Set module shutdown function name
#### Logging
- `void stk_set_logging_enabled(unsigned char enabled)` - Enable/disable all logging
- `unsigned char stk_is_logging_enabled(void)` - Query logging state
- `void stk_set_log_output(FILE *fp)` - Set log output stream (default: stdout, NULL disables)
- `void stk_set_log_prefix(const char *prefix)` - Set log prefix (default: "stk")
- `void stk_set_log_level(stk_log_level_t level)` - Set minimum log level (default: INFO)
**Log Levels:** `STK_LOG_ERROR`, `STK_LOG_WARN`, `STK_LOG_INFO`, `STK_LOG_DEBUG`
---
## Project Status
**Current Version:** 0.0.3 (Pre-release)
**Current Version:** 0.1.2 (Pre-release)
This is an early bugfix release improving compilation warnings on Linux. Phase 1 is still in progress.
Fixed Windows compatibility issues.
### What Works
- Cross-platform module loading and hot-reloading
- File watching (inotify/kqueue/FindFirstFile)
- Basic error handling
- Stable hot-reload even during rapid file changes
- Robust hot-reload even during extremely rapid file changes
- Enhanced logging with levels, timestamps, and filtering
- Runtime-configurable logging behavior
### In Progress (Phase 1)
- Complete logging system (log levels, verbosity, output configuration)
- Module metadata (name, version, description)
- Dependency management and versioning
+8 -2
View File
@@ -2,10 +2,10 @@
#define STK_H
#include "stk_version.h"
#include <stdint.h>
#include <stdlib.h>
/* Buffers */
#define STK_LOG_PREFIX_BUFFER 64
#define STK_MOD_DIR_BUFFER 256
#define STK_MOD_ID_BUFFER 64
#define STK_PATH_MAX 256
@@ -31,6 +31,10 @@
#define STK_PLATFORM_REMOVE_DIR_ERROR 3
#define STK_PLATFORM_REMOVE_FILE_ERROR 4
/* Settings flags */
#define STK_FLAG_INITIALIZED 0x01
#define STK_FLAG_LOGGING_ENABLED 0x02
#if defined(__linux__) || defined(_WIN32)
#define STK_EVENT_BUFFER 4096
#endif
@@ -55,7 +59,7 @@ typedef enum {
STK_MOD_RELOAD
} stk_module_event_t;
uint8_t stk_init(void);
unsigned char stk_init(void);
void stk_shutdown(void);
size_t stk_module_count(void);
size_t stk_poll(void);
@@ -63,6 +67,8 @@ void stk_set_mod_dir(const char *path);
void stk_set_tmp_dir_name(const char *name);
void stk_set_module_init_fn(const char *name);
void stk_set_module_shutdown_fn(const char *name);
void stk_set_logging_enabled(unsigned char enabled);
unsigned char stk_is_logging_enabled(void);
#ifdef __cplusplus
}
+12 -1
View File
@@ -7,7 +7,18 @@
extern "C" {
#endif
void stk_log(FILE *fp, const char *fmt, ...);
typedef enum {
STK_LOG_DEBUG,
STK_LOG_INFO,
STK_LOG_WARN,
STK_LOG_ERROR
} stk_log_level_t;
void stk_set_log_output(FILE *fp);
void stk_set_log_prefix(const char *prefix);
void stk_set_log_level(stk_log_level_t min_level);
void stk_log(stk_log_level_t level, const char *fmt, ...);
#ifdef __cplusplus
}
+2 -2
View File
@@ -2,8 +2,8 @@
#define STK_VERSION_H
#define STK_VERSION_MAJOR 0
#define STK_VERSION_MINOR 0
#define STK_VERSION_PATCH 3
#define STK_VERSION_MINOR 1
#define STK_VERSION_PATCH 2
#define STK_STRINGIFY_HELPER(x) #x
#define STK_STRINGIFY(x) STK_STRINGIFY_HELPER(x)
+8 -9
View File
@@ -1,6 +1,5 @@
#include "platform.h"
#include "stk.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -18,7 +17,7 @@ void **stk_handles = NULL;
stk_init_mod_func *stk_inits = NULL;
stk_shutdown_mod_func *stk_shutdowns = NULL;
extern uint8_t stk_initialized;
extern unsigned char stk_flags;
static char stk_mod_init_name[STK_MOD_FUNC_NAME_BUFFER] = "stk_mod_init";
static char stk_mod_shutdown_name[STK_MOD_FUNC_NAME_BUFFER] =
@@ -43,7 +42,7 @@ void extract_module_id(const char *path, char *out_id)
*dot = '\0';
}
uint8_t is_valid_module_file(const char *filename)
unsigned char is_valid_module_file(const char *filename)
{
const char *ext;
size_t name_len;
@@ -72,7 +71,7 @@ int is_mod_loaded(const char *module_name)
return -1;
}
uint8_t stk_module_load(const char *path, int index)
unsigned char stk_module_load(const char *path, int index)
{
void *handle;
stk_init_mod_func init_func;
@@ -121,7 +120,7 @@ uint8_t stk_module_load(const char *path, int index)
return STK_MOD_INIT_SUCCESS;
}
uint8_t stk_module_load_init(const char *path, int index)
unsigned char stk_module_load_init(const char *path, int index)
{
int result;
result = stk_module_load(path, index);
@@ -155,7 +154,7 @@ void stk_module_free_memory(void)
stk_shutdowns = NULL;
}
uint8_t stk_module_init_memory(size_t capacity)
unsigned char stk_module_init_memory(size_t capacity)
{
stk_module_ids = malloc(capacity * sizeof(*stk_module_ids));
stk_handles = malloc(capacity * sizeof(void *));
@@ -170,7 +169,7 @@ uint8_t stk_module_init_memory(size_t capacity)
return STK_INIT_SUCCESS;
}
uint8_t stk_module_realloc_memory(size_t new_capacity)
unsigned char stk_module_realloc_memory(size_t new_capacity)
{
char (*new_module_ids)[STK_MOD_ID_BUFFER] = NULL;
void **new_handles = NULL;
@@ -254,7 +253,7 @@ void stk_module_unload_all(void)
void stk_set_module_init_fn(const char *name)
{
if (!name || stk_initialized)
if (!name || (stk_flags & STK_FLAG_INITIALIZED))
return;
strncpy(stk_mod_init_name, name, STK_MOD_FUNC_NAME_BUFFER - 1);
@@ -263,7 +262,7 @@ void stk_set_module_init_fn(const char *name)
void stk_set_module_shutdown_fn(const char *name)
{
if (!name || stk_initialized)
if (!name || (stk_flags & STK_FLAG_INITIALIZED))
return;
strncpy(stk_mod_shutdown_name, name, STK_MOD_FUNC_NAME_BUFFER - 1);
+55 -17
View File
@@ -1,38 +1,34 @@
#include "stk.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <dirent.h>
#include <dlfcn.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#endif
#if defined(__linux__)
#include <dirent.h>
#include <dlfcn.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <unistd.h>
#elif defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif
int is_mod_loaded(const char *module_name);
uint8_t is_valid_module_file(const char *filename);
unsigned char is_valid_module_file(const char *filename);
void extract_module_id(const char *path, char *out_id);
static uint8_t is_file_ready(const char *dir_path, const char *filename)
static unsigned char is_file_ready(const char *dir_path, const char *filename)
{
char full_path[STK_PATH_MAX_OS];
#ifdef _WIN32
@@ -108,12 +104,32 @@ typedef struct {
} platform_watch_context_t;
#endif
uint8_t platform_mkdir(const char *path)
unsigned char platform_mkdir(const char *path)
{
#ifdef _WIN32
return CreateDirectoryA(path, NULL) ? STK_PLATFORM_OPERATION_SUCCESS
: STK_PLATFORM_MKDIR_ERROR;
DWORD attrib;
attrib = GetFileAttributesA(path);
if (attrib != INVALID_FILE_ATTRIBUTES &&
(attrib & FILE_ATTRIBUTE_DIRECTORY))
return STK_PLATFORM_OPERATION_SUCCESS;
if (!CreateDirectoryA(path, NULL))
return STK_PLATFORM_MKDIR_ERROR;
if (strrchr(path, '\\') && *(strrchr(path, '\\') + 1) == '.')
SetFileAttributesA(path, FILE_ATTRIBUTE_HIDDEN);
else if (!strrchr(path, '\\') && path[0] == '.')
SetFileAttributesA(path, FILE_ATTRIBUTE_HIDDEN);
return STK_PLATFORM_OPERATION_SUCCESS;
#else
struct stat st;
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
return STK_PLATFORM_OPERATION_SUCCESS;
return mkdir(path, 0755) == 0 ? STK_PLATFORM_OPERATION_SUCCESS
: STK_PLATFORM_MKDIR_ERROR;
#endif
@@ -130,7 +146,7 @@ int platform_remove_file(const char *path)
#endif
}
uint8_t platform_copy_file(const char *from, const char *to)
unsigned char platform_copy_file(const char *from, const char *to)
{
char buf[STK_PATH_MAX_OS];
int ret = STK_PLATFORM_FILE_COPY_ERROR;
@@ -203,7 +219,7 @@ done:
return ret;
}
uint8_t platform_remove_dir(const char *path)
unsigned char platform_remove_dir(const char *path)
{
#ifdef _WIN32
WIN32_FIND_DATAA fd;
@@ -1010,3 +1026,25 @@ no_change:
return NULL;
#endif
}
void platform_get_timestamp(char *buffer, size_t size)
{
#ifdef _WIN32
SYSTEMTIME st;
GetLocalTime(&st);
sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d.%03d", st.wYear,
st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
st.wMilliseconds);
#else
struct timeval tv;
struct tm *tm_info;
gettimeofday(&tv, NULL);
tm_info = localtime(&tv.tv_sec);
sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec,
(int)(tv.tv_usec / 1000));
#endif
}
+66 -39
View File
@@ -1,7 +1,6 @@
#include "stk.h"
#include "platform.h"
#include "stk_log.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -16,11 +15,11 @@ extern char (*stk_module_ids)[STK_MOD_ID_BUFFER];
extern size_t module_count;
uint8_t stk_initialized = 0;
unsigned char stk_flags = STK_FLAG_LOGGING_ENABLED;
static char stk_mod_dir[STK_PATH_MAX_OS] = "mods";
static char stk_tmp_name[STK_MOD_ID_BUFFER] = ".tmp";
static char stk_tmp_dir[STK_PATH_MAX_OS] = "mods/.tmp";
static char stk_tmp_dir[STK_PATH_MAX_OS] = "";
static void *watch_handle = NULL;
char (*platform_directory_init_scan(const char *path,
@@ -30,18 +29,18 @@ void platform_directory_watch_stop(void *handle);
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);
uint8_t platform_mkdir(const char *path);
uint8_t platform_copy_file(const char *from, const char *to);
uint8_t platform_remove_dir(const char *path);
unsigned char platform_mkdir(const char *path);
unsigned char platform_copy_file(const char *from, const char *to);
unsigned char platform_remove_dir(const char *path);
void extract_module_id(const char *path, char *out_id);
int is_mod_loaded(const char *module_id);
size_t stk_module_count(void);
uint8_t stk_module_load(const char *path, int index);
uint8_t stk_module_load_init(const char *path, int index);
uint8_t stk_module_init_memory(size_t capacity);
uint8_t stk_module_realloc_memory(size_t new_capacity);
unsigned char stk_module_load(const char *path, int index);
unsigned char stk_module_load_init(const char *path, int index);
unsigned char stk_module_init_memory(size_t capacity);
unsigned char stk_module_realloc_memory(size_t new_capacity);
void stk_module_unload(size_t index);
void stk_module_unload_all(void);
@@ -70,7 +69,7 @@ static const char *stk_error_string(int error_code)
}
}
uint8_t stk_init(void)
unsigned char stk_init(void)
{
char (*files)[STK_PATH_MAX] = NULL;
size_t file_count, i, successful_loads = 0;
@@ -78,6 +77,8 @@ uint8_t stk_init(void)
char tmp_path[STK_PATH_MAX_OS];
int load_result;
platform_mkdir(stk_mod_dir);
build_path(stk_tmp_dir, sizeof(stk_tmp_dir), stk_mod_dir, stk_tmp_name);
if (platform_mkdir(stk_tmp_dir) != STK_PLATFORM_OPERATION_SUCCESS) {
char (*test_scan)[STK_PATH_MAX];
size_t test_count;
@@ -87,7 +88,7 @@ uint8_t stk_init(void)
if (test_scan)
free(test_scan);
if (!test_scan && test_count == 0) {
stk_log(stderr,
stk_log(STK_LOG_ERROR,
"FATAL: Cannot create temp directory: %s",
stk_tmp_dir);
return STK_INIT_TMPDIR_ERROR;
@@ -97,7 +98,7 @@ uint8_t stk_init(void)
files = platform_directory_init_scan(stk_mod_dir, &file_count);
if (file_count > 0 && stk_module_init_memory(file_count) != 0) {
stk_log(stderr, "FATAL: Memory allocation failed");
stk_log(STK_LOG_ERROR, "FATAL: Memory allocation failed");
return STK_INIT_MEMORY_ERROR;
}
@@ -110,7 +111,8 @@ uint8_t stk_init(void)
if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) {
stk_log(stderr, "Failed to copy %s to temp directory",
stk_log(STK_LOG_ERROR,
"Failed to copy %s to temp directory",
files[i]);
continue;
}
@@ -118,7 +120,7 @@ uint8_t stk_init(void)
load_result = stk_module_load_init(tmp_path, successful_loads);
if (load_result != STK_MOD_INIT_SUCCESS) {
stk_log(stderr, "Failed to load module %s: %s",
stk_log(STK_LOG_ERROR, "Failed to load module %s: %s",
files[i], stk_error_string(load_result));
} else {
successful_loads++;
@@ -134,17 +136,18 @@ uint8_t stk_init(void)
scanned:
watch_handle = platform_directory_watch_start(stk_mod_dir);
if (!watch_handle) {
stk_log(stderr, "FATAL: Cannot start directory watch on %s",
stk_log(STK_LOG_ERROR,
"FATAL: Cannot start directory watch on %s",
stk_mod_dir);
stk_module_unload_all();
return STK_INIT_WATCH_ERROR;
}
stk_log(stdout, "stk v%s initialized! Loaded %lu mod%s from %s/",
stk_log(STK_LOG_INFO, "stk v%s initialized! Loaded %lu mod%s from %s/",
STK_VERSION_STRING, module_count, module_count != 1 ? "s" : "",
stk_mod_dir);
stk_initialized = 1;
stk_flags |= STK_FLAG_INITIALIZED;
return STK_INIT_SUCCESS;
}
@@ -159,12 +162,13 @@ void stk_shutdown(void)
if (platform_remove_dir(stk_tmp_dir) !=
STK_PLATFORM_OPERATION_SUCCESS) {
stk_log(stderr, "Warning: failed to remove temp directory %s",
stk_log(STK_LOG_WARN,
"Warning: failed to remove temp directory %s",
stk_tmp_dir);
}
stk_initialized = 0;
stk_log(stdout, "stk shutdown");
stk_flags &= ~STK_FLAG_INITIALIZED;
stk_log(STK_LOG_INFO, "stk shutdown");
}
size_t stk_poll(void)
@@ -172,8 +176,7 @@ size_t stk_poll(void)
char (*file_list)[STK_PATH_MAX] = NULL;
stk_module_event_t *events = NULL;
size_t i, file_count = 0, reload_count = 0, load_count = 0,
unload_count = 0, reload_index = 0, load_index = 0,
unload_index = 0;
unload_count = 0;
int *reloaded_mod_indices = NULL, *reloaded_mod_file_indices = NULL,
*unloaded_mod_indices = NULL, *loaded_mod_indices = NULL;
size_t remaining_loads, new_capacity, holes_to_fill;
@@ -208,20 +211,31 @@ size_t stk_poll(void)
unloaded_mod_indices = malloc(unload_count * sizeof(int));
loaded_mod_indices = malloc(load_count * sizeof(int));
reload_count = 0;
unload_count = 0;
load_count = 0;
for (i = 0; i < file_count; ++i) {
int mod_index;
extract_module_id(file_list[i], mod_id);
switch (events[i]) {
case STK_MOD_LOAD:
loaded_mod_indices[load_index++] = i;
loaded_mod_indices[load_count++] = i;
break;
case STK_MOD_RELOAD:
reloaded_mod_file_indices[reload_index] = i;
reloaded_mod_indices[reload_index++] =
is_mod_loaded(mod_id);
mod_index = is_mod_loaded(mod_id);
if (mod_index >= 0) {
reloaded_mod_file_indices[reload_count] = i;
reloaded_mod_indices[reload_count] = mod_index;
reload_count++;
}
break;
case STK_MOD_UNLOAD:
unloaded_mod_indices[unload_index++] =
is_mod_loaded(mod_id);
mod_index = is_mod_loaded(mod_id);
if (mod_index >= 0) {
unloaded_mod_indices[unload_count] = mod_index;
unload_count++;
}
break;
}
}
@@ -251,18 +265,18 @@ begin_operations:
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
file_list[file_index]);
stk_module_unload(mod_index);
if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) {
stk_log(stderr, "Failed to copy %s for reload",
stk_log(STK_LOG_ERROR, "Failed to copy %s for reload",
file_list[file_index]);
continue;
}
stk_module_unload(mod_index);
load_result = stk_module_load(tmp_path, mod_index);
if (load_result != STK_MOD_INIT_SUCCESS) {
stk_log(stderr, "Failed to reload module %s: %s",
stk_log(STK_LOG_ERROR, "Failed to reload module %s: %s",
file_list[file_index],
stk_error_string(load_result));
}
@@ -280,14 +294,14 @@ begin_operations:
if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) {
stk_log(stderr, "Failed to copy %s for loading",
stk_log(STK_LOG_ERROR, "Failed to copy %s for loading",
file_list[file_index]);
continue;
}
load_result = stk_module_load(tmp_path, target_index);
if (load_result != STK_MOD_INIT_SUCCESS) {
stk_log(stderr, "Failed to load module %s: %s",
stk_log(STK_LOG_ERROR, "Failed to load module %s: %s",
file_list[file_index],
stk_error_string(load_result));
}
@@ -312,7 +326,7 @@ append_modules:
if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) {
stk_log(stderr, "Failed to copy %s for loading",
stk_log(STK_LOG_ERROR, "Failed to copy %s for loading",
file_list[file_index]);
continue;
}
@@ -320,7 +334,7 @@ append_modules:
load_result = stk_module_load(tmp_path, module_count +
successful_appends);
if (load_result != STK_MOD_INIT_SUCCESS) {
stk_log(stderr, "Failed to load module %s: %s",
stk_log(STK_LOG_ERROR, "Failed to load module %s: %s",
file_list[file_index],
stk_error_string(load_result));
} else {
@@ -371,7 +385,7 @@ finish_poll:
void stk_set_mod_dir(const char *path)
{
if (!path || stk_initialized)
if (!path || (stk_flags & STK_FLAG_INITIALIZED))
return;
strncpy(stk_mod_dir, path, STK_PATH_MAX_OS - 1);
@@ -389,7 +403,7 @@ void stk_set_mod_dir(const char *path)
void stk_set_tmp_dir_name(const char *name)
{
if (!name || stk_initialized)
if (!name || (stk_flags & STK_FLAG_INITIALIZED))
return;
strncpy(stk_tmp_name, name, STK_MOD_ID_BUFFER - 1);
@@ -402,3 +416,16 @@ void stk_set_tmp_dir_name(const char *name)
strncat(stk_tmp_dir, stk_tmp_name,
STK_PATH_MAX_OS - strlen(stk_tmp_dir) - 1);
}
void stk_set_logging_enabled(unsigned char enabled)
{
if (enabled)
stk_flags |= STK_FLAG_LOGGING_ENABLED;
else
stk_flags &= ~STK_FLAG_LOGGING_ENABLED;
}
unsigned char stk_is_logging_enabled(void)
{
return (stk_flags & STK_FLAG_LOGGING_ENABLED) != 0;
}
+77 -5
View File
@@ -1,14 +1,86 @@
#include "stk_log.h"
#include "stk.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
void stk_log(FILE *fp, const char *fmt, ...)
#define STK_LOG_TIMESTAMP_BUFFER 32
extern unsigned char stk_flags;
void platform_get_timestamp(char *buffer, size_t size);
static FILE *log_output = NULL;
static char log_prefix[STK_LOG_PREFIX_BUFFER] = "stk";
static stk_log_level_t min_log_level = STK_LOG_INFO;
static const char *get_level_string(stk_log_level_t level)
{
va_list args;
va_start(args, fmt);
char *level_str = "";
switch (level) {
case STK_LOG_ERROR:
level_str = "ERROR";
break;
case STK_LOG_WARN:
level_str = "WARN";
break;
case STK_LOG_INFO:
level_str = "INFO";
break;
case STK_LOG_DEBUG:
level_str = "DEBUG";
break;
}
vfprintf(fp, fmt, args);
fputc('\n', fp);
return level_str;
}
void stk_set_log_output(FILE *fp)
{
if (fp == NULL)
stk_flags &= ~STK_FLAG_LOGGING_ENABLED;
log_output = fp;
}
void stk_set_log_prefix(const char *prefix)
{
if (!prefix) {
log_prefix[0] = '\0';
return;
}
strncpy(log_prefix, prefix, STK_LOG_PREFIX_BUFFER - 1);
log_prefix[STK_LOG_PREFIX_BUFFER - 1] = '\0';
}
void stk_set_log_level(stk_log_level_t level) { min_log_level = level; }
void stk_log(stk_log_level_t level, const char *fmt, ...)
{
FILE *output;
const char *level_str;
char timestamp[STK_LOG_TIMESTAMP_BUFFER];
va_list args;
if (!(stk_flags & STK_FLAG_LOGGING_ENABLED))
return;
if (level < min_log_level)
return;
output = log_output ? log_output : stdout;
level_str = get_level_string(level);
platform_get_timestamp(timestamp, sizeof(timestamp));
if (log_prefix[0] != '\0')
fprintf(output, "%s [%s] [%s] ", timestamp, log_prefix,
level_str);
else
fprintf(output, "%s [%s] ", timestamp, level_str);
va_start(args, fmt);
vfprintf(output, fmt, args);
va_end(args);
fputc('\n', output);
}
+2
View File
@@ -3,6 +3,8 @@ CFLAGS = -Wall -Wpedantic -I../include -std=c89
LDFLAGS = -L../bin/debug -lstk
ifeq ($(OS),Windows_NT)
SHELL := cmd.exe
.SHELLFLAGS := /c
MODULE_EXT = .dll
EXE_EXT = .exe
else
+5 -4
View File
@@ -31,8 +31,8 @@ void inthand(int signum)
int main(int argc, char **argv)
{
uint8_t init_result;
uint64_t iterations = 0;
unsigned char init_result;
size_t iterations = 0;
printf("stk test - CTRL+C to exit\n");
@@ -55,12 +55,13 @@ int main(int argc, char **argv)
while (!stop) {
size_t events = stk_poll();
if (events > 0)
printf("Poll: %lu module event(s) detected\n", (unsigned long) events);
printf("Poll: %lu module event(s) detected\n",
(unsigned long)events);
iterations++;
if (iterations % 5 == 0) {
printf("Still running... (iteration %lu)\n",
(unsigned long) iterations);
(unsigned long)iterations);
}
#ifdef _WIN32
Sleep(1000);