Mercurial > vim
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. |