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