]> www.wagner.pp.ru Git - oss/less.git/blob - pattern.c
Removed code page operation. Fix GLOB macros for 64-bit win32. Fixed debug flags...
[oss/less.git] / 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(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 #if NO_REGEX
238         return (pattern == NULL);
239 #endif
240 }
241
242 /*
243  * Simple pattern matching function.
244  * It supports no metacharacters like *, etc.
245  */
246         static int
247 match(pattern, pattern_len, buf, buf_len, pfound, pend)
248         char *pattern;
249         int pattern_len;
250         char *buf;
251         int buf_len;
252         char **pfound, **pend;
253 {
254         register char *pp, *lp;
255         register char *pattern_end = pattern + pattern_len;
256         register char *buf_end = buf + buf_len;
257
258         for ( ;  buf < buf_end;  buf++)
259         {
260                 for (pp = pattern, lp = buf;  ;  pp++, lp++)
261                 {
262                         char cp = *pp;
263                         char cl = *lp;
264                         if (caseless == OPT_ONPLUS && ASCII_IS_UPPER(cp))
265                                 cp = ASCII_TO_LOWER(cp);
266                         if (cp != cl)
267                                 break;
268                         if (pp == pattern_end || lp == buf_end)
269                                 break;
270                 }
271                 if (pp == pattern_end)
272                 {
273                         if (pfound != NULL)
274                                 *pfound = buf;
275                         if (pend != NULL)
276                                 *pend = lp;
277                         return (1);
278                 }
279         }
280         return (0);
281 }
282
283 /*
284  * Perform a pattern match with the previously compiled pattern.
285  * Set sp and ep to the start and end of the matched string.
286  */
287         public int
288 match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type)
289         void *pattern;
290         char *tpattern;
291         char *line;
292         int line_len;
293         char **sp;
294         char **ep;
295         int notbol;
296         int search_type;
297 {
298         int matched;
299 #if HAVE_GNU_REGEX
300         struct re_pattern_buffer *spattern = (struct re_pattern_buffer *) pattern;
301 #endif
302 #if HAVE_POSIX_REGCOMP
303         regex_t *spattern = (regex_t *) pattern;
304 #endif
305 #if HAVE_PCRE
306         pcre *spattern = (pcre *) pattern;
307 #endif
308 #if HAVE_RE_COMP
309         int spattern = (int) pattern;
310 #endif
311 #if HAVE_REGCMP
312         char *spattern = (char *) pattern;
313 #endif
314 #if HAVE_V8_REGCOMP
315         struct regexp *spattern = (struct regexp *) pattern;
316 #endif
317
318         *sp = *ep = NULL;
319 #if NO_REGEX
320         search_type |= SRCH_NO_REGEX;
321 #endif
322         if (search_type & SRCH_NO_REGEX)
323                 matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
324         else
325         {
326 #if HAVE_GNU_REGEX
327         {
328                 struct re_registers search_regs;
329                 spattern->not_bol = notbol;
330                 spattern->regs_allocated = REGS_UNALLOCATED;
331                 matched = re_search(spattern, line, line_len, 0, line_len, &search_regs) >= 0;
332                 if (matched)
333                 {
334                         *sp = line + search_regs.start[0];
335                         *ep = line + search_regs.end[0];
336                 }
337         }
338 #endif
339 #if HAVE_POSIX_REGCOMP
340         {
341                 regmatch_t rm;
342                 int flags = (notbol) ? REG_NOTBOL : 0;
343 #ifdef REG_STARTEND
344                 flags |= REG_STARTEND;
345                 rm.rm_so = 0;
346                 rm.rm_eo = line_len;
347 #endif
348                 matched = !regexec(spattern, line, 1, &rm, flags);
349                 if (matched)
350                 {
351 #ifndef __WATCOMC__
352                         *sp = line + rm.rm_so;
353                         *ep = line + rm.rm_eo;
354 #else
355                         *sp = rm.rm_sp;
356                         *ep = rm.rm_ep;
357 #endif
358                 }
359         }
360 #endif
361 #if HAVE_PCRE
362         {
363                 int flags = (notbol) ? PCRE_NOTBOL : 0;
364                 int ovector[3];
365                 matched = pcre_exec(spattern, NULL, line, line_len,
366                         0, flags, ovector, 3) >= 0;
367                 if (matched)
368                 {
369                         *sp = line + ovector[0];
370                         *ep = line + ovector[1];
371                 }
372         }
373 #endif
374 #if HAVE_RE_COMP
375         matched = (re_exec(line) == 1);
376         /*
377          * re_exec doesn't seem to provide a way to get the matched string.
378          */
379         *sp = *ep = NULL;
380 #endif
381 #if HAVE_REGCMP
382         *ep = regex(spattern, line);
383         matched = (*ep != NULL);
384         if (matched)
385                 *sp = __loc1;
386 #endif
387 #if HAVE_V8_REGCOMP
388 #if HAVE_REGEXEC2
389         matched = regexec2(spattern, line, notbol);
390 #else
391         matched = regexec(spattern, line);
392 #endif
393         if (matched)
394         {
395                 *sp = spattern->startp[0];
396                 *ep = spattern->endp[0];
397         }
398 #endif
399         }
400         matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
401                         ((search_type & SRCH_NO_MATCH) && !matched);
402         return (matched);
403 }
404