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