aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/sed.c19
-rwxr-xr-xtestsuite/sed.tests10
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
250static unsigned parse_escapes(char *dest, const char *string, int len, char from, char to) 249static 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
279static char *copy_parsing_escapes(const char *string, int len) 278static 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\+"
328testing "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 "&"
333testing "sed special char as s/// delimiter, in replacement" \
334 "sed 's&9&X\&&'" \
335 "X&+8=17\n" "" "9+8=17\n"
336
327testing "sed /\$_in_regex/ should not match newlines, only end-of-line" \ 337testing "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 "\