xref: /titanic_50/usr/src/lib/libast/common/regex/regcache.c (revision b323a6159ab002be737b0f5f6a56ade96637e5bd)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2009 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 /*
25  * regcomp() regex_t cache
26  * AT&T Research
27  */
28 
29 #include <ast.h>
30 #include <regex.h>
31 
32 #define CACHE		8		/* default # cached re's	*/
33 #define MAXPAT		256		/* max pattern length + 1	*/
34 
35 #define KEEP		01
36 #define DROP		02
37 
38 typedef union Pattern_u
39 {
40 	unsigned long	key;
41 	char		buf[MAXPAT];
42 } Pattern_t;
43 
44 typedef struct Cache_s
45 {
46 	Pattern_t	pattern;
47 	regex_t		re;
48 	unsigned long	serial;
49 	regflags_t	reflags;
50 	int		flags;
51 } Cache_t;
52 
53 typedef struct State_s
54 {
55 	unsigned int	size;
56 	unsigned long	serial;
57 	char*		locale;
58 	Cache_t**	cache;
59 } State_t;
60 
61 static State_t	matchstate;
62 
63 /*
64  * flush the cache
65  */
66 
67 static void
68 flushcache(void)
69 {
70 	register int		i;
71 
72 	for (i = matchstate.size; i--;)
73 		if (matchstate.cache[i] && matchstate.cache[i]->flags)
74 		{
75 			matchstate.cache[i]->flags = 0;
76 			regfree(&matchstate.cache[i]->re);
77 		}
78 }
79 
80 /*
81  * return regcomp() compiled re for pattern and reflags
82  */
83 
84 regex_t*
85 regcache(const char* pattern, regflags_t reflags, int* status)
86 {
87 	register Cache_t*	cp;
88 	register int		i;
89 	char*			s;
90 	int			empty;
91 	int			unused;
92 	int			old;
93 	Pattern_t		head;
94 
95 	/*
96 	 * 0 pattern flushes the cache and reflags>0 extends cache
97 	 */
98 
99 	if (!pattern)
100 	{
101 		flushcache();
102 		i = 0;
103 		if (reflags > matchstate.size)
104 		{
105 			if (matchstate.cache = newof(matchstate.cache, Cache_t*, reflags, 0))
106 				matchstate.size = reflags;
107 			else
108 			{
109 				matchstate.size = 0;
110 				i = 1;
111 			}
112 		}
113 		if (status)
114 			*status = i;
115 		return 0;
116 	}
117 	if (!matchstate.cache)
118 	{
119 		if (!(matchstate.cache = newof(0, Cache_t*, CACHE, 0)))
120 			return 0;
121 		matchstate.size = CACHE;
122 	}
123 
124 	/*
125 	 * flush the cache if the locale changed
126 	 * the ast setlocale() intercept maintains
127 	 * persistent setlocale() return values
128 	 */
129 
130 	if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
131 	{
132 		matchstate.locale = s;
133 		flushcache();
134 	}
135 
136 	/*
137 	 * check if the pattern is in the cache
138 	 */
139 
140 	for (i = 0; i < sizeof(unsigned long) && pattern[i]; i++)
141 		head.buf[i] = pattern[i];
142 	for (; i < sizeof(unsigned long); i++)
143 		head.buf[i] = 0;
144 	empty = unused = -1;
145 	old = 0;
146 	for (i = matchstate.size; i--;)
147 		if (!matchstate.cache[i])
148 			empty = i;
149 		else if (!(matchstate.cache[i]->flags & KEEP))
150 		{
151 			if (matchstate.cache[i]->flags)
152 			{
153 				matchstate.cache[i]->flags = 0;
154 				regfree(&matchstate.cache[i]->re);
155 			}
156 			unused = i;
157 		}
158 		else if (matchstate.cache[i]->pattern.key == head.key && !strcmp(matchstate.cache[i]->pattern.buf, pattern) && matchstate.cache[i]->reflags == reflags)
159 			break;
160 		else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
161 			old = i;
162 	if (i < 0)
163 	{
164 		if (unused < 0)
165 		{
166 			if (empty < 0)
167 				unused = old;
168 			else
169 				unused = empty;
170 		}
171 		if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
172 		{
173 			if (status)
174 				*status = REG_ESPACE;
175 			return 0;
176 		}
177 		if (cp->flags)
178 		{
179 			cp->flags = 0;
180 			regfree(&cp->re);
181 		}
182 		cp->reflags = reflags;
183 		if ((i = strlen(pattern)) < sizeof(cp->pattern.buf))
184 		{
185 			if (i < sizeof(unsigned long))
186 				memset(cp->pattern.buf, 0, sizeof(unsigned long));
187 			strcpy(cp->pattern.buf, pattern);
188 			pattern = (const char*)cp->pattern.buf;
189 			cp->flags = KEEP;
190 		}
191 		else
192 			cp->flags = DROP;
193 		if (i = regcomp(&cp->re, pattern, cp->reflags))
194 		{
195 			if (status)
196 				*status = i;
197 			cp->flags = 0;
198 			return 0;
199 		}
200 	}
201 	else
202 		cp = matchstate.cache[i];
203 	cp->serial = ++matchstate.serial;
204 	if (status)
205 		*status = 0;
206 	return &cp->re;
207 }
208