xref: /netbsd-src/external/bsd/less/dist/pattern.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: pattern.c,v 1.2 2011/07/03 19:51:26 tron Exp $	*/
2 
3 /*
4  * Copyright (C) 1984-2011  Mark Nudelman
5  *
6  * You may distribute under the terms of either the GNU General Public
7  * License or the Less License, as specified in the README file.
8  *
9  * For more information about less, or for information on how to
10  * contact the author, see the README file.
11  */
12 
13 /*
14  * Routines to do pattern matching.
15  */
16 
17 #include "less.h"
18 #include "pattern.h"
19 
20 extern int caseless;
21 
22 /*
23  * Compile a search pattern, for future use by match_pattern.
24  */
25 	static int
26 compile_pattern2(pattern, search_type, comp_pattern)
27 	char *pattern;
28 	int search_type;
29 	void **comp_pattern;
30 {
31 	if ((search_type & SRCH_NO_REGEX) == 0)
32 	{
33 #if HAVE_POSIX_REGCOMP
34 		regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
35 		regex_t **pcomp = (regex_t **) comp_pattern;
36 		if (regcomp(comp, pattern, REGCOMP_FLAG))
37 		{
38 			free(comp);
39 			error("Invalid pattern", NULL_PARG);
40 			return (-1);
41 		}
42 		if (*pcomp != NULL)
43 			regfree(*pcomp);
44 		*pcomp = comp;
45 #endif
46 #if HAVE_PCRE
47 		pcre *comp;
48 		pcre **pcomp = (pcre **) comp_pattern;
49 		const char *errstring;
50 		int erroffset;
51 		PARG parg;
52 		comp = pcre_compile(pattern, 0,
53 				&errstring, &erroffset, NULL);
54 		if (comp == NULL)
55 		{
56 			parg.p_string = (char *) errstring;
57 			error("%s", &parg);
58 			return (-1);
59 		}
60 		*pcomp = comp;
61 #endif
62 #if HAVE_RE_COMP
63 		PARG parg;
64 		int *pcomp = (int *) comp_pattern;
65 		if ((parg.p_string = re_comp(pattern)) != NULL)
66 		{
67 			error("%s", &parg);
68 			return (-1);
69 		}
70 		*pcomp = 1;
71 #endif
72 #if HAVE_REGCMP
73 		char *comp;
74 		char **pcomp = (char **) comp_pattern;
75 		if ((comp = regcmp(pattern, 0)) == NULL)
76 		{
77 			error("Invalid pattern", NULL_PARG);
78 			return (-1);
79 		}
80 		if (pcomp != NULL)
81 			free(*pcomp);
82 		*pcomp = comp;
83 #endif
84 #if HAVE_V8_REGCOMP
85 		struct regexp *comp;
86 		struct regexp **pcomp = (struct regexp **) comp_pattern;
87 		if ((comp = regcomp(pattern)) == NULL)
88 		{
89 			/*
90 			 * regcomp has already printed an error message
91 			 * via regerror().
92 			 */
93 			return (-1);
94 		}
95 		if (*pcomp != NULL)
96 			free(*pcomp);
97 		*pcomp = comp;
98 #endif
99 	}
100 	return (0);
101 }
102 
103 /*
104  * Like compile_pattern2, but convert the pattern to lowercase if necessary.
105  */
106 	public int
107 compile_pattern(pattern, search_type, comp_pattern)
108 	char *pattern;
109 	int search_type;
110 	void **comp_pattern;
111 {
112 	char *cvt_pattern;
113 	int result;
114 
115 	if (caseless != OPT_ONPLUS)
116 		cvt_pattern = pattern;
117 	else
118 	{
119 		cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
120 		cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC);
121 	}
122 	result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
123 	if (cvt_pattern != pattern)
124 		free(cvt_pattern);
125 	return (result);
126 }
127 
128 /*
129  * Forget that we have a compiled pattern.
130  */
131 	public void
132 uncompile_pattern(pattern)
133 	void **pattern;
134 {
135 #if HAVE_POSIX_REGCOMP
136 	regex_t **pcomp = (regex_t **) pattern;
137 	if (*pcomp != NULL)
138 		regfree(*pcomp);
139 	*pcomp = NULL;
140 #endif
141 #if HAVE_PCRE
142 	pcre **pcomp = (pcre **) pattern;
143 	if (*pcomp != NULL)
144 		pcre_free(*pcomp);
145 	*pcomp = NULL;
146 #endif
147 #if HAVE_RE_COMP
148 	int *pcomp = (int *) pattern;
149 	*pcomp = 0;
150 #endif
151 #if HAVE_REGCMP
152 	char **pcomp = (char **) pattern;
153 	if (*pcomp != NULL)
154 		free(*pcomp);
155 	*pcomp = NULL;
156 #endif
157 #if HAVE_V8_REGCOMP
158 	struct regexp **pcomp = (struct regexp **) pattern;
159 	if (*pcomp != NULL)
160 		free(*pcomp);
161 	*pcomp = NULL;
162 #endif
163 }
164 
165 /*
166  * Is a compiled pattern null?
167  */
168 	public int
169 is_null_pattern(pattern)
170 	void *pattern;
171 {
172 #if HAVE_POSIX_REGCOMP
173 	return (pattern == NULL);
174 #endif
175 #if HAVE_PCRE
176 	return (pattern == NULL);
177 #endif
178 #if HAVE_RE_COMP
179 	return (pattern == 0);
180 #endif
181 #if HAVE_REGCMP
182 	return (pattern == NULL);
183 #endif
184 #if HAVE_V8_REGCOMP
185 	return (pattern == NULL);
186 #endif
187 #if NO_REGEX
188 	return (search_pattern != NULL);
189 #endif
190 }
191 
192 /*
193  * Simple pattern matching function.
194  * It supports no metacharacters like *, etc.
195  */
196 	static int
197 match(pattern, pattern_len, buf, buf_len, pfound, pend)
198 	char *pattern;
199 	int pattern_len;
200 	char *buf;
201 	int buf_len;
202 	char **pfound, **pend;
203 {
204 	register char *pp, *lp;
205 	register char *pattern_end = pattern + pattern_len;
206 	register char *buf_end = buf + buf_len;
207 
208 	for ( ;  buf < buf_end;  buf++)
209 	{
210 		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
211 			if (pp == pattern_end || lp == buf_end)
212 				break;
213 		if (pp == pattern_end)
214 		{
215 			if (pfound != NULL)
216 				*pfound = buf;
217 			if (pend != NULL)
218 				*pend = lp;
219 			return (1);
220 		}
221 	}
222 	return (0);
223 }
224 
225 /*
226  * Perform a pattern match with the previously compiled pattern.
227  * Set sp and ep to the start and end of the matched string.
228  */
229 	public int
230 match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type)
231 	void *pattern;
232 	char *tpattern;
233 	char *line;
234 	int line_len;
235 	char **sp;
236 	char **ep;
237 	int notbol;
238 	int search_type;
239 {
240 	int matched;
241 #if HAVE_POSIX_REGCOMP
242 	regex_t *spattern = (regex_t *) pattern;
243 #endif
244 #if HAVE_PCRE
245 	pcre *spattern = (pcre *) pattern;
246 #endif
247 #if HAVE_RE_COMP
248 	int spattern = (int) pattern;
249 #endif
250 #if HAVE_REGCMP
251 	char *spattern = (char *) pattern;
252 #endif
253 #if HAVE_V8_REGCOMP
254 	struct regexp *spattern = (struct regexp *) pattern;
255 #endif
256 
257 	if (search_type & SRCH_NO_REGEX)
258 		matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
259 	else
260 	{
261 #if HAVE_POSIX_REGCOMP
262 	{
263 		regmatch_t rm;
264 		int flags = (notbol) ? REG_NOTBOL : 0;
265 		matched = !regexec(spattern, line, 1, &rm, flags);
266 		if (matched)
267 		{
268 #ifndef __WATCOMC__
269 			*sp = line + rm.rm_so;
270 			*ep = line + rm.rm_eo;
271 #else
272 			*sp = rm.rm_sp;
273 			*ep = rm.rm_ep;
274 #endif
275 		}
276 	}
277 #endif
278 #if HAVE_PCRE
279 	{
280 		int flags = (notbol) ? PCRE_NOTBOL : 0;
281 		int ovector[3];
282 		matched = pcre_exec(spattern, NULL, line, line_len,
283 			0, flags, ovector, 3) >= 0;
284 		if (matched)
285 		{
286 			*sp = line + ovector[0];
287 			*ep = line + ovector[1];
288 		}
289 	}
290 #endif
291 #if HAVE_RE_COMP
292 	matched = (re_exec(line) == 1);
293 	/*
294 	 * re_exec doesn't seem to provide a way to get the matched string.
295 	 */
296 	*sp = *ep = NULL;
297 #endif
298 #if HAVE_REGCMP
299 	*ep = regex(spattern, line);
300 	matched = (*ep != NULL);
301 	if (matched)
302 		*sp = __loc1;
303 #endif
304 #if HAVE_V8_REGCOMP
305 #if HAVE_REGEXEC2
306 	matched = regexec2(spattern, line, notbol);
307 #else
308 	matched = regexec(spattern, line);
309 #endif
310 	if (matched)
311 	{
312 		*sp = spattern->startp[0];
313 		*ep = spattern->endp[0];
314 	}
315 #endif
316 #if NO_REGEX
317 	matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
318 #endif
319 	}
320 	matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
321 			((search_type & SRCH_NO_MATCH) && !matched);
322 	return (matched);
323 }
324 
325