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