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