1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 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 ROUND 64 /* pattern buffer size round */
34
35 typedef unsigned long Key_t;
36
37 typedef struct Cache_s
38 {
39 char* pattern;
40 regex_t re;
41 unsigned long serial;
42 regflags_t reflags;
43 int keep;
44 int size;
45 } Cache_t;
46
47 typedef struct State_s
48 {
49 unsigned int size;
50 unsigned long serial;
51 char* locale;
52 Cache_t** cache;
53 } State_t;
54
55 static State_t matchstate;
56
57 /*
58 * flush the cache
59 */
60
61 static void
flushcache(void)62 flushcache(void)
63 {
64 register int i;
65
66 for (i = matchstate.size; i--;)
67 if (matchstate.cache[i] && matchstate.cache[i]->keep)
68 {
69 matchstate.cache[i]->keep = 0;
70 regfree(&matchstate.cache[i]->re);
71 }
72 }
73
74 /*
75 * return regcomp() compiled re for pattern and reflags
76 */
77
78 regex_t*
regcache(const char * pattern,regflags_t reflags,int * status)79 regcache(const char* pattern, regflags_t reflags, int* status)
80 {
81 register Cache_t* cp;
82 register int i;
83 char* s;
84 int empty;
85 int unused;
86 int old;
87 Key_t key;
88
89 /*
90 * 0 pattern flushes the cache and reflags>0 extends cache
91 */
92
93 if (!pattern)
94 {
95 flushcache();
96 i = 0;
97 if (reflags > matchstate.size)
98 {
99 if (matchstate.cache = newof(matchstate.cache, Cache_t*, reflags, 0))
100 matchstate.size = reflags;
101 else
102 {
103 matchstate.size = 0;
104 i = 1;
105 }
106 }
107 if (status)
108 *status = i;
109 return 0;
110 }
111 if (!matchstate.cache)
112 {
113 if (!(matchstate.cache = newof(0, Cache_t*, CACHE, 0)))
114 return 0;
115 matchstate.size = CACHE;
116 }
117
118 /*
119 * flush the cache if the locale changed
120 * the ast setlocale() intercept maintains
121 * persistent setlocale() return values
122 */
123
124 if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale)
125 {
126 matchstate.locale = s;
127 flushcache();
128 }
129
130 /*
131 * check if the pattern is in the cache
132 */
133
134 for (i = 0; i < sizeof(key) && pattern[i]; i++)
135 ((char*)&key)[i] = pattern[i];
136 for (; i < sizeof(key); i++)
137 ((char*)&key)[i] = 0;
138 empty = unused = -1;
139 old = 0;
140 for (i = matchstate.size; i--;)
141 if (!matchstate.cache[i])
142 empty = i;
143 else if (!matchstate.cache[i]->keep)
144 unused = i;
145 else if (*(Key_t*)matchstate.cache[i]->pattern == key && !strcmp(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags)
146 break;
147 else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial)
148 old = i;
149 if (i < 0)
150 {
151 if (unused < 0)
152 {
153 if (empty < 0)
154 unused = old;
155 else
156 unused = empty;
157 }
158 if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0)))
159 {
160 if (status)
161 *status = REG_ESPACE;
162 return 0;
163 }
164 if (cp->keep)
165 {
166 cp->keep = 0;
167 regfree(&cp->re);
168 }
169 if ((i = strlen(pattern) + 1) >= cp->size)
170 {
171 cp->size = roundof(i, ROUND);
172 if (!(cp->pattern = newof(cp->pattern, char, cp->size, 0)))
173 {
174 if (status)
175 *status = REG_ESPACE;
176 return 0;
177 }
178 }
179 strcpy(cp->pattern, pattern);
180 while (++i < sizeof(Key_t))
181 cp->pattern[i] = 0;
182 pattern = (const char*)cp->pattern;
183 if (i = regcomp(&cp->re, pattern, reflags))
184 {
185 if (status)
186 *status = i;
187 return 0;
188 }
189 cp->keep = 1;
190 cp->reflags = reflags;
191 }
192 else
193 cp = matchstate.cache[i];
194 cp->serial = ++matchstate.serial;
195 if (status)
196 *status = 0;
197 return &cp->re;
198 }
199