diff options
Diffstat (limited to 'Alc/helpers.c')
-rw-r--r-- | Alc/helpers.c | 1431 |
1 files changed, 622 insertions, 809 deletions
diff --git a/Alc/helpers.c b/Alc/helpers.c index 7b9e58e0..d2cb6253 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -32,12 +32,21 @@ #include <time.h> #include <errno.h> #include <stdarg.h> +#include <ctype.h> #ifdef HAVE_MALLOC_H #include <malloc.h> #endif #ifdef HAVE_DIRENT_H #include <dirent.h> #endif +#ifdef HAVE_PROC_PIDPATH +#include <libproc.h> +#endif + +#ifdef __FreeBSD__ +#include <sys/types.h> +#include <sys/sysctl.h> +#endif #ifndef AL_NO_UID_DEFS #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) @@ -60,11 +69,13 @@ DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); -#ifdef HAVE_MMDEVAPI +#ifdef HAVE_WASAPI +#include <wtypes.h> #include <devpropdef.h> #include <propkeydef.h> DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); #endif #endif #endif /* AL_NO_UID_DEFS */ @@ -89,6 +100,10 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x #endif #ifndef _WIN32 +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> #include <unistd.h> #elif defined(_WIN32_IE) #include <shlobj.h> @@ -96,6 +111,8 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x #include "alMain.h" #include "alu.h" +#include "cpu_caps.h" +#include "fpu_modes.h" #include "atomic.h" #include "uintmap.h" #include "vector.h" @@ -105,71 +122,51 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x extern inline ALuint NextPowerOf2(ALuint value); +extern inline size_t RoundUp(size_t value, size_t r); extern inline ALint fastf2i(ALfloat f); -extern inline ALuint fastf2u(ALfloat f); +extern inline int float2int(float f); +extern inline float fast_roundf(float f); +#ifndef __GNUC__ +#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) +extern inline int msvc64_ctz64(ALuint64 v); +#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) +extern inline int msvc_ctz64(ALuint64 v); +#else +extern inline int fallback_popcnt64(ALuint64 v); +extern inline int fallback_ctz64(ALuint64 value); +#endif +#endif -ALuint CPUCapFlags = 0; +#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +typedef unsigned int reg_type; +static inline void get_cpuid(int f, reg_type *regs) +{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } +#define CAN_GET_CPUID +#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +typedef int reg_type; +static inline void get_cpuid(int f, reg_type *regs) +{ (__cpuid)(regs, f); } +#define CAN_GET_CPUID +#endif +int CPUCapFlags = 0; -void FillCPUCaps(ALuint capfilter) +void FillCPUCaps(int capfilter) { - ALuint caps = 0; + int caps = 0; /* FIXME: We really should get this for all available CPUs in case different * CPUs have different caps (is that possible on one machine?). */ -#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) +#ifdef CAN_GET_CPUID union { - unsigned int regs[4]; - char str[sizeof(unsigned int[4])]; - } cpuinf[3]; + reg_type regs[4]; + char str[sizeof(reg_type[4])]; + } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; - if(!__get_cpuid(0, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - ERR("Failed to get CPUID\n"); - else - { - unsigned int maxfunc = cpuinf[0].regs[0]; - unsigned int maxextfunc = 0; - - if(__get_cpuid(0x80000000, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - maxextfunc = cpuinf[0].regs[0]; - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004 && - __get_cpuid(0x80000002, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]) && - __get_cpuid(0x80000003, &cpuinf[1].regs[0], &cpuinf[1].regs[1], &cpuinf[1].regs[2], &cpuinf[1].regs[3]) && - __get_cpuid(0x80000004, &cpuinf[2].regs[0], &cpuinf[2].regs[1], &cpuinf[2].regs[2], &cpuinf[2].regs[3])) - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - - if(maxfunc >= 1 && - __get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - { - if((cpuinf[0].regs[3]&(1<<25))) - { - caps |= CPU_CAP_SSE; - if((cpuinf[0].regs[3]&(1<<26))) - { - caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<0))) - { - caps |= CPU_CAP_SSE3; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } - } - } - } -#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) - union { - int regs[4]; - char str[sizeof(int[4])]; - } cpuinf[3]; - - (__cpuid)(cpuinf[0].regs, 0); + get_cpuid(0, cpuinf[0].regs); if(cpuinf[0].regs[0] == 0) ERR("Failed to get CPUID\n"); else @@ -177,7 +174,7 @@ void FillCPUCaps(ALuint capfilter) unsigned int maxfunc = cpuinf[0].regs[0]; unsigned int maxextfunc; - (__cpuid)(cpuinf[0].regs, 0x80000000); + get_cpuid(0x80000000, cpuinf[0].regs); maxextfunc = cpuinf[0].regs[0]; TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); @@ -185,29 +182,23 @@ void FillCPUCaps(ALuint capfilter) TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); if(maxextfunc >= 0x80000004) { - (__cpuid)(cpuinf[0].regs, 0x80000002); - (__cpuid)(cpuinf[1].regs, 0x80000003); - (__cpuid)(cpuinf[2].regs, 0x80000004); + get_cpuid(0x80000002, cpuinf[0].regs); + get_cpuid(0x80000003, cpuinf[1].regs); + get_cpuid(0x80000004, cpuinf[2].regs); TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); } if(maxfunc >= 1) { - (__cpuid)(cpuinf[0].regs, 1); + get_cpuid(1, cpuinf[0].regs); if((cpuinf[0].regs[3]&(1<<25))) - { caps |= CPU_CAP_SSE; - if((cpuinf[0].regs[3]&(1<<26))) - { - caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<0))) - { - caps |= CPU_CAP_SSE3; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } - } + if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) + caps |= CPU_CAP_SSE2; + if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) + caps |= CPU_CAP_SSE3; + if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) + caps |= CPU_CAP_SSE4_1; } } #else @@ -227,8 +218,50 @@ void FillCPUCaps(ALuint capfilter) #endif #endif #ifdef HAVE_NEON - /* Assume Neon support if compiled with it */ - caps |= CPU_CAP_NEON; + FILE *file = fopen("/proc/cpuinfo", "rt"); + if(!file) + ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); + else + { + al_string features = AL_STRING_INIT_STATIC(); + char buf[256]; + + while(fgets(buf, sizeof(buf), file) != NULL) + { + if(strncmp(buf, "Features\t:", 10) != 0) + continue; + + alstr_copy_cstr(&features, buf+10); + while(VECTOR_BACK(features) != '\n') + { + if(fgets(buf, sizeof(buf), file) == NULL) + break; + alstr_append_cstr(&features, buf); + } + break; + } + fclose(file); + file = NULL; + + if(!alstr_empty(features)) + { + const char *str = alstr_get_cstr(features); + while(isspace(str[0])) ++str; + + TRACE("Got features string:%s\n", str); + while((str=strstr(str, "neon")) != NULL) + { + if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) + { + caps |= CPU_CAP_NEON; + break; + } + ++str; + } + } + + alstr_reset(&features); + } #endif TRACE("Extensions:%s%s%s%s%s%s\n", @@ -236,136 +269,125 @@ void FillCPUCaps(ALuint capfilter) ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""), ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""), - ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""), + ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""), ((!capfilter) ? " -none-" : "") ); CPUCapFlags = caps & capfilter; } -void *al_malloc(size_t alignment, size_t size) -{ -#if defined(HAVE_ALIGNED_ALLOC) - size = (size+(alignment-1))&~(alignment-1); - return aligned_alloc(alignment, size); -#elif defined(HAVE_POSIX_MEMALIGN) - void *ret; - if(posix_memalign(&ret, alignment, size) == 0) - return ret; - return NULL; -#elif defined(HAVE__ALIGNED_MALLOC) - return _aligned_malloc(size, alignment); -#else - char *ret = malloc(size+alignment); - if(ret != NULL) - { - *(ret++) = 0x00; - while(((ptrdiff_t)ret&(alignment-1)) != 0) - *(ret++) = 0x55; - } - return ret; -#endif -} - -void *al_calloc(size_t alignment, size_t size) -{ - void *ret = al_malloc(alignment, size); - if(ret) memset(ret, 0, size); - return ret; -} - -void al_free(void *ptr) -{ -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) - free(ptr); -#elif defined(HAVE__ALIGNED_MALLOC) - _aligned_free(ptr); -#else - if(ptr != NULL) - { - char *finder = ptr; - do { - --finder; - } while(*finder == 0x55); - free(finder); - } -#endif -} - - void SetMixerFPUMode(FPUCtl *ctl) { -#ifdef HAVE_FENV_H - fegetenv(STATIC_CAST(fenv_t, ctl)); -#if defined(__GNUC__) && defined(HAVE_SSE) - /* FIXME: Some fegetenv implementations can get the SSE environment too? - * How to tell when it does? */ - if((CPUCapFlags&CPU_CAP_SSE)) - __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); -#endif - -#ifdef FE_TOWARDZERO - fesetround(FE_TOWARDZERO); -#endif #if defined(__GNUC__) && defined(HAVE_SSE) if((CPUCapFlags&CPU_CAP_SSE)) { - int sseState = ctl->sse_state; - sseState |= 0x6000; /* set round-to-zero */ + __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); + unsigned int sseState = ctl->sse_state; sseState |= 0x8000; /* set flush-to-zero */ if((CPUCapFlags&CPU_CAP_SSE2)) sseState |= 0x0040; /* set denormals-are-zero */ __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); } -#endif #elif defined(HAVE___CONTROL87_2) - int mode; - __control87_2(0, 0, &ctl->state, NULL); - __control87_2(_RC_CHOP, _MCW_RC, &mode, NULL); -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - { - __control87_2(0, 0, NULL, &ctl->sse_state); - __control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode); - } -#endif + __control87_2(0, 0, &ctl->state, &ctl->sse_state); + _control87(_DN_FLUSH, _MCW_DN); #elif defined(HAVE__CONTROLFP) ctl->state = _controlfp(0, 0); - (void)_controlfp(_RC_CHOP, _MCW_RC); + _controlfp(_DN_FLUSH, _MCW_DN); #endif } void RestoreFPUMode(const FPUCtl *ctl) { -#ifdef HAVE_FENV_H - fesetenv(STATIC_CAST(fenv_t, ctl)); #if defined(__GNUC__) && defined(HAVE_SSE) if((CPUCapFlags&CPU_CAP_SSE)) __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); -#endif #elif defined(HAVE___CONTROL87_2) int mode; - __control87_2(ctl->state, _MCW_RC, &mode, NULL); -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - __control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode); -#endif + __control87_2(ctl->state, _MCW_DN, &mode, NULL); + __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode); #elif defined(HAVE__CONTROLFP) - _controlfp(ctl->state, _MCW_RC); + _controlfp(ctl->state, _MCW_DN); #endif } +static int StringSortCompare(const void *str1, const void *str2) +{ + return alstr_cmp(*(const_al_string*)str1, *(const_al_string*)str2); +} + #ifdef _WIN32 +static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +{ + WCHAR *ret = NULL; + while(*str) + { + if(*str == ch) + ret = str; + ++str; + } + return ret; +} + +void GetProcBinary(al_string *path, al_string *fname) +{ + WCHAR *pathname, *sep; + DWORD pathlen; + DWORD len; + + pathlen = 256; + pathname = malloc(pathlen * sizeof(pathname[0])); + while(pathlen > 0 && (len=GetModuleFileNameW(NULL, pathname, pathlen)) == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = malloc(pathlen * sizeof(pathname[0])); + } + if(len == 0) + { + free(pathname); + ERR("Failed to get process name: error %lu\n", GetLastError()); + return; + } + + pathname[len] = 0; + if((sep=strrchrW(pathname, '\\')) != NULL) + { + WCHAR *sep2 = strrchrW(sep+1, '/'); + if(sep2) sep = sep2; + } + else + sep = strrchrW(pathname, '/'); + + if(sep) + { + if(path) alstr_copy_wrange(path, pathname, sep); + if(fname) alstr_copy_wcstr(fname, sep+1); + } + else + { + if(path) alstr_clear(path); + if(fname) alstr_copy_wcstr(fname, pathname); + } + free(pathname); + + if(path && fname) + TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); + else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); + else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); +} + + static WCHAR *FromUTF8(const char *str) { WCHAR *out = NULL; @@ -471,363 +493,290 @@ void al_print(const char *type, const char *func, const char *fmt, ...) static inline int is_slash(int c) { return (c == '\\' || c == '/'); } -FILE *OpenDataFile(const char *fname, const char *subdir) +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) { - static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - WCHAR *wname=NULL, *wsubdir=NULL; - FILE *f; - size_t i; + al_string pathstr = AL_STRING_INIT_STATIC(); + WIN32_FIND_DATAW fdata; + WCHAR *wpath; + HANDLE hdl; - wname = FromUTF8(fname); - if(!wname) - { - ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname); - return NULL; - } + alstr_copy_cstr(&pathstr, path); + alstr_append_cstr(&pathstr, "\\*"); + alstr_append_cstr(&pathstr, ext); - /* If the path is absolute, open it directly. */ - if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2])) - { - f = _wfopen(wname, L"rb"); - if(f) TRACE("Opened %s\n", fname); - else WARN("Could not open %s\n", fname); - free(wname); - return f; - } + TRACE("Searching %s\n", alstr_get_cstr(pathstr)); - /* Try the current directory first before the data directories. */ - if((f=_wfopen(wname, L"rb")) != NULL) - { - TRACE("Opened %s\n", fname); - free(wname); - return f; - } - - wsubdir = FromUTF8(subdir); - if(!wsubdir) - { - ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir); - free(wname); - return NULL; - } + wpath = FromUTF8(alstr_get_cstr(pathstr)); - for(i = 0;i < COUNTOF(ids);i++) + hdl = FindFirstFileW(wpath, &fdata); + if(hdl != INVALID_HANDLE_VALUE) { - WCHAR buffer[PATH_MAX]; - size_t len; - - if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE) - continue; - - len = lstrlenW(buffer); - if(len > 0 && is_slash(buffer[len-1])) - buffer[--len] = '\0'; - _snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname); - len = lstrlenW(buffer); - while(len > 0) - { - --len; - if(buffer[len] == '/') - buffer[len] = '\\'; - } - - if((f=_wfopen(buffer, L"rb")) != NULL) - { - al_string filepath = AL_STRING_INIT_STATIC(); - al_string_copy_wcstr(&filepath, buffer); - TRACE("Opened %s\n", al_string_get_cstr(filepath)); - al_string_deinit(&filepath); - break; - } + size_t base = VECTOR_SIZE(*results); + do { + al_string str = AL_STRING_INIT_STATIC(); + alstr_copy_cstr(&str, path); + alstr_append_char(&str, '\\'); + alstr_append_wcstr(&str, fdata.cFileName); + TRACE("Got result %s\n", alstr_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); + + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } - free(wname); - free(wsubdir); - if(f == NULL) - WARN("Could not open %s\\%s\n", subdir, fname); - return f; + free(wpath); + alstr_reset(&pathstr); } - -static const WCHAR *strchrW(const WCHAR *str, WCHAR ch) +vector_al_string SearchDataFiles(const char *ext, const char *subdir) { - for(;*str != 0;++str) - { - if(*str == ch) - return str; - } - return NULL; -} + static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + size_t i; -static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch) -{ - const WCHAR *ret = NULL; - for(;*str != 0;++str) + while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1) + althrd_yield(); + + /* If the path is absolute, use it directly. */ + if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) { - if(*str == ch) - ret = str; + al_string path = AL_STRING_INIT_STATIC(); + alstr_copy_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + + DirectorySearch(alstr_get_cstr(path), ext, &results); + + alstr_reset(&path); } - return ret; -} + else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + DirectorySearch(subdir, ext, &results); + else + { + al_string path = AL_STRING_INIT_STATIC(); + WCHAR *cwdbuf; -/* Compares the filename in the find data with the match string. The match - * string may contain the "%r" marker to signifiy a sample rate (really any - * positive integer), or "%%" to signify a single '%'. - */ -static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata) -{ - const WCHAR *name = fdata->cFileName; - int ret = 1; - - do { - const WCHAR *p = strchrW(match, '%'); - if(!p) - ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - match, -1, name, -1) == CSTR_EQUAL; + /* Search the app-local directory. */ + if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0') + { + alstr_copy_wcstr(&path, cwdbuf); + if(is_slash(VECTOR_BACK(path))) + { + VECTOR_POP_BACK(path); + *VECTOR_END(path) = 0; + } + } + else if(!(cwdbuf=_wgetcwd(NULL, 0))) + alstr_copy_cstr(&path, "."); else { - int len = p-match; - ret = lstrlenW(name) >= len; - if(ret) - ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - match, len, name, len) == CSTR_EQUAL; - if(ret) + alstr_copy_wcstr(&path, cwdbuf); + if(is_slash(VECTOR_BACK(path))) { - match += len; - name += len; - - ++p; - if(*p == 'r') - { - unsigned long l = 0; - while(*name >= '0' && *name <= '9') - { - l = l*10 + (*name-'0'); - ++name; - } - ret = l > 0; - ++p; - } + VECTOR_POP_BACK(path); + *VECTOR_END(path) = 0; } + free(cwdbuf); } +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + DirectorySearch(alstr_get_cstr(path), ext, &results); - match = p; - } while(ret && match && *match); - - return ret; -} - -static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results) -{ - WIN32_FIND_DATAW fdata; - const WCHAR *sep, *p; - HANDLE hdl; + /* Search the local and global data dirs. */ + for(i = 0;i < COUNTOF(ids);i++) + { + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) + { + alstr_copy_wcstr(&path, buffer); + if(!is_slash(VECTOR_BACK(path))) + alstr_append_char(&path, '\\'); + alstr_append_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH - if(!match[0]) - return; + DirectorySearch(alstr_get_cstr(path), ext, &results); + } + } - /* Find the last directory separator and the next '%' marker in the match - * string. */ - sep = strrchrW(match, '\\'); - p = strchrW(match, '%'); + alstr_reset(&path); + } - /* If there's no separator, test the files in the specified path against - * the match string, and add the results. */ - if(!sep) - { - al_string pathstr = AL_STRING_INIT_STATIC(); - WCHAR *wpath; + ATOMIC_STORE_SEQ(&search_lock, 0); - TRACE("Searching %s for %ls\n", path, match); + return results; +} - al_string_append_cstr(&pathstr, path); - al_string_append_cstr(&pathstr, "\\*.*"); - wpath = FromUTF8(al_string_get_cstr(pathstr)); - hdl = FindFirstFileW(wpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - do { - if(MatchFilter(match, &fdata)) - { - al_string str = AL_STRING_INIT_STATIC(); - al_string_copy_cstr(&str, path); - al_string_append_char(&str, '\\'); - al_string_append_wcstr(&str, fdata.cFileName); - TRACE("Got result %s\n", al_string_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - } +struct FileMapping MapFileToMem(const char *fname) +{ + struct FileMapping ret = { NULL, NULL, NULL, 0 }; + MEMORY_BASIC_INFORMATION meminfo; + HANDLE file, fmap; + WCHAR *wname; + void *ptr; - free(wpath); - al_string_deinit(&pathstr); + wname = FromUTF8(fname); - return; + file = CreateFileW(wname, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(file == INVALID_HANDLE_VALUE) + { + ERR("Failed to open %s: %lu\n", fname, GetLastError()); + free(wname); + return ret; } + free(wname); + wname = NULL; - /* If there's no '%' marker, or it's after the final separator, append the - * remaining directories to the path and recurse into it with the remaining - * filename portion. */ - if(!p || p-sep >= 0) + fmap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); + if(!fmap) { - al_string npath = AL_STRING_INIT_STATIC(); - al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '\\'); - al_string_append_wrange(&npath, match, sep); - - TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1); - RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); - - al_string_deinit(&npath); - return; + ERR("Failed to create map for %s: %lu\n", fname, GetLastError()); + CloseHandle(file); + return ret; } - /* Look for the last separator before the '%' marker, and the first - * separator after it. */ - sep = strchrW(match, '\\'); - if(sep-p >= 0) sep = NULL; - for(;;) + ptr = MapViewOfFile(fmap, FILE_MAP_READ, 0, 0, 0); + if(!ptr) { - const WCHAR *next = strchrW(sep?sep+1:match, '\\'); - if(next-p < 0) - { - al_string npath = AL_STRING_INIT_STATIC(); - WCHAR *nwpath, *nwmatch; - - /* Append up to the last directory before the one with a '%'. */ - al_string_copy_cstr(&npath, path); - if(sep) - { - al_string_append_char(&npath, '\\'); - al_string_append_wrange(&npath, match, sep); - } - al_string_append_cstr(&npath, "\\*.*"); - nwpath = FromUTF8(al_string_get_cstr(npath)); - - /* Take the directory name containing a '%' as a new string to - * match against. */ - if(!sep) - { - nwmatch = calloc(2, next-match+1); - memcpy(nwmatch, match, (next-match)*2); - } - else - { - nwmatch = calloc(2, next-(sep+1)+1); - memcpy(nwmatch, sep+1, (next-(sep+1))*2); - } - - /* For each matching directory name, recurse into it with the - * remaining string. */ - TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch); - hdl = FindFirstFileW(nwpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - do { - if(MatchFilter(nwmatch, &fdata)) - { - al_string ndir = AL_STRING_INIT_STATIC(); - al_string_copy(&ndir, npath); - al_string_append_char(&ndir, '\\'); - al_string_append_wcstr(&ndir, fdata.cFileName); - TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1); - RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); - al_string_deinit(&ndir); - } - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - } + ERR("Failed to map %s: %lu\n", fname, GetLastError()); + CloseHandle(fmap); + CloseHandle(file); + return ret; + } - free(nwmatch); - free(nwpath); - al_string_deinit(&npath); - break; - } - sep = next; + if(VirtualQuery(ptr, &meminfo, sizeof(meminfo)) != sizeof(meminfo)) + { + ERR("Failed to get map size for %s: %lu\n", fname, GetLastError()); + UnmapViewOfFile(ptr); + CloseHandle(fmap); + CloseHandle(file); + return ret; } + + ret.file = file; + ret.fmap = fmap; + ret.ptr = ptr; + ret.len = meminfo.RegionSize; + return ret; } -vector_al_string SearchDataFiles(const char *match, const char *subdir) +void UnmapFileMem(const struct FileMapping *mapping) { - static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - static RefCount search_lock; - vector_al_string results = VECTOR_INIT_STATIC(); - WCHAR *wmatch; - size_t i; + UnmapViewOfFile(mapping->ptr); + CloseHandle(mapping->fmap); + CloseHandle(mapping->file); +} - while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) - althrd_yield(); +#else - wmatch = FromUTF8(match); - if(!wmatch) - { - ERR("Failed to convert UTF-8 filename: \"%s\"\n", match); - return results; - } - for(i = 0;wmatch[i];++i) - { - if(wmatch[i] == '/') - wmatch[i] = '\\'; - } +void GetProcBinary(al_string *path, al_string *fname) +{ + char *pathname = NULL; + size_t pathlen; - /* If the path is absolute, use it directly. */ - if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2])) +#ifdef __FreeBSD__ + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) + WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); + else { - char drv[3] = { (char)wmatch[0], ':', 0 }; - RecurseDirectorySearch(drv, wmatch+3, &results); + pathname = malloc(pathlen + 1); + sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); + pathname[pathlen] = 0; } - else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\') - RecurseDirectorySearch("\\\\?", wmatch+4, &results); - else +#endif +#ifdef HAVE_PROC_PIDPATH + if(!pathname) { - al_string path = AL_STRING_INIT_STATIC(); - WCHAR *cwdbuf; + const pid_t pid = getpid(); + char procpath[PROC_PIDPATHINFO_MAXSIZE]; + int ret; - /* Search the CWD. */ - if(!(cwdbuf=_wgetcwd(NULL, 0))) - al_string_copy_cstr(&path, "."); + ret = proc_pidpath(pid, procpath, sizeof(procpath)); + if(ret < 1) + { + WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); + free(pathname); + pathname = NULL; + } else { - al_string_copy_wcstr(&path, cwdbuf); - if(is_slash(VECTOR_BACK(path))) - { - VECTOR_POP_BACK(path); - *VECTOR_ITER_END(path) = 0; - } - free(cwdbuf); + pathlen = strlen(procpath); + pathname = strdup(procpath); } - RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + } +#endif + if(!pathname) + { + const char *selfname; + ssize_t len; - /* Search the local and global data dirs. */ - for(i = 0;i < COUNTOF(ids);i++) + pathlen = 256; + pathname = malloc(pathlen); + + selfname = "/proc/self/exe"; + len = readlink(selfname, pathname, pathlen); + if(len == -1 && errno == ENOENT) { - WCHAR buffer[PATH_MAX]; - if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) - { - al_string_copy_wcstr(&path, buffer); - if(!is_slash(VECTOR_BACK(path))) - al_string_append_char(&path, '\\'); - al_string_append_cstr(&path, subdir); -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH + selfname = "/proc/self/file"; + len = readlink(selfname, pathname, pathlen); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/exe"; + len = readlink(selfname, pathname, pathlen); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/file"; + len = readlink(selfname, pathname, pathlen); + } - RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); - } + while(len > 0 && (size_t)len == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = malloc(pathlen); + len = readlink(selfname, pathname, pathlen); + } + if(len <= 0) + { + free(pathname); + WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); + return; } - al_string_deinit(&path); + pathname[len] = 0; } - free(wmatch); - ATOMIC_STORE(&search_lock, 0); + char *sep = strrchr(pathname, '/'); + if(sep) + { + if(path) alstr_copy_range(path, pathname, sep); + if(fname) alstr_copy_cstr(fname, sep+1); + } + else + { + if(path) alstr_clear(path); + if(fname) alstr_copy_cstr(fname, pathname); + } + free(pathname); - return results; + if(path && fname) + TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); + else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); + else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); } -#else #ifdef HAVE_DLFCN_H @@ -874,251 +823,108 @@ void al_print(const char *type, const char *func, const char *fmt, ...) } -FILE *OpenDataFile(const char *fname, const char *subdir) +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) { - char buffer[PATH_MAX] = ""; - const char *str, *next; - FILE *f; - - if(fname[0] == '/') - { - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - WARN("Could not open %s\n", fname); - return NULL; - } - - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - - if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') - snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname); - else if((str=getenv("HOME")) != NULL && str[0] != '\0') - snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", str, subdir, fname); - if(buffer[0]) - { - if((f=al_fopen(buffer, "rb")) != NULL) - { - TRACE("Opened %s\n", buffer); - return f; - } - } + size_t extlen = strlen(ext); + DIR *dir; - 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') + TRACE("Searching %s for *%s\n", path, ext); + dir = opendir(path); + if(dir != NULL) { - size_t len; - next = strchr(str, ':'); - - if(!next) - len = strlen(str); - else + size_t base = VECTOR_SIZE(*results); + struct dirent *dirent; + while((dirent=readdir(dir)) != NULL) { - len = next - str; - next++; + al_string str; + size_t len; + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + len = strlen(dirent->d_name); + if(!(len > extlen)) + continue; + if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) + continue; + + AL_STRING_INIT(str); + alstr_copy_cstr(&str, path); + if(VECTOR_BACK(str) != '/') + alstr_append_char(&str, '/'); + alstr_append_cstr(&str, dirent->d_name); + TRACE("Got result %s\n", alstr_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); } + closedir(dir); - if(len > sizeof(buffer)-1) - len = sizeof(buffer)-1; - strncpy(buffer, str, len); - buffer[len] = '\0'; - snprintf(buffer+len, sizeof(buffer)-len, "/%s/%s", subdir, fname); - - if((f=al_fopen(buffer, "rb")) != NULL) - { - TRACE("Opened %s\n", buffer); - return f; - } + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } - WARN("Could not open %s/%s\n", subdir, fname); - - 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 { - const 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) +vector_al_string SearchDataFiles(const char *ext, const char *subdir) { - 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); - } + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); - return; - } + while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1) + althrd_yield(); - if(!p || p-sep >= 0) + if(subdir[0] == '/') + DirectorySearch(subdir, ext, &results); + else { - 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; - } + al_string path = AL_STRING_INIT_STATIC(); + const char *str, *next; - sep = strchr(match, '/'); - if(sep-p >= 0) sep = NULL; - for(;;) - { - char *next = strchr(sep?sep+1:match, '/'); - if(next-p < 0) + /* Search the app-local directory. */ + if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') + DirectorySearch(str, ext, &results); + else { - al_string npath = AL_STRING_INIT_STATIC(); - al_string nmatch = AL_STRING_INIT_STATIC(); - - if(!sep) + size_t cwdlen = 256; + char *cwdbuf = malloc(cwdlen); + while(!getcwd(cwdbuf, cwdlen)) { - al_string_append_cstr(&npath, path?path:"/."); - MatchString = match; + free(cwdbuf); + cwdbuf = NULL; + if(errno != ERANGE) + break; + cwdlen <<= 1; + cwdbuf = malloc(cwdlen); } + if(!cwdbuf) + DirectorySearch(".", ext, &results); else { - 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); + DirectorySearch(cwdbuf, ext, &results); + free(cwdbuf); + cwdbuf = NULL; } - - al_string_deinit(&nmatch); - al_string_deinit(&npath); - break; } - sep = next; - } -} - -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; - char cwdbuf[PATH_MAX]; - - // Search CWD - if(!getcwd(cwdbuf, sizeof(cwdbuf))) - strcpy(cwdbuf, "."); - RecurseDirectorySearch(cwdbuf, 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); + alstr_copy_cstr(&path, str); + if(VECTOR_BACK(path) != '/') + alstr_append_char(&path, '/'); + alstr_append_cstr(&path, subdir); + DirectorySearch(alstr_get_cstr(path), ext, &results); } 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); + alstr_copy_cstr(&path, str); + if(VECTOR_BACK(path) == '/') + { + VECTOR_POP_BACK(path); + *VECTOR_END(path) = 0; + } + alstr_append_cstr(&path, "/.local/share/"); + alstr_append_cstr(&path, subdir); + DirectorySearch(alstr_get_cstr(path), ext, &results); } - 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') @@ -1129,30 +935,71 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) { next = strchr(str, ':'); if(!next) - al_string_copy_cstr(&path, str); + alstr_copy_cstr(&path, str); else { - al_string_clear(&path); - al_string_append_range(&path, str, next); + alstr_copy_range(&path, str, next); ++next; } - if(!al_string_empty(path)) + if(!alstr_empty(path)) { - al_string_append_char(&path, '/'); - al_string_append_cstr(&path, subdir); + if(VECTOR_BACK(path) != '/') + alstr_append_char(&path, '/'); + alstr_append_cstr(&path, subdir); - RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + DirectorySearch(alstr_get_cstr(path), ext, &results); } } - al_string_deinit(&path); + alstr_reset(&path); } - ATOMIC_STORE(&search_lock, 0); + ATOMIC_STORE_SEQ(&search_lock, 0); return results; } + +struct FileMapping MapFileToMem(const char *fname) +{ + struct FileMapping ret = { -1, NULL, 0 }; + struct stat sbuf; + void *ptr; + int fd; + + fd = open(fname, O_RDONLY, 0); + if(fd == -1) + { + ERR("Failed to open %s: (%d) %s\n", fname, errno, strerror(errno)); + return ret; + } + if(fstat(fd, &sbuf) == -1) + { + ERR("Failed to stat %s: (%d) %s\n", fname, errno, strerror(errno)); + close(fd); + return ret; + } + + ptr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if(ptr == MAP_FAILED) + { + ERR("Failed to map %s: (%d) %s\n", fname, errno, strerror(errno)); + close(fd); + return ret; + } + + ret.fd = fd; + ret.ptr = ptr; + ret.len = sbuf.st_size; + return ret; +} + +void UnmapFileMem(const struct FileMapping *mapping) +{ + munmap(mapping->ptr, mapping->len); + close(mapping->fd); +} + #endif @@ -1181,93 +1028,26 @@ void SetRTPriority(void) } -ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact) -{ - vector_ *vecptr = (vector_*)ptr; - if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count) - { - size_t old_size = (*vecptr ? (*vecptr)->Size : 0); - void *temp; - - /* Use the next power-of-2 size if we don't need to allocate the exact - * amount. This is preferred when regularly increasing the vector since - * it means fewer reallocations. Though it means it also wastes some - * memory. */ - if(exact == AL_FALSE && obj_count < INT_MAX) - obj_count = NextPowerOf2((ALuint)obj_count); - - /* Need to be explicit with the caller type's base size, because it - * could have extra padding before the start of the array (that is, - * sizeof(*vector_) may not equal base_size). */ - temp = realloc(*vecptr, base_size + obj_size*obj_count); - if(temp == NULL) return AL_FALSE; - - *vecptr = temp; - (*vecptr)->Capacity = obj_count; - (*vecptr)->Size = old_size; - } - return AL_TRUE; -} - -ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count) -{ - vector_ *vecptr = (vector_*)ptr; - if(*vecptr || obj_count > 0) - { - if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE)) - return AL_FALSE; - (*vecptr)->Size = obj_count; - } - return AL_TRUE; -} +extern inline void alstr_reset(al_string *str); +extern inline size_t alstr_length(const_al_string str); +extern inline ALboolean alstr_empty(const_al_string str); +extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); -ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend) +void alstr_clear(al_string *str) { - vector_ *vecptr = (vector_*)ptr; - if(datstart != datend) + if(!alstr_empty(*str)) { - ptrdiff_t ins_elem = (*vecptr ? ((char*)ins_pos - ((char*)(*vecptr) + base_size)) : - ((char*)ins_pos - (char*)NULL)) / - obj_size; - ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size; - - assert(numins > 0); - if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins || - !vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE)) - return AL_FALSE; - - /* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */ - if((size_t)ins_elem < (*vecptr)->Size) - { - memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size), - (char*)(*vecptr) + base_size + ((ins_elem )*obj_size), - ((*vecptr)->Size-ins_elem)*obj_size); - } - memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size), - datstart, numins*obj_size); - (*vecptr)->Size += numins; + /* Reserve one more character than the total size of the string. This + * is to ensure we have space to add a null terminator in the string + * data so it can be used as a C-style string. + */ + VECTOR_RESIZE(*str, 0, 1); + VECTOR_ELEM(*str, 0) = 0; } - return AL_TRUE; -} - - -extern inline void al_string_deinit(al_string *str); -extern inline size_t al_string_length(const_al_string str); -extern inline ALboolean al_string_empty(const_al_string str); -extern inline const al_string_char_type *al_string_get_cstr(const_al_string str); - -void al_string_clear(al_string *str) -{ - /* Reserve one more character than the total size of the string. This is to - * ensure we have space to add a null terminator in the string data so it - * can be used as a C-style string. */ - VECTOR_RESERVE(*str, 1); - VECTOR_RESIZE(*str, 0); - *VECTOR_ITER_END(*str) = 0; } -static inline int al_string_compare(const al_string_char_type *str1, size_t str1len, - const al_string_char_type *str2, size_t str2len) +static inline int alstr_compare(const al_string_char_type *str1, size_t str1len, + const al_string_char_type *str2, size_t str2len) { size_t complen = (str1len < str2len) ? str1len : str2len; int ret = memcmp(str1, str2, complen); @@ -1278,99 +1058,132 @@ static inline int al_string_compare(const al_string_char_type *str1, size_t str1 } return ret; } -int al_string_cmp(const_al_string str1, const_al_string str2) +int alstr_cmp(const_al_string str1, const_al_string str2) { - return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1), - &VECTOR_FRONT(str2), al_string_length(str2)); + return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), + &VECTOR_FRONT(str2), alstr_length(str2)); } -int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2) +int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2) { - return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1), - str2, strlen(str2)); + return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), + str2, strlen(str2)); } -void al_string_copy(al_string *str, const_al_string from) +void alstr_copy(al_string *str, const_al_string from) { - size_t len = al_string_length(from); - VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len); - *VECTOR_ITER_END(*str) = 0; + size_t len = alstr_length(from); + size_t i; + + VECTOR_RESIZE(*str, len, len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); + VECTOR_ELEM(*str, i) = 0; } -void al_string_copy_cstr(al_string *str, const al_string_char_type *from) +void alstr_copy_cstr(al_string *str, const al_string_char_type *from) { size_t len = strlen(from); - VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len); - *VECTOR_ITER_END(*str) = 0; + size_t i; + + VECTOR_RESIZE(*str, len, len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = from[i]; + VECTOR_ELEM(*str, i) = 0; +} + +void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +{ + size_t len = to - from; + size_t i; + + VECTOR_RESIZE(*str, len, len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = from[i]; + VECTOR_ELEM(*str, i) = 0; } -void al_string_append_char(al_string *str, const al_string_char_type c) +void alstr_append_char(al_string *str, const al_string_char_type c) { - VECTOR_RESERVE(*str, al_string_length(*str)+2); - VECTOR_PUSH_BACK(*str, c); - *VECTOR_ITER_END(*str) = 0; + size_t len = alstr_length(*str); + VECTOR_RESIZE(*str, len+1, len+2); + VECTOR_BACK(*str) = c; + VECTOR_ELEM(*str, len+1) = 0; } -void al_string_append_cstr(al_string *str, const al_string_char_type *from) +void alstr_append_cstr(al_string *str, const al_string_char_type *from) { size_t len = strlen(from); if(len != 0) { - VECTOR_RESERVE(*str, al_string_length(*str)+len+1); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len); - *VECTOR_ITER_END(*str) = 0; + size_t base = alstr_length(*str); + size_t i; + + VECTOR_RESIZE(*str, base+len, base+len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, base+i) = from[i]; + VECTOR_ELEM(*str, base+i) = 0; } } -void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) { - if(to != from) + size_t len = to - from; + if(len != 0) { - VECTOR_RESERVE(*str, al_string_length(*str)+(to-from)+1); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to); - *VECTOR_ITER_END(*str) = 0; + size_t base = alstr_length(*str); + size_t i; + + VECTOR_RESIZE(*str, base+len, base+len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, base+i) = from[i]; + VECTOR_ELEM(*str, base+i) = 0; } } #ifdef _WIN32 -void al_string_copy_wcstr(al_string *str, const wchar_t *from) +void alstr_copy_wcstr(al_string *str, const wchar_t *from) { int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) { - VECTOR_RESERVE(*str, len); - VECTOR_RESIZE(*str, len-1); + VECTOR_RESIZE(*str, len-1, len); WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; + VECTOR_ELEM(*str, len-1) = 0; } } -void al_string_append_wcstr(al_string *str, const wchar_t *from) +void alstr_append_wcstr(al_string *str, const wchar_t *from) { int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) { - size_t strlen = al_string_length(*str); - VECTOR_RESERVE(*str, strlen+len); - VECTOR_RESIZE(*str, strlen+len-1); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; + size_t base = alstr_length(*str); + VECTOR_RESIZE(*str, base+len-1, base+len); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL); + VECTOR_ELEM(*str, base+len-1) = 0; + } +} + +void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + { + VECTOR_RESIZE(*str, len, len+1); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, NULL, NULL); + VECTOR_ELEM(*str, len) = 0; } } -void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) { int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) { - size_t strlen = al_string_length(*str); - VECTOR_RESERVE(*str, strlen+len+1); - VECTOR_RESIZE(*str, strlen+len); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; + size_t base = alstr_length(*str); + VECTOR_RESIZE(*str, base+len, base+len+1); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL); + VECTOR_ELEM(*str, base+len) = 0; } } #endif |