Blame src/lib/libast/regex/regcache.c

Packit Service a8c26c
/***********************************************************************
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*               This software is part of the ast package               *
Packit Service a8c26c
*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
Packit Service a8c26c
*                      and is licensed under the                       *
Packit Service a8c26c
*                 Eclipse Public License, Version 1.0                  *
Packit Service a8c26c
*                    by AT&T Intellectual Property                     *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                A copy of the License is available at                 *
Packit Service a8c26c
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit Service a8c26c
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*              Information and Software Systems Research               *
Packit Service a8c26c
*                            AT&T Research                             *
Packit Service a8c26c
*                           Florham Park NJ                            *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                 Glenn Fowler <gsf@research.att.com>                  *
Packit Service a8c26c
*                  David Korn <dgk@research.att.com>                   *
Packit Service a8c26c
*                   Phong Vo <kpv@research.att.com>                    *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
***********************************************************************/
Packit Service a8c26c
#pragma prototyped
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * regcomp() regex_t cache
Packit Service a8c26c
 * at&t research
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
#include <ast.h>
Packit Service a8c26c
#include <regex.h>
Packit Service a8c26c
Packit Service a8c26c
#define CACHE		8		/* default # cached re's	*/
Packit Service a8c26c
#define ROUND		64		/* pattern buffer size round	*/
Packit Service a8c26c
Packit Service a8c26c
typedef unsigned long Key_t;
Packit Service a8c26c
Packit Service a8c26c
typedef struct Cache_s
Packit Service a8c26c
{
Packit Service a8c26c
	char*		pattern;
Packit Service a8c26c
	regex_t		re;
Packit Service a8c26c
	unsigned long	serial;
Packit Service a8c26c
	regflags_t	reflags;
Packit Service a8c26c
	int		keep;
Packit Service a8c26c
	int		size;
Packit Service a8c26c
} Cache_t;
Packit Service a8c26c
Packit Service a8c26c
typedef struct State_s
Packit Service a8c26c
{
Packit Service a8c26c
	unsigned int	size;
Packit Service a8c26c
	unsigned long	serial;
Packit Service a8c26c
	char*		locale;
Packit Service a8c26c
	Cache_t**	cache;
Packit Service a8c26c
} State_t;
Packit Service a8c26c
Packit Service a8c26c
static State_t	matchstate;
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * flush the cache
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
static void
Packit Service a8c26c
flushcache(void)
Packit Service a8c26c
{
Packit Service a8c26c
	register int		i;
Packit Service a8c26c
Packit Service a8c26c
	for (i = matchstate.size; i--;)
Packit Service a8c26c
		if (matchstate.cache[i] && matchstate.cache[i]->keep)
Packit Service a8c26c
		{
Packit Service a8c26c
			matchstate.cache[i]->keep = 0;
Packit Service a8c26c
			regfree(&matchstate.cache[i]->re);
Packit Service a8c26c
		}
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * return regcomp() compiled re for pattern and reflags
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
regex_t*
Packit Service a8c26c
regcache(const char* pattern, regflags_t reflags, int* status)
Packit Service a8c26c
{
Packit Service a8c26c
	register Cache_t*	cp;
Packit Service a8c26c
	register int		i;
Packit Service a8c26c
	char*			s;
Packit Service a8c26c
	int			empty;
Packit Service a8c26c
	int			unused;
Packit Service a8c26c
	int			old;
Packit Service a8c26c
	Key_t			key;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * 0 pattern flushes the cache and reflags>0 extends cache
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (!pattern)
Packit Service a8c26c
	{
Packit Service a8c26c
		flushcache();
Packit Service a8c26c
		i = 0;
Packit Service a8c26c
		if (reflags > matchstate.size)
Packit Service a8c26c
		{
Packit Service a8c26c
			if (matchstate.cache = newof(matchstate.cache, Cache_t*, reflags, 0))
Packit Service a8c26c
				matchstate.size = reflags;
Packit Service a8c26c
			else
Packit Service a8c26c
			{
Packit Service a8c26c
				matchstate.size = 0;
Packit Service a8c26c
				i = 1;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
		if (status)
Packit Service a8c26c
			*status = i;
Packit Service a8c26c
		return 0;
Packit Service a8c26c
	}
Packit Service a8c26c
	if (!matchstate.cache)
Packit Service a8c26c
	{
Packit Service a8c26c
		if (!(matchstate.cache = newof(0, Cache_t*, CACHE, 0)))
Packit Service a8c26c
			return 0;
Packit Service a8c26c
		matchstate.size = CACHE;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * flush the cache if the locale changed
Packit Service a8c26c
	 * the ast setlocale() intercept maintains
Packit Service a8c26c
	 * persistent setlocale() return values
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
Packit Service a8c26c
	{
Packit Service a8c26c
		matchstate.locale = s;
Packit Service a8c26c
		flushcache();
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * check if the pattern is in the cache
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	for (i = 0; i < sizeof(key) && pattern[i]; i++)
Packit Service a8c26c
		((char*)&key)[i] = pattern[i];
Packit Service a8c26c
	for (; i < sizeof(key); i++)
Packit Service a8c26c
		((char*)&key)[i] = 0;
Packit Service a8c26c
	empty = unused = -1;
Packit Service a8c26c
	old = 0;
Packit Service a8c26c
	for (i = matchstate.size; i--;)
Packit Service a8c26c
		if (!matchstate.cache[i])
Packit Service a8c26c
			empty = i;
Packit Service a8c26c
		else if (!matchstate.cache[i]->keep)
Packit Service a8c26c
			unused = i;
Packit Service a8c26c
		else if (*(Key_t*)matchstate.cache[i]->pattern == key && !strcmp(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags)
Packit Service a8c26c
			break;
Packit Service a8c26c
		else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
Packit Service a8c26c
			old = i;
Packit Service a8c26c
	if (i < 0)
Packit Service a8c26c
	{
Packit Service a8c26c
		if (unused < 0)
Packit Service a8c26c
		{
Packit Service a8c26c
			if (empty < 0)
Packit Service a8c26c
				unused = old;
Packit Service a8c26c
			else
Packit Service a8c26c
				unused = empty;
Packit Service a8c26c
		}
Packit Service a8c26c
		if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
Packit Service a8c26c
		{
Packit Service a8c26c
			if (status)
Packit Service a8c26c
				*status = REG_ESPACE;
Packit Service a8c26c
			return 0;
Packit Service a8c26c
		}
Packit Service a8c26c
		if (cp->keep)
Packit Service a8c26c
		{
Packit Service a8c26c
			cp->keep = 0;
Packit Service a8c26c
			regfree(&cp->re);
Packit Service a8c26c
		}
Packit Service a8c26c
		if ((i = strlen(pattern) + 1) > cp->size)
Packit Service a8c26c
		{
Packit Service a8c26c
			cp->size = roundof(i, ROUND);
Packit Service a8c26c
			if (!(cp->pattern = newof(cp->pattern, char, cp->size, 0)))
Packit Service a8c26c
			{
Packit Service a8c26c
				if (status)
Packit Service a8c26c
					*status = REG_ESPACE;
Packit Service a8c26c
				return 0;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
		strcpy(cp->pattern, pattern);
Packit Service a8c26c
		while (++i < sizeof(Key_t))
Packit Service a8c26c
			cp->pattern[i] = 0;
Packit Service a8c26c
		pattern = (const char*)cp->pattern;
Packit Service a8c26c
		if (i = regcomp(&cp->re, pattern, reflags))
Packit Service a8c26c
		{
Packit Service a8c26c
			if (status)
Packit Service a8c26c
				*status = i;
Packit Service a8c26c
			return 0;
Packit Service a8c26c
		}
Packit Service a8c26c
		cp->keep = 1;
Packit Service a8c26c
		cp->reflags = reflags;
Packit Service a8c26c
	}
Packit Service a8c26c
	else
Packit Service a8c26c
		cp = matchstate.cache[i];
Packit Service a8c26c
	cp->serial = ++matchstate.serial;
Packit Service a8c26c
	if (status)
Packit Service a8c26c
		*status = 0;
Packit Service a8c26c
	return &cp->re;
Packit Service a8c26c
}