Mercurial > vim
diff src/os_win32.c @ 12043:2796a2c9fc17 v8.0.0902
patch 8.0.0902: cannot specify directory or environment for a job
commit https://github.com/vim/vim/commit/05aafed54b50b602315ae55d83a7d089804cecb0
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Aug 11 19:12:11 2017 +0200
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)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 11 Aug 2017 19:15:04 +0200 |
parents | 85f0f557661e |
children | 779c9247cc0e |
line wrap: on
line diff
--- a/src/os_win32.c +++ b/src/os_win32.c @@ -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); - - if (wcmd != NULL) + BOOL ret; + WCHAR *wcmd, *wcwd = 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 option /* 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, job 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, job 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, job 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, job 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 *