Mercurial > vim
comparison src/channel.c @ 12096:0a61213afdd2 v8.0.0928
patch 8.0.0928: MS-Windows: passing arglist to job has escaping problems
commit https://github.com/vim/vim/commit/dcaa61384ca76e42f7feda5640fb85b58cee03e5
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Aug 13 17:13:09 2017 +0200
patch 8.0.0928: MS-Windows: passing arglist to job has escaping problems
Problem: MS-Windows: passing arglist to job has escaping problems.
Solution: Improve escaping. (Yasuhiro Matsumoto, closes https://github.com/vim/vim/issues/1954)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 13 Aug 2017 17:15:03 +0200 |
parents | f4e1e1e6886b |
children | 71e10b81226d |
comparison
equal
deleted
inserted
replaced
12095:975ec6e45168 | 12096:0a61213afdd2 |
---|---|
4718 job_still_useful(job_T *job) | 4718 job_still_useful(job_T *job) |
4719 { | 4719 { |
4720 return job_need_end_check(job) || job_channel_still_useful(job); | 4720 return job_need_end_check(job) || job_channel_still_useful(job); |
4721 } | 4721 } |
4722 | 4722 |
4723 #if !defined(USE_ARGV) || defined(PROTO) | |
4724 /* | |
4725 * Escape one argument for an external command. | |
4726 * Returns the escaped string in allocated memory. NULL when out of memory. | |
4727 */ | |
4728 static char_u * | |
4729 win32_escape_arg(char_u *arg) | |
4730 { | |
4731 int slen, dlen; | |
4732 int escaping = 0; | |
4733 int i; | |
4734 char_u *s, *d; | |
4735 char_u *escaped_arg; | |
4736 int has_spaces = FALSE; | |
4737 | |
4738 /* First count the number of extra bytes required. */ | |
4739 slen = STRLEN(arg); | |
4740 dlen = slen; | |
4741 for (s = arg; *s != NUL; MB_PTR_ADV(s)) | |
4742 { | |
4743 if (*s == '"' || *s == '\\') | |
4744 ++dlen; | |
4745 if (*s == ' ' || *s == '\t') | |
4746 has_spaces = TRUE; | |
4747 } | |
4748 | |
4749 if (has_spaces) | |
4750 dlen += 2; | |
4751 | |
4752 if (dlen == slen) | |
4753 return vim_strsave(arg); | |
4754 | |
4755 /* Allocate memory for the result and fill it. */ | |
4756 escaped_arg = alloc(dlen + 1); | |
4757 if (escaped_arg == NULL) | |
4758 return NULL; | |
4759 memset(escaped_arg, 0, dlen+1); | |
4760 | |
4761 d = escaped_arg; | |
4762 | |
4763 if (has_spaces) | |
4764 *d++ = '"'; | |
4765 | |
4766 for (s = arg; *s != NUL;) | |
4767 { | |
4768 switch (*s) | |
4769 { | |
4770 case '"': | |
4771 for (i = 0; i < escaping; i++) | |
4772 *d++ = '\\'; | |
4773 escaping = 0; | |
4774 *d++ = '\\'; | |
4775 *d++ = *s++; | |
4776 break; | |
4777 case '\\': | |
4778 escaping++; | |
4779 *d++ = *s++; | |
4780 break; | |
4781 default: | |
4782 escaping = 0; | |
4783 MB_COPY_CHAR(s, d); | |
4784 break; | |
4785 } | |
4786 } | |
4787 | |
4788 /* add terminating quote and finish with a NUL */ | |
4789 if (has_spaces) | |
4790 { | |
4791 for (i = 0; i < escaping; i++) | |
4792 *d++ = '\\'; | |
4793 *d++ = '"'; | |
4794 } | |
4795 *d = NUL; | |
4796 | |
4797 return escaped_arg; | |
4798 } | |
4799 | |
4800 /* | |
4801 * Build a command line from a list, taking care of escaping. | |
4802 * The result is put in gap->ga_data. | |
4803 * Returns FAIL when out of memory. | |
4804 */ | |
4805 int | |
4806 win32_build_cmd(list_T *l, garray_T *gap) | |
4807 { | |
4808 listitem_T *li; | |
4809 char_u *s; | |
4810 | |
4811 for (li = l->lv_first; li != NULL; li = li->li_next) | |
4812 { | |
4813 s = get_tv_string_chk(&li->li_tv); | |
4814 if (s == NULL) | |
4815 return FAIL; | |
4816 s = win32_escape_arg(s); | |
4817 if (s == NULL) | |
4818 return FAIL; | |
4819 ga_concat(gap, s); | |
4820 vim_free(s); | |
4821 if (li->li_next != NULL) | |
4822 ga_append(gap, ' '); | |
4823 } | |
4824 return OK; | |
4825 } | |
4826 #endif | |
4827 | |
4723 /* | 4828 /* |
4724 * NOTE: Must call job_cleanup() only once right after the status of "job" | 4829 * NOTE: Must call job_cleanup() only once right after the status of "job" |
4725 * changed to JOB_ENDED (i.e. after job_status() returned "dead" first or | 4830 * changed to JOB_ENDED (i.e. after job_status() returned "dead" first or |
4726 * mch_detect_ended_job() returned non-NULL). | 4831 * mch_detect_ended_job() returned non-NULL). |
4727 */ | 4832 */ |
5091 goto theend; | 5196 goto theend; |
5092 } | 5197 } |
5093 else | 5198 else |
5094 { | 5199 { |
5095 list_T *l = argvars[0].vval.v_list; | 5200 list_T *l = argvars[0].vval.v_list; |
5201 #ifdef USE_ARGV | |
5096 listitem_T *li; | 5202 listitem_T *li; |
5097 char_u *s; | 5203 char_u *s; |
5098 | 5204 |
5099 #ifdef USE_ARGV | |
5100 /* Pass argv[] to mch_call_shell(). */ | 5205 /* Pass argv[] to mch_call_shell(). */ |
5101 argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1)); | 5206 argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1)); |
5102 if (argv == NULL) | 5207 if (argv == NULL) |
5103 goto theend; | 5208 goto theend; |
5104 #endif | |
5105 for (li = l->lv_first; li != NULL; li = li->li_next) | 5209 for (li = l->lv_first; li != NULL; li = li->li_next) |
5106 { | 5210 { |
5107 s = get_tv_string_chk(&li->li_tv); | 5211 s = get_tv_string_chk(&li->li_tv); |
5108 if (s == NULL) | 5212 if (s == NULL) |
5109 goto theend; | 5213 goto theend; |
5110 #ifdef USE_ARGV | |
5111 argv[argc++] = (char *)s; | 5214 argv[argc++] = (char *)s; |
5112 #else | 5215 } |
5113 /* Only escape when needed, double quotes are not always allowed. */ | |
5114 if (li != l->lv_first && vim_strpbrk(s, (char_u *)" \t\"") != NULL) | |
5115 { | |
5116 # ifdef WIN32 | |
5117 int old_ssl = p_ssl; | |
5118 | |
5119 /* This is using CreateProcess, not cmd.exe. Always use | |
5120 * double quote and backslashes. */ | |
5121 p_ssl = 0; | |
5122 # endif | |
5123 s = vim_strsave_shellescape(s, FALSE, TRUE); | |
5124 # ifdef WIN32 | |
5125 p_ssl = old_ssl; | |
5126 # endif | |
5127 if (s == NULL) | |
5128 goto theend; | |
5129 ga_concat(&ga, s); | |
5130 vim_free(s); | |
5131 } | |
5132 else | |
5133 ga_concat(&ga, s); | |
5134 if (li->li_next != NULL) | |
5135 ga_append(&ga, ' '); | |
5136 #endif | |
5137 } | |
5138 #ifdef USE_ARGV | |
5139 argv[argc] = NULL; | 5216 argv[argc] = NULL; |
5140 #else | 5217 #else |
5218 if (win32_build_cmd(l, &ga) == FAIL) | |
5219 goto theend; | |
5141 cmd = ga.ga_data; | 5220 cmd = ga.ga_data; |
5142 #endif | 5221 #endif |
5143 } | 5222 } |
5144 | 5223 |
5145 #ifdef USE_ARGV | 5224 #ifdef USE_ARGV |