freebsd-dev/pattern.c

382 lines
7.6 KiB
C
Raw Normal View History

2012-07-23 21:31:53 +00:00
/*
2016-01-04 00:22:34 +00:00
* Copyright (C) 1984-2015 Mark Nudelman
2012-07-23 21:31:53 +00:00
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
*
* For more information, see the README file.
*/
2009-07-27 07:05:08 +00:00
/*
* Routines to do pattern matching.
*/
#include "less.h"
#include "pattern.h"
extern int caseless;
/*
* Compile a search pattern, for future use by match_pattern.
*/
static int
2017-04-25 03:28:38 +00:00
compile_pattern2(char *pattern, int search_type, void **comp_pattern, int show_error)
2009-07-27 07:05:08 +00:00
{
2012-06-26 20:38:53 +00:00
if (search_type & SRCH_NO_REGEX)
return (0);
{
#if HAVE_GNU_REGEX
struct re_pattern_buffer *comp = (struct re_pattern_buffer *)
ecalloc(1, sizeof(struct re_pattern_buffer));
struct re_pattern_buffer **pcomp =
(struct re_pattern_buffer **) comp_pattern;
re_set_syntax(RE_SYNTAX_POSIX_EXTENDED);
if (re_compile_pattern(pattern, strlen(pattern), comp))
2009-07-27 07:05:08 +00:00
{
2012-06-26 20:38:53 +00:00
free(comp);
2016-01-04 00:22:34 +00:00
if (show_error)
error("Invalid pattern", NULL_PARG);
2012-06-26 20:38:53 +00:00
return (-1);
}
if (*pcomp != NULL)
regfree(*pcomp);
*pcomp = comp;
#endif
2009-07-27 07:05:08 +00:00
#if HAVE_POSIX_REGCOMP
2012-06-26 20:38:53 +00:00
regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
regex_t **pcomp = (regex_t **) comp_pattern;
if (regcomp(comp, pattern, REGCOMP_FLAG))
{
free(comp);
2016-01-04 00:22:34 +00:00
if (show_error)
error("Invalid pattern", NULL_PARG);
2012-06-26 20:38:53 +00:00
return (-1);
}
if (*pcomp != NULL)
regfree(*pcomp);
*pcomp = comp;
2009-07-27 07:05:08 +00:00
#endif
#if HAVE_PCRE
2012-06-26 20:38:53 +00:00
pcre *comp;
pcre **pcomp = (pcre **) comp_pattern;
constant char *errstring;
int erroffset;
PARG parg;
comp = pcre_compile(pattern, 0,
&errstring, &erroffset, NULL);
if (comp == NULL)
{
parg.p_string = (char *) errstring;
2016-01-04 00:22:34 +00:00
if (show_error)
error("%s", &parg);
2012-06-26 20:38:53 +00:00
return (-1);
}
*pcomp = comp;
2009-07-27 07:05:08 +00:00
#endif
#if HAVE_RE_COMP
2012-06-26 20:38:53 +00:00
PARG parg;
int *pcomp = (int *) comp_pattern;
if ((parg.p_string = re_comp(pattern)) != NULL)
{
2016-01-04 00:22:34 +00:00
if (show_error)
error("%s", &parg);
2012-06-26 20:38:53 +00:00
return (-1);
}
*pcomp = 1;
2009-07-27 07:05:08 +00:00
#endif
#if HAVE_REGCMP
2012-06-26 20:38:53 +00:00
char *comp;
char **pcomp = (char **) comp_pattern;
if ((comp = regcmp(pattern, 0)) == NULL)
{
2016-01-04 00:22:34 +00:00
if (show_error)
error("Invalid pattern", NULL_PARG);
2012-06-26 20:38:53 +00:00
return (-1);
}
if (pcomp != NULL)
free(*pcomp);
*pcomp = comp;
2009-07-27 07:05:08 +00:00
#endif
#if HAVE_V8_REGCOMP
2012-06-26 20:38:53 +00:00
struct regexp *comp;
struct regexp **pcomp = (struct regexp **) comp_pattern;
2016-01-04 00:22:34 +00:00
reg_show_error = show_error;
comp = regcomp(pattern);
reg_show_error = 1;
if (comp == NULL)
2012-06-26 20:38:53 +00:00
{
/*
* regcomp has already printed an error message
* via regerror().
*/
return (-1);
2009-07-27 07:05:08 +00:00
}
2012-06-26 20:38:53 +00:00
if (*pcomp != NULL)
free(*pcomp);
*pcomp = comp;
#endif
}
2009-07-27 07:05:08 +00:00
return (0);
}
/*
* Like compile_pattern2, but convert the pattern to lowercase if necessary.
*/
public int
2017-04-25 03:28:38 +00:00
compile_pattern(char *pattern, int search_type, void **comp_pattern)
2009-07-27 07:05:08 +00:00
{
char *cvt_pattern;
int result;
if (caseless != OPT_ONPLUS)
cvt_pattern = pattern;
else
{
cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC);
}
2016-01-04 00:22:34 +00:00
result = compile_pattern2(cvt_pattern, search_type, comp_pattern, 1);
2009-07-27 07:05:08 +00:00
if (cvt_pattern != pattern)
free(cvt_pattern);
return (result);
}
/*
* Forget that we have a compiled pattern.
*/
public void
2017-04-25 03:28:38 +00:00
uncompile_pattern(void **pattern)
2009-07-27 07:05:08 +00:00
{
2012-06-26 20:38:53 +00:00
#if HAVE_GNU_REGEX
struct re_pattern_buffer **pcomp = (struct re_pattern_buffer **) pattern;
if (*pcomp != NULL)
regfree(*pcomp);
*pcomp = NULL;
#endif
2009-07-27 07:05:08 +00:00
#if HAVE_POSIX_REGCOMP
regex_t **pcomp = (regex_t **) pattern;
if (*pcomp != NULL)
regfree(*pcomp);
*pcomp = NULL;
#endif
#if HAVE_PCRE
pcre **pcomp = (pcre **) pattern;
if (*pcomp != NULL)
pcre_free(*pcomp);
*pcomp = NULL;
#endif
#if HAVE_RE_COMP
int *pcomp = (int *) pattern;
*pcomp = 0;
#endif
#if HAVE_REGCMP
char **pcomp = (char **) pattern;
if (*pcomp != NULL)
free(*pcomp);
*pcomp = NULL;
#endif
#if HAVE_V8_REGCOMP
struct regexp **pcomp = (struct regexp **) pattern;
if (*pcomp != NULL)
free(*pcomp);
*pcomp = NULL;
#endif
}
2016-01-04 00:22:34 +00:00
/*
* Can a pattern be successfully compiled?
*/
public int
2017-04-25 03:28:38 +00:00
valid_pattern(char *pattern)
2016-01-04 00:22:34 +00:00
{
void *comp_pattern;
int result;
CLEAR_PATTERN(comp_pattern);
result = compile_pattern2(pattern, 0, &comp_pattern, 0);
if (result != 0)
return (0);
uncompile_pattern(&comp_pattern);
return (1);
}
2009-07-27 07:05:08 +00:00
/*
* Is a compiled pattern null?
*/
public int
2017-04-25 03:28:38 +00:00
is_null_pattern(void *pattern)
2009-07-27 07:05:08 +00:00
{
2012-06-26 20:38:53 +00:00
#if HAVE_GNU_REGEX
return (pattern == NULL);
#endif
2009-07-27 07:05:08 +00:00
#if HAVE_POSIX_REGCOMP
return (pattern == NULL);
#endif
#if HAVE_PCRE
return (pattern == NULL);
#endif
#if HAVE_RE_COMP
return (pattern == 0);
#endif
#if HAVE_REGCMP
return (pattern == NULL);
#endif
#if HAVE_V8_REGCOMP
return (pattern == NULL);
#endif
2016-01-04 00:22:34 +00:00
#if NO_REGEX
return (pattern == NULL);
#endif
2009-07-27 07:05:08 +00:00
}
/*
* Simple pattern matching function.
* It supports no metacharacters like *, etc.
*/
static int
2017-04-25 03:28:38 +00:00
match(char *pattern, int pattern_len, char *buf, int buf_len, char **pfound, char **pend)
2009-07-27 07:05:08 +00:00
{
2017-04-25 03:28:38 +00:00
char *pp, *lp;
char *pattern_end = pattern + pattern_len;
char *buf_end = buf + buf_len;
2009-07-27 07:05:08 +00:00
for ( ; buf < buf_end; buf++)
{
2016-01-04 00:22:34 +00:00
for (pp = pattern, lp = buf; ; pp++, lp++)
{
char cp = *pp;
char cl = *lp;
if (caseless == OPT_ONPLUS && ASCII_IS_UPPER(cp))
cp = ASCII_TO_LOWER(cp);
if (cp != cl)
break;
2009-07-27 07:05:08 +00:00
if (pp == pattern_end || lp == buf_end)
break;
2016-01-04 00:22:34 +00:00
}
2009-07-27 07:05:08 +00:00
if (pp == pattern_end)
{
if (pfound != NULL)
*pfound = buf;
if (pend != NULL)
*pend = lp;
return (1);
}
}
return (0);
}
/*
* Perform a pattern match with the previously compiled pattern.
* Set sp and ep to the start and end of the matched string.
*/
public int
2017-04-25 03:28:38 +00:00
match_pattern(void *pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int notbol, int search_type)
2009-07-27 07:05:08 +00:00
{
int matched;
2012-06-26 20:38:53 +00:00
#if HAVE_GNU_REGEX
struct re_pattern_buffer *spattern = (struct re_pattern_buffer *) pattern;
#endif
2009-07-27 07:05:08 +00:00
#if HAVE_POSIX_REGCOMP
regex_t *spattern = (regex_t *) pattern;
#endif
#if HAVE_PCRE
pcre *spattern = (pcre *) pattern;
#endif
#if HAVE_RE_COMP
int spattern = (int) pattern;
#endif
#if HAVE_REGCMP
char *spattern = (char *) pattern;
#endif
#if HAVE_V8_REGCOMP
struct regexp *spattern = (struct regexp *) pattern;
#endif
2016-01-04 00:22:34 +00:00
*sp = *ep = NULL;
2012-06-26 20:38:53 +00:00
#if NO_REGEX
search_type |= SRCH_NO_REGEX;
#endif
2009-07-27 07:05:08 +00:00
if (search_type & SRCH_NO_REGEX)
matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
2011-05-09 18:30:23 +00:00
else
{
2012-06-26 20:38:53 +00:00
#if HAVE_GNU_REGEX
{
struct re_registers search_regs;
spattern->not_bol = notbol;
2016-01-04 00:22:34 +00:00
spattern->regs_allocated = REGS_UNALLOCATED;
2012-06-26 20:38:53 +00:00
matched = re_search(spattern, line, line_len, 0, line_len, &search_regs) >= 0;
if (matched)
{
*sp = line + search_regs.start[0];
*ep = line + search_regs.end[0];
}
}
#endif
2009-07-27 07:05:08 +00:00
#if HAVE_POSIX_REGCOMP
{
regmatch_t rm;
int flags = (notbol) ? REG_NOTBOL : 0;
2016-01-04 00:22:34 +00:00
#ifdef REG_STARTEND
flags |= REG_STARTEND;
rm.rm_so = 0;
rm.rm_eo = line_len;
#endif
2009-07-27 07:05:08 +00:00
matched = !regexec(spattern, line, 1, &rm, flags);
if (matched)
{
#ifndef __WATCOMC__
*sp = line + rm.rm_so;
*ep = line + rm.rm_eo;
#else
*sp = rm.rm_sp;
*ep = rm.rm_ep;
#endif
}
}
#endif
#if HAVE_PCRE
{
int flags = (notbol) ? PCRE_NOTBOL : 0;
int ovector[3];
matched = pcre_exec(spattern, NULL, line, line_len,
0, flags, ovector, 3) >= 0;
if (matched)
{
*sp = line + ovector[0];
*ep = line + ovector[1];
}
}
#endif
#if HAVE_RE_COMP
matched = (re_exec(line) == 1);
/*
* re_exec doesn't seem to provide a way to get the matched string.
*/
*sp = *ep = NULL;
#endif
#if HAVE_REGCMP
*ep = regex(spattern, line);
matched = (*ep != NULL);
if (matched)
*sp = __loc1;
#endif
#if HAVE_V8_REGCOMP
#if HAVE_REGEXEC2
matched = regexec2(spattern, line, notbol);
#else
matched = regexec(spattern, line);
#endif
if (matched)
{
*sp = spattern->startp[0];
*ep = spattern->endp[0];
}
#endif
2011-05-09 18:30:23 +00:00
}
2009-07-27 07:05:08 +00:00
matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
((search_type & SRCH_NO_MATCH) && !matched);
return (matched);
}