14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * Phong Vo <kpv@research.att.com> * 204887Schin * * 214887Schin ***********************************************************************/ 224887Schin #pragma prototyped 234887Schin 244887Schin /* 254887Schin * regcomp() regex_t cache 26*12068SRoger.Faulkner@Oracle.COM * at&t research 274887Schin */ 284887Schin 294887Schin #include <ast.h> 304887Schin #include <regex.h> 314887Schin 328462SApril.Chin@Sun.COM #define CACHE 8 /* default # cached re's */ 33*12068SRoger.Faulkner@Oracle.COM #define ROUND 64 /* pattern buffer size round */ 344887Schin 35*12068SRoger.Faulkner@Oracle.COM typedef unsigned long Key_t; 368462SApril.Chin@Sun.COM 374887Schin typedef struct Cache_s 384887Schin { 39*12068SRoger.Faulkner@Oracle.COM char* pattern; 404887Schin regex_t re; 414887Schin unsigned long serial; 424887Schin regflags_t reflags; 43*12068SRoger.Faulkner@Oracle.COM int keep; 44*12068SRoger.Faulkner@Oracle.COM int size; 454887Schin } Cache_t; 464887Schin 478462SApril.Chin@Sun.COM typedef struct State_s 484887Schin { 498462SApril.Chin@Sun.COM unsigned int size; 504887Schin unsigned long serial; 514887Schin char* locale; 528462SApril.Chin@Sun.COM Cache_t** cache; 538462SApril.Chin@Sun.COM } State_t; 548462SApril.Chin@Sun.COM 558462SApril.Chin@Sun.COM static State_t matchstate; 564887Schin 574887Schin /* 584887Schin * flush the cache 594887Schin */ 604887Schin 614887Schin static void 624887Schin flushcache(void) 634887Schin { 644887Schin register int i; 654887Schin 668462SApril.Chin@Sun.COM for (i = matchstate.size; i--;) 67*12068SRoger.Faulkner@Oracle.COM if (matchstate.cache[i] && matchstate.cache[i]->keep) 684887Schin { 69*12068SRoger.Faulkner@Oracle.COM matchstate.cache[i]->keep = 0; 704887Schin regfree(&matchstate.cache[i]->re); 714887Schin } 724887Schin } 734887Schin 744887Schin /* 754887Schin * return regcomp() compiled re for pattern and reflags 764887Schin */ 774887Schin 784887Schin regex_t* 794887Schin regcache(const char* pattern, regflags_t reflags, int* status) 804887Schin { 814887Schin register Cache_t* cp; 824887Schin register int i; 834887Schin char* s; 844887Schin int empty; 854887Schin int unused; 864887Schin int old; 87*12068SRoger.Faulkner@Oracle.COM Key_t key; 884887Schin 894887Schin /* 908462SApril.Chin@Sun.COM * 0 pattern flushes the cache and reflags>0 extends cache 914887Schin */ 924887Schin 934887Schin if (!pattern) 944887Schin { 954887Schin flushcache(); 968462SApril.Chin@Sun.COM i = 0; 978462SApril.Chin@Sun.COM if (reflags > matchstate.size) 988462SApril.Chin@Sun.COM { 998462SApril.Chin@Sun.COM if (matchstate.cache = newof(matchstate.cache, Cache_t*, reflags, 0)) 1008462SApril.Chin@Sun.COM matchstate.size = reflags; 1018462SApril.Chin@Sun.COM else 1028462SApril.Chin@Sun.COM { 1038462SApril.Chin@Sun.COM matchstate.size = 0; 1048462SApril.Chin@Sun.COM i = 1; 1058462SApril.Chin@Sun.COM } 1068462SApril.Chin@Sun.COM } 1074887Schin if (status) 1088462SApril.Chin@Sun.COM *status = i; 1094887Schin return 0; 1104887Schin } 1118462SApril.Chin@Sun.COM if (!matchstate.cache) 1128462SApril.Chin@Sun.COM { 1138462SApril.Chin@Sun.COM if (!(matchstate.cache = newof(0, Cache_t*, CACHE, 0))) 1148462SApril.Chin@Sun.COM return 0; 1158462SApril.Chin@Sun.COM matchstate.size = CACHE; 1168462SApril.Chin@Sun.COM } 1174887Schin 1184887Schin /* 1194887Schin * flush the cache if the locale changed 1204887Schin * the ast setlocale() intercept maintains 1214887Schin * persistent setlocale() return values 1224887Schin */ 1234887Schin 1244887Schin if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale) 1254887Schin { 1264887Schin matchstate.locale = s; 1274887Schin flushcache(); 1284887Schin } 1294887Schin 1304887Schin /* 1314887Schin * check if the pattern is in the cache 1324887Schin */ 1334887Schin 134*12068SRoger.Faulkner@Oracle.COM for (i = 0; i < sizeof(key) && pattern[i]; i++) 135*12068SRoger.Faulkner@Oracle.COM ((char*)&key)[i] = pattern[i]; 136*12068SRoger.Faulkner@Oracle.COM for (; i < sizeof(key); i++) 137*12068SRoger.Faulkner@Oracle.COM ((char*)&key)[i] = 0; 1384887Schin empty = unused = -1; 1394887Schin old = 0; 1408462SApril.Chin@Sun.COM for (i = matchstate.size; i--;) 1414887Schin if (!matchstate.cache[i]) 1424887Schin empty = i; 143*12068SRoger.Faulkner@Oracle.COM else if (!matchstate.cache[i]->keep) 1444887Schin unused = i; 145*12068SRoger.Faulkner@Oracle.COM else if (*(Key_t*)matchstate.cache[i]->pattern == key && !strcmp(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags) 1464887Schin break; 1474887Schin else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial) 1484887Schin old = i; 1498462SApril.Chin@Sun.COM if (i < 0) 1504887Schin { 1514887Schin if (unused < 0) 1524887Schin { 1534887Schin if (empty < 0) 1544887Schin unused = old; 1554887Schin else 1564887Schin unused = empty; 1574887Schin } 1584887Schin if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0))) 1594887Schin { 1604887Schin if (status) 1614887Schin *status = REG_ESPACE; 1624887Schin return 0; 1634887Schin } 164*12068SRoger.Faulkner@Oracle.COM if (cp->keep) 1654887Schin { 166*12068SRoger.Faulkner@Oracle.COM cp->keep = 0; 1674887Schin regfree(&cp->re); 1684887Schin } 169*12068SRoger.Faulkner@Oracle.COM if ((i = strlen(pattern) + 1) >= cp->size) 1704887Schin { 171*12068SRoger.Faulkner@Oracle.COM cp->size = roundof(i, ROUND); 172*12068SRoger.Faulkner@Oracle.COM if (!(cp->pattern = newof(cp->pattern, char, cp->size, 0))) 173*12068SRoger.Faulkner@Oracle.COM { 174*12068SRoger.Faulkner@Oracle.COM if (status) 175*12068SRoger.Faulkner@Oracle.COM *status = REG_ESPACE; 176*12068SRoger.Faulkner@Oracle.COM return 0; 177*12068SRoger.Faulkner@Oracle.COM } 1784887Schin } 179*12068SRoger.Faulkner@Oracle.COM strcpy(cp->pattern, pattern); 180*12068SRoger.Faulkner@Oracle.COM while (++i < sizeof(Key_t)) 181*12068SRoger.Faulkner@Oracle.COM cp->pattern[i] = 0; 182*12068SRoger.Faulkner@Oracle.COM pattern = (const char*)cp->pattern; 183*12068SRoger.Faulkner@Oracle.COM if (i = regcomp(&cp->re, pattern, reflags)) 1844887Schin { 1854887Schin if (status) 1864887Schin *status = i; 1874887Schin return 0; 1884887Schin } 189*12068SRoger.Faulkner@Oracle.COM cp->keep = 1; 190*12068SRoger.Faulkner@Oracle.COM cp->reflags = reflags; 1914887Schin } 1924887Schin else 1934887Schin cp = matchstate.cache[i]; 1944887Schin cp->serial = ++matchstate.serial; 1954887Schin if (status) 1964887Schin *status = 0; 1974887Schin return &cp->re; 1984887Schin } 199