1 /* $NetBSD: pattern.c,v 1.3 2013/09/04 19:44:21 tron 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