1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
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 * OBSOLETE Sfio_t buffer interface -- use regsubcomp(),regsubexec()
26 */
27
28#include "reglib.h"
29
30/*
31 * do a single substitution
32 */
33
34static int
35subold(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
241int
242regsub(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