diff options
| author | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-06-29 19:14:03 +0200 |
|---|---|---|
| committer | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-06-29 19:14:03 +0200 |
| commit | d71d7527a8be8654560867d761036598408bfe14 (patch) | |
| tree | 57a3f056e8b1039b172a618aec264e8c172d4925 | |
| parent | 7c103ba4914cb47cb1e6c51cc9b8121aa5e6ef62 (diff) | |
| download | terex-d71d7527a8be8654560867d761036598408bfe14.tar.gz | |
implemented tere_set_is_interrupted_cb()
Allows you to set up a callback that's invoked repeatedly during
matching. If it returns non-0 matching will abort and REG_EINTR is
returned.
Allows you to interrupt long-running regexp executions that would
otherwise block the UI or hang the entire application.
| -rw-r--r-- | README.md | 8 | ||||
| -rw-r--r-- | regcomp.c | 11 | ||||
| -rw-r--r-- | rege_dfa.c | 12 | ||||
| -rw-r--r-- | regerrs.h | 1 | ||||
| -rw-r--r-- | regex.h | 2 | ||||
| -rw-r--r-- | regexec.c | 5 | ||||
| -rw-r--r-- | regguts.h | 5 |
7 files changed, 39 insertions, 5 deletions
@@ -23,14 +23,12 @@ Compared to hsrex, this library has the following changes: `tere_comp()` compilation flag. * Support the `REG_ANCHORED` flag for `tere_exec()`. * `tere_free()` ignores nullified `regex_t` objects. +* `tere_set_is_interrupted_cb()` allows configuring a repeatedly + invoked callback. If it returns true (non-null) matching aborts + immediately and `tere_exec()` will return `REG_EINTR`. ## TODO -* Hook into the matching algorithm. - Even though runtime cannot be as catastrophically bad as in pure - backtracking engines like PCRE, `tere_exec()` calls can still be slow - on extremely large texts. - The hook allows interruptions. * Expose enough API to swap out the regular expression lexer. Useful for custom DSLs like glob patterns or TECO patterns. * Support splitting the subject string into two halves, so we can @@ -273,6 +273,17 @@ static struct fns functions = { }; /* + - tere_set_is_interrupted_cb - set is_interrupted callback + ^ void tere_set_is_interrupted_cb(regex_t *, int (*cb)(void)); + */ +void +tere_set_is_interrupted_cb( + regex_t *re, int (*cb)(void)) +{ + ((struct fns *)re->re_fns)->is_interrupted = cb; +} + +/* - compile - compile regular expression ^ int compile(regex_t *, const chr *, size_t, int); */ @@ -101,6 +101,9 @@ longest( if (ss->flags & NOPROGRESS && v->eflags & REG_ANCHORED) { return NULL; } + if (IS_INTERRUPTED(v->re)) { + return NULL; + } cp = nextchr(v, cp); ss->lastseen = cp; css = ss; @@ -119,6 +122,9 @@ longest( if (ss->flags & NOPROGRESS && v->eflags & REG_ANCHORED) { return NULL; } + if (IS_INTERRUPTED(v->re)) { + return NULL; + } cp = nextchr(v, cp); ss->lastseen = cp; css = ss; @@ -240,6 +246,9 @@ shortest( if (ss->flags & NOPROGRESS && v->eflags & REG_ANCHORED) { return NULL; } + if (IS_INTERRUPTED(v->re)) { + return NULL; + } cp = nextchr(v, cp); ss->lastseen = cp; css = ss; @@ -261,6 +270,9 @@ shortest( if (ss->flags & NOPROGRESS && v->eflags & REG_ANCHORED) { return NULL; } + if (IS_INTERRUPTED(v->re)) { + return NULL; + } cp = nextchr(v, cp); ss->lastseen = cp; css = ss; @@ -17,3 +17,4 @@ { REG_MIXED, "REG_MIXED", "character widths of regex and string differ" }, { REG_BADOPT, "REG_BADOPT", "invalid embedded option" }, { REG_ETOOBIG, "REG_ETOOBIG", "nfa has too many states" }, +{ REG_EINTR, "REG_EINTR", "interrupted" }, @@ -290,6 +290,7 @@ typedef struct { #define REG_MIXED 17 /* character widths of regex and string differ */ #define REG_BADOPT 18 /* invalid embedded option */ #define REG_ETOOBIG 19 /* nfa has too many states */ +#define REG_EINTR 20 /* interrupted by is_interrupted() callback */ /* two specials for debugging and testing */ #define REG_ATOI 101 /* convert error-code name to number */ #define REG_ITOA 102 /* convert error-code number to name */ @@ -320,6 +321,7 @@ MODULE_SCOPE int __REG_WIDE_EXEC(regex_t *, __REG_CONST __REG_WIDE_T *, size_t, #endif MODULE_SCOPE re_void regfree(regex_t *); MODULE_SCOPE size_t regerror(int, __REG_CONST regex_t *, char *, size_t); +MODULE_SCOPE void tere_set_is_interrupted_cb(regex_t *, int (*cb)(void)); /* automatically gathered by fwd; do not hand-edit */ /* =====^!^===== end forwards =====^!^===== */ @@ -328,6 +328,11 @@ exec( memcpy(VS(pmatch), VS(v->pmatch), n*sizeof(regmatch_t)); } + if (IS_INTERRUPTED(re)) { + /* normalize return code in case of interruptions */ + st = REG_EINTR; + } + /* * Clean up. */ @@ -385,8 +385,13 @@ struct subre { struct fns { VOID FUNCPTR(free, (regex_t *)); + int FUNCPTR(is_interrupted, (void)); }; +#define IS_INTERRUPTED(re) \ + (((struct fns *)(re)->re_fns)->is_interrupted && \ + (*((struct fns *)(re)->re_fns)->is_interrupted)()) + /* * the insides of a regex_t, hidden behind a void * */ |
