xref: /titanic_41/usr/src/lib/libast/common/regex/regcache.c (revision ed5289f91b9bf164dccd6c75398362be77a4478d)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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		/* # cached re's		*/
33 #define MAXPAT		256		/* max pattern length + 1	*/
34 
35 #define KEEP		01
36 #define DROP		02
37 
38 typedef struct Cache_s
39 {
40 	regex_t		re;
41 	unsigned long	serial;
42 	regflags_t	reflags;
43 	int		flags;
44 	char		pattern[MAXPAT];
45 } Cache_t;
46 
47 static struct State_s
48 {
49 	Cache_t*	cache[CACHE];
50 	unsigned long	serial;
51 	char*		locale;
52 } matchstate;
53 
54 /*
55  * flush the cache
56  */
57 
58 static void
59 flushcache(void)
60 {
61 	register int		i;
62 
63 	for (i = 0; i < elementsof(matchstate.cache); i++)
64 		if (matchstate.cache[i] && matchstate.cache[i]->flags)
65 		{
66 			matchstate.cache[i]->flags = 0;
67 			regfree(&matchstate.cache[i]->re);
68 		}
69 }
70 
71 /*
72  * return regcomp() compiled re for pattern and reflags
73  */
74 
75 regex_t*
76 regcache(const char* pattern, regflags_t reflags, int* status)
77 {
78 	register Cache_t*	cp;
79 	register int		i;
80 	char*			s;
81 	int			empty;
82 	int			unused;
83 	int			old;
84 
85 	/*
86 	 * 0 pattern flushes the cache
87 	 */
88 
89 	if (!pattern)
90 	{
91 		flushcache();
92 		if (status)
93 			*status = 0;
94 		return 0;
95 	}
96 
97 	/*
98 	 * flush the cache if the locale changed
99 	 * the ast setlocale() intercept maintains
100 	 * persistent setlocale() return values
101 	 */
102 
103 	if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
104 	{
105 		matchstate.locale = s;
106 		flushcache();
107 	}
108 
109 	/*
110 	 * check if the pattern is in the cache
111 	 */
112 
113 	empty = unused = -1;
114 	old = 0;
115 	for (i = 0; i < elementsof(matchstate.cache); i++)
116 		if (!matchstate.cache[i])
117 			empty = i;
118 		else if (!(matchstate.cache[i]->flags & KEEP))
119 		{
120 			if (matchstate.cache[i]->flags)
121 			{
122 				matchstate.cache[i]->flags = 0;
123 				regfree(&matchstate.cache[i]->re);
124 			}
125 			unused = i;
126 		}
127 		else if (streq(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags)
128 			break;
129 		else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
130 			old = i;
131 	if (i >= elementsof(matchstate.cache))
132 	{
133 		if (unused < 0)
134 		{
135 			if (empty < 0)
136 				unused = old;
137 			else
138 				unused = empty;
139 		}
140 		if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
141 		{
142 			if (status)
143 				*status = REG_ESPACE;
144 			return 0;
145 		}
146 		if (cp->flags)
147 		{
148 			cp->flags = 0;
149 			regfree(&cp->re);
150 		}
151 		cp->reflags = reflags;
152 		if (strlen(pattern) < sizeof(cp->pattern))
153 		{
154 			strcpy(cp->pattern, pattern);
155 			pattern = (const char*)cp->pattern;
156 			cp->flags = KEEP;
157 		}
158 		else
159 			cp->flags = DROP;
160 		if (i = regcomp(&cp->re, pattern, cp->reflags))
161 		{
162 			if (status)
163 				*status = i;
164 			cp->flags = 0;
165 			return 0;
166 		}
167 	}
168 	else
169 		cp = matchstate.cache[i];
170 	cp->serial = ++matchstate.serial;
171 	if (status)
172 		*status = 0;
173 	return &cp->re;
174 }
175