urbackup_backend/urbackupcommon/glob.cpp
2015-12-22 13:27:12 +01:00

230 lines
4.8 KiB
C++

/*
* robust glob pattern matcher
* ozan s. yigit/dec 1994
* public domain
*
* glob patterns:
* * matches zero or more characters
* ? matches any single character
* [set] matches any character in the set
* [^set] matches any character NOT in the set
* where a set is a group of characters or ranges. a range
* is written as two characters seperated with a hyphen: a-z denotes
* all characters between a to z inclusive.
* [-set] set matches a literal hypen and any character in the set
* []set] matches a literal close bracket and any character in the set
*
* char matches itself except where char is '*' or '?' or '['
* \char matches char, including any pattern character
*
* examples:
* a*c ac abc abbc ...
* a?c acc abc aXc ...
* a[a-z]c aac abc acc ...
* a[-a-z]c a-c aac abc ...
*
* $Log: glob.c,v $
* Revision 1.3 1995/09/14 23:24:23 oz
* removed boring test/main code.
*
* Revision 1.2 94/12/11 10:38:15 oz
* cset code fixed. it is now robust and interprets all
* variations of cset [i think] correctly, including [z-a] etc.
*
* Revision 1.1 94/12/08 12:45:23 oz
* Initial revision
*/
#ifndef NEGATE
#define NEGATE '^' /* std cset negation char */
#endif
bool amatch(const char *str, const char *p)
{
int negate;
int match;
int c;
bool np;
while (*p) {
if (!*str && *p != '*' && *p!=':')
return false;
switch (c = *p++) {
case ':':
case '*':
np=false;
if( c==':')
np=true;
while (*p == '*' || *p==':')
p++;
if(!np)
{
if (!*p)
return true;
}
if (*p != '?' && *p != '[' && *p != '\\')
while (*str && (!np || (*str!='/' && *str!='\\') ) && *p != *str)
str++;
if(np)
{
if(!*p && !*str)
return true;
}
while (*str) {
if (amatch(str, p))
return true;
if( np && (*str=='\\' || *str=='/') )
break;
str++;
}
return false;
case '?':
if (*str)
break;
return false;
/*
* set specification is inclusive, that is [a-z] is a, z and
* everything in between. this means [z-a] may be interpreted
* as a set that contains z, a and nothing in between.
*/
case '[':
if (*p != NEGATE)
negate = false;
else {
negate = true;
p++;
}
match = false;
while (!match && (c = *p++)) {
if (!*p)
return false;
if (*p == '-') { /* c-c */
if (!*++p)
return false;
if (*p != ']') {
if (*str == c || *str == *p ||
(*str > c && *str < *p))
match = true;
}
else { /* c-] */
if (*str >= c)
match = true;
break;
}
}
else { /* cc or c] */
if (c == *str)
match = true;
if (*p != ']') {
if (*p == *str)
match = true;
}
else
break;
}
}
if (negate == match)
return false;
/*
* if there is a match, skip past the cset and continue on
*/
while (*p && *p != ']')
p++;
if (!*p++) /* oops! */
return false;
break;
case '\\':
if (*p)
c = *p++;
default:
if (c != *str)
return false;
break;
}
str++;
}
return !*str;
}
bool test_amatch(void)
{
if(amatch("foo bar", "* bar")==false)
return false;
if(amatch("foo\\ bar", "*\\ bar")==false)
return false;
if(amatch("abcdef", "*")==false)
return false;
if(amatch("abcdef", ":")==false)
return false;
if(amatch("abcdef", "abcdef:")==false)
return false;
if(amatch("abcdef", "abcdef:\\\\")==true)
return false;
if(amatch("abcdef/", ":")==true)
return false;
if(amatch("abcdef/", ":/")==false)
return false;
if(amatch("abcdef\\", ":")==true)
return false;
if(amatch("abcdef\\", ":\\\\")==false)
return false;
if(amatch("abcdef/asd", ":/asd")==false)
return false;
if(amatch("abcdef\\asd", ":asd")==true)
return false;
if(amatch("abcdef\\asd", ":\\\\asd")==false)
return false;
if(amatch("abcdef/asd", ":/:")==false)
return false;
if(amatch("abcdef\\asd", "::")==true)
return false;
if(amatch("abcdef\\asd", ":\\\\:")==false)
return false;
if(amatch("abcdef\\", ":\\\\:")==false)
return false;
if(amatch("cvab_abba", "*ab*ab*ba")==false)
return false;
if(amatch("cvab_abba", "*abab*ba")==true)
return false;
if(amatch("cvab_abba", ":ab:ab:ba")==false)
return false;
if(amatch("cvab_abba", "abab:ba")==true)
return false;
if(amatch("Users/Bernd/Documents", "Users/:/Documents")==false)
return false;
if(amatch("Users/Bernd/bla/Documents", "Users/:/Documents")==true)
return false;
if(amatch("Users/Bernd/bla/Documents", "Users/*/Documents")==false)
return false;
if(amatch("Users/Bernd/Documents", "Users/:/:/Documents")==true)
return false;
if(amatch("Users/Bernd/bla/Documents", "Users/:/:/Documents")==false)
return false;
if(amatch("Users/Bernd/bla/Documents/xyz", "Users/:/:/Documents/*")==false)
return false;
if(amatch("Users/Bernd/bla/Documents2/xyz", "Users/:/:/Documents/*")==true)
return false;
return true;
}