Only compile regex's once
This commit is contained in:
106
src/common.c
106
src/common.c
@@ -1417,45 +1417,6 @@ set_boolean_if_valid (bool *out, const char *s)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
regerror_to_str (int code, const regex_t *preg, struct str *out)
|
||||
{
|
||||
size_t required = regerror (code, preg, NULL, 0);
|
||||
str_ensure_space (out, required);
|
||||
out->len += regerror (code, preg,
|
||||
out->str + out->len, out->alloc - out->len) - 1;
|
||||
}
|
||||
|
||||
static size_t regex_error_domain_tag;
|
||||
#define REGEX_ERROR (error_resolve_domain (®ex_error_domain_tag))
|
||||
|
||||
enum
|
||||
{
|
||||
REGEX_ERROR_COMPILATION_FAILED
|
||||
};
|
||||
|
||||
static bool
|
||||
regex_match (const char *regex, const char *s, struct error **e)
|
||||
{
|
||||
regex_t re;
|
||||
int err = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB);
|
||||
if (err)
|
||||
{
|
||||
struct str desc;
|
||||
|
||||
str_init (&desc);
|
||||
regerror_to_str (err, &re, &desc);
|
||||
error_set (e, REGEX_ERROR, REGEX_ERROR_COMPILATION_FAILED,
|
||||
"failed to compile regular expression: %s", desc.str);
|
||||
str_free (&desc);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = regexec (&re, s, 0, NULL, 0) != REG_NOMATCH;
|
||||
regfree (&re);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
read_line (FILE *fp, struct str *s)
|
||||
{
|
||||
@@ -1512,6 +1473,73 @@ xssl_get_error (SSL *ssl, int result, const char **error_info)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Regular expressions -----------------------------------------------------
|
||||
|
||||
static size_t regex_error_domain_tag;
|
||||
#define REGEX_ERROR (error_resolve_domain (®ex_error_domain_tag))
|
||||
|
||||
enum
|
||||
{
|
||||
REGEX_ERROR_COMPILATION_FAILED
|
||||
};
|
||||
|
||||
static regex_t *
|
||||
regex_compile (const char *regex, int flags, struct error **e)
|
||||
{
|
||||
regex_t *re = xmalloc (sizeof *re);
|
||||
int err = regcomp (re, regex, flags);
|
||||
if (!err)
|
||||
return re;
|
||||
|
||||
struct str desc;
|
||||
str_init (&desc);
|
||||
|
||||
size_t required = regerror (err, re, NULL, 0);
|
||||
str_ensure_space (&desc, required);
|
||||
desc.len += regerror (err, re,
|
||||
desc.str + desc.len, desc.alloc - desc.len) - 1;
|
||||
|
||||
free (re);
|
||||
error_set (e, REGEX_ERROR, REGEX_ERROR_COMPILATION_FAILED,
|
||||
"%s: %s", "failed to compile regular expression", desc.str);
|
||||
str_free (&desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
regex_free (void *regex)
|
||||
{
|
||||
regfree (regex);
|
||||
free (regex);
|
||||
}
|
||||
|
||||
// The cost of hashing a string is likely to be significantly smaller than that
|
||||
// of compiling the whole regular expression anew, so here is a simple cache.
|
||||
// Adding basic support for subgroups is easy: check `re_nsub' and output into
|
||||
// a `struct str_vector' (if all we want is the substrings).
|
||||
|
||||
static void
|
||||
regex_cache_init (struct str_map *cache)
|
||||
{
|
||||
str_map_init (cache);
|
||||
cache->free = regex_free;
|
||||
}
|
||||
|
||||
static bool
|
||||
regex_cache_match (struct str_map *cache, const char *regex, int flags,
|
||||
const char *s, struct error **e)
|
||||
{
|
||||
regex_t *re = str_map_find (cache, regex);
|
||||
if (!re)
|
||||
{
|
||||
re = regex_compile (regex, flags, e);
|
||||
if (!re)
|
||||
return false;
|
||||
str_map_set (cache, regex, re);
|
||||
}
|
||||
return regexec (re, s, 0, NULL, 0) != REG_NOMATCH;
|
||||
}
|
||||
|
||||
// --- IRC utilities -----------------------------------------------------------
|
||||
|
||||
struct irc_message
|
||||
|
||||
Reference in New Issue
Block a user