xref: /illumos-gate/usr/src/cmd/sendmail/libsm/match.c (revision bb9b6b3f59b8820022416cea99b49c50fef6e391)
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