More string and buffer functions.
[apps/madmutt.git] / lib-lib / rx.c
index f2b6720..58e943c 100644 (file)
  * please see the file GPL in the top level source directory.
  */
 
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <lib-lib/lib-lib.h>
+#include "lib-lib.h"
 
 rx_t *rx_compile(const char *s, int flags)
 {
     rx_t *pp = p_new(rx_t, 1);
 
     pp->pattern = m_strdup(s);
-    pp->rx = p_new(regex_t, 1);
+    pp->rx      = p_new(regex_t, 1);
+    pp->flags   = flags;
 
     if (REGCOMP(pp->rx, NONULL(s), flags) != 0) {
         rx_delete(&pp);
@@ -42,42 +39,160 @@ rx_t *rx_compile(const char *s, int flags)
     return pp;
 }
 
-void rx_delete(rx_t **p)
+rx_t *rx_dup(rx_t *r)
+{
+    rx_t *res = rx_compile(r->pattern, r->flags);
+    res->neg  = r->neg;
+    rx_set_template(res, r->tpl);
+    return res;
+}
+
+int rx_validate(const char *s, char *errbuf, ssize_t errlen)
 {
-    p_delete(&(*p)->pattern);
-    regfree((*p)->rx);
-    p_delete(&(*p)->rx);
-    p_delete(p);
+    regex_t re;
+    int res;
+
+    p_clear(&re, 1);
+    res = REGCOMP(&re, NONULL(s), 0);
+    if (res) {
+        regerror(res, &re, errbuf, errlen);
+    }
+    regfree(&re);
+
+    return res;
 }
 
-int rx_list_match(list2_t *l, const char *pat)
+void rx_set_template(rx_t *rx, const char *tpl)
 {
-    int i;
+    const char *p = tpl;
+
+    m_strreplace(&rx->tpl, tpl);
+    rx->nmatch = 0;
+    if (m_strisempty(rx->tpl))
+        return;
+
+    while ((p = strchr(p, '%'))) {
+        if (isdigit(*++p)) {
+            int n = strtol(p, (char **)&p, 10);
+            rx->nmatch = MAX(n, rx->nmatch);
+        } else {
+            if (*p == '%')
+                p++;
+        }
+    }
 
-    if (!pat || !*pat || list_empty(l))
+    rx->nmatch++;     /* match 0 is always the whole expr */
+}
+
+void rx_wipe(rx_t *rx)
+{
+    p_delete(&rx->pattern);
+    regfree(rx->rx);
+    p_delete(&rx->rx);
+    p_delete(&rx->tpl);
+}
+
+int rx_list_match(rx_t *l, const char *s)
+{
+    if (m_strisempty(s))
         return 0;
 
-    for (i = 0; i < l->length; i++) {
-        if (!REGEXEC(((rx_t*)l->data[i])->rx, pat))
+    while (l) {
+        if (!REGEXEC(l->rx, s))
             return 1;
+        l = l->next;
     }
 
     return 0;
 }
 
-int rx_lookup (list2_t *l, const char *pat)
+int rx_list_match2(rx_t *l, const char *s, char *dst, int dlen)
 {
-    int i;
+    static regmatch_t *pmatch = NULL;
+    static int nmatch = 0;
+    int pos = 0;
+
+    if (m_strisempty(s))
+        return 0;
+
+    for (; l; l = l->next) {
+        if (l->nmatch > nmatch) {
+            p_realloc(&pmatch, l->nmatch);
+            nmatch = l->nmatch;
+        }
+
+        if (regexec(l->rx, s, l->nmatch, pmatch, 0) == 0) {
+            /* Copy template into dst, with substitutions. */
+            const char *p = l->tpl, *q;
+
+            for (q = strchr(p, '%'); q; q = strchr(p + 1, '%')) {
+                int n;
+
+                pos += m_strncpy(dst + pos, dlen - pos, p, q - p);
+
+                if (!isdigit((unsigned char)q[1])) {
+                    p = q + (q[1] == '%');
+                    continue;
+                }
 
-    if (!pat || !*pat || list_empty(l))
-        return -1;
+                n = strtol(q + 1, (char **)&p, 10); /* find pmatch index */
+                pos += m_strncpy(dst + pos, dlen - pos, s + pmatch[n].rm_so,
+                                 pmatch[n].rm_eo - pmatch[n].rm_so);
+            }
 
-    for (i = 0; i < l->length; i++) {
-        if (!strcmp(((rx_t*)l->data[i])->pattern, pat))
-            return i;
+            pos += m_strcpy(dst + pos, dlen - pos, p);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+rx_t **rx_lookup(rx_t **l, const char *pat)
+{
+    if (m_strisempty(pat))
+        return NULL;
+
+    while (*l) {
+        if (!m_strcmp((*l)->pattern, pat))
+            return l;
+        l = &(*l)->next;
+    }
+
+    return l;
+}
+
+void rx_list_add(rx_t **l, rx_t *rxp)
+{
+    l = rx_lookup(l, rxp->pattern);
+    if (*l) {
+        rx_t *r = rx_list_pop(l);
+        rx_delete(&r);
     }
+    rx_list_push(l, rxp);
+}
 
-    return -1;
+void rx_list_add2(rx_t **l, rx_t **rxp)
+{
+    l = rx_lookup(l, (*rxp)->pattern);
+    if (*l) {
+        rx_t *r = rx_list_pop(l);
+        rx_delete(&r);
+    }
+    if (m_strisempty((*rxp)->tpl)) {
+        rx_delete(rxp);
+    } else {
+        rx_list_push(l, *rxp);
+    }
+}
+
+void rx_list_remove(rx_t **l, const rx_t *r)
+{
+    l = rx_lookup(l, r->pattern);
+    if (*l) {
+        rx_t *tmp = rx_list_pop(l);
+        rx_delete(&tmp);
+    }
 }
 
 int rx_sanitize_string(char *dst, ssize_t n, const char *src)