To: vim_dev@googlegroups.com
Subject: Patch 7.3.1191
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
------------
Patch 7.3.1191
Problem: Backreference to previous line doesn't work. (Lech Lorens)
Solution: Implement looking in another line.
Files: src/regexp.c, src/regexp_nfa.c, src/testdir/test64.in,
src/testdir/test64.ok
*** ../vim-7.3.1190/src/regexp.c 2013-06-08 18:19:39.000000000 +0200
--- src/regexp.c 2013-06-14 20:23:33.000000000 +0200
***************
*** 3519,3524 ****
--- 3519,3525 ----
*(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,4987 ****
case BACKREF + 9:
{
int len;
- linenr_T clnum;
- colnr_T ccol;
- char_u *p;
no = op - BACKREF;
cleanup_subexpr();
--- 4980,4985 ----
***************
*** 5023,5089 ****
{
/* 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. */
}
}
}
--- 5021,5032 ----
{
/* Messy situation: Need to compare between two
* lines. */
! status = match_with_backref(
! reg_startpos[no].lnum,
! reg_startpos[no].col,
! reg_endpos[no].lnum,
! reg_endpos[no].col,
! NULL);
}
}
}
***************
*** 6505,6510 ****
--- 6448,6522 ----
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
*** ../vim-7.3.1190/src/regexp_nfa.c 2013-06-13 22:59:25.000000000 +0200
--- src/regexp_nfa.c 2013-06-14 20:19:59.000000000 +0200
***************
*** 4367,4380 ****
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)
{
! *bytelen = len;
! return TRUE;
}
}
else
--- 4367,4393 ----
if (sub->list.multi[subidx].start.lnum < 0
|| sub->list.multi[subidx].end.lnum < 0)
goto retempty;
! if (sub->list.multi[subidx].start.lnum == reglnum
! && sub->list.multi[subidx].end.lnum == reglnum)
{
! 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
*** ../vim-7.3.1190/src/testdir/test64.in 2013-06-13 20:19:35.000000000 +0200
--- src/testdir/test64.in 2013-06-14 20:01:56.000000000 +0200
***************
*** 486,491 ****
--- 486,497 ----
:.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,571 ****
--- 572,584 ----
b
c
+ Backref:
+ ./Dir1/Dir2/zyxwvuts.txt
+ ./Dir1/Dir2/abcdefgh.bat
+
+ ./Dir1/Dir2/file1.txt
+ ./OtherDir1/OtherDir2/file1.txt
+
Behind:
asdfasd<yyy
xxstart1
*** ../vim-7.3.1190/src/testdir/test64.ok 2013-06-13 20:19:35.000000000 +0200
--- src/testdir/test64.ok 2013-06-14 20:02:44.000000000 +0200
***************
*** 920,925 ****
--- 920,927 ----
c
+ ./Dir1/Dir2/file1.txt
+
xxstart3
thexE thE thExethe
*** ../vim-7.3.1190/src/version.c 2013-06-14 19:15:52.000000000 +0200
--- src/version.c 2013-06-14 20:30:34.000000000 +0200
***************
*** 730,731 ****
--- 730,733 ----
{ /* Add new patch number below this line */
+ /**/
+ 1191,
/**/
--
hundred-and-one symptoms of being an internet addict:
198. You read all the quotes at Netaholics Anonymous and keep thinking
"What's wrong with that?"
/// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///