xref: /onnv-gate/usr/src/lib/libast/common/regex/regsubcomp.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * posix regex ed(1) style substitute compile
264887Schin  */
274887Schin 
284887Schin #include "reglib.h"
294887Schin 
304887Schin static const regflags_t	submap[] =
314887Schin {
324887Schin 	'g',	REG_SUB_ALL,
334887Schin 	'l',	REG_SUB_LOWER,
344887Schin 	'n',	REG_SUB_NUMBER,
354887Schin 	'p',	REG_SUB_PRINT,
364887Schin 	's',	REG_SUB_STOP,
374887Schin 	'u',	REG_SUB_UPPER,
384887Schin 	'w',	REG_SUB_WRITE|REG_SUB_LAST,
394887Schin 	0,	0
404887Schin };
414887Schin 
424887Schin int
regsubflags(regex_t * p,register const char * s,char ** e,int delim,register const regflags_t * map,int * pm,regflags_t * pf)434887Schin regsubflags(regex_t* p, register const char* s, char** e, int delim, register const regflags_t* map, int* pm, regflags_t* pf)
444887Schin {
454887Schin 	register int			c;
464887Schin 	register const regflags_t*	m;
474887Schin 	regflags_t			flags;
484887Schin 	int				minmatch;
494887Schin 	regdisc_t*			disc;
504887Schin 
514887Schin 	flags = pf ? *pf : 0;
524887Schin 	minmatch = pm ? *pm : 0;
534887Schin 	if (!map)
544887Schin 		map = submap;
554887Schin 	while (!(flags & REG_SUB_LAST))
564887Schin 	{
574887Schin 		if  (!(c = *s++) || c == delim)
584887Schin 		{
594887Schin 			s--;
604887Schin 			break;
614887Schin 		}
624887Schin 		else if (c >= '0' && c <= '9')
634887Schin 		{
644887Schin 			if (minmatch)
654887Schin 			{
664887Schin 				disc = p->env->disc;
674887Schin 				regfree(p);
684887Schin 				return fatal(disc, REG_EFLAGS, s - 1);
694887Schin 			}
704887Schin 			minmatch = c - '0';
714887Schin 			while (*s >= '0' && *s <= '9')
724887Schin 				minmatch = minmatch * 10 + *s++ - '0';
734887Schin 		}
744887Schin 		else
754887Schin 		{
764887Schin 			for (m = map; *m; m++)
774887Schin 				if (*m++ == c)
784887Schin 				{
794887Schin 					if (flags & *m)
804887Schin 					{
814887Schin 						disc = p->env->disc;
824887Schin 						regfree(p);
834887Schin 						return fatal(disc, REG_EFLAGS, s - 1);
844887Schin 					}
854887Schin 					flags |= *m--;
864887Schin 					break;
874887Schin 				}
884887Schin 			if (!*m)
894887Schin 			{
904887Schin 				s--;
914887Schin 				break;
924887Schin 			}
934887Schin 		}
944887Schin 	}
954887Schin 	if (pf)
964887Schin 		*pf = flags;
974887Schin 	if (pm)
984887Schin 		*pm = minmatch;
994887Schin 	if (e)
1004887Schin 		*e = (char*)s;
1014887Schin 	return 0;
1024887Schin }
1034887Schin 
1044887Schin /*
1054887Schin  * compile substitute rhs and optional flags
1064887Schin  */
1074887Schin 
1084887Schin int
regsubcomp(regex_t * p,register const char * s,const regflags_t * map,int minmatch,regflags_t flags)1094887Schin regsubcomp(regex_t* p, register const char* s, const regflags_t* map, int minmatch, regflags_t flags)
1104887Schin {
1114887Schin 	register regsub_t*	sub;
1124887Schin 	register int		c;
1134887Schin 	register int		d;
1144887Schin 	register char*		t;
1154887Schin 	register regsubop_t*	op;
1164887Schin 	char*			e;
1174887Schin 	const char*		r;
1184887Schin 	int			sre;
1194887Schin 	int			f;
1204887Schin 	int			g;
1214887Schin 	int			n;
1224887Schin 	int			nops;
1234887Schin 	const char*		o;
1244887Schin 	regdisc_t*		disc;
1254887Schin 
1264887Schin 	disc = p->env->disc;
1274887Schin 	if (p->env->flags & REG_NOSUB)
1284887Schin 	{
1294887Schin 		regfree(p);
1304887Schin 		return fatal(disc, REG_BADPAT, NiL);
1314887Schin 	}
1324887Schin 	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))))
1334887Schin 	{
1344887Schin 		if (sub)
1354887Schin 			alloc(p->env->disc, sub, 0);
1364887Schin 		regfree(p);
1374887Schin 		return fatal(disc, REG_ESPACE, s);
1384887Schin 	}
1394887Schin 	sub->re_buf = sub->re_end = 0;
1404887Schin 	p->re_sub = sub;
1414887Schin 	p->env->sub = 1;
1424887Schin 	op = sub->re_ops;
1434887Schin 	o = s;
1444887Schin 	if (!(p->env->flags & REG_DELIMITED))
1454887Schin 		d = 0;
1464887Schin 	else
1474887Schin 		switch (d = *(s - 1))
1484887Schin 		{
1494887Schin 		case '\\':
1504887Schin 		case '\n':
1514887Schin 		case '\r':
1524887Schin 			regfree(p);
1534887Schin 			return fatal(disc, REG_EDELIM, s);
1544887Schin 		}
1554887Schin 	sre = p->env->flags & REG_SHELL;
1564887Schin 	t = sub->re_rhs;
1574887Schin 	if (d)
1584887Schin 	{
1594887Schin 		r = s;
1604887Schin 		for (;;)
1614887Schin 		{
1624887Schin 			if (!*s)
1634887Schin 			{
1644887Schin 				if (p->env->flags & REG_MUSTDELIM)
1654887Schin 				{
1664887Schin 					regfree(p);
1674887Schin 					return fatal(disc, REG_EDELIM, r);
1684887Schin 				}
1694887Schin 				break;
1704887Schin 			}
1714887Schin 			else if (*s == d)
1724887Schin 			{
1734887Schin 				flags |= REG_SUB_FULL;
1744887Schin 				s++;
1754887Schin 				break;
1764887Schin 			}
1774887Schin 			else if (*s++ == '\\' && !*s++)
1784887Schin 			{
1794887Schin 				regfree(p);
1804887Schin 				return fatal(disc, REG_EESCAPE, r);
1814887Schin 			}
1824887Schin 		}
1834887Schin 		if (*s)
1844887Schin 		{
1854887Schin 			if (n = regsubflags(p, s, &e, d, map, &minmatch, &flags))
1864887Schin 				return n;
1874887Schin 			s = (const char*)e;
1884887Schin 		}
1894887Schin 		p->re_npat = s - o;
1904887Schin 		s = r;
1914887Schin 	}
1924887Schin 	else
1934887Schin 		p->re_npat = 0;
1944887Schin 	op->op = f = g = flags & (REG_SUB_LOWER|REG_SUB_UPPER);
1954887Schin 	op->off = 0;
1964887Schin 	while ((c = *s++) != d)
1974887Schin 	{
1984887Schin 	again:
1994887Schin 		if (!c)
2004887Schin 		{
2014887Schin 			p->re_npat = s - o - 1;
2024887Schin 			break;
2034887Schin 		}
2044887Schin 		else if (c == '\\')
2054887Schin 		{
2064887Schin 			if (*s == c)
2074887Schin 			{
2084887Schin 				*t++ = *s++;
2094887Schin 				continue;
2104887Schin 			}
2114887Schin 			if ((c = *s++) == d)
2124887Schin 				goto again;
2134887Schin 			if (!c)
2144887Schin 			{
2154887Schin 				regfree(p);
2164887Schin 				return fatal(disc, REG_EESCAPE, s - 2);
2174887Schin 			}
2184887Schin 			if (c == '&')
2194887Schin 			{
2204887Schin 				*t++ = c;
2214887Schin 				continue;
2224887Schin 			}
2234887Schin 		}
2244887Schin 		else if (c == '&')
2254887Schin 		{
2264887Schin 			if (sre)
2274887Schin 			{
2284887Schin 				*t++ = c;
2294887Schin 				continue;
2304887Schin 			}
2314887Schin 		}
2324887Schin 		else
2334887Schin 		{
2344887Schin 			switch (op->op)
2354887Schin 			{
2364887Schin 			case REG_SUB_UPPER:
2374887Schin 				if (islower(c))
2384887Schin 					c = toupper(c);
2394887Schin 				break;
2404887Schin 			case REG_SUB_LOWER:
2414887Schin 				if (isupper(c))
2424887Schin 					c = tolower(c);
2434887Schin 				break;
2444887Schin 			case REG_SUB_UPPER|REG_SUB_LOWER:
2454887Schin 				if (isupper(c))
2464887Schin 					c = tolower(c);
2474887Schin 				else if (islower(c))
2484887Schin 					c = toupper(c);
2494887Schin 				break;
2504887Schin 			}
2514887Schin 			*t++ = c;
2524887Schin 			continue;
2534887Schin 		}
2544887Schin 		switch (c)
2554887Schin 		{
2564887Schin 		case 0:
2574887Schin 			s--;
2584887Schin 			continue;
2594887Schin 		case '&':
2604887Schin 			c = 0;
2614887Schin 			break;
2624887Schin 		case '0': case '1': case '2': case '3': case '4':
2634887Schin 		case '5': case '6': case '7': case '8': case '9':
2644887Schin 			c -= '0';
2658462SApril.Chin@Sun.COM 			if (isdigit(*s) && (p->env->flags & REG_MULTIREF))
2664887Schin 				c = c * 10 + *s++ - '0';
2674887Schin 			break;
2684887Schin 		case 'l':
2694887Schin 			if (c = *s)
2704887Schin 			{
2714887Schin 				s++;
2724887Schin 				if (isupper(c))
2734887Schin 					c = tolower(c);
2744887Schin 				*t++ = c;
2754887Schin 			}
2764887Schin 			continue;
2774887Schin 		case 'u':
2784887Schin 			if (c = *s)
2794887Schin 			{
2804887Schin 				s++;
2814887Schin 				if (islower(c))
2824887Schin 					c = toupper(c);
2834887Schin 				*t++ = c;
2844887Schin 			}
2854887Schin 			continue;
2864887Schin 		case 'E':
2874887Schin 			f = g;
2884887Schin 		set:
2894887Schin 			if ((op->len = (t - sub->re_rhs) - op->off) && (n = ++op - sub->re_ops) >= nops)
2904887Schin 			{
2914887Schin 				if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
2924887Schin 				{
2934887Schin 					regfree(p);
2944887Schin 					return fatal(disc, REG_ESPACE, NiL);
2954887Schin 				}
2964887Schin 				op = sub->re_ops + n;
2974887Schin 			}
2984887Schin 			op->op = f;
2994887Schin 			op->off = t - sub->re_rhs;
3004887Schin 			continue;
3014887Schin 		case 'L':
3024887Schin 			g = f;
3034887Schin 			f = REG_SUB_LOWER;
3044887Schin 			goto set;
3054887Schin 		case 'U':
3064887Schin 			g = f;
3074887Schin 			f = REG_SUB_UPPER;
3084887Schin 			goto set;
3094887Schin 		default:
3104887Schin 			if (!sre)
3114887Schin 			{
3124887Schin 				*t++ = chresc(s - 2, &e);
3134887Schin 				s = (const char*)e;
3144887Schin 				continue;
3154887Schin 			}
3164887Schin 			s--;
3174887Schin 			c = -1;
3184887Schin 			break;
3194887Schin 		}
3204887Schin 		if (c > p->re_nsub)
3214887Schin 		{
3224887Schin 			regfree(p);
3234887Schin 			return fatal(disc, REG_ESUBREG, s - 1);
3244887Schin 		}
3254887Schin 		if ((n = op - sub->re_ops) >= (nops - 2))
3264887Schin 		{
3274887Schin 			if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
3284887Schin 			{
3294887Schin 				regfree(p);
3304887Schin 				return fatal(disc, REG_ESPACE, NiL);
3314887Schin 			}
3324887Schin 			op = sub->re_ops + n;
3334887Schin 		}
3344887Schin 		if (op->len = (t - sub->re_rhs) - op->off)
3354887Schin 			op++;
3364887Schin 		op->op = f;
3374887Schin 		op->off = c;
3384887Schin 		op->len = 0;
3394887Schin 		op++;
3404887Schin 		op->op = f;
3414887Schin 		op->off = t - sub->re_rhs;
3424887Schin 	}
3434887Schin 	if ((op->len = (t - sub->re_rhs) - op->off) && (n = ++op - sub->re_ops) >= nops)
3444887Schin 	{
3454887Schin 		if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
3464887Schin 		{
3474887Schin 			regfree(p);
3484887Schin 			return fatal(disc, REG_ESPACE, NiL);
3494887Schin 		}
3504887Schin 		op = sub->re_ops + n;
3514887Schin 	}
3524887Schin 	op->len = -1;
3534887Schin 	sub->re_flags = flags;
3544887Schin 	sub->re_min = minmatch;
3554887Schin 	return 0;
3564887Schin }
3574887Schin 
3584887Schin void
regsubfree(regex_t * p)3594887Schin regsubfree(regex_t* p)
3604887Schin {
3614887Schin 	Env_t*		env;
3624887Schin 	regsub_t*	sub;
3634887Schin 
3644887Schin 	if (p && (env = p->env) && env->sub && (sub = p->re_sub))
3654887Schin 	{
3664887Schin 		env->sub = 0;
3674887Schin 		p->re_sub = 0;
3684887Schin 		if (!(env->disc->re_flags & REG_NOFREE))
3694887Schin 		{
3704887Schin 			if (sub->re_buf)
3714887Schin 				alloc(env->disc, sub->re_buf, 0);
3724887Schin 			if (sub->re_ops)
3734887Schin 				alloc(env->disc, sub->re_ops, 0);
3744887Schin 			alloc(env->disc, sub, 0);
3754887Schin 		}
3764887Schin 	}
3774887Schin }
378