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 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* 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