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