2 * Copyright 2001-2014, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
4 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
5 * This file may be used under the terms of the MIT License.
9 // This needs to be the first include because of the fs shell API wrapper
12 #include <file_systems/QueryParserUtils.h>
17 # include <TypeConstants.h>
21 namespace QueryParser
{
24 template<typename Key
>
26 compare_integral(const Key
& a
, const Key
& b
)
40 skipWhitespace(char** expr
, int32 skip
)
42 char* string
= (*expr
) + skip
;
43 while (*string
== ' ' || *string
== '\t') string
++;
49 skipWhitespaceReverse(char** expr
, char* stop
)
52 while (string
> stop
&& (*string
== ' ' || *string
== '\t'))
59 compareKeys(uint32 type
, const void* key1
, size_t length1
, const void* key2
,
64 return compare_integral(*(int32
*)key1
, *(int32
*)key2
);
66 return compare_integral(*(uint32
*)key1
, *(uint32
*)key2
);
68 return compare_integral(*(int64
*)key1
, *(int64
*)key2
);
70 return compare_integral(*(uint64
*)key1
, *(uint64
*)key2
);
72 return compare_integral(*(float*)key1
, *(float*)key2
);
74 return compare_integral(*(double*)key1
, *(double*)key2
);
76 case B_MIME_STRING_TYPE
:
78 int result
= strncmp((const char*)key1
, (const char*)key2
,
79 std::min(length1
, length2
));
81 result
= compare_integral(strnlen((const char*)key1
, length1
),
82 strnlen((const char*)key2
, length2
));
95 utf8ToUnicode(char** string
)
97 uint8
* bytes
= (uint8
*)*string
;
101 switch (bytes
[0] & 0xf0) {
114 // valid 1-byte character
115 // and invalid characters
119 uint32 c
= bytes
[0] & mask
;
121 for (; i
< length
&& (bytes
[i
] & 0x80) > 0; i
++)
122 c
= (c
<< 6) | (bytes
[i
] & 0x3f);
127 return (uint32
)bytes
[0];
135 getFirstPatternSymbol(char* string
)
139 for (int32 index
= 0; (c
= *string
++); index
++) {
140 if (c
== '*' || c
== '?' || c
== '[')
148 isValidPattern(char* pattern
)
151 switch (*pattern
++) {
153 // the escape character must not be at the end of the pattern
155 return PATTERN_INVALID_ESCAPE
;
159 if (pattern
[0] == ']' || !pattern
[0])
160 return PATTERN_INVALID_SET
;
162 while (*pattern
!= ']') {
163 if (*pattern
== '\\' && !*++pattern
)
164 return PATTERN_INVALID_ESCAPE
;
167 return PATTERN_INVALID_SET
;
169 if (pattern
[0] == '-' && pattern
[1] == '-')
170 return PATTERN_INVALID_RANGE
;
181 /*! Matches the string against the given wildcard pattern.
182 Returns either MATCH_OK, or NO_MATCH when everything went fine, or
183 values < 0 (see enum at the top of Query.cpp) if an error occurs.
186 matchString(char* pattern
, char* string
)
189 // end of string == valid end of pattern?
191 while (pattern
[0] == '*')
193 return !pattern
[0] ? MATCH_OK
: NO_MATCH
;
196 switch (*pattern
++) {
199 // match exactly one UTF-8 character; we are
200 // not interested in the result
201 utf8ToUnicode(&string
);
209 if (pattern
[0] == '?') {
212 } else if (pattern
[0] != '*')
218 // if the pattern is done, we have matched the string
223 // we have removed all occurences of '*' and '?'
224 if (pattern
[0] == string
[0]
226 || pattern
[0] == '\\') {
227 status_t status
= matchString(pattern
, string
);
228 if (status
< B_OK
|| status
== MATCH_OK
)
232 // we could be nice here and just jump to the next
233 // UTF-8 character - but we wouldn't gain that much
234 // and it'd be slower (since we're checking for
235 // equality before entering the recursion)
245 if (pattern
[0] == '^' || pattern
[0] == '!') {
250 if (!pattern
[0] || pattern
[0] == ']')
251 return MATCH_BAD_PATTERN
;
253 uint32 c
= utf8ToUnicode(&string
);
254 bool matched
= false;
256 while (pattern
[0] != ']') {
258 return MATCH_BAD_PATTERN
;
260 if (pattern
[0] == '\\')
263 uint32 first
= utf8ToUnicode(&pattern
);
265 // Does this character match, or is this a range?
269 } else if (pattern
[0] == '-' && pattern
[1] != ']'
273 if (pattern
[0] == '\\') {
276 return MATCH_BAD_PATTERN
;
278 uint32 last
= utf8ToUnicode(&pattern
);
280 if (c
>= first
&& c
<= last
) {
291 while (pattern
[0] != ']') {
293 return MATCH_BAD_PATTERN
;
304 return MATCH_BAD_PATTERN
;
305 // supposed to fall through
307 if (pattern
[-1] != string
[0])
321 } // namespace QueryParser