# HG changeset patch # User Bram Moolenaar # Date 1371234688 -7200 # Node ID 4c42efb4c0982d305ec9ee99bb3bddfaeec2cf87 # Parent 96328930d94c9c5012e0be7e00d708a9404b69fa updated for version 7.3.1191 Problem: Backreference to previous line doesn't work. (Lech Lorens) Solution: Implement looking in another line. diff --git a/src/regexp.c b/src/regexp.c --- a/src/regexp.c +++ b/src/regexp.c @@ -3519,6 +3519,7 @@ static void save_se_one __ARGS((save_se_ *(pp) = (savep)->se_u.ptr; } static int re_num_cmp __ARGS((long_u val, char_u *scan)); +static int match_with_backref __ARGS((linenr_T start_lnum, colnr_T start_col, linenr_T end_lnum, colnr_T end_col, int *bytelen)); static int regmatch __ARGS((char_u *prog)); static int regrepeat __ARGS((char_u *p, long maxcount)); @@ -4979,9 +4980,6 @@ regmatch(scan) case BACKREF + 9: { int len; - linenr_T clnum; - colnr_T ccol; - char_u *p; no = op - BACKREF; cleanup_subexpr(); @@ -5023,67 +5021,12 @@ regmatch(scan) { /* Messy situation: Need to compare between two * lines. */ - ccol = reg_startpos[no].col; - clnum = reg_startpos[no].lnum; - for (;;) - { - /* Since getting one line may invalidate - * the other, need to make copy. Slow! */ - if (regline != reg_tofree) - { - len = (int)STRLEN(regline); - if (reg_tofree == NULL - || len >= (int)reg_tofreelen) - { - len += 50; /* get some extra */ - vim_free(reg_tofree); - reg_tofree = alloc(len); - if (reg_tofree == NULL) - { - status = RA_FAIL; /* outof memory!*/ - break; - } - reg_tofreelen = len; - } - STRCPY(reg_tofree, regline); - reginput = reg_tofree - + (reginput - regline); - regline = reg_tofree; - } - - /* Get the line to compare with. */ - p = reg_getline(clnum); - if (clnum == reg_endpos[no].lnum) - len = reg_endpos[no].col - ccol; - else - len = (int)STRLEN(p + ccol); - - if (cstrncmp(p + ccol, reginput, &len) != 0) - { - status = RA_NOMATCH; /* doesn't match */ - break; - } - if (clnum == reg_endpos[no].lnum) - break; /* match and at end! */ - if (reglnum >= reg_maxline) - { - status = RA_NOMATCH; /* text too short */ - break; - } - - /* Advance to next line. */ - reg_nextline(); - ++clnum; - ccol = 0; - if (got_int) - { - status = RA_FAIL; - break; - } - } - - /* found a match! Note that regline may now point - * to a copy of the line, that should not matter. */ + status = match_with_backref( + reg_startpos[no].lnum, + reg_startpos[no].col, + reg_endpos[no].lnum, + reg_endpos[no].col, + NULL); } } } @@ -6505,6 +6448,75 @@ re_num_cmp(val, scan) return val == n; } +/* + * Check whether a backreference matches. + * Returns RA_FAIL, RA_NOMATCH or RA_MATCH. + * If "bytelen" is not NULL, it is set to the bytelength of the whole match. + */ + static int +match_with_backref(start_lnum, start_col, end_lnum, end_col, bytelen) + linenr_T start_lnum; + colnr_T start_col; + linenr_T end_lnum; + colnr_T end_col; + int *bytelen; +{ + linenr_T clnum = start_lnum; + colnr_T ccol = start_col; + int len; + char_u *p; + + if (bytelen != NULL) + *bytelen = 0; + for (;;) + { + /* Since getting one line may invalidate the other, need to make copy. + * Slow! */ + if (regline != reg_tofree) + { + len = (int)STRLEN(regline); + if (reg_tofree == NULL || len >= (int)reg_tofreelen) + { + len += 50; /* get some extra */ + vim_free(reg_tofree); + reg_tofree = alloc(len); + if (reg_tofree == NULL) + return RA_FAIL; /* out of memory!*/ + reg_tofreelen = len; + } + STRCPY(reg_tofree, regline); + reginput = reg_tofree + (reginput - regline); + regline = reg_tofree; + } + + /* Get the line to compare with. */ + p = reg_getline(clnum); + if (clnum == end_lnum) + len = end_col - ccol; + else + len = (int)STRLEN(p + ccol); + + if (cstrncmp(p + ccol, reginput, &len) != 0) + return RA_NOMATCH; /* doesn't match */ + if (bytelen != NULL) + *bytelen += len; + if (clnum == end_lnum) + break; /* match and at end! */ + if (reglnum >= reg_maxline) + return RA_NOMATCH; /* text too short */ + + /* Advance to next line. */ + reg_nextline(); + ++clnum; + ccol = 0; + if (got_int) + return RA_FAIL; + } + + /* found a match! Note that regline may now point to a copy of the line, + * that should not matter. */ + return RA_MATCH; +} #ifdef BT_REGEXP_DUMP diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -4367,14 +4367,27 @@ retempty: if (sub->list.multi[subidx].start.lnum < 0 || sub->list.multi[subidx].end.lnum < 0) goto retempty; - /* TODO: line breaks */ - len = sub->list.multi[subidx].end.col - - sub->list.multi[subidx].start.col; - if (cstrncmp(regline + sub->list.multi[subidx].start.col, - reginput, &len) == 0) + if (sub->list.multi[subidx].start.lnum == reglnum + && sub->list.multi[subidx].end.lnum == reglnum) { - *bytelen = len; - return TRUE; + len = sub->list.multi[subidx].end.col + - sub->list.multi[subidx].start.col; + if (cstrncmp(regline + sub->list.multi[subidx].start.col, + reginput, &len) == 0) + { + *bytelen = len; + return TRUE; + } + } + else + { + if (match_with_backref( + sub->list.multi[subidx].start.lnum, + sub->list.multi[subidx].start.col, + sub->list.multi[subidx].end.lnum, + sub->list.multi[subidx].end.col, + bytelen) == RA_MATCH) + return TRUE; } } else diff --git a/src/testdir/test64.in b/src/testdir/test64.in --- a/src/testdir/test64.in +++ b/src/testdir/test64.in @@ -486,6 +486,12 @@ y$Gop:" :.yank Gop:" :" +:" Check using a backref matching in a previous line +/^Backref: +/\v.*\/(.*)\n.*\/\1$ +:.yank +Gop:" +:" :" Check a pattern with a look beind crossing a line boundary /^Behind: /\(<\_[xy]\+\)\@3<=start @@ -566,6 +572,13 @@ a b c +Backref: +./Dir1/Dir2/zyxwvuts.txt +./Dir1/Dir2/abcdefgh.bat + +./Dir1/Dir2/file1.txt +./OtherDir1/OtherDir2/file1.txt + Behind: asdfasd