aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-08-17 01:35:04 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-08-17 01:35:04 +0200
commitf210cff601cf034c522b41cae6acd4f56060126d (patch)
tree5d65de6fa4eccdb44448cef2baf9efb65b4ab40e
parent16d1e3c26fc2908d430aa94cc76227028b0fffc7 (diff)
downloadbusybox-w32-f210cff601cf034c522b41cae6acd4f56060126d.tar.gz
busybox-w32-f210cff601cf034c522b41cae6acd4f56060126d.tar.bz2
busybox-w32-f210cff601cf034c522b41cae6acd4f56060126d.zip
sed: fix " echo /usr/lib | sed 's,\(^/\|\)[^/][^/]*,..,g' " bug
function old new delta process_files 2102 2091 -11 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/sed.c45
-rwxr-xr-xtestsuite/sed.tests7
2 files changed, 33 insertions, 19 deletions
diff --git a/editors/sed.c b/editors/sed.c
index de18996b8..8b4f60a8c 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -589,7 +589,7 @@ static void pipe_putc(char c)
589 589
590static void do_subst_w_backrefs(char *line, char *replace) 590static void do_subst_w_backrefs(char *line, char *replace)
591{ 591{
592 int i,j; 592 int i, j;
593 593
594 /* go through the replacement string */ 594 /* go through the replacement string */
595 for (i = 0; replace[i]; i++) { 595 for (i = 0; replace[i]; i++) {
@@ -624,23 +624,24 @@ static void do_subst_w_backrefs(char *line, char *replace)
624 } 624 }
625} 625}
626 626
627static int do_subst_command(sed_cmd_t *sed_cmd, char **line) 627static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
628{ 628{
629 char *oldline = *line; 629 char *line = *line_p;
630 int altered = 0; 630 int altered = 0;
631 unsigned match_count = 0; 631 unsigned match_count = 0;
632 regex_t *current_regex; 632 regex_t *current_regex;
633 633
634 current_regex = sed_cmd->sub_match;
634 /* Handle empty regex. */ 635 /* Handle empty regex. */
635 if (sed_cmd->sub_match == NULL) { 636 if (!current_regex) {
636 current_regex = G.previous_regex_ptr; 637 current_regex = G.previous_regex_ptr;
637 if (!current_regex) 638 if (!current_regex)
638 bb_error_msg_and_die("no previous regexp"); 639 bb_error_msg_and_die("no previous regexp");
639 } else 640 }
640 G.previous_regex_ptr = current_regex = sed_cmd->sub_match; 641 G.previous_regex_ptr = current_regex;
641 642
642 /* Find the first match */ 643 /* Find the first match */
643 if (REG_NOMATCH == regexec(current_regex, oldline, 10, G.regmatch, 0)) 644 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0))
644 return 0; 645 return 0;
645 646
646 /* Initialize temporary output buffer. */ 647 /* Initialize temporary output buffer. */
@@ -657,7 +658,7 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line)
657 The match_count check is so not to break 658 The match_count check is so not to break
658 echo "hi" | busybox sed 's/^/!/g' */ 659 echo "hi" | busybox sed 's/^/!/g' */
659 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { 660 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
660 pipe_putc(*oldline++); 661 pipe_putc(*line++);
661 continue; 662 continue;
662 } 663 }
663 664
@@ -669,35 +670,41 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line)
669 && (sed_cmd->which_match != match_count) 670 && (sed_cmd->which_match != match_count)
670 ) { 671 ) {
671 for (i = 0; i < G.regmatch[0].rm_eo; i++) 672 for (i = 0; i < G.regmatch[0].rm_eo; i++)
672 pipe_putc(*oldline++); 673 pipe_putc(*line++);
673 continue; 674 continue;
674 } 675 }
675 676
676 /* print everything before the match */ 677 /* print everything before the match */
677 for (i = 0; i < G.regmatch[0].rm_so; i++) 678 for (i = 0; i < G.regmatch[0].rm_so; i++)
678 pipe_putc(oldline[i]); 679 pipe_putc(line[i]);
679 680
680 /* then print the substitution string */ 681 /* then print the substitution string */
681 do_subst_w_backrefs(oldline, sed_cmd->string); 682 do_subst_w_backrefs(line, sed_cmd->string);
682 683
683 /* advance past the match */ 684 /* advance past the match */
684 oldline += G.regmatch[0].rm_eo; 685 line += G.regmatch[0].rm_eo;
685 /* flag that something has changed */ 686 /* flag that something has changed */
686 altered++; 687 altered++;
687 688
688 /* if we're not doing this globally, get out now */ 689 /* if we're not doing this globally, get out now */
689 if (sed_cmd->which_match) 690 if (sed_cmd->which_match)
690 break; 691 break;
691 } while (*oldline && (regexec(current_regex, oldline, 10, G.regmatch, 0) != REG_NOMATCH));
692 692
693 /* Copy rest of string into output pipeline */ 693 if (*line == '\0')
694 break;
695//maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
696 } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);
694 697
695 while (*oldline) 698 /* Copy rest of string into output pipeline */
696 pipe_putc(*oldline++); 699 while (1) {
697 pipe_putc(0); 700 char c = *line++;
701 pipe_putc(c);
702 if (c == '\0')
703 break;
704 }
698 705
699 free(*line); 706 free(*line_p);
700 *line = G.pipeline.buf; 707 *line_p = G.pipeline.buf;
701 return altered; 708 return altered;
702} 709}
703 710
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index a9d9ada31..696d980ef 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -241,4 +241,11 @@ testing "sed 2d;2,1p (gnu compat)" \
241 "third\n" "" \ 241 "third\n" "" \
242 "first\nsecond\nthird\nfourth\n" 242 "first\nsecond\nthird\nfourth\n"
243 243
244# Regex means: "match / at BOL or nothing, then one or more not-slashes".
245# The bug was that second slash in /usr/lib was treated as "at BOL" too.
246testing "sed beginning (^) matches only once" \
247 "sed 's,\(^/\|\)[^/][^/]*,>\0<,g'" \
248 ">/usr</>lib<\n" "" \
249 "/usr/lib\n"
250
244exit $FAILCOUNT 251exit $FAILCOUNT