Karsten Hopp bec9c6
To: vim_dev@googlegroups.com
Karsten Hopp bec9c6
Subject: Patch 7.3.1088
Karsten Hopp bec9c6
Fcc: outbox
Karsten Hopp bec9c6
From: Bram Moolenaar <Bram@moolenaar.net>
Karsten Hopp bec9c6
Mime-Version: 1.0
Karsten Hopp bec9c6
Content-Type: text/plain; charset=UTF-8
Karsten Hopp bec9c6
Content-Transfer-Encoding: 8bit
Karsten Hopp bec9c6
------------
Karsten Hopp bec9c6
Karsten Hopp bec9c6
Patch 7.3.1088
Karsten Hopp bec9c6
Problem:    New regexp engine: \@<= and \@
Karsten Hopp bec9c6
Solution:   Implement look-behind matching.  Fix off-by-one error in old
Karsten Hopp bec9c6
	    regexp engine.
Karsten Hopp bec9c6
Files:	    src/regexp.c, src/regexp_nfa.c, src/testdir/test64.in,
Karsten Hopp bec9c6
	    src/testdir/test64.ok
Karsten Hopp bec9c6
Karsten Hopp bec9c6
Karsten Hopp bec9c6
*** ../vim-7.3.1087/src/regexp.c	2013-06-01 14:42:51.000000000 +0200
Karsten Hopp bec9c6
--- src/regexp.c	2013-06-01 18:55:07.000000000 +0200
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 5576,5582 ****
Karsten Hopp bec9c6
  		limit = OPERAND_MIN(rp->rs_scan);
Karsten Hopp bec9c6
  		if (REG_MULTI)
