From 682811903c0c5c891da3afb195be7542f0abce47 Mon Sep 17 00:00:00 2001 From: Serg One Zero Date: Sun, 24 May 2026 02:21:49 -0400 Subject: [PATCH 1/5] Make GLFW backend buildable under MSVC - Add vcpkg integration (CMakePresets.json, vcpkg.json, vcpkg-configuration.json) for dependency management - Update .gitignore for more build/IDE artifacts - Refactor CMakeLists.txt for MSVC/MinGW with conditional warnings - Replace VLA with calloc for MSVC compatibility; ensure proper memory freeing - Add ALIGN and NOINLINE macros; improve safe memory allocation functions - Make for-each/repeat macros portable for compilers without typeof - Replace switch-case ranges with explicit cases for MSVC - Add MSVC-specific workarounds (e.g., disable WASAPI in miniaudio) - General memory safety and portability improvements(?) --- .gitignore | 5 +- CMakeLists.txt | 14 ++- CMakePresets.json | 15 ++++ src/audio/miniaudio/ma_audio_system.c | 8 +- src/common.h | 18 ++++ src/overlay_file_system.c | 3 + src/profiler.c | 2 + src/rvalue.h | 2 +- src/utils.h | 114 ++++++++++++++----------- src/vm.c | 6 +- src/vm.h | 12 ++- src/vm_builtins.c | 118 ++++++++++++++++++++++++-- vcpkg-configuration.json | 14 +++ vcpkg.json | 7 ++ vendor/miniaudio/miniaudio.h | 4 + 15 files changed, 270 insertions(+), 72 deletions(-) create mode 100644 CMakePresets.json create mode 100644 vcpkg-configuration.json create mode 100644 vcpkg.json diff --git a/.gitignore b/.gitignore index 2dccd4e0..8bb1ce50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ build/ -build_ps2/ -build_ps3/ +build_*/ .gitignore .cache CMakeUserPresets.json .devcontainer/ +vcpkg_installed/ +.vs/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 57e215b8..c8cc307f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,9 @@ project(butterscotch C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) -add_compile_options(-Wall -Wextra) +if(NOT MSVC) + add_compile_options(-Wall -Wextra) +endif() set(PLATFORM "" CACHE STRING "Platform backend") set(AUDIO_BACKEND "" CACHE STRING "Audio backend") @@ -204,14 +206,20 @@ if(PLATFORM STREQUAL "glfw") target_include_directories(butterscotch PUBLIC vendor/stb/vorbis) if(MINGW) - find_package(glfw3 REQUIRED) - set(GLFW3_LIBRARIES glfw3) + find_package(glfw3 CONFIG REQUIRED) + set(GLFW3_LIBRARIES glfw) # Target Windows 7+ (avoids referencing newer APIs like MapViewOfFileNuma2 that MinGW import libs don't provide) # https://github.com/mirror/mingw-w64/blob/master/mingw-w64-headers/include/sdkddkver.h target_compile_definitions(butterscotch PRIVATE _WIN32_WINNT=0x0601 NTDDI_VERSION=0x06010000 WIN32_LEAN_AND_MEAN) target_link_libraries(butterscotch ${GLFW3_LIBRARIES} ${AUDIO_LIBRARIES} glad m opengl32 gdi32 winmm bz2) target_link_options(butterscotch PRIVATE -static) + elseif(MSVC) + find_package(glfw3 CONFIG REQUIRED) + set(GLFW3_LIBRARIES glfw) + find_package(BZip2 REQUIRED) + find_package(unofficial-getopt-win32 CONFIG REQUIRED) + target_link_libraries(butterscotch ${GLFW3_LIBRARIES} ${AUDIO_LIBRARIES} glad opengl32 gdi32 winmm BZip2::BZip2 unofficial::getopt-win32::getopt) elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku") find_package(PkgConfig REQUIRED) pkg_check_modules(GLFW3 REQUIRED glfw3) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..43097af8 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,15 @@ +{ + "version": 2, + "configurePresets": [ + { + "name": "vcpkg", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "PLATFORM": "glfw", + "ENABLE_ASAN": false, + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + } + } + ], +} \ No newline at end of file diff --git a/src/audio/miniaudio/ma_audio_system.c b/src/audio/miniaudio/ma_audio_system.c index 23c51a63..f0d448cb 100644 --- a/src/audio/miniaudio/ma_audio_system.c +++ b/src/audio/miniaudio/ma_audio_system.c @@ -8,6 +8,9 @@ // which enables miniaudio's built-in OGG Vorbis decoding support. #include "stb_vorbis.c" +#ifdef _MSC_VER // Workaround for miniaudio compilation error on MSVC +#define MA_DISABLE_WASAPI +#endif #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" @@ -607,8 +610,9 @@ static void maSetChannelCount(MAYBE_UNUSED AudioSystem* audio, MAYBE_UNUSED int3 static void maGroupLoad(AudioSystem* audio, int32_t groupIndex) { if (groupIndex > 0) { int sz = snprintf(nullptr, 0, "audiogroup%d.dat", groupIndex); - char buf[sz + 1]; - snprintf(buf, sizeof(buf), "audiogroup%d.dat", groupIndex); + char *buf = (char*)calloc(sz + 1, 1); + snprintf(buf, sz + 1, "audiogroup%d.dat", groupIndex); + free(buf); DataWin *audioGroup = DataWin_parse(((MaAudioSystem*)audio)->fileSystem->vtable->resolvePath(((MaAudioSystem*)audio)->fileSystem, buf), (DataWinParserOptions) { .parseAudo = true, diff --git a/src/common.h b/src/common.h index 2c8e4ba2..e7c6da2b 100644 --- a/src/common.h +++ b/src/common.h @@ -5,6 +5,10 @@ #define nullptr NULL #endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || defined(__BIG_ENDIAN__) #define IS_BIG_ENDIAN #endif @@ -22,3 +26,17 @@ #define MAYBE_UNUSED #endif #endif + +#if defined(__GNUC__) || defined(__clang__) + #define ALIGN(x) __attribute__((aligned(x))); +#else + #define ALIGN(x) +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER >= 1400 // VS2005 or later + #define NOINLINE __declspec(noinline) +#else + #define NOINLINE +#endif \ No newline at end of file diff --git a/src/overlay_file_system.c b/src/overlay_file_system.c index dabb55cb..e7128fa9 100644 --- a/src/overlay_file_system.c +++ b/src/overlay_file_system.c @@ -11,6 +11,9 @@ #include #define overlayMkdir(path) _mkdir(path) #define overlayRmdir(path) _rmdir(path) +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif #else #include #define overlayMkdir(path) mkdir((path), 0777) diff --git a/src/profiler.c b/src/profiler.c index 62a9a72f..e058c09b 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -3,7 +3,9 @@ #include #include #include +#ifndef _MSC_VER #include +#endif #include "utils.h" #include "stb_ds.h" diff --git a/src/rvalue.h b/src/rvalue.h index c90e616f..e008fd54 100644 --- a/src/rvalue.h +++ b/src/rvalue.h @@ -90,7 +90,7 @@ struct RValue { uint8_t gmlStackType; // GML data type from the instruction that pushed this value #endif uint8_t assetRefType; // For RVALUE_ASSETREF: Indicates the asset type (AssetRefType) -} __attribute__((aligned(8))); +} ALIGN(8); // Helper to initialize .gmlStackType only on BC17+ builds #if IS_BC17_OR_HIGHER_ENABLED diff --git a/src/utils.h b/src/utils.h index ef12f208..c4e838f2 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,12 +3,14 @@ #include "common.h" #include #include +#include #include #include #include #include "real_type.h" +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L) || defined(__GNUC__) || defined(__clang__) #define forEach(type, item, array, count) \ for (typeof(count) item##_i_ = 0; item##_i_ < (count); item##_i_++) \ for (type* item = &(array)[item##_i_]; item; item = NULL) @@ -20,6 +22,17 @@ // The "typeof((typeof(n))0" is used to remove the "const" from the typeof #define repeat(n, it) for (typeof((typeof(n))0) it = 0; it < (n); it++) +#else +#define forEach(type, item, array, count) \ + for (long long item##_i_ = 0; item##_i_ < (long long)(count); item##_i_++) \ + for (type* item = &(array)[item##_i_]; item; item = 0) + +#define forEachIndexed(type, item, index, array, count) \ + for (long long index = 0; index < (long long)(count); index++) \ + for (type* item = &(array)[index]; item; item = 0) + +#define repeat(n, it) for (long long it = 0; it < (long long)(n); it++) +#endif #define require(condition) \ do { \ @@ -45,52 +58,49 @@ abort(); \ } \ } while (0) -#define requireNotNull(ptr) ({ \ -typeof(ptr) _val = (ptr); \ -if (_val == NULL) { \ -fprintf(stderr, "%s:%d: requireNotNull failed: '%s'\n", __FILE__, __LINE__, #ptr); \ -abort(); \ -} \ -_val; \ -}) +static inline void* requireNotNullFunction(void* ptr, char* file, int line, char* name) { + if (ptr == nullptr) { + fprintf(stderr, "%s:%d: requireNotNull failed: '%s'\n", file, line, name); + abort(); + } + return ptr; +} +#define requireNotNull(ptr) requireNotNullFunction((void*)ptr, __FILE__, __LINE__, #ptr) -#define requireNotNullMessage(ptr, msg) ({ \ -typeof(ptr) _val = (ptr); \ -if (_val == NULL) { \ -fprintf(stderr, "%s:%d: requireNotNull failed: %s\n", __FILE__, __LINE__, (msg)); \ -abort(); \ -} \ -_val; \ -}) +#define requireNotNullMessage(ptr, msg) requireNotNullFunction((void*)ptr, __FILE__, __LINE__, msg) // Safe allocation macros - check for nullptr and abort with file/line info -#define safeMalloc(size) ({ \ - void* _ptr = malloc(size); \ - if (_ptr == nullptr) { \ - fprintf(stderr, "FATAL: malloc(%zu) failed at %s:%d\n", (size_t)(size), __FILE__, __LINE__); \ - abort(); \ - } \ - _ptr; \ -}) - -#define safeCalloc(count, size) ({ \ - void* _ptr = calloc(count, size); \ - if (_ptr == nullptr) { \ - fprintf(stderr, "FATAL: calloc(%zu, %zu) failed at %s:%d\n", (size_t)(count), (size_t)(size), __FILE__, __LINE__); \ - abort(); \ - } \ - _ptr; \ -}) - -#define safeRealloc(ptr, size) ({ \ - void* _ptr = realloc(ptr, size); \ - if (_ptr == nullptr) { \ - fprintf(stderr, "FATAL: realloc(%zu) failed at %s:%d\n", (size_t)(size), __FILE__, __LINE__); \ - abort(); \ - } \ - _ptr; \ -}) +static inline void* safeMallocFunction(size_t size, char* file, int line) { + void* _ptr = malloc(size); + if (_ptr == nullptr) { + fprintf(stderr, "FATAL: malloc(%zu) failed at %s:%d\n", size, file, line); + abort(); + } + return _ptr; +} +#define safeMalloc(size) safeMallocFunction(size, __FILE__, __LINE__) + +static inline void* safeCallocFunction(size_t count, size_t size, char* file, int line) { + void* _ptr = calloc(count, size); + if (_ptr == nullptr) { + fprintf(stderr, "FATAL: calloc(%zu, %zu) failed at %s:%d\n", count, size, file, line); + abort(); + } + return _ptr; +} +#define safeCalloc(count, size) safeCallocFunction(count, size, __FILE__, __LINE__) + +static inline void* safeReallocFunction(void* ptr, size_t size, char* file, int line) { + void* _ptr = realloc(ptr, size); + if (_ptr == nullptr) { + fprintf(stderr, "FATAL: realloc(%zu) failed at %s:%d\n", size, file, line); + abort(); + } + return _ptr; +} +#define safeRealloc(ptr, size) safeReallocFunction(ptr, size, __FILE__, __LINE__) +#if defined(PLATFORM_PS2) #define safeMemalign(alignment, size) ({ \ void* _ptr = memalign(alignment, size); \ if (_ptr == nullptr) { \ @@ -99,15 +109,17 @@ _val; \ } \ _ptr; \ }) - -#define safeStrdup(str) ({ \ - char* _ptr = strdup(str); \ - if (_ptr == nullptr) { \ - fprintf(stderr, "FATAL: strdup() failed at %s:%d\n", __FILE__, __LINE__); \ - abort(); \ - } \ - _ptr; \ -}) +#endif + +static inline const char* safeStrdupFunction(const char* str, char* file, int line) { + const char* _ptr = strdup(str); + if (_ptr == nullptr) { + fprintf(stderr, "FATAL: strdup() failed at %s:%d\n", file, line); + abort(); + } + return _ptr; +} +#define safeStrdup(str) safeStrdupFunction(str, __FILE__, __LINE__) // Truncates to 6 decimal places, matching the HTML5 runner's ClampFloat static inline GMLReal clampFloat(GMLReal f) { diff --git a/src/vm.c b/src/vm.c index 48cdfbca..38fa05c1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -848,7 +848,7 @@ static inline void writeIntoSlot(RValue* dest, RValue val) { } // Force out-of-line so the OP_POP fast path in executeLoop doesn't inline this, because we already have an "optimized" version for common writes -__attribute__((noinline)) +NOINLINE static void resolveVariableWrite(VMContext* ctx, int32_t instanceType, uint32_t varRef, RValue val) { Variable* varDef = resolveVarDef(ctx, varRef); @@ -1499,7 +1499,7 @@ static void handlePopz(VMContext* ctx) { RValue_free(&val); } -__attribute__((noinline)) +NOINLINE static void handleAddString(VMContext* ctx, RValue a, RValue b, uint8_t resultType) { if (a.type == RVALUE_STRING && b.type == RVALUE_STRING) { // String concatenation @@ -1540,7 +1540,7 @@ static void handleAddString(VMContext* ctx, RValue a, RValue b, uint8_t resultTy } } -__attribute__((noinline)) +NOINLINE static void handleMulString(VMContext* ctx, RValue a, RValue b, uint8_t resultType) { // a.type == RVALUE_STRING; b is the repetition count. int count = RValue_toInt32(b); diff --git a/src/vm.h b/src/vm.h index 434a6b65..4c2fcc06 100644 --- a/src/vm.h +++ b/src/vm.h @@ -333,13 +333,17 @@ static inline bool VM_shouldTraceVariable(StringBooleanEntry* traceMap, const ch if (shgeti(traceMap, "*") != -1) return true; if (shgeti(traceMap, scopeName) != -1) return true; if (altScopeName != nullptr && shgeti(traceMap, altScopeName) != -1) return true; - char formatted[strlen(scopeName) + 1 + strlen(varName) + 1]; + char *formatted = calloc(strlen(scopeName) + 1 + strlen(varName) + 1, 1); snprintf(formatted, sizeof(formatted), "%s.%s", scopeName, varName); - if (shgeti(traceMap, formatted) != -1) return true; + bool match = shgeti(traceMap, formatted) != -1; + free(formatted); + if (match) return true; if (altScopeName != nullptr) { - char altFormatted[strlen(altScopeName) + 1 + strlen(varName) + 1]; + char *altFormatted = calloc(strlen(altScopeName) + 1 + strlen(varName) + 1, 1); snprintf(altFormatted, sizeof(altFormatted), "%s.%s", altScopeName, varName); - if (shgeti(traceMap, altFormatted) != -1) return true; + bool altMatch = shgeti(traceMap, altFormatted) != -1; + free(altFormatted); + if (altMatch) return true; } return false; } diff --git a/src/vm_builtins.c b/src/vm_builtins.c index a6aa520f..50a7bfcc 100644 --- a/src/vm_builtins.c +++ b/src/vm_builtins.c @@ -14,7 +14,9 @@ #include #include #include +#ifndef _MSC_VER #include +#endif #ifdef _WIN32 #include #endif @@ -819,7 +821,22 @@ RValue VMBuiltins_getVariable(VMContext* ctx, int16_t builtinVarId, const char* } return RValue_makeUndefined(); } - case BUILTIN_VAR_ARGUMENT0 ... BUILTIN_VAR_ARGUMENT15: { + case BUILTIN_VAR_ARGUMENT0: + case BUILTIN_VAR_ARGUMENT1: + case BUILTIN_VAR_ARGUMENT2: + case BUILTIN_VAR_ARGUMENT3: + case BUILTIN_VAR_ARGUMENT4: + case BUILTIN_VAR_ARGUMENT5: + case BUILTIN_VAR_ARGUMENT6: + case BUILTIN_VAR_ARGUMENT7: + case BUILTIN_VAR_ARGUMENT8: + case BUILTIN_VAR_ARGUMENT9: + case BUILTIN_VAR_ARGUMENT10: + case BUILTIN_VAR_ARGUMENT11: + case BUILTIN_VAR_ARGUMENT12: + case BUILTIN_VAR_ARGUMENT13: + case BUILTIN_VAR_ARGUMENT14: + case BUILTIN_VAR_ARGUMENT15: { int argNumber = builtinVarId - BUILTIN_VAR_ARGUMENT0; if (ctx->scriptArgs != nullptr && ctx->scriptArgCount > argNumber) { RValue val = ctx->scriptArgs[argNumber]; @@ -1340,8 +1357,60 @@ void VMBuiltins_setVariable(VMContext* ctx, int16_t builtinVarId, const char* na return; // Read-only variables (silently ignore with warning) - case BUILTIN_VAR_OS_TYPE ... BUILTIN_VAR_OS_LLVM_WINPHONE: - case BUILTIN_VAR_BUFFER_FIXED ... BUILTIN_VAR_BUFFER_SEEK_END: + // OS constants + case BUILTIN_VAR_OS_TYPE: + case BUILTIN_VAR_OS_UNKNOWN: + case BUILTIN_VAR_OS_WIN32: + case BUILTIN_VAR_OS_WINDOWS: + case BUILTIN_VAR_OS_MACOSX: + case BUILTIN_VAR_OS_PSP: + case BUILTIN_VAR_OS_IOS: + case BUILTIN_VAR_OS_ANDROID: + case BUILTIN_VAR_OS_SYMBIAN: + case BUILTIN_VAR_OS_LINUX: + case BUILTIN_VAR_OS_WINPHONE: + case BUILTIN_VAR_OS_TIZEN: + case BUILTIN_VAR_OS_WIN8NATIVE: + case BUILTIN_VAR_OS_WIIU: + case BUILTIN_VAR_OS_3DS: + case BUILTIN_VAR_OS_PSVITA: + case BUILTIN_VAR_OS_BB10: + case BUILTIN_VAR_OS_PS4: + case BUILTIN_VAR_OS_XBOXONE: + case BUILTIN_VAR_OS_PS3: + case BUILTIN_VAR_OS_XBOX360: + case BUILTIN_VAR_OS_UWP: + case BUILTIN_VAR_OS_AMAZON: + case BUILTIN_VAR_OS_SWITCH: + case BUILTIN_VAR_OS_LLVM_WIN32: + case BUILTIN_VAR_OS_LLVM_MACOSX: + case BUILTIN_VAR_OS_LLVM_PSP: + case BUILTIN_VAR_OS_LLVM_IOS: + case BUILTIN_VAR_OS_LLVM_ANDROID: + case BUILTIN_VAR_OS_LLVM_SYMBIAN: + case BUILTIN_VAR_OS_LLVM_LINUX: + case BUILTIN_VAR_OS_LLVM_WINPHONE: + // Buffer constants + case BUILTIN_VAR_BUFFER_FIXED: + case BUILTIN_VAR_BUFFER_GROW: + case BUILTIN_VAR_BUFFER_WRAP: + case BUILTIN_VAR_BUFFER_FAST: + case BUILTIN_VAR_BUFFER_U8: + case BUILTIN_VAR_BUFFER_S8: + case BUILTIN_VAR_BUFFER_U16: + case BUILTIN_VAR_BUFFER_S16: + case BUILTIN_VAR_BUFFER_U32: + case BUILTIN_VAR_BUFFER_S32: + case BUILTIN_VAR_BUFFER_F16: + case BUILTIN_VAR_BUFFER_F32: + case BUILTIN_VAR_BUFFER_F64: + case BUILTIN_VAR_BUFFER_BOOL: + case BUILTIN_VAR_BUFFER_STRING: + case BUILTIN_VAR_BUFFER_U64: + case BUILTIN_VAR_BUFFER_TEXT: + case BUILTIN_VAR_BUFFER_SEEK_START: + case BUILTIN_VAR_BUFFER_SEEK_RELATIVE: + case BUILTIN_VAR_BUFFER_SEEK_END: case BUILTIN_VAR_ID: case BUILTIN_VAR_OBJECT_INDEX: case BUILTIN_VAR_CURRENT_TIME: @@ -1349,7 +1418,28 @@ void VMBuiltins_setVariable(VMContext* ctx, int16_t builtinVarId, const char* na case BUILTIN_VAR_PATH_INDEX: case BUILTIN_VAR_DEBUG_MODE: case BUILTIN_VAR_ROOM_FIRST: - case BUILTIN_VAR_GP_FACE1 ... BUILTIN_VAR_GP_AXIS_RV: + // Gamepad constants + case BUILTIN_VAR_GP_FACE1: + case BUILTIN_VAR_GP_FACE2: + case BUILTIN_VAR_GP_FACE3: + case BUILTIN_VAR_GP_FACE4: + case BUILTIN_VAR_GP_SHOULDERL: + case BUILTIN_VAR_GP_SHOULDERR: + case BUILTIN_VAR_GP_SHOULDERLB: + case BUILTIN_VAR_GP_SHOULDERRB: + case BUILTIN_VAR_GP_SELECT: + case BUILTIN_VAR_GP_START: + case BUILTIN_VAR_GP_STICKL: + case BUILTIN_VAR_GP_STICKR: + case BUILTIN_VAR_GP_PADU: + case BUILTIN_VAR_GP_PADD: + case BUILTIN_VAR_GP_PADL: + case BUILTIN_VAR_GP_PADR: + case BUILTIN_VAR_GP_HOME: + case BUILTIN_VAR_GP_AXIS_LH: + case BUILTIN_VAR_GP_AXIS_LV: + case BUILTIN_VAR_GP_AXIS_RH: + case BUILTIN_VAR_GP_AXIS_RV: fprintf(stderr, "VM: [%s] Attempted write to read-only built-in '%s'\n", ctx->currentCodeName, name); return; @@ -1362,7 +1452,22 @@ void VMBuiltins_setVariable(VMContext* ctx, int16_t builtinVarId, const char* na return; // Argument variables (argument0..argument15) - case BUILTIN_VAR_ARGUMENT0 ... BUILTIN_VAR_ARGUMENT15: { + case BUILTIN_VAR_ARGUMENT0: + case BUILTIN_VAR_ARGUMENT1: + case BUILTIN_VAR_ARGUMENT2: + case BUILTIN_VAR_ARGUMENT3: + case BUILTIN_VAR_ARGUMENT4: + case BUILTIN_VAR_ARGUMENT5: + case BUILTIN_VAR_ARGUMENT6: + case BUILTIN_VAR_ARGUMENT7: + case BUILTIN_VAR_ARGUMENT8: + case BUILTIN_VAR_ARGUMENT9: + case BUILTIN_VAR_ARGUMENT10: + case BUILTIN_VAR_ARGUMENT11: + case BUILTIN_VAR_ARGUMENT12: + case BUILTIN_VAR_ARGUMENT13: + case BUILTIN_VAR_ARGUMENT14: + case BUILTIN_VAR_ARGUMENT15: { int argNumber = builtinVarId - BUILTIN_VAR_ARGUMENT0; if (ctx->scriptArgs != nullptr && ctx->scriptArgCount > argNumber) { RValue_free(&ctx->scriptArgs[argNumber]); @@ -1423,7 +1528,7 @@ static RValue builtin_string_length(MAYBE_UNUSED VMContext* ctx, RValue* args, i // https://docs.vultr.com/clang/examples/remove-all-characters-in-a-string-except-alphabets void filterAlphabets(char *str) { - char result[strlen(str) + 1]; + char *result = (char*)calloc(strlen(str) + 1, sizeof(char)); int j = 0; for (int i = 0; str[i] != '\0'; i++) { if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) { @@ -1432,6 +1537,7 @@ void filterAlphabets(char *str) { } result[j] = '\0'; // Null-terminate the result string strcpy(str, result); // Optionally copy back to original string + free(result); } static RValue builtin_string_letters(MAYBE_UNUSED VMContext* ctx, RValue* args, int32_t argCount) { diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json new file mode 100644 index 00000000..970c045f --- /dev/null +++ b/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "default-registry": { + "kind": "git", + "baseline": "d59510da59a2ee8b943509998b63da7b472d93cf", + "repository": "https://github.com/microsoft/vcpkg" + }, + "registries": [ + { + "kind": "artifact", + "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", + "name": "microsoft" + } + ] +} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 00000000..8b332a19 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,7 @@ +{ + "dependencies": [ + "glfw3", + "getopt-win32", + "bzip2" + ] +} diff --git a/vendor/miniaudio/miniaudio.h b/vendor/miniaudio/miniaudio.h index 571a1f3c..2b18fd6d 100644 --- a/vendor/miniaudio/miniaudio.h +++ b/vendor/miniaudio/miniaudio.h @@ -23381,6 +23381,7 @@ typedef struct static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_uint32 loopbackProcessID, ma_bool32 loopbackProcessExclude, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface) { +#ifndef MA_DISABLE_WASAPI ma_result result; ma_bool32 usingProcessLoopback = MA_FALSE; MA_AUDIOCLIENT_ACTIVATION_PARAMS audioclientActivationParams; @@ -23430,6 +23431,9 @@ static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_de } return result; +#else + return MA_BACKEND_NOT_ENABLED; +#endif } From 0b38ad9431158fc2e0294949aef77101a16920c5 Mon Sep 17 00:00:00 2001 From: Serg One Zero Date: Sun, 24 May 2026 16:27:28 -0400 Subject: [PATCH 2/5] Fix -Wdiscarded-qualifiers warning in GCC --- src/utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.h b/src/utils.h index c4e838f2..ab7b78de 100644 --- a/src/utils.h +++ b/src/utils.h @@ -111,8 +111,8 @@ static inline void* safeReallocFunction(void* ptr, size_t size, char* file, int }) #endif -static inline const char* safeStrdupFunction(const char* str, char* file, int line) { - const char* _ptr = strdup(str); +static inline char* safeStrdupFunction(const char* str, char* file, int line) { + char* _ptr = strdup(str); if (_ptr == nullptr) { fprintf(stderr, "FATAL: strdup() failed at %s:%d\n", file, line); abort(); From dce211ad59d36692ab28f1feb467bc088e90bd48 Mon Sep 17 00:00:00 2001 From: Serg One Zero Date: Sun, 24 May 2026 16:50:24 -0400 Subject: [PATCH 3/5] Change calloc string allocations to use malloc instead --- src/audio/miniaudio/ma_audio_system.c | 5 +++-- src/vm.h | 10 ++++++---- src/vm_builtins.c | 3 ++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/audio/miniaudio/ma_audio_system.c b/src/audio/miniaudio/ma_audio_system.c index f0d448cb..9b14a3fd 100644 --- a/src/audio/miniaudio/ma_audio_system.c +++ b/src/audio/miniaudio/ma_audio_system.c @@ -610,8 +610,9 @@ static void maSetChannelCount(MAYBE_UNUSED AudioSystem* audio, MAYBE_UNUSED int3 static void maGroupLoad(AudioSystem* audio, int32_t groupIndex) { if (groupIndex > 0) { int sz = snprintf(nullptr, 0, "audiogroup%d.dat", groupIndex); - char *buf = (char*)calloc(sz + 1, 1); - snprintf(buf, sz + 1, "audiogroup%d.dat", groupIndex); + size_t bufSize = (size_t)sz + 1; + char *buf = malloc(bufSize); + snprintf(buf, bufSize, "audiogroup%d.dat", groupIndex); free(buf); DataWin *audioGroup = DataWin_parse(((MaAudioSystem*)audio)->fileSystem->vtable->resolvePath(((MaAudioSystem*)audio)->fileSystem, buf), (DataWinParserOptions) { diff --git a/src/vm.h b/src/vm.h index 4c2fcc06..84737521 100644 --- a/src/vm.h +++ b/src/vm.h @@ -333,14 +333,16 @@ static inline bool VM_shouldTraceVariable(StringBooleanEntry* traceMap, const ch if (shgeti(traceMap, "*") != -1) return true; if (shgeti(traceMap, scopeName) != -1) return true; if (altScopeName != nullptr && shgeti(traceMap, altScopeName) != -1) return true; - char *formatted = calloc(strlen(scopeName) + 1 + strlen(varName) + 1, 1); - snprintf(formatted, sizeof(formatted), "%s.%s", scopeName, varName); + size_t formattedLen = strlen(scopeName) + 1 + strlen(varName) + 1; + char *formatted = malloc(formattedLen); + snprintf(formatted, formattedLen, "%s.%s", scopeName, varName); bool match = shgeti(traceMap, formatted) != -1; free(formatted); if (match) return true; if (altScopeName != nullptr) { - char *altFormatted = calloc(strlen(altScopeName) + 1 + strlen(varName) + 1, 1); - snprintf(altFormatted, sizeof(altFormatted), "%s.%s", altScopeName, varName); + size_t altFormattedLen = strlen(altScopeName) + 1 + strlen(varName) + 1; + char *altFormatted = malloc(altFormattedLen); + snprintf(altFormatted, altFormattedLen, "%s.%s", altScopeName, varName); bool altMatch = shgeti(traceMap, altFormatted) != -1; free(altFormatted); if (altMatch) return true; diff --git a/src/vm_builtins.c b/src/vm_builtins.c index 50a7bfcc..78cedcdb 100644 --- a/src/vm_builtins.c +++ b/src/vm_builtins.c @@ -1528,7 +1528,8 @@ static RValue builtin_string_length(MAYBE_UNUSED VMContext* ctx, RValue* args, i // https://docs.vultr.com/clang/examples/remove-all-characters-in-a-string-except-alphabets void filterAlphabets(char *str) { - char *result = (char*)calloc(strlen(str) + 1, sizeof(char)); + size_t resultLen = strlen(str) + 1; + char *result = (char*)malloc(resultLen); int j = 0; for (int i = 0; str[i] != '\0'; i++) { if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) { From 7b4fb83d20bfd4b73282b3bd9a0158339ccde2c8 Mon Sep 17 00:00:00 2001 From: Serg One Zero Date: Sun, 24 May 2026 17:17:12 -0400 Subject: [PATCH 4/5] Add TYPEOF(x) macro to reduce LoC in utils.h, add TCC check --- src/utils.h | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/utils.h b/src/utils.h index ab7b78de..49afea67 100644 --- a/src/utils.h +++ b/src/utils.h @@ -10,29 +10,23 @@ #include "real_type.h" -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L) || defined(__GNUC__) || defined(__clang__) -#define forEach(type, item, array, count) \ - for (typeof(count) item##_i_ = 0; item##_i_ < (count); item##_i_++) \ - for (type* item = &(array)[item##_i_]; item; item = NULL) - -#define forEachIndexed(type, item, index, array, count) \ - for (typeof(count) index = 0; index < (count); index++) \ - for (type* item = &(array)[index]; item; item = NULL) - -// The "typeof((typeof(n))0" is used to remove the "const" from the typeof - -#define repeat(n, it) for (typeof((typeof(n))0) it = 0; it < (n); it++) +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)) \ + || defined(__GNUC__) || defined(__clang__) || defined(__TINYC__) + // The "typeof((typeof(x))0" is used to remove the "const" from the typeof + #define TYPEOF(x) typeof((typeof(x))0) #else + #define TYPEOF(x) long long +#endif + #define forEach(type, item, array, count) \ - for (long long item##_i_ = 0; item##_i_ < (long long)(count); item##_i_++) \ + for (TYPEOF(count) item##_i_ = 0; item##_i_ < (long long)(count); item##_i_++) \ for (type* item = &(array)[item##_i_]; item; item = 0) #define forEachIndexed(type, item, index, array, count) \ - for (long long index = 0; index < (long long)(count); index++) \ + for (TYPEOF(count) index = 0; index < (long long)(count); index++) \ for (type* item = &(array)[index]; item; item = 0) -#define repeat(n, it) for (long long it = 0; it < (long long)(n); it++) -#endif +#define repeat(n, it) for (TYPEOF(n) it = 0; it < (long long)(n); it++) #define require(condition) \ do { \ From 3e5bbec174519200c33dbb9260fc017356e27e24 Mon Sep 17 00:00:00 2001 From: Serg One Zero Date: Sun, 24 May 2026 17:26:55 -0400 Subject: [PATCH 5/5] oops (forgot unsigned in TYPEOF) --- src/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.h b/src/utils.h index 49afea67..ea4f04a1 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,7 +15,7 @@ // The "typeof((typeof(x))0" is used to remove the "const" from the typeof #define TYPEOF(x) typeof((typeof(x))0) #else - #define TYPEOF(x) long long + #define TYPEOF(x) unsigned long long #endif #define forEach(type, item, array, count) \