79ec5b83873793e44ea9d6ebaef22c6642c6c29b
[apps/madmutt.git] / lib-lib / rx.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  *
17  *  Copyright © 2006 Pierre Habouzit
18  */
19 /*
20  * This file is part of mutt-ng, see http://www.muttng.org/.
21  * It's licensed under the GNU General Public License,
22  * please see the file GPL in the top level source directory.
23  */
24
25 #include "lib-lib.h"
26
27 rx_t *rx_compile(const char *s, int flags)
28 {
29     rx_t *pp = p_new(rx_t, 1);
30
31     pp->pattern = m_strdup(s);
32     pp->rx = p_new(regex_t, 1);
33
34     if (REGCOMP(pp->rx, NONULL(s), flags) != 0) {
35         rx_delete(&pp);
36     }
37
38     return pp;
39 }
40
41 int rx_validate(const char *s, char *errbuf, ssize_t errlen)
42 {
43     regex_t re;
44     int res;
45
46     p_clear(&re, 1);
47     res = REGCOMP(&re, NONULL(s), 0);
48     if (res) {
49         regerror(res, &re, errbuf, errlen);
50     }
51     regfree(&re);
52
53     return res;
54 }
55
56 void rx_set_template(rx_t *rx, const char *tpl)
57 {
58     const char *p = tpl;
59
60     m_strreplace(&rx->tpl, tpl);
61     rx->nmatch = 0;
62
63     while ((p = strchr(p, '%'))) {
64         if (isdigit(*++p)) {
65             int n = strtol(p, (char **)&p, 10);
66             rx->nmatch = MAX(n, rx->nmatch);
67         } else {
68             if (*p == '%')
69                 p++;
70         }
71     }
72
73     rx->nmatch++;     /* match 0 is always the whole expr */
74 }
75
76 void rx_wipe(rx_t *rx)
77 {
78     p_delete(&rx->pattern);
79     regfree(rx->rx);
80     p_delete(&rx->rx);
81     p_delete(&rx->tpl);
82 }
83
84 int rx_list_match(rx_t *l, const char *s)
85 {
86     if (m_strisempty(s))
87         return 0;
88
89     while (l) {
90         if (!REGEXEC(l->rx, s))
91             return 1;
92         l = l->next;
93     }
94
95     return 0;
96 }
97
98 int rx_list_match2(rx_t *l, const char *s, char *dst, int dlen)
99 {
100     static regmatch_t *pmatch = NULL;
101     static int nmatch = 0;
102     int pos = 0;
103
104     if (m_strisempty(s))
105         return 0;
106
107     for (; l; l = l->next) {
108         if (l->nmatch > nmatch) {
109             p_realloc(&pmatch, l->nmatch);
110             nmatch = l->nmatch;
111         }
112
113         if (regexec(l->rx, s, l->nmatch, pmatch, 0) == 0) {
114             /* Copy template into dst, with substitutions. */
115             const char *p = l->tpl, *q;
116
117             for (q = strchr(p, '%'); q; q = strchr(p + 1, '%')) {
118                 int n;
119
120                 pos += m_strncpy(dst + pos, dlen - pos, p, q - p);
121
122                 if (!isdigit((unsigned char)q[1])) {
123                     p = q + (q[1] == '%');
124                     continue;
125                 }
126
127                 n = strtol(q + 1, (char **)&p, 10); /* find pmatch index */
128                 pos += m_strncpy(dst + pos, dlen - pos, s + pmatch[n].rm_so,
129                                  pmatch[n].rm_eo - pmatch[n].rm_so);
130             }
131
132             pos += m_strcpy(dst + pos, dlen - pos, p);
133             return 1;
134         }
135     }
136
137     return 0;
138 }
139
140 rx_t **rx_lookup(rx_t **l, const char *pat)
141 {
142     if (m_strisempty(pat))
143         return NULL;
144
145     while (*l) {
146         if (!m_strcmp((*l)->pattern, pat))
147             return l;
148         l = &(*l)->next;
149     }
150
151     return NULL;
152 }
153
154 int rx_sanitize_string(char *dst, ssize_t n, const char *src)
155 {
156     while (*src) {
157         if (n <= 1)
158             break;
159
160         /* these characters must be escaped in regular expressions */
161         if (strchr("^.[$()|*+?{\\", *src)) {
162             if (n <= 2)
163                 break;
164
165             *dst++ = '\\';
166             n--;
167         }
168
169         *dst++ = *src++;
170         n--;
171     }
172
173     *dst = '\0';
174
175     return *src ? -1 : 0;
176 }