comparison src/typval.c @ 28813:3626ca6a20ea v8.2.4930

patch 8.2.4930: interpolated string expression requires escaping Commit: https://github.com/vim/vim/commit/0abc2871c105882ed1c1effb9a7757fad8a395bd Author: Bram Moolenaar <Bram@vim.org> Date: Tue May 10 13:24:30 2022 +0100 patch 8.2.4930: interpolated string expression requires escaping Problem: Interpolated string expression requires escaping. Solution: Do not require escaping in the expression.
author Bram Moolenaar <Bram@vim.org>
date Tue, 10 May 2022 14:30:04 +0200
parents d0241e74bfdb
children 006d525419fa
comparison
equal deleted inserted replaced
28812:483371d05cd5 28813:3626ca6a20ea
2063 } 2063 }
2064 return OK; 2064 return OK;
2065 } 2065 }
2066 2066
2067 /* 2067 /*
2068 * Allocate a variable for a string constant. 2068 * Evaluate a string constant and put the result in "rettv".
2069 * "*arg" points to the double quote or to after it when "interpolate" is TRUE.
2070 * When "interpolate" is TRUE reduce "{{" to "{", reduce "}}" to "}" and stop
2071 * at a single "{".
2069 * Return OK or FAIL. 2072 * Return OK or FAIL.
2070 */ 2073 */
2071 int 2074 int
2072 eval_string(char_u **arg, typval_T *rettv, int evaluate) 2075 eval_string(char_u **arg, typval_T *rettv, int evaluate, int interpolate)
2073 { 2076 {
2074 char_u *p; 2077 char_u *p;
2075 char_u *end; 2078 char_u *end;
2076 int extra = 0; 2079 int extra = interpolate ? 1 : 0;
2080 int off = interpolate ? 0 : 1;
2077 int len; 2081 int len;
2078 2082
2079 // Find the end of the string, skipping backslashed characters. 2083 // Find the end of the string, skipping backslashed characters.
2080 for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) 2084 for (p = *arg + off; *p != NUL && *p != '"'; MB_PTR_ADV(p))
2081 { 2085 {
2082 if (*p == '\\' && p[1] != NUL) 2086 if (*p == '\\' && p[1] != NUL)
2083 { 2087 {
2084 ++p; 2088 ++p;
2085 // A "\<x>" form occupies at least 4 characters, and produces up 2089 // A "\<x>" form occupies at least 4 characters, and produces up
2086 // to 9 characters (6 for the char and 3 for a modifier): 2090 // to 9 characters (6 for the char and 3 for a modifier):
2087 // reserve space for 5 extra. 2091 // reserve space for 5 extra.
2088 if (*p == '<') 2092 if (*p == '<')
2089 extra += 5; 2093 extra += 5;
2090 } 2094 }
2091 } 2095 else if (interpolate && (*p == '{' || *p == '}'))
2092 2096 {
2093 if (*p != '"') 2097 if (*p == '{' && p[1] != '{') // start of expression
2098 break;
2099 ++p;
2100 if (p[-1] == '}' && *p != '}') // single '}' is an error
2101 {
2102 semsg(_(e_stray_closing_curly_str), *arg);
2103 return FAIL;
2104 }
2105 --extra; // "{{" becomes "{", "}}" becomes "}"
2106 }
2107 }
2108
2109 if (*p != '"' && !(interpolate && *p == '{'))
2094 { 2110 {
2095 semsg(_(e_missing_double_quote_str), *arg); 2111 semsg(_(e_missing_double_quote_str), *arg);
2096 return FAIL; 2112 return FAIL;
2097 } 2113 }
2098 2114
2099 // If only parsing, set *arg and return here 2115 // If only parsing, set *arg and return here
2100 if (!evaluate) 2116 if (!evaluate)
2101 { 2117 {
2102 *arg = p + 1; 2118 *arg = p + off;
2103 return OK; 2119 return OK;
2104 } 2120 }
2105 2121
2106 // Copy the string into allocated memory, handling backslashed 2122 // Copy the string into allocated memory, handling backslashed
2107 // characters. 2123 // characters.
2110 rettv->vval.v_string = alloc(len); 2126 rettv->vval.v_string = alloc(len);
2111 if (rettv->vval.v_string == NULL) 2127 if (rettv->vval.v_string == NULL)
2112 return FAIL; 2128 return FAIL;
2113 end = rettv->vval.v_string; 2129 end = rettv->vval.v_string;
2114 2130
2115 for (p = *arg + 1; *p != NUL && *p != '"'; ) 2131 for (p = *arg + off; *p != NUL && *p != '"'; )
2116 { 2132 {
2117 if (*p == '\\') 2133 if (*p == '\\')
2118 { 2134 {
2119 switch (*++p) 2135 switch (*++p)
2120 { 2136 {
2190 break; 2206 break;
2191 } 2207 }
2192 } 2208 }
2193 // FALLTHROUGH 2209 // FALLTHROUGH
2194 2210
2195 default: MB_COPY_CHAR(p, end); 2211 default: MB_COPY_CHAR(p, end);
2196 break; 2212 break;
2197 } 2213 }
2198 } 2214 }
2199 else 2215 else
2216 {
2217 if (interpolate && (*p == '{' || *p == '}'))
2218 {
2219 if (*p == '{' && p[1] != '{') // start of expression
2220 break;
2221 ++p; // reduce "{{" to "{" and "}}" to "}"
2222 }
2200 MB_COPY_CHAR(p, end); 2223 MB_COPY_CHAR(p, end);
2224 }
2201 } 2225 }
2202 *end = NUL; 2226 *end = NUL;
2203 if (*p != NUL) // just in case 2227 if (*p == '"' && !interpolate)
2204 ++p; 2228 ++p;
2205 *arg = p; 2229 *arg = p;
2206 2230
2207 return OK; 2231 return OK;
2208 } 2232 }
2209 2233
2210 /* 2234 /*
2211 * Allocate a variable for a 'str''ing' constant. 2235 * Allocate a variable for a 'str''ing' constant.
2212 * Return OK or FAIL. 2236 * When "interpolate" is TRUE reduce "{{" to "{" and stop at a single "{".
2213 */ 2237 * Return OK when a "rettv" was set to the string.
2214 int 2238 * Return FAIL on error, "rettv" is not set.
2215 eval_lit_string(char_u **arg, typval_T *rettv, int evaluate) 2239 */
2240 int
2241 eval_lit_string(char_u **arg, typval_T *rettv, int evaluate, int interpolate)
2216 { 2242 {
2217 char_u *p; 2243 char_u *p;
2218 char_u *str; 2244 char_u *str;
2219 int reduce = 0; 2245 int reduce = interpolate ? -1 : 0;
2246 int off = interpolate ? 0 : 1;
2220 2247
2221 // Find the end of the string, skipping ''. 2248 // Find the end of the string, skipping ''.
2222 for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p)) 2249 for (p = *arg + off; *p != NUL; MB_PTR_ADV(p))
2223 { 2250 {
2224 if (*p == '\'') 2251 if (*p == '\'')
2225 { 2252 {
2226 if (p[1] != '\'') 2253 if (p[1] != '\'')
2227 break; 2254 break;
2228 ++reduce; 2255 ++reduce;
2229 ++p; 2256 ++p;
2230 } 2257 }
2231 } 2258 else if (interpolate)
2232 2259 {
2233 if (*p != '\'') 2260 if (*p == '{')
2261 {
2262 if (p[1] != '{')
2263 break;
2264 ++p;
2265 ++reduce;
2266 }
2267 else if (*p == '}')
2268 {
2269 ++p;
2270 if (*p != '}')
2271 {
2272 semsg(_(e_stray_closing_curly_str), *arg);
2273 return FAIL;
2274 }
2275 ++reduce;
2276 }
2277 }
2278 }
2279
2280 if (*p != '\'' && !(interpolate && *p == '{'))
2234 { 2281 {
2235 semsg(_(e_missing_single_quote_str), *arg); 2282 semsg(_(e_missing_single_quote_str), *arg);
2236 return FAIL; 2283 return FAIL;
2237 } 2284 }
2238 2285
2239 // If only parsing return after setting "*arg" 2286 // If only parsing return after setting "*arg"
2240 if (!evaluate) 2287 if (!evaluate)
2241 { 2288 {
2242 *arg = p + 1; 2289 *arg = p + off;
2243 return OK; 2290 return OK;
2244 } 2291 }
2245 2292
2246 // Copy the string into allocated memory, handling '' to ' reduction. 2293 // Copy the string into allocated memory, handling '' to ' reduction and
2294 // any expressions.
2247 str = alloc((p - *arg) - reduce); 2295 str = alloc((p - *arg) - reduce);
2248 if (str == NULL) 2296 if (str == NULL)
2249 return FAIL; 2297 return FAIL;
2250 rettv->v_type = VAR_STRING; 2298 rettv->v_type = VAR_STRING;
2251 rettv->vval.v_string = str; 2299 rettv->vval.v_string = str;
2252 2300
2253 for (p = *arg + 1; *p != NUL; ) 2301 for (p = *arg + off; *p != NUL; )
2254 { 2302 {
2255 if (*p == '\'') 2303 if (*p == '\'')
2256 { 2304 {
2257 if (p[1] != '\'') 2305 if (p[1] != '\'')
2258 break; 2306 break;
2259 ++p; 2307 ++p;
2260 } 2308 }
2309 else if (interpolate && (*p == '{' || *p == '}'))
2310 {
2311 if (*p == '{' && p[1] != '{')
2312 break;
2313 ++p;
2314 }
2261 MB_COPY_CHAR(p, str); 2315 MB_COPY_CHAR(p, str);
2262 } 2316 }
2263 *str = NUL; 2317 *str = NUL;
2264 *arg = p + 1; 2318 *arg = p + off;
2265 2319
2266 return OK; 2320 return OK;
2267 } 2321 }
2268 2322
2323 /*
2324 * Evaluate a single or double quoted string possibly containing expressions.
2325 * "arg" points to the '$'. The result is put in "rettv".
2326 * Returns OK or FAIL.
2327 */
2269 int 2328 int
2270 eval_interp_string(char_u **arg, typval_T *rettv, int evaluate) 2329 eval_interp_string(char_u **arg, typval_T *rettv, int evaluate)
2271 { 2330 {
2272 typval_T tv; 2331 typval_T tv;
2273 int ret; 2332 int ret = OK;
2274 2333 int quote;
2275 // *arg is on the '$' character. 2334 garray_T ga;
2276 (*arg)++; 2335 char_u *p;
2336
2337 ga_init2(&ga, 1, 80);
2338
2339 // *arg is on the '$' character, move it to the first string character.
2340 ++*arg;
2341 quote = **arg;
2342 ++*arg;
2343
2344 for (;;)
2345 {
2346 // Get the string up to the matching quote or to a single '{'.
2347 // "arg" is advanced to either the quote or the '{'.
2348 if (quote == '"')
2349 ret = eval_string(arg, &tv, evaluate, TRUE);
2350 else
2351 ret = eval_lit_string(arg, &tv, evaluate, TRUE);
2352 if (ret == FAIL)
2353 break;
2354 if (evaluate)
2355 {
2356 ga_concat(&ga, tv.vval.v_string);
2357 clear_tv(&tv);
2358 }
2359
2360 if (**arg != '{')
2361 {
2362 // found terminating quote
2363 ++*arg;
2364 break;
2365 }
2366 p = eval_one_expr_in_str(*arg, &ga);
2367 if (p == NULL)
2368 {
2369 ret = FAIL;
2370 break;
2371 }
2372 *arg = p;
2373 }
2277 2374
2278 rettv->v_type = VAR_STRING; 2375 rettv->v_type = VAR_STRING;
2279 2376 if (ret == FAIL || !evaluate || ga_append(&ga, NUL) == FAIL)
2280 if (**arg == '"') 2377 {
2281 ret = eval_string(arg, &tv, evaluate); 2378 ga_clear(&ga);
2282 else 2379 rettv->vval.v_string = NULL;
2283 ret = eval_lit_string(arg, &tv, evaluate);
2284
2285 if (ret == FAIL || !evaluate)
2286 return ret; 2380 return ret;
2287 2381 }
2288 rettv->vval.v_string = eval_all_expr_in_str(tv.vval.v_string); 2382
2289 2383 rettv->vval.v_string = ga.ga_data;
2290 clear_tv(&tv); 2384 return OK;
2291
2292 return rettv->vval.v_string != NULL ? OK : FAIL;
2293 } 2385 }
2294 2386
2295 /* 2387 /*
2296 * Return a string with the string representation of a variable. 2388 * Return a string with the string representation of a variable.
2297 * If the memory is allocated "tofree" is set to it, otherwise NULL. 2389 * If the memory is allocated "tofree" is set to it, otherwise NULL.