From 475c83618a043c88e7414b839228c28452658166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sun, 13 Jul 2014 04:30:23 +0200 Subject: Only compile regex's once --- src/common.c | 106 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 39 deletions(-) (limited to 'src/common.c') diff --git a/src/common.c b/src/common.c index 283535f..fcb9742 100644 --- a/src/common.c +++ b/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 -- cgit v1.2.3