regsubcomp.c revision 1
1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A
1N/A/*
1N/A * posix regex ed(1) style substitute compile
1N/A */
1N/A
1N/A#include "reglib.h"
1N/A
1N/Astatic const regflags_t submap[] =
1N/A{
1N/A 'g', REG_SUB_ALL,
1N/A 'l', REG_SUB_LOWER,
1N/A 'n', REG_SUB_NUMBER,
1N/A 'p', REG_SUB_PRINT,
1N/A 's', REG_SUB_STOP,
1N/A 'u', REG_SUB_UPPER,
1N/A 'w', REG_SUB_WRITE|REG_SUB_LAST,
1N/A 0, 0
1N/A};
1N/A
1N/Aint
1N/Aregsubflags(regex_t* p, register const char* s, char** e, int delim, register const regflags_t* map, int* pm, regflags_t* pf)
1N/A{
1N/A register int c;
1N/A register const regflags_t* m;
1N/A regflags_t flags;
1N/A int minmatch;
1N/A regdisc_t* disc;
1N/A
1N/A flags = pf ? *pf : 0;
1N/A minmatch = pm ? *pm : 0;
1N/A if (!map)
1N/A map = submap;
1N/A while (!(flags & REG_SUB_LAST))
1N/A {
1N/A if (!(c = *s++) || c == delim)
1N/A {
1N/A s--;
1N/A break;
1N/A }
1N/A else if (c >= '0' && c <= '9')
1N/A {
1N/A if (minmatch)
1N/A {
1N/A disc = p->env->disc;
1N/A regfree(p);
1N/A return fatal(disc, REG_EFLAGS, s - 1);
1N/A }
1N/A minmatch = c - '0';
1N/A while (*s >= '0' && *s <= '9')
1N/A minmatch = minmatch * 10 + *s++ - '0';
1N/A }
1N/A else
1N/A {
1N/A for (m = map; *m; m++)
1N/A if (*m++ == c)
1N/A {
1N/A if (flags & *m)
1N/A {
1N/A disc = p->env->disc;
1N/A regfree(p);
1N/A return fatal(disc, REG_EFLAGS, s - 1);
1N/A }
1N/A flags |= *m--;
1N/A break;
1N/A }
1N/A if (!*m)
1N/A {
1N/A s--;
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A if (pf)
1N/A *pf = flags;
1N/A if (pm)
1N/A *pm = minmatch;
1N/A if (e)
1N/A *e = (char*)s;
1N/A return 0;
1N/A}
1N/A
1N/A/*
1N/A * compile substitute rhs and optional flags
1N/A */
1N/A
1N/Aint
1N/Aregsubcomp(regex_t* p, register const char* s, const regflags_t* map, int minmatch, regflags_t flags)
1N/A{
1N/A register regsub_t* sub;
1N/A register int c;
1N/A register int d;
1N/A register char* t;
1N/A register regsubop_t* op;
1N/A char* e;
1N/A const char* r;
1N/A int sre;
1N/A int f;
1N/A int g;
1N/A int n;
1N/A int nops;
1N/A const char* o;
1N/A regdisc_t* disc;
1N/A
1N/A disc = p->env->disc;
1N/A if (p->env->flags & REG_NOSUB)
1N/A {
1N/A regfree(p);
1N/A return fatal(disc, REG_BADPAT, NiL);
1N/A }
1N/A 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))))
1N/A {
1N/A if (sub)
1N/A alloc(p->env->disc, sub, 0);
1N/A regfree(p);
1N/A return fatal(disc, REG_ESPACE, s);
1N/A }
1N/A sub->re_buf = sub->re_end = 0;
1N/A p->re_sub = sub;
1N/A p->env->sub = 1;
1N/A op = sub->re_ops;
1N/A o = s;
1N/A if (!(p->env->flags & REG_DELIMITED))
1N/A d = 0;
1N/A else
1N/A switch (d = *(s - 1))
1N/A {
1N/A case '\\':
1N/A case '\n':
1N/A case '\r':
1N/A regfree(p);
1N/A return fatal(disc, REG_EDELIM, s);
1N/A }
1N/A sre = p->env->flags & REG_SHELL;
1N/A t = sub->re_rhs;
1N/A if (d)
1N/A {
1N/A r = s;
1N/A for (;;)
1N/A {
1N/A if (!*s)
1N/A {
1N/A if (p->env->flags & REG_MUSTDELIM)
1N/A {
1N/A regfree(p);
1N/A return fatal(disc, REG_EDELIM, r);
1N/A }
1N/A break;
1N/A }
1N/A else if (*s == d)
1N/A {
1N/A flags |= REG_SUB_FULL;
1N/A s++;
1N/A break;
1N/A }
1N/A else if (*s++ == '\\' && !*s++)
1N/A {
1N/A regfree(p);
1N/A return fatal(disc, REG_EESCAPE, r);
1N/A }
1N/A }
1N/A if (*s)
1N/A {
1N/A if (n = regsubflags(p, s, &e, d, map, &minmatch, &flags))
1N/A return n;
1N/A s = (const char*)e;
1N/A }
1N/A p->re_npat = s - o;
1N/A s = r;
1N/A }
1N/A else
1N/A p->re_npat = 0;
1N/A op->op = f = g = flags & (REG_SUB_LOWER|REG_SUB_UPPER);
1N/A op->off = 0;
1N/A while ((c = *s++) != d)
1N/A {
1N/A again:
1N/A if (!c)
1N/A {
1N/A p->re_npat = s - o - 1;
1N/A break;
1N/A }
1N/A else if (c == '\\')
1N/A {
1N/A if (*s == c)
1N/A {
1N/A *t++ = *s++;
1N/A continue;
1N/A }
1N/A if ((c = *s++) == d)
1N/A goto again;
1N/A if (!c)
1N/A {
1N/A regfree(p);
1N/A return fatal(disc, REG_EESCAPE, s - 2);
1N/A }
1N/A if (c == '&')
1N/A {
1N/A *t++ = c;
1N/A continue;
1N/A }
1N/A }
1N/A else if (c == '&')
1N/A {
1N/A if (sre)
1N/A {
1N/A *t++ = c;
1N/A continue;
1N/A }
1N/A }
1N/A else
1N/A {
1N/A switch (op->op)
1N/A {
1N/A case REG_SUB_UPPER:
1N/A if (islower(c))
1N/A c = toupper(c);
1N/A break;
1N/A case REG_SUB_LOWER:
1N/A if (isupper(c))
1N/A c = tolower(c);
1N/A break;
1N/A case REG_SUB_UPPER|REG_SUB_LOWER:
if (isupper(c))
c = tolower(c);
else if (islower(c))
c = toupper(c);
break;
}
*t++ = c;
continue;
}
switch (c)
{
case 0:
s--;
continue;
case '&':
c = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
c -= '0';
if (isdigit(*s) && (p->env->flags & REG_MULTIREF))
c = c * 10 + *s++ - '0';
break;
case 'l':
if (c = *s)
{
s++;
if (isupper(c))
c = tolower(c);
*t++ = c;
}
continue;
case 'u':
if (c = *s)
{
s++;
if (islower(c))
c = toupper(c);
*t++ = c;
}
continue;
case 'E':
f = g;
set:
if ((op->len = (t - sub->re_rhs) - op->off) && (n = ++op - sub->re_ops) >= nops)
{
if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
{
regfree(p);
return fatal(disc, REG_ESPACE, NiL);
}
op = sub->re_ops + n;
}
op->op = f;
op->off = t - sub->re_rhs;
continue;
case 'L':
g = f;
f = REG_SUB_LOWER;
goto set;
case 'U':
g = f;
f = REG_SUB_UPPER;
goto set;
default:
if (!sre)
{
*t++ = chresc(s - 2, &e);
s = (const char*)e;
continue;
}
s--;
c = -1;
break;
}
if (c > p->re_nsub)
{
regfree(p);
return fatal(disc, REG_ESUBREG, s - 1);
}
if ((n = op - sub->re_ops) >= (nops - 2))
{
if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
{
regfree(p);
return fatal(disc, REG_ESPACE, NiL);
}
op = sub->re_ops + n;
}
if (op->len = (t - sub->re_rhs) - op->off)
op++;
op->op = f;
op->off = c;
op->len = 0;
op++;
op->op = f;
op->off = t - sub->re_rhs;
}
if ((op->len = (t - sub->re_rhs) - op->off) && (n = ++op - sub->re_ops) >= nops)
{
if (!(sub->re_ops = (regsubop_t*)alloc(p->env->disc, sub->re_ops, (nops *= 2) * sizeof(regsubop_t))))
{
regfree(p);
return fatal(disc, REG_ESPACE, NiL);
}
op = sub->re_ops + n;
}
op->len = -1;
sub->re_flags = flags;
sub->re_min = minmatch;
return 0;
}
void
regsubfree(regex_t* p)
{
Env_t* env;
regsub_t* sub;
if (p && (env = p->env) && env->sub && (sub = p->re_sub))
{
env->sub = 0;
p->re_sub = 0;
if (!(env->disc->re_flags & REG_NOFREE))
{
if (sub->re_buf)
alloc(env->disc, sub->re_buf, 0);
if (sub->re_ops)
alloc(env->disc, sub->re_ops, 0);
alloc(env->disc, sub, 0);
}
}
}