1 /*
2 * Copyright (C) 1984-2012 Mark Nudelman
3 * Modified for use with illumos by Garrett D'Amore.
4 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
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 extern int less_is_more;
21
22 /*
23 * Compile a search pattern, for future use by match_pattern.
24 */
25 static int
compile_pattern2(char * pattern,int search_type,regex_t ** comp_pattern)26 compile_pattern2(char *pattern, int search_type, regex_t **comp_pattern)
27 {
28 regex_t *comp;
29
30 if (search_type & SRCH_NO_REGEX)
31 return (0);
32 comp = ecalloc(1, sizeof (regex_t));
33 if (regcomp(comp, pattern, less_is_more ? 0 : REGCOMP_FLAG)) {
34 free(comp);
35 error("Invalid pattern", NULL);
36 return (-1);
37 }
38 if (*comp_pattern != NULL)
39 regfree(*comp_pattern);
40 *comp_pattern = comp;
41 return (0);
42 }
43
44 /*
45 * Like compile_pattern2, but convert the pattern to lowercase if necessary.
46 */
47 int
compile_pattern(char * pattern,int search_type,regex_t ** comp_pattern)48 compile_pattern(char *pattern, int search_type, regex_t **comp_pattern)
49 {
50 char *cvt_pattern;
51 int result;
52
53 if (caseless != OPT_ONPLUS) {
54 cvt_pattern = pattern;
55 } else {
56 cvt_pattern = ecalloc(1, cvt_length(strlen(pattern)));
57 cvt_text(cvt_pattern, pattern, NULL, NULL, CVT_TO_LC);
58 }
59 result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
60 if (cvt_pattern != pattern)
61 free(cvt_pattern);
62 return (result);
63 }
64
65 /*
66 * Forget that we have a compiled pattern.
67 */
68 void
uncompile_pattern(regex_t ** pattern)69 uncompile_pattern(regex_t **pattern)
70 {
71 if (*pattern != NULL)
72 regfree(*pattern);
73 *pattern = NULL;
74 }
75
76 /*
77 * Simple pattern matching function.
78 * It supports no metacharacters like *, etc.
79 */
80 static int
match(char * pattern,int pattern_len,char * buf,int buf_len,char ** pfound,char ** pend)81 match(char *pattern, int pattern_len, char *buf, int buf_len,
82 char **pfound, char **pend)
83 {
84 char *pp, *lp;
85 char *pattern_end = pattern + pattern_len;
86 char *buf_end = buf + buf_len;
87
88 for (; buf < buf_end; buf++) {
89 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
90 if (pp == pattern_end || lp == buf_end)
91 break;
92 if (pp == pattern_end) {
93 if (pfound != NULL)
94 *pfound = buf;
95 if (pend != NULL)
96 *pend = lp;
97 return (1);
98 }
99 }
100 return (0);
101 }
102
103 /*
104 * Perform a pattern match with the previously compiled pattern.
105 * Set sp and ep to the start and end of the matched string.
106 */
107 int
match_pattern(void * pattern,char * tpattern,char * line,int line_len,char ** sp,char ** ep,int notbol,int search_type)108 match_pattern(void *pattern, char *tpattern, char *line, int line_len,
109 char **sp, char **ep, int notbol, int search_type)
110 {
111 int matched;
112 regex_t *spattern = (regex_t *)pattern;
113
114 if (search_type & SRCH_NO_REGEX) {
115 matched = match(tpattern, strlen(tpattern), line, line_len,
116 sp, ep);
117 } else {
118 regmatch_t rm;
119 int flags = (notbol) ? REG_NOTBOL : 0;
120 #ifdef REG_STARTEND
121 flags |= REG_STARTEND;
122 rm.rm_so = 0;
123 rm.rm_eo = line_len;
124 #endif
125 *sp = NULL;
126 *ep = NULL;
127 matched = !regexec(spattern, line, 1, &rm, flags);
128 if (matched) {
129 *sp = line + rm.rm_so;
130 *ep = line + rm.rm_eo;
131 }
132 }
133 matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
134 ((search_type & SRCH_NO_MATCH) && !matched);
135 return (matched);
136 }
137