8 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
11 changed files with 289 additions and 78 deletions
+57 -1
View File
@@ -7,6 +7,57 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [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 ## [0.0.4] - 2026-02-11
### Fixed ### Fixed
@@ -53,7 +104,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dependency management and versioning not yet implemented - Dependency management and versioning not yet implemented
- API is unstable and subject to change in future releases - 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.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.2]: https://github.com/anth64/stk/releases/tag/v0.0.2
[0.0.1]: https://github.com/anth64/stk/releases/tag/v0.0.1 [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 ### API Reference
#### Initialization #### 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 - `void stk_shutdown(void)` - Shutdown and cleanup all modules
#### Runtime #### 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_init_fn(const char *name)` - Set module init function name
- `void stk_set_module_shutdown_fn(const char *name)` - Set module shutdown 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 ## Project Status
**Current Version:** 0.0.4 (Pre-release) **Current Version:** 0.1.2 (Pre-release)
This is a bugfix release completing the Linux hot-reload stability improvements. Phase 1 is still in progress. Fixed Windows compatibility issues.
### What Works ### What Works
- Cross-platform module loading and hot-reloading - Cross-platform module loading and hot-reloading
- File watching (inotify/kqueue/FindFirstFile) - File watching (inotify/kqueue/FindFirstFile)
- Basic error handling - Robust hot-reload even during extremely rapid file changes
- Robust hot-reload even during extremely rapid file changes (Linux fixes in 0.0.2-0.0.4) - Enhanced logging with levels, timestamps, and filtering
- Runtime-configurable logging behavior
### In Progress (Phase 1) ### In Progress (Phase 1)
- Complete logging system (log levels, verbosity, output configuration)
- Module metadata (name, version, description) - Module metadata (name, version, description)
- Dependency management and versioning - Dependency management and versioning
+8 -2
View File
@@ -2,10 +2,10 @@
#define STK_H #define STK_H
#include "stk_version.h" #include "stk_version.h"
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
/* Buffers */ /* Buffers */
#define STK_LOG_PREFIX_BUFFER 64
#define STK_MOD_DIR_BUFFER 256 #define STK_MOD_DIR_BUFFER 256
#define STK_MOD_ID_BUFFER 64 #define STK_MOD_ID_BUFFER 64
#define STK_PATH_MAX 256 #define STK_PATH_MAX 256
@@ -31,6 +31,10 @@
#define STK_PLATFORM_REMOVE_DIR_ERROR 3 #define STK_PLATFORM_REMOVE_DIR_ERROR 3
#define STK_PLATFORM_REMOVE_FILE_ERROR 4 #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) #if defined(__linux__) || defined(_WIN32)
#define STK_EVENT_BUFFER 4096 #define STK_EVENT_BUFFER 4096
#endif #endif
@@ -55,7 +59,7 @@ typedef enum {
STK_MOD_RELOAD STK_MOD_RELOAD
} stk_module_event_t; } stk_module_event_t;
uint8_t stk_init(void); unsigned char stk_init(void);
void stk_shutdown(void); void stk_shutdown(void);
size_t stk_module_count(void); size_t stk_module_count(void);
size_t stk_poll(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_tmp_dir_name(const char *name);
void stk_set_module_init_fn(const char *name); void stk_set_module_init_fn(const char *name);
void stk_set_module_shutdown_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 #ifdef __cplusplus
} }
+12 -1
View File
@@ -7,7 +7,18 @@
extern "C" { extern "C" {
#endif #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 #ifdef __cplusplus
} }
+2 -2
View File
@@ -2,8 +2,8 @@
#define STK_VERSION_H #define STK_VERSION_H
#define STK_VERSION_MAJOR 0 #define STK_VERSION_MAJOR 0
#define STK_VERSION_MINOR 0 #define STK_VERSION_MINOR 1
#define STK_VERSION_PATCH 4 #define STK_VERSION_PATCH 2
#define STK_STRINGIFY_HELPER(x) #x #define STK_STRINGIFY_HELPER(x) #x
#define STK_STRINGIFY(x) STK_STRINGIFY_HELPER(x) #define STK_STRINGIFY(x) STK_STRINGIFY_HELPER(x)
+8 -9
View File
@@ -1,6 +1,5 @@
#include "platform.h" #include "platform.h"
#include "stk.h" #include "stk.h"
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -18,7 +17,7 @@ void **stk_handles = NULL;
stk_init_mod_func *stk_inits = NULL; stk_init_mod_func *stk_inits = NULL;
stk_shutdown_mod_func *stk_shutdowns = 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_init_name[STK_MOD_FUNC_NAME_BUFFER] = "stk_mod_init";
static char stk_mod_shutdown_name[STK_MOD_FUNC_NAME_BUFFER] = 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'; *dot = '\0';
} }
uint8_t is_valid_module_file(const char *filename) unsigned char is_valid_module_file(const char *filename)
{ {
const char *ext; const char *ext;
size_t name_len; size_t name_len;
@@ -72,7 +71,7 @@ int is_mod_loaded(const char *module_name)
return -1; return -1;
} }
uint8_t stk_module_load(const char *path, int index) unsigned char stk_module_load(const char *path, int index)
{ {
void *handle; void *handle;
stk_init_mod_func init_func; 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; 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; int result;
result = stk_module_load(path, index); result = stk_module_load(path, index);
@@ -155,7 +154,7 @@ void stk_module_free_memory(void)
stk_shutdowns = NULL; 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_module_ids = malloc(capacity * sizeof(*stk_module_ids));
stk_handles = malloc(capacity * sizeof(void *)); stk_handles = malloc(capacity * sizeof(void *));
@@ -170,7 +169,7 @@ uint8_t stk_module_init_memory(size_t capacity)
return STK_INIT_SUCCESS; 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; char (*new_module_ids)[STK_MOD_ID_BUFFER] = NULL;
void **new_handles = NULL; void **new_handles = NULL;
@@ -254,7 +253,7 @@ void stk_module_unload_all(void)
void stk_set_module_init_fn(const char *name) void stk_set_module_init_fn(const char *name)
{ {
if (!name || stk_initialized) if (!name || (stk_flags & STK_FLAG_INITIALIZED))
return; return;
strncpy(stk_mod_init_name, name, STK_MOD_FUNC_NAME_BUFFER - 1); 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) void stk_set_module_shutdown_fn(const char *name)
{ {
if (!name || stk_initialized) if (!name || (stk_flags & STK_FLAG_INITIALIZED))
return; return;
strncpy(stk_mod_shutdown_name, name, STK_MOD_FUNC_NAME_BUFFER - 1); strncpy(stk_mod_shutdown_name, name, STK_MOD_FUNC_NAME_BUFFER - 1);
+55 -17
View File
@@ -1,38 +1,34 @@
#include "stk.h" #include "stk.h"
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <dirent.h>
#include <dlfcn.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#endif #endif
#if defined(__linux__) #if defined(__linux__)
#include <dirent.h>
#include <dlfcn.h>
#include <sys/inotify.h> #include <sys/inotify.h>
#include <sys/stat.h>
#include <unistd.h>
#elif defined(_WIN32) #elif defined(_WIN32)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#else #else
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/event.h> #include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#endif #endif
int is_mod_loaded(const char *module_name); 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); 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]; char full_path[STK_PATH_MAX_OS];
#ifdef _WIN32 #ifdef _WIN32
@@ -108,12 +104,32 @@ typedef struct {
} platform_watch_context_t; } platform_watch_context_t;
#endif #endif
uint8_t platform_mkdir(const char *path) unsigned char platform_mkdir(const char *path)
{ {
#ifdef _WIN32 #ifdef _WIN32
return CreateDirectoryA(path, NULL) ? STK_PLATFORM_OPERATION_SUCCESS DWORD attrib;
: STK_PLATFORM_MKDIR_ERROR;
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 #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 return mkdir(path, 0755) == 0 ? STK_PLATFORM_OPERATION_SUCCESS
: STK_PLATFORM_MKDIR_ERROR; : STK_PLATFORM_MKDIR_ERROR;
#endif #endif
@@ -130,7 +146,7 @@ int platform_remove_file(const char *path)
#endif #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]; char buf[STK_PATH_MAX_OS];
int ret = STK_PLATFORM_FILE_COPY_ERROR; int ret = STK_PLATFORM_FILE_COPY_ERROR;
@@ -203,7 +219,7 @@ done:
return ret; return ret;
} }
uint8_t platform_remove_dir(const char *path) unsigned char platform_remove_dir(const char *path)
{ {
#ifdef _WIN32 #ifdef _WIN32
WIN32_FIND_DATAA fd; WIN32_FIND_DATAA fd;
@@ -1010,3 +1026,25 @@ no_change:
return NULL; return NULL;
#endif #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
}
+48 -31
View File
@@ -1,7 +1,6 @@
#include "stk.h" #include "stk.h"
#include "platform.h" #include "platform.h"
#include "stk_log.h" #include "stk_log.h"
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -16,11 +15,11 @@ extern char (*stk_module_ids)[STK_MOD_ID_BUFFER];
extern size_t module_count; 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_mod_dir[STK_PATH_MAX_OS] = "mods";
static char stk_tmp_name[STK_MOD_ID_BUFFER] = ".tmp"; 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; static void *watch_handle = NULL;
char (*platform_directory_init_scan(const char *path, 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( stk_module_event_t *platform_directory_watch_check(
void *handle, char (**file_list)[STK_PATH_MAX], size_t *out_count, 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); char (*loaded_module_ids)[STK_MOD_ID_BUFFER], const size_t loaded_count);
uint8_t platform_mkdir(const char *path); unsigned char platform_mkdir(const char *path);
uint8_t platform_copy_file(const char *from, const char *to); unsigned char platform_copy_file(const char *from, const char *to);
uint8_t platform_remove_dir(const char *path); unsigned char platform_remove_dir(const char *path);
void extract_module_id(const char *path, char *out_id); void extract_module_id(const char *path, char *out_id);
int is_mod_loaded(const char *module_id); int is_mod_loaded(const char *module_id);
size_t stk_module_count(void); size_t stk_module_count(void);
uint8_t stk_module_load(const char *path, int index); unsigned char stk_module_load(const char *path, int index);
uint8_t stk_module_load_init(const char *path, int index); unsigned char stk_module_load_init(const char *path, int index);
uint8_t stk_module_init_memory(size_t capacity); unsigned char stk_module_init_memory(size_t capacity);
uint8_t stk_module_realloc_memory(size_t new_capacity); unsigned char stk_module_realloc_memory(size_t new_capacity);
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);
@@ -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; char (*files)[STK_PATH_MAX] = NULL;
size_t file_count, i, successful_loads = 0; size_t file_count, i, successful_loads = 0;
@@ -78,6 +77,8 @@ uint8_t stk_init(void)
char tmp_path[STK_PATH_MAX_OS]; char tmp_path[STK_PATH_MAX_OS];
int load_result; 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) { if (platform_mkdir(stk_tmp_dir) != STK_PLATFORM_OPERATION_SUCCESS) {
char (*test_scan)[STK_PATH_MAX]; char (*test_scan)[STK_PATH_MAX];
size_t test_count; size_t test_count;
@@ -87,7 +88,7 @@ uint8_t stk_init(void)
if (test_scan) if (test_scan)
free(test_scan); free(test_scan);
if (!test_scan && test_count == 0) { if (!test_scan && test_count == 0) {
stk_log(stderr, stk_log(STK_LOG_ERROR,
"FATAL: Cannot create temp directory: %s", "FATAL: Cannot create temp directory: %s",
stk_tmp_dir); stk_tmp_dir);
return STK_INIT_TMPDIR_ERROR; return STK_INIT_TMPDIR_ERROR;
@@ -97,7 +98,7 @@ uint8_t stk_init(void)
files = platform_directory_init_scan(stk_mod_dir, &file_count); files = platform_directory_init_scan(stk_mod_dir, &file_count);
if (file_count > 0 && stk_module_init_memory(file_count) != 0) { 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; return STK_INIT_MEMORY_ERROR;
} }
@@ -110,7 +111,8 @@ uint8_t stk_init(void)
if (platform_copy_file(full_path, tmp_path) != if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) { 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]); files[i]);
continue; continue;
} }
@@ -118,7 +120,7 @@ uint8_t stk_init(void)
load_result = stk_module_load_init(tmp_path, successful_loads); load_result = stk_module_load_init(tmp_path, successful_loads);
if (load_result != STK_MOD_INIT_SUCCESS) { 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)); files[i], stk_error_string(load_result));
} else { } else {
successful_loads++; successful_loads++;
@@ -134,17 +136,18 @@ uint8_t stk_init(void)
scanned: scanned:
watch_handle = platform_directory_watch_start(stk_mod_dir); watch_handle = platform_directory_watch_start(stk_mod_dir);
if (!watch_handle) { 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_mod_dir);
stk_module_unload_all(); stk_module_unload_all();
return STK_INIT_WATCH_ERROR; 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_VERSION_STRING, module_count, module_count != 1 ? "s" : "",
stk_mod_dir); stk_mod_dir);
stk_initialized = 1; stk_flags |= STK_FLAG_INITIALIZED;
return STK_INIT_SUCCESS; return STK_INIT_SUCCESS;
} }
@@ -159,12 +162,13 @@ void stk_shutdown(void)
if (platform_remove_dir(stk_tmp_dir) != if (platform_remove_dir(stk_tmp_dir) !=
STK_PLATFORM_OPERATION_SUCCESS) { 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_tmp_dir);
} }
stk_initialized = 0; stk_flags &= ~STK_FLAG_INITIALIZED;
stk_log(stdout, "stk shutdown"); stk_log(STK_LOG_INFO, "stk shutdown");
} }
size_t stk_poll(void) size_t stk_poll(void)
@@ -261,18 +265,18 @@ begin_operations:
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir, build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
file_list[file_index]); file_list[file_index]);
stk_module_unload(mod_index);
if (platform_copy_file(full_path, tmp_path) != if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) { 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]); file_list[file_index]);
continue; continue;
} }
stk_module_unload(mod_index);
load_result = stk_module_load(tmp_path, mod_index); load_result = stk_module_load(tmp_path, mod_index);
if (load_result != STK_MOD_INIT_SUCCESS) { 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], file_list[file_index],
stk_error_string(load_result)); stk_error_string(load_result));
} }
@@ -290,14 +294,14 @@ begin_operations:
if (platform_copy_file(full_path, tmp_path) != if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) { 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]); file_list[file_index]);
continue; continue;
} }
load_result = stk_module_load(tmp_path, target_index); load_result = stk_module_load(tmp_path, target_index);
if (load_result != STK_MOD_INIT_SUCCESS) { 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], file_list[file_index],
stk_error_string(load_result)); stk_error_string(load_result));
} }
@@ -322,7 +326,7 @@ append_modules:
if (platform_copy_file(full_path, tmp_path) != if (platform_copy_file(full_path, tmp_path) !=
STK_PLATFORM_OPERATION_SUCCESS) { 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]); file_list[file_index]);
continue; continue;
} }
@@ -330,7 +334,7 @@ append_modules:
load_result = stk_module_load(tmp_path, module_count + load_result = stk_module_load(tmp_path, module_count +
successful_appends); successful_appends);
if (load_result != STK_MOD_INIT_SUCCESS) { 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], file_list[file_index],
stk_error_string(load_result)); stk_error_string(load_result));
} else { } else {
@@ -381,7 +385,7 @@ finish_poll:
void stk_set_mod_dir(const char *path) void stk_set_mod_dir(const char *path)
{ {
if (!path || stk_initialized) if (!path || (stk_flags & STK_FLAG_INITIALIZED))
return; return;
strncpy(stk_mod_dir, path, STK_PATH_MAX_OS - 1); strncpy(stk_mod_dir, path, STK_PATH_MAX_OS - 1);
@@ -399,7 +403,7 @@ void stk_set_mod_dir(const char *path)
void stk_set_tmp_dir_name(const char *name) void stk_set_tmp_dir_name(const char *name)
{ {
if (!name || stk_initialized) if (!name || (stk_flags & STK_FLAG_INITIALIZED))
return; return;
strncpy(stk_tmp_name, name, STK_MOD_ID_BUFFER - 1); strncpy(stk_tmp_name, name, STK_MOD_ID_BUFFER - 1);
@@ -412,3 +416,16 @@ void stk_set_tmp_dir_name(const char *name)
strncat(stk_tmp_dir, stk_tmp_name, strncat(stk_tmp_dir, stk_tmp_name,
STK_PATH_MAX_OS - strlen(stk_tmp_dir) - 1); 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_log.h"
#include "stk.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.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; char *level_str = "";
va_start(args, fmt); 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); return level_str;
fputc('\n', fp); }
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); 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 LDFLAGS = -L../bin/debug -lstk
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
SHELL := cmd.exe
.SHELLFLAGS := /c
MODULE_EXT = .dll MODULE_EXT = .dll
EXE_EXT = .exe EXE_EXT = .exe
else else
+5 -4
View File
@@ -31,8 +31,8 @@ void inthand(int signum)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
uint8_t init_result; unsigned char init_result;
uint64_t iterations = 0; size_t iterations = 0;
printf("stk test - CTRL+C to exit\n"); printf("stk test - CTRL+C to exit\n");
@@ -55,12 +55,13 @@ int main(int argc, char **argv)
while (!stop) { while (!stop) {
size_t events = stk_poll(); size_t events = stk_poll();
if (events > 0) 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++; iterations++;
if (iterations % 5 == 0) { if (iterations % 5 == 0) {
printf("Still running... (iteration %lu)\n", printf("Still running... (iteration %lu)\n",
(unsigned long) iterations); (unsigned long)iterations);
} }
#ifdef _WIN32 #ifdef _WIN32
Sleep(1000); Sleep(1000);