diff options
-rw-r--r-- | editors/sed.c | 19 | ||||
-rwxr-xr-x | testsuite/sed.tests | 10 |
2 files changed, 21 insertions, 8 deletions
diff --git a/editors/sed.c b/editors/sed.c index 48b0dbf67..02a527b4a 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -246,7 +246,6 @@ static void cleanup_outname(void) | |||
246 | } | 246 | } |
247 | 247 | ||
248 | /* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */ | 248 | /* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */ |
249 | |||
250 | static unsigned parse_escapes(char *dest, const char *string, int len, char from, char to) | 249 | static unsigned parse_escapes(char *dest, const char *string, int len, char from, char to) |
251 | { | 250 | { |
252 | char *d = dest; | 251 | char *d = dest; |
@@ -276,7 +275,7 @@ static unsigned parse_escapes(char *dest, const char *string, int len, char from | |||
276 | return d - dest; | 275 | return d - dest; |
277 | } | 276 | } |
278 | 277 | ||
279 | static char *copy_parsing_escapes(const char *string, int len) | 278 | static char *copy_parsing_escapes(const char *string, int len, char delim) |
280 | { | 279 | { |
281 | const char *s; | 280 | const char *s; |
282 | char *dest = xmalloc(len + 1); | 281 | char *dest = xmalloc(len + 1); |
@@ -287,10 +286,15 @@ static char *copy_parsing_escapes(const char *string, int len) | |||
287 | len = parse_escapes(dest, string, len, s[1], s[0]); | 286 | len = parse_escapes(dest, string, len, s[1], s[0]); |
288 | string = dest; | 287 | string = dest; |
289 | } | 288 | } |
289 | if (delim) { | ||
290 | /* we additionally unescape any instances of escaped delimiter. | ||
291 | * For example, in 's+9\++X+' the pattern is "9+", not "9\+". | ||
292 | */ | ||
293 | len = parse_escapes(dest, string, len, delim, delim); | ||
294 | } | ||
290 | return dest; | 295 | return dest; |
291 | } | 296 | } |
292 | 297 | ||
293 | |||
294 | /* | 298 | /* |
295 | * index_of_next_unescaped_regexp_delim - walks left to right through a string | 299 | * index_of_next_unescaped_regexp_delim - walks left to right through a string |
296 | * beginning at a specified index and returns the index of the next regular | 300 | * beginning at a specified index and returns the index of the next regular |
@@ -347,12 +351,11 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | |||
347 | 351 | ||
348 | /* save the match string */ | 352 | /* save the match string */ |
349 | idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr); | 353 | idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr); |
350 | *match = copy_parsing_escapes(cmdstr_ptr, idx); | 354 | *match = copy_parsing_escapes(cmdstr_ptr, idx, delimiter); |
351 | |||
352 | /* save the replacement string */ | 355 | /* save the replacement string */ |
353 | cmdstr_ptr += idx + 1; | 356 | cmdstr_ptr += idx + 1; |
354 | idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); | 357 | idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); |
355 | *replace = copy_parsing_escapes(cmdstr_ptr, idx); | 358 | *replace = copy_parsing_escapes(cmdstr_ptr, idx, 0); |
356 | 359 | ||
357 | return ((cmdstr_ptr - cmdstr) + idx); | 360 | return ((cmdstr_ptr - cmdstr) + idx); |
358 | } | 361 | } |
@@ -380,7 +383,7 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) | |||
380 | delimiter = *++pos; | 383 | delimiter = *++pos; |
381 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); | 384 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); |
382 | if (next != 0) { | 385 | if (next != 0) { |
383 | temp = copy_parsing_escapes(pos, next); | 386 | temp = copy_parsing_escapes(pos, next, 0); |
384 | G.previous_regex_ptr = *regex = xzalloc(sizeof(regex_t)); | 387 | G.previous_regex_ptr = *regex = xzalloc(sizeof(regex_t)); |
385 | xregcomp(*regex, temp, G.regex_type); | 388 | xregcomp(*regex, temp, G.regex_type); |
386 | free(temp); | 389 | free(temp); |
@@ -575,7 +578,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) | |||
575 | cmdstr++; | 578 | cmdstr++; |
576 | } | 579 | } |
577 | len = strlen(cmdstr); | 580 | len = strlen(cmdstr); |
578 | sed_cmd->string = copy_parsing_escapes(cmdstr, len); | 581 | sed_cmd->string = copy_parsing_escapes(cmdstr, len, 0); |
579 | cmdstr += len; | 582 | cmdstr += len; |
580 | /* "\anychar" -> "anychar" */ | 583 | /* "\anychar" -> "anychar" */ |
581 | parse_escapes(sed_cmd->string, sed_cmd->string, -1, '\0', '\0'); | 584 | parse_escapes(sed_cmd->string, sed_cmd->string, -1, '\0', '\0'); |
diff --git a/testsuite/sed.tests b/testsuite/sed.tests index e62b839f7..440996a21 100755 --- a/testsuite/sed.tests +++ b/testsuite/sed.tests | |||
@@ -324,6 +324,16 @@ testing "sed zero chars match/replace logic must not falsely trigger here 2" \ | |||
324 | "sed 's/ *$/_/g'" \ | 324 | "sed 's/ *$/_/g'" \ |
325 | "qwerty_\n" "" "qwerty\n" | 325 | "qwerty_\n" "" "qwerty\n" |
326 | 326 | ||
327 | # the pattern here is interpreted as "9+", not as "9\+" | ||
328 | testing "sed special char as s/// delimiter, in pattern" \ | ||
329 | "sed 's+9\++X+'" \ | ||
330 | "X8=17\n" "" "9+8=17\n" | ||
331 | |||
332 | # but in replacement string, "\&" remains "\&", not interpreted as "&" | ||
333 | testing "sed special char as s/// delimiter, in replacement" \ | ||
334 | "sed 's&9&X\&&'" \ | ||
335 | "X&+8=17\n" "" "9+8=17\n" | ||
336 | |||
327 | testing "sed /\$_in_regex/ should not match newlines, only end-of-line" \ | 337 | testing "sed /\$_in_regex/ should not match newlines, only end-of-line" \ |
328 | "sed ': testcont; /\\\\$/{ =; N; b testcont }'" \ | 338 | "sed ': testcont; /\\\\$/{ =; N; b testcont }'" \ |
329 | "\ | 339 | "\ |