summaryrefslogtreecommitdiff
path: root/src/common.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2014-07-13 04:30:23 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2014-07-13 04:30:23 +0200
commit475c83618a043c88e7414b839228c28452658166 (patch)
treeddb990b472d723ad26c63a974bbf7e686cab0baf /src/common.c
parent4904128c9836150e6157b4d143c69be4e3a18392 (diff)
downloadxK-475c83618a043c88e7414b839228c28452658166.tar.gz
xK-475c83618a043c88e7414b839228c28452658166.tar.xz
xK-475c83618a043c88e7414b839228c28452658166.zip
Only compile regex's once
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c106
1 files changed, 67 insertions, 39 deletions
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 (&regex_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 (&regex_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