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