Karsten Hopp bec9c6
  		{
Karsten Hopp bec9c6
! 		    if (rp->rs_un.regsave.rs_u.pos.col == 0)
Karsten Hopp bec9c6
  		    {
Karsten Hopp bec9c6
  			if (rp->rs_un.regsave.rs_u.pos.lnum
Karsten Hopp bec9c6
  					< behind_pos.rs_u.pos.lnum
Karsten Hopp bec9c6
--- 5576,5589 ----
Karsten Hopp bec9c6
  		limit = OPERAND_MIN(rp->rs_scan);
Karsten Hopp bec9c6
  		if (REG_MULTI)
Karsten Hopp bec9c6
  		{
Karsten Hopp bec9c6
! 		    if (limit > 0
Karsten Hopp bec9c6
! 			    && ((rp->rs_un.regsave.rs_u.pos.lnum
Karsten Hopp bec9c6
! 						    < behind_pos.rs_u.pos.lnum
Karsten Hopp bec9c6
! 				    ? (colnr_T)STRLEN(regline)
Karsten Hopp bec9c6
! 				    : behind_pos.rs_u.pos.col)
Karsten Hopp bec9c6
! 				- rp->rs_un.regsave.rs_u.pos.col >= limit))
Karsten Hopp bec9c6
! 			no = FAIL;
Karsten Hopp bec9c6
! 		    else if (rp->rs_un.regsave.rs_u.pos.col == 0)
Karsten Hopp bec9c6
  		    {
Karsten Hopp bec9c6
  			if (rp->rs_un.regsave.rs_u.pos.lnum
Karsten Hopp bec9c6
  					< behind_pos.rs_u.pos.lnum
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 5601,5613 ****
Karsten Hopp bec9c6
  			else
Karsten Hopp bec9c6
  #endif
Karsten Hopp bec9c6
  			    --rp->rs_un.regsave.rs_u.pos.col;
Karsten Hopp bec9c6
- 			if (limit > 0
Karsten Hopp bec9c6
- 				&& ((rp->rs_un.regsave.rs_u.pos.lnum
Karsten Hopp bec9c6
- 						    < behind_pos.rs_u.pos.lnum
Karsten Hopp bec9c6
- 					? (colnr_T)STRLEN(regline)
Karsten Hopp bec9c6
- 					: behind_pos.rs_u.pos.col)
Karsten Hopp bec9c6
- 				    - rp->rs_un.regsave.rs_u.pos.col > limit))
Karsten Hopp bec9c6
- 			    no = FAIL;
Karsten Hopp bec9c6
  		    }
Karsten Hopp bec9c6
  		}
Karsten Hopp bec9c6
  		else
Karsten Hopp bec9c6
--- 5608,5613 ----
Karsten Hopp bec9c6
*** ../vim-7.3.1087/src/regexp_nfa.c	2013-06-01 14:42:51.000000000 +0200
Karsten Hopp bec9c6
--- src/regexp_nfa.c	2013-06-01 19:42:22.000000000 +0200
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 56,61 ****
Karsten Hopp bec9c6
--- 56,62 ----
Karsten Hopp bec9c6
      NFA_NOPEN,			    /* Start of subexpression marked with \%( */
Karsten Hopp bec9c6
      NFA_NCLOSE,			    /* End of subexpr. marked with \%( ... \) */
Karsten Hopp bec9c6
      NFA_START_INVISIBLE,
Karsten Hopp bec9c6
+     NFA_START_INVISIBLE_BEFORE,
Karsten Hopp bec9c6
      NFA_END_INVISIBLE,
Karsten Hopp bec9c6
      NFA_COMPOSING,		    /* Next nodes in NFA are part of the
Karsten Hopp bec9c6
  				       composing multibyte char */
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 1369,1402 ****
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	case Magic('@'):
Karsten Hopp bec9c6
  	    op = no_Magic(getchr());
Karsten Hopp bec9c6
  	    switch(op)
Karsten Hopp bec9c6
  	    {
Karsten Hopp bec9c6
  		case '=':
Karsten Hopp bec9c6
! 		    EMIT(NFA_PREV_ATOM_NO_WIDTH);
Karsten Hopp bec9c6
  		    break;
Karsten Hopp bec9c6
  		case '!':
Karsten Hopp bec9c6
! 		    EMIT(NFA_PREV_ATOM_NO_WIDTH_NEG);
Karsten Hopp bec9c6
  		    break;
Karsten Hopp bec9c6
- 		case '0':
Karsten Hopp bec9c6
- 		case '1':
Karsten Hopp bec9c6
- 		case '2':
Karsten Hopp bec9c6
- 		case '3':
Karsten Hopp bec9c6
- 		case '4':
Karsten Hopp bec9c6
- 		case '5':
Karsten Hopp bec9c6
- 		case '6':
Karsten Hopp bec9c6
- 		case '7':
Karsten Hopp bec9c6
- 		case '8':
Karsten Hopp bec9c6
- 		case '9':
Karsten Hopp bec9c6
  		case '<':
Karsten Hopp bec9c6
  		case '>':
Karsten Hopp bec9c6
! 		    /* Not supported yet */
Karsten Hopp bec9c6
! 		    return FAIL;
Karsten Hopp bec9c6
! 		default:
Karsten Hopp bec9c6
! 		    syntax_error = TRUE;
Karsten Hopp bec9c6
! 		    EMSGN(_("E869: (NFA) Unknown operator '\\@%c'"), op);
Karsten Hopp bec9c6
  		    return FAIL;
Karsten Hopp bec9c6
  	    }
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	case Magic('?'):
Karsten Hopp bec9c6
--- 1370,1412 ----
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	case Magic('@'):
Karsten Hopp bec9c6
+ 	    c2 = getdecchrs();
Karsten Hopp bec9c6
  	    op = no_Magic(getchr());
Karsten Hopp bec9c6
+ 	    i = 0;
Karsten Hopp bec9c6
  	    switch(op)
Karsten Hopp bec9c6
  	    {
Karsten Hopp bec9c6
  		case '=':
Karsten Hopp bec9c6
! 		    /* \@= */
Karsten Hopp bec9c6
! 		    i = NFA_PREV_ATOM_NO_WIDTH;
Karsten Hopp bec9c6
  		    break;
Karsten Hopp bec9c6
  		case '!':
Karsten Hopp bec9c6
! 		    /* \@! */
Karsten Hopp bec9c6
! 		    i = NFA_PREV_ATOM_NO_WIDTH_NEG;
Karsten Hopp bec9c6
  		    break;
Karsten Hopp bec9c6
  		case '<':
Karsten Hopp bec9c6
+ 		    op = no_Magic(getchr());
Karsten Hopp bec9c6
+ 		    if (op == '=')
Karsten Hopp bec9c6
+ 			/* \@<= */
Karsten Hopp bec9c6
+ 			i = NFA_PREV_ATOM_JUST_BEFORE;
Karsten Hopp bec9c6
+ 		    else if (op == '!')
Karsten Hopp bec9c6
+ 			/* \@
Karsten Hopp bec9c6
+ 			i = NFA_PREV_ATOM_JUST_BEFORE_NEG;
Karsten Hopp bec9c6
+ 		    break;
Karsten Hopp bec9c6
  		case '>':
Karsten Hopp bec9c6
! 		    /* \@> Not supported yet */
Karsten Hopp bec9c6
! 		    /* i = NFA_PREV_ATOM_LIKE_PATTERN; */
Karsten Hopp bec9c6
  		    return FAIL;
Karsten Hopp bec9c6
  	    }
Karsten Hopp bec9c6
+ 	    if (i == 0)
Karsten Hopp bec9c6
+ 	    {
Karsten Hopp bec9c6
+ 		syntax_error = TRUE;
Karsten Hopp bec9c6
+ 		EMSGN(_("E869: (NFA) Unknown operator '\\@%c'"), op);
Karsten Hopp bec9c6
+ 		return FAIL;
Karsten Hopp bec9c6
+ 	    }
Karsten Hopp bec9c6
+ 	    EMIT(i);
Karsten Hopp bec9c6
+ 	    if (i == NFA_PREV_ATOM_JUST_BEFORE
Karsten Hopp bec9c6
+ 					|| i == NFA_PREV_ATOM_JUST_BEFORE_NEG)
Karsten Hopp bec9c6
+ 		EMIT(c2);
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	case Magic('?'):
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 1734,1742 ****
Karsten Hopp bec9c6
--- 1744,1758 ----
Karsten Hopp bec9c6
  			    STRCPY(code, "NFA_PREV_ATOM_NO_WIDTH"); break;
Karsten Hopp bec9c6
  	case NFA_PREV_ATOM_NO_WIDTH_NEG:
Karsten Hopp bec9c6
  			    STRCPY(code, "NFA_PREV_ATOM_NO_WIDTH_NEG"); break;
Karsten Hopp bec9c6
+ 	case NFA_PREV_ATOM_JUST_BEFORE:
Karsten Hopp bec9c6
+ 			    STRCPY(code, "NFA_PREV_ATOM_JUST_BEFORE"); break;
Karsten Hopp bec9c6
+ 	case NFA_PREV_ATOM_JUST_BEFORE_NEG:
Karsten Hopp bec9c6
+ 			 STRCPY(code, "NFA_PREV_ATOM_JUST_BEFORE_NEG"); break;
Karsten Hopp bec9c6
  	case NFA_NOPEN:		    STRCPY(code, "NFA_NOPEN"); break;
Karsten Hopp bec9c6
  	case NFA_NCLOSE:	    STRCPY(code, "NFA_NCLOSE"); break;
Karsten Hopp bec9c6
  	case NFA_START_INVISIBLE:   STRCPY(code, "NFA_START_INVISIBLE"); break;
Karsten Hopp bec9c6
+ 	case NFA_START_INVISIBLE_BEFORE:
Karsten Hopp bec9c6
+ 			    STRCPY(code, "NFA_START_INVISIBLE_BEFORE"); break;
Karsten Hopp bec9c6
  	case NFA_END_INVISIBLE:	    STRCPY(code, "NFA_END_INVISIBLE"); break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	case NFA_COMPOSING:	    STRCPY(code, "NFA_COMPOSING"); break;
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 2237,2243 ****
Karsten Hopp bec9c6
      if (nfa_calc_size == FALSE)
Karsten Hopp bec9c6
      {
Karsten Hopp bec9c6
  	/* Allocate space for the stack. Max states on the stack : nstate */
Karsten Hopp bec9c6
! 	stack = (Frag_T *) lalloc((nstate + 1) * sizeof(Frag_T), TRUE);
Karsten Hopp bec9c6
  	stackp = stack;
Karsten Hopp bec9c6
  	stack_end = stack + (nstate + 1);
Karsten Hopp bec9c6
      }
Karsten Hopp bec9c6
--- 2253,2259 ----
Karsten Hopp bec9c6
      if (nfa_calc_size == FALSE)
Karsten Hopp bec9c6
      {
Karsten Hopp bec9c6
  	/* Allocate space for the stack. Max states on the stack : nstate */
Karsten Hopp bec9c6
! 	stack = (Frag_T *)lalloc((nstate + 1) * sizeof(Frag_T), TRUE);
Karsten Hopp bec9c6
  	stackp = stack;
Karsten Hopp bec9c6
  	stack_end = stack + (nstate + 1);
Karsten Hopp bec9c6
      }
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 2370,2377 ****
Karsten Hopp bec9c6
--- 2386,2397 ----
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	case NFA_PREV_ATOM_NO_WIDTH:
Karsten Hopp bec9c6
  	case NFA_PREV_ATOM_NO_WIDTH_NEG:
Karsten Hopp bec9c6
+ 	case NFA_PREV_ATOM_JUST_BEFORE:
Karsten Hopp bec9c6
+ 	case NFA_PREV_ATOM_JUST_BEFORE_NEG:
Karsten Hopp bec9c6
  	    /* The \@= operator: match the preceding atom with zero width.
Karsten Hopp bec9c6
  	     * The \@! operator: no match for the preceding atom.
Karsten Hopp bec9c6
+ 	     * The \@<= operator: match for the preceding atom.
Karsten Hopp bec9c6
+ 	     * The \@
Karsten Hopp bec9c6
  	     * Surrounds the preceding atom with START_INVISIBLE and
Karsten Hopp bec9c6
  	     * END_INVISIBLE, similarly to MOPEN. */
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 2389,2399 ****
Karsten Hopp bec9c6
  	    s = new_state(NFA_START_INVISIBLE, e.start, s1);
Karsten Hopp bec9c6
  	    if (s == NULL)
Karsten Hopp bec9c6
  		goto theend;
Karsten Hopp bec9c6
! 	    if (*p == NFA_PREV_ATOM_NO_WIDTH_NEG)
Karsten Hopp bec9c6
  	    {
Karsten Hopp bec9c6
  		s->negated = TRUE;
Karsten Hopp bec9c6
  		s1->negated = TRUE;
Karsten Hopp bec9c6
  	    }
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	    PUSH(frag(s, list1(&s1->out)));
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
--- 2409,2426 ----
Karsten Hopp bec9c6
  	    s = new_state(NFA_START_INVISIBLE, e.start, s1);
Karsten Hopp bec9c6
  	    if (s == NULL)
Karsten Hopp bec9c6
  		goto theend;
Karsten Hopp bec9c6
! 	    if (*p == NFA_PREV_ATOM_NO_WIDTH_NEG
Karsten Hopp bec9c6
! 				       || *p == NFA_PREV_ATOM_JUST_BEFORE_NEG)
Karsten Hopp bec9c6
  	    {
Karsten Hopp bec9c6
  		s->negated = TRUE;
Karsten Hopp bec9c6
  		s1->negated = TRUE;
Karsten Hopp bec9c6
  	    }
Karsten Hopp bec9c6
+ 	    if (*p == NFA_PREV_ATOM_JUST_BEFORE
Karsten Hopp bec9c6
+ 				       || *p == NFA_PREV_ATOM_JUST_BEFORE_NEG)
Karsten Hopp bec9c6
+ 	    {
Karsten Hopp bec9c6
+ 		s->val = *++p; /* get the count */
Karsten Hopp bec9c6
+ 		++s->c; /* NFA_START_INVISIBLE -> NFA_START_INVISIBLE_BEFORE */
Karsten Hopp bec9c6
+ 	    }
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	    PUSH(frag(s, list1(&s1->out)));
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 3307,3327 ****
Karsten Hopp bec9c6
      return val == pos;
Karsten Hopp bec9c6
  }
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
! static int nfa_regmatch __ARGS((nfa_state_T *start, regsub_T *submatch, regsub_T *m));
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  /*
Karsten Hopp bec9c6
   * Main matching routine.
Karsten Hopp bec9c6
   *
Karsten Hopp bec9c6
   * Run NFA to determine whether it matches reginput.
Karsten Hopp bec9c6
   *
Karsten Hopp bec9c6
   * Return TRUE if there is a match, FALSE otherwise.
Karsten Hopp bec9c6
   * Note: Caller must ensure that: start != NULL.
Karsten Hopp bec9c6
   */
Karsten Hopp bec9c6
      static int
Karsten Hopp bec9c6
! nfa_regmatch(start, submatch, m)
Karsten Hopp bec9c6
      nfa_state_T		*start;
Karsten Hopp bec9c6
      regsub_T		*submatch;
Karsten Hopp bec9c6
      regsub_T		*m;
Karsten Hopp bec9c6
  {
Karsten Hopp bec9c6
      int		result;
Karsten Hopp bec9c6
      int		size = 0;
Karsten Hopp bec9c6
--- 3334,3357 ----
Karsten Hopp bec9c6
      return val == pos;
Karsten Hopp bec9c6
  }
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
! static int nfa_regmatch __ARGS((nfa_state_T *start, regsub_T *submatch, regsub_T *m, save_se_T *endp));
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  /*
Karsten Hopp bec9c6
   * Main matching routine.
Karsten Hopp bec9c6
   *
Karsten Hopp bec9c6
   * Run NFA to determine whether it matches reginput.
Karsten Hopp bec9c6
   *
Karsten Hopp bec9c6
+  * When "endp" is not NULL it is a required end-of-match position.
Karsten Hopp bec9c6
+  *
Karsten Hopp bec9c6
   * Return TRUE if there is a match, FALSE otherwise.
Karsten Hopp bec9c6
   * Note: Caller must ensure that: start != NULL.
Karsten Hopp bec9c6
   */
Karsten Hopp bec9c6
      static int
Karsten Hopp bec9c6
! nfa_regmatch(start, submatch, m, endp)
Karsten Hopp bec9c6
      nfa_state_T		*start;
Karsten Hopp bec9c6
      regsub_T		*submatch;
Karsten Hopp bec9c6
      regsub_T		*m;
Karsten Hopp bec9c6
+     save_se_T		*endp;
Karsten Hopp bec9c6
  {
Karsten Hopp bec9c6
      int		result;
Karsten Hopp bec9c6
      int		size = 0;
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 3532,3547 ****
Karsten Hopp bec9c6
  	      }
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	    case NFA_END_INVISIBLE:
Karsten Hopp bec9c6
! 		/* This is only encountered after a NFA_START_INVISIBLE node.
Karsten Hopp bec9c6
! 		 * They surround a zero-width group, used with "\@=" and "\&".
Karsten Hopp bec9c6
  		 * If we got here, it means that the current "invisible" group
Karsten Hopp bec9c6
  		 * finished successfully, so return control to the parent
Karsten Hopp bec9c6
  		 * nfa_regmatch().  Submatches are stored in *m, and used in
Karsten Hopp bec9c6
  		 * the parent call. */
Karsten Hopp bec9c6
  		if (start->c == NFA_MOPEN + 0)
Karsten Hopp bec9c6
  		    addstate_here(thislist, t->state->out, &t->sub, &listidx);
Karsten Hopp bec9c6
  		else
Karsten Hopp bec9c6
  		{
Karsten Hopp bec9c6
  		    /* do not set submatches for \@! */
Karsten Hopp bec9c6
  		    if (!t->state->negated)
Karsten Hopp bec9c6
  			/* TODO: only copy positions in use. */
Karsten Hopp bec9c6
--- 3562,3603 ----
Karsten Hopp bec9c6
  	      }
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	    case NFA_END_INVISIBLE:
Karsten Hopp bec9c6
! 		/* This is only encountered after a NFA_START_INVISIBLE or
Karsten Hopp bec9c6
! 		 * NFA_START_INVISIBLE_BEFORE node.
Karsten Hopp bec9c6
! 		 * They surround a zero-width group, used with "\@=", "\&",
Karsten Hopp bec9c6
! 		 * "\@!", "\@<=" and "\@
Karsten Hopp bec9c6
  		 * If we got here, it means that the current "invisible" group
Karsten Hopp bec9c6
  		 * finished successfully, so return control to the parent
Karsten Hopp bec9c6
  		 * nfa_regmatch().  Submatches are stored in *m, and used in
Karsten Hopp bec9c6
  		 * the parent call. */
Karsten Hopp bec9c6
  		if (start->c == NFA_MOPEN + 0)
Karsten Hopp bec9c6
+ 		    /* TODO: do we ever get here? */
Karsten Hopp bec9c6
  		    addstate_here(thislist, t->state->out, &t->sub, &listidx);
Karsten Hopp bec9c6
  		else
Karsten Hopp bec9c6
  		{
Karsten Hopp bec9c6
+ #ifdef ENABLE_LOG
Karsten Hopp bec9c6
+ 		    if (endp != NULL)
Karsten Hopp bec9c6
+ 		    {
Karsten Hopp bec9c6
+ 			if (REG_MULTI)
Karsten Hopp bec9c6
+ 			    fprintf(log_fd, "Current lnum: %d, endp lnum: %d; current col: %d, endp col: %d\n",
Karsten Hopp bec9c6
+ 				    (int)reglnum,
Karsten Hopp bec9c6
+ 				    (int)endp->se_u.pos.lnum,
Karsten Hopp bec9c6
+ 				    (int)(reginput - regline),
Karsten Hopp bec9c6
+ 				    endp->se_u.pos.col);
Karsten Hopp bec9c6
+ 			else
Karsten Hopp bec9c6
+ 			    fprintf(log_fd, "Current col: %d, endp col: %d\n",
Karsten Hopp bec9c6
+ 				    (int)(reginput - regline),
Karsten Hopp bec9c6
+ 				    (int)(endp->se_u.ptr - reginput));
Karsten Hopp bec9c6
+ 		    }
Karsten Hopp bec9c6
+ #endif
Karsten Hopp bec9c6
+ 		    /* It's only a match if it ends at "endp" */
Karsten Hopp bec9c6
+ 		    if (endp != NULL && (REG_MULTI
Karsten Hopp bec9c6
+ 			    ? (reglnum != endp->se_u.pos.lnum
Karsten Hopp bec9c6
+ 				|| (int)(reginput - regline)
Karsten Hopp bec9c6
+ 							!= endp->se_u.pos.col)
Karsten Hopp bec9c6
+ 			    : reginput != endp->se_u.ptr))
Karsten Hopp bec9c6
+ 			break;
Karsten Hopp bec9c6
+ 
Karsten Hopp bec9c6
  		    /* do not set submatches for \@! */
Karsten Hopp bec9c6
  		    if (!t->state->negated)
Karsten Hopp bec9c6
  			/* TODO: only copy positions in use. */
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 3551,3561 ****
Karsten Hopp bec9c6
  		break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	    case NFA_START_INVISIBLE:
Karsten Hopp bec9c6
  	      {
Karsten Hopp bec9c6
! 		char_u	*save_reginput = reginput;
Karsten Hopp bec9c6
! 		char_u	*save_regline = regline;
Karsten Hopp bec9c6
! 		int	save_reglnum = reglnum;
Karsten Hopp bec9c6
! 		int	save_nfa_match = nfa_match;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  		/* Call nfa_regmatch() to check if the current concat matches
Karsten Hopp bec9c6
  		 * at this position. The concat ends with the node
Karsten Hopp bec9c6
--- 3607,3676 ----
Karsten Hopp bec9c6
  		break;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  	    case NFA_START_INVISIBLE:
Karsten Hopp bec9c6
+ 	    case NFA_START_INVISIBLE_BEFORE:
Karsten Hopp bec9c6
  	      {
Karsten Hopp bec9c6
! 		char_u	    *save_reginput = reginput;
Karsten Hopp bec9c6
! 		char_u	    *save_regline = regline;
Karsten Hopp bec9c6
! 		int	    save_reglnum = reglnum;
Karsten Hopp bec9c6
! 		int	    save_nfa_match = nfa_match;
Karsten Hopp bec9c6
! 		save_se_T   endpos;
Karsten Hopp bec9c6
! 		save_se_T   *endposp = NULL;
Karsten Hopp bec9c6
! 
Karsten Hopp bec9c6
! 		if (t->state->c == NFA_START_INVISIBLE_BEFORE)
Karsten Hopp bec9c6
! 		{
Karsten Hopp bec9c6
! 		    /* The recursive match must end at the current position. */
Karsten Hopp bec9c6
! 		    endposp = &endpos;
Karsten Hopp bec9c6
! 		    if (REG_MULTI)
Karsten Hopp bec9c6
! 		    {
Karsten Hopp bec9c6
! 			endpos.se_u.pos.col = (int)(reginput - regline);
Karsten Hopp bec9c6
! 			endpos.se_u.pos.lnum = reglnum;
Karsten Hopp bec9c6
! 		    }
Karsten Hopp bec9c6
! 		    else
Karsten Hopp bec9c6
! 			endpos.se_u.ptr = reginput;
Karsten Hopp bec9c6
! 
Karsten Hopp bec9c6
! 		    /* Go back the specified number of bytes, or as far as the
Karsten Hopp bec9c6
! 		     * start of the previous line, to try matching "\@<=" or
Karsten Hopp bec9c6
! 		     * not matching "\@
Karsten Hopp bec9c6
! 		    if (t->state->val <= 0)
Karsten Hopp bec9c6
! 		    {
Karsten Hopp bec9c6
! 			if (REG_MULTI)
Karsten Hopp bec9c6
! 			{
Karsten Hopp bec9c6
! 			    regline = reg_getline(--reglnum);
Karsten Hopp bec9c6
! 			    if (regline == NULL)
Karsten Hopp bec9c6
! 				/* can't go before the first line */
Karsten Hopp bec9c6
! 				regline = reg_getline(++reglnum);
Karsten Hopp bec9c6
! 			}
Karsten Hopp bec9c6
! 			reginput = regline;
Karsten Hopp bec9c6
! 		    }
Karsten Hopp bec9c6
! 		    else
Karsten Hopp bec9c6
! 		    {
Karsten Hopp bec9c6
! 			if (REG_MULTI
Karsten Hopp bec9c6
! 				&& (int)(reginput - regline) < t->state->val)
Karsten Hopp bec9c6
! 			{
Karsten Hopp bec9c6
! 			    /* Not enough bytes in this line, go to end of
Karsten Hopp bec9c6
! 			     * previous line. */
Karsten Hopp bec9c6
! 			    regline = reg_getline(--reglnum);
Karsten Hopp bec9c6
! 			    if (regline == NULL)
Karsten Hopp bec9c6
! 			    {
Karsten Hopp bec9c6
! 				/* can't go before the first line */
Karsten Hopp bec9c6
! 				regline = reg_getline(++reglnum);
Karsten Hopp bec9c6
! 				reginput = regline;
Karsten Hopp bec9c6
! 			    }
Karsten Hopp bec9c6
! 			    else
Karsten Hopp bec9c6
! 				reginput = regline + STRLEN(regline);
Karsten Hopp bec9c6
! 			}
Karsten Hopp bec9c6
! 			if ((int)(reginput - regline) >= t->state->val)
Karsten Hopp bec9c6
! 			{
Karsten Hopp bec9c6
! 			    reginput -= t->state->val;
Karsten Hopp bec9c6
! #ifdef FEAT_MBYTE
Karsten Hopp bec9c6
! 			    if (has_mbyte)
Karsten Hopp bec9c6
! 				reginput -= mb_head_off(regline, reginput);
Karsten Hopp bec9c6
! #endif
Karsten Hopp bec9c6
! 			}
Karsten Hopp bec9c6
! 			else
Karsten Hopp bec9c6
! 			    reginput = regline;
Karsten Hopp bec9c6
! 		    }
Karsten Hopp bec9c6
! 		}
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  		/* Call nfa_regmatch() to check if the current concat matches
Karsten Hopp bec9c6
  		 * at this position. The concat ends with the node
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 3579,3585 ****
Karsten Hopp bec9c6
  		 * recursion. */
Karsten Hopp bec9c6
  		nfa_save_listids(start, listids);
Karsten Hopp bec9c6
  		nfa_set_null_listids(start);
Karsten Hopp bec9c6
! 		result = nfa_regmatch(t->state->out, submatch, m);
Karsten Hopp bec9c6
  		nfa_set_neg_listids(start);
Karsten Hopp bec9c6
  		nfa_restore_listids(start, listids);
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
--- 3694,3700 ----
Karsten Hopp bec9c6
  		 * recursion. */
Karsten Hopp bec9c6
  		nfa_save_listids(start, listids);
Karsten Hopp bec9c6
  		nfa_set_null_listids(start);
Karsten Hopp bec9c6
! 		result = nfa_regmatch(t->state->out, submatch, m, endposp);
Karsten Hopp bec9c6
  		nfa_set_neg_listids(start);
Karsten Hopp bec9c6
  		nfa_restore_listids(start, listids);
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 4120,4130 ****
Karsten Hopp bec9c6
  	 * matters!
Karsten Hopp bec9c6
  	 * Do not add the start state in recursive calls of nfa_regmatch(),
Karsten Hopp bec9c6
  	 * because recursive calls should only start in the first position.
Karsten Hopp bec9c6
  	 * Also don't start a match past the first line. */
Karsten Hopp bec9c6
! 	if (nfa_match == FALSE && start->c == NFA_MOPEN + 0
Karsten Hopp bec9c6
! 		&& reglnum == 0 && clen != 0
Karsten Hopp bec9c6
! 		&& (ireg_maxcol == 0
Karsten Hopp bec9c6
! 			      || (colnr_T)(reginput - regline) < ireg_maxcol))
Karsten Hopp bec9c6
  	{
Karsten Hopp bec9c6
  #ifdef ENABLE_LOG
Karsten Hopp bec9c6
  	    fprintf(log_fd, "(---) STARTSTATE\n");
Karsten Hopp bec9c6
--- 4235,4255 ----
Karsten Hopp bec9c6
  	 * matters!
Karsten Hopp bec9c6
  	 * Do not add the start state in recursive calls of nfa_regmatch(),
Karsten Hopp bec9c6
  	 * because recursive calls should only start in the first position.
Karsten Hopp bec9c6
+ 	 * Unless "endp" is not NULL, then we match the end position.
Karsten Hopp bec9c6
  	 * Also don't start a match past the first line. */
Karsten Hopp bec9c6
! 	if (nfa_match == FALSE
Karsten Hopp bec9c6
! 		&& ((start->c == NFA_MOPEN + 0
Karsten Hopp bec9c6
! 			&& reglnum == 0
Karsten Hopp bec9c6
! 			&& clen != 0
Karsten Hopp bec9c6
! 			&& (ireg_maxcol == 0
Karsten Hopp bec9c6
! 			    || (colnr_T)(reginput - regline) < ireg_maxcol))
Karsten Hopp bec9c6
! 		    || (endp != NULL
Karsten Hopp bec9c6
! 			&& (REG_MULTI
Karsten Hopp bec9c6
! 			    ? (reglnum < endp->se_u.pos.lnum
Karsten Hopp bec9c6
! 			       || (reglnum == endp->se_u.pos.lnum
Karsten Hopp bec9c6
! 			           && (int)(reginput - regline)
Karsten Hopp bec9c6
! 						       < endp->se_u.pos.col))
Karsten Hopp bec9c6
! 			    : reginput < endp->se_u.ptr))))
Karsten Hopp bec9c6
  	{
Karsten Hopp bec9c6
  #ifdef ENABLE_LOG
Karsten Hopp bec9c6
  	    fprintf(log_fd, "(---) STARTSTATE\n");
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 4148,4154 ****
Karsten Hopp bec9c6
  	 * finish. */
Karsten Hopp bec9c6
  	if (clen != 0)
Karsten Hopp bec9c6
  	    reginput += clen;
Karsten Hopp bec9c6
! 	else if (go_to_nextline)
Karsten Hopp bec9c6
  	    reg_nextline();
Karsten Hopp bec9c6
  	else
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
--- 4273,4280 ----
Karsten Hopp bec9c6
  	 * finish. */
Karsten Hopp bec9c6
  	if (clen != 0)
Karsten Hopp bec9c6
  	    reginput += clen;
Karsten Hopp bec9c6
! 	else if (go_to_nextline || (endp != NULL && REG_MULTI
Karsten Hopp bec9c6
! 					    && reglnum < endp->se_u.pos.lnum))
Karsten Hopp bec9c6
  	    reg_nextline();
Karsten Hopp bec9c6
  	else
Karsten Hopp bec9c6
  	    break;
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 4225,4231 ****
Karsten Hopp bec9c6
      sub.in_use = 0;
Karsten Hopp bec9c6
      m.in_use = 0;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
!     if (nfa_regmatch(start, &sub, &m) == FALSE)
Karsten Hopp bec9c6
  	return 0;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
      cleanup_subexpr();
Karsten Hopp bec9c6
--- 4351,4357 ----
Karsten Hopp bec9c6
      sub.in_use = 0;
Karsten Hopp bec9c6
      m.in_use = 0;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
!     if (nfa_regmatch(start, &sub, &m, NULL) == FALSE)
Karsten Hopp bec9c6
  	return 0;
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
      cleanup_subexpr();
Karsten Hopp bec9c6
*** ../vim-7.3.1087/src/testdir/test64.in	2013-06-01 14:42:51.000000000 +0200
Karsten Hopp bec9c6
--- src/testdir/test64.in	2013-06-01 18:45:09.000000000 +0200
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 363,374 ****
Karsten Hopp bec9c6
  :call add(tl, [2, '\(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9', 'xabcddefghiabcddefghix', 'abcddefghiabcddefghi', 'a', 'b', 'c', 'dd', 'e', 'f', 'g', 'h', 'i'])
Karsten Hopp bec9c6
  :"
Karsten Hopp bec9c6
  :"""" Look-behind with limit
Karsten Hopp bec9c6
! :call add(tl, [0, '<\@<=span.', 'xxspanxx
Karsten Hopp bec9c6
! :call add(tl, [0, '<\@1<=span.', 'xxspanxx
Karsten Hopp bec9c6
! :call add(tl, [0, '<\@2<=span.', 'xxspanxx
Karsten Hopp bec9c6
! :call add(tl, [0, '\(<<\)\@<=span.', 'xxspanxxxx
Karsten Hopp bec9c6
! :call add(tl, [0, '\(<<\)\@1<=span.', 'xxspanxxxx
Karsten Hopp bec9c6
! :call add(tl, [0, '\(<<\)\@2<=span.', 'xxspanxxxx
Karsten Hopp bec9c6
  :"
Karsten Hopp bec9c6
  :"""" "\_" prepended negated collection matches EOL
Karsten Hopp bec9c6
  :call add(tl, [2, '\_[^8-9]\+', "asfi\n9888", "asfi\n"])
Karsten Hopp bec9c6
--- 363,375 ----
Karsten Hopp bec9c6
  :call add(tl, [2, '\(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9', 'xabcddefghiabcddefghix', 'abcddefghiabcddefghi', 'a', 'b', 'c', 'dd', 'e', 'f', 'g', 'h', 'i'])
Karsten Hopp bec9c6
  :"
Karsten Hopp bec9c6
  :"""" Look-behind with limit
Karsten Hopp bec9c6
! :call add(tl, [2, '<\@<=span.', 'xxspanxx
Karsten Hopp bec9c6
! :call add(tl, [2, '<\@1<=span.', 'xxspanxx
Karsten Hopp bec9c6
! :call add(tl, [2, '<\@2<=span.', 'xxspanxx
Karsten Hopp bec9c6
! :call add(tl, [2, '\(<<\)\@<=span.', 'xxspanxxxx
Karsten Hopp bec9c6
! :call add(tl, [2, '\(<<\)\@1<=span.', 'xxspanxxxx
Karsten Hopp bec9c6
! :call add(tl, [2, '\(<<\)\@2<=span.', 'xxspanxxxx
Karsten Hopp bec9c6
! :call add(tl, [2, '\(foo\)\@
Karsten Hopp bec9c6
  :"
Karsten Hopp bec9c6
  :"""" "\_" prepended negated collection matches EOL
Karsten Hopp bec9c6
  :call add(tl, [2, '\_[^8-9]\+', "asfi\n9888", "asfi\n"])
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 514,521 ****
Karsten Hopp bec9c6
  asdfasd
Karsten Hopp bec9c6
  xxstart1
Karsten Hopp bec9c6
  asdfasd
Karsten Hopp bec9c6
! xxxxstart2
Karsten Hopp bec9c6
  asdfasd
Karsten Hopp bec9c6
! xxxstart3
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  Results of test64:
Karsten Hopp bec9c6
--- 515,522 ----
Karsten Hopp bec9c6
  asdfasd
Karsten Hopp bec9c6
  xxstart1
Karsten Hopp bec9c6
  asdfasd
Karsten Hopp bec9c6
! xxxstart2
Karsten Hopp bec9c6
  asdfasd
Karsten Hopp bec9c6
! xxstart3
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
  Results of test64:
Karsten Hopp bec9c6
*** ../vim-7.3.1087/src/testdir/test64.ok	2013-06-01 14:42:51.000000000 +0200
Karsten Hopp bec9c6
--- src/testdir/test64.ok	2013-06-01 18:55:43.000000000 +0200
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 817,832 ****
Karsten Hopp bec9c6
--- 817,841 ----
Karsten Hopp bec9c6
  OK 2 - \(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9
Karsten Hopp bec9c6
  OK 0 - <\@<=span.
Karsten Hopp bec9c6
  OK 1 - <\@<=span.
Karsten Hopp bec9c6
+ OK 2 - <\@<=span.
Karsten Hopp bec9c6
  OK 0 - <\@1<=span.
Karsten Hopp bec9c6
  OK 1 - <\@1<=span.
Karsten Hopp bec9c6
+ OK 2 - <\@1<=span.
Karsten Hopp bec9c6
  OK 0 - <\@2<=span.
Karsten Hopp bec9c6
  OK 1 - <\@2<=span.
Karsten Hopp bec9c6
+ OK 2 - <\@2<=span.
Karsten Hopp bec9c6
  OK 0 - \(<<\)\@<=span.
Karsten Hopp bec9c6
  OK 1 - \(<<\)\@<=span.
Karsten Hopp bec9c6
+ OK 2 - \(<<\)\@<=span.
Karsten Hopp bec9c6
  OK 0 - \(<<\)\@1<=span.
Karsten Hopp bec9c6
  OK 1 - \(<<\)\@1<=span.
Karsten Hopp bec9c6
+ OK 2 - \(<<\)\@1<=span.
Karsten Hopp bec9c6
  OK 0 - \(<<\)\@2<=span.
Karsten Hopp bec9c6
  OK 1 - \(<<\)\@2<=span.
Karsten Hopp bec9c6
+ OK 2 - \(<<\)\@2<=span.
Karsten Hopp bec9c6
+ OK 0 - \(foo\)\@
Karsten Hopp bec9c6
+ OK 1 - \(foo\)\@
Karsten Hopp bec9c6
+ OK 2 - \(foo\)\@
Karsten Hopp bec9c6
  OK 0 - \_[^8-9]\+
Karsten Hopp bec9c6
  OK 1 - \_[^8-9]\+
Karsten Hopp bec9c6
  OK 2 - \_[^8-9]\+
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 844,850 ****
Karsten Hopp bec9c6
  <T="7">Ac 7</Title>
Karsten Hopp bec9c6
  ghi
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
! xxxstart3
Karsten Hopp bec9c6
  -0-
Karsten Hopp bec9c6
  ffo
Karsten Hopp bec9c6
  bob
Karsten Hopp bec9c6
--- 853,859 ----
Karsten Hopp bec9c6
  <T="7">Ac 7</Title>
Karsten Hopp bec9c6
  ghi
Karsten Hopp bec9c6
  
Karsten Hopp bec9c6
! xxstart3
Karsten Hopp bec9c6
  -0-
Karsten Hopp bec9c6
  ffo
Karsten Hopp bec9c6
  bob
Karsten Hopp bec9c6
*** ../vim-7.3.1087/src/version.c	2013-06-01 14:42:51.000000000 +0200
Karsten Hopp bec9c6
--- src/version.c	2013-06-01 18:37:11.000000000 +0200
Karsten Hopp bec9c6
***************
Karsten Hopp bec9c6
*** 730,731 ****
Karsten Hopp bec9c6
--- 730,733 ----
Karsten Hopp bec9c6
  {   /* Add new patch number below this line */
Karsten Hopp bec9c6
+ /**/
Karsten Hopp bec9c6
+     1088,
Karsten Hopp bec9c6
  /**/
Karsten Hopp bec9c6
Karsten Hopp bec9c6
-- 
Karsten Hopp bec9c6
Seen it all, done it all, can't remember most of it.
Karsten Hopp bec9c6
Karsten Hopp bec9c6
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
Karsten Hopp bec9c6
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
Karsten Hopp bec9c6
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
Karsten Hopp bec9c6
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///