#include <config.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "glob.h"
#include "xmalloc.h"
#define SEPCHAR '.'
static char inbox[] = "INBOX";
#define INBOXLEN (sizeof (inbox) - 1)
glob *glob_init_suppress (str, flags, suppress)
const char *str;
int flags;
const char *suppress;
{
glob *g;
char *dst;
int slen = 0, newglob;
newglob = flags & GLOB_HIERARCHY;
if (suppress) slen = strlen(suppress);
g = (glob *) xmalloc(sizeof (glob) + slen + strlen(str) + 1);
if (g != 0) {
strcpy(g->inbox, inbox);
g->sep_char = '.';
dst = g->str;
if (flags & GLOB_SUBSTRING) {
if (newglob) {
while (*str == '*' || (*str == '%' && str[1])) ++str;
} else {
while (*str == '%' || *str == '*' || *str == '?') {
if (*str++ != '*') *dst++ = '?';
}
}
*dst++ = '*';
}
if (!newglob) {
while (*str) {
if (*str == '*') {
while (*str == '*' || *str == '%' || *str == '?') {
if (*str++ != '*') *dst++ = '?';
}
*dst++ = '*';
} else {
*dst++ = (char)((*str == '%') ? '?' : *str);
++str;
}
}
} else {
while (*str) {
if (*str == '*' || *str == '%') {
while (*str == '%') ++str;
if (*str == '*') {
while (*str == '*' || (*str == '%' && str[1])) ++str;
*dst++ = '*';
} else {
*dst++ = '%';
}
} else {
*dst++ = *str++;
}
}
}
if (flags & GLOB_SUBSTRING && dst[-1] != '*') {
if (newglob) while (dst[-1] == '%') --dst;
*dst++ = '*';
}
*dst++ = '\0';
if (flags & GLOB_ICASE) lcase(g->str);
g->flags = flags;
if (flags & GLOB_INBOXCASE) {
str = g->str;
dst = g->inbox;
g->gstar = g->ghier = NULL;
do {
while (*dst && TOLOWER(*str) == TOLOWER(*dst)) {
*dst++ = *str++;
}
if (*str == '*') g->gstar = ++str, g->ghier = 0;
else if (*str == '%') g->ghier = ++str;
else break;
if (*str != '%') {
while (*dst && TOLOWER(*str) != TOLOWER(*dst)) ++dst;
}
} while (*str && *dst);
g->gptr = str;
if (*dst) g->flags &= ~GLOB_INBOXCASE;
}
g->suppress = 0;
if (suppress) {
dst = g->str + strlen(g->str) + 1;
strcpy(dst, suppress);
str = g->str;
if (strncmp(suppress, str, slen) ||
(str[slen] != '\0' && str[slen] != g->sep_char
&& str[slen] != '*' && str[slen] != '%')) {
while (*str && *str == *suppress) ++str, ++suppress;
if ((g->flags & GLOB_INBOXCASE)
|| *str == '*' || *str == '%' || *suppress == '\0') {
g->suppress = dst;
g->slen = slen;
}
}
}
}
return (g);
}
void glob_free (g)
glob **g;
{
if (*g) free((void *) *g);
*g = NULL;
}
int glob_test (g, ptr, len, min)
glob* g;
const char* ptr;
long int len;
long int *min;
{
const char *gptr, *pend;
const char *gstar, *pstar;
const char *ghier, *phier;
const char *start;
int newglob;
int sepfound;
if (min && *min < 0) return (-1);
if (!len) len = strlen(ptr);
gptr = g->str;
start = ptr;
pend = ptr + len;
gstar = ghier = NULL;
newglob = g->flags & GLOB_HIERARCHY;
phier = pstar = NULL;
if ((g->flags & GLOB_INBOXCASE) && !strncmp(ptr, inbox, INBOXLEN)) {
pstar = phier = ptr += INBOXLEN;
gstar = g->gstar;
ghier = g->ghier;
gptr = g->gptr;
}
if (g->suppress && !strncmp(g->suppress, ptr, g->slen) &&
(ptr[g->slen] == '\0' || ptr[g->slen] == g->sep_char)) {
if (!(g->flags & GLOB_INBOXCASE)) {
if (min) *min = -1;
return (-1);
}
pstar = phier = ptr += g->slen;
gstar = g->gstar;
ghier = g->ghier;
gptr = g->gptr;
}
if (!(g->flags & GLOB_ICASE)) {
do {
sepfound = 0;
while (*gptr != '*' && *gptr != '%' && ptr != pend
&& (*gptr == *ptr || (!newglob && *gptr == '?'))) {
++ptr, ++gptr;
}
if (*gptr == '\0' && ptr == pend) {
break;
}
if (*gptr == '*') {
ghier = NULL;
gstar = ++gptr;
pstar = ptr;
}
if (*gptr == '%') {
ghier = ++gptr;
phier = ptr;
}
if (ghier) {
ptr = phier;
while (ptr != pend && *ghier != *ptr
&& (*ptr != g->sep_char ||
(!*ghier && gstar && *gstar == '%' && min
&& ptr - start < *min))) {
++ptr;
}
if (ptr == pend) {
gptr = ghier;
break;
}
if (*ptr == g->sep_char) {
if (!*ghier && min
&& *min < ptr - start && ptr != pend
&& *ptr == g->sep_char
) {
*min = gstar ? ptr - start + 1 : -1;
return (ptr - start);
}
ghier = NULL;
sepfound = 1;
} else {
phier = ++ptr;
gptr = ghier + 1;
}
}
if (gstar && !ghier) {
if (!*gstar) {
ptr = pend;
break;
}
while (pstar != pend && *gstar != *pstar) ++pstar;
if (pstar == pend) {
if (*gptr == '\0' && min && *min < ptr - start && ptr != pend &&
*ptr == g->sep_char) {
*min = ptr - start + 1;
return ptr - start;
}
gptr = gstar;
break;
}
ptr = ++pstar;
gptr = gstar + 1;
}
if (*gptr == '\0' && min && *min < ptr - start && ptr != pend &&
*ptr == g->sep_char) {
*min = ptr - start + 1;
return ptr - start;
}
} while (*gptr == '*' || *gptr == '%' ||
((gstar || ghier || sepfound) && (*gptr || ptr != pend)));
} else {
do {
sepfound = 0;
while (*gptr != '*' && *gptr != '%' && ptr != pend
&& ((unsigned char) *gptr == TOLOWER(*ptr) ||
(!newglob && *gptr == '?'))) {
++ptr, ++gptr;
}
if (*gptr == '\0' && ptr == pend) {
break;
}
if (*gptr == '*') {
ghier = NULL;
gstar = ++gptr;
pstar = ptr;
}
if (*gptr == '%') {
ghier = ++gptr;
phier = ptr;
}
if (ghier) {
ptr = phier;
while (ptr != pend && (unsigned char) *ghier != TOLOWER(*ptr)
&& (*ptr != g->sep_char ||
(!*ghier && gstar && *gstar == '%' && min
&& ptr - start < *min))) {
++ptr;
}
if (ptr == pend) {
gptr = ghier;
break;
}
if (*ptr == g->sep_char) {
if (!*ghier && min
&& *min < ptr - start && ptr != pend
&& *ptr == g->sep_char
) {
*min = gstar ? ptr - start + 1 : -1;
return (ptr - start);
}
ghier = NULL;
sepfound = 1;
} else {
phier = ++ptr;
gptr = ghier + 1;
}
}
if (gstar && !ghier) {
if (!*gstar) {
ptr = pend;
break;
}
while (pstar != pend &&
(unsigned char) *gstar != TOLOWER(*pstar)) ++pstar;
if (pstar == pend) {
if (*gptr == '\0' && min && *min < ptr - start && ptr != pend &&
*ptr == g->sep_char) {
*min = ptr - start + 1;
return ptr - start;
}
gptr = gstar;
break;
}
ptr = ++pstar;
gptr = gstar + 1;
}
if (*gptr == '\0' && min && *min < ptr - start && ptr != pend &&
*ptr == g->sep_char) {
*min = ptr - start + 1;
return ptr - start;
}
} while (*gptr == '*' || *gptr == '%' ||
((gstar || ghier || sepfound) && (*gptr || ptr != pend)));
}
if (min) *min = -1;
return (*gptr == '\0' && ptr == pend ? ptr - start : -1);
}
#ifdef TEST_GLOB
int main (argc, argv)
int argc;
char* argv[];
{
glob *g = glob_init_suppress(argv[1], GLOB_INBOXCASE|GLOB_HIERARCHY,
"user.nifty");
char text[1024];
int len;
long min;
if (g) {
printf("%d/%s/%s\n", g->flags, g->inbox, g->str);
while (fgets(text, sizeof (text), stdin) != NULL) {
len = strlen(text) - 1;
text[len] = '\0';
min = 0;
while (min >= 0) {
printf("%d\n", glob_test(g, text, len, &min));
}
}
}
}
#endif