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