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