mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-12-13 03:32:28 +00:00
chore(build): use SDL3
This commit is contained in:
parent
9d04a35d87
commit
b3c0734a9e
3286 changed files with 866354 additions and 554996 deletions
611
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi.c
vendored
Normal file
611
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi.c
vendored
Normal file
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_build_config.h"
|
||||
#include "SDL_dynapi.h"
|
||||
#include "SDL_dynapi_unsupported.h"
|
||||
|
||||
#if SDL_DYNAMIC_API
|
||||
|
||||
#define SDL_DYNAMIC_API_ENVVAR "SDL3_DYNAMIC_API"
|
||||
#define SDL_SLOW_MEMCPY
|
||||
#define SDL_SLOW_MEMMOVE
|
||||
#define SDL_SLOW_MEMSET
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#define SDL_MAIN_NOIMPL // don't drag in header-only implementation of SDL_main
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
|
||||
// These headers have system specific definitions, so aren't included above
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* This is the version of the dynamic API. This doesn't match the SDL version
|
||||
and should not change until there's been a major revamp in API/ABI.
|
||||
So 2.0.5 adds functions over 2.0.4? This number doesn't change;
|
||||
the sizeof(jump_table) changes instead. But 2.1.0 changes how a function
|
||||
works in an incompatible way or removes a function? This number changes,
|
||||
since sizeof(jump_table) isn't sufficient anymore. It's likely
|
||||
we'll forget to bump every time we add a function, so this is the
|
||||
failsafe switch for major API change decisions. Respect it and use it
|
||||
sparingly. */
|
||||
#define SDL_DYNAPI_VERSION 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static void SDL_InitDynamicAPI(void);
|
||||
|
||||
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
|
||||
Even self-contained stuff might call SDL_SetError() and break everything. */
|
||||
|
||||
// behold, the macro salsa!
|
||||
|
||||
// Can't use the macro for varargs nonsense. This is atrocious.
|
||||
#define SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, logname, prio) \
|
||||
_static void SDLCALL SDL_Log##logname##name(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
jump_table.SDL_LogMessageV(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
|
||||
va_end(ap); \
|
||||
}
|
||||
|
||||
#define SDL_DYNAPI_VARARGS(_static, name, initcall) \
|
||||
_static bool SDLCALL SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
char buf[128], *str = buf; \
|
||||
int result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \
|
||||
va_end(ap); \
|
||||
if (result >= 0 && (size_t)result >= sizeof(buf)) { \
|
||||
str = NULL; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vasprintf(&str, fmt, ap); \
|
||||
va_end(ap); \
|
||||
} \
|
||||
if (result >= 0) { \
|
||||
jump_table.SDL_SetError("%s", str); \
|
||||
} \
|
||||
if (str != buf) { \
|
||||
jump_table.SDL_free(str); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
_static int SDLCALL SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
int result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vsscanf(buf, fmt, ap); \
|
||||
va_end(ap); \
|
||||
return result; \
|
||||
} \
|
||||
_static int SDLCALL SDL_snprintf##name(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
int result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vsnprintf(buf, maxlen, fmt, ap); \
|
||||
va_end(ap); \
|
||||
return result; \
|
||||
} \
|
||||
_static int SDLCALL SDL_swprintf##name(SDL_OUT_Z_CAP(maxlen) wchar_t *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const wchar_t *fmt, ...) \
|
||||
{ \
|
||||
int result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vswprintf(buf, maxlen, fmt, ap); \
|
||||
va_end(ap); \
|
||||
return result; \
|
||||
} \
|
||||
_static int SDLCALL SDL_asprintf##name(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
int result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vasprintf(strp, fmt, ap); \
|
||||
va_end(ap); \
|
||||
return result; \
|
||||
} \
|
||||
_static size_t SDLCALL SDL_IOprintf##name(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
size_t result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_IOvprintf(context, fmt, ap); \
|
||||
va_end(ap); \
|
||||
return result; \
|
||||
} \
|
||||
_static bool SDLCALL SDL_RenderDebugTextFormat##name(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
char buf[128], *str = buf; \
|
||||
int result; \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap); \
|
||||
va_end(ap); \
|
||||
if (result >= 0 && (size_t)result >= sizeof(buf)) { \
|
||||
str = NULL; \
|
||||
va_start(ap, fmt); \
|
||||
result = jump_table.SDL_vasprintf(&str, fmt, ap); \
|
||||
va_end(ap); \
|
||||
} \
|
||||
bool retval = false; \
|
||||
if (result >= 0) { \
|
||||
retval = jump_table.SDL_RenderDebugTextFormat(renderer, x, y, "%s", str); \
|
||||
} \
|
||||
if (str != buf) { \
|
||||
jump_table.SDL_free(str); \
|
||||
} \
|
||||
return retval; \
|
||||
} \
|
||||
_static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
jump_table.SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \
|
||||
va_end(ap); \
|
||||
} \
|
||||
_static void SDLCALL SDL_LogMessage##name(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
va_list ap; \
|
||||
initcall; \
|
||||
va_start(ap, fmt); \
|
||||
jump_table.SDL_LogMessageV(category, priority, fmt, ap); \
|
||||
va_end(ap); \
|
||||
} \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Trace, TRACE) \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Warn, WARN) \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Error, ERROR) \
|
||||
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Critical, CRITICAL)
|
||||
|
||||
// Typedefs for function pointers for jump table, and predeclare funcs
|
||||
// The DEFAULT funcs will init jump table and then call real function.
|
||||
// The REAL funcs are the actual functions, name-mangled to not clash.
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \
|
||||
typedef rc (SDLCALL *SDL_DYNAPIFN_##fn) params;\
|
||||
static rc SDLCALL fn##_DEFAULT params; \
|
||||
extern rc SDLCALL fn##_REAL params;
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
|
||||
// The jump table!
|
||||
typedef struct
|
||||
{
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) SDL_DYNAPIFN_##fn fn;
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
} SDL_DYNAPI_jump_table;
|
||||
|
||||
// The actual jump table.
|
||||
static SDL_DYNAPI_jump_table jump_table = {
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) fn##_DEFAULT,
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
};
|
||||
|
||||
// Default functions init the function table then call right thing.
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \
|
||||
static rc SDLCALL fn##_DEFAULT params \
|
||||
{ \
|
||||
SDL_InitDynamicAPI(); \
|
||||
ret jump_table.fn args; \
|
||||
}
|
||||
#define SDL_DYNAPI_PROC_NO_VARARGS 1
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
#undef SDL_DYNAPI_PROC_NO_VARARGS
|
||||
SDL_DYNAPI_VARARGS(static, _DEFAULT, SDL_InitDynamicAPI())
|
||||
|
||||
// Public API functions to jump into the jump table.
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \
|
||||
rc SDLCALL fn params \
|
||||
{ \
|
||||
ret jump_table.fn args; \
|
||||
}
|
||||
#define SDL_DYNAPI_PROC_NO_VARARGS 1
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
#undef SDL_DYNAPI_PROC_NO_VARARGS
|
||||
SDL_DYNAPI_VARARGS(, , )
|
||||
|
||||
#define ENABLE_SDL_CALL_LOGGING 0
|
||||
#if ENABLE_SDL_CALL_LOGGING
|
||||
static bool SDLCALL SDL_SetError_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
char buf[512]; // !!! FIXME: dynamic allocation
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_SetError");
|
||||
va_start(ap, fmt);
|
||||
SDL_vsnprintf_REAL(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
return SDL_SetError_REAL("%s", buf);
|
||||
}
|
||||
static int SDLCALL SDL_sscanf_LOGSDLCALLS(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
int result;
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_sscanf");
|
||||
va_start(ap, fmt);
|
||||
result = SDL_vsscanf_REAL(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
static int SDLCALL SDL_snprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
int result;
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_snprintf");
|
||||
va_start(ap, fmt);
|
||||
result = SDL_vsnprintf_REAL(buf, maxlen, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
static int SDLCALL SDL_asprintf_LOGSDLCALLS(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
int result;
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_asprintf");
|
||||
va_start(ap, fmt);
|
||||
result = SDL_vasprintf_REAL(strp, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
static int SDLCALL SDL_swprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) wchar_t *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const wchar_t *fmt, ...)
|
||||
{
|
||||
int result;
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_swprintf");
|
||||
va_start(ap, fmt);
|
||||
result = SDL_vswprintf_REAL(buf, maxlen, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
static size_t SDLCALL SDL_IOprintf_LOGSDLCALLS(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
size_t result;
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_IOprintf");
|
||||
va_start(ap, fmt);
|
||||
result = SDL_IOvprintf_REAL(context, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
static bool SDLCALL SDL_RenderDebugTextFormat_LOGSDLCALLS(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
char buf[128], *str = buf;
|
||||
int result;
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_RenderDebugTextFormat");
|
||||
va_start(ap, fmt);
|
||||
result = jump_table.SDL_vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
if (result >= 0 && (size_t)result >= sizeof(buf)) {
|
||||
str = NULL;
|
||||
va_start(ap, fmt);
|
||||
result = SDL_vasprintf_REAL(&str, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
bool retval = false;
|
||||
if (result >= 0) {
|
||||
retval = SDL_RenderDebugTextFormat_REAL(renderer, x, y, "%s", str);
|
||||
}
|
||||
if (str != buf) {
|
||||
jump_table.SDL_free(str);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
static void SDLCALL SDL_Log_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_Log");
|
||||
va_start(ap, fmt);
|
||||
SDL_LogMessageV_REAL(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
static void SDLCALL SDL_LogMessage_LOGSDLCALLS(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
SDL_Log_REAL("SDL3CALL SDL_LogMessage");
|
||||
va_start(ap, fmt);
|
||||
SDL_LogMessageV_REAL(category, priority, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#define SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(logname, prio) \
|
||||
static void SDLCALL SDL_Log##logname##_LOGSDLCALLS(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \
|
||||
{ \
|
||||
va_list ap; \
|
||||
va_start(ap, fmt); \
|
||||
SDL_Log_REAL("SDL3CALL SDL_Log%s", #logname); \
|
||||
SDL_LogMessageV_REAL(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
|
||||
va_end(ap); \
|
||||
}
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Trace, TRACE)
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Verbose, VERBOSE)
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Debug, DEBUG)
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Info, INFO)
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Warn, WARN)
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Error, ERROR)
|
||||
SDL_DYNAPI_VARARGS_LOGFN_LOGSDLCALLS(Critical, CRITICAL)
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) \
|
||||
rc SDLCALL fn##_LOGSDLCALLS params \
|
||||
{ \
|
||||
SDL_Log_REAL("SDL3CALL %s", #fn); \
|
||||
ret fn##_REAL args; \
|
||||
}
|
||||
#define SDL_DYNAPI_PROC_NO_VARARGS 1
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
#undef SDL_DYNAPI_PROC_NO_VARARGS
|
||||
#endif
|
||||
|
||||
/* we make this a static function so we can call the correct one without the
|
||||
system's dynamic linker resolving to the wrong version of this. */
|
||||
static Sint32 initialize_jumptable(Uint32 apiver, void *table, Uint32 tablesize)
|
||||
{
|
||||
SDL_DYNAPI_jump_table *output_jump_table = (SDL_DYNAPI_jump_table *)table;
|
||||
|
||||
if (apiver != SDL_DYNAPI_VERSION) {
|
||||
// !!! FIXME: can maybe handle older versions?
|
||||
return -1; // not compatible.
|
||||
} else if (tablesize > sizeof(jump_table)) {
|
||||
return -1; // newer version of SDL with functions we can't provide.
|
||||
}
|
||||
|
||||
// Init our jump table first.
|
||||
#if ENABLE_SDL_CALL_LOGGING
|
||||
{
|
||||
const char *env = SDL_getenv_unsafe_REAL("SDL_DYNAPI_LOG_CALLS");
|
||||
const bool log_calls = (env && SDL_atoi_REAL(env));
|
||||
if (log_calls) {
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_LOGSDLCALLS;
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
} else {
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_REAL;
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_REAL;
|
||||
#include "SDL_dynapi_procs.h"
|
||||
#undef SDL_DYNAPI_PROC
|
||||
#endif
|
||||
|
||||
// Then the external table...
|
||||
if (output_jump_table != &jump_table) {
|
||||
jump_table.SDL_memcpy(output_jump_table, &jump_table, tablesize);
|
||||
}
|
||||
|
||||
// Safe to call SDL functions now; jump table is initialized!
|
||||
|
||||
return 0; // success!
|
||||
}
|
||||
|
||||
// Here's the exported entry point that fills in the jump table.
|
||||
// Use specific types when an "int" might suffice to keep this sane.
|
||||
typedef Sint32 (SDLCALL *SDL_DYNAPI_ENTRYFN)(Uint32 apiver, void *table, Uint32 tablesize);
|
||||
extern SDL_DECLSPEC Sint32 SDLCALL SDL_DYNAPI_entry(Uint32, void *, Uint32);
|
||||
|
||||
Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
|
||||
{
|
||||
return initialize_jumptable(apiver, table, tablesize);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Obviously we can't use SDL_LoadObject() to load SDL. :)
|
||||
// Also obviously, we never close the loaded library.
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)
|
||||
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
|
||||
{
|
||||
HMODULE lib = LoadLibraryA(fname);
|
||||
void *result = NULL;
|
||||
if (lib) {
|
||||
result = (void *) GetProcAddress(lib, sym);
|
||||
if (!result) {
|
||||
FreeLibrary(lib);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE) || defined(SDL_PLATFORM_HAIKU)
|
||||
#include <dlfcn.h>
|
||||
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
|
||||
{
|
||||
void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
|
||||
void *result = NULL;
|
||||
if (lib) {
|
||||
result = dlsym(lib, sym);
|
||||
if (!result) {
|
||||
dlclose(lib);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
#error Please define your platform.
|
||||
#endif
|
||||
|
||||
static void dynapi_warn(const char *msg)
|
||||
{
|
||||
const char *caption = "SDL Dynamic API Failure!";
|
||||
(void)caption;
|
||||
// SDL_ShowSimpleMessageBox() is a too heavy for here.
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR);
|
||||
#elif defined(HAVE_STDIO_H)
|
||||
fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This is not declared in any header, although it is shared between some
|
||||
parts of SDL, because we don't want anything calling it without an
|
||||
extremely good reason. */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
|
||||
#ifdef __WATCOMC__
|
||||
#pragma aux SDL_ExitProcess aborts;
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SDL_InitDynamicAPILocked(void)
|
||||
{
|
||||
// this can't use SDL_getenv_unsafe_REAL, because it might allocate memory before the app can set their allocator.
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
// We've always used LoadLibraryA for this, so this has never worked with Unicode paths on Windows. Sorry.
|
||||
char envbuf[512]; // overflows will just report as environment variable being unset, but LoadLibraryA has a MAX_PATH of 260 anyhow, apparently.
|
||||
const DWORD rc = GetEnvironmentVariableA(SDL_DYNAMIC_API_ENVVAR, envbuf, (DWORD) sizeof (envbuf));
|
||||
char *libname = ((rc != 0) && (rc < sizeof (envbuf))) ? envbuf : NULL;
|
||||
#else
|
||||
char *libname = getenv(SDL_DYNAMIC_API_ENVVAR);
|
||||
#endif
|
||||
|
||||
SDL_DYNAPI_ENTRYFN entry = NULL; // funcs from here by default.
|
||||
bool use_internal = true;
|
||||
|
||||
if (libname) {
|
||||
while (*libname && !entry) {
|
||||
// This is evil, but we're not making any permanent changes...
|
||||
char *ptr = (char *)libname;
|
||||
while (true) {
|
||||
char ch = *ptr;
|
||||
if ((ch == ',') || (ch == '\0')) {
|
||||
*ptr = '\0';
|
||||
entry = (SDL_DYNAPI_ENTRYFN)get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
|
||||
*ptr = ch;
|
||||
libname = (ch == '\0') ? ptr : (ptr + 1);
|
||||
break;
|
||||
} else {
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!entry) {
|
||||
dynapi_warn("Couldn't load an overriding SDL library. Please fix or remove the " SDL_DYNAMIC_API_ENVVAR " environment variable. Using the default SDL.");
|
||||
// Just fill in the function pointers from this library, later.
|
||||
}
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof(jump_table)) < 0) {
|
||||
dynapi_warn("Couldn't override SDL library. Using a newer SDL build might help. Please fix or remove the " SDL_DYNAMIC_API_ENVVAR " environment variable. Using the default SDL.");
|
||||
// Just fill in the function pointers from this library, later.
|
||||
} else {
|
||||
use_internal = false; // We overrode SDL! Don't use the internal version!
|
||||
}
|
||||
}
|
||||
|
||||
// Just fill in the function pointers from this library.
|
||||
if (use_internal) {
|
||||
if (initialize_jumptable(SDL_DYNAPI_VERSION, &jump_table, sizeof(jump_table)) < 0) {
|
||||
// Now we're screwed. Should definitely abort now.
|
||||
dynapi_warn("Failed to initialize internal SDL dynapi. As this would otherwise crash, we have to abort now.");
|
||||
#ifndef NDEBUG
|
||||
SDL_TriggerBreakpoint();
|
||||
#endif
|
||||
SDL_ExitProcess(86);
|
||||
}
|
||||
}
|
||||
|
||||
// we intentionally never close the newly-loaded lib, of course.
|
||||
}
|
||||
|
||||
static void SDL_InitDynamicAPI(void)
|
||||
{
|
||||
/* So the theory is that every function in the jump table defaults to
|
||||
* calling this function, and then replaces itself with a version that
|
||||
* doesn't call this function anymore. But it's possible that, in an
|
||||
* extreme corner case, you can have a second thread hit this function
|
||||
* while the jump table is being initialized by the first.
|
||||
* In this case, a spinlock is really painful compared to what spinlocks
|
||||
* _should_ be used for, but this would only happen once, and should be
|
||||
* insanely rare, as you would have to spin a thread outside of SDL (as
|
||||
* SDL_CreateThread() would also call this function before building the
|
||||
* new thread).
|
||||
*/
|
||||
static bool already_initialized = false;
|
||||
|
||||
static SDL_SpinLock lock = 0;
|
||||
SDL_LockSpinlock_REAL(&lock);
|
||||
|
||||
if (!already_initialized) {
|
||||
SDL_InitDynamicAPILocked();
|
||||
already_initialized = true;
|
||||
}
|
||||
|
||||
SDL_UnlockSpinlock_REAL(&lock);
|
||||
}
|
||||
|
||||
#else // SDL_DYNAMIC_API
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize);
|
||||
Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
|
||||
{
|
||||
(void)apiver;
|
||||
(void)table;
|
||||
(void)tablesize;
|
||||
return -1; // not compatible.
|
||||
}
|
||||
|
||||
#endif // SDL_DYNAMIC_API
|
||||
75
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi.h
vendored
Normal file
75
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi.h
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_dynapi_h_
|
||||
#define SDL_dynapi_h_
|
||||
|
||||
/* IMPORTANT:
|
||||
This is the master switch to disabling the dynamic API. We made it so you
|
||||
have to hand-edit an internal source file in SDL to turn it off; you
|
||||
can do it if you want it badly enough, but hopefully you won't want to.
|
||||
You should understand the ramifications of turning this off: it makes it
|
||||
hard to update your SDL in the field, and impossible if you've statically
|
||||
linked SDL into your app. Understand that platforms change, and if we can't
|
||||
drop in an updated SDL, your application can definitely break some time
|
||||
in the future, even if it's fine today.
|
||||
To be sure, as new system-level video and audio APIs are introduced, an
|
||||
updated SDL can transparently take advantage of them, but your program will
|
||||
not without this feature. Think hard before turning it off.
|
||||
*/
|
||||
#ifdef SDL_DYNAMIC_API // Tried to force it on the command line?
|
||||
#error Nope, you have to edit this file to force this off.
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_APPLE
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
|
||||
#if defined(SDL_PLATFORM_PRIVATE) // probably not useful on private platforms.
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE // probably not useful on iOS.
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(SDL_PLATFORM_ANDROID) // probably not useful on Android.
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(SDL_PLATFORM_EMSCRIPTEN) // probably not useful on Emscripten.
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(SDL_PLATFORM_PS2) && SDL_PLATFORM_PS2
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(SDL_PLATFORM_PSP) && SDL_PLATFORM_PSP
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(SDL_PLATFORM_RISCOS) // probably not useful on RISC OS, since dlopen() can't be used when using static linking.
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif defined(__clang_analyzer__) || defined(__INTELLISENSE__) || defined(SDL_THREAD_SAFETY_ANALYSIS)
|
||||
#define SDL_DYNAMIC_API 0 // Turn off for static analysis, so reports are more clear.
|
||||
#elif defined(SDL_PLATFORM_VITA)
|
||||
#define SDL_DYNAMIC_API 0 // vitasdk doesn't support dynamic linking
|
||||
#elif defined(SDL_PLATFORM_3DS)
|
||||
#define SDL_DYNAMIC_API 0 // devkitARM doesn't support dynamic linking
|
||||
#elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN)
|
||||
#define SDL_DYNAMIC_API 0 // we need dlopen(), but don't have it....
|
||||
#endif
|
||||
|
||||
// everyone else. This is where we turn on the API if nothing forced it off.
|
||||
#ifndef SDL_DYNAMIC_API
|
||||
#define SDL_DYNAMIC_API 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1239
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi.sym
vendored
Normal file
1239
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi.sym
vendored
Normal file
File diff suppressed because it is too large
Load diff
1261
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi_overrides.h
vendored
Normal file
1261
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi_overrides.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1269
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi_procs.h
vendored
Normal file
1269
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi_procs.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
52
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi_unsupported.h
vendored
Normal file
52
vendor/sdl-3.2.10/src/dynapi/SDL_dynapi_unsupported.h
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_dynapi_unsupported_h_
|
||||
#define SDL_dynapi_unsupported_h_
|
||||
|
||||
|
||||
#if !defined(SDL_PLATFORM_WINDOWS)
|
||||
typedef struct ID3D12Device ID3D12Device;
|
||||
typedef void *SDL_WindowsMessageHook;
|
||||
#endif
|
||||
|
||||
#if !(defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK))
|
||||
typedef struct ID3D11Device ID3D11Device;
|
||||
typedef struct IDirect3DDevice9 IDirect3DDevice9;
|
||||
#endif
|
||||
|
||||
#ifndef SDL_PLATFORM_GDK
|
||||
typedef struct XTaskQueueHandle XTaskQueueHandle;
|
||||
#endif
|
||||
|
||||
#ifndef SDL_PLATFORM_GDK
|
||||
typedef struct XUserHandle XUserHandle;
|
||||
#endif
|
||||
|
||||
#ifndef SDL_PLATFORM_ANDROID
|
||||
typedef void *SDL_RequestAndroidPermissionCallback;
|
||||
#endif
|
||||
|
||||
#ifndef SDL_PLATFORM_IOS
|
||||
typedef void *SDL_iOSAnimationCallback;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
547
vendor/sdl-3.2.10/src/dynapi/gendynapi.py
vendored
Executable file
547
vendor/sdl-3.2.10/src/dynapi/gendynapi.py
vendored
Executable file
|
|
@ -0,0 +1,547 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Simple DirectMedia Layer
|
||||
# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
# WHAT IS THIS?
|
||||
# When you add a public API to SDL, please run this script, make sure the
|
||||
# output looks sane (git diff, it adds to existing files), and commit it.
|
||||
# It keeps the dynamic API jump table operating correctly.
|
||||
#
|
||||
# Platform-specific API:
|
||||
# After running the script, you have to manually add #ifdef SDL_PLATFORM_WIN32
|
||||
# or similar around the function in 'SDL_dynapi_procs.h'.
|
||||
#
|
||||
|
||||
import argparse
|
||||
import dataclasses
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import pprint
|
||||
import re
|
||||
|
||||
|
||||
SDL_ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3"
|
||||
SDL_DYNAPI_PROCS_H = SDL_ROOT / "src/dynapi/SDL_dynapi_procs.h"
|
||||
SDL_DYNAPI_OVERRIDES_H = SDL_ROOT / "src/dynapi/SDL_dynapi_overrides.h"
|
||||
SDL_DYNAPI_SYM = SDL_ROOT / "src/dynapi/SDL_dynapi.sym"
|
||||
|
||||
RE_EXTERN_C = re.compile(r'.*extern[ "]*C[ "].*')
|
||||
RE_COMMENT_REMOVE_CONTENT = re.compile(r'\/\*.*\*/')
|
||||
RE_PARSING_FUNCTION = re.compile(r'(.*SDLCALL[^\(\)]*) ([a-zA-Z0-9_]+) *\((.*)\) *;.*')
|
||||
|
||||
#eg:
|
||||
# void (SDLCALL *callback)(void*, int)
|
||||
# \1(\2)\3
|
||||
RE_PARSING_CALLBACK = re.compile(r'([^\(\)]*)\(([^\(\)]+)\)(.*)')
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class SdlProcedure:
|
||||
retval: str
|
||||
name: str
|
||||
parameter: list[str]
|
||||
parameter_name: list[str]
|
||||
header: str
|
||||
comment: str
|
||||
|
||||
@property
|
||||
def variadic(self) -> bool:
|
||||
return "..." in self.parameter
|
||||
|
||||
|
||||
def parse_header(header_path: Path) -> list[SdlProcedure]:
|
||||
logger.debug("Parse header: %s", header_path)
|
||||
|
||||
header_procedures = []
|
||||
|
||||
parsing_function = False
|
||||
current_func = ""
|
||||
parsing_comment = False
|
||||
current_comment = ""
|
||||
ignore_wiki_documentation = False
|
||||
|
||||
with header_path.open() as f:
|
||||
for line in f:
|
||||
|
||||
# Skip lines if we're in a wiki documentation block.
|
||||
if ignore_wiki_documentation:
|
||||
if line.startswith("#endif"):
|
||||
ignore_wiki_documentation = False
|
||||
continue
|
||||
|
||||
# Discard wiki documentations blocks.
|
||||
if line.startswith("#ifdef SDL_WIKI_DOCUMENTATION_SECTION"):
|
||||
ignore_wiki_documentation = True
|
||||
continue
|
||||
|
||||
# Discard pre-processor directives ^#.*
|
||||
if line.startswith("#"):
|
||||
continue
|
||||
|
||||
# Discard "extern C" line
|
||||
match = RE_EXTERN_C.match(line)
|
||||
if match:
|
||||
continue
|
||||
|
||||
# Remove one line comment // ...
|
||||
# eg: extern SDL_DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open_path(const char *path, int bExclusive /* = false */)
|
||||
line = RE_COMMENT_REMOVE_CONTENT.sub('', line)
|
||||
|
||||
# Get the comment block /* ... */ across several lines
|
||||
match_start = "/*" in line
|
||||
match_end = "*/" in line
|
||||
if match_start and match_end:
|
||||
continue
|
||||
if match_start:
|
||||
parsing_comment = True
|
||||
current_comment = line
|
||||
continue
|
||||
if match_end:
|
||||
parsing_comment = False
|
||||
current_comment += line
|
||||
continue
|
||||
if parsing_comment:
|
||||
current_comment += line
|
||||
continue
|
||||
|
||||
# Get the function prototype across several lines
|
||||
if parsing_function:
|
||||
# Append to the current function
|
||||
current_func += " "
|
||||
current_func += line.strip()
|
||||
else:
|
||||
# if is contains "extern", start grabbing
|
||||
if "extern" not in line:
|
||||
continue
|
||||
# Start grabbing the new function
|
||||
current_func = line.strip()
|
||||
parsing_function = True
|
||||
|
||||
# If it contains ';', then the function is complete
|
||||
if ";" not in current_func:
|
||||
continue
|
||||
|
||||
# Got function/comment, reset vars
|
||||
parsing_function = False
|
||||
func = current_func
|
||||
comment = current_comment
|
||||
current_func = ""
|
||||
current_comment = ""
|
||||
|
||||
# Discard if it doesn't contain 'SDLCALL'
|
||||
if "SDLCALL" not in func:
|
||||
logger.debug(" Discard, doesn't have SDLCALL: %r", func)
|
||||
continue
|
||||
|
||||
# Discard if it contains 'SDLMAIN_DECLSPEC' (these are not SDL symbols).
|
||||
if "SDLMAIN_DECLSPEC" in func:
|
||||
logger.debug(" Discard, has SDLMAIN_DECLSPEC: %r", func)
|
||||
continue
|
||||
|
||||
logger.debug("Raw data: %r", func)
|
||||
|
||||
# Replace unusual stuff...
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNC(1)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNC(2)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNC(3)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNC(4)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(1)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(2)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(3)", "")
|
||||
func = func.replace(" SDL_PRINTF_VARARG_FUNCV(4)", "")
|
||||
func = func.replace(" SDL_WPRINTF_VARARG_FUNC(3)", "")
|
||||
func = func.replace(" SDL_WPRINTF_VARARG_FUNCV(3)", "")
|
||||
func = func.replace(" SDL_SCANF_VARARG_FUNC(2)", "")
|
||||
func = func.replace(" SDL_SCANF_VARARG_FUNCV(2)", "")
|
||||
func = func.replace(" SDL_ANALYZER_NORETURN", "")
|
||||
func = func.replace(" SDL_MALLOC", "")
|
||||
func = func.replace(" SDL_ALLOC_SIZE2(1, 2)", "")
|
||||
func = func.replace(" SDL_ALLOC_SIZE(2)", "")
|
||||
func = re.sub(r" SDL_ACQUIRE\(.*\)", "", func)
|
||||
func = re.sub(r" SDL_ACQUIRE_SHARED\(.*\)", "", func)
|
||||
func = re.sub(r" SDL_TRY_ACQUIRE\(.*\)", "", func)
|
||||
func = re.sub(r" SDL_TRY_ACQUIRE_SHARED\(.*\)", "", func)
|
||||
func = re.sub(r" SDL_RELEASE\(.*\)", "", func)
|
||||
func = re.sub(r" SDL_RELEASE_SHARED\(.*\)", "", func)
|
||||
func = re.sub(r" SDL_RELEASE_GENERIC\(.*\)", "", func)
|
||||
func = re.sub(r"([ (),])(SDL_IN_BYTECAP\([^)]*\))", r"\1", func)
|
||||
func = re.sub(r"([ (),])(SDL_OUT_BYTECAP\([^)]*\))", r"\1", func)
|
||||
func = re.sub(r"([ (),])(SDL_INOUT_Z_CAP\([^)]*\))", r"\1", func)
|
||||
func = re.sub(r"([ (),])(SDL_OUT_Z_CAP\([^)]*\))", r"\1", func)
|
||||
|
||||
# Should be a valid function here
|
||||
match = RE_PARSING_FUNCTION.match(func)
|
||||
if not match:
|
||||
logger.error("Cannot parse: %s", func)
|
||||
raise ValueError(func)
|
||||
|
||||
func_ret = match.group(1)
|
||||
func_name = match.group(2)
|
||||
func_params = match.group(3)
|
||||
|
||||
#
|
||||
# Parse return value
|
||||
#
|
||||
func_ret = func_ret.replace('extern', ' ')
|
||||
func_ret = func_ret.replace('SDLCALL', ' ')
|
||||
func_ret = func_ret.replace('SDL_DECLSPEC', ' ')
|
||||
func_ret, _ = re.subn('([ ]{2,})', ' ', func_ret)
|
||||
# Remove trailing spaces in front of '*'
|
||||
func_ret = func_ret.replace(' *', '*')
|
||||
func_ret = func_ret.strip()
|
||||
|
||||
#
|
||||
# Parse parameters
|
||||
#
|
||||
func_params = func_params.strip()
|
||||
if func_params == "":
|
||||
func_params = "void"
|
||||
|
||||
# Identify each function parameters with type and name
|
||||
# (eventually there are callbacks of several parameters)
|
||||
tmp = func_params.split(',')
|
||||
tmp2 = []
|
||||
param = ""
|
||||
for t in tmp:
|
||||
if param == "":
|
||||
param = t
|
||||
else:
|
||||
param = param + "," + t
|
||||
# Identify a callback or parameter when there is same count of '(' and ')'
|
||||
if param.count('(') == param.count(')'):
|
||||
tmp2.append(param.strip())
|
||||
param = ""
|
||||
|
||||
# Process each parameters, separation name and type
|
||||
func_param_type = []
|
||||
func_param_name = []
|
||||
for t in tmp2:
|
||||
if t == "void":
|
||||
func_param_type.append(t)
|
||||
func_param_name.append("")
|
||||
continue
|
||||
|
||||
if t == "...":
|
||||
func_param_type.append(t)
|
||||
func_param_name.append("")
|
||||
continue
|
||||
|
||||
param_name = ""
|
||||
|
||||
# parameter is a callback
|
||||
if '(' in t:
|
||||
match = RE_PARSING_CALLBACK.match(t)
|
||||
if not match:
|
||||
logger.error("cannot parse callback: %s", t)
|
||||
raise ValueError(t)
|
||||
a = match.group(1).strip()
|
||||
b = match.group(2).strip()
|
||||
c = match.group(3).strip()
|
||||
|
||||
try:
|
||||
(param_type, param_name) = b.rsplit('*', 1)
|
||||
except:
|
||||
param_type = t
|
||||
param_name = "param_name_not_specified"
|
||||
|
||||
# bug rsplit ??
|
||||
if param_name == "":
|
||||
param_name = "param_name_not_specified"
|
||||
|
||||
# reconstruct a callback name for future parsing
|
||||
func_param_type.append(a + " (" + param_type.strip() + " *REWRITE_NAME)" + c)
|
||||
func_param_name.append(param_name.strip())
|
||||
|
||||
continue
|
||||
|
||||
# array like "char *buf[]"
|
||||
has_array = False
|
||||
if t.endswith("[]"):
|
||||
t = t.replace("[]", "")
|
||||
has_array = True
|
||||
|
||||
# pointer
|
||||
if '*' in t:
|
||||
try:
|
||||
(param_type, param_name) = t.rsplit('*', 1)
|
||||
except:
|
||||
param_type = t
|
||||
param_name = "param_name_not_specified"
|
||||
|
||||
# bug rsplit ??
|
||||
if param_name == "":
|
||||
param_name = "param_name_not_specified"
|
||||
|
||||
val = param_type.strip() + "*REWRITE_NAME"
|
||||
|
||||
# Remove trailing spaces in front of '*'
|
||||
tmp = ""
|
||||
while val != tmp:
|
||||
tmp = val
|
||||
val = val.replace(' ', ' ')
|
||||
val = val.replace(' *', '*')
|
||||
# first occurrence
|
||||
val = val.replace('*', ' *', 1)
|
||||
val = val.strip()
|
||||
|
||||
else: # non pointer
|
||||
# cut-off last word on
|
||||
try:
|
||||
(param_type, param_name) = t.rsplit(' ', 1)
|
||||
except:
|
||||
param_type = t
|
||||
param_name = "param_name_not_specified"
|
||||
|
||||
val = param_type.strip() + " REWRITE_NAME"
|
||||
|
||||
# set back array
|
||||
if has_array:
|
||||
val += "[]"
|
||||
|
||||
func_param_type.append(val)
|
||||
func_param_name.append(param_name.strip())
|
||||
|
||||
new_proc = SdlProcedure(
|
||||
retval=func_ret, # Return value type
|
||||
name=func_name, # Function name
|
||||
comment=comment, # Function comment
|
||||
header=header_path.name, # Header file
|
||||
parameter=func_param_type, # List of parameters (type + anonymized param name 'REWRITE_NAME')
|
||||
parameter_name=func_param_name, # Real parameter name, or 'param_name_not_specified'
|
||||
)
|
||||
|
||||
header_procedures.append(new_proc)
|
||||
|
||||
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
logger.debug("%s", pprint.pformat(new_proc))
|
||||
|
||||
return header_procedures
|
||||
|
||||
|
||||
# Dump API into a json file
|
||||
def full_API_json(path: Path, procedures: list[SdlProcedure]):
|
||||
with path.open('w', newline='') as f:
|
||||
json.dump([dataclasses.asdict(proc) for proc in procedures], f, indent=4, sort_keys=True)
|
||||
logger.info("dump API to '%s'", path)
|
||||
|
||||
|
||||
class CallOnce:
|
||||
def __init__(self, cb):
|
||||
self._cb = cb
|
||||
self._called = False
|
||||
def __call__(self, *args, **kwargs):
|
||||
if self._called:
|
||||
return
|
||||
self._called = True
|
||||
self._cb(*args, **kwargs)
|
||||
|
||||
|
||||
# Check public function comments are correct
|
||||
def print_check_comment_header():
|
||||
logger.warning("")
|
||||
logger.warning("Please fix following warning(s):")
|
||||
logger.warning("--------------------------------")
|
||||
|
||||
|
||||
def check_documentations(procedures: list[SdlProcedure]) -> None:
|
||||
|
||||
check_comment_header = CallOnce(print_check_comment_header)
|
||||
|
||||
warning_header_printed = False
|
||||
|
||||
# Check \param
|
||||
for proc in procedures:
|
||||
expected = len(proc.parameter)
|
||||
if expected == 1:
|
||||
if proc.parameter[0] == 'void':
|
||||
expected = 0
|
||||
count = proc.comment.count("\\param")
|
||||
if count != expected:
|
||||
# skip SDL_stdinc.h
|
||||
if proc.header != 'SDL_stdinc.h':
|
||||
# Warning mismatch \param and function prototype
|
||||
check_comment_header()
|
||||
logger.warning(" In file %s: function %s() has %d '\\param' but expected %d", proc.header, proc.name, count, expected)
|
||||
|
||||
# Warning check \param uses the correct parameter name
|
||||
# skip SDL_stdinc.h
|
||||
if proc.header != 'SDL_stdinc.h':
|
||||
for n in proc.parameter_name:
|
||||
if n != "" and "\\param " + n not in proc.comment and "\\param[out] " + n not in proc.comment:
|
||||
check_comment_header()
|
||||
logger.warning(" In file %s: function %s() missing '\\param %s'", proc.header, proc.name, n)
|
||||
|
||||
# Check \returns
|
||||
for proc in procedures:
|
||||
expected = 1
|
||||
if proc.retval == 'void':
|
||||
expected = 0
|
||||
|
||||
count = proc.comment.count("\\returns")
|
||||
if count != expected:
|
||||
# skip SDL_stdinc.h
|
||||
if proc.header != 'SDL_stdinc.h':
|
||||
# Warning mismatch \param and function prototype
|
||||
check_comment_header()
|
||||
logger.warning(" In file %s: function %s() has %d '\\returns' but expected %d" % (proc.header, proc.name, count, expected))
|
||||
|
||||
# Check \since
|
||||
for proc in procedures:
|
||||
expected = 1
|
||||
count = proc.comment.count("\\since")
|
||||
if count != expected:
|
||||
# skip SDL_stdinc.h
|
||||
if proc.header != 'SDL_stdinc.h':
|
||||
# Warning mismatch \param and function prototype
|
||||
check_comment_header()
|
||||
logger.warning(" In file %s: function %s() has %d '\\since' but expected %d" % (proc.header, proc.name, count, expected))
|
||||
|
||||
|
||||
# Parse 'sdl_dynapi_procs_h' file to find existing functions
|
||||
def find_existing_proc_names() -> list[str]:
|
||||
reg = re.compile(r'SDL_DYNAPI_PROC\([^,]*,([^,]*),.*\)')
|
||||
ret = []
|
||||
|
||||
with SDL_DYNAPI_PROCS_H.open() as f:
|
||||
for line in f:
|
||||
match = reg.match(line)
|
||||
if not match:
|
||||
continue
|
||||
existing_func = match.group(1)
|
||||
ret.append(existing_func)
|
||||
return ret
|
||||
|
||||
# Get list of SDL headers
|
||||
def get_header_list() -> list[Path]:
|
||||
ret = []
|
||||
|
||||
for f in SDL_INCLUDE_DIR.iterdir():
|
||||
# Only *.h files
|
||||
if f.is_file() and f.suffix == ".h":
|
||||
ret.append(f)
|
||||
else:
|
||||
logger.debug("Skip %s", f)
|
||||
|
||||
# Order headers for reproducible behavior
|
||||
ret.sort()
|
||||
|
||||
return ret
|
||||
|
||||
# Write the new API in files: _procs.h _overrivides.h and .sym
|
||||
def add_dyn_api(proc: SdlProcedure) -> None:
|
||||
decl_args: list[str] = []
|
||||
call_args = []
|
||||
for i, argtype in enumerate(proc.parameter):
|
||||
# Special case, void has no parameter name
|
||||
if argtype == "void":
|
||||
assert len(decl_args) == 0
|
||||
assert len(proc.parameter) == 1
|
||||
decl_args.append("void")
|
||||
continue
|
||||
|
||||
# Var name: a, b, c, ...
|
||||
varname = chr(ord('a') + i)
|
||||
|
||||
decl_args.append(argtype.replace("REWRITE_NAME", varname))
|
||||
if argtype != "...":
|
||||
call_args.append(varname)
|
||||
|
||||
macro_args = (
|
||||
proc.retval,
|
||||
proc.name,
|
||||
"({})".format(",".join(decl_args)),
|
||||
"({})".format(",".join(call_args)),
|
||||
"" if proc.retval == "void" else "return",
|
||||
)
|
||||
|
||||
# File: SDL_dynapi_procs.h
|
||||
#
|
||||
# Add at last
|
||||
# SDL_DYNAPI_PROC(SDL_EGLConfig,SDL_EGL_GetCurrentConfig,(void),(),return)
|
||||
with SDL_DYNAPI_PROCS_H.open("a", newline="") as f:
|
||||
if proc.variadic:
|
||||
f.write("#ifndef SDL_DYNAPI_PROC_NO_VARARGS\n")
|
||||
f.write(f"SDL_DYNAPI_PROC({','.join(macro_args)})\n")
|
||||
if proc.variadic:
|
||||
f.write("#endif\n")
|
||||
|
||||
# File: SDL_dynapi_overrides.h
|
||||
#
|
||||
# Add at last
|
||||
# "#define SDL_DelayNS SDL_DelayNS_REAL
|
||||
f = open(SDL_DYNAPI_OVERRIDES_H, "a", newline="")
|
||||
f.write(f"#define {proc.name} {proc.name}_REAL\n")
|
||||
f.close()
|
||||
|
||||
# File: SDL_dynapi.sym
|
||||
#
|
||||
# Add before "extra symbols go here" line
|
||||
with SDL_DYNAPI_SYM.open() as f:
|
||||
new_input = []
|
||||
for line in f:
|
||||
if "extra symbols go here" in line:
|
||||
new_input.append(f" {proc.name};\n")
|
||||
new_input.append(line)
|
||||
|
||||
with SDL_DYNAPI_SYM.open('w', newline='') as f:
|
||||
for line in new_input:
|
||||
f.write(line)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.set_defaults(loglevel=logging.INFO)
|
||||
parser.add_argument('--dump', nargs='?', default=None, const="sdl.json", metavar="JSON", help='output all SDL API into a .json file')
|
||||
parser.add_argument('--debug', action='store_const', const=logging.DEBUG, dest="loglevel", help='add debug traces')
|
||||
args = parser.parse_args()
|
||||
|
||||
logging.basicConfig(level=args.loglevel, format='[%(levelname)s] %(message)s')
|
||||
|
||||
# Get list of SDL headers
|
||||
sdl_list_includes = get_header_list()
|
||||
procedures = []
|
||||
for filename in sdl_list_includes:
|
||||
header_procedures = parse_header(filename)
|
||||
procedures.extend(header_procedures)
|
||||
|
||||
# Parse 'sdl_dynapi_procs_h' file to find existing functions
|
||||
existing_proc_names = find_existing_proc_names()
|
||||
for procedure in procedures:
|
||||
if procedure.name not in existing_proc_names:
|
||||
logger.info("NEW %s", procedure.name)
|
||||
add_dyn_api(procedure)
|
||||
|
||||
if args.dump:
|
||||
# Dump API into a json file
|
||||
full_API_json(path=Path(args.dump), procedures=procedures)
|
||||
|
||||
# Check comment formatting
|
||||
check_documentations(procedures)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue