1 /* 2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11 #include <sm/gen.h> 12 SM_RCSID("@(#)$Id: match.c,v 1.10 2001/09/11 04:04:48 gshapiro Exp $") 13 14 #include <sm/string.h> 15 16 /* 17 ** SM_MATCH -- Match a character string against a glob pattern. 18 ** 19 ** Parameters: 20 ** str -- string. 21 ** par -- pattern to find in str. 22 ** 23 ** Returns: 24 ** true on match, false on non-match. 25 ** 26 ** A pattern consists of normal characters, which match themselves, 27 ** and meta-sequences. A * matches any sequence of characters. 28 ** A ? matches any single character. A [ introduces a character class. 29 ** A ] marks the end of a character class; if the ] is missing then 30 ** the [ matches itself rather than introducing a character class. 31 ** A character class matches any of the characters between the brackets. 32 ** The range of characters from X to Y inclusive is written X-Y. 33 ** If the first character after the [ is ! then the character class is 34 ** complemented. 35 ** 36 ** To include a ] in a character class, make it the first character 37 ** listed (after the !, if any). To include a -, make it the first 38 ** character listed (after the !, if any) or the last character. 39 ** It is impossible for a ] to be the final character in a range. 40 ** For glob patterns that literally match "*", "?" or "[", 41 ** use [*], [?] or [[]. 42 */ 43 44 bool 45 sm_match(str, pat) 46 const char *str; 47 const char *pat; 48 { 49 bool ccnot, ccmatch, ccfirst; 50 const char *ccstart; 51 char c, c2; 52 53 for (;;) 54 { 55 switch (*pat) 56 { 57 case '\0': 58 return *str == '\0'; 59 case '?': 60 if (*str == '\0') 61 return false; 62 ++pat; 63 ++str; 64 continue; 65 case '*': 66 ++pat; 67 if (*pat == '\0') 68 { 69 /* optimize case of trailing '*' */ 70 return true; 71 } 72 for (;;) 73 { 74 if (sm_match(pat, str)) 75 return true; 76 if (*str == '\0') 77 return false; 78 ++str; 79 } 80 /* NOTREACHED */ 81 case '[': 82 ccstart = pat++; 83 ccnot = false; 84 if (*pat == '!') 85 { 86 ccnot = true; 87 ++pat; 88 } 89 ccmatch = false; 90 ccfirst = true; 91 for (;;) 92 { 93 if (*pat == '\0') 94 { 95 pat = ccstart; 96 goto defl; 97 } 98 if (*pat == ']' && !ccfirst) 99 break; 100 c = *pat++; 101 ccfirst = false; 102 if (*pat == '-' && pat[1] != ']') 103 { 104 ++pat; 105 if (*pat == '\0') 106 { 107 pat = ccstart; 108 goto defl; 109 } 110 c2 = *pat++; 111 if (*str >= c && *str <= c2) 112 ccmatch = true; 113 } 114 else 115 { 116 if (*str == c) 117 ccmatch = true; 118 } 119 } 120 if (ccmatch ^ ccnot) 121 { 122 ++pat; 123 ++str; 124 } 125 else 126 return false; 127 continue; 128 default: 129 defl: 130 if (*pat != *str) 131 return false; 132 ++pat; 133 ++str; 134 continue; 135 } 136 } 137 } 138