diff options
author | Chris Robinson <[email protected]> | 2015-10-03 20:41:18 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2015-10-03 20:41:18 -0700 |
commit | 70fbc2b1ff254295338c6d42b41d9fdb43b02d8f (patch) | |
tree | 71b1e437aca72282b170d584f270c429a84b3149 | |
parent | aa10068ca20c2241c8d80627a5be3aeb39efcea2 (diff) |
Add a function to get a list of data files
The method takes a marked-up filename (e.g. may include %r for a sample rate,
%% for %, etc), and returns a vector of strings of found filenames that match.
It will search the CWD, the local, and global data directories, in that order.
-rw-r--r-- | Alc/alstring.h | 1 | ||||
-rw-r--r-- | Alc/backends/winmm.c | 1 | ||||
-rw-r--r-- | Alc/helpers.c | 211 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 2 | ||||
-rw-r--r-- | config.h.in | 4 |
6 files changed, 217 insertions, 4 deletions
diff --git a/Alc/alstring.h b/Alc/alstring.h index 8791fbc0..5cbb6ac5 100644 --- a/Alc/alstring.h +++ b/Alc/alstring.h @@ -8,6 +8,7 @@ typedef char al_string_char_type; TYPEDEF_VECTOR(al_string_char_type, al_string) +TYPEDEF_VECTOR(al_string, vector_al_string) inline void al_string_deinit(al_string *str) { VECTOR_DEINIT(*str); } diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 0839818e..bf97ef2e 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -40,7 +40,6 @@ #define DEVNAME_TAIL " on OpenAL Soft" -TYPEDEF_VECTOR(al_string, vector_al_string) static vector_al_string PlaybackDevices; static vector_al_string CaptureDevices; diff --git a/Alc/helpers.c b/Alc/helpers.c index 43889d5d..6355dd1e 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -35,6 +35,9 @@ #ifdef HAVE_MALLOC_H #include <malloc.h> #endif +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#endif #ifndef AL_NO_UID_DEFS #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) @@ -529,6 +532,22 @@ FILE *OpenDataFile(const char *fname, const char *subdir) return f; } + +vector_al_string SearchDataFiles(const char *match, const char *subdir) +{ + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + + while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) + althrd_yield(); + + ERR("FIXME\n"); + + ATOMIC_LOAD(&search_lock, 0); + + return results; +} + #else #ifdef HAVE_DLFCN_H @@ -646,6 +665,198 @@ FILE *OpenDataFile(const char *fname, const char *subdir) return NULL; } + +static const char *MatchString; +static int MatchFilter(const struct dirent *dir) +{ + const char *match = MatchString; + const char *name = dir->d_name; + int ret = 1; + + do { + char *p = strchr(match, '%'); + if(!p) + ret = strcmp(match, name) == 0; + else + { + size_t len = p-match; + ret = strncmp(match, name, len) == 0; + if(ret) + { + match += len; + name += len; + + ++p; + if(*p == 'r') + { + char *end; + ret = strtoul(name, &end, 10) > 0; + if(ret) name = end; + ++p; + } + } + } + + match = p; + } while(ret && match && *match); + + return ret; +} + +static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results) +{ + struct dirent **namelist; + char *sep, *p; + int n, i; + + if(!match[0]) + return; + + sep = strrchr(match, '/'); + p = strchr(match, '%'); + + if(!sep) + { + MatchString = match; + TRACE("Searching %s for %s\n", path?path:"/", match); + n = scandir(path?path:"/", &namelist, MatchFilter, alphasort); + if(n >= 0) + { + for(i = 0;i < n;++i) + { + al_string str = AL_STRING_INIT_STATIC(); + if(path) al_string_copy_cstr(&str, path); + al_string_append_char(&str, '/'); + al_string_append_cstr(&str, namelist[i]->d_name); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + free(namelist[i]); + } + free(namelist); + } + + return; + } + + if(!p || p-sep >= 0) + { + al_string npath = AL_STRING_INIT_STATIC(); + if(path) al_string_append_cstr(&npath, path); + al_string_append_char(&npath, '/'); + al_string_append_range(&npath, match, sep); + + TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1); + RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); + + al_string_deinit(&npath); + return; + } + + sep = strchr(match, '/'); + while(sep) + { + char *next = strchr(sep+1, '/'); + if(next-p < 0) + { + al_string npath = AL_STRING_INIT_STATIC(); + al_string nmatch = AL_STRING_INIT_STATIC(); + + if(path) al_string_append_cstr(&npath, path); + al_string_append_char(&npath, '/'); + al_string_append_range(&npath, match, sep); + + al_string_append_range(&nmatch, sep+1, next); + + MatchString = al_string_get_cstr(nmatch); + TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString); + n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort); + if(n >= 0) + { + al_string ndir = AL_STRING_INIT_STATIC(); + for(i = 0;i < n;++i) + { + al_string_copy(&ndir, npath); + al_string_append_char(&ndir, '/'); + al_string_append_cstr(&ndir, namelist[i]->d_name); + free(namelist[i]); + TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1); + RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); + } + al_string_deinit(&ndir); + free(namelist); + } + + al_string_deinit(&nmatch); + al_string_deinit(&npath); + break; + } + } +} + +vector_al_string SearchDataFiles(const char *match, const char *subdir) +{ + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + + while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) + althrd_yield(); + + if(match[0] == '/') + RecurseDirectorySearch(NULL, match+1, &results); + else + { + al_string path = AL_STRING_INIT_STATIC(); + const char *str, *next; + + // Search CWD + RecurseDirectorySearch(".", match, &results); + + // Search local data dir + if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') + { + al_string_append_cstr(&path, str); + al_string_append_char(&path, '/'); + al_string_append_cstr(&path, subdir); + } + else if((str=getenv("HOME")) != NULL && str[0] != '\0') + { + al_string_append_cstr(&path, str); + al_string_append_cstr(&path, "/.local/share/"); + al_string_append_cstr(&path, subdir); + } + if(!al_string_empty(path)) + RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + + // Search global data dirs + if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') + str = "/usr/local/share/:/usr/share/"; + + next = str; + while((str=next) != NULL && str[0] != '\0') + { + next = strchr(str, ':'); + if(!next) + al_string_copy_cstr(&path, str); + else + { + al_string_clear(&path); + al_string_append_range(&path, str, next); + ++next; + } + al_string_append_char(&path, '/'); + al_string_append_cstr(&path, subdir); + + RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + } + + al_string_deinit(&path); + } + + ATOMIC_LOAD(&search_lock, 0); + + return results; +} + #endif diff --git a/CMakeLists.txt b/CMakeLists.txt index 39fdd44e..ea2d5150 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,7 +337,7 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H) CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H) -CHECK_INCLUDE_FILE(ftw.h HAVE_FTW_H) +CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H) CHECK_INCLUDE_FILE(io.h HAVE_IO_H) CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H) CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5051baf7..837d9e76 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -971,6 +971,8 @@ void FillCPUCaps(ALuint capfilter); FILE *OpenDataFile(const char *fname, const char *subdir); +vector_al_string SearchDataFiles(const char *match, const char *subdir); + /* Small hack to use a pointer-to-array type as a normal argument type. * Shouldn't be used directly. */ typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; diff --git a/config.h.in b/config.h.in index 817e1691..863b5e6e 100644 --- a/config.h.in +++ b/config.h.in @@ -139,8 +139,8 @@ /* Define if we have malloc.h */ #cmakedefine HAVE_MALLOC_H -/* Define if we have ftw.h */ -#cmakedefine HAVE_FTW_H +/* Define if we have dirent.h */ +#cmakedefine HAVE_DIRENT_H /* Define if we have io.h */ #cmakedefine HAVE_IO_H |