blob: 1ba159ccaddb73a3f3dc8e0cfb067677a501dc6a [file] [log] [blame]
/************************************************************************
*
* fnmatch.cpp - definitions of testsuite helpers
*
* $Id$
*
************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
**************************************************************************/
// expand _TEST_EXPORT macros
#define _RWSTD_TEST_SRC
#include <rw_fnmatch.h>
typedef unsigned char UChar;
// matches a character against a POSIX bracket expression
static const char*
_rw_bracketmatch (const char *pattern, const unsigned char ch, int)
{
const char *pc = pattern;
// negate the match?
bool neg = false;
// treat '!' and '^' the same (according to POSIX, the latter has
// unspecified behavior)
if ('!' == *pc || '^' == *pc) {
++pc;
neg = true;
}
if ('-' == *pc || ']' == *pc) {
// the '-' and ']' lose their special meaning when they occur
// first in the bracket expression, after the initial '!', if
// any
if (ch == UChar (*pc)) {
if (neg)
return 0;
// skip over the ']'
if (']' == *pc)
++pc;
// skip over any subsequent characters until the closing
// (unescaped) ']'
for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
return pc;
}
else if (!neg)
return 0;
}
unsigned first = 0;
bool esc = false;
for ( ; *pc; ++pc) {
if ('\\' == *pc) {
if (esc) {
if (ch == UChar (*pc)) {
if (neg)
return 0;
// skip over any subsequent characters until the closing
// (unescaped) ']'
for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
return pc;
}
}
esc = true;
continue;
}
if (']' == *pc && !esc)
break;
if ('-' == *pc && !esc)
first = UChar (pc [-1]);
else if (first) {
// check if character is in the current range
if (first <= ch && ch <= UChar (*pc)) {
if (neg)
return 0;
// skip over any subsequent characters until the closing
// (unescaped) ']'
for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
return pc;
}
first = 0;
}
else if (ch == UChar (*pc)) {
if (neg)
return 0;
// skip over any subsequent characters until the closing
// (unescaped) ']'
for ( ; *pc && (*pc != ']' || pc [-1] == '\\'); ++pc);
return pc;
}
}
return neg ? pc : 0;
}
_TEST_EXPORT int
rw_fnmatch (const char *pattern, const char *string, int arg)
{
RW_ASSERT (pattern);
RW_ASSERT (string);
const char *next = string;
bool esc = false;
for (const char *pc = pattern; ; ++pc) {
switch (const char c = *pc) {
case '\0':
return !!*next;
case '\\':
if (esc) {
if (c != *next)
return 1;
esc = false;
++next;
}
else
esc = true;
break;
case '*':
if (esc) {
if (c != *next)
return 1;
esc = false;
++next;
}
else {
// skip any subsequent asterisks as an optimization
for ( ; '*' == pc [1]; ++pc);
for ( ; *next; ++next) {
// try to match the rest of the string against
// the rest of the pattern after the asterisk
if (0 == rw_fnmatch (pc + 1, next, arg))
return 0;
}
}
break;
case '?':
if (esc) {
if (c != *next)
return 1;
esc = false;
}
if ('\0' == *next)
return 1;
++next;
break;
case '[':
if (esc) {
if (c != *next)
return 1;
esc = false;
}
else {
if ('\0' == *next)
return 1;
pc = _rw_bracketmatch (pc + 1, UChar (*next), arg);
if (0 == pc)
return 1;
}
++next;
break;
default:
if (c != *next)
return 1;
esc = false;
++next;
}
if ('\0' == *next) {
// reached the end of string: this is a match if the end
// of the pattern has also been reached or if the rest
// of the pattern in all asterisks
if (!esc)
while ('*' == *++pc);
return !!*pc;
}
}
return 1;
}