XS-libuv
view release on metacpan or search on metacpan
libuv-1.49.2/src/win/process.c view on Meta::CPAN
WCHAR** ptr_copy;
WCHAR** env_copy;
char* p;
size_t required_vars_value_len[ARRAY_SIZE(required_vars)];
/* first pass: determine size in UTF-16 */
for (env = env_block; *env; env++) {
ssize_t len;
if (strchr(*env, '=')) {
len = uv_wtf8_length_as_utf16(*env);
if (len < 0)
return len;
env_len += len;
env_block_count++;
}
}
/* second pass: copy to UTF-16 environment block */
len = env_block_count * sizeof(WCHAR*);
p = uv__malloc(len + env_len * sizeof(WCHAR));
if (p == NULL) {
return UV_ENOMEM;
}
env_copy = (void*) &p[0];
dst_copy = (void*) &p[len];
ptr = dst_copy;
ptr_copy = env_copy;
for (env = env_block; *env; env++) {
ssize_t len;
if (strchr(*env, '=')) {
len = uv_wtf8_length_as_utf16(*env);
assert(len > 0);
assert((size_t) len <= env_len - (ptr - dst_copy));
uv_wtf8_to_utf16(*env, ptr, len);
*ptr_copy++ = ptr;
ptr += len;
}
}
*ptr_copy = NULL;
assert(env_len == 0 || env_len == (size_t) (ptr - dst_copy));
/* sort our (UTF-16) copy */
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
/* third pass: check for required variables */
for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) {
int cmp;
if (!*ptr_copy) {
cmp = -1;
} else {
cmp = env_strncmp(required_vars[i].wide_eq,
required_vars[i].len,
*ptr_copy);
}
if (cmp < 0) {
/* missing required var */
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
required_vars_value_len[i] = var_size;
if (var_size != 0) {
env_len += required_vars[i].len;
env_len += var_size;
}
i++;
} else {
ptr_copy++;
if (cmp == 0)
i++;
}
}
/* final pass: copy, in sort order, and inserting required variables */
dst = uv__malloc((1+env_len) * sizeof(WCHAR));
if (!dst) {
uv__free(p);
return UV_ENOMEM;
}
for (ptr = dst, ptr_copy = env_copy, i = 0;
*ptr_copy || i < ARRAY_SIZE(required_vars);
ptr += len) {
int cmp;
if (i >= ARRAY_SIZE(required_vars)) {
cmp = 1;
} else if (!*ptr_copy) {
cmp = -1;
} else {
cmp = env_strncmp(required_vars[i].wide_eq,
required_vars[i].len,
*ptr_copy);
}
if (cmp < 0) {
/* missing required var */
len = required_vars_value_len[i];
if (len) {
wcscpy(ptr, required_vars[i].wide_eq);
ptr += required_vars[i].len;
var_size = GetEnvironmentVariableW(required_vars[i].wide,
ptr,
(int) (env_len - (ptr - dst)));
if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
}
}
i++;
} else {
/* copy var from env_block */
len = wcslen(*ptr_copy) + 1;
wmemcpy(ptr, *ptr_copy, len);
ptr_copy++;
if (cmp == 0)
i++;
}
}
/* Terminate with an extra NULL. */
assert(env_len == (size_t) (ptr - dst));
*ptr = L'\0';
uv__free(p);
*dst_ptr = dst;
return 0;
}
/*
* Attempt to find the value of the PATH environment variable in the child's
* preprocessed environment.
*
* If found, a pointer into `env` is returned. If not found, NULL is returned.
*/
static WCHAR* find_path(WCHAR *env) {
for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
if ((env[0] == L'P' || env[0] == L'p') &&
(env[1] == L'A' || env[1] == L'a') &&
(env[2] == L'T' || env[2] == L't') &&
(env[3] == L'H' || env[3] == L'h') &&
(env[4] == L'=')) {
return &env[5];
}
}
return NULL;
}
/*
* Called on Windows thread-pool thread to indicate that
* a child process has exited.
*/
static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
uv_process_t* process = (uv_process_t*) data;
uv_loop_t* loop = process->loop;
assert(didTimeout == FALSE);
assert(process);
assert(!process->exit_cb_pending);
process->exit_cb_pending = 1;
( run in 0.895 second using v1.01-cache-2.11-cpan-39bf76dae61 )