Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / libdm / regex / matcher.c
blob7f2d203d7e9370b496de25e5ce646ea7daaecce0
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of the device-mapper userspace tools.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include "dmlib.h"
19 #include "parse_rx.h"
20 #include "ttree.h"
21 #include "assert.h"
23 struct dfa_state {
24 int final;
25 struct dfa_state *lookup[256];
28 struct state_queue {
29 struct dfa_state *s;
30 dm_bitset_t bits;
31 struct state_queue *next;
34 struct dm_regex { /* Instance variables for the lexer */
35 struct dfa_state *start;
36 unsigned num_nodes;
37 int nodes_entered;
38 struct rx_node **nodes;
39 struct dm_pool *scratch, *mem;
42 #define TARGET_TRANS '\0'
44 static int _count_nodes(struct rx_node *rx)
46 int r = 1;
48 if (rx->left)
49 r += _count_nodes(rx->left);
51 if (rx->right)
52 r += _count_nodes(rx->right);
54 return r;
57 static void _fill_table(struct dm_regex *m, struct rx_node *rx)
59 assert((rx->type != OR) || (rx->left && rx->right));
61 if (rx->left)
62 _fill_table(m, rx->left);
64 if (rx->right)
65 _fill_table(m, rx->right);
67 m->nodes[m->nodes_entered++] = rx;
70 static void _create_bitsets(struct dm_regex *m)
72 int i;
74 for (i = 0; i < m->num_nodes; i++) {
75 struct rx_node *n = m->nodes[i];
76 n->firstpos = dm_bitset_create(m->scratch, m->num_nodes);
77 n->lastpos = dm_bitset_create(m->scratch, m->num_nodes);
78 n->followpos = dm_bitset_create(m->scratch, m->num_nodes);
82 static void _calc_functions(struct dm_regex *m)
84 int i, j, final = 1;
85 struct rx_node *rx, *c1, *c2;
87 for (i = 0; i < m->num_nodes; i++) {
88 rx = m->nodes[i];
89 c1 = rx->left;
90 c2 = rx->right;
92 if (dm_bit(rx->charset, TARGET_TRANS))
93 rx->final = final++;
95 switch (rx->type) {
96 case CAT:
97 if (c1->nullable)
98 dm_bit_union(rx->firstpos,
99 c1->firstpos, c2->firstpos);
100 else
101 dm_bit_copy(rx->firstpos, c1->firstpos);
103 if (c2->nullable)
104 dm_bit_union(rx->lastpos,
105 c1->lastpos, c2->lastpos);
106 else
107 dm_bit_copy(rx->lastpos, c2->lastpos);
109 rx->nullable = c1->nullable && c2->nullable;
110 break;
112 case PLUS:
113 dm_bit_copy(rx->firstpos, c1->firstpos);
114 dm_bit_copy(rx->lastpos, c1->lastpos);
115 rx->nullable = c1->nullable;
116 break;
118 case OR:
119 dm_bit_union(rx->firstpos, c1->firstpos, c2->firstpos);
120 dm_bit_union(rx->lastpos, c1->lastpos, c2->lastpos);
121 rx->nullable = c1->nullable || c2->nullable;
122 break;
124 case QUEST:
125 case STAR:
126 dm_bit_copy(rx->firstpos, c1->firstpos);
127 dm_bit_copy(rx->lastpos, c1->lastpos);
128 rx->nullable = 1;
129 break;
131 case CHARSET:
132 dm_bit_set(rx->firstpos, i);
133 dm_bit_set(rx->lastpos, i);
134 rx->nullable = 0;
135 break;
137 default:
138 log_error("Internal error: Unknown calc node type");
142 * followpos has it's own switch
143 * because PLUS and STAR do the
144 * same thing.
146 switch (rx->type) {
147 case CAT:
148 for (j = 0; j < m->num_nodes; j++) {
149 if (dm_bit(c1->lastpos, j)) {
150 struct rx_node *n = m->nodes[j];
151 dm_bit_union(n->followpos,
152 n->followpos, c2->firstpos);
155 break;
157 case PLUS:
158 case STAR:
159 for (j = 0; j < m->num_nodes; j++) {
160 if (dm_bit(rx->lastpos, j)) {
161 struct rx_node *n = m->nodes[j];
162 dm_bit_union(n->followpos,
163 n->followpos, rx->firstpos);
166 break;
171 static struct dfa_state *_create_dfa_state(struct dm_pool *mem)
173 return dm_pool_zalloc(mem, sizeof(struct dfa_state));
176 static struct state_queue *_create_state_queue(struct dm_pool *mem,
177 struct dfa_state *dfa,
178 dm_bitset_t bits)
180 struct state_queue *r = dm_pool_alloc(mem, sizeof(*r));
182 if (!r) {
183 stack;
184 return NULL;
187 r->s = dfa;
188 r->bits = dm_bitset_create(mem, bits[0]); /* first element is the size */
189 dm_bit_copy(r->bits, bits);
190 r->next = 0;
191 return r;
194 static int _calc_states(struct dm_regex *m, struct rx_node *rx)
196 unsigned iwidth = (m->num_nodes / DM_BITS_PER_INT) + 1;
197 struct ttree *tt = ttree_create(m->scratch, iwidth);
198 struct state_queue *h, *t, *tmp;
199 struct dfa_state *dfa, *ldfa;
200 int i, a, set_bits = 0, count = 0;
201 dm_bitset_t bs, dfa_bits;
203 if (!tt)
204 return_0;
206 if (!(bs = dm_bitset_create(m->scratch, m->num_nodes)))
207 return_0;
209 /* create first state */
210 dfa = _create_dfa_state(m->mem);
211 m->start = dfa;
212 ttree_insert(tt, rx->firstpos + 1, dfa);
214 /* prime the queue */
215 h = t = _create_state_queue(m->scratch, dfa, rx->firstpos);
216 while (h) {
217 /* pop state off front of the queue */
218 dfa = h->s;
219 dfa_bits = h->bits;
220 h = h->next;
222 /* iterate through all the inputs for this state */
223 dm_bit_clear_all(bs);
224 for (a = 0; a < 256; a++) {
225 /* iterate through all the states in firstpos */
226 for (i = dm_bit_get_first(dfa_bits);
227 i >= 0; i = dm_bit_get_next(dfa_bits, i)) {
228 if (dm_bit(m->nodes[i]->charset, a)) {
229 if (a == TARGET_TRANS)
230 dfa->final = m->nodes[i]->final;
232 dm_bit_union(bs, bs,
233 m->nodes[i]->followpos);
234 set_bits = 1;
238 if (set_bits) {
239 ldfa = ttree_lookup(tt, bs + 1);
240 if (!ldfa) {
241 /* push */
242 ldfa = _create_dfa_state(m->mem);
243 ttree_insert(tt, bs + 1, ldfa);
244 tmp =
245 _create_state_queue(m->scratch,
246 ldfa, bs);
247 if (!h)
248 h = t = tmp;
249 else {
250 t->next = tmp;
251 t = tmp;
254 count++;
257 dfa->lookup[a] = ldfa;
258 set_bits = 0;
259 dm_bit_clear_all(bs);
264 log_debug("Matcher built with %d dfa states", count);
265 return 1;
268 struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
269 unsigned num_patterns)
271 char *all, *ptr;
272 int i;
273 size_t len = 0;
274 struct rx_node *rx;
275 struct dm_pool *scratch = dm_pool_create("regex matcher", 10 * 1024);
276 struct dm_regex *m;
278 if (!scratch)
279 return_NULL;
281 if (!(m = dm_pool_alloc(mem, sizeof(*m)))) {
282 dm_pool_destroy(scratch);
283 return_NULL;
286 memset(m, 0, sizeof(*m));
288 /* join the regexps together, delimiting with zero */
289 for (i = 0; i < num_patterns; i++)
290 len += strlen(patterns[i]) + 8;
292 ptr = all = dm_pool_alloc(scratch, len + 1);
294 if (!all)
295 goto_bad;
297 for (i = 0; i < num_patterns; i++) {
298 ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
299 if (i < (num_patterns - 1))
300 *ptr++ = '|';
303 /* parse this expression */
304 if (!(rx = rx_parse_tok(scratch, all, ptr))) {
305 log_error("Couldn't parse regex");
306 goto bad;
309 m->mem = mem;
310 m->scratch = scratch;
311 m->num_nodes = _count_nodes(rx);
312 m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes);
314 if (!m->nodes)
315 goto_bad;
317 _fill_table(m, rx);
318 _create_bitsets(m);
319 _calc_functions(m);
320 _calc_states(m, rx);
321 dm_pool_destroy(scratch);
322 m->scratch = NULL;
324 return m;
326 bad:
327 dm_pool_destroy(scratch);
328 dm_pool_free(mem, m);
329 return NULL;
332 static struct dfa_state *_step_matcher(int c, struct dfa_state *cs, int *r)
334 if (!(cs = cs->lookup[(unsigned char) c]))
335 return NULL;
337 if (cs->final && (cs->final > *r))
338 *r = cs->final;
340 return cs;
343 int dm_regex_match(struct dm_regex *regex, const char *s)
345 struct dfa_state *cs = regex->start;
346 int r = 0;
348 if (!(cs = _step_matcher(HAT_CHAR, cs, &r)))
349 goto out;
351 for (; *s; s++)
352 if (!(cs = _step_matcher(*s, cs, &r)))
353 goto out;
355 _step_matcher(DOLLAR_CHAR, cs, &r);
357 out:
358 /* subtract 1 to get back to zero index */
359 return r - 1;