1
0
forked from aniani/vim

patch 8.0.0902: cannot specify directory or environment for a job

Problem:    Cannot specify directory or environment for a job.
Solution:   Add the "cwd" and "env" arguments to job options. (Yasuhiro
            Matsumoto, closes #1160)
This commit is contained in:
Bram Moolenaar
2017-08-11 19:12:11 +02:00
parent 76ca1b4041
commit 05aafed54b
9 changed files with 252 additions and 43 deletions

View File

@@ -3981,31 +3981,46 @@ vim_create_process(
BOOL inherit_handles,
DWORD flags,
STARTUPINFO *si,
PROCESS_INFORMATION *pi)
PROCESS_INFORMATION *pi,
LPVOID *env,
char *cwd)
{
#ifdef FEAT_MBYTE
if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
{
WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
BOOL ret;
WCHAR *wcmd, *wcwd = NULL;
if (wcmd != NULL)
wcmd = enc_to_utf16((char_u *)cmd, NULL);
if (wcmd == NULL)
goto fallback;
if (cwd != NULL)
{
BOOL ret;
ret = CreateProcessW(
NULL, /* Executable name */
wcmd, /* Command to execute */
NULL, /* Process security attributes */
NULL, /* Thread security attributes */
inherit_handles, /* Inherit handles */
flags, /* Creation flags */
NULL, /* Environment */
NULL, /* Current directory */
(LPSTARTUPINFOW)si, /* Startup information */
pi); /* Process information */
vim_free(wcmd);
return ret;
wcwd = enc_to_utf16((char_u *)cwd, NULL);
if (wcwd == NULL)
{
vim_free(wcmd);
goto fallback;
}
}
ret = CreateProcessW(
NULL, /* Executable name */
wcmd, /* Command to execute */
NULL, /* Process security attributes */
NULL, /* Thread security attributes */
inherit_handles, /* Inherit handles */
flags, /* Creation flags */
env, /* Environment */
wcwd, /* Current directory */
(LPSTARTUPINFOW)si, /* Startup information */
pi); /* Process information */
vim_free(wcmd);
if (wcwd != NULL)
vim_free(wcwd);
return ret;
}
fallback:
#endif
return CreateProcess(
NULL, /* Executable name */
@@ -4014,8 +4029,8 @@ vim_create_process(
NULL, /* Thread security attributes */
inherit_handles, /* Inherit handles */
flags, /* Creation flags */
NULL, /* Environment */
NULL, /* Current directory */
env, /* Environment */
cwd, /* Current directory */
si, /* Startup information */
pi); /* Process information */
}
@@ -4079,7 +4094,8 @@ mch_system_classic(char *cmd, int options)
/* Now, run the command */
vim_create_process(cmd, FALSE,
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, &si, &pi);
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE,
&si, &pi, NULL, NULL);
/* Wait for the command to terminate before continuing */
{
@@ -4398,7 +4414,8 @@ mch_system_piped(char *cmd, int options)
* About "Inherit handles" being TRUE: this command can be litigious,
* handle inheritance was deactivated for pending temp file, but, if we
* deactivate it, the pipes don't work for some reason. */
vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE, &si, &pi);
vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE,
&si, &pi, NULL, NULL);
if (p != cmd)
vim_free(p);
@@ -4835,7 +4852,8 @@ mch_call_shell(
* inherit our handles which causes unpleasant dangling swap
* files if we exit before the spawned process
*/
if (vim_create_process((char *)newcmd, FALSE, flags, &si, &pi))
if (vim_create_process((char *)newcmd, FALSE, flags,
&si, &pi, NULL, NULL))
x = 0;
else if (vim_shell_execute((char *)newcmd, n_show_cmd)
> (HINSTANCE)32)
@@ -4976,6 +4994,67 @@ job_io_file_open(
return h;
}
/*
* Turn the dictionary "env" into a NUL separated list that can be used as the
* environment argument of vim_create_process().
*/
static void
make_job_env(garray_T *gap, dict_T *env)
{
hashitem_T *hi;
int todo = (int)env->dv_hashtab.ht_used;
LPVOID base = GetEnvironmentStringsW();
/* for last \0 */
if (ga_grow(gap, 1) == FAIL)
return;
if (base)
{
WCHAR *p = (WCHAR*) base;
/* for last \0 */
if (ga_grow(gap, 1) == FAIL)
return;
while (*p != 0 || *(p + 1) != 0)
{
if (ga_grow(gap, 1) == OK)
*((WCHAR*)gap->ga_data + gap->ga_len++) = *p;
p++;
}
FreeEnvironmentStrings(base);
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
}
for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
typval_T *item = &dict_lookup(hi)->di_tv;
WCHAR *wkey = enc_to_utf16((char_u *)hi->hi_key, NULL);
WCHAR *wval = enc_to_utf16(get_tv_string(item), NULL);
--todo;
if (wkey != NULL && wval != NULL)
{
int n, lkey = wcslen(wkey), lval = wcslen(wval);
if (ga_grow(gap, lkey + lval + 2) != OK)
continue;
for (n = 0; n < lkey; n++)
*((WCHAR*)gap->ga_data + gap->ga_len++) = wkey[n];
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'=';
for (n = 0; n < lval; n++)
*((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n];
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
}
if (wkey != NULL) vim_free(wkey);
if (wval != NULL) vim_free(wval);
}
}
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
}
void
mch_job_start(char *cmd, job_T *job, jobopt_T *options)
{
@@ -4987,6 +5066,7 @@ mch_job_start(char *cmd, job_T *job, jobopt_T *options)
HANDLE ifd[2];
HANDLE ofd[2];
HANDLE efd[2];
garray_T ga;
int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
@@ -5005,6 +5085,7 @@ mch_job_start(char *cmd, job_T *job, jobopt_T *options)
ofd[1] = INVALID_HANDLE_VALUE;
efd[0] = INVALID_HANDLE_VALUE;
efd[1] = INVALID_HANDLE_VALUE;
ga_init2(&ga, (int)sizeof(wchar_t), 500);
jo = CreateJobObject(NULL, NULL);
if (jo == NULL)
@@ -5013,6 +5094,9 @@ mch_job_start(char *cmd, job_T *job, jobopt_T *options)
goto failed;
}
if (options->jo_env != NULL)
make_job_env(&ga, options->jo_env);
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
@@ -5100,14 +5184,19 @@ mch_job_start(char *cmd, job_T *job, jobopt_T *options)
CREATE_SUSPENDED |
CREATE_DEFAULT_ERROR_MODE |
CREATE_NEW_PROCESS_GROUP |
CREATE_UNICODE_ENVIRONMENT |
CREATE_NEW_CONSOLE,
&si, &pi))
&si, &pi,
ga.ga_data,
(char *)options->jo_cwd))
{
CloseHandle(jo);
job->jv_status = JOB_FAILED;
goto failed;
}
ga_clear(&ga);
if (!AssignProcessToJobObject(jo, pi.hProcess))
{
/* if failing, switch the way to terminate
@@ -5148,6 +5237,7 @@ failed:
CloseHandle(ofd[1]);
CloseHandle(efd[1]);
channel_unref(channel);
ga_clear(&ga);
}
char *