xref: /rk3399_rockchip-uboot/lib/slre.c (revision a5ecbe62c25c7c9d6ddd0c9eb4d5ec3350642614)
1*a5ecbe62SWolfgang Denk /*
2*a5ecbe62SWolfgang Denk  * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
3*a5ecbe62SWolfgang Denk  * All rights reserved
4*a5ecbe62SWolfgang Denk  *
5*a5ecbe62SWolfgang Denk  * "THE BEER-WARE LICENSE" (Revision 42):
6*a5ecbe62SWolfgang Denk  * Sergey Lyubka wrote this file.  As long as you retain this notice you
7*a5ecbe62SWolfgang Denk  * can do whatever you want with this stuff. If we meet some day, and you think
8*a5ecbe62SWolfgang Denk  * this stuff is worth it, you can buy me a beer in return.
9*a5ecbe62SWolfgang Denk  */
10*a5ecbe62SWolfgang Denk 
11*a5ecbe62SWolfgang Denk /*
12*a5ecbe62SWolfgang Denk  * Downloaded Sat Nov  5 17:43:06 CET 2011 at
13*a5ecbe62SWolfgang Denk  * http://slre.sourceforge.net/1.0/slre.c
14*a5ecbe62SWolfgang Denk  */
15*a5ecbe62SWolfgang Denk 
16*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST
17*a5ecbe62SWolfgang Denk #include <stdio.h>
18*a5ecbe62SWolfgang Denk #include <assert.h>
19*a5ecbe62SWolfgang Denk #include <ctype.h>
20*a5ecbe62SWolfgang Denk #include <stdlib.h>
21*a5ecbe62SWolfgang Denk #include <string.h>
22*a5ecbe62SWolfgang Denk #else
23*a5ecbe62SWolfgang Denk #include <common.h>
24*a5ecbe62SWolfgang Denk #include <linux/ctype.h>
25*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */
26*a5ecbe62SWolfgang Denk 
27*a5ecbe62SWolfgang Denk #include <errno.h>
28*a5ecbe62SWolfgang Denk 
29*a5ecbe62SWolfgang Denk #include <slre.h>
30*a5ecbe62SWolfgang Denk 
31*a5ecbe62SWolfgang Denk enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL,
32*a5ecbe62SWolfgang Denk 	STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT};
33*a5ecbe62SWolfgang Denk 
34*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST
35*a5ecbe62SWolfgang Denk static struct {
36*a5ecbe62SWolfgang Denk 	const char	*name;
37*a5ecbe62SWolfgang Denk 	int		narg;
38*a5ecbe62SWolfgang Denk 	const char	*flags;
39*a5ecbe62SWolfgang Denk } opcodes[] = {
40*a5ecbe62SWolfgang Denk 	{"END",		0, ""},		/* End of code block or program	*/
41*a5ecbe62SWolfgang Denk 	{"BRANCH",	2, "oo"},	/* Alternative operator, "|"	*/
42*a5ecbe62SWolfgang Denk 	{"ANY",		0, ""},		/* Match any character, "."	*/
43*a5ecbe62SWolfgang Denk 	{"EXACT",	2, "d"},	/* Match exact string		*/
44*a5ecbe62SWolfgang Denk 	{"ANYOF",	2, "D"},	/* Match any from set, "[]"	*/
45*a5ecbe62SWolfgang Denk 	{"ANYBUT",	2, "D"},	/* Match any but from set, "[^]"*/
46*a5ecbe62SWolfgang Denk 	{"OPEN ",	1, "i"},	/* Capture start, "("		*/
47*a5ecbe62SWolfgang Denk 	{"CLOSE",	1, "i"},	/* Capture end, ")"		*/
48*a5ecbe62SWolfgang Denk 	{"BOL",		0, ""},		/* Beginning of string, "^"	*/
49*a5ecbe62SWolfgang Denk 	{"EOL",		0, ""},		/* End of string, "$"		*/
50*a5ecbe62SWolfgang Denk 	{"STAR",	1, "o"},	/* Match zero or more times "*"	*/
51*a5ecbe62SWolfgang Denk 	{"PLUS",	1, "o"},	/* Match one or more times, "+"	*/
52*a5ecbe62SWolfgang Denk 	{"STARQ",	1, "o"},	/* Non-greedy STAR,  "*?"	*/
53*a5ecbe62SWolfgang Denk 	{"PLUSQ",	1, "o"},	/* Non-greedy PLUS, "+?"	*/
54*a5ecbe62SWolfgang Denk 	{"QUEST",	1, "o"},	/* Match zero or one time, "?"	*/
55*a5ecbe62SWolfgang Denk 	{"SPACE",	0, ""},		/* Match whitespace, "\s"	*/
56*a5ecbe62SWolfgang Denk 	{"NONSPACE",	0, ""},		/* Match non-space, "\S"	*/
57*a5ecbe62SWolfgang Denk 	{"DIGIT",	0, ""}		/* Match digit, "\d"		*/
58*a5ecbe62SWolfgang Denk };
59*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */
60*a5ecbe62SWolfgang Denk 
61*a5ecbe62SWolfgang Denk /*
62*a5ecbe62SWolfgang Denk  * Commands and operands are all unsigned char (1 byte long). All code offsets
63*a5ecbe62SWolfgang Denk  * are relative to current address, and positive (always point forward). Data
64*a5ecbe62SWolfgang Denk  * offsets are absolute. Commands with operands:
65*a5ecbe62SWolfgang Denk  *
66*a5ecbe62SWolfgang Denk  * BRANCH offset1 offset2
67*a5ecbe62SWolfgang Denk  *	Try to match the code block that follows the BRANCH instruction
68*a5ecbe62SWolfgang Denk  *	(code block ends with END). If no match, try to match code block that
69*a5ecbe62SWolfgang Denk  *	starts at offset1. If either of these match, jump to offset2.
70*a5ecbe62SWolfgang Denk  *
71*a5ecbe62SWolfgang Denk  * EXACT data_offset data_length
72*a5ecbe62SWolfgang Denk  *	Try to match exact string. String is recorded in data section from
73*a5ecbe62SWolfgang Denk  *	data_offset, and has length data_length.
74*a5ecbe62SWolfgang Denk  *
75*a5ecbe62SWolfgang Denk  * OPEN capture_number
76*a5ecbe62SWolfgang Denk  * CLOSE capture_number
77*a5ecbe62SWolfgang Denk  *	If the user have passed 'struct cap' array for captures, OPEN
78*a5ecbe62SWolfgang Denk  *	records the beginning of the matched substring (cap->ptr), CLOSE
79*a5ecbe62SWolfgang Denk  *	sets the length (cap->len) for respective capture_number.
80*a5ecbe62SWolfgang Denk  *
81*a5ecbe62SWolfgang Denk  * STAR code_offset
82*a5ecbe62SWolfgang Denk  * PLUS code_offset
83*a5ecbe62SWolfgang Denk  * QUEST code_offset
84*a5ecbe62SWolfgang Denk  *	*, +, ?, respectively. Try to gobble as much as possible from the
85*a5ecbe62SWolfgang Denk  *	matched buffer, until code block that follows these instructions
86*a5ecbe62SWolfgang Denk  *	matches. When the longest possible string is matched,
87*a5ecbe62SWolfgang Denk  *	jump to code_offset
88*a5ecbe62SWolfgang Denk  *
89*a5ecbe62SWolfgang Denk  * STARQ, PLUSQ are non-greedy versions of STAR and PLUS.
90*a5ecbe62SWolfgang Denk  */
91*a5ecbe62SWolfgang Denk 
92*a5ecbe62SWolfgang Denk static const char *meta_chars = "|.^$*+?()[\\";
93*a5ecbe62SWolfgang Denk 
94*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST
95*a5ecbe62SWolfgang Denk 
96*a5ecbe62SWolfgang Denk static void
97*a5ecbe62SWolfgang Denk print_character_set(FILE *fp, const unsigned char *p, int len)
98*a5ecbe62SWolfgang Denk {
99*a5ecbe62SWolfgang Denk 	int	i;
100*a5ecbe62SWolfgang Denk 
101*a5ecbe62SWolfgang Denk 	for (i = 0; i < len; i++) {
102*a5ecbe62SWolfgang Denk 		if (i > 0)
103*a5ecbe62SWolfgang Denk 			(void) fputc(',', fp);
104*a5ecbe62SWolfgang Denk 		if (p[i] == 0) {
105*a5ecbe62SWolfgang Denk 			i++;
106*a5ecbe62SWolfgang Denk 			if (p[i] == 0)
107*a5ecbe62SWolfgang Denk 				(void) fprintf(fp, "\\x%02x", p[i]);
108*a5ecbe62SWolfgang Denk 			else
109*a5ecbe62SWolfgang Denk 				(void) fprintf(fp, "%s", opcodes[p[i]].name);
110*a5ecbe62SWolfgang Denk 		} else if (isprint(p[i])) {
111*a5ecbe62SWolfgang Denk 			(void) fputc(p[i], fp);
112*a5ecbe62SWolfgang Denk 		} else {
113*a5ecbe62SWolfgang Denk 			(void) fprintf(fp, "\\x%02x", p[i]);
114*a5ecbe62SWolfgang Denk 		}
115*a5ecbe62SWolfgang Denk 	}
116*a5ecbe62SWolfgang Denk }
117*a5ecbe62SWolfgang Denk 
118*a5ecbe62SWolfgang Denk void
119*a5ecbe62SWolfgang Denk slre_dump(const struct slre *r, FILE *fp)
120*a5ecbe62SWolfgang Denk {
121*a5ecbe62SWolfgang Denk 	int	i, j, ch, op, pc;
122*a5ecbe62SWolfgang Denk 
123*a5ecbe62SWolfgang Denk 	for (pc = 0; pc < r->code_size; pc++) {
124*a5ecbe62SWolfgang Denk 
125*a5ecbe62SWolfgang Denk 		op = r->code[pc];
126*a5ecbe62SWolfgang Denk 		(void) fprintf(fp, "%3d %s ", pc, opcodes[op].name);
127*a5ecbe62SWolfgang Denk 
128*a5ecbe62SWolfgang Denk 		for (i = 0; opcodes[op].flags[i] != '\0'; i++)
129*a5ecbe62SWolfgang Denk 			switch (opcodes[op].flags[i]) {
130*a5ecbe62SWolfgang Denk 			case 'i':
131*a5ecbe62SWolfgang Denk 				(void) fprintf(fp, "%d ", r->code[pc + 1]);
132*a5ecbe62SWolfgang Denk 				pc++;
133*a5ecbe62SWolfgang Denk 				break;
134*a5ecbe62SWolfgang Denk 			case 'o':
135*a5ecbe62SWolfgang Denk 				(void) fprintf(fp, "%d ",
136*a5ecbe62SWolfgang Denk 				    pc + r->code[pc + 1] - i);
137*a5ecbe62SWolfgang Denk 				pc++;
138*a5ecbe62SWolfgang Denk 				break;
139*a5ecbe62SWolfgang Denk 			case 'D':
140*a5ecbe62SWolfgang Denk 				print_character_set(fp, r->data +
141*a5ecbe62SWolfgang Denk 				    r->code[pc + 1], r->code[pc + 2]);
142*a5ecbe62SWolfgang Denk 				pc += 2;
143*a5ecbe62SWolfgang Denk 				break;
144*a5ecbe62SWolfgang Denk 			case 'd':
145*a5ecbe62SWolfgang Denk 				(void) fputc('"', fp);
146*a5ecbe62SWolfgang Denk 				for (j = 0; j < r->code[pc + 2]; j++) {
147*a5ecbe62SWolfgang Denk 					ch = r->data[r->code[pc + 1] + j];
148*a5ecbe62SWolfgang Denk 					if (isprint(ch)) {
149*a5ecbe62SWolfgang Denk 						(void) fputc(ch, fp);
150*a5ecbe62SWolfgang Denk 					} else {
151*a5ecbe62SWolfgang Denk 						(void) fprintf(fp,
152*a5ecbe62SWolfgang Denk 							"\\x%02x", ch);
153*a5ecbe62SWolfgang Denk 					}
154*a5ecbe62SWolfgang Denk 				}
155*a5ecbe62SWolfgang Denk 				(void) fputc('"', fp);
156*a5ecbe62SWolfgang Denk 				pc += 2;
157*a5ecbe62SWolfgang Denk 				break;
158*a5ecbe62SWolfgang Denk 			}
159*a5ecbe62SWolfgang Denk 
160*a5ecbe62SWolfgang Denk 		(void) fputc('\n', fp);
161*a5ecbe62SWolfgang Denk 	}
162*a5ecbe62SWolfgang Denk }
163*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */
164*a5ecbe62SWolfgang Denk 
165*a5ecbe62SWolfgang Denk static void
166*a5ecbe62SWolfgang Denk set_jump_offset(struct slre *r, int pc, int offset)
167*a5ecbe62SWolfgang Denk {
168*a5ecbe62SWolfgang Denk 	assert(offset < r->code_size);
169*a5ecbe62SWolfgang Denk 
170*a5ecbe62SWolfgang Denk 	if (r->code_size - offset > 0xff)
171*a5ecbe62SWolfgang Denk 		r->err_str = "Jump offset is too big";
172*a5ecbe62SWolfgang Denk 	else
173*a5ecbe62SWolfgang Denk 		r->code[pc] = (unsigned char) (r->code_size - offset);
174*a5ecbe62SWolfgang Denk }
175*a5ecbe62SWolfgang Denk 
176*a5ecbe62SWolfgang Denk static void
177*a5ecbe62SWolfgang Denk emit(struct slre *r, int code)
178*a5ecbe62SWolfgang Denk {
179*a5ecbe62SWolfgang Denk 	if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0])))
180*a5ecbe62SWolfgang Denk 		r->err_str = "RE is too long (code overflow)";
181*a5ecbe62SWolfgang Denk 	else
182*a5ecbe62SWolfgang Denk 		r->code[r->code_size++] = (unsigned char) code;
183*a5ecbe62SWolfgang Denk }
184*a5ecbe62SWolfgang Denk 
185*a5ecbe62SWolfgang Denk static void
186*a5ecbe62SWolfgang Denk store_char_in_data(struct slre *r, int ch)
187*a5ecbe62SWolfgang Denk {
188*a5ecbe62SWolfgang Denk 	if (r->data_size >= (int) sizeof(r->data))
189*a5ecbe62SWolfgang Denk 		r->err_str = "RE is too long (data overflow)";
190*a5ecbe62SWolfgang Denk 	else
191*a5ecbe62SWolfgang Denk 		r->data[r->data_size++] = ch;
192*a5ecbe62SWolfgang Denk }
193*a5ecbe62SWolfgang Denk 
194*a5ecbe62SWolfgang Denk static void
195*a5ecbe62SWolfgang Denk exact(struct slre *r, const char **re)
196*a5ecbe62SWolfgang Denk {
197*a5ecbe62SWolfgang Denk 	int	old_data_size = r->data_size;
198*a5ecbe62SWolfgang Denk 
199*a5ecbe62SWolfgang Denk 	while (**re != '\0' && (strchr(meta_chars, **re)) == NULL)
200*a5ecbe62SWolfgang Denk 		store_char_in_data(r, *(*re)++);
201*a5ecbe62SWolfgang Denk 
202*a5ecbe62SWolfgang Denk 	emit(r, EXACT);
203*a5ecbe62SWolfgang Denk 	emit(r, old_data_size);
204*a5ecbe62SWolfgang Denk 	emit(r, r->data_size - old_data_size);
205*a5ecbe62SWolfgang Denk }
206*a5ecbe62SWolfgang Denk 
207*a5ecbe62SWolfgang Denk static int
208*a5ecbe62SWolfgang Denk get_escape_char(const char **re)
209*a5ecbe62SWolfgang Denk {
210*a5ecbe62SWolfgang Denk 	int	res;
211*a5ecbe62SWolfgang Denk 
212*a5ecbe62SWolfgang Denk 	switch (*(*re)++) {
213*a5ecbe62SWolfgang Denk 	case 'n':
214*a5ecbe62SWolfgang Denk 		res = '\n';
215*a5ecbe62SWolfgang Denk 		break;
216*a5ecbe62SWolfgang Denk 	case 'r':
217*a5ecbe62SWolfgang Denk 		res = '\r';
218*a5ecbe62SWolfgang Denk 		break;
219*a5ecbe62SWolfgang Denk 	case 't':
220*a5ecbe62SWolfgang Denk 		res = '\t';
221*a5ecbe62SWolfgang Denk 		break;
222*a5ecbe62SWolfgang Denk 	case '0':
223*a5ecbe62SWolfgang Denk 		res = 0;
224*a5ecbe62SWolfgang Denk 		break;
225*a5ecbe62SWolfgang Denk 	case 'S':
226*a5ecbe62SWolfgang Denk 		res = NONSPACE << 8;
227*a5ecbe62SWolfgang Denk 		break;
228*a5ecbe62SWolfgang Denk 	case 's':
229*a5ecbe62SWolfgang Denk 		res = SPACE << 8;
230*a5ecbe62SWolfgang Denk 		break;
231*a5ecbe62SWolfgang Denk 	case 'd':
232*a5ecbe62SWolfgang Denk 		res = DIGIT << 8;
233*a5ecbe62SWolfgang Denk 		break;
234*a5ecbe62SWolfgang Denk 	default:
235*a5ecbe62SWolfgang Denk 		res = (*re)[-1];
236*a5ecbe62SWolfgang Denk 		break;
237*a5ecbe62SWolfgang Denk 	}
238*a5ecbe62SWolfgang Denk 
239*a5ecbe62SWolfgang Denk 	return res;
240*a5ecbe62SWolfgang Denk }
241*a5ecbe62SWolfgang Denk 
242*a5ecbe62SWolfgang Denk static void
243*a5ecbe62SWolfgang Denk anyof(struct slre *r, const char **re)
244*a5ecbe62SWolfgang Denk {
245*a5ecbe62SWolfgang Denk 	int	esc, old_data_size = r->data_size, op = ANYOF;
246*a5ecbe62SWolfgang Denk 
247*a5ecbe62SWolfgang Denk 	if (**re == '^') {
248*a5ecbe62SWolfgang Denk 		op = ANYBUT;
249*a5ecbe62SWolfgang Denk 		(*re)++;
250*a5ecbe62SWolfgang Denk 	}
251*a5ecbe62SWolfgang Denk 
252*a5ecbe62SWolfgang Denk 	while (**re != '\0')
253*a5ecbe62SWolfgang Denk 
254*a5ecbe62SWolfgang Denk 		switch (*(*re)++) {
255*a5ecbe62SWolfgang Denk 		case ']':
256*a5ecbe62SWolfgang Denk 			emit(r, op);
257*a5ecbe62SWolfgang Denk 			emit(r, old_data_size);
258*a5ecbe62SWolfgang Denk 			emit(r, r->data_size - old_data_size);
259*a5ecbe62SWolfgang Denk 			return;
260*a5ecbe62SWolfgang Denk 			/* NOTREACHED */
261*a5ecbe62SWolfgang Denk 			break;
262*a5ecbe62SWolfgang Denk 		case '\\':
263*a5ecbe62SWolfgang Denk 			esc = get_escape_char(re);
264*a5ecbe62SWolfgang Denk 			if ((esc & 0xff) == 0) {
265*a5ecbe62SWolfgang Denk 				store_char_in_data(r, 0);
266*a5ecbe62SWolfgang Denk 				store_char_in_data(r, esc >> 8);
267*a5ecbe62SWolfgang Denk 			} else {
268*a5ecbe62SWolfgang Denk 				store_char_in_data(r, esc);
269*a5ecbe62SWolfgang Denk 			}
270*a5ecbe62SWolfgang Denk 			break;
271*a5ecbe62SWolfgang Denk 		default:
272*a5ecbe62SWolfgang Denk 			store_char_in_data(r, (*re)[-1]);
273*a5ecbe62SWolfgang Denk 			break;
274*a5ecbe62SWolfgang Denk 		}
275*a5ecbe62SWolfgang Denk 
276*a5ecbe62SWolfgang Denk 	r->err_str = "No closing ']' bracket";
277*a5ecbe62SWolfgang Denk }
278*a5ecbe62SWolfgang Denk 
279*a5ecbe62SWolfgang Denk static void
280*a5ecbe62SWolfgang Denk relocate(struct slre *r, int begin, int shift)
281*a5ecbe62SWolfgang Denk {
282*a5ecbe62SWolfgang Denk 	emit(r, END);
283*a5ecbe62SWolfgang Denk 	memmove(r->code + begin + shift, r->code + begin, r->code_size - begin);
284*a5ecbe62SWolfgang Denk 	r->code_size += shift;
285*a5ecbe62SWolfgang Denk }
286*a5ecbe62SWolfgang Denk 
287*a5ecbe62SWolfgang Denk static void
288*a5ecbe62SWolfgang Denk quantifier(struct slre *r, int prev, int op)
289*a5ecbe62SWolfgang Denk {
290*a5ecbe62SWolfgang Denk 	if (r->code[prev] == EXACT && r->code[prev + 2] > 1) {
291*a5ecbe62SWolfgang Denk 		r->code[prev + 2]--;
292*a5ecbe62SWolfgang Denk 		emit(r, EXACT);
293*a5ecbe62SWolfgang Denk 		emit(r, r->code[prev + 1] + r->code[prev + 2]);
294*a5ecbe62SWolfgang Denk 		emit(r, 1);
295*a5ecbe62SWolfgang Denk 		prev = r->code_size - 3;
296*a5ecbe62SWolfgang Denk 	}
297*a5ecbe62SWolfgang Denk 	relocate(r, prev, 2);
298*a5ecbe62SWolfgang Denk 	r->code[prev] = op;
299*a5ecbe62SWolfgang Denk 	set_jump_offset(r, prev + 1, prev);
300*a5ecbe62SWolfgang Denk }
301*a5ecbe62SWolfgang Denk 
302*a5ecbe62SWolfgang Denk static void
303*a5ecbe62SWolfgang Denk exact_one_char(struct slre *r, int ch)
304*a5ecbe62SWolfgang Denk {
305*a5ecbe62SWolfgang Denk 	emit(r, EXACT);
306*a5ecbe62SWolfgang Denk 	emit(r, r->data_size);
307*a5ecbe62SWolfgang Denk 	emit(r, 1);
308*a5ecbe62SWolfgang Denk 	store_char_in_data(r, ch);
309*a5ecbe62SWolfgang Denk }
310*a5ecbe62SWolfgang Denk 
311*a5ecbe62SWolfgang Denk static void
312*a5ecbe62SWolfgang Denk fixup_branch(struct slre *r, int fixup)
313*a5ecbe62SWolfgang Denk {
314*a5ecbe62SWolfgang Denk 	if (fixup > 0) {
315*a5ecbe62SWolfgang Denk 		emit(r, END);
316*a5ecbe62SWolfgang Denk 		set_jump_offset(r, fixup, fixup - 2);
317*a5ecbe62SWolfgang Denk 	}
318*a5ecbe62SWolfgang Denk }
319*a5ecbe62SWolfgang Denk 
320*a5ecbe62SWolfgang Denk static void
321*a5ecbe62SWolfgang Denk compile(struct slre *r, const char **re)
322*a5ecbe62SWolfgang Denk {
323*a5ecbe62SWolfgang Denk 	int	op, esc, branch_start, last_op, fixup, cap_no, level;
324*a5ecbe62SWolfgang Denk 
325*a5ecbe62SWolfgang Denk 	fixup = 0;
326*a5ecbe62SWolfgang Denk 	level = r->num_caps;
327*a5ecbe62SWolfgang Denk 	branch_start = last_op = r->code_size;
328*a5ecbe62SWolfgang Denk 
329*a5ecbe62SWolfgang Denk 	for (;;)
330*a5ecbe62SWolfgang Denk 		switch (*(*re)++) {
331*a5ecbe62SWolfgang Denk 		case '\0':
332*a5ecbe62SWolfgang Denk 			(*re)--;
333*a5ecbe62SWolfgang Denk 			return;
334*a5ecbe62SWolfgang Denk 			/* NOTREACHED */
335*a5ecbe62SWolfgang Denk 			break;
336*a5ecbe62SWolfgang Denk 		case '^':
337*a5ecbe62SWolfgang Denk 			emit(r, BOL);
338*a5ecbe62SWolfgang Denk 			break;
339*a5ecbe62SWolfgang Denk 		case '$':
340*a5ecbe62SWolfgang Denk 			emit(r, EOL);
341*a5ecbe62SWolfgang Denk 			break;
342*a5ecbe62SWolfgang Denk 		case '.':
343*a5ecbe62SWolfgang Denk 			last_op = r->code_size;
344*a5ecbe62SWolfgang Denk 			emit(r, ANY);
345*a5ecbe62SWolfgang Denk 			break;
346*a5ecbe62SWolfgang Denk 		case '[':
347*a5ecbe62SWolfgang Denk 			last_op = r->code_size;
348*a5ecbe62SWolfgang Denk 			anyof(r, re);
349*a5ecbe62SWolfgang Denk 			break;
350*a5ecbe62SWolfgang Denk 		case '\\':
351*a5ecbe62SWolfgang Denk 			last_op = r->code_size;
352*a5ecbe62SWolfgang Denk 			esc = get_escape_char(re);
353*a5ecbe62SWolfgang Denk 			if (esc & 0xff00)
354*a5ecbe62SWolfgang Denk 				emit(r, esc >> 8);
355*a5ecbe62SWolfgang Denk 			else
356*a5ecbe62SWolfgang Denk 				exact_one_char(r, esc);
357*a5ecbe62SWolfgang Denk 			break;
358*a5ecbe62SWolfgang Denk 		case '(':
359*a5ecbe62SWolfgang Denk 			last_op = r->code_size;
360*a5ecbe62SWolfgang Denk 			cap_no = ++r->num_caps;
361*a5ecbe62SWolfgang Denk 			emit(r, OPEN);
362*a5ecbe62SWolfgang Denk 			emit(r, cap_no);
363*a5ecbe62SWolfgang Denk 
364*a5ecbe62SWolfgang Denk 			compile(r, re);
365*a5ecbe62SWolfgang Denk 			if (*(*re)++ != ')') {
366*a5ecbe62SWolfgang Denk 				r->err_str = "No closing bracket";
367*a5ecbe62SWolfgang Denk 				return;
368*a5ecbe62SWolfgang Denk 			}
369*a5ecbe62SWolfgang Denk 
370*a5ecbe62SWolfgang Denk 			emit(r, CLOSE);
371*a5ecbe62SWolfgang Denk 			emit(r, cap_no);
372*a5ecbe62SWolfgang Denk 			break;
373*a5ecbe62SWolfgang Denk 		case ')':
374*a5ecbe62SWolfgang Denk 			(*re)--;
375*a5ecbe62SWolfgang Denk 			fixup_branch(r, fixup);
376*a5ecbe62SWolfgang Denk 			if (level == 0) {
377*a5ecbe62SWolfgang Denk 				r->err_str = "Unbalanced brackets";
378*a5ecbe62SWolfgang Denk 				return;
379*a5ecbe62SWolfgang Denk 			}
380*a5ecbe62SWolfgang Denk 			return;
381*a5ecbe62SWolfgang Denk 			/* NOTREACHED */
382*a5ecbe62SWolfgang Denk 			break;
383*a5ecbe62SWolfgang Denk 		case '+':
384*a5ecbe62SWolfgang Denk 		case '*':
385*a5ecbe62SWolfgang Denk 			op = (*re)[-1] == '*' ? STAR : PLUS;
386*a5ecbe62SWolfgang Denk 			if (**re == '?') {
387*a5ecbe62SWolfgang Denk 				(*re)++;
388*a5ecbe62SWolfgang Denk 				op = op == STAR ? STARQ : PLUSQ;
389*a5ecbe62SWolfgang Denk 			}
390*a5ecbe62SWolfgang Denk 			quantifier(r, last_op, op);
391*a5ecbe62SWolfgang Denk 			break;
392*a5ecbe62SWolfgang Denk 		case '?':
393*a5ecbe62SWolfgang Denk 			quantifier(r, last_op, QUEST);
394*a5ecbe62SWolfgang Denk 			break;
395*a5ecbe62SWolfgang Denk 		case '|':
396*a5ecbe62SWolfgang Denk 			fixup_branch(r, fixup);
397*a5ecbe62SWolfgang Denk 			relocate(r, branch_start, 3);
398*a5ecbe62SWolfgang Denk 			r->code[branch_start] = BRANCH;
399*a5ecbe62SWolfgang Denk 			set_jump_offset(r, branch_start + 1, branch_start);
400*a5ecbe62SWolfgang Denk 			fixup = branch_start + 2;
401*a5ecbe62SWolfgang Denk 			r->code[fixup] = 0xff;
402*a5ecbe62SWolfgang Denk 			break;
403*a5ecbe62SWolfgang Denk 		default:
404*a5ecbe62SWolfgang Denk 			(*re)--;
405*a5ecbe62SWolfgang Denk 			last_op = r->code_size;
406*a5ecbe62SWolfgang Denk 			exact(r, re);
407*a5ecbe62SWolfgang Denk 			break;
408*a5ecbe62SWolfgang Denk 		}
409*a5ecbe62SWolfgang Denk }
410*a5ecbe62SWolfgang Denk 
411*a5ecbe62SWolfgang Denk int
412*a5ecbe62SWolfgang Denk slre_compile(struct slre *r, const char *re)
413*a5ecbe62SWolfgang Denk {
414*a5ecbe62SWolfgang Denk 	r->err_str = NULL;
415*a5ecbe62SWolfgang Denk 	r->code_size = r->data_size = r->num_caps = r->anchored = 0;
416*a5ecbe62SWolfgang Denk 
417*a5ecbe62SWolfgang Denk 	if (*re == '^')
418*a5ecbe62SWolfgang Denk 		r->anchored++;
419*a5ecbe62SWolfgang Denk 
420*a5ecbe62SWolfgang Denk 	emit(r, OPEN);	/* This will capture what matches full RE */
421*a5ecbe62SWolfgang Denk 	emit(r, 0);
422*a5ecbe62SWolfgang Denk 
423*a5ecbe62SWolfgang Denk 	while (*re != '\0')
424*a5ecbe62SWolfgang Denk 		compile(r, &re);
425*a5ecbe62SWolfgang Denk 
426*a5ecbe62SWolfgang Denk 	if (r->code[2] == BRANCH)
427*a5ecbe62SWolfgang Denk 		fixup_branch(r, 4);
428*a5ecbe62SWolfgang Denk 
429*a5ecbe62SWolfgang Denk 	emit(r, CLOSE);
430*a5ecbe62SWolfgang Denk 	emit(r, 0);
431*a5ecbe62SWolfgang Denk 	emit(r, END);
432*a5ecbe62SWolfgang Denk 
433*a5ecbe62SWolfgang Denk 	return (r->err_str == NULL ? 1 : 0);
434*a5ecbe62SWolfgang Denk }
435*a5ecbe62SWolfgang Denk 
436*a5ecbe62SWolfgang Denk static int match(const struct slre *, int,
437*a5ecbe62SWolfgang Denk 		const char *, int, int *, struct cap *);
438*a5ecbe62SWolfgang Denk 
439*a5ecbe62SWolfgang Denk static void
440*a5ecbe62SWolfgang Denk loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs)
441*a5ecbe62SWolfgang Denk {
442*a5ecbe62SWolfgang Denk 	int	saved_offset, matched_offset;
443*a5ecbe62SWolfgang Denk 
444*a5ecbe62SWolfgang Denk 	saved_offset = matched_offset = *ofs;
445*a5ecbe62SWolfgang Denk 
446*a5ecbe62SWolfgang Denk 	while (match(r, pc + 2, s, len, ofs, NULL)) {
447*a5ecbe62SWolfgang Denk 		saved_offset = *ofs;
448*a5ecbe62SWolfgang Denk 		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
449*a5ecbe62SWolfgang Denk 			matched_offset = saved_offset;
450*a5ecbe62SWolfgang Denk 		*ofs = saved_offset;
451*a5ecbe62SWolfgang Denk 	}
452*a5ecbe62SWolfgang Denk 
453*a5ecbe62SWolfgang Denk 	*ofs = matched_offset;
454*a5ecbe62SWolfgang Denk }
455*a5ecbe62SWolfgang Denk 
456*a5ecbe62SWolfgang Denk static void
457*a5ecbe62SWolfgang Denk loop_non_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs)
458*a5ecbe62SWolfgang Denk {
459*a5ecbe62SWolfgang Denk 	int	saved_offset = *ofs;
460*a5ecbe62SWolfgang Denk 
461*a5ecbe62SWolfgang Denk 	while (match(r, pc + 2, s, len, ofs, NULL)) {
462*a5ecbe62SWolfgang Denk 		saved_offset = *ofs;
463*a5ecbe62SWolfgang Denk 		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
464*a5ecbe62SWolfgang Denk 			break;
465*a5ecbe62SWolfgang Denk 	}
466*a5ecbe62SWolfgang Denk 
467*a5ecbe62SWolfgang Denk 	*ofs = saved_offset;
468*a5ecbe62SWolfgang Denk }
469*a5ecbe62SWolfgang Denk 
470*a5ecbe62SWolfgang Denk static int
471*a5ecbe62SWolfgang Denk is_any_of(const unsigned char *p, int len, const char *s, int *ofs)
472*a5ecbe62SWolfgang Denk {
473*a5ecbe62SWolfgang Denk 	int	i, ch;
474*a5ecbe62SWolfgang Denk 
475*a5ecbe62SWolfgang Denk 	ch = s[*ofs];
476*a5ecbe62SWolfgang Denk 
477*a5ecbe62SWolfgang Denk 	for (i = 0; i < len; i++)
478*a5ecbe62SWolfgang Denk 		if (p[i] == ch) {
479*a5ecbe62SWolfgang Denk 			(*ofs)++;
480*a5ecbe62SWolfgang Denk 			return 1;
481*a5ecbe62SWolfgang Denk 		}
482*a5ecbe62SWolfgang Denk 
483*a5ecbe62SWolfgang Denk 	return 0;
484*a5ecbe62SWolfgang Denk }
485*a5ecbe62SWolfgang Denk 
486*a5ecbe62SWolfgang Denk static int
487*a5ecbe62SWolfgang Denk is_any_but(const unsigned char *p, int len, const char *s, int *ofs)
488*a5ecbe62SWolfgang Denk {
489*a5ecbe62SWolfgang Denk 	int	i, ch;
490*a5ecbe62SWolfgang Denk 
491*a5ecbe62SWolfgang Denk 	ch = s[*ofs];
492*a5ecbe62SWolfgang Denk 
493*a5ecbe62SWolfgang Denk 	for (i = 0; i < len; i++) {
494*a5ecbe62SWolfgang Denk 		if (p[i] == ch)
495*a5ecbe62SWolfgang Denk 			return 0;
496*a5ecbe62SWolfgang Denk 	}
497*a5ecbe62SWolfgang Denk 
498*a5ecbe62SWolfgang Denk 	(*ofs)++;
499*a5ecbe62SWolfgang Denk 	return 1;
500*a5ecbe62SWolfgang Denk }
501*a5ecbe62SWolfgang Denk 
502*a5ecbe62SWolfgang Denk static int
503*a5ecbe62SWolfgang Denk match(const struct slre *r, int pc, const char *s, int len,
504*a5ecbe62SWolfgang Denk 		int *ofs, struct cap *caps)
505*a5ecbe62SWolfgang Denk {
506*a5ecbe62SWolfgang Denk 	int	n, saved_offset, res = 1;
507*a5ecbe62SWolfgang Denk 
508*a5ecbe62SWolfgang Denk 	while (res && r->code[pc] != END) {
509*a5ecbe62SWolfgang Denk 
510*a5ecbe62SWolfgang Denk 		assert(pc < r->code_size);
511*a5ecbe62SWolfgang Denk 		assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0])));
512*a5ecbe62SWolfgang Denk 
513*a5ecbe62SWolfgang Denk 		switch (r->code[pc]) {
514*a5ecbe62SWolfgang Denk 		case BRANCH:
515*a5ecbe62SWolfgang Denk 			saved_offset = *ofs;
516*a5ecbe62SWolfgang Denk 			res = match(r, pc + 3, s, len, ofs, caps);
517*a5ecbe62SWolfgang Denk 			if (res == 0) {
518*a5ecbe62SWolfgang Denk 				*ofs = saved_offset;
519*a5ecbe62SWolfgang Denk 				res = match(r, pc + r->code[pc + 1],
520*a5ecbe62SWolfgang Denk 				    s, len, ofs, caps);
521*a5ecbe62SWolfgang Denk 			}
522*a5ecbe62SWolfgang Denk 			pc += r->code[pc + 2];
523*a5ecbe62SWolfgang Denk 			break;
524*a5ecbe62SWolfgang Denk 		case EXACT:
525*a5ecbe62SWolfgang Denk 			res = 0;
526*a5ecbe62SWolfgang Denk 			n = r->code[pc + 2];	/* String length */
527*a5ecbe62SWolfgang Denk 			if (n <= len - *ofs && !memcmp(s + *ofs, r->data +
528*a5ecbe62SWolfgang Denk 			    r->code[pc + 1], n)) {
529*a5ecbe62SWolfgang Denk 				(*ofs) += n;
530*a5ecbe62SWolfgang Denk 				res = 1;
531*a5ecbe62SWolfgang Denk 			}
532*a5ecbe62SWolfgang Denk 			pc += 3;
533*a5ecbe62SWolfgang Denk 			break;
534*a5ecbe62SWolfgang Denk 		case QUEST:
535*a5ecbe62SWolfgang Denk 			res = 1;
536*a5ecbe62SWolfgang Denk 			saved_offset = *ofs;
537*a5ecbe62SWolfgang Denk 			if (!match(r, pc + 2, s, len, ofs, caps))
538*a5ecbe62SWolfgang Denk 				*ofs = saved_offset;
539*a5ecbe62SWolfgang Denk 			pc += r->code[pc + 1];
540*a5ecbe62SWolfgang Denk 			break;
541*a5ecbe62SWolfgang Denk 		case STAR:
542*a5ecbe62SWolfgang Denk 			res = 1;
543*a5ecbe62SWolfgang Denk 			loop_greedy(r, pc, s, len, ofs);
544*a5ecbe62SWolfgang Denk 			pc += r->code[pc + 1];
545*a5ecbe62SWolfgang Denk 			break;
546*a5ecbe62SWolfgang Denk 		case STARQ:
547*a5ecbe62SWolfgang Denk 			res = 1;
548*a5ecbe62SWolfgang Denk 			loop_non_greedy(r, pc, s, len, ofs);
549*a5ecbe62SWolfgang Denk 			pc += r->code[pc + 1];
550*a5ecbe62SWolfgang Denk 			break;
551*a5ecbe62SWolfgang Denk 		case PLUS:
552*a5ecbe62SWolfgang Denk 			res = match(r, pc + 2, s, len, ofs, caps);
553*a5ecbe62SWolfgang Denk 			if (res == 0)
554*a5ecbe62SWolfgang Denk 				break;
555*a5ecbe62SWolfgang Denk 
556*a5ecbe62SWolfgang Denk 			loop_greedy(r, pc, s, len, ofs);
557*a5ecbe62SWolfgang Denk 			pc += r->code[pc + 1];
558*a5ecbe62SWolfgang Denk 			break;
559*a5ecbe62SWolfgang Denk 		case PLUSQ:
560*a5ecbe62SWolfgang Denk 			res = match(r, pc + 2, s, len, ofs, caps);
561*a5ecbe62SWolfgang Denk 			if (res == 0)
562*a5ecbe62SWolfgang Denk 				break;
563*a5ecbe62SWolfgang Denk 
564*a5ecbe62SWolfgang Denk 			loop_non_greedy(r, pc, s, len, ofs);
565*a5ecbe62SWolfgang Denk 			pc += r->code[pc + 1];
566*a5ecbe62SWolfgang Denk 			break;
567*a5ecbe62SWolfgang Denk 		case SPACE:
568*a5ecbe62SWolfgang Denk 			res = 0;
569*a5ecbe62SWolfgang Denk 			if (*ofs < len && isspace(((unsigned char *)s)[*ofs])) {
570*a5ecbe62SWolfgang Denk 				(*ofs)++;
571*a5ecbe62SWolfgang Denk 				res = 1;
572*a5ecbe62SWolfgang Denk 			}
573*a5ecbe62SWolfgang Denk 			pc++;
574*a5ecbe62SWolfgang Denk 			break;
575*a5ecbe62SWolfgang Denk 		case NONSPACE:
576*a5ecbe62SWolfgang Denk 			res = 0;
577*a5ecbe62SWolfgang Denk 			if (*ofs < len &&
578*a5ecbe62SWolfgang Denk 					!isspace(((unsigned char *)s)[*ofs])) {
579*a5ecbe62SWolfgang Denk 				(*ofs)++;
580*a5ecbe62SWolfgang Denk 				res = 1;
581*a5ecbe62SWolfgang Denk 			}
582*a5ecbe62SWolfgang Denk 			pc++;
583*a5ecbe62SWolfgang Denk 			break;
584*a5ecbe62SWolfgang Denk 		case DIGIT:
585*a5ecbe62SWolfgang Denk 			res = 0;
586*a5ecbe62SWolfgang Denk 			if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) {
587*a5ecbe62SWolfgang Denk 				(*ofs)++;
588*a5ecbe62SWolfgang Denk 				res = 1;
589*a5ecbe62SWolfgang Denk 			}
590*a5ecbe62SWolfgang Denk 			pc++;
591*a5ecbe62SWolfgang Denk 			break;
592*a5ecbe62SWolfgang Denk 		case ANY:
593*a5ecbe62SWolfgang Denk 			res = 0;
594*a5ecbe62SWolfgang Denk 			if (*ofs < len) {
595*a5ecbe62SWolfgang Denk 				(*ofs)++;
596*a5ecbe62SWolfgang Denk 				res = 1;
597*a5ecbe62SWolfgang Denk 			}
598*a5ecbe62SWolfgang Denk 			pc++;
599*a5ecbe62SWolfgang Denk 			break;
600*a5ecbe62SWolfgang Denk 		case ANYOF:
601*a5ecbe62SWolfgang Denk 			res = 0;
602*a5ecbe62SWolfgang Denk 			if (*ofs < len)
603*a5ecbe62SWolfgang Denk 				res = is_any_of(r->data + r->code[pc + 1],
604*a5ecbe62SWolfgang Denk 					r->code[pc + 2], s, ofs);
605*a5ecbe62SWolfgang Denk 			pc += 3;
606*a5ecbe62SWolfgang Denk 			break;
607*a5ecbe62SWolfgang Denk 		case ANYBUT:
608*a5ecbe62SWolfgang Denk 			res = 0;
609*a5ecbe62SWolfgang Denk 			if (*ofs < len)
610*a5ecbe62SWolfgang Denk 				res = is_any_but(r->data + r->code[pc + 1],
611*a5ecbe62SWolfgang Denk 					r->code[pc + 2], s, ofs);
612*a5ecbe62SWolfgang Denk 			pc += 3;
613*a5ecbe62SWolfgang Denk 			break;
614*a5ecbe62SWolfgang Denk 		case BOL:
615*a5ecbe62SWolfgang Denk 			res = *ofs == 0 ? 1 : 0;
616*a5ecbe62SWolfgang Denk 			pc++;
617*a5ecbe62SWolfgang Denk 			break;
618*a5ecbe62SWolfgang Denk 		case EOL:
619*a5ecbe62SWolfgang Denk 			res = *ofs == len ? 1 : 0;
620*a5ecbe62SWolfgang Denk 			pc++;
621*a5ecbe62SWolfgang Denk 			break;
622*a5ecbe62SWolfgang Denk 		case OPEN:
623*a5ecbe62SWolfgang Denk 			if (caps != NULL)
624*a5ecbe62SWolfgang Denk 				caps[r->code[pc + 1]].ptr = s + *ofs;
625*a5ecbe62SWolfgang Denk 			pc += 2;
626*a5ecbe62SWolfgang Denk 			break;
627*a5ecbe62SWolfgang Denk 		case CLOSE:
628*a5ecbe62SWolfgang Denk 			if (caps != NULL)
629*a5ecbe62SWolfgang Denk 				caps[r->code[pc + 1]].len = (s + *ofs) -
630*a5ecbe62SWolfgang Denk 				    caps[r->code[pc + 1]].ptr;
631*a5ecbe62SWolfgang Denk 			pc += 2;
632*a5ecbe62SWolfgang Denk 			break;
633*a5ecbe62SWolfgang Denk 		case END:
634*a5ecbe62SWolfgang Denk 			pc++;
635*a5ecbe62SWolfgang Denk 			break;
636*a5ecbe62SWolfgang Denk 		default:
637*a5ecbe62SWolfgang Denk 			printf("unknown cmd (%d) at %d\n", r->code[pc], pc);
638*a5ecbe62SWolfgang Denk 			assert(0);
639*a5ecbe62SWolfgang Denk 			break;
640*a5ecbe62SWolfgang Denk 		}
641*a5ecbe62SWolfgang Denk 	}
642*a5ecbe62SWolfgang Denk 
643*a5ecbe62SWolfgang Denk 	return res;
644*a5ecbe62SWolfgang Denk }
645*a5ecbe62SWolfgang Denk 
646*a5ecbe62SWolfgang Denk int
647*a5ecbe62SWolfgang Denk slre_match(const struct slre *r, const char *buf, int len,
648*a5ecbe62SWolfgang Denk 		struct cap *caps)
649*a5ecbe62SWolfgang Denk {
650*a5ecbe62SWolfgang Denk 	int	i, ofs = 0, res = 0;
651*a5ecbe62SWolfgang Denk 
652*a5ecbe62SWolfgang Denk 	if (r->anchored) {
653*a5ecbe62SWolfgang Denk 		res = match(r, 0, buf, len, &ofs, caps);
654*a5ecbe62SWolfgang Denk 	} else {
655*a5ecbe62SWolfgang Denk 		for (i = 0; i < len && res == 0; i++) {
656*a5ecbe62SWolfgang Denk 			ofs = i;
657*a5ecbe62SWolfgang Denk 			res = match(r, 0, buf, len, &ofs, caps);
658*a5ecbe62SWolfgang Denk 		}
659*a5ecbe62SWolfgang Denk 	}
660*a5ecbe62SWolfgang Denk 
661*a5ecbe62SWolfgang Denk 	return res;
662*a5ecbe62SWolfgang Denk }
663*a5ecbe62SWolfgang Denk 
664*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST
665*a5ecbe62SWolfgang Denk #define N_CAPS	5
666*a5ecbe62SWolfgang Denk 
667*a5ecbe62SWolfgang Denk int main(int argc, char *argv[])
668*a5ecbe62SWolfgang Denk {
669*a5ecbe62SWolfgang Denk 	struct slre	slre;
670*a5ecbe62SWolfgang Denk 	struct cap	caps[N_CAPS];
671*a5ecbe62SWolfgang Denk 	unsigned char	data[1 * 1024 * 1024];
672*a5ecbe62SWolfgang Denk 	FILE		*fp;
673*a5ecbe62SWolfgang Denk 	int		i, res, len;
674*a5ecbe62SWolfgang Denk 
675*a5ecbe62SWolfgang Denk 	if (argc < 2) {
676*a5ecbe62SWolfgang Denk 		fprintf(stderr, "Usage: %s 'slre' <file>\n", argv[0]);
677*a5ecbe62SWolfgang Denk 		return 1;
678*a5ecbe62SWolfgang Denk 	}
679*a5ecbe62SWolfgang Denk 
680*a5ecbe62SWolfgang Denk 	fp = fopen(argv[2], "rb");
681*a5ecbe62SWolfgang Denk 	if (fp == NULL) {
682*a5ecbe62SWolfgang Denk 		fprintf(stderr, "Error: cannot open %s:%s\n",
683*a5ecbe62SWolfgang Denk 			argv[2], strerror(errno));
684*a5ecbe62SWolfgang Denk 		return 1;
685*a5ecbe62SWolfgang Denk 	}
686*a5ecbe62SWolfgang Denk 
687*a5ecbe62SWolfgang Denk 	if (!slre_compile(&slre, argv[1])) {
688*a5ecbe62SWolfgang Denk 		fprintf(stderr, "Error compiling slre: %s\n", slre.err_str);
689*a5ecbe62SWolfgang Denk 		return 1;
690*a5ecbe62SWolfgang Denk 	}
691*a5ecbe62SWolfgang Denk 
692*a5ecbe62SWolfgang Denk 	slre_dump(&slre, stderr);
693*a5ecbe62SWolfgang Denk 
694*a5ecbe62SWolfgang Denk 	while (fgets(data, sizeof(data), fp) != NULL) {
695*a5ecbe62SWolfgang Denk 		len = strlen(data);
696*a5ecbe62SWolfgang Denk 
697*a5ecbe62SWolfgang Denk 		if ((len > 0) && (data[len-1] == '\n')) {
698*a5ecbe62SWolfgang Denk 			data[len-1] = '\0';
699*a5ecbe62SWolfgang Denk 			--len;
700*a5ecbe62SWolfgang Denk 		}
701*a5ecbe62SWolfgang Denk 
702*a5ecbe62SWolfgang Denk 		printf("Data = \"%s\"\n", data);
703*a5ecbe62SWolfgang Denk 
704*a5ecbe62SWolfgang Denk 		(void) memset(caps, 0, sizeof(caps));
705*a5ecbe62SWolfgang Denk 
706*a5ecbe62SWolfgang Denk 		res = 0;
707*a5ecbe62SWolfgang Denk 
708*a5ecbe62SWolfgang Denk 		res = slre_match(&slre, data, len, caps);
709*a5ecbe62SWolfgang Denk 		printf("Result [%d]: %d\n", i, res);
710*a5ecbe62SWolfgang Denk 
711*a5ecbe62SWolfgang Denk 		for (i = 0; i < N_CAPS; i++) {
712*a5ecbe62SWolfgang Denk 			if (caps[i].len > 0) {
713*a5ecbe62SWolfgang Denk 				printf("Substring %d: len=%d  [%.*s]\n", i,
714*a5ecbe62SWolfgang Denk 					caps[i].len,
715*a5ecbe62SWolfgang Denk 					caps[i].len, caps[i].ptr);
716*a5ecbe62SWolfgang Denk 			}
717*a5ecbe62SWolfgang Denk 		}
718*a5ecbe62SWolfgang Denk 		printf("----------------------------------------------------\n");
719*a5ecbe62SWolfgang Denk 	}
720*a5ecbe62SWolfgang Denk 	(void) fclose(fp);
721*a5ecbe62SWolfgang Denk 
722*a5ecbe62SWolfgang Denk 	return 0;
723*a5ecbe62SWolfgang Denk }
724*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */
725