diff --git a/docs/README-migration.md b/docs/README-migration.md index ee5052dc19..91e8376e7a 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -802,10 +802,9 @@ On Haiku OS, SDL no longer sets the current working directory to the executable' ```c { - char *path = SDL_GetBasePath(); + const char *path = SDL_GetBasePath(); if (path) { chdir(path); - SDL_free(path); } } ``` diff --git a/include/SDL3/SDL_filesystem.h b/include/SDL3/SDL_filesystem.h index c3bda170fa..26d6401163 100644 --- a/include/SDL3/SDL_filesystem.h +++ b/include/SDL3/SDL_filesystem.h @@ -41,8 +41,8 @@ extern "C" { /** * Get the directory where the application was run from. * - * This is not necessarily a fast call, so you should call this once near - * startup and save the string if you need it. + * SDL caches the result of this call internally, but the first call to this + * function is not necessarily fast, so plan accordingly. * * **macOS and iOS Specific Functionality**: If the application is in a ".app" * bundle, this function returns the Resource directory (e.g. @@ -68,8 +68,7 @@ extern "C" { * The returned path is guaranteed to end with a path separator ('\\' on * Windows, '/' on most other platforms). * - * The pointer returned is owned by the caller. Please call SDL_free() on the - * pointer when done with it. + * The returned string follows the SDL_GetStringRule. * * \returns an absolute path in UTF-8 encoding to the application data * directory. NULL will be returned on error or when the platform @@ -80,7 +79,7 @@ extern "C" { * * \sa SDL_GetPrefPath */ -extern SDL_DECLSPEC char *SDLCALL SDL_GetBasePath(void); +extern SDL_DECLSPEC const char *SDLCALL SDL_GetBasePath(void); /** * Get the user-and-app-specific path where files can be written. diff --git a/src/SDL.c b/src/SDL.c index 8866b0ebc2..8b76ef2744 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -53,6 +53,7 @@ #include "thread/SDL_thread_c.h" #include "video/SDL_pixels_c.h" #include "video/SDL_video_c.h" +#include "filesystem/SDL_filesystem_c.h" #define SDL_INIT_EVERYTHING ~0U @@ -192,6 +193,7 @@ void SDL_InitMainThread(void) SDL_InitTLSData(); SDL_InitTicks(); + SDL_InitFilesystem(); SDL_InitLog(); SDL_InitProperties(); SDL_GetGlobalProperties(); @@ -207,6 +209,7 @@ static void SDL_QuitMainThread(void) SDL_QuitProperties(); SDL_QuitLog(); + SDL_QuitFilesystem(); SDL_QuitTicks(); SDL_QuitTLSData(); diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 533cc20f5a..0322906dfc 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -219,7 +219,7 @@ SDL_DYNAPI_PROC(const int*,SDL_GetAudioStreamInputChannelMap,(SDL_AudioStream *a SDL_DYNAPI_PROC(const int*,SDL_GetAudioStreamOutputChannelMap,(SDL_AudioStream *a, int *b),(a,b),return) SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetAudioStreamProperties,(SDL_AudioStream *a),(a),return) SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return) -SDL_DYNAPI_PROC(char*,SDL_GetBasePath,(void),(),return) +SDL_DYNAPI_PROC(const char*,SDL_GetBasePath,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_GetBooleanProperty,(SDL_PropertiesID a, const char *b, SDL_bool c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_GetCPUCacheLineSize,(void),(),return) SDL_DYNAPI_PROC(int,SDL_GetCPUCount,(void),(),return) diff --git a/src/filesystem/SDL_filesystem.c b/src/filesystem/SDL_filesystem.c index 4310bbb6a6..16c59f6e8b 100644 --- a/src/filesystem/SDL_filesystem.c +++ b/src/filesystem/SDL_filesystem.c @@ -400,3 +400,25 @@ char **SDL_GlobDirectory(const char *path, const char *pattern, SDL_GlobFlags fl return SDL_InternalGlobDirectory(path, pattern, flags, count, GlobDirectoryEnumerator, GlobDirectoryGetPathInfo, NULL); } + +static char *CachedBasePath = NULL; + +const char *SDL_GetBasePath(void) +{ + if (!CachedBasePath) { + CachedBasePath = SDL_SYS_GetBasePath(); + } + return CachedBasePath; +} + +void SDL_InitFilesystem(void) +{ + CachedBasePath = NULL; // just in case. +} + +void SDL_QuitFilesystem(void) +{ + SDL_free(CachedBasePath); + CachedBasePath = NULL; +} + diff --git a/src/filesystem/SDL_filesystem_c.h b/src/filesystem/SDL_filesystem_c.h new file mode 100644 index 0000000000..4cf8725c21 --- /dev/null +++ b/src/filesystem/SDL_filesystem_c.h @@ -0,0 +1,29 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + 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_filesystem_c_h_ +#define SDL_filesystem_c_h_ + +extern void SDL_InitFilesystem(void); +extern void SDL_QuitFilesystem(void); + +#endif + diff --git a/src/filesystem/SDL_sysfilesystem.h b/src/filesystem/SDL_sysfilesystem.h index 1655e69d64..b7fe7f6ffb 100644 --- a/src/filesystem/SDL_sysfilesystem.h +++ b/src/filesystem/SDL_sysfilesystem.h @@ -22,6 +22,9 @@ #ifndef SDL_sysfilesystem_h_ #define SDL_sysfilesystem_h_ +// return a string that we can SDL_free(). It will be cached at the higher level. +extern char *SDL_SYS_GetBasePath(void); + int SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata); int SDL_SYS_RemovePath(const char *path); int SDL_SYS_RenamePath(const char *oldpath, const char *newpath); diff --git a/src/filesystem/android/SDL_sysfilesystem.c b/src/filesystem/android/SDL_sysfilesystem.c index a59f2bb41d..0170264134 100644 --- a/src/filesystem/android/SDL_sysfilesystem.c +++ b/src/filesystem/android/SDL_sysfilesystem.c @@ -27,7 +27,7 @@ #include -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { /* The current working directory is / on Android */ SDL_Unsupported(); diff --git a/src/filesystem/cocoa/SDL_sysfilesystem.m b/src/filesystem/cocoa/SDL_sysfilesystem.m index 7491953bda..308d675615 100644 --- a/src/filesystem/cocoa/SDL_sysfilesystem.m +++ b/src/filesystem/cocoa/SDL_sysfilesystem.m @@ -29,7 +29,7 @@ #include #include -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { @autoreleasepool { NSBundle *bundle = [NSBundle mainBundle]; diff --git a/src/filesystem/dummy/SDL_sysfilesystem.c b/src/filesystem/dummy/SDL_sysfilesystem.c index 442728223e..cf9ca53d98 100644 --- a/src/filesystem/dummy/SDL_sysfilesystem.c +++ b/src/filesystem/dummy/SDL_sysfilesystem.c @@ -25,7 +25,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { SDL_Unsupported(); return NULL; diff --git a/src/filesystem/emscripten/SDL_sysfilesystem.c b/src/filesystem/emscripten/SDL_sysfilesystem.c index b2ae8c529b..ea415547f5 100644 --- a/src/filesystem/emscripten/SDL_sysfilesystem.c +++ b/src/filesystem/emscripten/SDL_sysfilesystem.c @@ -29,10 +29,9 @@ #include -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { - char *retval = "/"; - return SDL_strdup(retval); + return SDL_strdup("/"); } char *SDL_GetPrefPath(const char *org, const char *app) diff --git a/src/filesystem/gdk/SDL_sysfilesystem.cpp b/src/filesystem/gdk/SDL_sysfilesystem.cpp index 0ba16306cf..c1d9fa98f0 100644 --- a/src/filesystem/gdk/SDL_sysfilesystem.cpp +++ b/src/filesystem/gdk/SDL_sysfilesystem.cpp @@ -31,7 +31,7 @@ #include char * -SDL_GetBasePath(void) +SDL_SYS_GetBasePath(void) { /* NOTE: This function is a UTF8 version of the Win32 SDL_GetBasePath()! * The GDK actually _recommends_ the 'A' functions over the 'W' functions :o diff --git a/src/filesystem/haiku/SDL_sysfilesystem.cc b/src/filesystem/haiku/SDL_sysfilesystem.cc index 0e91b06b00..82fc4ea12f 100644 --- a/src/filesystem/haiku/SDL_sysfilesystem.cc +++ b/src/filesystem/haiku/SDL_sysfilesystem.cc @@ -25,6 +25,10 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ +extern "C" { +#include "../SDL_sysfilesystem.h" +} + #include #include #include @@ -32,7 +36,7 @@ #include -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { char name[MAXPATHLEN]; @@ -51,13 +55,12 @@ char *SDL_GetBasePath(void) const size_t len = SDL_strlen(str); char *retval = (char *) SDL_malloc(len + 2); - if (!retval) { - return NULL; + if (retval) { + SDL_memcpy(retval, str, len); + retval[len] = '/'; + retval[len+1] = '\0'; } - SDL_memcpy(retval, str, len); - retval[len] = '/'; - retval[len+1] = '\0'; return retval; } diff --git a/src/filesystem/n3ds/SDL_sysfilesystem.c b/src/filesystem/n3ds/SDL_sysfilesystem.c index 689a35bbbb..897d11a508 100644 --- a/src/filesystem/n3ds/SDL_sysfilesystem.c +++ b/src/filesystem/n3ds/SDL_sysfilesystem.c @@ -32,7 +32,7 @@ static char *MakePrefPath(const char *app); static int CreatePrefPathDir(const char *pref); -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { char *base_path = SDL_strdup("romfs:/"); return base_path; diff --git a/src/filesystem/ps2/SDL_sysfilesystem.c b/src/filesystem/ps2/SDL_sysfilesystem.c index da773eb690..86d908af73 100644 --- a/src/filesystem/ps2/SDL_sysfilesystem.c +++ b/src/filesystem/ps2/SDL_sysfilesystem.c @@ -28,7 +28,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { char *retval = NULL; size_t len; @@ -37,7 +37,9 @@ char *SDL_GetBasePath(void) getcwd(cwd, sizeof(cwd)); len = SDL_strlen(cwd) + 2; retval = (char *)SDL_malloc(len); - SDL_snprintf(retval, len, "%s/", cwd); + if (retval) { + SDL_snprintf(retval, len, "%s/", cwd); + } return retval; } @@ -46,7 +48,7 @@ char *SDL_GetBasePath(void) static void recursive_mkdir(const char *dir) { char tmp[FILENAME_MAX]; - char *base = SDL_GetBasePath(); + const char *base = SDL_GetBasePath(); char *p = NULL; size_t len; @@ -60,7 +62,7 @@ static void recursive_mkdir(const char *dir) if (*p == '/') { *p = 0; // Just creating subfolders from current path - if (SDL_strstr(tmp, base) != NULL) { + if (base && SDL_strstr(tmp, base) != NULL) { mkdir(tmp, S_IRWXU); } @@ -68,7 +70,6 @@ static void recursive_mkdir(const char *dir) } } - SDL_free(base); mkdir(tmp, S_IRWXU); } @@ -76,26 +77,32 @@ char *SDL_GetPrefPath(const char *org, const char *app) { char *retval = NULL; size_t len; - char *base = SDL_GetBasePath(); + if (!app) { SDL_InvalidParamError("app"); return NULL; } + if (!org) { org = ""; } + const char *base = SDL_GetBasePath(); + if (!base) { + return NULL; + } + len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4; retval = (char *)SDL_malloc(len); + if (retval) { + if (*org) { + SDL_snprintf(retval, len, "%s%s/%s/", base, org, app); + } else { + SDL_snprintf(retval, len, "%s%s/", base, app); + } - if (*org) { - SDL_snprintf(retval, len, "%s%s/%s/", base, org, app); - } else { - SDL_snprintf(retval, len, "%s%s/", base, app); + recursive_mkdir(retval); } - SDL_free(base); - - recursive_mkdir(retval); return retval; } diff --git a/src/filesystem/psp/SDL_sysfilesystem.c b/src/filesystem/psp/SDL_sysfilesystem.c index 5386cb53a4..b29b1b210a 100644 --- a/src/filesystem/psp/SDL_sysfilesystem.c +++ b/src/filesystem/psp/SDL_sysfilesystem.c @@ -28,7 +28,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { char *retval = NULL; size_t len; @@ -37,7 +37,9 @@ char *SDL_GetBasePath(void) getcwd(cwd, sizeof(cwd)); len = SDL_strlen(cwd) + 2; retval = (char *)SDL_malloc(len); - SDL_snprintf(retval, len, "%s/", cwd); + if (retval) { + SDL_snprintf(retval, len, "%s/", cwd); + } return retval; } @@ -46,26 +48,32 @@ char *SDL_GetPrefPath(const char *org, const char *app) { char *retval = NULL; size_t len; - char *base = SDL_GetBasePath(); if (!app) { SDL_InvalidParamError("app"); return NULL; } + + const char *base = SDL_GetBasePath(); + if (!base) { + return NULL; + } + if (!org) { org = ""; } len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4; retval = (char *)SDL_malloc(len); + if (retval) { + if (*org) { + SDL_snprintf(retval, len, "%s%s/%s/", base, org, app); + } else { + SDL_snprintf(retval, len, "%s%s/", base, app); + } - if (*org) { - SDL_snprintf(retval, len, "%s%s/%s/", base, org, app); - } else { - SDL_snprintf(retval, len, "%s%s/", base, app); + mkdir(retval, 0755); } - SDL_free(base); - mkdir(retval, 0755); return retval; } diff --git a/src/filesystem/riscos/SDL_sysfilesystem.c b/src/filesystem/riscos/SDL_sysfilesystem.c index bbbc144b00..55f69f3b8f 100644 --- a/src/filesystem/riscos/SDL_sysfilesystem.c +++ b/src/filesystem/riscos/SDL_sysfilesystem.c @@ -123,7 +123,7 @@ static _kernel_oserror *createDirectoryRecursive(char *path) return _kernel_swi(OS_File, ®s, ®s); } -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { _kernel_swi_regs regs; _kernel_oserror *error; diff --git a/src/filesystem/unix/SDL_sysfilesystem.c b/src/filesystem/unix/SDL_sysfilesystem.c index 70a5ee6b41..8c62d603fa 100644 --- a/src/filesystem/unix/SDL_sysfilesystem.c +++ b/src/filesystem/unix/SDL_sysfilesystem.c @@ -119,7 +119,7 @@ static char *search_path_for_binary(const char *bin) } #endif -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { char *retval = NULL; diff --git a/src/filesystem/vita/SDL_sysfilesystem.c b/src/filesystem/vita/SDL_sysfilesystem.c index 11d320ee4b..d030da2fdd 100644 --- a/src/filesystem/vita/SDL_sysfilesystem.c +++ b/src/filesystem/vita/SDL_sysfilesystem.c @@ -34,11 +34,9 @@ #include #include -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { - const char *basepath = "app0:/"; - char *retval = SDL_strdup(basepath); - return retval; + return SDL_strdup("app0:/"); } char *SDL_GetPrefPath(const char *org, const char *app) diff --git a/src/filesystem/windows/SDL_sysfilesystem.c b/src/filesystem/windows/SDL_sysfilesystem.c index e321b7dc02..ff30453e02 100644 --- a/src/filesystem/windows/SDL_sysfilesystem.c +++ b/src/filesystem/windows/SDL_sysfilesystem.c @@ -41,7 +41,7 @@ DEFINE_GUID(SDL_FOLDERID_Screenshots, 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x DEFINE_GUID(SDL_FOLDERID_Templates, 0xA63293E8, 0x664E, 0x48DB, 0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7); DEFINE_GUID(SDL_FOLDERID_Videos, 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC); -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { DWORD buflen = 128; WCHAR *path = NULL; diff --git a/src/filesystem/winrt/SDL_sysfilesystem.cpp b/src/filesystem/winrt/SDL_sysfilesystem.cpp index a1378a6740..9f710e71c2 100644 --- a/src/filesystem/winrt/SDL_sysfilesystem.cpp +++ b/src/filesystem/winrt/SDL_sysfilesystem.cpp @@ -27,6 +27,7 @@ extern "C" { #include "../../core/windows/SDL_windows.h" +#include "../SDL_sysfilesystem.h" } #include @@ -115,7 +116,7 @@ extern "C" const char *SDL_GetWinRTFSPath(SDL_WinRT_Path pathType) return utf8Paths[pathType].c_str(); } -extern "C" char *SDL_GetBasePath(void) +extern "C" char *SDL_SYS_GetBasePath(void) { const char *srcPath = SDL_GetWinRTFSPath(SDL_WINRT_PATH_INSTALLED_LOCATION); size_t destPathLen; diff --git a/src/storage/generic/SDL_genericstorage.c b/src/storage/generic/SDL_genericstorage.c index e624a541d4..c6bfb74fe7 100644 --- a/src/storage/generic/SDL_genericstorage.c +++ b/src/storage/generic/SDL_genericstorage.c @@ -181,22 +181,25 @@ static const SDL_StorageInterface GENERIC_title_iface = { static SDL_Storage *GENERIC_Title_Create(const char *override, SDL_PropertiesID props) { - SDL_Storage *result; + SDL_Storage *result = NULL; - char *basepath; + char *basepath = NULL; if (override != NULL) { basepath = SDL_strdup(override); } else { - basepath = SDL_GetBasePath(); - } - if (basepath == NULL) { - return NULL; + const char *sdlbasepath = SDL_GetBasePath(); + if (sdlbasepath) { + basepath = SDL_strdup(sdlbasepath); + } } - result = SDL_OpenStorage(&GENERIC_title_iface, basepath); - if (result == NULL) { - SDL_free(basepath); + if (basepath != NULL) { + result = SDL_OpenStorage(&GENERIC_title_iface, basepath); + if (result == NULL) { + SDL_free(basepath); // otherwise CloseStorage will free it. + } } + return result; } diff --git a/test/testfilesystem.c b/test/testfilesystem.c index e975b19a67..54214d71da 100644 --- a/test/testfilesystem.c +++ b/test/testfilesystem.c @@ -62,7 +62,7 @@ int main(int argc, char *argv[]) { SDLTest_CommonState *state; char *pref_path; - char *base_path; + const char *base_path; /* Initialize test framework */ state = SDLTest_CommonCreateState(argv, 0); @@ -145,8 +145,6 @@ int main(int argc, char *argv[]) } } - SDL_free(base_path); - SDL_Quit(); SDLTest_CommonDestroyState(state); return 0; diff --git a/test/testutils.c b/test/testutils.c index 09dfb726c8..c80dd35396 100644 --- a/test/testutils.c +++ b/test/testutils.c @@ -23,11 +23,9 @@ char * GetNearbyFilename(const char *file) { - char *base; + const char *base = SDL_GetBasePath(); char *path; - base = SDL_GetBasePath(); - if (base) { SDL_IOStream *rw; size_t len = SDL_strlen(base) + SDL_strlen(file) + 1; @@ -35,12 +33,10 @@ GetNearbyFilename(const char *file) path = SDL_malloc(len); if (!path) { - SDL_free(base); return NULL; } (void)SDL_snprintf(path, len, "%s%s", base, file); - SDL_free(base); rw = SDL_IOFromFile(path, "rb"); if (rw) {