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