1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin 
24*4887Schin /*
25*4887Schin  * posix regex ed(1) style substitute execute
26*4887Schin  */
27*4887Schin 
28*4887Schin #include "reglib.h"
29*4887Schin 
30*4887Schin #define NEED(p,b,n,r)	\
31*4887Schin 	do \
32*4887Schin 	{ \
33*4887Schin 		if (((b)->re_end - (b)->re_cur) < (n)) \
34*4887Schin 		{ \
35*4887Schin 			size_t	o = (b)->re_cur - (b)->re_buf; \
36*4887Schin 			size_t	a = ((b)->re_end - (b)->re_buf); \
37*4887Schin 			if (a < n) \
38*4887Schin 				a = roundof(n, 128); \
39*4887Schin 			a *= 2; \
40*4887Schin 			if (!((b)->re_buf = alloc(p->env->disc, (b)->re_buf, a))) \
41*4887Schin 			{ \
42*4887Schin 				(b)->re_buf = (b)->re_cur = (b)->re_end = 0; \
43*4887Schin 				c = REG_ESPACE; \
44*4887Schin 				r; \
45*4887Schin 			} \
46*4887Schin 			(b)->re_cur = (b)->re_buf + o; \
47*4887Schin 			(b)->re_end = (b)->re_buf + a; \
48*4887Schin 		} \
49*4887Schin 	} while (0)
50*4887Schin 
51*4887Schin #define PUTC(p,b,x,r)	\
52*4887Schin 	do \
53*4887Schin 	{ \
54*4887Schin 		NEED(p, b, 1, r); \
55*4887Schin 		*(b)->re_cur++ = (x); \
56*4887Schin 	} while (0)
57*4887Schin 
58*4887Schin #define PUTS(p,b,x,z,r)	\
59*4887Schin 	do if (z) \
60*4887Schin 	{ \
61*4887Schin 		NEED(p, b, z, r); \
62*4887Schin 		memcpy((b)->re_cur, x, z); \
63*4887Schin 		(b)->re_cur += (z); \
64*4887Schin 	} while (0)
65*4887Schin 
66*4887Schin /*
67*4887Schin  * do a single substitution
68*4887Schin  */
69*4887Schin 
70*4887Schin static int
71*4887Schin sub(const regex_t* p, register regsub_t* b, const char* ss, register regsubop_t* op, size_t nmatch, register regmatch_t* match)
72*4887Schin {
73*4887Schin 	register char*	s;
74*4887Schin 	register char*	e;
75*4887Schin 	register int	c;
76*4887Schin 
77*4887Schin 	for (;; op++)
78*4887Schin 	{
79*4887Schin 		switch (op->len)
80*4887Schin 		{
81*4887Schin 		case -1:
82*4887Schin 			break;
83*4887Schin 		case 0:
84*4887Schin 			if (op->off >= nmatch)
85*4887Schin 				return REG_ESUBREG;
86*4887Schin 			if ((c = match[op->off].rm_so) < 0)
87*4887Schin 				continue;
88*4887Schin 			s = (char*)ss + c;
89*4887Schin 			if ((c = match[op->off].rm_eo) < 0)
90*4887Schin 				continue;
91*4887Schin 			e = (char*)ss + c;
92*4887Schin 			NEED(p, b, e - s, return c);
93*4887Schin 			switch (op->op)
94*4887Schin 			{
95*4887Schin 			case REG_SUB_UPPER:
96*4887Schin 				while (s < e)
97*4887Schin 				{
98*4887Schin 					c = *s++;
99*4887Schin 					if (islower(c))
100*4887Schin 						c = toupper(c);
101*4887Schin 					*b->re_cur++ = c;
102*4887Schin 				}
103*4887Schin 				break;
104*4887Schin 			case REG_SUB_LOWER:
105*4887Schin 				while (s < e)
106*4887Schin 				{
107*4887Schin 					c = *s++;
108*4887Schin 					if (isupper(c))
109*4887Schin 						c = tolower(c);
110*4887Schin 					*b->re_cur++ = c;
111*4887Schin 				}
112*4887Schin 				break;
113*4887Schin 			case REG_SUB_UPPER|REG_SUB_LOWER:
114*4887Schin 				while (s < e)
115*4887Schin 				{
116*4887Schin 					c = *s++;
117*4887Schin 					if (isupper(c))
118*4887Schin 						c = tolower(c);
119*4887Schin 					else if (islower(c))
120*4887Schin 						c = toupper(c);
121*4887Schin 					*b->re_cur++ = c;
122*4887Schin 				}
123*4887Schin 				break;
124*4887Schin 			default:
125*4887Schin 				while (s < e)
126*4887Schin 					*b->re_cur++ = *s++;
127*4887Schin 				break;
128*4887Schin 			}
129*4887Schin 			continue;
130*4887Schin 		default:
131*4887Schin 			NEED(p, b, op->len, return c);
132*4887Schin 			s = b->re_rhs + op->off;
133*4887Schin 			e = s + op->len;
134*4887Schin 			while (s < e)
135*4887Schin 				*b->re_cur++ = *s++;
136*4887Schin 			continue;
137*4887Schin 		}
138*4887Schin 		break;
139*4887Schin 	}
140*4887Schin 	return 0;
141*4887Schin }
142*4887Schin 
143*4887Schin /*
144*4887Schin  * ed(1) style substitute using matches from last regexec()
145*4887Schin  */
146*4887Schin 
147*4887Schin int
148*4887Schin regsubexec(const regex_t* p, const char* s, size_t nmatch, regmatch_t* match)
149*4887Schin {
150*4887Schin 	register int		c;
151*4887Schin 	register regsub_t*	b;
152*4887Schin 	const char*		e;
153*4887Schin 	int			m;
154*4887Schin 
155*4887Schin 	if (!p->env->sub || (p->env->flags & REG_NOSUB) || !nmatch)
156*4887Schin 		return fatal(p->env->disc, REG_BADPAT, NiL);
157*4887Schin 	b = p->re_sub;
158*4887Schin 	m = b->re_min;
159*4887Schin 	b->re_cur = b->re_buf;
160*4887Schin 	e = (const char*)p->env->end;
161*4887Schin 	for (;;)
162*4887Schin 	{
163*4887Schin 		if (--m > 0)
164*4887Schin 			PUTS(p, b, s, match->rm_eo, return fatal(p->env->disc, c, NiL));
165*4887Schin 		else
166*4887Schin 		{
167*4887Schin 			PUTS(p, b, s, match->rm_so, return fatal(p->env->disc, c, NiL));
168*4887Schin 			if (c = sub(p, b, s, b->re_ops, nmatch, match))
169*4887Schin 				return fatal(p->env->disc, c, NiL);
170*4887Schin 		}
171*4887Schin 		s += match->rm_eo;
172*4887Schin 		if (m <= 0 && !(b->re_flags & REG_SUB_ALL))
173*4887Schin 			break;
174*4887Schin 		if (c = regnexec(p, s, e - s, nmatch, match, p->env->flags|(match->rm_so == match->rm_eo ? REG_ADVANCE : 0)))
175*4887Schin 		{
176*4887Schin 			if (c != REG_NOMATCH)
177*4887Schin 				return fatal(p->env->disc, c, NiL);
178*4887Schin 			break;
179*4887Schin 		}
180*4887Schin 	}
181*4887Schin 	while (s < e)
182*4887Schin 	{
183*4887Schin 		c = *s++;
184*4887Schin 		PUTC(p, b, c, return fatal(p->env->disc, c, NiL));
185*4887Schin 	}
186*4887Schin 	NEED(p, b, 1, return fatal(p->env->disc, c, NiL));
187*4887Schin 	*b->re_cur = 0;
188*4887Schin 	b->re_len = b->re_cur - b->re_buf;
189*4887Schin 	return 0;
190*4887Schin }
191