1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 /* # cached re's */ 33 #define MAXPAT 256 /* max pattern length + 1 */ 34 35 #define KEEP 01 36 #define DROP 02 37 38 typedef struct Cache_s 39 { 40 regex_t re; 41 unsigned long serial; 42 regflags_t reflags; 43 int flags; 44 char pattern[MAXPAT]; 45 } Cache_t; 46 47 static struct State_s 48 { 49 Cache_t* cache[CACHE]; 50 unsigned long serial; 51 char* locale; 52 } matchstate; 53 54 /* 55 * flush the cache 56 */ 57 58 static void 59 flushcache(void) 60 { 61 register int i; 62 63 for (i = 0; i < elementsof(matchstate.cache); i++) 64 if (matchstate.cache[i] && matchstate.cache[i]->flags) 65 { 66 matchstate.cache[i]->flags = 0; 67 regfree(&matchstate.cache[i]->re); 68 } 69 } 70 71 /* 72 * return regcomp() compiled re for pattern and reflags 73 */ 74 75 regex_t* 76 regcache(const char* pattern, regflags_t reflags, int* status) 77 { 78 register Cache_t* cp; 79 register int i; 80 char* s; 81 int empty; 82 int unused; 83 int old; 84 85 /* 86 * 0 pattern flushes the cache 87 */ 88 89 if (!pattern) 90 { 91 flushcache(); 92 if (status) 93 *status = 0; 94 return 0; 95 } 96 97 /* 98 * flush the cache if the locale changed 99 * the ast setlocale() intercept maintains 100 * persistent setlocale() return values 101 */ 102 103 if ((s = setlocale(LC_CTYPE, NiL)) != matchstate.locale) 104 { 105 matchstate.locale = s; 106 flushcache(); 107 } 108 109 /* 110 * check if the pattern is in the cache 111 */ 112 113 empty = unused = -1; 114 old = 0; 115 for (i = 0; i < elementsof(matchstate.cache); i++) 116 if (!matchstate.cache[i]) 117 empty = i; 118 else if (!(matchstate.cache[i]->flags & KEEP)) 119 { 120 if (matchstate.cache[i]->flags) 121 { 122 matchstate.cache[i]->flags = 0; 123 regfree(&matchstate.cache[i]->re); 124 } 125 unused = i; 126 } 127 else if (streq(matchstate.cache[i]->pattern, pattern) && matchstate.cache[i]->reflags == reflags) 128 break; 129 else if (!matchstate.cache[old] || matchstate.cache[old]->serial > matchstate.cache[i]->serial) 130 old = i; 131 if (i >= elementsof(matchstate.cache)) 132 { 133 if (unused < 0) 134 { 135 if (empty < 0) 136 unused = old; 137 else 138 unused = empty; 139 } 140 if (!(cp = matchstate.cache[unused]) && !(cp = matchstate.cache[unused] = newof(0, Cache_t, 1, 0))) 141 { 142 if (status) 143 *status = REG_ESPACE; 144 return 0; 145 } 146 if (cp->flags) 147 { 148 cp->flags = 0; 149 regfree(&cp->re); 150 } 151 cp->reflags = reflags; 152 if (strlen(pattern) < sizeof(cp->pattern)) 153 { 154 strcpy(cp->pattern, pattern); 155 pattern = (const char*)cp->pattern; 156 cp->flags = KEEP; 157 } 158 else 159 cp->flags = DROP; 160 if (i = regcomp(&cp->re, pattern, cp->reflags)) 161 { 162 if (status) 163 *status = i; 164 cp->flags = 0; 165 return 0; 166 } 167 } 168 else 169 cp = matchstate.cache[i]; 170 cp->serial = ++matchstate.serial; 171 if (status) 172 *status = 0; 173 return &cp->re; 174 } 175