xref: /onnv-gate/usr/src/lib/libast/common/regex/regcache.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * regcomp() regex_t cache
26*12068SRoger.Faulkner@Oracle.COM  * at&t research
274887Schin  */
284887Schin 
294887Schin #include <ast.h>
304887Schin #include <regex.h>
314887Schin 
328462SApril.Chin@Sun.COM #define CACHE		8		/* default # cached re's	*/
33*12068SRoger.Faulkner@Oracle.COM #define ROUND		64		/* pattern buffer size round	*/
344887Schin 
35*12068SRoger.Faulkner@Oracle.COM typedef unsigned long Key_t;
368462SApril.Chin@Sun.COM 
374887Schin typedef struct Cache_s
384887Schin {
39*12068SRoger.Faulkner@Oracle.COM 	char*		pattern;
404887Schin 	regex_t		re;
414887Schin 	unsigned long	serial;
424887Schin 	regflags_t	reflags;
43*12068SRoger.Faulkner@Oracle.COM 	int		keep;
44*12068SRoger.Faulkner@Oracle.COM 	int		size;
454887Schin } Cache_t;
464887Schin 
478462SApril.Chin@Sun.COM typedef struct State_s
484887Schin {
498462SApril.Chin@Sun.COM 	unsigned int	size;
504887Schin 	unsigned long	serial;
514887Schin 	char*		locale;
528462SApril.Chin@Sun.COM 	Cache_t**	cache;
538462SApril.Chin@Sun.COM } State_t;
548462SApril.Chin@Sun.COM 
558462SApril.Chin@Sun.COM static State_t	matchstate;
564887Schin 
574887Schin /*
584887Schin  * flush the cache
594887Schin  */
604887Schin 
614887Schin static void
flushcache(void)624887Schin flushcache(void)
634887Schin {
644887Schin 	register int		i;
654887Schin 
668462SApril.Chin@Sun.COM 	for (i = matchstate.size; i--;)
67*12068SRoger.Faulkner@Oracle.COM 		if (matchstate.cache[i] && matchstate.cache[i]->keep)
684887Schin 		{
69*12068SRoger.Faulkner@Oracle.COM 			matchstate.cache[i]->keep = 0;
704887Schin 			regfree(&matchstate.cache[i]->re);
714887Schin 		}
724887Schin }
734887Schin 
744887Schin /*
754887Schin  * return regcomp() compiled re for pattern and reflags
764887Schin  */
774887Schin 
784887Schin regex_t*
regcache(const char * pattern,regflags_t reflags,int * status)794887Schin regcache(const char* pattern, regflags_t reflags, int* status)
804887Schin {
814887Schin 	register Cache_t*	cp;
824887Schin 	register int		i;
834887Schin 	char*			s;
844887Schin 	int			empty;
854887Schin 	int			unused;
864887Schin 	int			old;
87*12068SRoger.Faulkner@Oracle.COM 	Key_t			key;
884887Schin 
894887Schin 	/*
908462SApril.Chin@Sun.COM 	 * 0 pattern flushes the cache and reflags>0 extends cache
914887Schin 	 */
924887Schin 
934887Schin 	if (!pattern)
944887Schin 	{
954887Schin 		flushcache();
968462SApril.Chin@Sun.COM 		i = 0;
978462SApril.Chin@Sun.COM 		if (reflags > matchstate.size)
988462SApril.Chin@Sun.COM 		{
998462SApril.Chin@Sun.COM 			if (matchstate.cache = newof(matchstate.cache, Cache_t*, reflags, 0))
1008462SApril.Chin@Sun.COM 				matchstate.size = reflags;
1018462SApril.Chin@Sun.COM 			else
1028462SApril.Chin@Sun.COM 			{
1038462SApril.Chin@Sun.COM 				matchstate.size = 0;
1048462SApril.Chin@Sun.COM 				i = 1;
1058462SApril.Chin@Sun.COM 			}
1068462SApril.Chin@Sun.COM 		}
1074887Schin 		if (status)
1088462SApril.Chin@Sun.COM 			*status = i;
1094887Schin 		return 0;
1104887Schin 	}
1118462SApril.Chin@Sun.COM 	if (!matchstate.cache)
1128462SApril.Chin@Sun.COM 	{
1138462SApril.Chin@Sun.COM 		if (!(matchstate.cache = newof(0, Cache_t*, CACHE, 0)))
1148462SApril.Chin@Sun.COM 			return 0;
1158462SApril.Chin@Sun.COM 		matchstate.size = CACHE;
1168462SApril.Chin@Sun.COM 	}
1174887Schin 
1184887Schin 	/*
1194887Schin 	 * flush the cache if the locale changed
1204887Schin 	 * the ast setlocale() intercept maintains
1214887Schin 	 * persistent setlocale() return values
1224887Schin 	 */
1234887Schin 
1244887Schin 	if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
1254887Schin 	{
1264887Schin 		matchstate.locale = s;
1274887Schin 		flushcache();
1284887Schin 	}
1294887Schin 
1304887Schin 	/*
1314887Schin 	 * check if the pattern is in the cache
1324887Schin 	 */
1334887Schin 
134*12068SRoger.Faulkner@Oracle.COM 	for (i = 0; i < sizeof(key) && pattern[i]; i++)
135*12068SRoger.Faulkner@Oracle.COM 		((char*)&key)[i] = pattern[i];
136*12068SRoger.Faulkner@Oracle.COM 	for (; i < sizeof(key); i++)
137*12068SRoger.Faulkner@Oracle.COM 		((char*)&key)[i] = 0;
1384887Schin 	empty = unused = -1;
1394887Schin 	old = 0;
1408462SApril.Chin@Sun.COM 	for (i = matchstate.size; i--;)
1414887Schin 		if (!matchstate.cache[i])
1424887Schin 			empty = i;
143*12068SRoger.Faulkner@Oracle.COM 		else if (!matchstate.cache[i]->keep)
1444887Schin 			unused = i;
145*12068SRoger.Faulkner@Oracle.COM 		else if (*(Key_t*)matchstate.cache[i]->pattern == key && !strcmp(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags)
1464887Schin 			break;
1474887Schin 		else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
1484887Schin 			old = i;
1498462SApril.Chin@Sun.COM 	if (i < 0)
1504887Schin 	{
1514887Schin 		if (unused < 0)
1524887Schin 		{
1534887Schin 			if (empty < 0)
1544887Schin 				unused = old;
1554887Schin 			else
1564887Schin 				unused = empty;
1574887Schin 		}
1584887Schin 		if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
1594887Schin 		{
1604887Schin 			if (status)
1614887Schin 				*status = REG_ESPACE;
1624887Schin 			return 0;
1634887Schin 		}
164*12068SRoger.Faulkner@Oracle.COM 		if (cp->keep)
1654887Schin 		{
166*12068SRoger.Faulkner@Oracle.COM 			cp->keep = 0;
1674887Schin 			regfree(&cp->re);
1684887Schin 		}
169*12068SRoger.Faulkner@Oracle.COM 		if ((i = strlen(pattern) + 1) >= cp->size)
1704887Schin 		{
171*12068SRoger.Faulkner@Oracle.COM 			cp->size = roundof(i, ROUND);
172*12068SRoger.Faulkner@Oracle.COM 			if (!(cp->pattern = newof(cp->pattern, char, cp->size, 0)))
173*12068SRoger.Faulkner@Oracle.COM 			{
174*12068SRoger.Faulkner@Oracle.COM 				if (status)
175*12068SRoger.Faulkner@Oracle.COM 					*status = REG_ESPACE;
176*12068SRoger.Faulkner@Oracle.COM 				return 0;
177*12068SRoger.Faulkner@Oracle.COM 			}
1784887Schin 		}
179*12068SRoger.Faulkner@Oracle.COM 		strcpy(cp->pattern, pattern);
180*12068SRoger.Faulkner@Oracle.COM 		while (++i < sizeof(Key_t))
181*12068SRoger.Faulkner@Oracle.COM 			cp->pattern[i] = 0;
182*12068SRoger.Faulkner@Oracle.COM 		pattern = (const char*)cp->pattern;
183*12068SRoger.Faulkner@Oracle.COM 		if (i = regcomp(&cp->re, pattern, reflags))
1844887Schin 		{
1854887Schin 			if (status)
1864887Schin 				*status = i;
1874887Schin 			return 0;
1884887Schin 		}
189*12068SRoger.Faulkner@Oracle.COM 		cp->keep = 1;
190*12068SRoger.Faulkner@Oracle.COM 		cp->reflags = reflags;
1914887Schin 	}
1924887Schin 	else
1934887Schin 		cp = matchstate.cache[i];
1944887Schin 	cp->serial = ++matchstate.serial;
1954887Schin 	if (status)
1964887Schin 		*status = 0;
1974887Schin 	return &cp->re;
1984887Schin }
199