match.c revision 98122
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> 12SM_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 44bool 45sm_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