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  * posix regex ed(1) style substitute execute
26  */
27 
28 #include "reglib.h"
29 
30 #define NEED(p,b,n,r)	\
31 	do \
32 	{ \
33 		if (((b)->re_end - (b)->re_cur) < (n)) \
34 		{ \
35 			size_t	o = (b)->re_cur - (b)->re_buf; \
36 			size_t	a = ((b)->re_end - (b)->re_buf); \
37 			if (a < n) \
38 				a = roundof(n, 128); \
39 			a *= 2; \
40 			if (!((b)->re_buf = alloc(p->env->disc, (b)->re_buf, a))) \
41 			{ \
42 				(b)->re_buf = (b)->re_cur = (b)->re_end = 0; \
43 				c = REG_ESPACE; \
44 				r; \
45 			} \
46 			(b)->re_cur = (b)->re_buf + o; \
47 			(b)->re_end = (b)->re_buf + a; \
48 		} \
49 	} while (0)
50 
51 #define PUTC(p,b,x,r)	\
52 	do \
53 	{ \
54 		NEED(p, b, 1, r); \
55 		*(b)->re_cur++ = (x); \
56 	} while (0)
57 
58 #define PUTS(p,b,x,z,r)	\
59 	do if (z) \
60 	{ \
61 		NEED(p, b, z, r); \
62 		memcpy((b)->re_cur, x, z); \
63 		(b)->re_cur += (z); \
64 	} while (0)
65 
66 /*
67  * do a single substitution
68  */
69 
70 static int
71 sub(const regex_t* p, register regsub_t* b, const char* ss, register regsubop_t* op, size_t nmatch, register regmatch_t* match)
72 {
73 	register char*	s;
74 	register char*	e;
75 	register int	c;
76 
77 	for (;; op++)
78 	{
79 		switch (op->len)
80 		{
81 		case -1:
82 			break;
83 		case 0:
84 			if (op->off >= nmatch)
85 				return REG_ESUBREG;
86 			if ((c = match[op->off].rm_so) < 0)
87 				continue;
88 			s = (char*)ss + c;
89 			if ((c = match[op->off].rm_eo) < 0)
90 				continue;
91 			e = (char*)ss + c;
92 			NEED(p, b, e - s, return c);
93 			switch (op->op)
94 			{
95 			case REG_SUB_UPPER:
96 				while (s < e)
97 				{
98 					c = *s++;
99 					if (islower(c))
100 						c = toupper(c);
101 					*b->re_cur++ = c;
102 				}
103 				break;
104 			case REG_SUB_LOWER:
105 				while (s < e)
106 				{
107 					c = *s++;
108 					if (isupper(c))
109 						c = tolower(c);
110 					*b->re_cur++ = c;
111 				}
112 				break;
113 			case REG_SUB_UPPER|REG_SUB_LOWER:
114 				while (s < e)
115 				{
116 					c = *s++;
117 					if (isupper(c))
118 						c = tolower(c);
119 					else if (islower(c))
120 						c = toupper(c);
121 					*b->re_cur++ = c;
122 				}
123 				break;
124 			default:
125 				while (s < e)
126 					*b->re_cur++ = *s++;
127 				break;
128 			}
129 			continue;
130 		default:
131 			NEED(p, b, op->len, return c);
132 			s = b->re_rhs + op->off;
133 			e = s + op->len;
134 			while (s < e)
135 				*b->re_cur++ = *s++;
136 			continue;
137 		}
138 		break;
139 	}
140 	return 0;
141 }
142 
143 /*
144  * ed(1) style substitute using matches from last regexec()
145  */
146 
147 int
148 regsubexec(const regex_t* p, const char* s, size_t nmatch, regmatch_t* match)
149 {
150 	register int		c;
151 	register regsub_t*	b;
152 	const char*		e;
153 	int			m;
154 
155 	if (!p->env->sub || (p->env->flags & REG_NOSUB) || !nmatch)
156 		return fatal(p->env->disc, REG_BADPAT, NiL);
157 	b = p->re_sub;
158 	m = b->re_min;
159 	b->re_cur = b->re_buf;
160 	e = (const char*)p->env->end;
161 	for (;;)
162 	{
163 		if (--m > 0)
164 			PUTS(p, b, s, match->rm_eo, return fatal(p->env->disc, c, NiL));
165 		else
166 		{
167 			PUTS(p, b, s, match->rm_so, return fatal(p->env->disc, c, NiL));
168 			if (c = sub(p, b, s, b->re_ops, nmatch, match))
169 				return fatal(p->env->disc, c, NiL);
170 		}
171 		s += match->rm_eo;
172 		if (m <= 0 && !(b->re_flags & REG_SUB_ALL))
173 			break;
174 		if (c = regnexec(p, s, e - s, nmatch, match, p->env->flags|(match->rm_so == match->rm_eo ? REG_ADVANCE : 0)))
175 		{
176 			if (c != REG_NOMATCH)
177 				return fatal(p->env->disc, c, NiL);
178 			break;
179 		}
180 	}
181 	while (s < e)
182 	{
183 		c = *s++;
184 		PUTC(p, b, c, return fatal(p->env->disc, c, NiL));
185 	}
186 	NEED(p, b, 1, return fatal(p->env->disc, c, NiL));
187 	*b->re_cur = 0;
188 	b->re_len = b->re_cur - b->re_buf;
189 	return 0;
190 }
191