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