Merge from vendor branch BIND:
[dragonfly.git] / contrib / sendmail-8.13.4 / libsm / match.c
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 }