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