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