xref: /openbsd-src/usr.bin/less/pattern.c (revision d37538d056dd056237a42ff11be4c4d5351ebc3c)
1a0ef22f9Sshadchin /*
226ad794dSshadchin  * Copyright (C) 1984-2012  Mark Nudelman
3b8c1323eSnicm  * Modified for use with illumos by Garrett D'Amore.
4b8c1323eSnicm  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5a0ef22f9Sshadchin  *
6a0ef22f9Sshadchin  * You may distribute under the terms of either the GNU General Public
7a0ef22f9Sshadchin  * License or the Less License, as specified in the README file.
8a0ef22f9Sshadchin  *
926ad794dSshadchin  * For more information, see the README file.
10a0ef22f9Sshadchin  */
11a0ef22f9Sshadchin 
12a0ef22f9Sshadchin /*
13a0ef22f9Sshadchin  * Routines to do pattern matching.
14a0ef22f9Sshadchin  */
15a0ef22f9Sshadchin 
16a0ef22f9Sshadchin #include "less.h"
17a0ef22f9Sshadchin #include "pattern.h"
18a0ef22f9Sshadchin 
19a0ef22f9Sshadchin extern int caseless;
204dc37c62Smillert extern int less_is_more;
21a0ef22f9Sshadchin 
22a0ef22f9Sshadchin /*
23a0ef22f9Sshadchin  * Compile a search pattern, for future use by match_pattern.
24a0ef22f9Sshadchin  */
25a0ef22f9Sshadchin static int
compile_pattern2(char * pattern,int search_type,regex_t ** comp_pattern)26171bb95eSnicm compile_pattern2(char *pattern, int search_type, regex_t **comp_pattern)
27a0ef22f9Sshadchin {
28171bb95eSnicm 	regex_t *comp;
29171bb95eSnicm 
3026ad794dSshadchin 	if (search_type & SRCH_NO_REGEX)
3126ad794dSshadchin 		return (0);
32171bb95eSnicm 	comp = ecalloc(1, sizeof (regex_t));
33171bb95eSnicm 	if (regcomp(comp, pattern, less_is_more ? 0 : REGCOMP_FLAG)) {
3426ad794dSshadchin 		free(comp);
35bf1039baSderaadt 		error("Invalid pattern", NULL);
3626ad794dSshadchin 		return (-1);
3726ad794dSshadchin 	}
38171bb95eSnicm 	if (*comp_pattern != NULL)
39171bb95eSnicm 		regfree(*comp_pattern);
40171bb95eSnicm 	*comp_pattern = comp;
41a0ef22f9Sshadchin 	return (0);
42a0ef22f9Sshadchin }
43a0ef22f9Sshadchin 
44a0ef22f9Sshadchin /*
45a0ef22f9Sshadchin  * Like compile_pattern2, but convert the pattern to lowercase if necessary.
46a0ef22f9Sshadchin  */
47171bb95eSnicm int
compile_pattern(char * pattern,int search_type,regex_t ** comp_pattern)48171bb95eSnicm compile_pattern(char *pattern, int search_type, regex_t **comp_pattern)
49a0ef22f9Sshadchin {
50a0ef22f9Sshadchin 	char *cvt_pattern;
51a0ef22f9Sshadchin 	int result;
52a0ef22f9Sshadchin 
53171bb95eSnicm 	if (caseless != OPT_ONPLUS) {
54a0ef22f9Sshadchin 		cvt_pattern = pattern;
55171bb95eSnicm 	} else {
56171bb95eSnicm 		cvt_pattern = ecalloc(1, cvt_length(strlen(pattern)));
57171bb95eSnicm 		cvt_text(cvt_pattern, pattern, NULL, NULL, CVT_TO_LC);
58a0ef22f9Sshadchin 	}
59a0ef22f9Sshadchin 	result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
60a0ef22f9Sshadchin 	if (cvt_pattern != pattern)
61a0ef22f9Sshadchin 		free(cvt_pattern);
62a0ef22f9Sshadchin 	return (result);
63a0ef22f9Sshadchin }
64a0ef22f9Sshadchin 
65a0ef22f9Sshadchin /*
66a0ef22f9Sshadchin  * Forget that we have a compiled pattern.
67a0ef22f9Sshadchin  */
68171bb95eSnicm void
uncompile_pattern(regex_t ** pattern)69171bb95eSnicm uncompile_pattern(regex_t **pattern)
70a0ef22f9Sshadchin {
71171bb95eSnicm 	if (*pattern != NULL)
72171bb95eSnicm 		regfree(*pattern);
73171bb95eSnicm 	*pattern = NULL;
74a0ef22f9Sshadchin }
75a0ef22f9Sshadchin 
76a0ef22f9Sshadchin /*
77a0ef22f9Sshadchin  * Simple pattern matching function.
78a0ef22f9Sshadchin  * It supports no metacharacters like *, etc.
79a0ef22f9Sshadchin  */
80a0ef22f9Sshadchin static int
match(char * pattern,int pattern_len,char * buf,int buf_len,char ** pfound,char ** pend)81171bb95eSnicm match(char *pattern, int pattern_len, char *buf, int buf_len,
82171bb95eSnicm     char **pfound, char **pend)
83a0ef22f9Sshadchin {
84171bb95eSnicm 	char *pp, *lp;
85171bb95eSnicm 	char *pattern_end = pattern + pattern_len;
86171bb95eSnicm 	char *buf_end = buf + buf_len;
87a0ef22f9Sshadchin 
88171bb95eSnicm 	for (; buf < buf_end; buf++) {
89a0ef22f9Sshadchin 		for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
90a0ef22f9Sshadchin 			if (pp == pattern_end || lp == buf_end)
91a0ef22f9Sshadchin 				break;
92171bb95eSnicm 		if (pp == pattern_end) {
93a0ef22f9Sshadchin 			if (pfound != NULL)
94a0ef22f9Sshadchin 				*pfound = buf;
95a0ef22f9Sshadchin 			if (pend != NULL)
96a0ef22f9Sshadchin 				*pend = lp;
97a0ef22f9Sshadchin 			return (1);
98a0ef22f9Sshadchin 		}
99a0ef22f9Sshadchin 	}
100a0ef22f9Sshadchin 	return (0);
101a0ef22f9Sshadchin }
102a0ef22f9Sshadchin 
103a0ef22f9Sshadchin /*
104a0ef22f9Sshadchin  * Perform a pattern match with the previously compiled pattern.
105a0ef22f9Sshadchin  * Set sp and ep to the start and end of the matched string.
106a0ef22f9Sshadchin  */
107171bb95eSnicm int
match_pattern(void * pattern,char * tpattern,char * line,int line_len,char ** sp,char ** ep,int notbol,int search_type)108171bb95eSnicm match_pattern(void *pattern, char *tpattern, char *line, int line_len,
109171bb95eSnicm     char **sp, char **ep, int notbol, int search_type)
110a0ef22f9Sshadchin {
111a0ef22f9Sshadchin 	int matched;
112a0ef22f9Sshadchin 	regex_t *spattern = (regex_t *)pattern;
113a0ef22f9Sshadchin 
114171bb95eSnicm 	if (search_type & SRCH_NO_REGEX) {
115171bb95eSnicm 		matched = match(tpattern, strlen(tpattern), line, line_len,
116171bb95eSnicm 		    sp, ep);
117171bb95eSnicm 	} else {
118a0ef22f9Sshadchin 		regmatch_t rm;
119a0ef22f9Sshadchin 		int flags = (notbol) ? REG_NOTBOL : 0;
120d2a22d61Sguenther #ifdef	REG_STARTEND
121d2a22d61Sguenther 		flags |= REG_STARTEND;
122d2a22d61Sguenther 		rm.rm_so = 0;
123d2a22d61Sguenther 		rm.rm_eo = line_len;
124d2a22d61Sguenther #endif
125*d37538d0Santon 		*sp = NULL;
126*d37538d0Santon 		*ep = NULL;
127a0ef22f9Sshadchin 		matched = !regexec(spattern, line, 1, &rm, flags);
128171bb95eSnicm 		if (matched) {
129a0ef22f9Sshadchin 			*sp = line + rm.rm_so;
130a0ef22f9Sshadchin 			*ep = line + rm.rm_eo;
131a0ef22f9Sshadchin 		}
132a0ef22f9Sshadchin 	}
133a0ef22f9Sshadchin 	matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
134a0ef22f9Sshadchin 	    ((search_type & SRCH_NO_MATCH) && !matched);
135a0ef22f9Sshadchin 	return (matched);
136a0ef22f9Sshadchin }
137