changeset 4891:4c42efb4c098 v7.3.1191

updated for version 7.3.1191 Problem: Backreference to previous line doesn't work. (Lech Lorens) Solution: Implement looking in another line.
author Bram Moolenaar <bram@vim.org>
date Fri, 14 Jun 2013 20:31:28 +0200
parents 96328930d94c
children c2b5b3ead8e9
files src/regexp.c src/regexp_nfa.c src/testdir/test64.in src/testdir/test64.ok src/version.c
diffstat 5 files changed, 113 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- 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
 
--- 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
--- 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<yyy
 xxstart1
--- a/src/testdir/test64.ok
+++ b/src/testdir/test64.ok
@@ -920,6 +920,8 @@ ghi
 
 c
 
+./Dir1/Dir2/file1.txt
+
 xxstart3
 
 thexE thE thExethe
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1191,
+/**/
     1190,
 /**/
     1189,