168 lines
3.6 KiB
C
168 lines
3.6 KiB
C
|
/* Copyright 1986-1992 Emmet P. Gray.
|
||
|
* Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff.
|
||
|
* This file is part of mtools.
|
||
|
*
|
||
|
* Mtools is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Mtools is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards.
|
||
|
* Returns 1 if match, 0 if not.
|
||
|
*/
|
||
|
|
||
|
#include "sysincludes.h"
|
||
|
#include "mtools.h"
|
||
|
|
||
|
|
||
|
static int casecmp(wchar_t a, wchar_t b)
|
||
|
{
|
||
|
return towupper((wint_t)a) == towupper((wint_t)b);
|
||
|
}
|
||
|
|
||
|
static int exactcmp(wchar_t a,wchar_t b)
|
||
|
{
|
||
|
return a == b;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int is_in_range(wchar_t ch, const wchar_t **p, int *reverse) {
|
||
|
wchar_t first, last;
|
||
|
int found=0;
|
||
|
if (**p == '^') {
|
||
|
*reverse = 1;
|
||
|
(*p)++;
|
||
|
} else
|
||
|
*reverse=0;
|
||
|
while( (first = **p) != ']') {
|
||
|
if(!first)
|
||
|
/* Malformed pattern, range not closed */
|
||
|
return 0;
|
||
|
if(*(++(*p)) == '-') {
|
||
|
last = *(++(*p));
|
||
|
if(last==']') {
|
||
|
/* Last "-" in range designates itself */
|
||
|
if(ch == first || ch == '-')
|
||
|
found = 1;
|
||
|
break;
|
||
|
}
|
||
|
(*p)++;
|
||
|
|
||
|
/* a proper range */
|
||
|
if(ch >= first && ch <= last)
|
||
|
found = 1;
|
||
|
} else
|
||
|
/* a Just one character */
|
||
|
if(ch == first)
|
||
|
found = 1;
|
||
|
}
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out,
|
||
|
int (*compfn)(wchar_t a, wchar_t b))
|
||
|
{
|
||
|
int reverse;
|
||
|
const wchar_t *p0 = *p;
|
||
|
const wchar_t *p1 = *p;
|
||
|
if(out)
|
||
|
*out = *s;
|
||
|
if(is_in_range(*s, p, &reverse))
|
||
|
return 1 ^ reverse;
|
||
|
if(compfn == exactcmp)
|
||
|
return reverse;
|
||
|
if(is_in_range((wchar_t)towlower((wint_t)*s), &p0, &reverse)) {
|
||
|
if(out)
|
||
|
*out = (wchar_t)towlower((wint_t)*s);
|
||
|
return 1 ^ reverse;
|
||
|
}
|
||
|
if(is_in_range((wchar_t)towupper((wint_t)*s), &p1, &reverse)) {
|
||
|
if(out)
|
||
|
*out = (wchar_t)towupper((wint_t)*s);
|
||
|
return 1 ^ reverse;
|
||
|
}
|
||
|
return reverse;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case,
|
||
|
int length,
|
||
|
int (*compfn) (wchar_t a, wchar_t b))
|
||
|
{
|
||
|
for (; *p != '\0' && length; ) {
|
||
|
switch (*p) {
|
||
|
case '?': /* match any one character */
|
||
|
if (*s == '\0')
|
||
|
return(0);
|
||
|
if(out)
|
||
|
*(out++) = *s;
|
||
|
break;
|
||
|
case '*': /* match everything */
|
||
|
while (*p == '*' && length) {
|
||
|
p++;
|
||
|
length--;
|
||
|
}
|
||
|
|
||
|
/* search for next char in pattern */
|
||
|
while(*s) {
|
||
|
if(_match(s, p, out, Case, length,
|
||
|
compfn))
|
||
|
return 1;
|
||
|
if(out)
|
||
|
*out++ = *s;
|
||
|
s++;
|
||
|
}
|
||
|
continue;
|
||
|
case '[': /* match range of characters */
|
||
|
p++;
|
||
|
length--;
|
||
|
if(!parse_range(&p, s, out++, compfn))
|
||
|
return 0;
|
||
|
break;
|
||
|
case '\\': /* Literal match with next character */
|
||
|
p++;
|
||
|
length--;
|
||
|
/* fall thru */
|
||
|
default:
|
||
|
if (!compfn(*s,*p))
|
||
|
return(0);
|
||
|
if(out)
|
||
|
*(out++) = *p;
|
||
|
break;
|
||
|
}
|
||
|
p++;
|
||
|
length--;
|
||
|
s++;
|
||
|
}
|
||
|
if(out)
|
||
|
*out = '\0';
|
||
|
|
||
|
/* string ended prematurely ? */
|
||
|
if (*s != '\0')
|
||
|
return(0);
|
||
|
else
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length)
|
||
|
{
|
||
|
int (*compfn)(wchar_t a, wchar_t b);
|
||
|
|
||
|
if(Case)
|
||
|
compfn = casecmp;
|
||
|
else
|
||
|
/*compfn = exactcmp;*/
|
||
|
compfn = casecmp;
|
||
|
return _match(s, p, out, Case, length, compfn);
|
||
|
}
|
||
|
|