2 * Copyright (C) 1984-2021 Mark Nudelman
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.
7 * For more information, see the README file.
11 * Routines to do pattern matching.
20 * Compile a search pattern, for future use by match_pattern.
23 compile_pattern2(pattern, search_type, comp_pattern, show_error)
26 PATTERN_TYPE *comp_pattern;
29 if (search_type & SRCH_NO_REGEX)
33 struct re_pattern_buffer *comp = (struct re_pattern_buffer *)
34 ecalloc(1, sizeof(struct re_pattern_buffer));
35 re_set_syntax(RE_SYNTAX_POSIX_EXTENDED);
36 if (re_compile_pattern(pattern, strlen(pattern), comp))
40 error("Invalid pattern", NULL_PARG);
43 if (*comp_pattern != NULL)
45 regfree(*comp_pattern);
50 #if HAVE_POSIX_REGCOMP
51 regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
52 if (regcomp(comp, pattern, REGCOMP_FLAG))
56 error("Invalid pattern", NULL_PARG);
59 if (*comp_pattern != NULL)
61 regfree(*comp_pattern);
67 constant char *errstring;
70 pcre *comp = pcre_compile(pattern,
71 (utf_mode) ? PCRE_UTF8 | PCRE_NO_UTF8_CHECK : 0,
72 &errstring, &erroffset, NULL);
75 parg.p_string = (char *) errstring;
86 pcre2_code *comp = pcre2_compile((PCRE2_SPTR)pattern, strlen(pattern),
87 0, &errcode, &erroffset, NULL);
93 pcre2_get_error_message(errcode, (PCRE2_UCHAR*)msg, sizeof(msg));
103 if ((parg.p_string = re_comp(pattern)) != NULL)
113 if ((comp = regcmp(pattern, 0)) == NULL)
116 error("Invalid pattern", NULL_PARG);
119 if (comp_pattern != NULL)
121 *comp_pattern = comp;
125 reg_show_error = show_error;
126 comp = regcomp(pattern);
131 * regcomp has already printed an error message
136 if (*comp_pattern != NULL)
138 *comp_pattern = comp;
145 * Like compile_pattern2, but convert the pattern to lowercase if necessary.
148 compile_pattern(pattern, search_type, show_error, comp_pattern)
152 PATTERN_TYPE *comp_pattern;
157 if (caseless != OPT_ONPLUS)
158 cvt_pattern = pattern;
161 cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
162 cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC);
164 result = compile_pattern2(cvt_pattern, search_type, comp_pattern, show_error);
165 if (cvt_pattern != pattern)
171 * Forget that we have a compiled pattern.
174 uncompile_pattern(pattern)
175 PATTERN_TYPE *pattern;
178 if (*pattern != NULL)
185 #if HAVE_POSIX_REGCOMP
186 if (*pattern != NULL)
194 if (*pattern != NULL)
199 if (*pattern != NULL)
200 pcre2_code_free(*pattern);
207 if (*pattern != NULL)
212 if (*pattern != NULL)
220 * Can a pattern be successfully compiled?
223 valid_pattern(pattern)
226 PATTERN_TYPE comp_pattern;
229 SET_NULL_PATTERN(comp_pattern);
230 result = compile_pattern2(pattern, 0, &comp_pattern, 0);
233 uncompile_pattern(&comp_pattern);
239 * Is a compiled pattern null?
242 is_null_pattern(pattern)
243 PATTERN_TYPE pattern;
246 return (pattern == NULL);
248 #if HAVE_POSIX_REGCOMP
249 return (pattern == NULL);
252 return (pattern == NULL);
255 return (pattern == NULL);
258 return (pattern == 0);
261 return (pattern == NULL);
264 return (pattern == NULL);
267 return (pattern == NULL);
272 * Simple pattern matching function.
273 * It supports no metacharacters like *, etc.
276 match(pattern, pattern_len, buf, buf_len, pfound, pend)
281 char **pfound, **pend;
284 char *pattern_end = pattern + pattern_len;
285 char *buf_end = buf + buf_len;
287 for ( ; buf < buf_end; buf++)
289 for (pp = pattern, lp = buf; ; pp++, lp++)
293 if (caseless == OPT_ONPLUS && ASCII_IS_UPPER(cp))
294 cp = ASCII_TO_LOWER(cp);
297 if (pp == pattern_end || lp == buf_end)
300 if (pp == pattern_end)
313 * Perform a pattern match with the previously compiled pattern.
314 * Set sp and ep to the start and end of the matched string.
317 match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type)
318 PATTERN_TYPE pattern;
331 search_type |= SRCH_NO_REGEX;
333 if (search_type & SRCH_NO_REGEX)
334 matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
339 struct re_registers search_regs;
340 pattern->not_bol = notbol;
341 pattern->regs_allocated = REGS_UNALLOCATED;
342 matched = re_search(pattern, line, line_len, 0, line_len, &search_regs) >= 0;
345 *sp = line + search_regs.start[0];
346 *ep = line + search_regs.end[0];
350 #if HAVE_POSIX_REGCOMP
353 int flags = (notbol) ? REG_NOTBOL : 0;
355 flags |= REG_STARTEND;
359 matched = !regexec(pattern, line, 1, &rm, flags);
363 *sp = line + rm.rm_so;
364 *ep = line + rm.rm_eo;
374 int flags = (notbol) ? PCRE_NOTBOL : 0;
376 matched = pcre_exec(pattern, NULL, line, line_len,
377 0, flags, ovector, 3) >= 0;
380 *sp = line + ovector[0];
381 *ep = line + ovector[1];
387 int flags = (notbol) ? PCRE2_NOTBOL : 0;
388 pcre2_match_data *md = pcre2_match_data_create(3, NULL);
389 matched = pcre2_match(pattern, (PCRE2_SPTR)line, line_len,
390 0, flags, md, NULL) >= 0;
393 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(md);
394 *sp = line + ovector[0];
395 *ep = line + ovector[1];
397 pcre2_match_data_free(md);
401 matched = (re_exec(line) == 1);
403 * re_exec doesn't seem to provide a way to get the matched string.
408 *ep = regex(pattern, line);
409 matched = (*ep != NULL);
415 matched = regexec2(pattern, line, notbol);
417 matched = regexec(pattern, line);
421 *sp = pattern->startp[0];
422 *ep = pattern->endp[0];
426 matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
427 ((search_type & SRCH_NO_MATCH) && !matched);
432 * Return the name of the pattern matching library.
435 pattern_lib_name(VOID_PARAM)
440 #if HAVE_POSIX_REGCOMP
456 return ("Spencer V8");