aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2015-10-03 20:41:18 -0700
committerChris Robinson <[email protected]>2015-10-03 20:41:18 -0700
commit70fbc2b1ff254295338c6d42b41d9fdb43b02d8f (patch)
tree71b1e437aca72282b170d584f270c429a84b3149
parentaa10068ca20c2241c8d80627a5be3aeb39efcea2 (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.h1
-rw-r--r--Alc/backends/winmm.c1
-rw-r--r--Alc/helpers.c211
-rw-r--r--CMakeLists.txt2
-rw-r--r--OpenAL32/Include/alMain.h2
-rw-r--r--config.h.in4
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