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