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.)
This commit is contained in:
wm4 2013-09-18 17:49:10 +02:00
parent b97d10a839
commit 12372298a2
2 changed files with 62 additions and 0 deletions

View File

@ -58,6 +58,12 @@ char *mp_to_utf8(void *talloc_ctx, const wchar_t *s)
#include <io.h>
#include <fcntl.h>
#ifdef HAVE_PTHREADS
#include <pthread.h>
#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__

View File

@ -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__ */