Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
windows: make spawn with custom environment work again
Browse files Browse the repository at this point in the history
  • Loading branch information
piscisaureus committed Aug 28, 2012
1 parent 5c674b2 commit abc945b
Showing 1 changed file with 44 additions and 18 deletions.
62 changes: 44 additions & 18 deletions src/win/process.c
Expand Up @@ -37,9 +37,9 @@
typedef struct env_var {
const char* narrow;
const WCHAR* wide;
int len; /* including null or '=' */
size_t len; /* including null or '=' */
DWORD value_len;
int supplied;
int value_len;
} env_var_t;

#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
Expand Down Expand Up @@ -549,10 +549,10 @@ uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr)
* issues associated with that solution; this is the caller's
* char**, and modifying it is rude.
*/
static void check_required_vars_contains_var(env_var_t* required, int size,
static void check_required_vars_contains_var(env_var_t* required, int count,
const char* var) {
int i;
for (i = 0; i < size; ++i) {
for (i = 0; i < count; ++i) {
if (_strnicmp(required[i].narrow, var, required[i].len) == 0) {
required[i].supplied = 1;
return;
Expand All @@ -572,11 +572,11 @@ static void check_required_vars_contains_var(env_var_t* required, int size,
* these get defined if the input environment block does not contain any
* values for them.
*/
WCHAR* make_program_env(char** env_block) {
uv_err_t make_program_env(char* env_block[], WCHAR** dst_ptr) {
WCHAR* dst;
WCHAR* ptr;
char** env;
int env_len = 1 * sizeof(WCHAR); /* room for closing null */
size_t env_len = 1; /* room for closing null */
int len;
int i;
DWORD var_size;
Expand All @@ -588,36 +588,53 @@ WCHAR* make_program_env(char** env_block) {
};

for (env = env_block; *env; env++) {
int len;
check_required_vars_contains_var(required_vars,
ARRAY_SIZE(required_vars),
*env);
env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(WCHAR));

len = MultiByteToWideChar(CP_UTF8,
0,
*env,
-1,
NULL,
0);
if (len <= 0) {
return uv__new_sys_error(GetLastError());
}

env_len += len;
}

for (i = 0; i < ARRAY_SIZE(required_vars); ++i) {
if (!required_vars[i].supplied) {
env_len += required_vars[i].len * sizeof(WCHAR);
env_len += required_vars[i].len;
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
if (var_size == 0) {
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
return uv__new_sys_error(GetLastError());
}
required_vars[i].value_len = (int)var_size;
env_len += (int)var_size * sizeof(WCHAR);
required_vars[i].value_len = var_size;
env_len += var_size;
}
}

dst = malloc(env_len);
dst = malloc(env_len * sizeof(WCHAR));
if (!dst) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
return uv__new_artificial_error(UV_ENOMEM);
}

ptr = dst;

for (env = env_block; *env; env++, ptr += len) {
len = uv_utf8_to_utf16(*env, ptr, (size_t)(env_len - (ptr - dst)));
if (!len) {
len = MultiByteToWideChar(CP_UTF8,
0,
*env,
-1,
ptr,
(int) (env_len - (ptr - dst)));

This comment has been minimized.

Copy link
@bnoordhuis

bnoordhuis Aug 28, 2012

Contributor

An int? The win32 API is so daft...

This comment has been minimized.

Copy link
@piscisaureus

piscisaureus Aug 28, 2012

Author

yup

I considered writing my own, but the benefit isn't very obvious :-)

if (len <= 0) {
free(dst);
return NULL;
return uv__new_sys_error(GetLastError());
}
}

Expand All @@ -636,8 +653,11 @@ WCHAR* make_program_env(char** env_block) {
}
}

/* Terminate with an extra NULL. */
*ptr = L'\0';
return dst;

*dst_ptr = dst;
return uv_ok_;
}


Expand Down Expand Up @@ -740,7 +760,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
WCHAR* path = NULL;
BOOL result;
WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
*env = NULL, *cwd = NULL;
*env = NULL, *cwd = NULL;
STARTUPINFOW startup;
PROCESS_INFORMATION info;
DWORD process_flags;
Expand Down Expand Up @@ -775,6 +795,12 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
if (err.code != UV_OK)
goto done;

if (options.env) {
err = make_program_env(options.env, &env);
if (err.code != UV_OK)
goto done;
}

if (options.cwd) {
/* Explicit cwd */
err = uv_utf8_to_utf16_alloc(options.cwd, &cwd);
Expand Down

1 comment on commit abc945b

@bnoordhuis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Please sign in to comment.