/*
* Copyright (C) 1984-2023 Mark Nudelman
*
* 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.
*/
/*
* Routines to do pattern matching.
*/
#include "less.h"
extern int caseless;
extern int is_caseless;
extern int utf_mode;
/*
* Like compile_pattern2, but convert the pattern to lowercase if necessary.
*/
public int compile_pattern(char *pattern, int search_type, int show_error, PATTERN_TYPE *comp_pattern)
{
char *cvt_pattern;
int result;
/*
* Perform a pattern match with the previously compiled pattern.
* Set sp[0] and ep[0] to the start and end of the matched string.
* Set sp[i] and ep[i] to the start and end of the i-th matched subpattern.
* Subpatterns are defined by parentheses in the regex language.
*/
static int match_pattern1(PATTERN_TYPE pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int nsp, int notbol, int search_type)
{
int matched;
#if NO_REGEX
search_type |= SRCH_NO_REGEX;
#endif
if (search_type & SRCH_NO_REGEX)
matched = match(tpattern, strlen(tpattern), line, line_len, &sp, &ep, nsp);
else
{
#if HAVE_GNU_REGEX
{
struct re_registers search_regs;
pattern->not_bol = notbol;
pattern->regs_allocated = REGS_UNALLOCATED;
matched = re_search(pattern, line, line_len, 0, line_len, &search_regs) >= 0;
if (matched)
{
*sp++ = line + search_regs.start[0];
*ep++ = line + search_regs.end[0];
}
}
#endif
#if HAVE_POSIX_REGCOMP
{
#define RM_COUNT (NUM_SEARCH_COLORS+2)
regmatch_t rm[RM_COUNT];
int flags = (notbol) ? REG_NOTBOL : 0;
#ifdef REG_STARTEND
flags |= REG_STARTEND;
rm[0].rm_so = 0;
rm[0].rm_eo = line_len;
#endif
matched = !regexec(pattern, line, RM_COUNT, rm, flags);
if (matched)
{
int i;
int ecount;
for (ecount = RM_COUNT; ecount > 0; ecount--)
if (rm[ecount-1].rm_so >= 0)
break;
if (ecount >= nsp)
ecount = nsp-1;
for (i = 0; i < ecount; i++)
{
if (rm[i].rm_so < 0)
{
*sp++ = *ep++ = line;
} else
{
#ifndef __WATCOMC__
*sp++ = line + rm[i].rm_so;
*ep++ = line + rm[i].rm_eo;
#else
*sp++ = rm[i].rm_sp;
*ep++ = rm[i].rm_ep;
#endif
}
}
}
}
#endif
#if HAVE_PCRE
{
#define OVECTOR_COUNT ((3*NUM_SEARCH_COLORS)+3)
int ovector[OVECTOR_COUNT];
int flags = (notbol) ? PCRE_NOTBOL : 0;
int i;
int ecount;
int mcount = pcre_exec(pattern, NULL, line, line_len,
0, flags, ovector, OVECTOR_COUNT);
matched = (mcount > 0);
ecount = nsp-1;
if (ecount > mcount) ecount = mcount;
for (i = 0; i < ecount*2; )
{
if (ovector[i] < 0 || ovector[i+1] < 0)
{
*sp++ = *ep++ = line;
i += 2;
} else
{
*sp++ = line + ovector[i++];
*ep++ = line + ovector[i++];
}
}
}
#endif
#if HAVE_PCRE2
{
int flags = (notbol) ? PCRE2_NOTBOL : 0;
pcre2_match_data *md = pcre2_match_data_create(nsp-1, NULL);
int mcount = pcre2_match(pattern, (PCRE2_SPTR)line, line_len,
0, flags, md, NULL);
matched = (mcount > 0);
if (matched)
{
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(md);
int i;
int ecount = nsp-1;
if (ecount > mcount) ecount = mcount;
for (i = 0; i < ecount*2; )
{
if (ovector[i] < 0 || ovector[i+1] < 0)
{
*sp++ = *ep++ = line;
i += 2;
} else
{
*sp++ = line + ovector[i++];
*ep++ = line + ovector[i++];
}
}
}
pcre2_match_data_free(md);
}
#endif
#if HAVE_RE_COMP
matched = (re_exec(line) == 1);
/*
* re_exec doesn't seem to provide a way to get the matched string.
*/
#endif
#if HAVE_REGCMP
matched = ((*ep++ = regex(pattern, line)) != NULL);
if (matched)
*sp++ = __loc1;
#endif
#if HAVE_V8_REGCOMP
#if HAVE_REGEXEC2
matched = regexec2(pattern, line, notbol);
#else
matched = regexec(pattern, line);
#endif
if (matched)
{
*sp++ = pattern->startp[0];
*ep++ = pattern->endp[0];
}
#endif
}
*sp = *ep = NULL;
matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
((search_type & SRCH_NO_MATCH) && !matched);
return (matched);
}
public int match_pattern(PATTERN_TYPE pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int nsp, int notbol, int search_type)
{
int matched = match_pattern1(pattern, tpattern, line, line_len, sp, ep, nsp, notbol, search_type);
int i;
for (i = 1; i <= NUM_SEARCH_COLORS; i++)
{
if ((search_type & SRCH_SUBSEARCH(i)) && ep[i] == sp[i])
matched = 0;
}
return matched;
}