return isn't a function FFS
[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     pp->flags   = flags;
34
35     if (REGCOMP(pp->rx, NONULL(s), flags) != 0) {
36         rx_delete(&pp);
37     }
38
39     return pp;
40 }
41
42 rx_t *rx_dup(rx_t *r)
43 {
44     rx_t *res = rx_compile(r->pattern, r->flags);
45     res->neg  = r->neg;
46     rx_set_template(res, r->tpl);
47     return res;
48 }
49
50 int rx_validate(const char *s, char *errbuf, ssize_t errlen)
51 {
52     regex_t re;
53     int res;
54
55     p_clear(&re, 1);
56     res = REGCOMP(&re, NONULL(s), 0);
57     if (res) {
58         regerror(res, &re, errbuf, errlen);
59     }
60     regfree(&re);
61
62     return res;
63 }
64
65 void rx_set_template(rx_t *rx, const char *tpl)
66 {
67     const char *p = tpl;
68
69     m_strreplace(&rx->tpl, tpl);
70     rx->nmatch = 0;
71     if (m_strisempty(rx->tpl))
72         return;
73
74     while ((p = strchr(p, '%'))) {
75         if (isdigit(*++p)) {
76             int n = strtol(p, (char **)&p, 10);
77             rx->nmatch = MAX(n, rx->nmatch);
78         } else {
79             if (*p == '%')
80                 p++;
81         }
82     }
83
84     rx->nmatch++;     /* match 0 is always the whole expr */
85 }
86
87 void rx_wipe(rx_t *rx)
88 {
89     p_delete(&rx->pattern);
90     regfree(rx->rx);
91     p_delete(&rx->rx);
92     p_delete(&rx->tpl);
93 }
94
95 int rx_list_match(rx_t *l, const char *s)
96 {
97     if (m_strisempty(s))
98         return 0;
99
100     while (l) {
101         if (!REGEXEC(l->rx, s))
102             return 1;
103         l = l->next;
104     }
105
106     return 0;
107 }
108
109 int rx_list_match2(rx_t *l, const char *s, char *dst, int dlen)
110 {
111     static regmatch_t *pmatch = NULL;
112     static int nmatch = 0;
113     int pos = 0;
114
115     if (m_strisempty(s))
116         return 0;
117
118     for (; l; l = l->next) {
119         if (l->nmatch > nmatch) {
120             p_realloc(&pmatch, l->nmatch);
121             nmatch = l->nmatch;
122         }
123
124         if (regexec(l->rx, s, l->nmatch, pmatch, 0) == 0) {
125             /* Copy template into dst, with substitutions. */
126             const char *p = l->tpl, *q;
127
128             for (q = strchr(p, '%'); q; q = strchr(p + 1, '%')) {
129                 int n;
130
131                 pos += m_strncpy(dst + pos, dlen - pos, p, q - p);
132
133                 if (!isdigit((unsigned char)q[1])) {
134                     p = q + (q[1] == '%');
135                     continue;
136                 }
137
138                 n = strtol(q + 1, (char **)&p, 10); /* find pmatch index */
139                 pos += m_strncpy(dst + pos, dlen - pos, s + pmatch[n].rm_so,
140                                  pmatch[n].rm_eo - pmatch[n].rm_so);
141             }
142
143             pos += m_strcpy(dst + pos, dlen - pos, p);
144             return 1;
145         }
146     }
147
148     return 0;
149 }
150
151 rx_t **rx_lookup(rx_t **l, const char *pat)
152 {
153     if (m_strisempty(pat))
154         return NULL;
155
156     while (*l) {
157         if (!m_strcmp((*l)->pattern, pat))
158             return l;
159         l = &(*l)->next;
160     }
161
162     return l;
163 }
164
165 void rx_list_add(rx_t **l, rx_t *rxp)
166 {
167     l = rx_lookup(l, rxp->pattern);
168     if (*l) {
169         rx_t *r = rx_list_pop(l);
170         rx_delete(&r);
171     }
172     rx_list_push(l, rxp);
173 }
174
175 void rx_list_add2(rx_t **l, rx_t **rxp)
176 {
177     l = rx_lookup(l, (*rxp)->pattern);
178     if (*l) {
179         rx_t *r = rx_list_pop(l);
180         rx_delete(&r);
181     }
182     if (m_strisempty((*rxp)->tpl)) {
183         rx_delete(rxp);
184     } else {
185         rx_list_push(l, *rxp);
186     }
187 }
188
189 void rx_list_remove(rx_t **l, const rx_t *r)
190 {
191     l = rx_lookup(l, r->pattern);
192     if (*l) {
193         rx_t *tmp = rx_list_pop(l);
194         rx_delete(&tmp);
195     }
196 }
197
198 int rx_sanitize_string(char *dst, ssize_t n, const char *src)
199 {
200     while (*src) {
201         if (n <= 1)
202             break;
203
204         /* these characters must be escaped in regular expressions */
205         if (strchr("^.[$()|*+?{\\", *src)) {
206             if (n <= 2)
207                 break;
208
209             *dst++ = '\\';
210             n--;
211         }
212
213         *dst++ = *src++;
214         n--;
215     }
216
217     *dst = '\0';
218
219     return *src ? -1 : 0;
220 }