From 12372298a2a5fd7cd2274fcb2427581f35a6a2c1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 18 Sep 2013 17:49:10 +0200 Subject: win32: add getenv() UTF-8 variant This is a bit "hard", because getenv() returns a static string, and we can't just return an allocated string. We also want getenv() to be thread-safe if possible. (If the mpv core is going to be more threaded, we sure do want the lower layers to be thread-safe as well.) --- osdep/io.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ osdep/io.h | 2 ++ 2 files changed, 62 insertions(+) (limited to 'osdep') diff --git a/osdep/io.c b/osdep/io.c index f6ccbb4f74..b618c76747 100644 --- a/osdep/io.c +++ b/osdep/io.c @@ -58,6 +58,12 @@ char *mp_to_utf8(void *talloc_ctx, const wchar_t *s) #include #include +#ifdef HAVE_PTHREADS +#include +#endif + +#include "mpvcore/mp_talloc.h" + //http://git.libav.org/?p=libav.git;a=blob;f=cmdutils.c;h=ade3f10ce2fc030e32e375a85fbd06c26d43a433#l161 static char** win32_argv_utf8; @@ -255,4 +261,58 @@ int mp_mkdir(const char *path, int mode) return res; } +static char **utf8_environ; +static void *utf8_environ_ctx; + +static void free_env(void) +{ + talloc_free(utf8_environ_ctx); + utf8_environ_ctx = NULL; + utf8_environ = NULL; +} + +// Note: UNIX getenv() returns static strings, and we try to do the same. Since +// using putenv() is not multithreading safe, we don't expect env vars to change +// at runtime, and converting/allocating them in advance is ok. +static void init_getenv(void) +{ + if (utf8_environ_ctx) + return; + wchar_t *wenv = GetEnvironmentStringsW(); + if (!wenv) + return; + utf8_environ_ctx = talloc_new(NULL); + int num_env = 0; + while (1) { + size_t len = wcslen(wenv); + if (!len) + break; + char *s = mp_to_utf8(utf8_environ_ctx, wenv); + MP_TARRAY_APPEND(utf8_environ_ctx, utf8_environ, num_env, s); + wenv += len + 1; + } + MP_TARRAY_APPEND(utf8_environ_ctx, utf8_environ, num_env, NULL); + // Avoid showing up in leak detectors etc. + atexit(free_env); +} + +char *mp_getenv(const char *name) +{ +#ifdef HAVE_PTHREADS + static pthread_once_t once_init_getenv = PTHREAD_ONCE_INIT; + pthread_once(&once_init_getenv, init_getenv); +#else + init_getenv(); +#endif + // Copied from musl, http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT + // Copyright © 2005-2013 Rich Felker, standard MIT license + int i; + size_t l = strlen(name); + if (!utf8_environ || !*name || strchr(name, '=')) return NULL; + for (i=0; utf8_environ[i] && (strncmp(name, utf8_environ[i], l) + || utf8_environ[i][l] != '='); i++) {} + if (utf8_environ[i]) return utf8_environ[i] + l+1; + return NULL; +} + #endif // __MINGW32__ diff --git a/osdep/io.h b/osdep/io.h index 7554b402d4..5dd93a79a1 100644 --- a/osdep/io.h +++ b/osdep/io.h @@ -59,6 +59,7 @@ DIR *mp_opendir(const char *path); struct dirent *mp_readdir(DIR *dir); int mp_closedir(DIR *dir); int mp_mkdir(const char *path, int mode); +char *mp_getenv(const char *name); // NOTE: stat is not overridden with mp_stat, because MinGW-w64 defines it as // macro. @@ -72,6 +73,7 @@ int mp_mkdir(const char *path, int mode); #define readdir(...) mp_readdir(__VA_ARGS__) #define closedir(...) mp_closedir(__VA_ARGS__) #define mkdir(...) mp_mkdir(__VA_ARGS__) +#define getenv(...) mp_getenv(__VA_ARGS__) #else /* __MINGW32__ */ -- cgit v1.2.3