Mercurial > vim
comparison 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 |
comparison
equal
deleted
inserted
replaced
12042:3b09a43a3830 | 12043:2796a2c9fc17 |
---|---|
3979 vim_create_process( | 3979 vim_create_process( |
3980 char *cmd, | 3980 char *cmd, |
3981 BOOL inherit_handles, | 3981 BOOL inherit_handles, |
3982 DWORD flags, | 3982 DWORD flags, |
3983 STARTUPINFO *si, | 3983 STARTUPINFO *si, |
3984 PROCESS_INFORMATION *pi) | 3984 PROCESS_INFORMATION *pi, |
3985 LPVOID *env, | |
3986 char *cwd) | |
3985 { | 3987 { |
3986 #ifdef FEAT_MBYTE | 3988 #ifdef FEAT_MBYTE |
3987 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) | 3989 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) |
3988 { | 3990 { |
3989 WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL); | 3991 BOOL ret; |
3990 | 3992 WCHAR *wcmd, *wcwd = NULL; |
3991 if (wcmd != NULL) | 3993 |
3992 { | 3994 wcmd = enc_to_utf16((char_u *)cmd, NULL); |
3993 BOOL ret; | 3995 if (wcmd == NULL) |
3994 ret = CreateProcessW( | 3996 goto fallback; |
3995 NULL, /* Executable name */ | 3997 if (cwd != NULL) |
3996 wcmd, /* Command to execute */ | 3998 { |
3997 NULL, /* Process security attributes */ | 3999 wcwd = enc_to_utf16((char_u *)cwd, NULL); |
3998 NULL, /* Thread security attributes */ | 4000 if (wcwd == NULL) |
3999 inherit_handles, /* Inherit handles */ | 4001 { |
4000 flags, /* Creation flags */ | 4002 vim_free(wcmd); |
4001 NULL, /* Environment */ | 4003 goto fallback; |
4002 NULL, /* Current directory */ | 4004 } |
4003 (LPSTARTUPINFOW)si, /* Startup information */ | 4005 } |
4004 pi); /* Process information */ | 4006 |
4005 vim_free(wcmd); | 4007 ret = CreateProcessW( |
4006 return ret; | 4008 NULL, /* Executable name */ |
4007 } | 4009 wcmd, /* Command to execute */ |
4008 } | 4010 NULL, /* Process security attributes */ |
4011 NULL, /* Thread security attributes */ | |
4012 inherit_handles, /* Inherit handles */ | |
4013 flags, /* Creation flags */ | |
4014 env, /* Environment */ | |
4015 wcwd, /* Current directory */ | |
4016 (LPSTARTUPINFOW)si, /* Startup information */ | |
4017 pi); /* Process information */ | |
4018 vim_free(wcmd); | |
4019 if (wcwd != NULL) | |
4020 vim_free(wcwd); | |
4021 return ret; | |
4022 } | |
4023 fallback: | |
4009 #endif | 4024 #endif |
4010 return CreateProcess( | 4025 return CreateProcess( |
4011 NULL, /* Executable name */ | 4026 NULL, /* Executable name */ |
4012 cmd, /* Command to execute */ | 4027 cmd, /* Command to execute */ |
4013 NULL, /* Process security attributes */ | 4028 NULL, /* Process security attributes */ |
4014 NULL, /* Thread security attributes */ | 4029 NULL, /* Thread security attributes */ |
4015 inherit_handles, /* Inherit handles */ | 4030 inherit_handles, /* Inherit handles */ |
4016 flags, /* Creation flags */ | 4031 flags, /* Creation flags */ |
4017 NULL, /* Environment */ | 4032 env, /* Environment */ |
4018 NULL, /* Current directory */ | 4033 cwd, /* Current directory */ |
4019 si, /* Startup information */ | 4034 si, /* Startup information */ |
4020 pi); /* Process information */ | 4035 pi); /* Process information */ |
4021 } | 4036 } |
4022 | 4037 |
4023 | 4038 |
4077 si.cbReserved2 = 0; | 4092 si.cbReserved2 = 0; |
4078 si.lpReserved2 = NULL; | 4093 si.lpReserved2 = NULL; |
4079 | 4094 |
4080 /* Now, run the command */ | 4095 /* Now, run the command */ |
4081 vim_create_process(cmd, FALSE, | 4096 vim_create_process(cmd, FALSE, |
4082 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, &si, &pi); | 4097 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, |
4098 &si, &pi, NULL, NULL); | |
4083 | 4099 |
4084 /* Wait for the command to terminate before continuing */ | 4100 /* Wait for the command to terminate before continuing */ |
4085 { | 4101 { |
4086 #ifdef FEAT_GUI | 4102 #ifdef FEAT_GUI |
4087 int delay = 1; | 4103 int delay = 1; |
4396 | 4412 |
4397 /* Now, run the command. | 4413 /* Now, run the command. |
4398 * About "Inherit handles" being TRUE: this command can be litigious, | 4414 * About "Inherit handles" being TRUE: this command can be litigious, |
4399 * handle inheritance was deactivated for pending temp file, but, if we | 4415 * handle inheritance was deactivated for pending temp file, but, if we |
4400 * deactivate it, the pipes don't work for some reason. */ | 4416 * deactivate it, the pipes don't work for some reason. */ |
4401 vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE, &si, &pi); | 4417 vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE, |
4418 &si, &pi, NULL, NULL); | |
4402 | 4419 |
4403 if (p != cmd) | 4420 if (p != cmd) |
4404 vim_free(p); | 4421 vim_free(p); |
4405 | 4422 |
4406 /* Close our unused side of the pipes */ | 4423 /* Close our unused side of the pipes */ |
4833 /* | 4850 /* |
4834 * Now, start the command as a process, so that it doesn't | 4851 * Now, start the command as a process, so that it doesn't |
4835 * inherit our handles which causes unpleasant dangling swap | 4852 * inherit our handles which causes unpleasant dangling swap |
4836 * files if we exit before the spawned process | 4853 * files if we exit before the spawned process |
4837 */ | 4854 */ |
4838 if (vim_create_process((char *)newcmd, FALSE, flags, &si, &pi)) | 4855 if (vim_create_process((char *)newcmd, FALSE, flags, |
4856 &si, &pi, NULL, NULL)) | |
4839 x = 0; | 4857 x = 0; |
4840 else if (vim_shell_execute((char *)newcmd, n_show_cmd) | 4858 else if (vim_shell_execute((char *)newcmd, n_show_cmd) |
4841 > (HINSTANCE)32) | 4859 > (HINSTANCE)32) |
4842 x = 0; | 4860 x = 0; |
4843 else | 4861 else |
4974 lpSecurityAttributes, dwCreationDisposition, | 4992 lpSecurityAttributes, dwCreationDisposition, |
4975 dwFlagsAndAttributes, NULL); | 4993 dwFlagsAndAttributes, NULL); |
4976 return h; | 4994 return h; |
4977 } | 4995 } |
4978 | 4996 |
4997 /* | |
4998 * Turn the dictionary "env" into a NUL separated list that can be used as the | |
4999 * environment argument of vim_create_process(). | |
5000 */ | |
5001 static void | |
5002 make_job_env(garray_T *gap, dict_T *env) | |
5003 { | |
5004 hashitem_T *hi; | |
5005 int todo = (int)env->dv_hashtab.ht_used; | |
5006 LPVOID base = GetEnvironmentStringsW(); | |
5007 | |
5008 /* for last \0 */ | |
5009 if (ga_grow(gap, 1) == FAIL) | |
5010 return; | |
5011 | |
5012 if (base) | |
5013 { | |
5014 WCHAR *p = (WCHAR*) base; | |
5015 | |
5016 /* for last \0 */ | |
5017 if (ga_grow(gap, 1) == FAIL) | |
5018 return; | |
5019 | |
5020 while (*p != 0 || *(p + 1) != 0) | |
5021 { | |
5022 if (ga_grow(gap, 1) == OK) | |
5023 *((WCHAR*)gap->ga_data + gap->ga_len++) = *p; | |
5024 p++; | |
5025 } | |
5026 FreeEnvironmentStrings(base); | |
5027 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; | |
5028 } | |
5029 | |
5030 for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi) | |
5031 { | |
5032 if (!HASHITEM_EMPTY(hi)) | |
5033 { | |
5034 typval_T *item = &dict_lookup(hi)->di_tv; | |
5035 WCHAR *wkey = enc_to_utf16((char_u *)hi->hi_key, NULL); | |
5036 WCHAR *wval = enc_to_utf16(get_tv_string(item), NULL); | |
5037 --todo; | |
5038 if (wkey != NULL && wval != NULL) | |
5039 { | |
5040 int n, lkey = wcslen(wkey), lval = wcslen(wval); | |
5041 if (ga_grow(gap, lkey + lval + 2) != OK) | |
5042 continue; | |
5043 for (n = 0; n < lkey; n++) | |
5044 *((WCHAR*)gap->ga_data + gap->ga_len++) = wkey[n]; | |
5045 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'='; | |
5046 for (n = 0; n < lval; n++) | |
5047 *((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n]; | |
5048 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; | |
5049 } | |
5050 if (wkey != NULL) vim_free(wkey); | |
5051 if (wval != NULL) vim_free(wval); | |
5052 } | |
5053 } | |
5054 | |
5055 *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; | |
5056 } | |
5057 | |
4979 void | 5058 void |
4980 mch_job_start(char *cmd, job_T *job, jobopt_T *options) | 5059 mch_job_start(char *cmd, job_T *job, jobopt_T *options) |
4981 { | 5060 { |
4982 STARTUPINFO si; | 5061 STARTUPINFO si; |
4983 PROCESS_INFORMATION pi; | 5062 PROCESS_INFORMATION pi; |
4985 SECURITY_ATTRIBUTES saAttr; | 5064 SECURITY_ATTRIBUTES saAttr; |
4986 channel_T *channel = NULL; | 5065 channel_T *channel = NULL; |
4987 HANDLE ifd[2]; | 5066 HANDLE ifd[2]; |
4988 HANDLE ofd[2]; | 5067 HANDLE ofd[2]; |
4989 HANDLE efd[2]; | 5068 HANDLE efd[2]; |
5069 garray_T ga; | |
4990 | 5070 |
4991 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL; | 5071 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL; |
4992 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL; | 5072 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL; |
4993 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL; | 5073 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL; |
4994 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE; | 5074 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE; |
5003 ifd[1] = INVALID_HANDLE_VALUE; | 5083 ifd[1] = INVALID_HANDLE_VALUE; |
5004 ofd[0] = INVALID_HANDLE_VALUE; | 5084 ofd[0] = INVALID_HANDLE_VALUE; |
5005 ofd[1] = INVALID_HANDLE_VALUE; | 5085 ofd[1] = INVALID_HANDLE_VALUE; |
5006 efd[0] = INVALID_HANDLE_VALUE; | 5086 efd[0] = INVALID_HANDLE_VALUE; |
5007 efd[1] = INVALID_HANDLE_VALUE; | 5087 efd[1] = INVALID_HANDLE_VALUE; |
5088 ga_init2(&ga, (int)sizeof(wchar_t), 500); | |
5008 | 5089 |
5009 jo = CreateJobObject(NULL, NULL); | 5090 jo = CreateJobObject(NULL, NULL); |
5010 if (jo == NULL) | 5091 if (jo == NULL) |
5011 { | 5092 { |
5012 job->jv_status = JOB_FAILED; | 5093 job->jv_status = JOB_FAILED; |
5013 goto failed; | 5094 goto failed; |
5014 } | 5095 } |
5096 | |
5097 if (options->jo_env != NULL) | |
5098 make_job_env(&ga, options->jo_env); | |
5015 | 5099 |
5016 ZeroMemory(&pi, sizeof(pi)); | 5100 ZeroMemory(&pi, sizeof(pi)); |
5017 ZeroMemory(&si, sizeof(si)); | 5101 ZeroMemory(&si, sizeof(si)); |
5018 si.cb = sizeof(si); | 5102 si.cb = sizeof(si); |
5019 si.dwFlags |= STARTF_USESHOWWINDOW; | 5103 si.dwFlags |= STARTF_USESHOWWINDOW; |
5098 | 5182 |
5099 if (!vim_create_process(cmd, TRUE, | 5183 if (!vim_create_process(cmd, TRUE, |
5100 CREATE_SUSPENDED | | 5184 CREATE_SUSPENDED | |
5101 CREATE_DEFAULT_ERROR_MODE | | 5185 CREATE_DEFAULT_ERROR_MODE | |
5102 CREATE_NEW_PROCESS_GROUP | | 5186 CREATE_NEW_PROCESS_GROUP | |
5187 CREATE_UNICODE_ENVIRONMENT | | |
5103 CREATE_NEW_CONSOLE, | 5188 CREATE_NEW_CONSOLE, |
5104 &si, &pi)) | 5189 &si, &pi, |
5190 ga.ga_data, | |
5191 (char *)options->jo_cwd)) | |
5105 { | 5192 { |
5106 CloseHandle(jo); | 5193 CloseHandle(jo); |
5107 job->jv_status = JOB_FAILED; | 5194 job->jv_status = JOB_FAILED; |
5108 goto failed; | 5195 goto failed; |
5109 } | 5196 } |
5197 | |
5198 ga_clear(&ga); | |
5110 | 5199 |
5111 if (!AssignProcessToJobObject(jo, pi.hProcess)) | 5200 if (!AssignProcessToJobObject(jo, pi.hProcess)) |
5112 { | 5201 { |
5113 /* if failing, switch the way to terminate | 5202 /* if failing, switch the way to terminate |
5114 * process with TerminateProcess. */ | 5203 * process with TerminateProcess. */ |
5146 CloseHandle(efd[0]); | 5235 CloseHandle(efd[0]); |
5147 CloseHandle(ifd[1]); | 5236 CloseHandle(ifd[1]); |
5148 CloseHandle(ofd[1]); | 5237 CloseHandle(ofd[1]); |
5149 CloseHandle(efd[1]); | 5238 CloseHandle(efd[1]); |
5150 channel_unref(channel); | 5239 channel_unref(channel); |
5240 ga_clear(&ga); | |
5151 } | 5241 } |
5152 | 5242 |
5153 char * | 5243 char * |
5154 mch_job_status(job_T *job) | 5244 mch_job_status(job_T *job) |
5155 { | 5245 { |