diff options
author | Mark Whitley <markw@lineo.com> | 2001-06-11 23:50:06 +0000 |
---|---|---|
committer | Mark Whitley <markw@lineo.com> | 2001-06-11 23:50:06 +0000 |
commit | 0915c4b98533502b23b8021d0aa7b1a8c7f7ea4f (patch) | |
tree | 330947eca0179548f16126612af00dae488dd64d | |
parent | bf0a010cf705d21c75d2c6ba8de38cec038f9aa1 (diff) | |
download | busybox-w32-0915c4b98533502b23b8021d0aa7b1a8c7f7ea4f.tar.gz busybox-w32-0915c4b98533502b23b8021d0aa7b1a8c7f7ea4f.tar.bz2 busybox-w32-0915c4b98533502b23b8021d0aa7b1a8c7f7ea4f.zip |
- Fixed bug where you couldn't mix line number and regexes in two-address cmds
- Fixed bug where you couldn't use two addresses for a 'c' cmd
- Moved the do_sed_cmd function into process_file to simplify some things
- Reduced a buncha lines of code in the process
-rw-r--r-- | editors/sed.c | 249 | ||||
-rw-r--r-- | sed.c | 249 | ||||
-rw-r--r-- | tests/testcases | 10 |
3 files changed, 273 insertions, 235 deletions
diff --git a/editors/sed.c b/editors/sed.c index 95be01822..73ed058e2 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -156,7 +156,7 @@ static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const c | |||
156 | /* | 156 | /* |
157 | * returns the index in the string just past where the address ends. | 157 | * returns the index in the string just past where the address ends. |
158 | */ | 158 | */ |
159 | static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, regex_t **regex) | 159 | static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex) |
160 | { | 160 | { |
161 | char *my_str = strdup(str); | 161 | char *my_str = strdup(str); |
162 | int idx = 0; | 162 | int idx = 0; |
@@ -169,10 +169,10 @@ static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, rege | |||
169 | idx++; | 169 | idx++; |
170 | } while (isdigit(my_str[idx])); | 170 | } while (isdigit(my_str[idx])); |
171 | my_str[idx] = 0; | 171 | my_str[idx] = 0; |
172 | *line = atoi(my_str); | 172 | *linenum = atoi(my_str); |
173 | } | 173 | } |
174 | else if (my_str[idx] == '$') { | 174 | else if (my_str[idx] == '$') { |
175 | *line = -1; | 175 | *linenum = -1; |
176 | idx++; | 176 | idx++; |
177 | } | 177 | } |
178 | else if (my_str[idx] == '/') { | 178 | else if (my_str[idx] == '/') { |
@@ -423,13 +423,13 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
423 | if (strchr("pd", cmdstr[idx])) { | 423 | if (strchr("pd", cmdstr[idx])) { |
424 | idx++; | 424 | idx++; |
425 | } | 425 | } |
426 | /* handle (s)ubstitution */ | 426 | /* handle (s)ubstitution command */ |
427 | else if (sed_cmd->cmd == 's') { | 427 | else if (sed_cmd->cmd == 's') { |
428 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); | 428 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); |
429 | } | 429 | } |
430 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ | 430 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ |
431 | else if (strchr("aic", cmdstr[idx])) { | 431 | else if (strchr("aic", sed_cmd->cmd)) { |
432 | if (sed_cmd->end_line || sed_cmd->end_match) | 432 | if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') |
433 | error_msg_and_die("only a beginning address can be specified for edit commands"); | 433 | error_msg_and_die("only a beginning address can be specified for edit commands"); |
434 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); | 434 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); |
435 | } | 435 | } |
@@ -584,91 +584,13 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | |||
584 | return altered; | 584 | return altered; |
585 | } | 585 | } |
586 | 586 | ||
587 | static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line) | ||
588 | { | ||
589 | int altered = 0; | ||
590 | |||
591 | switch (sed_cmd->cmd) { | ||
592 | |||
593 | case 'p': | ||
594 | puts(line); | ||
595 | break; | ||
596 | |||
597 | case 'd': | ||
598 | altered++; | ||
599 | break; | ||
600 | |||
601 | case 's': | ||
602 | |||
603 | /* | ||
604 | * Some special cases for 's' printing to make it compliant with | ||
605 | * GNU sed printing behavior (aka "The -n | s///p Matrix"): | ||
606 | * | ||
607 | * -n ONLY = never print anything regardless of any successful | ||
608 | * substitution | ||
609 | * | ||
610 | * s///p ONLY = always print successful substitutions, even if | ||
611 | * the line is going to be printed anyway (line will be printed | ||
612 | * twice). | ||
613 | * | ||
614 | * -n AND s///p = print ONLY a successful substitution ONE TIME; | ||
615 | * no other lines are printed - this is the reason why the 'p' | ||
616 | * flag exists in the first place. | ||
617 | */ | ||
618 | |||
619 | /* if the user specified that they didn't want anything printed (i.e., a -n | ||
620 | * flag and no 'p' flag after the s///), then there's really no point doing | ||
621 | * anything here. */ | ||
622 | if (be_quiet && !sed_cmd->sub_p) | ||
623 | break; | ||
624 | |||
625 | /* we print the line once, unless we were told to be quiet */ | ||
626 | if (!be_quiet) | ||
627 | altered = do_subst_command(sed_cmd, line); | ||
628 | |||
629 | /* we also print the line if we were given the 'p' flag | ||
630 | * (this is quite possibly the second printing) */ | ||
631 | if (sed_cmd->sub_p) | ||
632 | altered = do_subst_command(sed_cmd, line); | ||
633 | |||
634 | break; | ||
635 | |||
636 | case 'a': | ||
637 | puts(line); | ||
638 | fputs(sed_cmd->editline, stdout); | ||
639 | altered++; | ||
640 | break; | ||
641 | |||
642 | case 'i': | ||
643 | fputs(sed_cmd->editline, stdout); | ||
644 | break; | ||
645 | |||
646 | case 'c': | ||
647 | fputs(sed_cmd->editline, stdout); | ||
648 | altered++; | ||
649 | break; | ||
650 | |||
651 | case 'r': { | ||
652 | FILE *file; | ||
653 | puts(line); | ||
654 | file = fopen(sed_cmd->filename, "r"); | ||
655 | if (file) | ||
656 | print_file(file); | ||
657 | /* else if we couldn't open the file, no biggie, just don't print anything */ | ||
658 | altered++; | ||
659 | } | ||
660 | break; | ||
661 | } | ||
662 | |||
663 | return altered; | ||
664 | } | ||
665 | 587 | ||
666 | static void process_file(FILE *file) | 588 | static void process_file(FILE *file) |
667 | { | 589 | { |
668 | char *line = NULL; | 590 | char *line = NULL; |
669 | static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ | 591 | static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ |
670 | unsigned int still_in_range = 0; | 592 | unsigned int still_in_range = 0; |
671 | int line_altered; | 593 | int altered; |
672 | int i; | 594 | int i; |
673 | 595 | ||
674 | /* go through every line in the file */ | 596 | /* go through every line in the file */ |
@@ -676,51 +598,144 @@ static void process_file(FILE *file) | |||
676 | 598 | ||
677 | chomp(line); | 599 | chomp(line); |
678 | linenum++; | 600 | linenum++; |
679 | line_altered = 0; | 601 | altered = 0; |
680 | 602 | ||
681 | /* for every line, go through all the commands */ | 603 | /* for every line, go through all the commands */ |
682 | for (i = 0; i < ncmds; i++) { | 604 | for (i = 0; i < ncmds; i++) { |
683 | 605 | ||
684 | /* are we acting on a range of matched lines? */ | ||
685 | if (sed_cmds[i].beg_match && sed_cmds[i].end_match) { | ||
686 | if (still_in_range || regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0) { | ||
687 | line_altered += do_sed_command(&sed_cmds[i], line); | ||
688 | if (still_in_range && regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0) | ||
689 | still_in_range = 0; | ||
690 | else | ||
691 | still_in_range = 1; | ||
692 | } | ||
693 | } | ||
694 | 606 | ||
695 | /* are we trying to match a single line? */ | 607 | /* |
696 | else if (sed_cmds[i].beg_match) { | 608 | * entry point into sedding... |
697 | if (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0) | 609 | */ |
698 | line_altered += do_sed_command(&sed_cmds[i], line); | 610 | if ( |
699 | } | 611 | /* this line number is the first address we're looking for */ |
612 | (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) || | ||
613 | /* this line matches our first address regex */ | ||
614 | (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) || | ||
615 | /* we are currently within the beginning & ending address range */ | ||
616 | still_in_range | ||
617 | ) { | ||
618 | |||
619 | /* | ||
620 | * actual sedding | ||
621 | */ | ||
622 | switch (sed_cmds[i].cmd) { | ||
623 | |||
624 | case 'p': | ||
625 | puts(line); | ||
626 | break; | ||
627 | |||
628 | case 'd': | ||
629 | altered++; | ||
630 | break; | ||
631 | |||
632 | case 's': | ||
633 | |||
634 | /* | ||
635 | * Some special cases for 's' printing to make it compliant with | ||
636 | * GNU sed printing behavior (aka "The -n | s///p Matrix"): | ||
637 | * | ||
638 | * -n ONLY = never print anything regardless of any successful | ||
639 | * substitution | ||
640 | * | ||
641 | * s///p ONLY = always print successful substitutions, even if | ||
642 | * the line is going to be printed anyway (line will be printed | ||
643 | * twice). | ||
644 | * | ||
645 | * -n AND s///p = print ONLY a successful substitution ONE TIME; | ||
646 | * no other lines are printed - this is the reason why the 'p' | ||
647 | * flag exists in the first place. | ||
648 | */ | ||
649 | |||
650 | /* if the user specified that they didn't want anything printed (i.e., a -n | ||
651 | * flag and no 'p' flag after the s///), then there's really no point doing | ||
652 | * anything here. */ | ||
653 | if (be_quiet && !sed_cmds[i].sub_p) | ||
654 | break; | ||
655 | |||
656 | /* we print the line once, unless we were told to be quiet */ | ||
657 | if (!be_quiet) | ||
658 | altered = do_subst_command(&sed_cmds[i], line); | ||
659 | |||
660 | /* we also print the line if we were given the 'p' flag | ||
661 | * (this is quite possibly the second printing) */ | ||
662 | if (sed_cmds[i].sub_p) | ||
663 | altered = do_subst_command(&sed_cmds[i], line); | ||
664 | |||
665 | break; | ||
666 | |||
667 | case 'a': | ||
668 | puts(line); | ||
669 | fputs(sed_cmds[i].editline, stdout); | ||
670 | altered++; | ||
671 | break; | ||
672 | |||
673 | case 'i': | ||
674 | fputs(sed_cmds[i].editline, stdout); | ||
675 | break; | ||
676 | |||
677 | case 'c': | ||
678 | /* single-address case */ | ||
679 | if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) { | ||
680 | fputs(sed_cmds[i].editline, stdout); | ||
681 | } | ||
682 | /* multi-address case */ | ||
683 | else { | ||
684 | /* matching text */ | ||
685 | if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) | ||
686 | fputs(sed_cmds[i].editline, stdout); | ||
687 | /* matching line numbers */ | ||
688 | if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum) | ||
689 | fputs(sed_cmds[i].editline, stdout); | ||
690 | } | ||
691 | altered++; | ||
692 | |||
693 | break; | ||
694 | |||
695 | case 'r': { | ||
696 | FILE *outfile; | ||
697 | puts(line); | ||
698 | outfile = fopen(sed_cmds[i].filename, "r"); | ||
699 | if (outfile) | ||
700 | print_file(outfile); | ||
701 | /* else if we couldn't open the output file, | ||
702 | * no biggie, just don't print anything */ | ||
703 | altered++; | ||
704 | } | ||
705 | break; | ||
706 | } | ||
700 | 707 | ||
701 | /* are we acting on a range of line numbers? */ | 708 | /* |
702 | else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) { | 709 | * exit point from sedding... |
703 | if (linenum >= sed_cmds[i].beg_line && | 710 | */ |
704 | (sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line)) | 711 | if ( |
705 | line_altered += do_sed_command(&sed_cmds[i], line); | 712 | /* this is a single-address command or... */ |
706 | } | 713 | (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || ( |
714 | /* we were in the middle of our address range (this | ||
715 | * isn't the first time through) and.. */ | ||
716 | (still_in_range == 1) && ( | ||
717 | /* this line number is the last address we're looking for or... */ | ||
718 | (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) || | ||
719 | /* this line matches our last address regex */ | ||
720 | (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) | ||
721 | ) | ||
722 | ) | ||
723 | ) { | ||
724 | /* we're out of our address range */ | ||
725 | still_in_range = 0; | ||
726 | } | ||
707 | 727 | ||
708 | /* are we acting on a specified line number */ | 728 | /* didn't hit the exit? then we're still in the middle of an address range */ |
709 | else if (sed_cmds[i].beg_line > 0) { | 729 | else { |
710 | if (linenum == sed_cmds[i].beg_line) | 730 | still_in_range = 1; |
711 | line_altered += do_sed_command(&sed_cmds[i], line); | 731 | } |
712 | } | 732 | } |
713 | |||
714 | /* not acting on matches or line numbers. act on every line */ | ||
715 | else | ||
716 | line_altered += do_sed_command(&sed_cmds[i], line); | ||
717 | |||
718 | } | 733 | } |
719 | 734 | ||
720 | /* we will print the line unless we were told to be quiet or if the | 735 | /* we will print the line unless we were told to be quiet or if the |
721 | * line was altered (via a 'd'elete or 's'ubstitution), in which case | 736 | * line was altered (via a 'd'elete or 's'ubstitution), in which case |
722 | * the altered line was already printed */ | 737 | * the altered line was already printed */ |
723 | if (!be_quiet && !line_altered) | 738 | if (!be_quiet && !altered) |
724 | puts(line); | 739 | puts(line); |
725 | 740 | ||
726 | free(line); | 741 | free(line); |
@@ -156,7 +156,7 @@ static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const c | |||
156 | /* | 156 | /* |
157 | * returns the index in the string just past where the address ends. | 157 | * returns the index in the string just past where the address ends. |
158 | */ | 158 | */ |
159 | static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, regex_t **regex) | 159 | static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex) |
160 | { | 160 | { |
161 | char *my_str = strdup(str); | 161 | char *my_str = strdup(str); |
162 | int idx = 0; | 162 | int idx = 0; |
@@ -169,10 +169,10 @@ static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, rege | |||
169 | idx++; | 169 | idx++; |
170 | } while (isdigit(my_str[idx])); | 170 | } while (isdigit(my_str[idx])); |
171 | my_str[idx] = 0; | 171 | my_str[idx] = 0; |
172 | *line = atoi(my_str); | 172 | *linenum = atoi(my_str); |
173 | } | 173 | } |
174 | else if (my_str[idx] == '$') { | 174 | else if (my_str[idx] == '$') { |
175 | *line = -1; | 175 | *linenum = -1; |
176 | idx++; | 176 | idx++; |
177 | } | 177 | } |
178 | else if (my_str[idx] == '/') { | 178 | else if (my_str[idx] == '/') { |
@@ -423,13 +423,13 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
423 | if (strchr("pd", cmdstr[idx])) { | 423 | if (strchr("pd", cmdstr[idx])) { |
424 | idx++; | 424 | idx++; |
425 | } | 425 | } |
426 | /* handle (s)ubstitution */ | 426 | /* handle (s)ubstitution command */ |
427 | else if (sed_cmd->cmd == 's') { | 427 | else if (sed_cmd->cmd == 's') { |
428 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); | 428 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); |
429 | } | 429 | } |
430 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ | 430 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ |
431 | else if (strchr("aic", cmdstr[idx])) { | 431 | else if (strchr("aic", sed_cmd->cmd)) { |
432 | if (sed_cmd->end_line || sed_cmd->end_match) | 432 | if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') |
433 | error_msg_and_die("only a beginning address can be specified for edit commands"); | 433 | error_msg_and_die("only a beginning address can be specified for edit commands"); |
434 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); | 434 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); |
435 | } | 435 | } |
@@ -584,91 +584,13 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | |||
584 | return altered; | 584 | return altered; |
585 | } | 585 | } |
586 | 586 | ||
587 | static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line) | ||
588 | { | ||
589 | int altered = 0; | ||
590 | |||
591 | switch (sed_cmd->cmd) { | ||
592 | |||
593 | case 'p': | ||
594 | puts(line); | ||
595 | break; | ||
596 | |||
597 | case 'd': | ||
598 | altered++; | ||
599 | break; | ||
600 | |||
601 | case 's': | ||
602 | |||
603 | /* | ||
604 | * Some special cases for 's' printing to make it compliant with | ||
605 | * GNU sed printing behavior (aka "The -n | s///p Matrix"): | ||
606 | * | ||
607 | * -n ONLY = never print anything regardless of any successful | ||
608 | * substitution | ||
609 | * | ||
610 | * s///p ONLY = always print successful substitutions, even if | ||
611 | * the line is going to be printed anyway (line will be printed | ||
612 | * twice). | ||
613 | * | ||
614 | * -n AND s///p = print ONLY a successful substitution ONE TIME; | ||
615 | * no other lines are printed - this is the reason why the 'p' | ||
616 | * flag exists in the first place. | ||
617 | */ | ||
618 | |||
619 | /* if the user specified that they didn't want anything printed (i.e., a -n | ||
620 | * flag and no 'p' flag after the s///), then there's really no point doing | ||
621 | * anything here. */ | ||
622 | if (be_quiet && !sed_cmd->sub_p) | ||
623 | break; | ||
624 | |||
625 | /* we print the line once, unless we were told to be quiet */ | ||
626 | if (!be_quiet) | ||
627 | altered = do_subst_command(sed_cmd, line); | ||
628 | |||
629 | /* we also print the line if we were given the 'p' flag | ||
630 | * (this is quite possibly the second printing) */ | ||
631 | if (sed_cmd->sub_p) | ||
632 | altered = do_subst_command(sed_cmd, line); | ||
633 | |||
634 | break; | ||
635 | |||
636 | case 'a': | ||
637 | puts(line); | ||
638 | fputs(sed_cmd->editline, stdout); | ||
639 | altered++; | ||
640 | break; | ||
641 | |||
642 | case 'i': | ||
643 | fputs(sed_cmd->editline, stdout); | ||
644 | break; | ||
645 | |||
646 | case 'c': | ||
647 | fputs(sed_cmd->editline, stdout); | ||
648 | altered++; | ||
649 | break; | ||
650 | |||
651 | case 'r': { | ||
652 | FILE *file; | ||
653 | puts(line); | ||
654 | file = fopen(sed_cmd->filename, "r"); | ||
655 | if (file) | ||
656 | print_file(file); | ||
657 | /* else if we couldn't open the file, no biggie, just don't print anything */ | ||
658 | altered++; | ||
659 | } | ||
660 | break; | ||
661 | } | ||
662 | |||
663 | return altered; | ||
664 | } | ||
665 | 587 | ||
666 | static void process_file(FILE *file) | 588 | static void process_file(FILE *file) |
667 | { | 589 | { |
668 | char *line = NULL; | 590 | char *line = NULL; |
669 | static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ | 591 | static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ |
670 | unsigned int still_in_range = 0; | 592 | unsigned int still_in_range = 0; |
671 | int line_altered; | 593 | int altered; |
672 | int i; | 594 | int i; |
673 | 595 | ||
674 | /* go through every line in the file */ | 596 | /* go through every line in the file */ |
@@ -676,51 +598,144 @@ static void process_file(FILE *file) | |||
676 | 598 | ||
677 | chomp(line); | 599 | chomp(line); |
678 | linenum++; | 600 | linenum++; |
679 | line_altered = 0; | 601 | altered = 0; |
680 | 602 | ||
681 | /* for every line, go through all the commands */ | 603 | /* for every line, go through all the commands */ |
682 | for (i = 0; i < ncmds; i++) { | 604 | for (i = 0; i < ncmds; i++) { |
683 | 605 | ||
684 | /* are we acting on a range of matched lines? */ | ||
685 | if (sed_cmds[i].beg_match && sed_cmds[i].end_match) { | ||
686 | if (still_in_range || regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0) { | ||
687 | line_altered += do_sed_command(&sed_cmds[i], line); | ||
688 | if (still_in_range && regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0) | ||
689 | still_in_range = 0; | ||
690 | else | ||
691 | still_in_range = 1; | ||
692 | } | ||
693 | } | ||
694 | 606 | ||
695 | /* are we trying to match a single line? */ | 607 | /* |
696 | else if (sed_cmds[i].beg_match) { | 608 | * entry point into sedding... |
697 | if (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0) | 609 | */ |
698 | line_altered += do_sed_command(&sed_cmds[i], line); | 610 | if ( |
699 | } | 611 | /* this line number is the first address we're looking for */ |
612 | (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) || | ||
613 | /* this line matches our first address regex */ | ||
614 | (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) || | ||
615 | /* we are currently within the beginning & ending address range */ | ||
616 | still_in_range | ||
617 | ) { | ||
618 | |||
619 | /* | ||
620 | * actual sedding | ||
621 | */ | ||
622 | switch (sed_cmds[i].cmd) { | ||
623 | |||
624 | case 'p': | ||
625 | puts(line); | ||
626 | break; | ||
627 | |||
628 | case 'd': | ||
629 | altered++; | ||
630 | break; | ||
631 | |||
632 | case 's': | ||
633 | |||
634 | /* | ||
635 | * Some special cases for 's' printing to make it compliant with | ||
636 | * GNU sed printing behavior (aka "The -n | s///p Matrix"): | ||
637 | * | ||
638 | * -n ONLY = never print anything regardless of any successful | ||
639 | * substitution | ||
640 | * | ||
641 | * s///p ONLY = always print successful substitutions, even if | ||
642 | * the line is going to be printed anyway (line will be printed | ||
643 | * twice). | ||
644 | * | ||
645 | * -n AND s///p = print ONLY a successful substitution ONE TIME; | ||
646 | * no other lines are printed - this is the reason why the 'p' | ||
647 | * flag exists in the first place. | ||
648 | */ | ||
649 | |||
650 | /* if the user specified that they didn't want anything printed (i.e., a -n | ||
651 | * flag and no 'p' flag after the s///), then there's really no point doing | ||
652 | * anything here. */ | ||
653 | if (be_quiet && !sed_cmds[i].sub_p) | ||
654 | break; | ||
655 | |||
656 | /* we print the line once, unless we were told to be quiet */ | ||
657 | if (!be_quiet) | ||
658 | altered = do_subst_command(&sed_cmds[i], line); | ||
659 | |||
660 | /* we also print the line if we were given the 'p' flag | ||
661 | * (this is quite possibly the second printing) */ | ||
662 | if (sed_cmds[i].sub_p) | ||
663 | altered = do_subst_command(&sed_cmds[i], line); | ||
664 | |||
665 | break; | ||
666 | |||
667 | case 'a': | ||
668 | puts(line); | ||
669 | fputs(sed_cmds[i].editline, stdout); | ||
670 | altered++; | ||
671 | break; | ||
672 | |||
673 | case 'i': | ||
674 | fputs(sed_cmds[i].editline, stdout); | ||
675 | break; | ||
676 | |||
677 | case 'c': | ||
678 | /* single-address case */ | ||
679 | if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) { | ||
680 | fputs(sed_cmds[i].editline, stdout); | ||
681 | } | ||
682 | /* multi-address case */ | ||
683 | else { | ||
684 | /* matching text */ | ||
685 | if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) | ||
686 | fputs(sed_cmds[i].editline, stdout); | ||
687 | /* matching line numbers */ | ||
688 | if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum) | ||
689 | fputs(sed_cmds[i].editline, stdout); | ||
690 | } | ||
691 | altered++; | ||
692 | |||
693 | break; | ||
694 | |||
695 | case 'r': { | ||
696 | FILE *outfile; | ||
697 | puts(line); | ||
698 | outfile = fopen(sed_cmds[i].filename, "r"); | ||
699 | if (outfile) | ||
700 | print_file(outfile); | ||
701 | /* else if we couldn't open the output file, | ||
702 | * no biggie, just don't print anything */ | ||
703 | altered++; | ||
704 | } | ||
705 | break; | ||
706 | } | ||
700 | 707 | ||
701 | /* are we acting on a range of line numbers? */ | 708 | /* |
702 | else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) { | 709 | * exit point from sedding... |
703 | if (linenum >= sed_cmds[i].beg_line && | 710 | */ |
704 | (sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line)) | 711 | if ( |
705 | line_altered += do_sed_command(&sed_cmds[i], line); | 712 | /* this is a single-address command or... */ |
706 | } | 713 | (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || ( |
714 | /* we were in the middle of our address range (this | ||
715 | * isn't the first time through) and.. */ | ||
716 | (still_in_range == 1) && ( | ||
717 | /* this line number is the last address we're looking for or... */ | ||
718 | (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) || | ||
719 | /* this line matches our last address regex */ | ||
720 | (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) | ||
721 | ) | ||
722 | ) | ||
723 | ) { | ||
724 | /* we're out of our address range */ | ||
725 | still_in_range = 0; | ||
726 | } | ||
707 | 727 | ||
708 | /* are we acting on a specified line number */ | 728 | /* didn't hit the exit? then we're still in the middle of an address range */ |
709 | else if (sed_cmds[i].beg_line > 0) { | 729 | else { |
710 | if (linenum == sed_cmds[i].beg_line) | 730 | still_in_range = 1; |
711 | line_altered += do_sed_command(&sed_cmds[i], line); | 731 | } |
712 | } | 732 | } |
713 | |||
714 | /* not acting on matches or line numbers. act on every line */ | ||
715 | else | ||
716 | line_altered += do_sed_command(&sed_cmds[i], line); | ||
717 | |||
718 | } | 733 | } |
719 | 734 | ||
720 | /* we will print the line unless we were told to be quiet or if the | 735 | /* we will print the line unless we were told to be quiet or if the |
721 | * line was altered (via a 'd'elete or 's'ubstitution), in which case | 736 | * line was altered (via a 'd'elete or 's'ubstitution), in which case |
722 | * the altered line was already printed */ | 737 | * the altered line was already printed */ |
723 | if (!be_quiet && !line_altered) | 738 | if (!be_quiet && !altered) |
724 | puts(line); | 739 | puts(line); |
725 | 740 | ||
726 | free(line); | 741 | free(line); |
diff --git a/tests/testcases b/tests/testcases index 5043c309e..a38d31770 100644 --- a/tests/testcases +++ b/tests/testcases | |||
@@ -294,11 +294,19 @@ route | |||
294 | 294 | ||
295 | # rpmunpack | 295 | # rpmunpack |
296 | 296 | ||
297 | # sed - we can do some one-liners here; probably needs it's own input file | 297 | # sed - we can do some one-liners here, some testing is a little |
298 | # difficult to do in just this space (like a,i,c cmds). | ||
299 | |||
300 | # test ^$ matching | ||
298 | echo foo | sed -ne '/^$/p' | 301 | echo foo | sed -ne '/^$/p' |
302 | echo -e "foo\\n\\nbar" | sed -ne '/^$/p' | ||
303 | |||
299 | sed -e '/test$/d' testcases | 304 | sed -e '/test$/d' testcases |
300 | sed -e '/^echo/d' testcases | 305 | sed -e '/^echo/d' testcases |
301 | sed -e '/test/s/dangerous/PELIGROSO/' testcases | 306 | sed -e '/test/s/dangerous/PELIGROSO/' testcases |
307 | sed -ne '1,/getopt/p' ../pwd.c | ||
308 | sed -e '/getopt/r ../pwd.c' ../sed.c | ||
309 | |||
302 | 310 | ||
303 | # setkeycodes | 311 | # setkeycodes |
304 | 312 | ||