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