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