diff --git a/include/SDL3/SDL_rwops.h b/include/SDL3/SDL_rwops.h index 26fd5299f..8ecd75f1d 100644 --- a/include/SDL3/SDL_rwops.h +++ b/include/SDL3/SDL_rwops.h @@ -490,11 +490,56 @@ extern DECLSPEC size_t SDLCALL SDL_RWread(SDL_RWops *context, void *ptr, size_t * \sa SDL_RWFromConstMem * \sa SDL_RWFromFile * \sa SDL_RWFromMem + * \sa SDL_RWprint * \sa SDL_RWread * \sa SDL_RWseek */ extern DECLSPEC size_t SDLCALL SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size); +/** + * Print to an SDL_RWops data stream. + * + * This function does formatted printing to the stream. + * + * \param context a pointer to an SDL_RWops structure + * \param fmt a printf() style format string + * \param ... additional parameters matching % tokens in the `fmt` string, if any + * \returns the number of bytes written, or 0 on error; call SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_RWclose + * \sa SDL_RWFromConstMem + * \sa SDL_RWFromFile + * \sa SDL_RWFromMem + * \sa SDL_RWread + * \sa SDL_RWseek + * \sa SDL_RWwrite + */ +extern DECLSPEC size_t SDLCALL SDL_RWprintf(SDL_RWops *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...); + +/** + * Print to an SDL_RWops data stream. + * + * This function does formatted printing to the stream. + * + * \param context a pointer to an SDL_RWops structure + * \param fmt a printf() style format string + * \param ap a variable argument list + * \returns the number of bytes written, or 0 on error; call SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_RWclose + * \sa SDL_RWFromConstMem + * \sa SDL_RWFromFile + * \sa SDL_RWFromMem + * \sa SDL_RWread + * \sa SDL_RWseek + * \sa SDL_RWwrite + */ +extern DECLSPEC size_t SDLCALL SDL_RWvprintf(SDL_RWops *context, const char *fmt, va_list ap); + /** * Close and free an allocated SDL_RWops structure. * diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c index 603ea36a3..23cf60432 100644 --- a/src/dynapi/SDL_dynapi.c +++ b/src/dynapi/SDL_dynapi.c @@ -144,6 +144,16 @@ static void SDL_InitDynamicAPI(void); va_end(ap); \ return retval; \ } \ + _static size_t SDLCALL SDL_RWprintf##name(SDL_RWops *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ + { \ + size_t retval; \ + va_list ap; \ + initcall; \ + va_start(ap, fmt); \ + retval = jump_table.SDL_RWvprintf(context, fmt, ap); \ + va_end(ap); \ + return retval; \ + } \ _static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) \ { \ va_list ap; \ @@ -285,6 +295,16 @@ static int SDLCALL SDL_swprintf_LOGSDLCALLS(SDL_OUT_Z_CAP(maxlen) wchar_t *buf, va_end(ap); return retval; } +_static size_t SDLCALL SDL_RWprintf_LOGSDLCALLS(SDL_RWops *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) +{ + size_t retval; + va_list ap; + SDL_Log_REAL("SDL3CALL SDL_RWprintf"); + va_start(ap, fmt); + retval = SDL_RWvprintf_REAL(context, fmt, ap); + va_end(ap); + return retval; +} static void SDLCALL SDL_Log_LOGSDLCALLS(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { va_list ap; diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 75e19c3c1..fb0a2f38e 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -922,6 +922,8 @@ SDL3_0.0.0 { SDL_ClearProperty; SDL_EnterAppMainCallbacks; SDL_CleanupEvent; + SDL_RWprintf; + SDL_RWvprintf; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 4cfa59166..84d0d91f7 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -947,3 +947,5 @@ #define SDL_ClearProperty SDL_ClearProperty_REAL #define SDL_EnterAppMainCallbacks SDL_EnterAppMainCallbacks_REAL #define SDL_CleanupEvent SDL_CleanupEvent_REAL +#define SDL_RWprintf SDL_RWprintf_REAL +#define SDL_RWvprintf SDL_RWvprintf_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index d73e3e312..5b9dace0f 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -43,6 +43,7 @@ SDL_DYNAPI_PROC(int,SDL_asprintf,(char **a, SDL_PRINTF_FORMAT_STRING const char SDL_DYNAPI_PROC(int,SDL_snprintf,(SDL_OUT_Z_CAP(b) char *a, size_t b, SDL_PRINTF_FORMAT_STRING const char *c, ...),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_swprintf,(SDL_OUT_Z_CAP(b) wchar_t *a, size_t b, SDL_PRINTF_FORMAT_STRING const wchar_t *c, ...),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_sscanf,(const char *a, SDL_SCANF_FORMAT_STRING const char *b, ...),(a,b),return) +SDL_DYNAPI_PROC(size_t,SDL_RWprintf,(SDL_RWops *a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),return) #endif #ifdef SDL_CreateThread @@ -979,3 +980,4 @@ SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetWindowProperties,(SDL_Window *a),(a),ret SDL_DYNAPI_PROC(int,SDL_ClearProperty,(SDL_PropertiesID a, const char *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_EnterAppMainCallbacks,(int a, char *b[], SDL_AppInit_func c, SDL_AppIterate_func d, SDL_AppEvent_func e, SDL_AppQuit_func f),(a,b,c,d,e,f),return) SDL_DYNAPI_PROC(void,SDL_CleanupEvent,(SDL_Event *a),(a),) +SDL_DYNAPI_PROC(size_t,SDL_RWvprintf,(SDL_RWops *a, const char *b, va_list c),(a,b,c),return) diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index 049cf5120..b6f943f1c 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -808,6 +808,35 @@ size_t SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size) return bytes; } +size_t SDL_RWprintf(SDL_RWops *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) +{ + va_list ap; + int size; + char *string = NULL; + size_t bytes; + + va_start(ap, fmt); + size = SDL_vasprintf(&string, fmt, ap); + va_end(ap); + + bytes = SDL_RWwrite(context, string, size); + SDL_free(string); + return bytes; +} + +size_t SDL_RWvprintf(SDL_RWops *context, const char *fmt, va_list ap) +{ + int size; + char *string = NULL; + size_t bytes; + + size = SDL_vasprintf(&string, fmt, ap); + + bytes = SDL_RWwrite(context, string, size); + SDL_free(string); + return bytes; +} + int SDL_RWclose(SDL_RWops *context) { if (!context) { diff --git a/test/testautomation_rwops.c b/test/testautomation_rwops.c index a8cdb903f..59487e364 100644 --- a/test/testautomation_rwops.c +++ b/test/testautomation_rwops.c @@ -110,11 +110,11 @@ static void testGenericRWopsValidations(SDL_RWops *rw, SDL_bool write) SDLTest_AssertPass("Call to SDL_RWseek succeeded"); SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (SDL_RW_SEEK_SET), expected 0, got %" SDL_PRIs64, i); - /* Test write. */ + /* Test write */ s = SDL_RWwrite(rw, RWopsHelloWorldTestString, sizeof(RWopsHelloWorldTestString) - 1); SDLTest_AssertPass("Call to SDL_RWwrite succeeded"); if (write) { - SDLTest_AssertCheck(s == sizeof(RWopsHelloWorldTestString) - 1, "Verify result of writing one byte with SDL_RWwrite, expected 1, got %i", (int)s); + SDLTest_AssertCheck(s == sizeof(RWopsHelloWorldTestString) - 1, "Verify result of writing with SDL_RWwrite, expected %i, got %i", (int)sizeof(RWopsHelloWorldTestString) - 1, (int)s); } else { SDLTest_AssertCheck(s == 0, "Verify result of writing with SDL_RWwrite, expected: 0, got %i", (int)s); } @@ -129,6 +129,37 @@ static void testGenericRWopsValidations(SDL_RWops *rw, SDL_bool write) SDLTest_AssertPass("Call to SDL_RWseek succeeded"); SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (SDL_RW_SEEK_SET), expected 0, got %" SDL_PRIs64, i); + /* Test read */ + s = SDL_RWread(rw, buf, sizeof(RWopsHelloWorldTestString) - 1); + SDLTest_AssertPass("Call to SDL_RWread succeeded"); + SDLTest_AssertCheck( + s == (sizeof(RWopsHelloWorldTestString) - 1), + "Verify result from SDL_RWread, expected %i, got %i", + (int)(sizeof(RWopsHelloWorldTestString) - 1), + (int)s); + SDLTest_AssertCheck( + SDL_memcmp(buf, RWopsHelloWorldTestString, sizeof(RWopsHelloWorldTestString) - 1) == 0, + "Verify read bytes match expected string, expected '%s', got '%s'", RWopsHelloWorldTestString, buf); + + /* Test seek back to start */ + i = SDL_RWseek(rw, 0, SDL_RW_SEEK_SET); + SDLTest_AssertPass("Call to SDL_RWseek succeeded"); + SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (SDL_RW_SEEK_SET), expected 0, got %" SDL_PRIs64, i); + + /* Test printf */ + s = SDL_RWprintf(rw, "%s", RWopsHelloWorldTestString); + SDLTest_AssertPass("Call to SDL_RWprintf succeeded"); + if (write) { + SDLTest_AssertCheck(s == sizeof(RWopsHelloWorldTestString) - 1, "Verify result of writing with SDL_RWprintf, expected %i, got %i", (int)sizeof(RWopsHelloWorldTestString) - 1, (int)s); + } else { + SDLTest_AssertCheck(s == 0, "Verify result of writing with SDL_RWwrite, expected: 0, got %i", (int)s); + } + + /* Test seek back to start */ + i = SDL_RWseek(rw, 0, SDL_RW_SEEK_SET); + SDLTest_AssertPass("Call to SDL_RWseek succeeded"); + SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (SDL_RW_SEEK_SET), expected 0, got %" SDL_PRIs64, i); + /* Test read */ s = SDL_RWread(rw, buf, sizeof(RWopsHelloWorldTestString) - 1); SDLTest_AssertPass("Call to SDL_RWread succeeded");