#pragma prototyped
#include <ast.h>
#include <regex.h>
#define CACHE 8
#define MAXPAT 256
#define KEEP 01
#define DROP 02
typedef struct Cache_s
{
regex_t re;
unsigned long serial;
regflags_t reflags;
int flags;
char pattern[MAXPAT];
} Cache_t;
static struct State_s
{
Cache_t* cache[CACHE];
unsigned long serial;
char* locale;
} matchstate;
static void
flushcache(void)
{
register int i;
for (i = 0; i < elementsof(matchstate.cache); i++)
if (matchstate.cache[i] && matchstate.cache[i]->flags)
{
matchstate.cache[i]->flags = 0;
regfree(&matchstate.cache[i]->re);
}
}
regex_t*
regcache(const char* pattern, regflags_t reflags, int* status)
{
register Cache_t* cp;
register int i;
char* s;
int empty;
int unused;
int old;
if (!pattern)
{
flushcache();
if (status)
*status = 0;
return 0;
}
if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
{
matchstate.locale = s;
flushcache();
}
empty = unused = -1;
old = 0;
for (i = 0; i < elementsof(matchstate.cache); i++)
if (!matchstate.cache[i])
empty = i;
else if (!(matchstate.cache[i]->flags & KEEP))
{
if (matchstate.cache[i]->flags)
{
matchstate.cache[i]->flags = 0;
regfree(&matchstate.cache[i]->re);
}
unused = i;
}
else if (streq(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags)
break;
else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
old = i;
if (i >= elementsof(matchstate.cache))
{
if (unused < 0)
{
if (empty < 0)
unused = old;
else
unused = empty;
}
if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
{
if (status)
*status = REG_ESPACE;
return 0;
}
if (cp->flags)
{
cp->flags = 0;
regfree(&cp->re);
}
cp->reflags = reflags;
if (strlen(pattern) < sizeof(cp->pattern))
{
strcpy(cp->pattern, pattern);
pattern = (const char*)cp->pattern;
cp->flags = KEEP;
}
else
cp->flags = DROP;
if (i = regcomp(&cp->re, pattern, cp->reflags))
{
if (status)
*status = i;
cp->flags = 0;
return 0;
}
}
else
cp = matchstate.cache[i];
cp->serial = ++matchstate.serial;
if (status)
*status = 0;
return &cp->re;
}