1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 
14 // common goes first
15 #include "common.h"
16 
17 // implementation header
18 #include "bzglob.h"
19 
20 // system headers
21 #include <string>
22 
23 
24 static int match_multi (const char **pattern, const char **string);
25 
26 static const char MATCH_MULTI  = '*'; // matches any number of characters
27 static const char MATCH_SINGLE = '?'; // matches a single character
28 
29 
30 /******************************************************************************/
31 
glob_match(const std::string & pattern,const std::string & string)32 bool glob_match (const std::string& pattern, const std::string& string)
33 {
34     return glob_match (pattern.c_str(), string.c_str());
35 }
36 
37 /******************************************************************************/
38 
glob_match(const char * pattern,const char * string)39 bool glob_match (const char *pattern, const char *string)
40 {
41     if (pattern == NULL)
42         return false;
43     if (string == NULL)
44         return false;
45 
46     if ((pattern[0] == MATCH_MULTI) && (pattern[1] == '\0'))
47         return true;
48 
49     while (*pattern != '\0')
50     {
51         if (*pattern == MATCH_MULTI)
52         {
53             pattern++;
54             switch (match_multi (&pattern, &string))
55             {
56             case +1:
57             {
58                 return true;
59             }
60             case -1:
61             {
62                 return false;
63             }
64             }
65         }
66         else if (*string == '\0')
67             return false;
68         else if ((*pattern == MATCH_SINGLE) || (*pattern == *string))
69         {
70             pattern++;
71             string++;
72         }
73         else
74             return false;
75     }
76 
77     if (*string == '\0')
78         return true;
79     else
80         return false;
81 }
82 
83 /******************************************************************************/
84 
match_multi(const char ** pattern,const char ** string)85 static int match_multi (const char **pattern, const char **string)
86 {
87     const char *str = *pattern;
88     const char *obj = *string;
89 
90     while ((*str != '\0') && (*str == MATCH_MULTI))
91     {
92         str++; // get rid of multiple '*'s
93     }
94 
95     if (*str == '\0')   // '*' was last, auto-match
96         return +1;
97 
98     const char *strtop = str;
99     const char *objtop = obj;
100 
101     while (*str != '\0')
102     {
103         if (*str == MATCH_MULTI)
104         {
105             *pattern = str;
106             *string = obj;
107             return 0; // matched this segment
108         }
109         else if (*obj == '\0')
110         {
111             return -1; // can't match
112         }
113         else
114         {
115             if ((*str == MATCH_SINGLE) || (*str == *obj))
116             {
117                 str++;
118                 obj++;
119                 if ((*str == '\0') && (*obj != '\0'))   // advanced check
120                 {
121                     obj++;
122                     objtop++;
123                     obj = objtop;
124                     str = strtop;
125                 }
126             }
127             else
128             {
129                 obj++;
130                 objtop++;
131                 obj = objtop;
132                 str = strtop;
133             }
134         }
135     }
136 
137     *pattern = str;
138     *string = obj;
139 
140     return +1; // full match
141 }
142 
143 
144 // Local Variables: ***
145 // mode: C++ ***
146 // tab-width: 4 ***
147 // c-basic-offset: 4 ***
148 // indent-tabs-mode: nil ***
149 // End: ***
150 // ex: shiftwidth=4 tabstop=4
151