aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/regexp_nfa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/regexp_nfa.c')
-rw-r--r--src/nvim/regexp_nfa.c80
1 files changed, 62 insertions, 18 deletions
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 95030974d8..b935b44291 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1338,8 +1338,15 @@ static int nfa_regatom(void)
case Magic('7'):
case Magic('8'):
case Magic('9'):
- EMIT(NFA_BACKREF1 + (no_Magic(c) - '1'));
- nfa_has_backref = TRUE;
+ {
+ int refnum = no_Magic(c) - '1';
+
+ if (!seen_endbrace(refnum + 1)) {
+ return FAIL;
+ }
+ EMIT(NFA_BACKREF1 + refnum);
+ nfa_has_backref = true;
+ }
break;
case Magic('z'):
@@ -3568,6 +3575,7 @@ static char *pim_info(nfa_pim_T *pim)
// Used during execution: whether a match has been found.
static int nfa_match;
static proftime_T *nfa_time_limit;
+static int *nfa_timed_out;
static int nfa_time_count;
// Copy postponed invisible match info from "from" to "to".
@@ -4574,7 +4582,9 @@ static bool nfa_re_num_cmp(uintmax_t val, int op, uintmax_t pos)
* "pim" is NULL or contains info about a Postponed Invisible Match (start
* position).
*/
-static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T *prog, regsubs_T *submatch, regsubs_T *m, int **listids)
+static int recursive_regmatch(
+ nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T *prog,
+ regsubs_T *submatch, regsubs_T *m, int **listids, int *listids_len)
{
int save_reginput_col = (int)(reginput - regline);
int save_reglnum = reglnum;
@@ -4657,8 +4667,10 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T
if (nfa_ll_index == 1) {
/* Already calling nfa_regmatch() recursively. Save the lastlist[1]
* values and clear them. */
- if (*listids == NULL) {
+ if (*listids == NULL || *listids_len < nstate) {
+ xfree(*listids);
*listids = xmalloc(sizeof(**listids) * nstate);
+ *listids_len = nstate;
}
nfa_save_listids(prog, *listids);
need_restore = TRUE;
@@ -4939,6 +4951,17 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
#undef PTR2LEN
}
+static int nfa_did_time_out(void)
+{
+ if (nfa_time_limit != NULL && profile_passed_limit(*nfa_time_limit)) {
+ if (nfa_timed_out != NULL) {
+ *nfa_timed_out = true;
+ }
+ return true;
+ }
+ return false;
+}
+
/// Main matching routine.
///
/// Run NFA to determine whether it matches reginput.
@@ -4960,6 +4983,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
nfa_list_T *thislist;
nfa_list_T *nextlist;
int *listids = NULL;
+ int listids_len = 0;
nfa_state_T *add_state;
bool add_here;
int add_count;
@@ -4982,7 +5006,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
#endif
return false;
}
- if (nfa_time_limit != NULL && profile_passed_limit(*nfa_time_limit)) {
+ if (nfa_did_time_out()) {
#ifdef NFA_REGEXP_DEBUG_LOG
fclose(debug);
#endif
@@ -5095,8 +5119,20 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
if (thislist->n == 0)
break;
- /* compute nextlist */
- for (listidx = 0; listidx < thislist->n; ++listidx) {
+ // compute nextlist
+ for (listidx = 0; listidx < thislist->n; listidx++) {
+ // If the list gets very long there probably is something wrong.
+ // At least allow interrupting with CTRL-C.
+ fast_breakcheck();
+ if (got_int) {
+ break;
+ }
+ if (nfa_time_limit != NULL && ++nfa_time_count == 20) {
+ nfa_time_count = 0;
+ if (nfa_did_time_out()) {
+ break;
+ }
+ }
t = &thislist->t[listidx];
#ifdef NFA_REGEXP_DEBUG_LOG
@@ -5240,7 +5276,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
// First try matching the invisible match, then what
// follows.
result = recursive_regmatch(t->state, NULL, prog, submatch, m,
- &listids);
+ &listids, &listids_len);
if (result == NFA_TOO_EXPENSIVE) {
nfa_match = result;
goto theend;
@@ -5341,7 +5377,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
// First try matching the pattern.
result = recursive_regmatch(t->state, NULL, prog, submatch, m,
- &listids);
+ &listids, &listids_len);
if (result == NFA_TOO_EXPENSIVE) {
nfa_match = result;
goto theend;
@@ -6048,8 +6084,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
fprintf(log_fd, "Postponed recursive nfa_regmatch()\n");
fprintf(log_fd, "\n");
#endif
- result = recursive_regmatch(pim->state, pim,
- prog, submatch, m, &listids);
+ result = recursive_regmatch(pim->state, pim, prog, submatch, m,
+ &listids, &listids_len);
pim->result = result ? NFA_PIM_MATCH : NFA_PIM_NOMATCH;
// for \@! and \@<! it is a match when the result is
// FALSE
@@ -6218,7 +6254,7 @@ nextchar:
// Check for timeout once every twenty times to avoid overhead.
if (nfa_time_limit != NULL && ++nfa_time_count == 20) {
nfa_time_count = 0;
- if (profile_passed_limit(*nfa_time_limit)) {
+ if (nfa_did_time_out()) {
break;
}
}
@@ -6245,7 +6281,10 @@ theend:
// Try match of "prog" with at regline["col"].
// Returns <= 0 for failure, number of lines contained in the match otherwise.
-static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
+static long nfa_regtry(nfa_regprog_T *prog,
+ colnr_T col,
+ proftime_T *tm, // timeout limit or NULL
+ int *timed_out) // flag set on timeout or NULL
{
int i;
regsubs_T subs, m;
@@ -6256,6 +6295,7 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
reginput = regline + col;
nfa_time_limit = tm;
+ nfa_timed_out = timed_out;
nfa_time_count = 0;
#ifdef REGEXP_DEBUG
@@ -6364,10 +6404,12 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
/// @param line String in which to search or NULL
/// @param startcol Column to start looking for match
/// @param tm Timeout limit or NULL
+/// @param timed_out Flag set on timeout or NULL
///
/// @return <= 0 if there is no match and number of lines contained in the
/// match otherwise.
-static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
+static long nfa_regexec_both(char_u *line, colnr_T startcol,
+ proftime_T *tm, int *timed_out)
{
nfa_regprog_T *prog;
long retval = 0L;
@@ -6449,7 +6491,7 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
prog->state[i].lastlist[1] = 0;
}
- retval = nfa_regtry(prog, col, tm);
+ retval = nfa_regtry(prog, col, tm, timed_out);
nfa_regengine.expr = NULL;
@@ -6596,7 +6638,7 @@ nfa_regexec_nl (
rex.reg_ic = rmp->rm_ic;
rex.reg_icombine = false;
rex.reg_maxcol = 0;
- return nfa_regexec_both(line, col, NULL);
+ return nfa_regexec_both(line, col, NULL, NULL);
}
/// Matches a regexp against multiple lines.
@@ -6608,6 +6650,7 @@ nfa_regexec_nl (
/// @param lnum Number of line to start looking for match
/// @param col Column to start looking for match
/// @param tm Timeout limit or NULL
+/// @param timed_out Flag set on timeout or NULL
///
/// @return <= 0 if there is no match and number of lines contained in the match
/// otherwise.
@@ -6634,7 +6677,8 @@ nfa_regexec_nl (
/// @par
/// FIXME if this behavior is not compatible.
static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
- linenr_T lnum, colnr_T col, proftime_T *tm)
+ linenr_T lnum, colnr_T col,
+ proftime_T *tm, int *timed_out)
{
rex.reg_match = NULL;
rex.reg_mmatch = rmp;
@@ -6647,5 +6691,5 @@ static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
rex.reg_icombine = false;
rex.reg_maxcol = rmp->rmm_maxcol;
- return nfa_regexec_both(NULL, col, tm);
+ return nfa_regexec_both(NULL, col, tm, timed_out);
}