Admin Panel
/**
* Coded by Stefan "Bebbo" Franke in 2019. Replacement for all that copyrighted stuff.
*/
#include <ctype.h>
#include <fnmatch.h>
#include <string.h>
#include "stdio.h"
typedef int (*fxtype)(int);
#define FX(a) {#a, is##a}
static struct __fx {
const char * name;
fxtype fx;
} const data[] = { FX(alnum), FX(alpha), FX(blank), FX(cntrl), FX(digit), FX(lower), FX(print), FX(punct), FX(space), FX(upper), FX(xdigit), };
/**
* Search the matching ctype function.
*/
static fxtype lookup(const char * name, size_t len) {
// printf("%s %d, %d, %d\n", name, len, sizeof(data), sizeof(struct __fx));
if (len == 5) {
size_t i;
for (i = 0; i < sizeof(data) / sizeof(struct __fx) - 1; ++i)
if (0 == strncmp(data[i].name, name, 5))
return data[i].fx;
} else if (len == 6) {
int i = sizeof(data) / sizeof(struct __fx) - 1;
if (0 == strncmp(data[i].name, name, 6))
return data[i].fx;
}
return 0;
}
#define FLAG_PATHNAME (flags & FNM_PATHNAME)
#define FLAG_NOESCAPE (flags & FNM_NOESCAPE)
#define FLAG_INPERIOD (flags & FNM_PERIOD)
#define FLAG_CASEFOLD (flags & FNM_CASEFOLD)
int fnmatch(const char *pattern, const char *string, int flags) {
short period = FLAG_INPERIOD;
unsigned char c = *string;
unsigned char p = *pattern;
while (c && p) {
// if (flags & 0x8000)
// fprintf(stderr, "%s == %s\n", pattern, string);
if (FLAG_CASEFOLD)
c = tolower(c);
switch (p) {
case '*':
if ((FLAG_PATHNAME && c == '/') || (period && c == '.')) {
--string;
break;
}
// try with '*' and rest of string
if (!fnmatch(pattern, string + 1, flags))
return 0;
// skip the '*'
--string;
break;
case '?':
// skip the '?' if match isn't allowed
if ((FLAG_PATHNAME && c == '/') || (period && c == '.'))
--string;
break;
case '[': {
const char * start;
short not, match;
if (c == '/' && FLAG_PATHNAME)
return FNM_NOMATCH;
start = pattern;
p = *++pattern;
not = 0;
if (p == '!') {
not = 1;
p = *++pattern;
}
// unterminated '[' -> compare as characters
if (!p) {
pattern = start;
p = *pattern;
break;
}
match = 0;
do {
if (!p) {
match = not;
break;
}
// character classes
if (p == '[' && pattern[1] == ':') {
fxtype is;
const char * name = pattern += 2;
while (*pattern && *pattern != ':')
++pattern;
is = lookup(name, pattern - name);
if (*pattern == 0) {
match = not;
break;
}
if (*++pattern != ']') {
match = not;
break;
}
if (FLAG_CASEFOLD && is == isupper)
is = islower;
if (is)
match |= is(c);
} else
// range handling
if (pattern[1] == '-' && pattern[2] != ']') {
unsigned char to;
pattern += 2;
to = *pattern;
if (to == '\\' && !FLAG_NOESCAPE)
to = *++pattern;
while (!match && p <= to) {
if (!period || c == '.') {
if (FLAG_CASEFOLD && tolower(p) == c)
match = 1;
else if (p == c) {
match = 1;
}
}
++p;
}
} else {
if (!period || c != '.') {
if (FLAG_CASEFOLD)
p = tolower(p);
match |= p == c;
}
}
p = *++pattern;
} while (p != ']' || pattern[1] == '-');
// goto next char if ok
if (match != not)
break;
// no match - try to apply this as character compare - fall through to character compare
pattern = start;
p = *pattern;
}
/* no break */
case '\\':
// recompare because of fall through - could be something else
if (p == '\\') {
if (!FLAG_NOESCAPE && pattern[1]) {
p = *++pattern;
}
}
/* no break */
default:
// to character compare
if (FLAG_CASEFOLD) {
if (tolower(p) != c)
return FNM_NOMATCH;
} else if (p != c)
return FNM_NOMATCH;
break;
}
// reset dynamic period switch
if (FLAG_PATHNAME && c == '/')
period = FLAG_INPERIOD;
else
period = 0;
// matched
p = *++pattern;
c = *++string;
}
while (p == '*')
p = *++pattern;
// if (flags & 0x8000)
// fprintf(stderr, "->%d\n", !!(p || c));
return p | c;
}