1 /* 2 * Copyright (C) 1984-2012 Mark Nudelman 3 * Modified for use with illumos by Garrett D'Amore. 4 * Copyright 2014 Garrett D'Amore <garrett@damore.org> 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 extern int less_is_more; 21 22 /* 23 * Compile a search pattern, for future use by match_pattern. 24 */ 25 static int 26 compile_pattern2(char *pattern, int search_type, regex_t **comp_pattern) 27 { 28 regex_t *comp; 29 30 if (search_type & SRCH_NO_REGEX) 31 return (0); 32 comp = ecalloc(1, sizeof (regex_t)); 33 if (regcomp(comp, pattern, less_is_more ? 0 : REGCOMP_FLAG)) { 34 free(comp); 35 error("Invalid pattern", NULL); 36 return (-1); 37 } 38 if (*comp_pattern != NULL) 39 regfree(*comp_pattern); 40 *comp_pattern = comp; 41 return (0); 42 } 43 44 /* 45 * Like compile_pattern2, but convert the pattern to lowercase if necessary. 46 */ 47 int 48 compile_pattern(char *pattern, int search_type, regex_t **comp_pattern) 49 { 50 char *cvt_pattern; 51 int result; 52 53 if (caseless != OPT_ONPLUS) { 54 cvt_pattern = pattern; 55 } else { 56 cvt_pattern = ecalloc(1, cvt_length(strlen(pattern))); 57 cvt_text(cvt_pattern, pattern, NULL, NULL, CVT_TO_LC); 58 } 59 result = compile_pattern2(cvt_pattern, search_type, comp_pattern); 60 if (cvt_pattern != pattern) 61 free(cvt_pattern); 62 return (result); 63 } 64 65 /* 66 * Forget that we have a compiled pattern. 67 */ 68 void 69 uncompile_pattern(regex_t **pattern) 70 { 71 if (*pattern != NULL) 72 regfree(*pattern); 73 *pattern = NULL; 74 } 75 76 /* 77 * Simple pattern matching function. 78 * It supports no metacharacters like *, etc. 79 */ 80 static int 81 match(char *pattern, int pattern_len, char *buf, int buf_len, 82 char **pfound, char **pend) 83 { 84 char *pp, *lp; 85 char *pattern_end = pattern + pattern_len; 86 char *buf_end = buf + buf_len; 87 88 for (; buf < buf_end; buf++) { 89 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 90 if (pp == pattern_end || lp == buf_end) 91 break; 92 if (pp == pattern_end) { 93 if (pfound != NULL) 94 *pfound = buf; 95 if (pend != NULL) 96 *pend = lp; 97 return (1); 98 } 99 } 100 return (0); 101 } 102 103 /* 104 * Perform a pattern match with the previously compiled pattern. 105 * Set sp and ep to the start and end of the matched string. 106 */ 107 int 108 match_pattern(void *pattern, char *tpattern, char *line, int line_len, 109 char **sp, char **ep, int notbol, int search_type) 110 { 111 int matched; 112 regex_t *spattern = (regex_t *)pattern; 113 114 if (search_type & SRCH_NO_REGEX) { 115 matched = match(tpattern, strlen(tpattern), line, line_len, 116 sp, ep); 117 } else { 118 regmatch_t rm; 119 int flags = (notbol) ? REG_NOTBOL : 0; 120 #ifdef REG_STARTEND 121 flags |= REG_STARTEND; 122 rm.rm_so = 0; 123 rm.rm_eo = line_len; 124 #endif 125 *sp = NULL; 126 *ep = NULL; 127 matched = !regexec(spattern, line, 1, &rm, flags); 128 if (matched) { 129 *sp = line + rm.rm_so; 130 *ep = line + rm.rm_eo; 131 } 132 } 133 matched = (!(search_type & SRCH_NO_MATCH) && matched) || 134 ((search_type & SRCH_NO_MATCH) && !matched); 135 return (matched); 136 } 137