diff --git a/include/SDL3/SDL_process.h b/include/SDL3/SDL_process.h index 2af0bdcc9..17b727c54 100644 --- a/include/SDL3/SDL_process.h +++ b/include/SDL3/SDL_process.h @@ -310,6 +310,46 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ReadProcess(SDL_Process *process, size_t */ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_WriteProcess(SDL_Process *process, const void *ptr, size_t size, SDL_bool closeio); +/** + * Get the SDL_IOStream associated with process standard output. + * + * The process must have been created with I/O enabled. + * + * This is just a convenience function that retrieves the SDL_IOStream from the process `SDL_PROP_PROCESS_STDOUT_POINTER` property. + * + * \param process The process to get the output stream for. + * \returns the output stream or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_CreateProcess + * \sa SDL_CreateProcessWithProperties + */ +extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessOutputStream(SDL_Process *process); + +/** + * Get the SDL_IOStream associated with process standard input. + * + * The process must have been created with I/O enabled. + * + * This is just a convenience function that retrieves the SDL_IOStream from the process `SDL_PROP_PROCESS_STDIN_POINTER` property. + * + * \param process The process to get the input stream for. + * \returns the input stream or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_CreateProcess + * \sa SDL_CreateProcessWithProperties + */ +extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInputStream(SDL_Process *process); + /** * Stop a process. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 21b51d2db..3067f0f4c 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -431,6 +431,8 @@ SDL3_0.0.0 { SDL_GetPreferredLocales; SDL_GetPrimaryDisplay; SDL_GetPrimarySelectionText; + SDL_GetProcessInputStream; + SDL_GetProcessOutputStream; SDL_GetProcessProperties; SDL_GetPropertyType; SDL_GetRGB; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 7aa3c9bdc..f8ad7502a 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -456,6 +456,8 @@ #define SDL_GetPreferredLocales SDL_GetPreferredLocales_REAL #define SDL_GetPrimaryDisplay SDL_GetPrimaryDisplay_REAL #define SDL_GetPrimarySelectionText SDL_GetPrimarySelectionText_REAL +#define SDL_GetProcessInputStream SDL_GetProcessInputStream_REAL +#define SDL_GetProcessOutputStream SDL_GetProcessOutputStream_REAL #define SDL_GetProcessProperties SDL_GetProcessProperties_REAL #define SDL_GetPropertyType SDL_GetPropertyType_REAL #define SDL_GetRGB SDL_GetRGB_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 069d04ccc..1395c28a7 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -476,6 +476,8 @@ SDL_DYNAPI_PROC(char*,SDL_GetPrefPath,(const char *a, const char *b),(a,b),retur SDL_DYNAPI_PROC(SDL_Locale**,SDL_GetPreferredLocales,(int *a),(a),return) SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetPrimaryDisplay,(void),(),return) SDL_DYNAPI_PROC(char*,SDL_GetPrimarySelectionText,(void),(),return) +SDL_DYNAPI_PROC(SDL_IOStream*,SDL_GetProcessInputStream,(SDL_Process *a),(a),return) +SDL_DYNAPI_PROC(SDL_IOStream*,SDL_GetProcessOutputStream,(SDL_Process *a),(a),return) SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetProcessProperties,(SDL_Process *a),(a),return) SDL_DYNAPI_PROC(SDL_PropertyType,SDL_GetPropertyType,(SDL_PropertiesID a, const char *b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_GetRGB,(Uint32 a, const SDL_PixelFormatDetails *b, const SDL_Palette *c, Uint8 *d, Uint8 *e, Uint8 *f),(a,b,c,d,e,f),) diff --git a/src/process/SDL_process.c b/src/process/SDL_process.c index 4f0ca2712..6521b1296 100644 --- a/src/process/SDL_process.c +++ b/src/process/SDL_process.c @@ -153,6 +153,38 @@ done: return result; } +SDL_IOStream *SDL_GetProcessOutputStream(SDL_Process *process) +{ + if (!process) { + SDL_InvalidParamError("process"); + return NULL; + } + + SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL); + if (!io) { + SDL_SetError("Process not created with I/O enabled"); + return NULL; + } + + return io; +} + +SDL_IOStream *SDL_GetProcessInputStream(SDL_Process *process) +{ + if (!process) { + SDL_InvalidParamError("process"); + return NULL; + } + + SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDIN_POINTER, NULL); + if (!io) { + SDL_SetError("Process not created with I/O enabled"); + return NULL; + } + + return io; +} + SDL_bool SDL_KillProcess(SDL_Process *process, SDL_bool force) { if (!process) { diff --git a/test/testprocess.c b/test/testprocess.c index 0c6a13886..cc14fe780 100644 --- a/test/testprocess.c +++ b/test/testprocess.c @@ -172,7 +172,7 @@ static int SDLCALL process_testInheritedEnv(void *arg) pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); - process_stdout = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL); + process_stdout = SDL_GetProcessOutputStream(process); SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream"); if (!process_stdout) { goto failed; @@ -250,7 +250,7 @@ static int SDLCALL process_testNewEnv(void *arg) pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); - process_stdout = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL); + process_stdout = SDL_GetProcessOutputStream(process); SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream"); if (!process_stdout) { goto failed; @@ -326,9 +326,9 @@ static int process_testStdinToStdout(void *arg) pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); - process_stdin = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDIN_POINTER, NULL); + process_stdin = SDL_GetProcessInputStream(process); SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) returns a valid IO stream"); - process_stdout = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL); + process_stdout = SDL_GetProcessOutputStream(process); SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream"); if (!process_stdin || !process_stdout) { goto failed; @@ -370,7 +370,7 @@ static int process_testStdinToStdout(void *arg) /* Closing stdin of `subprocessstdin --stdin-to-stdout` should close the process */ SDL_CloseIO(process_stdin); - process_stdin = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDIN_POINTER, NULL); + process_stdin = SDL_GetProcessInputStream(process); SDLTest_AssertCheck(process_stdin == NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) is cleared after close"); SDLTest_AssertPass("About to wait on process");