parent
810656962c
commit
764207d873
|
@ -272,7 +272,11 @@ extern DECLSPEC int SDLCALL SDL_CreateDirectory(const char *path);
|
||||||
typedef int (SDLCALL *SDL_EnumerateDirectoryCallback)(void *userdata, const char *dirname, const char *fname);
|
typedef int (SDLCALL *SDL_EnumerateDirectoryCallback)(void *userdata, const char *dirname, const char *fname);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerate a directory.
|
* Enumerate a directory through a callback function.
|
||||||
|
*
|
||||||
|
* This function provides every directory entry through an app-provided
|
||||||
|
* callback, called once for each directory entry, until all results have
|
||||||
|
* been provided or the callback returns <= 0.
|
||||||
*
|
*
|
||||||
* \param path the path of the directory to enumerate
|
* \param path the path of the directory to enumerate
|
||||||
* \param callback a function that is called for each entry in the directory
|
* \param callback a function that is called for each entry in the directory
|
||||||
|
@ -320,6 +324,42 @@ extern DECLSPEC int SDLCALL SDL_RenamePath(const char *oldpath, const char *newp
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC int SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo *info);
|
extern DECLSPEC int SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo *info);
|
||||||
|
|
||||||
|
|
||||||
|
#define SDL_GLOBDIR_CASEINSENSITIVE (1 << 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerate a directory tree, filtered by pattern, and return a list.
|
||||||
|
*
|
||||||
|
* Files are filtered out if they don't match the string in `pattern`, which
|
||||||
|
* may contain wildcard characters '*' (match everything) and '?' (match one
|
||||||
|
* character). If pattern is NULL, no filtering is done and all results are
|
||||||
|
* returned. Subdirectories are permitted, and are specified with a path
|
||||||
|
* separator of '/'. Wildcard characters '*' and '?' never match a path
|
||||||
|
* separator.
|
||||||
|
*
|
||||||
|
* `flags` may be set to SDL_GLOBDIR_CASEINSENSITIVE to make the pattern
|
||||||
|
* matching case-insensitive.
|
||||||
|
*
|
||||||
|
* The returned array is always NULL-terminated, for your iterating
|
||||||
|
* convenience, but if `count` is non-NULL, on return it will contain the
|
||||||
|
* number of items in the array, not counting the NULL terminator.
|
||||||
|
*
|
||||||
|
* You must free the returned pointer with SDL_free() when done with it.
|
||||||
|
*
|
||||||
|
* \param path the path of the directory to enumerate
|
||||||
|
* \param pattern the pattern that files in the directory must match. Can be NULL.
|
||||||
|
* \param flags `SDL_GLOBDIR_*` bitflags that affect this search.
|
||||||
|
* \param count on return, will be set to the number of items in the returned array. Can be NULL.
|
||||||
|
* \returns an array of strings on success or NULL on failure; call
|
||||||
|
* SDL_GetError() for more information. The caller should pass the
|
||||||
|
* returned pointer to SDL_free when done with it.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC char **SDLCALL SDL_GlobDirectory(const char *path, const char *pattern, Uint32 flags, int *count);
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,11 @@ extern DECLSPEC int SDL_WriteStorageFile(SDL_Storage *storage, const char *path,
|
||||||
extern DECLSPEC int SDLCALL SDL_CreateStorageDirectory(SDL_Storage *storage, const char *path);
|
extern DECLSPEC int SDLCALL SDL_CreateStorageDirectory(SDL_Storage *storage, const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerate a directory in a storage container.
|
* Enumerate a directory in a storage container through a callback function.
|
||||||
|
*
|
||||||
|
* This function provides every directory entry through an app-provided
|
||||||
|
* callback, called once for each directory entry, until all results have
|
||||||
|
* been provided or the callback returns <= 0.
|
||||||
*
|
*
|
||||||
* \param storage a storage container
|
* \param storage a storage container
|
||||||
* \param path the path of the directory to enumerate
|
* \param path the path of the directory to enumerate
|
||||||
|
@ -341,6 +345,40 @@ extern DECLSPEC int SDLCALL SDL_GetStoragePathInfo(SDL_Storage *storage, const c
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC Uint64 SDLCALL SDL_GetStorageSpaceRemaining(SDL_Storage *storage);
|
extern DECLSPEC Uint64 SDLCALL SDL_GetStorageSpaceRemaining(SDL_Storage *storage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerate a directory tree, filtered by pattern, and return a list.
|
||||||
|
*
|
||||||
|
* Files are filtered out if they don't match the string in `pattern`, which
|
||||||
|
* may contain wildcard characters '*' (match everything) and '?' (match one
|
||||||
|
* character). If pattern is NULL, no filtering is done and all results are
|
||||||
|
* returned. Subdirectories are permitted, and are specified with a path
|
||||||
|
* separator of '/'. Wildcard characters '*' and '?' never match a path
|
||||||
|
* separator.
|
||||||
|
*
|
||||||
|
* `flags` may be set to SDL_GLOBDIR_CASEINSENSITIVE to make the pattern
|
||||||
|
* matching case-insensitive.
|
||||||
|
*
|
||||||
|
* The returned array is always NULL-terminated, for your iterating
|
||||||
|
* convenience, but if `count` is non-NULL, on return it will contain the
|
||||||
|
* number of items in the array, not counting the NULL terminator.
|
||||||
|
*
|
||||||
|
* You must free the returned pointer with SDL_free() when done with it.
|
||||||
|
*
|
||||||
|
* \param storage a storage container
|
||||||
|
* \param path the path of the directory to enumerate
|
||||||
|
* \param pattern the pattern that files in the directory must match. Can be NULL.
|
||||||
|
* \param flags `SDL_GLOBDIR_*` bitflags that affect this search.
|
||||||
|
* \param count on return, will be set to the number of items in the returned array. Can be NULL.
|
||||||
|
* \returns an array of strings on success or NULL on failure; call
|
||||||
|
* SDL_GetError() for more information. The caller should pass the
|
||||||
|
* returned pointer to SDL_free when done with it.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, assuming the `storage` object is thread-safe.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC char **SDLCALL SDL_GlobStorageDirectory(SDL_Storage *storage, const char *path, const char *pattern, Uint32 flags, int *count);
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -481,6 +481,8 @@ SDL3_0.0.0 {
|
||||||
SDL_GetWindowSizeInPixels;
|
SDL_GetWindowSizeInPixels;
|
||||||
SDL_GetWindowSurface;
|
SDL_GetWindowSurface;
|
||||||
SDL_GetWindowTitle;
|
SDL_GetWindowTitle;
|
||||||
|
SDL_GlobDirectory;
|
||||||
|
SDL_GlobStorageDirectory;
|
||||||
SDL_HapticEffectSupported;
|
SDL_HapticEffectSupported;
|
||||||
SDL_HapticRumbleSupported;
|
SDL_HapticRumbleSupported;
|
||||||
SDL_HasARMSIMD;
|
SDL_HasARMSIMD;
|
||||||
|
|
|
@ -506,6 +506,8 @@
|
||||||
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
|
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
|
||||||
#define SDL_GetWindowSurface SDL_GetWindowSurface_REAL
|
#define SDL_GetWindowSurface SDL_GetWindowSurface_REAL
|
||||||
#define SDL_GetWindowTitle SDL_GetWindowTitle_REAL
|
#define SDL_GetWindowTitle SDL_GetWindowTitle_REAL
|
||||||
|
#define SDL_GlobDirectory SDL_GlobDirectory_REAL
|
||||||
|
#define SDL_GlobStorageDirectory SDL_GlobStorageDirectory_REAL
|
||||||
#define SDL_HapticEffectSupported SDL_HapticEffectSupported_REAL
|
#define SDL_HapticEffectSupported SDL_HapticEffectSupported_REAL
|
||||||
#define SDL_HapticRumbleSupported SDL_HapticRumbleSupported_REAL
|
#define SDL_HapticRumbleSupported SDL_HapticRumbleSupported_REAL
|
||||||
#define SDL_HasARMSIMD SDL_HasARMSIMD_REAL
|
#define SDL_HasARMSIMD SDL_HasARMSIMD_REAL
|
||||||
|
|
|
@ -537,6 +537,8 @@ SDL_DYNAPI_PROC(int,SDL_GetWindowSize,(SDL_Window *a, int *b, int *c),(a,b,c),re
|
||||||
SDL_DYNAPI_PROC(int,SDL_GetWindowSizeInPixels,(SDL_Window *a, int *b, int *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_GetWindowSizeInPixels,(SDL_Window *a, int *b, int *c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_GetWindowSurface,(SDL_Window *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_Surface*,SDL_GetWindowSurface,(SDL_Window *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const char*,SDL_GetWindowTitle,(SDL_Window *a),(a),return)
|
SDL_DYNAPI_PROC(const char*,SDL_GetWindowTitle,(SDL_Window *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(char**,SDL_GlobDirectory,(const char *a, const char *b, Uint32 c, int *d),(a,b,c,d),return)
|
||||||
|
SDL_DYNAPI_PROC(char**,SDL_GlobStorageDirectory,(SDL_Storage *a, const char *b, const char *c, Uint32 d, int *e),(a,b,c,d,e),return)
|
||||||
SDL_DYNAPI_PROC(SDL_bool,SDL_HapticEffectSupported,(SDL_Haptic *a, const SDL_HapticEffect *b),(a,b),return)
|
SDL_DYNAPI_PROC(SDL_bool,SDL_HapticEffectSupported,(SDL_Haptic *a, const SDL_HapticEffect *b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(SDL_bool,SDL_HapticRumbleSupported,(SDL_Haptic *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_bool,SDL_HapticRumbleSupported,(SDL_Haptic *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(SDL_bool,SDL_HasARMSIMD,(void),(),return)
|
SDL_DYNAPI_PROC(SDL_bool,SDL_HasARMSIMD,(void),(),return)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
#include "SDL_sysfilesystem.h"
|
#include "SDL_sysfilesystem.h"
|
||||||
|
#include "../stdlib/SDL_sysstdlib.h"
|
||||||
|
|
||||||
int SDL_RemovePath(const char *path)
|
int SDL_RemovePath(const char *path)
|
||||||
{
|
{
|
||||||
|
@ -74,3 +75,279 @@ int SDL_GetPathInfo(const char *path, SDL_PathInfo *info)
|
||||||
|
|
||||||
return SDL_SYS_GetPathInfo(path, info);
|
return SDL_SYS_GetPathInfo(path, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool EverythingMatch(const char *pattern, const char *str, SDL_bool *matched_to_dir)
|
||||||
|
{
|
||||||
|
SDL_assert(pattern == NULL);
|
||||||
|
SDL_assert(str != NULL);
|
||||||
|
SDL_assert(matched_to_dir != NULL);
|
||||||
|
|
||||||
|
*matched_to_dir = SDL_TRUE;
|
||||||
|
return SDL_TRUE; // everything matches!
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is just '*' and '?', with '/' matching nothing.
|
||||||
|
static SDL_bool WildcardMatch(const char *pattern, const char *str, SDL_bool *matched_to_dir)
|
||||||
|
{
|
||||||
|
SDL_assert(pattern != NULL);
|
||||||
|
SDL_assert(str != NULL);
|
||||||
|
SDL_assert(matched_to_dir != NULL);
|
||||||
|
|
||||||
|
const char *str_backtrack = NULL;
|
||||||
|
const char *pattern_backtrack = NULL;
|
||||||
|
char sch_backtrack = 0;
|
||||||
|
char sch = *str;
|
||||||
|
char pch = *pattern;
|
||||||
|
|
||||||
|
while (sch) {
|
||||||
|
if (pch == '*') {
|
||||||
|
str_backtrack = str;
|
||||||
|
pattern_backtrack = ++pattern;
|
||||||
|
sch_backtrack = sch;
|
||||||
|
pch = *pattern;
|
||||||
|
} else if (pch == sch) {
|
||||||
|
if (pch == '/') {
|
||||||
|
str_backtrack = pattern_backtrack = NULL;
|
||||||
|
}
|
||||||
|
sch = *(++str);
|
||||||
|
pch = *(++pattern);
|
||||||
|
} else if ((pch == '?') && (sch != '/')) { // end of string (checked at `while`) or path separator do not match '?'.
|
||||||
|
sch = *(++str);
|
||||||
|
pch = *(++pattern);
|
||||||
|
} else if (!pattern_backtrack || (sch_backtrack == '/')) { // we didn't have a match. Are we in a '*' and NOT on a path separator? Keep going. Otherwise, fail.
|
||||||
|
*matched_to_dir = SDL_FALSE;
|
||||||
|
return SDL_FALSE;
|
||||||
|
} else { // still here? Wasn't a match, but we're definitely in a '*' pattern.
|
||||||
|
str = ++str_backtrack;
|
||||||
|
pattern = pattern_backtrack;
|
||||||
|
sch_backtrack = sch;
|
||||||
|
sch = *str;
|
||||||
|
pch = *pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// '*' at the end can be ignored, they are allowed to match nothing.
|
||||||
|
while (pch == '*') {
|
||||||
|
pch = *(++pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
*matched_to_dir = ((pch == '/') || (pch == '\0')); // end of string and the pattern is complete or failed at a '/'? We should descend into this directory.
|
||||||
|
|
||||||
|
return (pch == '\0'); // survived the whole pattern? That's a match!
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *CaseFoldUtf8String(const char *fname)
|
||||||
|
{
|
||||||
|
SDL_assert(fname != NULL);
|
||||||
|
const size_t allocation = (SDL_strlen(fname) + 1) * 3;
|
||||||
|
char *retval = (char *) SDL_malloc(allocation); // lazy: just allocating the max needed.
|
||||||
|
if (!retval) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 codepoint;
|
||||||
|
size_t written = 0;
|
||||||
|
while ((codepoint = SDL_StepUTF8(&fname, 4)) != 0) {
|
||||||
|
Uint32 folded[3];
|
||||||
|
const int num_folded = SDL_CaseFoldUnicode(codepoint, folded);
|
||||||
|
SDL_assert(num_folded > 0);
|
||||||
|
SDL_assert(num_folded <= SDL_arraysize(folded));
|
||||||
|
for (int i = 0; i < num_folded; i++) {
|
||||||
|
SDL_assert(written < allocation);
|
||||||
|
retval[written++] = folded[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(written < allocation);
|
||||||
|
retval[written++] = '\0';
|
||||||
|
|
||||||
|
if (written < allocation) {
|
||||||
|
void *ptr = SDL_realloc(retval, written); // shrink it down.
|
||||||
|
if (ptr) { // shouldn't fail, but if it does, `retval` is still valid.
|
||||||
|
retval = (char *) ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct GlobDirCallbackData
|
||||||
|
{
|
||||||
|
SDL_bool (*matcher)(const char *pattern, const char *str, SDL_bool *matched_to_dir);
|
||||||
|
const char *pattern;
|
||||||
|
int num_entries;
|
||||||
|
Uint32 flags;
|
||||||
|
SDL_GlobEnumeratorFunc enumerator;
|
||||||
|
SDL_GlobGetPathInfoFunc getpathinfo;
|
||||||
|
void *fsuserdata;
|
||||||
|
size_t basedirlen;
|
||||||
|
SDL_IOStream *string_stream;
|
||||||
|
} GlobDirCallbackData;
|
||||||
|
|
||||||
|
static int SDLCALL GlobDirectoryCallback(void *userdata, const char *dirname, const char *fname)
|
||||||
|
{
|
||||||
|
SDL_assert(userdata != NULL);
|
||||||
|
SDL_assert(dirname != NULL);
|
||||||
|
SDL_assert(fname != NULL);
|
||||||
|
|
||||||
|
//SDL_Log("GlobDirectoryCallback('%s', '%s')", dirname, fname);
|
||||||
|
|
||||||
|
GlobDirCallbackData *data = (GlobDirCallbackData *) userdata;
|
||||||
|
|
||||||
|
// !!! FIXME: if we're careful, we can keep a single buffer in `data` that we push and pop paths off the end of as we walk the tree,
|
||||||
|
// !!! FIXME: and only casefold the new pieces instead of allocating and folding full paths for all of this.
|
||||||
|
|
||||||
|
char *fullpath = NULL;
|
||||||
|
if (SDL_asprintf(&fullpath, "%s/%s", dirname, fname) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *folded = NULL;
|
||||||
|
if (data->flags & SDL_GLOBDIR_CASEINSENSITIVE) {
|
||||||
|
folded = CaseFoldUtf8String(fullpath);
|
||||||
|
if (!folded) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_bool matched_to_dir = SDL_FALSE;
|
||||||
|
const SDL_bool matched = data->matcher(data->pattern, (folded ? folded : fullpath) + data->basedirlen, &matched_to_dir);
|
||||||
|
//SDL_Log("GlobDirectoryCallback: Considered %spath='%s' vs pattern='%s': %smatched (matched_to_dir=%s)", folded ? "(folded) " : "", (folded ? folded : fullpath) + data->basedirlen, data->pattern, matched ? "" : "NOT ", matched_to_dir ? "TRUE" : "FALSE");
|
||||||
|
SDL_free(folded);
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
const char *subpath = fullpath + data->basedirlen;
|
||||||
|
const size_t slen = SDL_strlen(subpath) + 1;
|
||||||
|
if (SDL_WriteIO(data->string_stream, subpath, slen) != slen) {
|
||||||
|
SDL_free(fullpath);
|
||||||
|
return -1; // stop enumerating, return failure to the app.
|
||||||
|
}
|
||||||
|
data->num_entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = 1; // keep enumerating by default.
|
||||||
|
if (matched_to_dir) {
|
||||||
|
SDL_PathInfo info;
|
||||||
|
if ((data->getpathinfo(fullpath, &info, data->fsuserdata) == 0) && (info.type == SDL_PATHTYPE_DIRECTORY)) {
|
||||||
|
//SDL_Log("GlobDirectoryCallback: Descending into subdir '%s'", fname);
|
||||||
|
if (data->enumerator(fullpath, GlobDirectoryCallback, data, data->fsuserdata) < 0) {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(fullpath);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **SDL_InternalGlobDirectory(const char *path, const char *pattern, Uint32 flags, int *count, SDL_GlobEnumeratorFunc enumerator, SDL_GlobGetPathInfoFunc getpathinfo, void *userdata)
|
||||||
|
{
|
||||||
|
int dummycount;
|
||||||
|
if (!count) {
|
||||||
|
count = &dummycount;
|
||||||
|
}
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
SDL_InvalidParamError("path");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if path ends with any '/', chop them off, so we don't confuse the pattern matcher later.
|
||||||
|
char *pathcpy = NULL;
|
||||||
|
size_t pathlen = SDL_strlen(path);
|
||||||
|
if (pathlen && (path[pathlen-1] == '/')) {
|
||||||
|
pathcpy = SDL_strdup(path);
|
||||||
|
if (!pathcpy) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char *ptr = &pathcpy[pathlen-1];
|
||||||
|
while ((ptr >= pathcpy) && (*ptr == '/')) {
|
||||||
|
*(ptr--) = '\0';
|
||||||
|
}
|
||||||
|
path = pathcpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *folded = NULL;
|
||||||
|
if (pattern && (flags & SDL_GLOBDIR_CASEINSENSITIVE)) {
|
||||||
|
folded = CaseFoldUtf8String(pattern);
|
||||||
|
if (!folded) {
|
||||||
|
SDL_free(pathcpy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobDirCallbackData data;
|
||||||
|
SDL_zero(data);
|
||||||
|
data.string_stream = SDL_IOFromDynamicMem();
|
||||||
|
if (!data.string_stream) {
|
||||||
|
SDL_free(folded);
|
||||||
|
SDL_free(pathcpy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pattern) {
|
||||||
|
data.matcher = EverythingMatch; // no pattern? Everything matches.
|
||||||
|
|
||||||
|
// !!! FIXME
|
||||||
|
//} else if (flags & SDL_GLOBDIR_GITIGNORE) {
|
||||||
|
// data.matcher = GitIgnoreMatch;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
data.matcher = WildcardMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.pattern = folded ? folded : pattern;
|
||||||
|
data.flags = flags;
|
||||||
|
data.enumerator = enumerator;
|
||||||
|
data.getpathinfo = getpathinfo;
|
||||||
|
data.fsuserdata = userdata;
|
||||||
|
data.basedirlen = SDL_strlen(path) + 1; // +1 for the '/' we'll be adding.
|
||||||
|
|
||||||
|
char **retval = NULL;
|
||||||
|
if (data.enumerator(path, GlobDirectoryCallback, &data, data.fsuserdata) == 0) {
|
||||||
|
const size_t streamlen = (size_t) SDL_GetIOSize(data.string_stream);
|
||||||
|
const size_t buflen = streamlen + ((data.num_entries + 1) * sizeof (char *)); // +1 for NULL terminator at end of array.
|
||||||
|
retval = (char **) SDL_malloc(buflen);
|
||||||
|
if (retval) {
|
||||||
|
if (data.num_entries > 0) {
|
||||||
|
Sint64 iorc = SDL_SeekIO(data.string_stream, 0, SDL_IO_SEEK_SET);
|
||||||
|
SDL_assert(iorc == 0); // this should never fail for a memory stream!
|
||||||
|
char *ptr = (char *) (retval + (data.num_entries + 1));
|
||||||
|
iorc = SDL_ReadIO(data.string_stream, ptr, streamlen);
|
||||||
|
SDL_assert(iorc == (Sint64) streamlen); // this should never fail for a memory stream!
|
||||||
|
for (int i = 0; i < data.num_entries; i++) {
|
||||||
|
retval[i] = ptr;
|
||||||
|
ptr += SDL_strlen(ptr) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval[data.num_entries] = NULL; // NULL terminate the list.
|
||||||
|
*count = data.num_entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_CloseIO(data.string_stream);
|
||||||
|
SDL_free(folded);
|
||||||
|
SDL_free(pathcpy);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GlobDirectoryGetPathInfo(const char *path, SDL_PathInfo *info, void *userdata)
|
||||||
|
{
|
||||||
|
return SDL_GetPathInfo(path, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GlobDirectoryEnumerator(const char *path, SDL_EnumerateDirectoryCallback cb, void *cbuserdata, void *userdata)
|
||||||
|
{
|
||||||
|
return SDL_EnumerateDirectory(path, cb, cbuserdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
char **SDL_GlobDirectory(const char *path, const char *pattern, Uint32 flags, int *count)
|
||||||
|
{
|
||||||
|
//SDL_Log("SDL_GlobDirectory('%s', '%s') ...", path, pattern);
|
||||||
|
return SDL_InternalGlobDirectory(path, pattern, flags, count, GlobDirectoryEnumerator, GlobDirectoryGetPathInfo, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,5 +28,9 @@ int SDL_SYS_RenamePath(const char *oldpath, const char *newpath);
|
||||||
int SDL_SYS_CreateDirectory(const char *path);
|
int SDL_SYS_CreateDirectory(const char *path);
|
||||||
int SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info);
|
int SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info);
|
||||||
|
|
||||||
|
typedef int (*SDL_GlobEnumeratorFunc)(const char *path, SDL_EnumerateDirectoryCallback cb, void *cbuserdata, void *userdata);
|
||||||
|
typedef int (*SDL_GlobGetPathInfoFunc)(const char *path, SDL_PathInfo *info, void *userdata);
|
||||||
|
char **SDL_InternalGlobDirectory(const char *path, const char *pattern, Uint32 flags, int *count, SDL_GlobEnumeratorFunc enumerator, SDL_GlobGetPathInfoFunc getpathinfo, void *userdata);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
#include "SDL_sysstorage.h"
|
#include "SDL_sysstorage.h"
|
||||||
|
#include "../filesystem/SDL_sysfilesystem.h"
|
||||||
|
|
||||||
/* Available title storage drivers */
|
/* Available title storage drivers */
|
||||||
static TitleStorageBootStrap *titlebootstrap[] = {
|
static TitleStorageBootStrap *titlebootstrap[] = {
|
||||||
|
@ -321,3 +322,20 @@ Uint64 SDL_GetStorageSpaceRemaining(SDL_Storage *storage)
|
||||||
|
|
||||||
return storage->iface.space_remaining(storage->userdata);
|
return storage->iface.space_remaining(storage->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GlobStorageDirectoryGetPathInfo(const char *path, SDL_PathInfo *info, void *userdata)
|
||||||
|
{
|
||||||
|
return SDL_GetStoragePathInfo((SDL_Storage *) userdata, path, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GlobStorageDirectoryEnumerator(const char *path, SDL_EnumerateDirectoryCallback cb, void *cbuserdata, void *userdata)
|
||||||
|
{
|
||||||
|
return SDL_EnumerateStorageDirectory((SDL_Storage *) userdata, path, cb, cbuserdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
char **SDL_GlobStorageDirectory(SDL_Storage *storage, const char *path, const char *pattern, Uint32 flags, int *count)
|
||||||
|
{
|
||||||
|
CHECK_STORAGE_MAGIC_RET(NULL)
|
||||||
|
return SDL_InternalGlobDirectory(path, pattern, flags, count, GlobStorageDirectoryEnumerator, GlobStorageDirectoryGetPathInfo, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,10 +110,23 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base_path) {
|
if (base_path) {
|
||||||
|
char **globlist;
|
||||||
|
|
||||||
if (SDL_EnumerateDirectory(base_path, enum_callback, NULL) < 0) {
|
if (SDL_EnumerateDirectory(base_path, enum_callback, NULL) < 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Base path enumeration failed!");
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Base path enumeration failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
globlist = SDL_GlobDirectory(base_path, "*/test*/Test*", SDL_GLOBDIR_CASEINSENSITIVE, NULL);
|
||||||
|
if (!globlist) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Base path globbing failed!");
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 0; globlist[i]; i++) {
|
||||||
|
SDL_Log("GLOB[%d]: '%s'", i, globlist[i]);
|
||||||
|
}
|
||||||
|
SDL_free(globlist);
|
||||||
|
}
|
||||||
|
|
||||||
/* !!! FIXME: put this in a subroutine and make it test more thoroughly (and put it in testautomation). */
|
/* !!! FIXME: put this in a subroutine and make it test more thoroughly (and put it in testautomation). */
|
||||||
if (SDL_CreateDirectory("testfilesystem-test") == -1) {
|
if (SDL_CreateDirectory("testfilesystem-test") == -1) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateDirectory('testfilesystem-test') failed: %s", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateDirectory('testfilesystem-test') failed: %s", SDL_GetError());
|
||||||
|
|
Loading…
Reference in New Issue