1 /*****************************************************************************/
5 /* Unix shell like pattern matching */
9 /* (C) 2002 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
43 /*****************************************************************************/
44 /* Character bit set implementation */
45 /*****************************************************************************/
49 typedef unsigned char CharSet[32]; /* 256 bits */
53 /* Clear a character set */
54 #define CS_CLEAR(CS) memset (CS, 0, sizeof (CharSet))
56 /* Set all characters in the set */
57 #define CS_SETALL(CS) memset (CS, 0xFF, sizeof (CharSet))
59 /* Add one char to the set */
60 #define CS_ADD(CS, C) ((CS)[(C) >> 3] |= (0x01 << ((C) & 0x07)))
62 /* Check if a character is a member of the set */
63 #define CS_CONTAINS(CS, C) ((CS)[(C) >> 3] & (0x01 << ((C) & 0x07)))
65 /* Invert a character set */
66 #define CS_INVERT(CS) \
69 for (I = 0; I < sizeof (CharSet); ++I) { \
78 /*****************************************************************************/
80 /*****************************************************************************/
84 /* Escape character */
85 #define ESCAPE_CHAR '\\'
87 /* Utility macro used in RecursiveMatch */
88 #define IncPattern() Pattern++; \
89 if (*Pattern == '\0') { \
95 static int RealChar (const unsigned char* Pattern)
96 /* Return the next character from Pattern. If the next character is the
97 * escape character, skip it and return the following.
100 if (*Pattern == ESCAPE_CHAR) {
102 return (*Pattern == '\0') ? -1 : *Pattern;
110 static int RecursiveMatch (const unsigned char* Source, const unsigned char* Pattern)
111 /* A recursive pattern matcher */
118 if (*Pattern == '\0') {
120 /* Reached the end of Pattern, what about Source? */
121 return (*Source == '\0') ? 1 : 0;
123 } else if (*Pattern == '*') {
125 if (*++Pattern == '\0') {
126 /* A trailing '*' is always a match */
130 /* Check the rest of the string */
132 if (RecursiveMatch (Source++, Pattern)) {
141 } else if (*Source == '\0') {
143 /* End of Source reached, no match */
148 /* Check a single char. Build a set of all possible characters in
149 * CS, then check if the current char of Source is contained in
152 CS_CLEAR (CS); /* Clear the character set */
154 if (*Pattern == '?') {
156 /* All chars are allowed */
158 ++Pattern; /* Skip '?' */
160 } else if (*Pattern == ESCAPE_CHAR) {
162 /* Use the next char as is */
164 CS_ADD (CS, *Pattern);
165 ++Pattern; /* Skip the character */
167 } else if (*Pattern == '[') {
172 if (*Pattern == '!') {
176 while (*Pattern != ']') {
179 if ((C1 = RealChar (Pattern)) == -1) {
183 if (*Pattern != '-') {
189 if ((C2 = RealChar (Pattern)) == -1) {
193 for (C = C1; C <= C2; C++) {
201 /* Reverse all bits in the set */
207 /* Include the char in the charset, then skip it */
208 CS_ADD (CS, *Pattern);
213 if (!CS_CONTAINS (CS, *Source)) {
225 int MatchPattern (const char* Source, const char* Pattern)
226 /* Match the string in Source against Pattern. Pattern may contain the
227 * wildcards '*', '?', '[abcd]' '[ab-d]', '[!abcd]', '[!ab-d]'. The
228 * function returns a value of zero if Source does not match Pattern,
229 * otherwise a non zero value is returned. If Pattern contains an invalid
230 * wildcard pattern (e.g. 'A[x'), the function returns zero.
233 /* Handle the trivial cases */
234 if (Pattern == 0 || *Pattern == '\0') {
235 return (Source == 0 || *Source == '\0');
238 /* Do the real thing */
239 return RecursiveMatch ((const unsigned char*) Source, (const unsigned char*) Pattern);