#pragma prototyped
#include "reglib.h"
#define NEED(p,b,n,r) \
do \
{ \
if (((b)->re_end - (b)->re_cur) < (n)) \
{ \
size_t o = (b)->re_cur - (b)->re_buf; \
size_t a = ((b)->re_end - (b)->re_buf); \
if (a < n) \
a = roundof(n, 128); \
a *= 2; \
if (!((b)->re_buf = alloc(p->env->disc, (b)->re_buf, a))) \
{ \
(b)->re_buf = (b)->re_cur = (b)->re_end = 0; \
c = REG_ESPACE; \
r; \
} \
(b)->re_cur = (b)->re_buf + o; \
(b)->re_end = (b)->re_buf + a; \
} \
} while (0)
#define PUTC(p,b,x,r) \
do \
{ \
NEED(p, b, 1, r); \
*(b)->re_cur++ = (x); \
} while (0)
#define PUTS(p,b,x,z,r) \
do if (z) \
{ \
NEED(p, b, z, r); \
memcpy((b)->re_cur, x, z); \
(b)->re_cur += (z); \
} while (0)
static int
sub(const regex_t* p, register regsub_t* b, const char* ss, register regsubop_t* op, size_t nmatch, register regmatch_t* match)
{
register char* s;
register char* e;
register int c;
for (;; op++)
{
switch (op->len)
{
case -1:
break;
case 0:
if (op->off >= nmatch)
return REG_ESUBREG;
if ((c = match[op->off].rm_so) < 0)
continue;
s = (char*)ss + c;
if ((c = match[op->off].rm_eo) < 0)
continue;
e = (char*)ss + c;
NEED(p, b, e - s, return c);
switch (op->op)
{
case REG_SUB_UPPER:
while (s < e)
{
c = *s++;
if (islower(c))
c = toupper(c);
*b->re_cur++ = c;
}
break;
case REG_SUB_LOWER:
while (s < e)
{
c = *s++;
if (isupper(c))
c = tolower(c);
*b->re_cur++ = c;
}
break;
case REG_SUB_UPPER|REG_SUB_LOWER:
while (s < e)
{
c = *s++;
if (isupper(c))
c = tolower(c);
else if (islower(c))
c = toupper(c);
*b->re_cur++ = c;
}
break;
default:
while (s < e)
*b->re_cur++ = *s++;
break;
}
continue;
default:
NEED(p, b, op->len, return c);
s = b->re_rhs + op->off;
e = s + op->len;
while (s < e)
*b->re_cur++ = *s++;
continue;
}
break;
}
return 0;
}
int
regsubexec(const regex_t* p, const char* s, size_t nmatch, regmatch_t* match)
{
register int c;
register regsub_t* b;
const char* e;
int m;
if (!p->env->sub || (p->env->flags & REG_NOSUB) || !nmatch)
return fatal(p->env->disc, REG_BADPAT, NiL);
b = p->re_sub;
m = b->re_min;
b->re_cur = b->re_buf;
e = (const char*)p->env->end;
for (;;)
{
if (--m > 0)
PUTS(p, b, s, match->rm_eo, return fatal(p->env->disc, c, NiL));
else
{
PUTS(p, b, s, match->rm_so, return fatal(p->env->disc, c, NiL));
if (c = sub(p, b, s, b->re_ops, nmatch, match))
return fatal(p->env->disc, c, NiL);
}
s += match->rm_eo;
if (m <= 0 && !(b->re_flags & REG_SUB_ALL))
break;
if (c = regnexec(p, s, e - s, nmatch, match, p->env->flags|(match->rm_so == match->rm_eo ? REG_ADVANCE : 0)))
{
if (c != REG_NOMATCH)
return fatal(p->env->disc, c, NiL);
break;
}
}
while (s < e)
{
c = *s++;
PUTC(p, b, c, return fatal(p->env->disc, c, NiL));
}
NEED(p, b, 1, return fatal(p->env->disc, c, NiL));
*b->re_cur = 0;
b->re_len = b->re_cur - b->re_buf;
return 0;
}