[PATCH 1/1] sed: /regex/,+N ranges

Denys Vlasenko vda.linux at googlemail.com
Thu Apr 16 16:07:10 UTC 2015


It fails a case where we have more than one file:

testing "sed -i finishes ranges correctly" \
        "cat - >input2; sed /^4/,+2{d} -i input input2; echo \$?; cat
input input2; rm input2" \
        "0\n""1\n2\n3\n7\n8\n""1\n2\n7\n8\n" \
        "1\n2\n3\n4\n5\n6\n7\n8\n" \
        "1\n2\n4\n5\n6\n7\n8\n"

I'm working on a code which will handle this too.

On Wed, Apr 15, 2015 at 1:35 AM, Bernhard Reutner-Fischer
<rep.dot.nop at gmail.com> wrote:
> function                                             old     new   delta
> add_cmd                                             1207    1359    +152
> process_files                                       2502    2530     +28
> ------------------------------------------------------------------------------
> (add/remove: 0/0 grow/shrink: 2/0 up/down: 180/0)             Total: 180 bytes
>
> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
> ---
>  editors/sed.c       | 36 +++++++++++++++++++++++++++++++-----
>  testsuite/sed.tests | 12 ++++++++++++
>  2 files changed, 43 insertions(+), 5 deletions(-)
>
> diff --git a/editors/sed.c b/editors/sed.c
> index 2c64ad5..7d7e17c 100644
> --- a/editors/sed.c
> +++ b/editors/sed.c
> @@ -640,10 +640,25 @@ static void add_cmd(const char *cmdstr)
>                         int idx;
>
>                         cmdstr++;
> -                       idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
> +                       if (*cmdstr == '+') {
> +                               /* http://sed.sourceforge.net/sedfaq3.html#s3.3
> +                                * Under GNU sed 3.02+, ssed, and sed15+, <address2>
> +                                * may also be a notation of the form +num,
> +                                * indicating the next num lines after <address1> is
> +                                * matched. */
> +                               /* Set both end_line and end_match to distinguish this case */
> +                               idx = strtol(cmdstr, (char**)&cmdstr, 10);
> +                               if (cmdstr == NULL)
> +                                       idx = 0;
> +                               sed_cmd->end_line = idx;
> +                               sed_cmd->end_match = xzalloc(sizeof(regex_t));
> +                               xregcomp(sed_cmd->end_match, ".*", REG_EXTENDED);
> +                       } else {
> +                               idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
> +                               cmdstr += idx;
> +                       }
>                         if (!idx)
>                                 bb_error_msg_and_die("no address after comma");
> -                       cmdstr += idx;
>                 }
>
>                 /* skip whitespace before the command */
> @@ -1089,10 +1104,21 @@ static void process_files(void)
>                 /* Is this line the end of the current match? */
>
>                 if (matched) {
> -                       /* once matched, "n,xxx" range is dead, disabling it */
> -                       if (sed_cmd->beg_line > 0) {
> -                               sed_cmd->beg_line = -2;
> +                       if (sed_cmd->end_line && sed_cmd->end_match) {
> +                               /* address2 is +N, i.e. N lines from beg_line */
> +                               sed_cmd->end_line--;
> +                               sed_cmd->beg_line++;
> +                       } else {
> +                               /* once matched, "n,xxx" range is dead, disabling it */
> +                               if (sed_cmd->beg_line > 0) {
> +                                       sed_cmd->beg_line = -2;
> +                               }
>                         }
> +                       dbg("end1:%d", sed_cmd->end_line ? sed_cmd->end_line == -1
> +                                               ? !next_line : (sed_cmd->end_line <= linenum)
> +                                       : !sed_cmd->end_match);
> +                       dbg("end2:%d", sed_cmd->end_match && old_matched
> +                                       && !regexec(sed_cmd->end_match,pattern_space, 0, NULL, 0));
>                         sed_cmd->in_match = !(
>                                 /* has the ending line come, or is this a single address command? */
>                                 (sed_cmd->end_line
> diff --git a/testsuite/sed.tests b/testsuite/sed.tests
> index 19f2915..399230f 100755
> --- a/testsuite/sed.tests
> +++ b/testsuite/sed.tests
> @@ -333,6 +333,18 @@ testing "sed s///NUM test" \
>         "sed -e 's/a/b/2; s/a/c/g'" \
>         "cb\n" "" "aa\n"
>
> +testing "sed /regex/,N/{} addresses work" \
> +       "sed /^2/,2{d}" \
> +       "1\n3\n4\n5\n" \
> +       "" \
> +       "1\n2\n3\n4\n5\n"
> +
> +testing "sed /regex/,+N/{} addresses work" \
> +       "sed /^2/,+2{d}" \
> +       "1\n5\n" \
> +       "" \
> +       "1\n2\n3\n4\n5\n"
> +
>  # testing "description" "commands" "result" "infile" "stdin"
>
>  exit $FAILCOUNT
> --
> 2.1.4
>


More information about the busybox mailing list