Home | History | Annotate | Line # | Download | only in dist
pattern.c revision 1.3
      1  1.3  tron /*	$NetBSD: pattern.c,v 1.3 2013/09/04 19:44:21 tron Exp $	*/
      2  1.1  tron 
      3  1.1  tron /*
      4  1.3  tron  * Copyright (C) 1984-2012  Mark Nudelman
      5  1.1  tron  *
      6  1.1  tron  * You may distribute under the terms of either the GNU General Public
      7  1.1  tron  * License or the Less License, as specified in the README file.
      8  1.1  tron  *
      9  1.3  tron  * For more information, see the README file.
     10  1.1  tron  */
     11  1.1  tron 
     12  1.1  tron /*
     13  1.1  tron  * Routines to do pattern matching.
     14  1.1  tron  */
     15  1.1  tron 
     16  1.1  tron #include "less.h"
     17  1.1  tron #include "pattern.h"
     18  1.1  tron 
     19  1.1  tron extern int caseless;
     20  1.1  tron 
     21  1.1  tron /*
     22  1.1  tron  * Compile a search pattern, for future use by match_pattern.
     23  1.1  tron  */
     24  1.1  tron 	static int
     25  1.1  tron compile_pattern2(pattern, search_type, comp_pattern)
     26  1.1  tron 	char *pattern;
     27  1.1  tron 	int search_type;
     28  1.1  tron 	void **comp_pattern;
     29  1.1  tron {
     30  1.3  tron 	if (search_type & SRCH_NO_REGEX)
     31  1.3  tron 		return (0);
     32  1.3  tron   {
     33  1.3  tron #if HAVE_GNU_REGEX
     34  1.3  tron 	struct re_pattern_buffer *comp = (struct re_pattern_buffer *)
     35  1.3  tron 		ecalloc(1, sizeof(struct re_pattern_buffer));
     36  1.3  tron 	struct re_pattern_buffer **pcomp =
     37  1.3  tron 		(struct re_pattern_buffer **) comp_pattern;
     38  1.3  tron 	re_set_syntax(RE_SYNTAX_POSIX_EXTENDED);
     39  1.3  tron 	if (re_compile_pattern(pattern, strlen(pattern), comp))
     40  1.1  tron 	{
     41  1.3  tron 		free(comp);
     42  1.3  tron 		error("Invalid pattern", NULL_PARG);
     43  1.3  tron 		return (-1);
     44  1.3  tron 	}
     45  1.3  tron 	if (*pcomp != NULL)
     46  1.3  tron 		regfree(*pcomp);
     47  1.3  tron 	*pcomp = comp;
     48  1.3  tron #endif
     49  1.1  tron #if HAVE_POSIX_REGCOMP
     50  1.3  tron 	regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
     51  1.3  tron 	regex_t **pcomp = (regex_t **) comp_pattern;
     52  1.3  tron 	if (regcomp(comp, pattern, REGCOMP_FLAG))
     53  1.3  tron 	{
     54  1.3  tron 		free(comp);
     55  1.3  tron 		error("Invalid pattern", NULL_PARG);
     56  1.3  tron 		return (-1);
     57  1.3  tron 	}
     58  1.3  tron 	if (*pcomp != NULL)
     59  1.3  tron 		regfree(*pcomp);
     60  1.3  tron 	*pcomp = comp;
     61  1.1  tron #endif
     62  1.1  tron #if HAVE_PCRE
     63  1.3  tron 	pcre *comp;
     64  1.3  tron 	pcre **pcomp = (pcre **) comp_pattern;
     65  1.3  tron 	constant char *errstring;
     66  1.3  tron 	int erroffset;
     67  1.3  tron 	PARG parg;
     68  1.3  tron 	comp = pcre_compile(pattern, 0,
     69  1.3  tron 			&errstring, &erroffset, NULL);
     70  1.3  tron 	if (comp == NULL)
     71  1.3  tron 	{
     72  1.3  tron 		parg.p_string = (char *) errstring;
     73  1.3  tron 		error("%s", &parg);
     74  1.3  tron 		return (-1);
     75  1.3  tron 	}
     76  1.3  tron 	*pcomp = comp;
     77  1.1  tron #endif
     78  1.1  tron #if HAVE_RE_COMP
     79  1.3  tron 	PARG parg;
     80  1.3  tron 	int *pcomp = (int *) comp_pattern;
     81  1.3  tron 	if ((parg.p_string = re_comp(pattern)) != NULL)
     82  1.3  tron 	{
     83  1.3  tron 		error("%s", &parg);
     84  1.3  tron 		return (-1);
     85  1.3  tron 	}
     86  1.3  tron 	*pcomp = 1;
     87  1.1  tron #endif
     88  1.1  tron #if HAVE_REGCMP
     89  1.3  tron 	char *comp;
     90  1.3  tron 	char **pcomp = (char **) comp_pattern;
     91  1.3  tron 	if ((comp = regcmp(pattern, 0)) == NULL)
     92  1.3  tron 	{
     93  1.3  tron 		error("Invalid pattern", NULL_PARG);
     94  1.3  tron 		return (-1);
     95  1.3  tron 	}
     96  1.3  tron 	if (pcomp != NULL)
     97  1.3  tron 		free(*pcomp);
     98  1.3  tron 	*pcomp = comp;
     99  1.1  tron #endif
    100  1.1  tron #if HAVE_V8_REGCOMP
    101  1.3  tron 	struct regexp *comp;
    102  1.3  tron 	struct regexp **pcomp = (struct regexp **) comp_pattern;
    103  1.3  tron 	if ((comp = regcomp(pattern)) == NULL)
    104  1.3  tron 	{
    105  1.3  tron 		/*
    106  1.3  tron 		 * regcomp has already printed an error message
    107  1.3  tron 		 * via regerror().
    108  1.3  tron 		 */
    109  1.3  tron 		return (-1);
    110  1.3  tron 	}
    111  1.3  tron 	if (*pcomp != NULL)
    112  1.3  tron 		free(*pcomp);
    113  1.3  tron 	*pcomp = comp;
    114  1.1  tron #endif
    115  1.3  tron   }
    116  1.1  tron 	return (0);
    117  1.1  tron }
    118  1.1  tron 
    119  1.1  tron /*
    120  1.1  tron  * Like compile_pattern2, but convert the pattern to lowercase if necessary.
    121  1.1  tron  */
    122  1.1  tron 	public int
    123  1.1  tron compile_pattern(pattern, search_type, comp_pattern)
    124  1.1  tron 	char *pattern;
    125  1.1  tron 	int search_type;
    126  1.1  tron 	void **comp_pattern;
    127  1.1  tron {
    128  1.1  tron 	char *cvt_pattern;
    129  1.1  tron 	int result;
    130  1.1  tron 
    131  1.1  tron 	if (caseless != OPT_ONPLUS)
    132  1.1  tron 		cvt_pattern = pattern;
    133  1.1  tron 	else
    134  1.1  tron 	{
    135  1.1  tron 		cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
    136  1.1  tron 		cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC);
    137  1.1  tron 	}
    138  1.1  tron 	result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
    139  1.1  tron 	if (cvt_pattern != pattern)
    140  1.1  tron 		free(cvt_pattern);
    141  1.1  tron 	return (result);
    142  1.1  tron }
    143  1.1  tron 
    144  1.1  tron /*
    145  1.1  tron  * Forget that we have a compiled pattern.
    146  1.1  tron  */
    147  1.1  tron 	public void
    148  1.1  tron uncompile_pattern(pattern)
    149  1.1  tron 	void **pattern;
    150  1.1  tron {
    151  1.3  tron #if HAVE_GNU_REGEX
    152  1.3  tron 	struct re_pattern_buffer **pcomp = (struct re_pattern_buffer **) pattern;
    153  1.3  tron 	if (*pcomp != NULL)
    154  1.3  tron 		regfree(*pcomp);
    155  1.3  tron 	*pcomp = NULL;
    156  1.3  tron #endif
    157  1.1  tron #if HAVE_POSIX_REGCOMP
    158  1.1  tron 	regex_t **pcomp = (regex_t **) pattern;
    159  1.1  tron 	if (*pcomp != NULL)
    160  1.1  tron 		regfree(*pcomp);
    161  1.1  tron 	*pcomp = NULL;
    162  1.1  tron #endif
    163  1.1  tron #if HAVE_PCRE
    164  1.1  tron 	pcre **pcomp = (pcre **) pattern;
    165  1.1  tron 	if (*pcomp != NULL)
    166  1.1  tron 		pcre_free(*pcomp);
    167  1.1  tron 	*pcomp = NULL;
    168  1.1  tron #endif
    169  1.1  tron #if HAVE_RE_COMP
    170  1.1  tron 	int *pcomp = (int *) pattern;
    171  1.1  tron 	*pcomp = 0;
    172  1.1  tron #endif
    173  1.1  tron #if HAVE_REGCMP
    174  1.1  tron 	char **pcomp = (char **) pattern;
    175  1.1  tron 	if (*pcomp != NULL)
    176  1.1  tron 		free(*pcomp);
    177  1.1  tron 	*pcomp = NULL;
    178  1.1  tron #endif
    179  1.1  tron #if HAVE_V8_REGCOMP
    180  1.1  tron 	struct regexp **pcomp = (struct regexp **) pattern;
    181  1.1  tron 	if (*pcomp != NULL)
    182  1.1  tron 		free(*pcomp);
    183  1.1  tron 	*pcomp = NULL;
    184  1.1  tron #endif
    185  1.1  tron }
    186  1.1  tron 
    187  1.1  tron /*
    188  1.1  tron  * Is a compiled pattern null?
    189  1.1  tron  */
    190  1.1  tron 	public int
    191  1.1  tron is_null_pattern(pattern)
    192  1.1  tron 	void *pattern;
    193  1.1  tron {
    194  1.3  tron #if HAVE_GNU_REGEX
    195  1.3  tron 	return (pattern == NULL);
    196  1.3  tron #endif
    197  1.1  tron #if HAVE_POSIX_REGCOMP
    198  1.1  tron 	return (pattern == NULL);
    199  1.1  tron #endif
    200  1.1  tron #if HAVE_PCRE
    201  1.1  tron 	return (pattern == NULL);
    202  1.1  tron #endif
    203  1.1  tron #if HAVE_RE_COMP
    204  1.1  tron 	return (pattern == 0);
    205  1.1  tron #endif
    206  1.1  tron #if HAVE_REGCMP
    207  1.1  tron 	return (pattern == NULL);
    208  1.1  tron #endif
    209  1.1  tron #if HAVE_V8_REGCOMP
    210  1.1  tron 	return (pattern == NULL);
    211  1.1  tron #endif
    212  1.1  tron }
    213  1.1  tron 
    214  1.1  tron /*
    215  1.1  tron  * Simple pattern matching function.
    216  1.1  tron  * It supports no metacharacters like *, etc.
    217  1.1  tron  */
    218  1.1  tron 	static int
    219  1.1  tron match(pattern, pattern_len, buf, buf_len, pfound, pend)
    220  1.1  tron 	char *pattern;
    221  1.1  tron 	int pattern_len;
    222  1.1  tron 	char *buf;
    223  1.1  tron 	int buf_len;
    224  1.1  tron 	char **pfound, **pend;
    225  1.1  tron {
    226  1.1  tron 	register char *pp, *lp;
    227  1.1  tron 	register char *pattern_end = pattern + pattern_len;
    228  1.1  tron 	register char *buf_end = buf + buf_len;
    229  1.1  tron 
    230  1.1  tron 	for ( ;  buf < buf_end;  buf++)
    231  1.1  tron 	{
    232  1.1  tron 		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
    233  1.1  tron 			if (pp == pattern_end || lp == buf_end)
    234  1.1  tron 				break;
    235  1.1  tron 		if (pp == pattern_end)
    236  1.1  tron 		{
    237  1.1  tron 			if (pfound != NULL)
    238  1.1  tron 				*pfound = buf;
    239  1.1  tron 			if (pend != NULL)
    240  1.1  tron 				*pend = lp;
    241  1.1  tron 			return (1);
    242  1.1  tron 		}
    243  1.1  tron 	}
    244  1.1  tron 	return (0);
    245  1.1  tron }
    246  1.1  tron 
    247  1.1  tron /*
    248  1.1  tron  * Perform a pattern match with the previously compiled pattern.
    249  1.1  tron  * Set sp and ep to the start and end of the matched string.
    250  1.1  tron  */
    251  1.1  tron 	public int
    252  1.1  tron match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type)
    253  1.1  tron 	void *pattern;
    254  1.1  tron 	char *tpattern;
    255  1.1  tron 	char *line;
    256  1.1  tron 	int line_len;
    257  1.1  tron 	char **sp;
    258  1.1  tron 	char **ep;
    259  1.1  tron 	int notbol;
    260  1.1  tron 	int search_type;
    261  1.1  tron {
    262  1.1  tron 	int matched;
    263  1.3  tron #if HAVE_GNU_REGEX
    264  1.3  tron 	struct re_pattern_buffer *spattern = (struct re_pattern_buffer *) pattern;
    265  1.3  tron #endif
    266  1.1  tron #if HAVE_POSIX_REGCOMP
    267  1.1  tron 	regex_t *spattern = (regex_t *) pattern;
    268  1.1  tron #endif
    269  1.1  tron #if HAVE_PCRE
    270  1.1  tron 	pcre *spattern = (pcre *) pattern;
    271  1.1  tron #endif
    272  1.1  tron #if HAVE_RE_COMP
    273  1.1  tron 	int spattern = (int) pattern;
    274  1.1  tron #endif
    275  1.1  tron #if HAVE_REGCMP
    276  1.1  tron 	char *spattern = (char *) pattern;
    277  1.1  tron #endif
    278  1.1  tron #if HAVE_V8_REGCOMP
    279  1.1  tron 	struct regexp *spattern = (struct regexp *) pattern;
    280  1.1  tron #endif
    281  1.1  tron 
    282  1.3  tron #if NO_REGEX
    283  1.3  tron 	search_type |= SRCH_NO_REGEX;
    284  1.3  tron #endif
    285  1.1  tron 	if (search_type & SRCH_NO_REGEX)
    286  1.1  tron 		matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
    287  1.1  tron 	else
    288  1.1  tron 	{
    289  1.3  tron #if HAVE_GNU_REGEX
    290  1.3  tron 	{
    291  1.3  tron 		struct re_registers search_regs;
    292  1.3  tron 		regoff_t *starts = (regoff_t *) ecalloc(1, sizeof (regoff_t));
    293  1.3  tron 		regoff_t *ends = (regoff_t *) ecalloc(1, sizeof (regoff_t));
    294  1.3  tron 		spattern->not_bol = notbol;
    295  1.3  tron 		re_set_registers(spattern, &search_regs, 1, starts, ends);
    296  1.3  tron 		matched = re_search(spattern, line, line_len, 0, line_len, &search_regs) >= 0;
    297  1.3  tron 		if (matched)
    298  1.3  tron 		{
    299  1.3  tron 			*sp = line + search_regs.start[0];
    300  1.3  tron 			*ep = line + search_regs.end[0];
    301  1.3  tron 		}
    302  1.3  tron 		free(starts);
    303  1.3  tron 		free(ends);
    304  1.3  tron 	}
    305  1.3  tron #endif
    306  1.1  tron #if HAVE_POSIX_REGCOMP
    307  1.1  tron 	{
    308  1.1  tron 		regmatch_t rm;
    309  1.1  tron 		int flags = (notbol) ? REG_NOTBOL : 0;
    310  1.1  tron 		matched = !regexec(spattern, line, 1, &rm, flags);
    311  1.1  tron 		if (matched)
    312  1.1  tron 		{
    313  1.1  tron #ifndef __WATCOMC__
    314  1.1  tron 			*sp = line + rm.rm_so;
    315  1.1  tron 			*ep = line + rm.rm_eo;
    316  1.1  tron #else
    317  1.1  tron 			*sp = rm.rm_sp;
    318  1.1  tron 			*ep = rm.rm_ep;
    319  1.1  tron #endif
    320  1.1  tron 		}
    321  1.1  tron 	}
    322  1.1  tron #endif
    323  1.1  tron #if HAVE_PCRE
    324  1.1  tron 	{
    325  1.1  tron 		int flags = (notbol) ? PCRE_NOTBOL : 0;
    326  1.1  tron 		int ovector[3];
    327  1.1  tron 		matched = pcre_exec(spattern, NULL, line, line_len,
    328  1.1  tron 			0, flags, ovector, 3) >= 0;
    329  1.1  tron 		if (matched)
    330  1.1  tron 		{
    331  1.1  tron 			*sp = line + ovector[0];
    332  1.1  tron 			*ep = line + ovector[1];
    333  1.1  tron 		}
    334  1.1  tron 	}
    335  1.1  tron #endif
    336  1.1  tron #if HAVE_RE_COMP
    337  1.1  tron 	matched = (re_exec(line) == 1);
    338  1.1  tron 	/*
    339  1.1  tron 	 * re_exec doesn't seem to provide a way to get the matched string.
    340  1.1  tron 	 */
    341  1.1  tron 	*sp = *ep = NULL;
    342  1.1  tron #endif
    343  1.1  tron #if HAVE_REGCMP
    344  1.1  tron 	*ep = regex(spattern, line);
    345  1.1  tron 	matched = (*ep != NULL);
    346  1.1  tron 	if (matched)
    347  1.1  tron 		*sp = __loc1;
    348  1.1  tron #endif
    349  1.1  tron #if HAVE_V8_REGCOMP
    350  1.1  tron #if HAVE_REGEXEC2
    351  1.1  tron 	matched = regexec2(spattern, line, notbol);
    352  1.1  tron #else
    353  1.1  tron 	matched = regexec(spattern, line);
    354  1.1  tron #endif
    355  1.1  tron 	if (matched)
    356  1.1  tron 	{
    357  1.1  tron 		*sp = spattern->startp[0];
    358  1.1  tron 		*ep = spattern->endp[0];
    359  1.1  tron 	}
    360  1.1  tron #endif
    361  1.1  tron 	}
    362  1.1  tron 	matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
    363  1.1  tron 			((search_type & SRCH_NO_MATCH) && !matched);
    364  1.1  tron 	return (matched);
    365  1.1  tron }
    366  1.1  tron 
    367