xref: /illumos-gate/usr/src/contrib/ast/src/lib/libast/regex/regsub.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
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  * OBSOLETE Sfio_t buffer interface -- use regsubcomp(),regsubexec()
26  */
27 
28 #include "reglib.h"
29 
30 /*
31  * do a single substitution
32  */
33 
34 static int
subold(register Sfio_t * dp,const char * op,register const char * sp,size_t nmatch,register regmatch_t * match,register regflags_t flags,int sre)35 subold(register Sfio_t* dp, const char* op, register const char* sp, size_t nmatch, register regmatch_t* match, register regflags_t flags, int sre)
36 {
37 	register int	c;
38 	char*		s;
39 	char*		e;
40 	const char*	b;
41 	regflags_t	f;
42 
43 	f = flags &= (REG_SUB_LOWER|REG_SUB_UPPER);
44 	for (;;)
45 	{
46 		switch (c = *sp++)
47 		{
48 		case 0:
49 			return 0;
50 		case '~':
51 			if (!sre || *sp != '(')
52 			{
53 				sfputc(dp, c);
54 				continue;
55 			}
56 			b = sp - 1;
57 			sp++;
58 			break;
59 		case '\\':
60 			if (sre)
61 			{
62 				sfputc(dp, chresc(sp - 1, &s));
63 				sp = (const char*)s;
64 				continue;
65 			}
66 			if (*sp == '&')
67 			{
68 				c = *sp++;
69 				sfputc(dp, c);
70 				continue;
71 			}
72 			break;
73 		case '&':
74 			if (sre)
75 			{
76 				sfputc(dp, c);
77 				continue;
78 			}
79 			sp--;
80 			break;
81 		default:
82 			switch (flags)
83 			{
84 			case REG_SUB_UPPER:
85 				if (islower(c))
86 					c = toupper(c);
87 				break;
88 			case REG_SUB_LOWER:
89 				if (isupper(c))
90 					c = tolower(c);
91 				break;
92 			case REG_SUB_UPPER|REG_SUB_LOWER:
93 				if (isupper(c))
94 					c = tolower(c);
95 				else if (islower(c))
96 					c = toupper(c);
97 				break;
98 			}
99 			sfputc(dp, c);
100 			continue;
101 		}
102 		switch (c = *sp++)
103 		{
104 		case 0:
105 			sp--;
106 			continue;
107 		case '&':
108 			c = 0;
109 			break;
110 		case '0': case '1': case '2': case '3': case '4':
111 		case '5': case '6': case '7': case '8': case '9':
112 			c -= '0';
113 			if (sre)
114 				while (isdigit(*sp))
115 					c = c * 10 + *sp++ - '0';
116 			break;
117 		case 'l':
118 			if (sre && *sp != ')')
119 			{
120 				c = -1;
121 				break;
122 			}
123 			if (c = *sp)
124 			{
125 				sp++;
126 				if (isupper(c))
127 					c = tolower(c);
128 				sfputc(dp, c);
129 			}
130 			continue;
131 		case 'u':
132 			if (sre)
133 			{
134 				if (*sp != ')')
135 				{
136 					c = -1;
137 					break;
138 				}
139 				sp++;
140 			}
141 			if (c = *sp)
142 			{
143 				sp++;
144 				if (islower(c))
145 					c = toupper(c);
146 				sfputc(dp, c);
147 			}
148 			continue;
149 		case 'E':
150 			if (sre)
151 			{
152 				if (*sp != ')')
153 				{
154 					c = -1;
155 					break;
156 				}
157 				sp++;
158 			}
159 			flags = f;
160 			continue;
161 		case 'L':
162 			if (sre)
163 			{
164 				if (*sp != ')')
165 				{
166 					c = -1;
167 					break;
168 				}
169 				sp++;
170 			}
171 			f = flags;
172 			flags = REG_SUB_LOWER;
173 			continue;
174 		case 'U':
175 			if (sre)
176 			{
177 				if (*sp != ')')
178 				{
179 					c = -1;
180 					break;
181 				}
182 				sp++;
183 			}
184 			f = flags;
185 			flags = REG_SUB_UPPER;
186 			continue;
187 		default:
188 			if (!sre)
189 			{
190 				sfputc(dp, chresc(sp - 2, &s));
191 				sp = (const char*)s;
192 				continue;
193 			}
194 			sp--;
195 			c = -1;
196 			break;
197 		}
198 		if (sre)
199 		{
200 			if (c < 0 || *sp != ')')
201 			{
202 				for (; b < sp; b++)
203 					sfputc(dp, *b);
204 				continue;
205 			}
206 			sp++;
207 		}
208 		if (c >= nmatch)
209 			return REG_ESUBREG;
210 		s = (char*)op + match[c].rm_so;
211 		e = (char*)op + match[c].rm_eo;
212 		while (s < e)
213 		{
214 			c = *s++;
215 			switch (flags)
216 			{
217 			case REG_SUB_UPPER:
218 				if (islower(c))
219 					c = toupper(c);
220 				break;
221 			case REG_SUB_LOWER:
222 				if (isupper(c))
223 					c = tolower(c);
224 				break;
225 			case REG_SUB_UPPER|REG_SUB_LOWER:
226 				if (isupper(c))
227 					c = tolower(c);
228 				else if (islower(c))
229 					c = toupper(c);
230 				break;
231 			}
232 			sfputc(dp, c);
233 		}
234 	}
235 }
236 
237 /*
238  * ed(1) style substitute using matches from last regexec()
239  */
240 
241 int
regsub(const regex_t * p,Sfio_t * dp,const char * op,const char * sp,size_t nmatch,regmatch_t * match,regflags_t flags)242 regsub(const regex_t* p, Sfio_t* dp, const char* op, const char* sp, size_t nmatch, regmatch_t* match, regflags_t flags)
243 {
244 	int	m;
245 	int	r;
246 	int	sre;
247 
248 	if ((p->env->flags & REG_NOSUB) || !nmatch)
249 		return fatal(p->env->disc, REG_BADPAT, NiL);
250 	m = (flags >> 16) & 0x3fff;
251 	sre = !!(p->env->flags & REG_SHELL);
252 	r = 0;
253 	do
254 	{
255 		if (--m > 0)
256 			sfwrite(dp, op, match->rm_eo);
257 		else
258 		{
259 			sfwrite(dp, op, match->rm_so);
260 			if (r = subold(dp, op, sp, nmatch, match, flags, sre))
261 				return fatal(p->env->disc, r, NiL);
262 		}
263 		op += match->rm_eo;
264 	} while ((m > 0 || (flags & REG_SUB_ALL)) && !(r = regexec(p, op, nmatch, match, p->env->flags|(match->rm_so == match->rm_eo ? REG_ADVANCE : 0))));
265 	if (r && r != REG_NOMATCH)
266 		return fatal(p->env->disc, r, NiL);
267 	sfputr(dp, op, -1);
268 	return 0;
269 }
270