xref: /titanic_51/usr/src/lib/libast/common/regex/regcache.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * regcomp() regex_t cache
26*3e14f97fSRoger A. Faulkner  * at&t research
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include <ast.h>
30da2e3ebdSchin #include <regex.h>
31da2e3ebdSchin 
327c2fbfb3SApril Chin #define CACHE		8		/* default # cached re's	*/
33*3e14f97fSRoger A. Faulkner #define ROUND		64		/* pattern buffer size round	*/
34da2e3ebdSchin 
35*3e14f97fSRoger A. Faulkner typedef unsigned long Key_t;
367c2fbfb3SApril Chin 
37da2e3ebdSchin typedef struct Cache_s
38da2e3ebdSchin {
39*3e14f97fSRoger A. Faulkner 	char*		pattern;
40da2e3ebdSchin 	regex_t		re;
41da2e3ebdSchin 	unsigned long	serial;
42da2e3ebdSchin 	regflags_t	reflags;
43*3e14f97fSRoger A. Faulkner 	int		keep;
44*3e14f97fSRoger A. Faulkner 	int		size;
45da2e3ebdSchin } Cache_t;
46da2e3ebdSchin 
477c2fbfb3SApril Chin typedef struct State_s
48da2e3ebdSchin {
497c2fbfb3SApril Chin 	unsigned int	size;
50da2e3ebdSchin 	unsigned long	serial;
51da2e3ebdSchin 	char*		locale;
527c2fbfb3SApril Chin 	Cache_t**	cache;
537c2fbfb3SApril Chin } State_t;
547c2fbfb3SApril Chin 
557c2fbfb3SApril Chin static State_t	matchstate;
56da2e3ebdSchin 
57da2e3ebdSchin /*
58da2e3ebdSchin  * flush the cache
59da2e3ebdSchin  */
60da2e3ebdSchin 
61da2e3ebdSchin static void
flushcache(void)62da2e3ebdSchin flushcache(void)
63da2e3ebdSchin {
64da2e3ebdSchin 	register int		i;
65da2e3ebdSchin 
667c2fbfb3SApril Chin 	for (i = matchstate.size; i--;)
67*3e14f97fSRoger A. Faulkner 		if (matchstate.cache[i] && matchstate.cache[i]->keep)
68da2e3ebdSchin 		{
69*3e14f97fSRoger A. Faulkner 			matchstate.cache[i]->keep = 0;
70da2e3ebdSchin 			regfree(&matchstate.cache[i]->re);
71da2e3ebdSchin 		}
72da2e3ebdSchin }
73da2e3ebdSchin 
74da2e3ebdSchin /*
75da2e3ebdSchin  * return regcomp() compiled re for pattern and reflags
76da2e3ebdSchin  */
77da2e3ebdSchin 
78da2e3ebdSchin regex_t*
regcache(const char * pattern,regflags_t reflags,int * status)79da2e3ebdSchin regcache(const char* pattern, regflags_t reflags, int* status)
80da2e3ebdSchin {
81da2e3ebdSchin 	register Cache_t*	cp;
82da2e3ebdSchin 	register int		i;
83da2e3ebdSchin 	char*			s;
84da2e3ebdSchin 	int			empty;
85da2e3ebdSchin 	int			unused;
86da2e3ebdSchin 	int			old;
87*3e14f97fSRoger A. Faulkner 	Key_t			key;
88da2e3ebdSchin 
89da2e3ebdSchin 	/*
907c2fbfb3SApril Chin 	 * 0 pattern flushes the cache and reflags>0 extends cache
91da2e3ebdSchin 	 */
92da2e3ebdSchin 
93da2e3ebdSchin 	if (!pattern)
94da2e3ebdSchin 	{
95da2e3ebdSchin 		flushcache();
967c2fbfb3SApril Chin 		i = 0;
977c2fbfb3SApril Chin 		if (reflags > matchstate.size)
987c2fbfb3SApril Chin 		{
997c2fbfb3SApril Chin 			if (matchstate.cache = newof(matchstate.cache, Cache_t*, reflags, 0))
1007c2fbfb3SApril Chin 				matchstate.size = reflags;
1017c2fbfb3SApril Chin 			else
1027c2fbfb3SApril Chin 			{
1037c2fbfb3SApril Chin 				matchstate.size = 0;
1047c2fbfb3SApril Chin 				i = 1;
1057c2fbfb3SApril Chin 			}
1067c2fbfb3SApril Chin 		}
107da2e3ebdSchin 		if (status)
1087c2fbfb3SApril Chin 			*status = i;
109da2e3ebdSchin 		return 0;
110da2e3ebdSchin 	}
1117c2fbfb3SApril Chin 	if (!matchstate.cache)
1127c2fbfb3SApril Chin 	{
1137c2fbfb3SApril Chin 		if (!(matchstate.cache = newof(0, Cache_t*, CACHE, 0)))
1147c2fbfb3SApril Chin 			return 0;
1157c2fbfb3SApril Chin 		matchstate.size = CACHE;
1167c2fbfb3SApril Chin 	}
117da2e3ebdSchin 
118da2e3ebdSchin 	/*
119da2e3ebdSchin 	 * flush the cache if the locale changed
120da2e3ebdSchin 	 * the ast setlocale() intercept maintains
121da2e3ebdSchin 	 * persistent setlocale() return values
122da2e3ebdSchin 	 */
123da2e3ebdSchin 
124da2e3ebdSchin 	if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
125da2e3ebdSchin 	{
126da2e3ebdSchin 		matchstate.locale = s;
127da2e3ebdSchin 		flushcache();
128da2e3ebdSchin 	}
129da2e3ebdSchin 
130da2e3ebdSchin 	/*
131da2e3ebdSchin 	 * check if the pattern is in the cache
132da2e3ebdSchin 	 */
133da2e3ebdSchin 
134*3e14f97fSRoger A. Faulkner 	for (i = 0; i < sizeof(key) && pattern[i]; i++)
135*3e14f97fSRoger A. Faulkner 		((char*)&key)[i] = pattern[i];
136*3e14f97fSRoger A. Faulkner 	for (; i < sizeof(key); i++)
137*3e14f97fSRoger A. Faulkner 		((char*)&key)[i] = 0;
138da2e3ebdSchin 	empty = unused = -1;
139da2e3ebdSchin 	old = 0;
1407c2fbfb3SApril Chin 	for (i = matchstate.size; i--;)
141da2e3ebdSchin 		if (!matchstate.cache[i])
142da2e3ebdSchin 			empty = i;
143*3e14f97fSRoger A. Faulkner 		else if (!matchstate.cache[i]->keep)
144da2e3ebdSchin 			unused = i;
145*3e14f97fSRoger A. Faulkner 		else if (*(Key_t*)matchstate.cache[i]->pattern == key && !strcmp(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags)
146da2e3ebdSchin 			break;
147da2e3ebdSchin 		else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
148da2e3ebdSchin 			old = i;
1497c2fbfb3SApril Chin 	if (i < 0)
150da2e3ebdSchin 	{
151da2e3ebdSchin 		if (unused < 0)
152da2e3ebdSchin 		{
153da2e3ebdSchin 			if (empty < 0)
154da2e3ebdSchin 				unused = old;
155da2e3ebdSchin 			else
156da2e3ebdSchin 				unused = empty;
157da2e3ebdSchin 		}
158da2e3ebdSchin 		if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
159da2e3ebdSchin 		{
160da2e3ebdSchin 			if (status)
161da2e3ebdSchin 				*status = REG_ESPACE;
162da2e3ebdSchin 			return 0;
163da2e3ebdSchin 		}
164*3e14f97fSRoger A. Faulkner 		if (cp->keep)
165da2e3ebdSchin 		{
166*3e14f97fSRoger A. Faulkner 			cp->keep = 0;
167da2e3ebdSchin 			regfree(&cp->re);
168da2e3ebdSchin 		}
169*3e14f97fSRoger A. Faulkner 		if ((i = strlen(pattern) + 1) >= cp->size)
170da2e3ebdSchin 		{
171*3e14f97fSRoger A. Faulkner 			cp->size = roundof(i, ROUND);
172*3e14f97fSRoger A. Faulkner 			if (!(cp->pattern = newof(cp->pattern, char, cp->size, 0)))
173*3e14f97fSRoger A. Faulkner 			{
174*3e14f97fSRoger A. Faulkner 				if (status)
175*3e14f97fSRoger A. Faulkner 					*status = REG_ESPACE;
176*3e14f97fSRoger A. Faulkner 				return 0;
177da2e3ebdSchin 			}
178*3e14f97fSRoger A. Faulkner 		}
179*3e14f97fSRoger A. Faulkner 		strcpy(cp->pattern, pattern);
180*3e14f97fSRoger A. Faulkner 		while (++i < sizeof(Key_t))
181*3e14f97fSRoger A. Faulkner 			cp->pattern[i] = 0;
182*3e14f97fSRoger A. Faulkner 		pattern = (const char*)cp->pattern;
183*3e14f97fSRoger A. Faulkner 		if (i = regcomp(&cp->re, pattern, reflags))
184da2e3ebdSchin 		{
185da2e3ebdSchin 			if (status)
186da2e3ebdSchin 				*status = i;
187da2e3ebdSchin 			return 0;
188da2e3ebdSchin 		}
189*3e14f97fSRoger A. Faulkner 		cp->keep = 1;
190*3e14f97fSRoger A. Faulkner 		cp->reflags = reflags;
191da2e3ebdSchin 	}
192da2e3ebdSchin 	else
193da2e3ebdSchin 		cp = matchstate.cache[i];
194da2e3ebdSchin 	cp->serial = ++matchstate.serial;
195da2e3ebdSchin 	if (status)
196da2e3ebdSchin 		*status = 0;
197da2e3ebdSchin 	return &cp->re;
198da2e3ebdSchin }
199