Skip to content

SDL_EnumerateDirectory(""): Don't append path separator if path is empty#15357

Open
Sackzement wants to merge 2 commits intolibsdl-org:mainfrom
Sackzement:enum_empty_root
Open

SDL_EnumerateDirectory(""): Don't append path separator if path is empty#15357
Sackzement wants to merge 2 commits intolibsdl-org:mainfrom
Sackzement:enum_empty_root

Conversation

@Sackzement
Copy link
Copy Markdown
Contributor

Calling SDL_EnumerateDirectory("") enumerates the root directory "/".

Example code:

#include <SDL3/SDL.h>

#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL_main.h>

const char *path = "";

SDL_EnumerationResult enum_dir_callback(void *userdata, const char *dirname, const char *fname)
{
    SDL_Log("dirname = \"%s\", fname = \"%s\"", dirname, fname);
    
    return SDL_ENUM_CONTINUE;
}


SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
    if(!SDL_Init(0)) {
        SDL_Log("ERROR: SDL_Init(): %s", SDL_GetError());
    }
    
    SDL_Log("SDL_EnumerateDirectory(\"%s\")", path);
    if(!SDL_EnumerateDirectory(path, enum_dir_callback, NULL)) {
        SDL_Log("ERROR: %s", SDL_GetError());
    }
    
    SDL_Log("");
    
    SDL_Log("SDL_GlobDirectory(\"%s\")", path);
    int glob_count =  0;
    char **globs = SDL_GlobDirectory(path, "*", 0, &glob_count);
    if (!globs) {
        SDL_Log("ERROR: %s", SDL_GetError());
    } else {
        SDL_Log("glob_count: %d", glob_count);
        for (int i = 0; i < glob_count; ++i) {
            SDL_Log("%s", globs[i]);
        }
        SDL_free(globs);
    }
    
    return SDL_APP_SUCCESS;
}

SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
    return SDL_APP_SUCCESS;
}

SDL_AppResult SDL_AppIterate(void *appstate)
{
    return SDL_APP_SUCCESS;
}

void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
}

Output:

SDL_EnumerateDirectory("")
dirname = "/", fname = "tmp"
dirname = "/", fname = "var"
dirname = "/", fname = "efi"
dirname = "/", fname = "root"
dirname = "/", fname = "bin"
dirname = "/", fname = "dev"
dirname = "/", fname = "lost+found"
dirname = "/", fname = "media"
dirname = "/", fname = "mnt"
dirname = "/", fname = "run"
dirname = "/", fname = "lib64"
dirname = "/", fname = "proc"
dirname = "/", fname = "sbin"
dirname = "/", fname = "opt"
dirname = "/", fname = "lib"
dirname = "/", fname = "srv"
dirname = "/", fname = "etc"
dirname = "/", fname = "home"
dirname = "/", fname = "sys"
dirname = "/", fname = "boot"
dirname = "/", fname = "usr"

SDL_GlobDirectory("")
glob_count: 0

This is due to an appended path separator on an empty string here:

char *pathwithsep = NULL;
int pathwithseplen = SDL_asprintf(&pathwithsep, "%s/", apath ? apath : path);
const size_t extralen = apath ? (SDL_strlen(apath) - SDL_strlen(path)) : 0;
SDL_free(apath);
if ((pathwithseplen == -1) || (!pathwithsep)) {
return false;
}

This PR only appends the path separator if the path is not empty.
Outpt after change:

SDL_EnumerateDirectory("")
ERROR: Can't open directory: No such file or directory

SDL_GlobDirectory("")
ERROR: Can't open directory: No such file or directory

The changed code is not the prettiest, but a pretty fix would take more refactoring.
Ideas for a pretty fix are welcome.

@slouken slouken requested a review from icculus April 10, 2026 15:35
@slouken slouken added this to the 3.4.6 milestone Apr 10, 2026
@Sackzement
Copy link
Copy Markdown
Contributor Author

Refactored the code a bit.
Hopefully it's not too pretty now / too verbose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants