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