pattern.c (1ea316270f1f75922ac53976d5d8808a41442f46) pattern.c (f6b74a7d164b5fada266d00e723155a178a4529f)
1/*
1/*
2 * Copyright (C) 1984-2015 Mark Nudelman
2 * Copyright (C) 1984-2017 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"
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
17extern int caseless;
18
19/*
20 * Compile a search pattern, for future use by match_pattern.
21 */
22 static int
15
16extern int caseless;
17
18/*
19 * Compile a search pattern, for future use by match_pattern.
20 */
21 static int
23compile_pattern2(char *pattern, int search_type, void **comp_pattern, int show_error)
22compile_pattern2(pattern, search_type, comp_pattern, show_error)
23 char *pattern;
24 int search_type;
25 PATTERN_TYPE *comp_pattern;
26 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));
27{
28 if (search_type & SRCH_NO_REGEX)
29 return (0);
30 {
31#if HAVE_GNU_REGEX
32 struct re_pattern_buffer *comp = (struct re_pattern_buffer *)
33 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 }
34 re_set_syntax(RE_SYNTAX_POSIX_EXTENDED);
35 if (re_compile_pattern(pattern, strlen(pattern), comp))
36 {
37 free(comp);
38 if (show_error)
39 error("Invalid pattern", NULL_PARG);
40 return (-1);
41 }
41 if (*pcomp != NULL)
42 regfree(*pcomp);
43 *pcomp = comp;
42 if (*comp_pattern != NULL)
43 {
44 regfree(*comp_pattern);
45 free(*comp_pattern);
46 }
47 *comp_pattern = comp;
44#endif
45#if HAVE_POSIX_REGCOMP
46 regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
48#endif
49#if HAVE_POSIX_REGCOMP
50 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 }
51 if (regcomp(comp, pattern, REGCOMP_FLAG))
52 {
53 free(comp);
54 if (show_error)
55 error("Invalid pattern", NULL_PARG);
56 return (-1);
57 }
55 if (*pcomp != NULL)
56 regfree(*pcomp);
57 *pcomp = comp;
58 if (*comp_pattern != NULL)
59 {
60 regfree(*comp_pattern);
61 free(*comp_pattern);
62 }
63 *comp_pattern = comp;
58#endif
59#if HAVE_PCRE
60 pcre *comp;
64#endif
65#if HAVE_PCRE
66 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 }
67 constant char *errstring;
68 int erroffset;
69 PARG parg;
70 comp = pcre_compile(pattern, 0,
71 &errstring, &erroffset, NULL);
72 if (comp == NULL)
73 {
74 parg.p_string = (char *) errstring;
75 if (show_error)
76 error("%s", &parg);
77 return (-1);
78 }
74 *pcomp = comp;
79 *comp_pattern = comp;
75#endif
76#if HAVE_RE_COMP
77 PARG parg;
80#endif
81#if HAVE_RE_COMP
82 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 }
83 if ((parg.p_string = re_comp(pattern)) != NULL)
84 {
85 if (show_error)
86 error("%s", &parg);
87 return (-1);
88 }
85 *pcomp = 1;
89 *comp_pattern = 1;
86#endif
87#if HAVE_REGCMP
88 char *comp;
90#endif
91#if HAVE_REGCMP
92 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 }
93 if ((comp = regcmp(pattern, 0)) == NULL)
94 {
95 if (show_error)
96 error("Invalid pattern", NULL_PARG);
97 return (-1);
98 }
96 if (pcomp != NULL)
97 free(*pcomp);
98 *pcomp = comp;
99 if (comp_pattern != NULL)
100 free(*comp_pattern);
101 *comp_pattern = comp;
99#endif
100#if HAVE_V8_REGCOMP
101 struct regexp *comp;
102#endif
103#if HAVE_V8_REGCOMP
104 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 }
105 reg_show_error = show_error;
106 comp = regcomp(pattern);
107 reg_show_error = 1;
108 if (comp == NULL)
109 {
110 /*
111 * regcomp has already printed an error message
112 * via regerror().
113 */
114 return (-1);
115 }
114 if (*pcomp != NULL)
115 free(*pcomp);
116 *pcomp = comp;
116 if (*comp_pattern != NULL)
117 free(*comp_pattern);
118 *comp_pattern = 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
119#endif
120 }
121 return (0);
122}
123
124/*
125 * Like compile_pattern2, but convert the pattern to lowercase if necessary.
126 */
127 public int
126compile_pattern(char *pattern, int search_type, void **comp_pattern)
128compile_pattern(pattern, search_type, comp_pattern)
129 char *pattern;
130 int search_type;
131 PATTERN_TYPE *comp_pattern;
127{
128 char *cvt_pattern;
129 int result;
130
131 if (caseless != OPT_ONPLUS)
132 cvt_pattern = pattern;
133 else
134 {

--- 5 unchanged lines hidden (view full) ---

140 free(cvt_pattern);
141 return (result);
142}
143
144/*
145 * Forget that we have a compiled pattern.
146 */
147 public void
132{
133 char *cvt_pattern;
134 int result;
135
136 if (caseless != OPT_ONPLUS)
137 cvt_pattern = pattern;
138 else
139 {

--- 5 unchanged lines hidden (view full) ---

145 free(cvt_pattern);
146 return (result);
147}
148
149/*
150 * Forget that we have a compiled pattern.
151 */
152 public void
148uncompile_pattern(void **pattern)
153uncompile_pattern(pattern)
154 PATTERN_TYPE *pattern;
149{
150#if HAVE_GNU_REGEX
155{
156#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;
157 if (*pattern != NULL)
158 {
159 regfree(*pattern);
160 free(*pattern);
161 }
162 *pattern = NULL;
155#endif
156#if HAVE_POSIX_REGCOMP
163#endif
164#if HAVE_POSIX_REGCOMP
157 regex_t **pcomp = (regex_t **) pattern;
158 if (*pcomp != NULL)
159 regfree(*pcomp);
160 *pcomp = NULL;
165 if (*pattern != NULL)
166 {
167 regfree(*pattern);
168 free(*pattern);
169 }
170 *pattern = NULL;
161#endif
162#if HAVE_PCRE
171#endif
172#if HAVE_PCRE
163 pcre **pcomp = (pcre **) pattern;
164 if (*pcomp != NULL)
165 pcre_free(*pcomp);
166 *pcomp = NULL;
173 if (*pattern != NULL)
174 pcre_free(*pattern);
175 *pattern = NULL;
167#endif
168#if HAVE_RE_COMP
176#endif
177#if HAVE_RE_COMP
169 int *pcomp = (int *) pattern;
170 *pcomp = 0;
178 *pattern = 0;
171#endif
172#if HAVE_REGCMP
179#endif
180#if HAVE_REGCMP
173 char **pcomp = (char **) pattern;
174 if (*pcomp != NULL)
175 free(*pcomp);
176 *pcomp = NULL;
181 if (*pattern != NULL)
182 free(*pattern);
183 *pattern = NULL;
177#endif
178#if HAVE_V8_REGCOMP
184#endif
185#if HAVE_V8_REGCOMP
179 struct regexp **pcomp = (struct regexp **) pattern;
180 if (*pcomp != NULL)
181 free(*pcomp);
182 *pcomp = NULL;
186 if (*pattern != NULL)
187 free(*pattern);
188 *pattern = NULL;
183#endif
184}
185
186/*
187 * Can a pattern be successfully compiled?
188 */
189 public int
189#endif
190}
191
192/*
193 * Can a pattern be successfully compiled?
194 */
195 public int
190valid_pattern(char *pattern)
196valid_pattern(pattern)
197 char *pattern;
191{
198{
192 void *comp_pattern;
199 PATTERN_TYPE 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
200 int result;
201
202 CLEAR_PATTERN(comp_pattern);
203 result = compile_pattern2(pattern, 0, &comp_pattern, 0);
204 if (result != 0)
205 return (0);
206 uncompile_pattern(&comp_pattern);
207 return (1);
208}
209
210/*
211 * Is a compiled pattern null?
212 */
213 public int
207is_null_pattern(void *pattern)
214is_null_pattern(pattern)
215 PATTERN_TYPE 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

--- 13 unchanged lines hidden (view full) ---

229#endif
230}
231
232/*
233 * Simple pattern matching function.
234 * It supports no metacharacters like *, etc.
235 */
236 static int
216{
217#if HAVE_GNU_REGEX
218 return (pattern == NULL);
219#endif
220#if HAVE_POSIX_REGCOMP
221 return (pattern == NULL);
222#endif
223#if HAVE_PCRE

--- 13 unchanged lines hidden (view full) ---

237#endif
238}
239
240/*
241 * Simple pattern matching function.
242 * It supports no metacharacters like *, etc.
243 */
244 static int
237match(char *pattern, int pattern_len, char *buf, int buf_len, char **pfound, char **pend)
245match(pattern, pattern_len, buf, buf_len, pfound, pend)
246 char *pattern;
247 int pattern_len;
248 char *buf;
249 int buf_len;
250 char **pfound, **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++)

--- 19 unchanged lines hidden (view full) ---

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
251{
252 char *pp, *lp;
253 char *pattern_end = pattern + pattern_len;
254 char *buf_end = buf + buf_len;
255
256 for ( ; buf < buf_end; buf++)
257 {
258 for (pp = pattern, lp = buf; ; pp++, lp++)

--- 19 unchanged lines hidden (view full) ---

278 return (0);
279}
280
281/*
282 * Perform a pattern match with the previously compiled pattern.
283 * Set sp and ep to the start and end of the matched string.
284 */
285 public int
273match_pattern(void *pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int notbol, int search_type)
286match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type)
287 PATTERN_TYPE pattern;
288 char *tpattern;
289 char *line;
290 int line_len;
291 char **sp;
292 char **ep;
293 int notbol;
294 int search_type;
274{
275 int matched;
295{
296 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;
297
298 *sp = *ep = NULL;
299#if NO_REGEX
300 search_type |= SRCH_NO_REGEX;
301#endif
302 if (search_type & SRCH_NO_REGEX)
303 matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
304 else
305 {
306#if HAVE_GNU_REGEX
307 {
308 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 pattern->not_bol = notbol;
310 pattern->regs_allocated = REGS_UNALLOCATED;
311 matched = re_search(pattern, 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
312 if (matched)
313 {
314 *sp = line + search_regs.start[0];
315 *ep = line + search_regs.end[0];
316 }
317 }
318#endif
319#if HAVE_POSIX_REGCOMP
320 {
321 regmatch_t rm;
322 int flags = (notbol) ? REG_NOTBOL : 0;
323#ifdef REG_STARTEND
324 flags |= REG_STARTEND;
325 rm.rm_so = 0;
326 rm.rm_eo = line_len;
327#endif
325 matched = !regexec(spattern, line, 1, &rm, flags);
328 matched = !regexec(pattern, 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];
329 if (matched)
330 {
331#ifndef __WATCOMC__
332 *sp = line + rm.rm_so;
333 *ep = line + rm.rm_eo;
334#else
335 *sp = rm.rm_sp;
336 *ep = rm.rm_ep;
337#endif
338 }
339 }
340#endif
341#if HAVE_PCRE
342 {
343 int flags = (notbol) ? PCRE_NOTBOL : 0;
344 int ovector[3];
342 matched = pcre_exec(spattern, NULL, line, line_len,
345 matched = pcre_exec(pattern, 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
346 0, flags, ovector, 3) >= 0;
347 if (matched)
348 {
349 *sp = line + ovector[0];
350 *ep = line + ovector[1];
351 }
352 }
353#endif
354#if HAVE_RE_COMP
355 matched = (re_exec(line) == 1);
356 /*
357 * re_exec doesn't seem to provide a way to get the matched string.
358 */
359 *sp = *ep = NULL;
360#endif
361#if HAVE_REGCMP
359 *ep = regex(spattern, line);
362 *ep = regex(pattern, line);
360 matched = (*ep != NULL);
361 if (matched)
362 *sp = __loc1;
363#endif
364#if HAVE_V8_REGCOMP
365#if HAVE_REGEXEC2
363 matched = (*ep != NULL);
364 if (matched)
365 *sp = __loc1;
366#endif
367#if HAVE_V8_REGCOMP
368#if HAVE_REGEXEC2
366 matched = regexec2(spattern, line, notbol);
369 matched = regexec2(pattern, line, notbol);
367#else
370#else
368 matched = regexec(spattern, line);
371 matched = regexec(pattern, line);
369#endif
370 if (matched)
371 {
372#endif
373 if (matched)
374 {
372 *sp = spattern->startp[0];
373 *ep = spattern->endp[0];
375 *sp = pattern->startp[0];
376 *ep = pattern->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
377 }
378#endif
379 }
380 matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
381 ((search_type & SRCH_NO_MATCH) && !matched);
382 return (matched);
383}
384