197 lines
6.6 KiB
C++
197 lines
6.6 KiB
C++
|
// This may look like C code, but it is really -*- C++ -*-
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
// The Goldware Library
|
||
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
||
|
// ------------------------------------------------------------------
|
||
|
// This library is free software; you can redistribute it and/or
|
||
|
// modify it under the terms of the GNU Library General Public
|
||
|
// License as published by the Free Software Foundation; either
|
||
|
// version 2 of the License, or (at your option) any later version.
|
||
|
//
|
||
|
// This library 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
|
||
|
// Library General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU Library General Public
|
||
|
// License along with this program; if not, write to the Free
|
||
|
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||
|
// MA 02111-1307, USA
|
||
|
// ------------------------------------------------------------------
|
||
|
// $Id$
|
||
|
// ------------------------------------------------------------------
|
||
|
// A wildcard pattern matching function. Based on TIN source.
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
#include <gstrall.h>
|
||
|
#include <gwildmat.h>
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
/*
|
||
|
** Do shell-style pattern matching for ?, \, [], and * characters.
|
||
|
** Might not be robust in face of malformed patterns; e.g., "foo[a-"
|
||
|
** could cause a segmentation violation. It is 8bit clean.
|
||
|
**
|
||
|
** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
|
||
|
** Rich $alz is now <rsalz@osf.org>.
|
||
|
** April, 1991: Replaced mutually-recursive calls with in-line code
|
||
|
** for the star character.
|
||
|
**
|
||
|
** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
|
||
|
** This can greatly speed up failing wildcard patterns. For example:
|
||
|
** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
|
||
|
** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
|
||
|
** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
|
||
|
** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without
|
||
|
** the ABORT code, it takes 22310 calls to fail. Ugh. The following
|
||
|
** explanation is from Lars:
|
||
|
** The precondition that must be fulfilled is that DoMatch will consume
|
||
|
** at least one character in text. This is true if *p is neither '*' nor
|
||
|
** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic
|
||
|
** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With
|
||
|
** FALSE, each star-loop has to run to the end of the text; with ABORT
|
||
|
** only the last one does.
|
||
|
**
|
||
|
** Once the control of one instance of DoMatch enters the star-loop, that
|
||
|
** instance will return either TRUE or ABORT, and any calling instance
|
||
|
** will therefore return immediately after (without calling recursively
|
||
|
** again). In effect, only one star-loop is ever active. It would be
|
||
|
** possible to modify the code to maintain this context explicitly,
|
||
|
** eliminating all recursive calls at the cost of some complication and
|
||
|
** loss of clarity (and the ABORT stuff seems to be unclear enough by
|
||
|
** itself). I think it would be unwise to try to get this into a
|
||
|
** released version unless you have a good test data base to try it out
|
||
|
** on.
|
||
|
*/
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
int gwildmatch::match_internal(const char* text, const char* pattern, bool ignorecase) {
|
||
|
|
||
|
register int last;
|
||
|
register int matched;
|
||
|
register int reverse;
|
||
|
const char* p = pattern;
|
||
|
|
||
|
for( ; *p; text++, p++) {
|
||
|
if(*text == NUL and *p != '*')
|
||
|
return -1;
|
||
|
switch (*p) {
|
||
|
case '?':
|
||
|
// Match anything
|
||
|
continue;
|
||
|
case '*':
|
||
|
while(*++p == '*') // Consecutive stars act just like one.
|
||
|
continue;
|
||
|
if(*p == NUL) // Trailing star matches everything
|
||
|
return true;
|
||
|
while(*text) {
|
||
|
if((matched = match_internal(text++, p, ignorecase)) != false)
|
||
|
return matched;
|
||
|
}
|
||
|
return -1;
|
||
|
case '[':
|
||
|
reverse = p[1] == '^' ? true : false;
|
||
|
if(reverse) // Inverted character class
|
||
|
p++;
|
||
|
matched = false;
|
||
|
if(p[1] == ']' or p[1] == '-') {
|
||
|
if(ignorecase) {
|
||
|
if(tolower(*++p) == tolower(*text))
|
||
|
matched = true;
|
||
|
}
|
||
|
else {
|
||
|
if(*++p == *text)
|
||
|
matched = true;
|
||
|
}
|
||
|
}
|
||
|
for(last = *p; *++p and *p != ']'; last = *p) {
|
||
|
// This next line requires a good C compiler
|
||
|
if(ignorecase) {
|
||
|
if(*p == '-' and p[1] != ']' ? tolower(*text) <= tolower(*++p) and tolower(*text) >= tolower(last) : tolower(*text) == tolower(*p))
|
||
|
matched = true;
|
||
|
}
|
||
|
else {
|
||
|
if(*p == '-' and p[1] != ']' ? *text <= *++p and *text >= last : *text == *p)
|
||
|
matched = true;
|
||
|
}
|
||
|
}
|
||
|
if(matched == reverse)
|
||
|
return false;
|
||
|
continue;
|
||
|
case '\\':
|
||
|
// Literal match with following character
|
||
|
p++;
|
||
|
// FALLTHROUGH
|
||
|
default:
|
||
|
if(ignorecase) {
|
||
|
if(tolower(*text) != tolower(*p))
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
if(*text != *p)
|
||
|
return false;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return *text == NUL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
bool gwildmatch::match(const char* text, const char* pattern, bool ignorecase) {
|
||
|
|
||
|
if(*pattern == '*' and pattern[1] == NUL)
|
||
|
return true;
|
||
|
return match_internal(text, pattern, ignorecase) == true;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
// 4DOS-style wildcard string match.
|
||
|
|
||
|
bool strwild(const char* str, const char* wild) {
|
||
|
|
||
|
while(*str) {
|
||
|
if(*wild == '*') { // Match all
|
||
|
if(wild[1] == NUL)
|
||
|
return true;
|
||
|
else {
|
||
|
char *buf = (char *)alloca(strlen(wild));
|
||
|
strcpy(buf, wild+1);
|
||
|
char* ptr = strpbrk(buf, "*?");
|
||
|
if(ptr)
|
||
|
*ptr = NUL;
|
||
|
ptr = (char*)striinc(buf, str);
|
||
|
if(ptr) {
|
||
|
str = ptr + strlen(buf);
|
||
|
wild += strlen(buf) + 1;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if(toupper(*str) == toupper(*wild) or *wild == '?') {
|
||
|
wild++;
|
||
|
str++;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
if((*str == NUL) and (*wild == NUL or (*wild == '*' and wild[1] == NUL)))
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|