#include <sys/types.h>
#include <stdlib.h>
#include <stddef.h>
#define CBRA 1
#define CCHR 2
#define CDOT 4
#define CCL 6
#define NCCL 8
#define CDOL 10
#define CEOF 11
#define CKET 12
#define CBACK 18
#define CSTAR 01
#define ESIZE 512
#define NBRA 9
static struct re_globals {
char _expbuf[ESIZE];
char *_braslist[NBRA], *_braelist[NBRA];
char _circf;
} *re_globals;
#define expbuf (_re->_expbuf)
#define braslist (_re->_braslist)
#define braelist (_re->_braelist)
#define circf (_re->_circf)
static int backref(int, char *);
static int advance(char *, char *);
static int cclass(char *, char, int);
char *
re_comp(char *sp)
{
char c;
struct re_globals *_re = re_globals;
char *ep;
int cclcnt, numbra = 0;
char *lastep = 0;
char bracket[NBRA];
char *bracketp = &bracket[0];
char *retoolong = "Regular expression too long";
if (_re == 0) {
_re = (struct re_globals *)calloc(1, sizeof (*_re));
if (_re == 0)
return ("Out of memory");
re_globals = _re;
}
ep = expbuf;
#define comerr(msg) {expbuf[0] = 0; return (msg); }
if (sp == 0 || *sp == '\0') {
if (*ep == 0)
return ("No previous regular expression");
return (0);
}
if (*sp == '^') {
circf = 1;
sp++;
}
else
circf = 0;
for (;;) {
if (ep >= &expbuf[ESIZE])
comerr(retoolong);
if ((c = *sp++) == '\0') {
if (bracketp != bracket)
comerr("unmatched \\(");
*ep++ = CEOF;
*ep++ = 0;
return (0);
}
if (c != '*')
lastep = ep;
switch (c) {
case '.':
*ep++ = CDOT;
continue;
case '*':
if (lastep == 0 || *lastep == CBRA || *lastep == CKET)
goto defchar;
*lastep |= CSTAR;
continue;
case '$':
if (*sp != '\0')
goto defchar;
*ep++ = CDOL;
continue;
case '[':
*ep++ = CCL;
*ep++ = 0;
cclcnt = 1;
if ((c = *sp++) == '^') {
c = *sp++;
ep[-2] = NCCL;
}
do {
if (c == '\0')
comerr("missing ]");
if (c == '-' && ep [-1] != 0) {
if ((c = *sp++) == ']') {
*ep++ = '-';
cclcnt++;
break;
}
while (ep[-1] < c) {
*ep = ep[-1] + 1;
ep++;
cclcnt++;
if (ep >= &expbuf[ESIZE])
comerr(retoolong);
}
}
*ep++ = c;
cclcnt++;
if (ep >= &expbuf[ESIZE])
comerr(retoolong);
} while ((c = *sp++) != ']');
lastep[1] = (char)cclcnt;
continue;
case '\\':
if ((c = *sp++) == '(') {
if (numbra >= NBRA)
comerr("too many \\(\\) pairs");
*bracketp++ = (char)numbra;
*ep++ = CBRA;
*ep++ = numbra++;
continue;
}
if (c == ')') {
if (bracketp <= bracket)
comerr("unmatched \\)");
*ep++ = CKET;
*ep++ = *--bracketp;
continue;
}
if (c >= '1' && c < ('1' + NBRA)) {
*ep++ = CBACK;
*ep++ = c - '1';
continue;
}
*ep++ = CCHR;
*ep++ = c;
continue;
defchar:
default:
*ep++ = CCHR;
*ep++ = c;
}
}
}
int
re_exec(char *p1)
{
struct re_globals *_re = re_globals;
char *p2;
int c;
int rv;
if (_re == 0)
return (0);
p2 = expbuf;
for (c = 0; c < NBRA; c++) {
braslist[c] = 0;
braelist[c] = 0;
}
if (circf)
return ((advance(p1, p2)));
if (*p2 == CCHR) {
c = p2[1];
do {
if (*p1 != c)
continue;
if (rv = advance(p1, p2))
return (rv);
} while (*p1++);
return (0);
}
do
if (rv = advance(p1, p2))
return (rv);
while (*p1++);
return (0);
}
static int
advance(char *lp, char *ep)
{
char *curlp;
int i;
ptrdiff_t ct;
int rv;
struct re_globals *_re = re_globals;
for (;;)
switch (*ep++) {
case CCHR:
if (*ep++ == *lp++)
continue;
return (0);
case CDOT:
if (*lp++)
continue;
return (0);
case CDOL:
if (*lp == '\0')
continue;
return (0);
case CEOF:
return (1);
case CCL:
if (cclass(ep, *lp++, 1)) {
ep += *ep;
continue;
}
return (0);
case NCCL:
if (cclass(ep, *lp++, 0)) {
ep += *ep;
continue;
}
return (0);
case CBRA:
braslist[*ep++] = lp;
continue;
case CKET:
braelist[*ep++] = lp;
continue;
case CBACK:
if (braelist[i = *ep++] == 0)
return (-1);
if (backref(i, lp)) {
lp += braelist[i] - braslist[i];
continue;
}
return (0);
case CBACK|CSTAR:
if (braelist[i = *ep++] == 0)
return (-1);
curlp = lp;
ct = braelist[i] - braslist[i];
while (backref(i, lp))
lp += ct;
while (lp >= curlp) {
if (rv = advance(lp, ep))
return (rv);
lp -= ct;
}
continue;
case CDOT|CSTAR:
curlp = lp;
while (*lp++)
;
goto star;
case CCHR|CSTAR:
curlp = lp;
while (*lp++ == *ep)
;
ep++;
goto star;
case CCL|CSTAR:
case NCCL|CSTAR:
curlp = lp;
while (cclass(ep, *lp++, ep[-1] == (CCL|CSTAR)))
;
ep += *ep;
goto star;
star:
do {
lp--;
if (rv = advance(lp, ep))
return (rv);
} while (lp > curlp);
return (0);
default:
return (-1);
}
}
static int
backref(int i, char *lp)
{
char *bp;
struct re_globals *_re = re_globals;
bp = braslist[i];
while (*bp++ == *lp++)
if (bp >= braelist[i])
return (1);
return (0);
}
static int
cclass(char *set, char c, int af)
{
int n;
if (c == 0)
return (0);
n = *set++;
while (--n)
if (*set++ == c)
return (af);
return (! af);
}