Blame | Last modification | View Log | Download | RSS feed
/* ACC -- Automatic Compiler Configuration
Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
This software is a copyrighted work licensed under the terms of
the GNU General Public License. Please consult the file "ACC_LICENSE"
for details.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/
*/
#define __ACCLIB_FNMATCH_CH_INCLUDED 1
#if !defined(ACCLIB_PUBLIC)
# define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f)
#endif
/*************************************************************************
//
**************************************************************************/
typedef struct {
const acc_hbyte_p s;
const acc_hbyte_p s_start;
int f;
int f_escape;
int f_casefold;
} acc_fnmatch_internal_t;
static int __ACCLIB_FUNCNAME(acc_fnmatch_internal) (const acc_hbyte_p p, acc_fnmatch_internal_t* a)
{
const acc_hbyte_p s = a->s;
int f_pathname = (a->f & (ACC_FNMATCH_PATHNAME | ACC_FNMATCH_PATHSTAR));
while (*p) {
switch (*p) {
case '?': case '[':
if (*s == 0) return 0;
if (*s == '/' && f_pathname) return 0;
if (*s == '.' && (a->f & ACC_FNMATCH_PERIOD) && (s == a->s_start || (f_pathname && s[-1] == '/'))) return 0;
if (*p == '?') break;
{
int r = 0, fail = 0; unsigned char last = 0;
if (*++p == '^' || *p == '!')
fail = 1, ++p;
do {
switch (*p) {
case 0:
return -1;
case '-':
if (last == 0 || p[1] == ']') goto acc_label_default;
if (a->f_escape && p[1] == '\\') ++p;
if (*++p == 0) return -1;
if (!a->f_casefold && last <= *s && *s <= *p) r = 1;
else if (a->f_casefold && acc_ascii_tolower(last) <= acc_ascii_tolower(*s) && acc_ascii_tolower(*s) <= acc_ascii_tolower(*p)) r = 1;
last = 0;
continue;
/* TODO: implement sets like [:alpha:] ??? */
case '\\':
if (a->f_escape && *++p == 0) return -1;
default: acc_label_default:
if (*s == *p) r = 1;
else if (a->f_casefold && acc_ascii_tolower(*s) == acc_ascii_tolower(*p)) r = 1;
break;
}
last = *p;
} while (*++p != ']');
if (r == fail)
return 0;
break;
}
case '*':
while (*++p == '*') if (a->f & ACC_FNMATCH_PATHSTAR) f_pathname = 0;
if (*s == '.' && (a->f & ACC_FNMATCH_PERIOD) && (s == a->s_start || (f_pathname && s[-1] == '/'))) return 0;
if (*p == 0) {
if (f_pathname) while (*s) if (*s++ == '/') return 0;
return 1;
}
for ( ; *s; ++s) {
int r;
a->s = s; r = __ACCLIB_FUNCNAME(acc_fnmatch_internal)(p, a);
switch (r) {
case 0: if (*s == '/' && f_pathname) return 2; break;
case 2: if (!f_pathname) break;
default: return r;
}
}
return 0;
case '\\':
if (a->f_escape && *++p == 0) return -1;
default:
if (*s == *p) break;
if (a->f_casefold && acc_ascii_tolower(*s) == acc_ascii_tolower(*p)) break;
return 0;
}
++p, ++s;
}
return *s == 0;
}
ACCLIB_PUBLIC(int, acc_fnmatch) (const acc_hchar_p p, const acc_hchar_p s, int flags)
{
int r;
acc_fnmatch_internal_t args;
args.s = args.s_start = (const acc_hbyte_p) s;
args.f = flags;
args.f_escape = !(flags & ACC_FNMATCH_NOESCAPE);
args.f_casefold = (flags & ACC_FNMATCH_ASCII_CASEFOLD);
r = __ACCLIB_FUNCNAME(acc_fnmatch_internal)((const acc_hbyte_p)p, &args);
if (r < 0) return r;
return r != 1;
}
/*
vi:ts=4:et
*/