unix,win: add ability to retrieve all env variables

Fixes: https://github.com/libuv/libuv/issues/2400

PR-URL: https://github.com/libuv/libuv/pull/2404
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
Saúl Ibarra Corretgé 2019-08-01 09:48:38 +02:00
parent ef218cede9
commit 2480b6158a
6 changed files with 212 additions and 1 deletions

View File

@ -180,6 +180,17 @@ Data types
char machine[256];
} uv_utsname_t;
.. c:type:: uv_env_item_t
Data type for environment variable storage.
::
typedef struct uv_env_item_s {
char* name;
char* value;
} uv_env_item_t;
API
---
@ -523,6 +534,23 @@ API
.. versionadded:: 1.8.0
.. c:function:: int uv_os_environ(uv_env_item_t** envitems, int* count)
Retrieves all environment variables. This function will allocate memory
which must be freed by calling :c:func:`uv_os_free_environ`.
.. warning::
This function is not thread safe.
.. versionadded:: 1.31.0
.. c:function:: void uv_os_free_environ(uv_env_item_t* envitems, int count);
Frees the memory allocated for the environment variables by
:c:func:`uv_os_environ`.
.. versionadded:: 1.31.0
.. c:function:: int uv_os_getenv(const char* name, char* buffer, size_t* size)
Retrieves the environment variable specified by `name`, copies its value

View File

@ -231,6 +231,7 @@ typedef struct uv_fs_s uv_fs_t;
typedef struct uv_work_s uv_work_t;
/* None of the above. */
typedef struct uv_env_item_s uv_env_item_t;
typedef struct uv_cpu_info_s uv_cpu_info_t;
typedef struct uv_interface_address_s uv_interface_address_t;
typedef struct uv_dirent_s uv_dirent_t;
@ -1162,6 +1163,13 @@ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count);
struct uv_env_item_s {
char* name;
char* value;
};
UV_EXTERN int uv_os_environ(uv_env_item_t** envitems, int* count);
UV_EXTERN void uv_os_free_environ(uv_env_item_t* envitems, int count);
UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
UV_EXTERN int uv_os_setenv(const char* name, const char* value);
UV_EXTERN int uv_os_unsetenv(const char* name);

View File

@ -50,11 +50,15 @@
#endif
#ifdef __APPLE__
# include <crt_externs.h>
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
# include <sys/filio.h>
# if defined(O_CLOEXEC)
# define UV__O_CLOEXEC O_CLOEXEC
# endif
# define environ (*_NSGetEnviron())
#else
extern char** environ;
#endif
#if defined(__DragonFly__) || \
@ -1284,6 +1288,62 @@ int uv_translate_sys_error(int sys_errno) {
}
int uv_os_environ(uv_env_item_t** envitems, int* count) {
int i, j, cnt;
uv_env_item_t* envitem;
*envitems = NULL;
*count = 0;
for (i = 0; environ[i] != NULL; i++);
*envitems = uv__calloc(i, sizeof(**envitems));
if (envitems == NULL)
return UV_ENOMEM;
for (j = 0, cnt = 0; j < i; j++) {
char* buf;
char* ptr;
if (environ[j] == NULL)
break;
buf = uv__strdup(environ[j]);
if (buf == NULL)
goto fail;
ptr = strchr(buf, '=');
if (ptr == NULL) {
uv__free(buf);
continue;
}
*ptr = '\0';
envitem = &(*envitems)[cnt];
envitem->name = buf;
envitem->value = ptr + 1;
cnt++;
}
*count = cnt;
return 0;
fail:
for (i = 0; i < cnt; i++) {
envitem = &(*envitems)[cnt];
uv__free(envitem->name);
}
uv__free(*envitems);
*envitems = NULL;
*count = 0;
return UV_ENOMEM;
}
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
char* var;
size_t len;

View File

@ -786,3 +786,14 @@ void uv_loop_delete(uv_loop_t* loop) {
if (loop != default_loop)
uv__free(loop);
}
void uv_os_free_environ(uv_env_item_t* envitems, int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(envitems[i].name);
}
uv__free(envitems);
}

View File

@ -1397,6 +1397,75 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
}
int uv_os_environ(uv_env_item_t** envitems, int* count) {
wchar_t* env;
wchar_t* penv;
int i, cnt;
uv_env_item_t* envitem;
*envitems = NULL;
*count = 0;
env = GetEnvironmentStringsW();
if (env == NULL)
return 0;
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
*envitems = uv__calloc(i, sizeof(**envitems));
if (envitems == NULL) {
FreeEnvironmentStringsW(env);
return UV_ENOMEM;
}
penv = env;
cnt = 0;
while (*penv != L'\0' && cnt < i) {
char* buf;
char* ptr;
if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
goto fail;
ptr = strchr(buf, '=');
if (ptr == NULL) {
uv__free(buf);
goto do_continue;
}
*ptr = '\0';
envitem = &(*envitems)[cnt];
envitem->name = buf;
envitem->value = ptr + 1;
cnt++;
do_continue:
penv += wcslen(penv) + 1;
}
FreeEnvironmentStringsW(env);
*count = cnt;
return 0;
fail:
FreeEnvironmentStringsW(env);
for (i = 0; i < cnt; i++) {
envitem = &(*envitems)[cnt];
uv__free(envitem->name);
}
uv__free(*envitems);
*envitems = NULL;
*count = 0;
return UV_ENOMEM;
}
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
wchar_t var[MAX_ENV_VAR_LENGTH];
wchar_t* name_w;

View File

@ -27,9 +27,11 @@
TEST_IMPL(env_vars) {
const char* name = "UV_TEST_FOO";
const char* name2 = "UV_TEST_FOO2";
char buf[BUF_SIZE];
size_t size;
int r;
int i, r, envcount, found;
uv_env_item_t* envitems;
/* Reject invalid inputs when setting an environment variable */
r = uv_os_setenv(NULL, "foo");
@ -86,5 +88,38 @@ TEST_IMPL(env_vars) {
r = uv_os_unsetenv(name);
ASSERT(r == 0);
/* Check getting all env variables. */
r = uv_os_setenv(name, "123456789");
ASSERT(r == 0);
r = uv_os_setenv(name2, "");
ASSERT(r == 0);
r = uv_os_environ(&envitems, &envcount);
ASSERT(r == 0);
ASSERT(envcount > 0);
found = 0;
for (i = 0; i < envcount; i++) {
/* printf("Env: %s = %s\n", envitems[i].name, envitems[i].value); */
if (strcmp(envitems[i].name, name) == 0) {
found++;
ASSERT(strcmp(envitems[i].value, "123456789") == 0);
} else if (strcmp(envitems[i].name, name2) == 0) {
found++;
ASSERT(strlen(envitems[i].value) == 0);
}
}
ASSERT(found == 2);
uv_os_free_environ(envitems, envcount);
r = uv_os_unsetenv(name);
ASSERT(r == 0);
r = uv_os_unsetenv(name2);
ASSERT(r == 0);
return 0;
}