Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
fnmatch.cpp
Go to the documentation of this file.
1
27// expand _TEST_EXPORT macros
28#define _RWSTD_TEST_SRC
29#include <rw_fnmatch.h>
30
31
32typedef unsigned char UChar;
33
34
35// matches a character against a POSIX bracket expression
36static const char*
37_rw_bracketmatch (const char *pattern, const unsigned char ch, int)
38{
39 const char *pc = pattern;
40
41 // negate the match?
42 bool neg = false;
43
44 // treat '!' and '^' the same (according to POSIX, the latter has
45 // unspecified behavior)
46 if ('!' == *pc || '^' == *pc) {
47 ++pc;
48 neg = true;
49 }
50
51 if ('-' == *pc || ']' == *pc) {
52 // the '-' and ']' lose their special meaning when they occur
53 // first in the bracket expression, after the initial '!', if
54 // any
55 if (ch == UChar (*pc)) {
56 if (neg)
57 return 0;
58
59 // skip over the ']'
60 if (']' == *pc)
61 ++pc;
62
63 // skip over any subsequent characters until the closing
64 // (unescaped) ']'
65 for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
66 return pc;
67 }
68 else if (!neg)
69 return 0;
70 }
71
72 unsigned first = 0;
73 bool esc = false;
74
75 for ( ; *pc; ++pc) {
76 if ('\\' == *pc) {
77 if (esc) {
78 if (ch == UChar (*pc)) {
79 if (neg)
80 return 0;
81
82 // skip over any subsequent characters until the closing
83 // (unescaped) ']'
84 for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
85 return pc;
86 }
87 }
88 esc = true;
89 continue;
90 }
91
92 if (']' == *pc && !esc)
93 break;
94
95 if ('-' == *pc && !esc)
96 first = UChar (pc [-1]);
97 else if (first) {
98 // check if character is in the current range
99 if (first <= ch && ch <= UChar (*pc)) {
100 if (neg)
101 return 0;
102
103 // skip over any subsequent characters until the closing
104 // (unescaped) ']'
105 for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
106 return pc;
107 }
108
109 first = 0;
110 }
111 else if (ch == UChar (*pc)) {
112 if (neg)
113 return 0;
114
115 // skip over any subsequent characters until the closing
116 // (unescaped) ']'
117 for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
118 return pc;
119 }
120 }
121
122 return neg ? pc : 0;
123}
124
125
126_TEST_EXPORT int
127rw_fnmatch (const char *pattern, const char *string, int arg)
128{
129 RW_ASSERT (pattern);
130 RW_ASSERT (string);
131
132 const char *next = string;
133
134 bool esc = false;
135
136 for (const char *pc = pattern; ; ++pc) {
137
138 switch (const char c = *pc) {
139 case '\0':
140 return !!*next;
141
142 case '\\':
143 if (esc) {
144 if (c != *next)
145 return 1;
146
147 esc = false;
148 ++next;
149 }
150 else
151 esc = true;
152
153 break;
154
155 case '*':
156 if (esc) {
157 if (c != *next)
158 return 1;
159
160 esc = false;
161
162 ++next;
163 }
164 else {
165
166 // skip any subsequent asterisks as an optimization
167 for ( ; '*' == pc [1]; ++pc);
168
169 for ( ; *next; ++next) {
170 // try to match the rest of the string against
171 // the rest of the pattern after the asterisk
172 if (0 == rw_fnmatch (pc + 1, next, arg))
173 return 0;
174 }
175 }
176
177 break;
178
179 case '?':
180 if (esc) {
181 if (c != *next)
182 return 1;
183
184 esc = false;
185 }
186
187 if ('\0' == *next)
188 return 1;
189
190 ++next;
191 break;
192
193 case '[':
194 if (esc) {
195 if (c != *next)
196 return 1;
197
198 esc = false;
199 }
200 else {
201 if ('\0' == *next)
202 return 1;
203
204 pc = _rw_bracketmatch (pc + 1, UChar (*next), arg);
205 if (0 == pc)
206 return 1;
207 }
208
209 ++next;
210 break;
211
212 default:
213 if (c != *next)
214 return 1;
215
216 esc = false;
217
218 ++next;
219 }
220
221 if ('\0' == *next) {
222 // reached the end of string: this is a match if the end
223 // of the pattern has also been reached or if the rest
224 // of the pattern in all asterisks
225 if (!esc)
226 while ('*' == *++pc);
227 return !!*pc;
228 }
229 }
230
231 return 1;
232}
#define neg
Definition 17.names.cpp:503
#define c
Definition 17.names.cpp:111
_TEST_EXPORT int rw_fnmatch(const char *pattern, const char *string, int arg)
Definition fnmatch.cpp:127
unsigned char UChar
Definition fnmatch.cpp:32
#define _TEST_EXPORT
Definition rw_testdefs.h:55
#define RW_ASSERT(expr)
unsigned char UChar
Definition collate.cpp:122
int arg
Definition locale.cpp:2806