1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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 * posix regex ed(1) style substitute compile
26 */
27
28 #include "reglib.h"
29
30 static const regflags_t submap[] =
31 {
32 'g', REG_SUB_ALL,
33 'l', REG_SUB_LOWER,
34 'n', REG_SUB_NUMBER,
35 'p', REG_SUB_PRINT,
36 's', REG_SUB_STOP,
37 'u', REG_SUB_UPPER,
38 'w', REG_SUB_WRITE|REG_SUB_LAST,
39 0, 0
40 };
41
42 int
regsubflags(regex_t * p,register const char * s,char ** e,int delim,register const regflags_t * map,int * pm,regflags_t * pf)43 regsubflags(regex_t* p, register const char* s, char** e, int delim, register const regflags_t* map, int* pm, regflags_t* pf)
44 {
45 register int c;
46 register const regflags_t* m;
47 regflags_t flags;
48 int minmatch;
49 regdisc_t* disc;
50
51 flags = pf ? *pf : 0;
52 minmatch = pm ? *pm : 0;
53 if (!map)
54 map = submap;
55 while (!(flags & REG_SUB_LAST))
56 {
57 if (!(c = *s++) || c == delim)
58 {
59 s--;
60 break;
61 }
62 else if (c >= '0' && c <= '9')
63 {
64 if (minmatch)
65 {
66 disc = p->env->disc;
67 regfree(p);
68 return fatal(disc, REG_EFLAGS, s - 1);
69 }
70 minmatch = c - '0';
71 while (*s >= '0' && *s <= '9')
72 minmatch = minmatch * 10 + *s++ - '0';
73 }
74 else
75 {
76 for (m = map; *m; m++)
77 if (*m++ == c)
78 {
79 if (flags & *m)
80 {
81 disc = p->env->disc;
82 regfree(p);
83 return fatal(disc, REG_EFLAGS, s - 1);
84 }
85 flags |= *m--;
86 break;
87 }
88 if (!*m)
89 {
90 s--;
91 break;
92 }
93 }
94 }
95 if (pf)
96 *pf = flags;
97 if (pm)
98 *pm = minmatch;
99 if (e)
100 *e = (char*)s;
101 return 0;
102 }
103
104 /*
105 * compile substitute rhs and optional flags
106 */
107
108 int
regsubcomp(regex_t * p,register const char * s,const regflags_t * map,int minmatch,regflags_t flags)109 regsubcomp(regex_t* p, register const char* s, const regflags_t* map, int minmatch, regflags_t flags)
110 {
111 register regsub_t* sub;
112 register int c;
113 register int d;
114 register char* t;
115 register regsubop_t* op;
116 char* e;
117 const char* r;
118 int sre;
119 int f;
120 int g;
121 int n;
122 int nops;
123 const char* o;
124 regdisc_t* disc;
125
126 disc = p->env->disc;
127 if (p->env->flags & REG_NOSUB)
128 {
129 regfree(p);
130 return fatal(disc, REG_BADPAT, NiL);
131 }
132 if (!(sub = (regsub_t*)alloc(p->env->disc, 0, sizeof(regsub_t) + strlen(s))) || !(sub->re_ops = (regsubop_t*)alloc(p->env->disc, 0, (nops = 8) * sizeof(regsubop_t))))
133 {
134 if (sub)
135 alloc(p->env->disc, sub, 0);
136 regfree(p);
137 return fatal(disc, REG_ESPACE, s);
138 }
139 sub->re_buf = sub->re_end = 0;
140 p->re_sub = sub;
141 p->env->sub = 1;
142 op = sub->re_ops;
143 o = s;
144 if (!(p->env->flags & REG_DELIMITED))
145 d = 0;
146 else
147 switch (d = *(s - 1))
148 {
149 case '\\':
150 case '\n':
151 case '\r':
152 regfree(p);
153 return fatal(disc, REG_EDELIM, s);
154 }
155 sre = p->env->flags & REG_SHELL;
156 t = sub->re_rhs;
157 if (d)
158 {
159 r = s;
160 for (;;)
161 {
162 if (!*s)
163 {
164 if (p->env->flags & REG_MUSTDELIM)
165 {
166 regfree(p);
167 return fatal(disc, REG_EDELIM, r);
168 }
169 break;
170 }
171 else if (*s == d)
172 {
173 flags |= REG_SUB_FULL;
174 s++;
175 break;
176 }
177 else if (*s++ == '\\' && !*s++)
178 {
179 regfree(p);
180 return fatal(disc, REG_EESCAPE, r);
181 }
182 }
183 if (*s)
184 {
185 if (n = regsubflags(p, s, &e, d, map, &minmatch, &flags))
186 return n;
187 s = (const char*)e;
188 }
189 p->re_npat = s - o;
190 s = r;
191 }
192 else
193 p->re_npat = 0;
194 op->op = f = g = flags & (REG_SUB_LOWER|REG_SUB_UPPER);
195 op->off = 0;
196 while ((c = *s++) != d)
197 {
198 again:
199 if (!c)
200 {
201 p->re_npat = s - o - 1;
202 break;
203 }
204 else if (c == '\\')
205 {
206 if (*s == c)
207 {
208 *t++ = *s++;
209 continue;
210 }
211 if ((c = *s++) == d)
212 goto again;
213 if (!c)
214 {
215 regfree(p);
216 return fatal(disc, REG_EESCAPE, s - 2);
217 }
218 if (c == '&')
219 {
220 *t++ = c;
221 continue;
222 }
223 }
224 else if (c == '&')
225 {
226 if (sre)
227 {
228 *t++ = c;
229 continue;
230 }
231 }
232 else
233 {
234 switch (op->op)
235 {
236 case REG_SUB_UPPER:
237 if (islower(c))
238 c = toupper(c);
239 break;
240 case REG_SUB_LOWER:
241 if (isupper(c))
242 c = tolower(c);
243 break;
244 case REG_SUB_UPPER|REG_SUB_LOWER:
245 if (isupper(c))
246 c = tolower(c);
247 else if (islower(c))
248 c = toupper(c);
249 break;
250 }
251 *t++ = c;
252 continue;
253 }
254 switch (c)
255 {
256 case 0:
257 s--;
258 continue;
259 case '&':
260 c = 0;
261 break;
262 case '0': case '1': case '2': case '3': case '4':
263 case '5': case '6': case '7': case '8': case '9':
264 c -= '0';
265 if (isdigit(*s) && (p->env->flags & REG_MULTIREF))
266 c = c * 10 + *s++ - '0';
267 break;
268 case 'l':
269 if (c = *s)
270 {
271 s++;
272 if (isupper(c))
273 c = tolower(c);
274 *t++ = c;
275 }
276 continue;
277 case 'u':
278 if (c = *s)
279 {
280 s++;
281 if (islower(c))
282 c = toupper(c);
283 *t++ = c;
284 }
285 continue;
286 case 'E':
287 f = g;
288 set:
289 if ((op->len = (t - sub->re_rhs) - op->off) && (n = ++op - sub->re_ops) >= nops)
290 {
291 if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
292 {
293 regfree(p);
294 return fatal(disc, REG_ESPACE, NiL);
295 }
296 op = sub->re_ops + n;
297 }
298 op->op = f;
299 op->off = t - sub->re_rhs;
300 continue;
301 case 'L':
302 g = f;
303 f = REG_SUB_LOWER;
304 goto set;
305 case 'U':
306 g = f;
307 f = REG_SUB_UPPER;
308 goto set;
309 default:
310 if (!sre)
311 {
312 *t++ = chresc(s - 2, &e);
313 s = (const char*)e;
314 continue;
315 }
316 s--;
317 c = -1;
318 break;
319 }
320 if (c > p->re_nsub)
321 {
322 regfree(p);
323 return fatal(disc, REG_ESUBREG, s - 1);
324 }
325 if ((n = op - sub->re_ops) >= (nops - 2))
326 {
327 if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
328 {
329 regfree(p);
330 return fatal(disc, REG_ESPACE, NiL);
331 }
332 op = sub->re_ops + n;
333 }
334 if (op->len = (t - sub->re_rhs) - op->off)
335 op++;
336 op->op = f;
337 op->off = c;
338 op->len = 0;
339 op++;
340 op->op = f;
341 op->off = t - sub->re_rhs;
342 }
343 if ((op->len = (t - sub->re_rhs) - op->off) && (n = ++op - sub->re_ops) >= nops)
344 {
345 if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
346 {
347 regfree(p);
348 return fatal(disc, REG_ESPACE, NiL);
349 }
350 op = sub->re_ops + n;
351 }
352 op->len = -1;
353 sub->re_flags = flags;
354 sub->re_min = minmatch;
355 return 0;
356 }
357
358 void
regsubfree(regex_t * p)359 regsubfree(regex_t* p)
360 {
361 Env_t* env;
362 regsub_t* sub;
363
364 if (p && (env = p->env) && env->sub && (sub = p->re_sub))
365 {
366 env->sub = 0;
367 p->re_sub = 0;
368 if (!(env->disc->re_flags & REG_NOFREE))
369 {
370 if (sub->re_buf)
371 alloc(env->disc, sub->re_buf, 0);
372 if (sub->re_ops)
373 alloc(env->disc, sub->re_ops, 0);
374 alloc(env->disc, sub, 0);
375 }
376 }
377 }
378