Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions | Variables

regcomp.c File Reference

#include "regex/regguts.h"
#include "regc_lex.c"
#include "regc_color.c"
#include "regc_nfa.c"
#include "regc_cvec.c"
#include "regc_pg_locale.c"
#include "regc_locale.c"
Include dependency graph for regcomp.c:

Go to the source code of this file.

Data Structures

struct  vars

Defines

#define INCOMPATIBLE   1
#define SATISFIED   2
#define COMPATIBLE   3
#define NEXT()   (next(v))
#define SEE(t)   (v->nexttype == (t))
#define EAT(t)   (SEE(t) && next(v))
#define VISERR(vv)   ((vv)->err != 0)
#define ISERR()   VISERR(v)
#define VERR(vv, e)
#define ERR(e)   VERR(v, e)
#define NOERR()   {if (ISERR()) return;}
#define NOERRN()   {if (ISERR()) return NULL;}
#define NOERRZ()   {if (ISERR()) return 0;}
#define INSIST(c, e)   do { if (!(c)) ERR(e); } while (0)
#define NOTE(b)   (v->re->re_info |= (b))
#define EMPTYARC(x, y)   newarc(v->nfa, EMPTY, 0, x, y)
#define EMPTY   'n'
#define EOS   'e'
#define PLAIN   'p'
#define DIGIT   'd'
#define BACKREF   'b'
#define COLLEL   'I'
#define ECLASS   'E'
#define CCLASS   'C'
#define END   'X'
#define RANGE   'R'
#define LACON   'L'
#define AHEAD   'a'
#define BEHIND   'r'
#define WBDRY   'w'
#define NWBDRY   'W'
#define SBEGIN   'A'
#define SEND   'Z'
#define PREFER   'P'
#define COLORED(a)   ((a)->type == PLAIN || (a)->type == AHEAD || (a)->type == BEHIND)
#define CNOERR()   { if (ISERR()) return freev(v, v->err); }
#define ARCV(t, val)   newarc(v->nfa, t, val, lp, rp)
#define SOME   2
#define INF   3
#define PAIR(x, y)   ((x)*4 + (y))
#define REDUCE(x)   ( ((x) == INFINITY) ? INF : (((x) > 1) ? SOME : (x)) )

Functions

static void moresubs (struct vars *, int)
static int freev (struct vars *, int)
static void makesearch (struct vars *, struct nfa *)
static struct subreparse (struct vars *, int, int, struct state *, struct state *)
static struct subreparsebranch (struct vars *, int, int, struct state *, struct state *, int)
static void parseqatom (struct vars *, int, int, struct state *, struct state *, struct subre *)
static void nonword (struct vars *, int, struct state *, struct state *)
static void word (struct vars *, int, struct state *, struct state *)
static int scannum (struct vars *)
static void repeat (struct vars *, struct state *, struct state *, int, int)
static void bracket (struct vars *, struct state *, struct state *)
static void cbracket (struct vars *, struct state *, struct state *)
static void brackpart (struct vars *, struct state *, struct state *)
static const chrscanplain (struct vars *)
static void onechr (struct vars *, chr, struct state *, struct state *)
static void dovec (struct vars *, struct cvec *, struct state *, struct state *)
static void wordchrs (struct vars *)
static struct subresubre (struct vars *, int, int, struct state *, struct state *)
static void freesubre (struct vars *, struct subre *)
static void freesrnode (struct vars *, struct subre *)
static void optst (struct vars *, struct subre *)
static int numst (struct subre *, int)
static void markst (struct subre *)
static void cleanst (struct vars *)
static long nfatree (struct vars *, struct subre *, FILE *)
static long nfanode (struct vars *, struct subre *, FILE *)
static int newlacon (struct vars *, struct state *, struct state *, int)
static void freelacons (struct subre *, int)
static void rfree (regex_t *)
static void lexstart (struct vars *)
static void prefixes (struct vars *)
static void lexnest (struct vars *, const chr *, const chr *)
static void lexword (struct vars *)
static int next (struct vars *)
static int lexescape (struct vars *)
static chr lexdigits (struct vars *, int, int, int)
static int brenext (struct vars *, chr)
static void skip (struct vars *)
static chr newline (void)
static chr chrnamed (struct vars *, const chr *, const chr *, chr)
static void initcm (struct vars *, struct colormap *)
static void freecm (struct colormap *)
static void cmtreefree (struct colormap *, union tree *, int)
static color setcolor (struct colormap *, chr, pcolor)
static color maxcolor (struct colormap *)
static color newcolor (struct colormap *)
static void freecolor (struct colormap *, pcolor)
static color pseudocolor (struct colormap *)
static color subcolor (struct colormap *, chr c)
static color newsub (struct colormap *, pcolor)
static void subrange (struct vars *, chr, chr, struct state *, struct state *)
static void subblock (struct vars *, chr, struct state *, struct state *)
static void okcolors (struct nfa *, struct colormap *)
static void colorchain (struct colormap *, struct arc *)
static void uncolorchain (struct colormap *, struct arc *)
static void rainbow (struct nfa *, struct colormap *, int, pcolor, struct state *, struct state *)
static void colorcomplement (struct nfa *, struct colormap *, int, struct state *, struct state *, struct state *)
static struct nfanewnfa (struct vars *, struct colormap *, struct nfa *)
static void freenfa (struct nfa *)
static struct statenewstate (struct nfa *)
static struct statenewfstate (struct nfa *, int flag)
static void dropstate (struct nfa *, struct state *)
static void freestate (struct nfa *, struct state *)
static void destroystate (struct nfa *, struct state *)
static void newarc (struct nfa *, int, pcolor, struct state *, struct state *)
static struct arcallocarc (struct nfa *, struct state *)
static void freearc (struct nfa *, struct arc *)
static int hasnonemptyout (struct state *)
static int nonemptyouts (struct state *)
static int nonemptyins (struct state *)
static struct arcfindarc (struct state *, int, pcolor)
static void cparc (struct nfa *, struct arc *, struct state *, struct state *)
static void moveins (struct nfa *, struct state *, struct state *)
static void copyins (struct nfa *, struct state *, struct state *, int)
static void moveouts (struct nfa *, struct state *, struct state *)
static void copyouts (struct nfa *, struct state *, struct state *, int)
static void cloneouts (struct nfa *, struct state *, struct state *, struct state *, int)
static void delsub (struct nfa *, struct state *, struct state *)
static void deltraverse (struct nfa *, struct state *, struct state *)
static void dupnfa (struct nfa *, struct state *, struct state *, struct state *, struct state *)
static void duptraverse (struct nfa *, struct state *, struct state *)
static void cleartraverse (struct nfa *, struct state *)
static void specialcolors (struct nfa *)
static long optimize (struct nfa *, FILE *)
static void pullback (struct nfa *, FILE *)
static int pull (struct nfa *, struct arc *)
static void pushfwd (struct nfa *, FILE *)
static int push (struct nfa *, struct arc *)
static int combine (struct arc *, struct arc *)
static void fixempties (struct nfa *, FILE *)
static struct stateemptyreachable (struct state *, struct state *)
static void replaceempty (struct nfa *, struct state *, struct state *)
static void cleanup (struct nfa *)
static void markreachable (struct nfa *, struct state *, struct state *, struct state *)
static void markcanreach (struct nfa *, struct state *, struct state *, struct state *)
static long analyze (struct nfa *)
static void compact (struct nfa *, struct cnfa *)
static void carcsort (struct carc *, struct carc *)
static void freecnfa (struct cnfa *)
static void dumpnfa (struct nfa *, FILE *)
static struct cvecnewcvec (int, int)
static struct cvecclearcvec (struct cvec *)
static void addchr (struct cvec *, chr)
static void addrange (struct cvec *, chr, chr)
static struct cvecgetcvec (struct vars *, int, int)
static void freecvec (struct cvec *)
static int pg_wc_isdigit (pg_wchar c)
static int pg_wc_isalpha (pg_wchar c)
static int pg_wc_isalnum (pg_wchar c)
static int pg_wc_isupper (pg_wchar c)
static int pg_wc_islower (pg_wchar c)
static int pg_wc_isgraph (pg_wchar c)
static int pg_wc_isprint (pg_wchar c)
static int pg_wc_ispunct (pg_wchar c)
static int pg_wc_isspace (pg_wchar c)
static pg_wchar pg_wc_toupper (pg_wchar c)
static pg_wchar pg_wc_tolower (pg_wchar c)
static celt element (struct vars *, const chr *, const chr *)
static struct cvecrange (struct vars *, celt, celt, int)
static int before (celt, celt)
static struct cvececlass (struct vars *, celt, int)
static struct cveccclass (struct vars *, const chr *, const chr *, int)
static struct cvecallcases (struct vars *, chr)
static int cmp (const chr *, const chr *, size_t)
static int casecmp (const chr *, const chr *, size_t)
int pg_regcomp (regex_t *re, const chr *string, size_t len, int flags, Oid collation)

Variables

static struct fns functions

Define Documentation

#define AHEAD   'a'

Definition at line 263 of file regcomp.c.

Referenced by combine(), nonword(), parseqatom(), pull(), push(), pushfwd(), and word().

#define ARCV (   t,
  val 
)    newarc(v->nfa, t, val, lp, rp)

Referenced by parseqatom().

#define BACKREF   'b'

Definition at line 256 of file regcomp.c.

Referenced by brenext(), lexescape(), and parseqatom().

#define BEHIND   'r'

Definition at line 264 of file regcomp.c.

Referenced by combine(), nonword(), parseqatom(), pull(), pullback(), push(), and word().

#define CCLASS   'C'

Definition at line 259 of file regcomp.c.

Referenced by brackpart(), lexescape(), next(), and scanplain().

#define CNOERR (  )     { if (ISERR()) return freev(v, v->err); }

Referenced by pg_regcomp().

#define COLLEL   'I'

Definition at line 257 of file regcomp.c.

Referenced by brackpart(), next(), and scanplain().

#define COLORED (   a  )     ((a)->type == PLAIN || (a)->type == AHEAD || (a)->type == BEHIND)

Definition at line 272 of file regcomp.c.

Referenced by freearc(), and newarc().

#define COMPATIBLE   3

Definition at line 149 of file regcomp.c.

Referenced by pull(), and push().

#define DIGIT   'd'

Definition at line 255 of file regcomp.c.

Referenced by next(), parseqatom(), and scannum().

#define EAT (   t  )     (SEE(t) && next(v))

Definition at line 238 of file regcomp.c.

Referenced by parse(), and parseqatom().

#define ECLASS   'E'

Definition at line 258 of file regcomp.c.

Referenced by brackpart(), next(), and scanplain().

#define EMPTY   'n'
#define EMPTYARC (   x,
  y 
)    newarc(v->nfa, EMPTY, 0, x, y)

Definition at line 249 of file regcomp.c.

Referenced by parse(), parsebranch(), parseqatom(), and repeat().

#define END   'X'

Definition at line 260 of file regcomp.c.

Referenced by scanplain().

#define EOS   'e'

Definition at line 253 of file regcomp.c.

Referenced by bracket(), next(), parse(), parsebranch(), parseqatom(), and pg_regcomp().

#define ERR (   e  )     VERR(v, e)

Definition at line 243 of file regcomp.c.

Referenced by brackpart(), freev(), moresubs(), newlacon(), parse(), parseqatom(), repeat(), scannum(), and subre().

#define INCOMPATIBLE   1

Definition at line 147 of file regcomp.c.

Referenced by pull(), and push().

#define INF   3

Referenced by repeat().

#define INSIST (   c,
  e 
)    do { if (!(c)) ERR(e); } while (0)

Definition at line 247 of file regcomp.c.

Referenced by brackpart(), and parseqatom().

#define ISERR (  )     VISERR(v)

Definition at line 240 of file regcomp.c.

Referenced by bracket(), lexescape(), newnfa(), next(), nfanode(), parseqatom(), scanplain(), and wordchrs().

#define LACON   'L'

Definition at line 262 of file regcomp.c.

Referenced by combine(), compact(), next(), and parseqatom().

#define NEXT (  )     (next(v))

Definition at line 236 of file regcomp.c.

Referenced by bracket(), brackpart(), parseqatom(), scannum(), scanplain(), and wordchrs().

#define NOERR (  )     {if (ISERR()) return;}

Definition at line 244 of file regcomp.c.

Referenced by brackpart(), cbracket(), lexstart(), parseqatom(), repeat(), and wordchrs().

#define NOERRN (  )     {if (ISERR()) return NULL;}

Definition at line 245 of file regcomp.c.

Referenced by parse(), parsebranch(), and range().

#define NOERRZ (  )     {if (ISERR()) return 0;}

Definition at line 246 of file regcomp.c.

Referenced by nfanode().

#define NOTE (   b  )     (v->re->re_info |= (b))
#define NWBDRY   'W'

Definition at line 266 of file regcomp.c.

Referenced by lexescape(), and parseqatom().

#define PAIR (   x,
  y 
)    ((x)*4 + (y))

Referenced by repeat().

#define PLAIN   'p'
#define PREFER   'P'

Definition at line 269 of file regcomp.c.

#define RANGE   'R'

Definition at line 261 of file regcomp.c.

Referenced by brackpart(), and next().

#define REDUCE (   x  )     ( ((x) == INFINITY) ? INF : (((x) > 1) ? SOME : (x)) )

Referenced by repeat().

#define SATISFIED   2

Definition at line 148 of file regcomp.c.

Referenced by pull(), and push().

#define SBEGIN   'A'

Definition at line 267 of file regcomp.c.

Referenced by lexescape(), next(), and parseqatom().

#define SEE (   t  )     (v->nexttype == (t))
#define SEND   'Z'

Definition at line 268 of file regcomp.c.

Referenced by lexescape(), and parseqatom().

#define SOME   2

Referenced by repeat().

#define VERR (   vv,
  e 
)
Value:
((vv)->nexttype = EOS, \
                     (vv)->err = ((vv)->err ? (vv)->err : (e)))

Definition at line 241 of file regcomp.c.

#define VISERR (   vv  )     ((vv)->err != 0)

Definition at line 239 of file regcomp.c.

#define WBDRY   'w'

Definition at line 265 of file regcomp.c.

Referenced by lexescape(), and parseqatom().


Function Documentation

static void addchr ( struct cvec ,
chr   
) [static]
static void addrange ( struct cvec ,
chr  ,
chr   
) [static]
static struct cvec* allcases ( struct vars ,
chr   
) [static, read]

Referenced by onechr().

static struct arc* allocarc ( struct nfa ,
struct state  
) [static, read]
static long analyze ( struct nfa  )  [static]
static int before ( celt  ,
celt   
) [static]
static void bracket ( struct vars v,
struct state lp,
struct state rp 
) [static]

Definition at line 1336 of file regcomp.c.

References assert, brackpart(), vars::cm, EOS, ISERR, NEXT, vars::nfa, okcolors(), and SEE.

Referenced by cbracket(), parseqatom(), and wordchrs().

{
    assert(SEE('['));
    NEXT();
    while (!SEE(']') && !SEE(EOS))
        brackpart(v, lp, rp);
    assert(SEE(']') || ISERR());
    okcolors(v->nfa, v->cm);
}

static void brackpart ( struct vars v,
struct state lp,
struct state rp 
) [static]

Definition at line 1385 of file regcomp.c.

References cclass(), CCLASS, vars::cflags, COLLEL, dovec(), eclass(), ECLASS, element(), ERR, INSIST, NEXT, vars::nexttype, vars::nextvalue, NOERR, NOTE, vars::now, onechr(), PLAIN, range(), RANGE, REG_ASSERT, REG_ECOLLATE, REG_ECTYPE, REG_ERANGE, REG_ICASE, REG_UUNPORT, scanplain(), and SEE.

Referenced by bracket().

{
    celt        startc;
    celt        endc;
    struct cvec *cv;
    const chr  *startp;
    const chr  *endp;
    chr         c[1];

    /* parse something, get rid of special cases, take shortcuts */
    switch (v->nexttype)
    {
        case RANGE:             /* a-b-c or other botch */
            ERR(REG_ERANGE);
            return;
            break;
        case PLAIN:
            c[0] = v->nextvalue;
            NEXT();
            /* shortcut for ordinary chr (not range) */
            if (!SEE(RANGE))
            {
                onechr(v, c[0], lp, rp);
                return;
            }
            startc = element(v, c, c + 1);
            NOERR();
            break;
        case COLLEL:
            startp = v->now;
            endp = scanplain(v);
            INSIST(startp < endp, REG_ECOLLATE);
            NOERR();
            startc = element(v, startp, endp);
            NOERR();
            break;
        case ECLASS:
            startp = v->now;
            endp = scanplain(v);
            INSIST(startp < endp, REG_ECOLLATE);
            NOERR();
            startc = element(v, startp, endp);
            NOERR();
            cv = eclass(v, startc, (v->cflags & REG_ICASE));
            NOERR();
            dovec(v, cv, lp, rp);
            return;
            break;
        case CCLASS:
            startp = v->now;
            endp = scanplain(v);
            INSIST(startp < endp, REG_ECTYPE);
            NOERR();
            cv = cclass(v, startp, endp, (v->cflags & REG_ICASE));
            NOERR();
            dovec(v, cv, lp, rp);
            return;
            break;
        default:
            ERR(REG_ASSERT);
            return;
            break;
    }

    if (SEE(RANGE))
    {
        NEXT();
        switch (v->nexttype)
        {
            case PLAIN:
            case RANGE:
                c[0] = v->nextvalue;
                NEXT();
                endc = element(v, c, c + 1);
                NOERR();
                break;
            case COLLEL:
                startp = v->now;
                endp = scanplain(v);
                INSIST(startp < endp, REG_ECOLLATE);
                NOERR();
                endc = element(v, startp, endp);
                NOERR();
                break;
            default:
                ERR(REG_ERANGE);
                return;
                break;
        }
    }
    else
        endc = startc;

    /*
     * Ranges are unportable.  Actually, standard C does guarantee that digits
     * are contiguous, but making that an exception is just too complicated.
     */
    if (startc != endc)
        NOTE(REG_UUNPORT);
    cv = range(v, startc, endc, (v->cflags & REG_ICASE));
    NOERR();
    dovec(v, cv, lp, rp);
}

static int brenext ( struct vars ,
chr   
) [static]
static void carcsort ( struct carc ,
struct carc  
) [static]
static int casecmp ( const chr ,
const chr ,
size_t   
) [static]

Referenced by pg_regcomp().

static void cbracket ( struct vars v,
struct state lp,
struct state rp 
) [static]

Definition at line 1355 of file regcomp.c.

References assert, bracket(), vars::cflags, vars::cm, colorcomplement(), dropstate(), freestate(), newarc(), newstate(), vars::nfa, state::nins, vars::nlcolor, NOERR, state::nouts, PLAIN, and REG_NLSTOP.

Referenced by parseqatom().

{
    struct state *left = newstate(v->nfa);
    struct state *right = newstate(v->nfa);

    NOERR();
    bracket(v, left, right);
    if (v->cflags & REG_NLSTOP)
        newarc(v->nfa, PLAIN, v->nlcolor, left, right);
    NOERR();

    assert(lp->nouts == 0);     /* all outarcs will be ours */

    /*
     * Easy part of complementing, and all there is to do since the MCCE code
     * was removed.
     */
    colorcomplement(v->nfa, v->cm, PLAIN, left, lp, rp);
    NOERR();
    dropstate(v->nfa, left);
    assert(right->nins == 0);
    freestate(v->nfa, right);
}

static struct cvec* cclass ( struct vars ,
const chr ,
const chr ,
int   
) [static, read]

Referenced by brackpart().

static chr chrnamed ( struct vars ,
const chr ,
const chr ,
chr   
) [static]
static void cleanst ( struct vars v  )  [static]

Definition at line 1743 of file regcomp.c.

References subre::chain, subre::flags, FREE, INUSE, NULL, vars::treechain, and vars::treefree.

Referenced by freev(), and pg_regcomp().

{
    struct subre *t;
    struct subre *next;

    for (t = v->treechain; t != NULL; t = next)
    {
        next = t->chain;
        if (!(t->flags & INUSE))
            FREE(t);
    }
    v->treechain = NULL;
    v->treefree = NULL;         /* just on general principles */
}

static void cleanup ( struct nfa  )  [static]
static struct cvec* clearcvec ( struct cvec  )  [static, read]
static void cleartraverse ( struct nfa ,
struct state  
) [static]
static void cloneouts ( struct nfa ,
struct state ,
struct state ,
struct state ,
int   
) [static]

Referenced by word().

static int cmp ( const chr ,
const chr ,
size_t   
) [static]

Referenced by pg_regcomp().

static void cmtreefree ( struct colormap ,
union tree ,
int   
) [static]
static void colorchain ( struct colormap ,
struct arc  
) [static]
static void colorcomplement ( struct nfa ,
struct colormap ,
int  ,
struct state ,
struct state ,
struct state  
) [static]

Referenced by cbracket(), and nonword().

static int combine ( struct arc ,
struct arc  
) [static]
static void compact ( struct nfa ,
struct cnfa  
) [static]

Referenced by nfanode(), and pg_regcomp().

static void copyins ( struct nfa ,
struct state ,
struct state ,
int   
) [static]
static void copyouts ( struct nfa ,
struct state ,
struct state ,
int   
) [static]

Referenced by makesearch().

static void cparc ( struct nfa ,
struct arc ,
struct state ,
struct state  
) [static]

Referenced by makesearch().

static void delsub ( struct nfa ,
struct state ,
struct state  
) [static]

Referenced by parseqatom(), and repeat().

static void deltraverse ( struct nfa ,
struct state ,
struct state  
) [static]
static void destroystate ( struct nfa ,
struct state  
) [static]
static void dovec ( struct vars v,
struct cvec cv,
struct state lp,
struct state rp 
) [static]

Definition at line 1542 of file regcomp.c.

References cvec::chrs, vars::cm, i, cvec::nchrs, newarc(), vars::nfa, cvec::nranges, PLAIN, cvec::ranges, subcolor(), and subrange().

Referenced by brackpart(), and onechr().

{
    chr         ch,
                from,
                to;
    const chr  *p;
    int         i;

    /* ordinary characters */
    for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--)
    {
        ch = *p;
        newarc(v->nfa, PLAIN, subcolor(v->cm, ch), lp, rp);
    }

    /* and the ranges */
    for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--)
    {
        from = *p;
        to = *(p + 1);
        if (from <= to)
            subrange(v, from, to, lp, rp);
    }
}

static void dropstate ( struct nfa ,
struct state  
) [static]

Referenced by cbracket().

static void dumpnfa ( struct nfa ,
FILE *   
) [static]

Referenced by pg_regcomp().

static void dupnfa ( struct nfa ,
struct state ,
struct state ,
struct state ,
struct state  
) [static]

Referenced by nfanode(), parseqatom(), and repeat().

static void duptraverse ( struct nfa ,
struct state ,
struct state  
) [static]
static struct cvec* eclass ( struct vars ,
celt  ,
int   
) [static, read]

Referenced by brackpart().

static celt element ( struct vars ,
const chr ,
const chr  
) [static]

Referenced by brackpart().

static struct state* emptyreachable ( struct state ,
struct state  
) [static, read]
static struct arc* findarc ( struct state ,
int  ,
pcolor   
) [static, read]
static void fixempties ( struct nfa ,
FILE *   
) [static]
static void freearc ( struct nfa ,
struct arc  
) [static]

Referenced by makesearch().

static void freecm ( struct colormap  )  [static]

Referenced by rfree().

static void freecnfa ( struct cnfa  )  [static]

Referenced by freelacons(), freesrnode(), and rfree().

static void freecolor ( struct colormap ,
pcolor   
) [static]
static void freecvec ( struct cvec  )  [static]

Referenced by freev().

static void freelacons ( struct subre subs,
int  n 
) [static]

Definition at line 1854 of file regcomp.c.

References assert, subre::cnfa, FREE, freecnfa(), i, and NULLCNFA.

Referenced by freev(), and rfree().

{
    struct subre *sub;
    int         i;

    assert(n > 0);
    for (sub = subs + 1, i = n - 1; i > 0; sub++, i--)  /* no 0th */
        if (!NULLCNFA(sub->cnfa))
            freecnfa(&sub->cnfa);
    FREE(subs);
}

static void freenfa ( struct nfa  )  [static]

Referenced by freev(), and nfanode().

static void freesrnode ( struct vars v,
struct subre sr 
) [static]

Definition at line 1669 of file regcomp.c.

References subre::cnfa, subre::flags, FREE, freecnfa(), subre::left, NULL, NULLCNFA, and vars::treefree.

Referenced by freesubre().

{
    if (sr == NULL)
        return;

    if (!NULLCNFA(sr->cnfa))
        freecnfa(&sr->cnfa);
    sr->flags = 0;

    if (v != NULL)
    {
        sr->left = v->treefree;
        v->treefree = sr;
    }
    else
        FREE(sr);
}

static void freestate ( struct nfa ,
struct state  
) [static]

Referenced by cbracket().

static void freesubre ( struct vars v,
struct subre sr 
) [static]

Definition at line 1651 of file regcomp.c.

References freesrnode(), subre::left, NULL, and subre::right.

Referenced by freev(), parse(), parseqatom(), and rfree().

{
    if (sr == NULL)
        return;

    if (sr->left != NULL)
        freesubre(v, sr->left);
    if (sr->right != NULL)
        freesubre(v, sr->right);

    freesrnode(v, sr);
}

static int freev ( struct vars v,
int  err 
) [static]

Definition at line 502 of file regcomp.c.

References cleanst(), vars::cv, vars::cv2, vars::err, ERR, FREE, freecvec(), freelacons(), freenfa(), freesubre(), vars::lacons, vars::nfa, vars::nlacons, NULL, vars::re, rfree(), vars::sub10, vars::subs, vars::tree, and vars::treechain.

Referenced by pg_regcomp().

{
    if (v->re != NULL)
        rfree(v->re);
    if (v->subs != v->sub10)
        FREE(v->subs);
    if (v->nfa != NULL)
        freenfa(v->nfa);
    if (v->tree != NULL)
        freesubre(v, v->tree);
    if (v->treechain != NULL)
        cleanst(v);
    if (v->cv != NULL)
        freecvec(v->cv);
    if (v->cv2 != NULL)
        freecvec(v->cv2);
    if (v->lacons != NULL)
        freelacons(v->lacons, v->nlacons);
    ERR(err);                   /* nop if err==0 */

    return v->err;
}

static struct cvec* getcvec ( struct vars ,
int  ,
int   
) [static, read]
static int hasnonemptyout ( struct state  )  [static]
static void initcm ( struct vars ,
struct colormap  
) [static]

Referenced by pg_regcomp().

static chr lexdigits ( struct vars ,
int  ,
int  ,
int   
) [static]
static int lexescape ( struct vars  )  [static]
static void lexnest ( struct vars ,
const chr ,
const chr  
) [static]
static void lexstart ( struct vars  )  [static]

Referenced by pg_regcomp().

static void lexword ( struct vars  )  [static]

Referenced by wordchrs().

static void makesearch ( struct vars v,
struct nfa nfa 
) [static]

Definition at line 531 of file regcomp.c.

References assert, nfa::bos, vars::cm, arc::co, COLORLESS, copyouts(), cparc(), freearc(), arc::from, arc::inchain, state::ins, newarc(), newstate(), NULL, arc::outchain, state::outs, PLAIN, nfa::pre, rainbow(), s2, state::tmp, arc::to, and arc::type.

Referenced by pg_regcomp().

{
    struct arc *a;
    struct arc *b;
    struct state *pre = nfa->pre;
    struct state *s;
    struct state *s2;
    struct state *slist;

    /* no loops are needed if it's anchored */
    for (a = pre->outs; a != NULL; a = a->outchain)
    {
        assert(a->type == PLAIN);
        if (a->co != nfa->bos[0] && a->co != nfa->bos[1])
            break;
    }
    if (a != NULL)
    {
        /* add implicit .* in front */
        rainbow(nfa, v->cm, PLAIN, COLORLESS, pre, pre);

        /* and ^* and \A* too -- not always necessary, but harmless */
        newarc(nfa, PLAIN, nfa->bos[0], pre, pre);
        newarc(nfa, PLAIN, nfa->bos[1], pre, pre);
    }

    /*
     * Now here's the subtle part.  Because many REs have no lookback
     * constraints, often knowing when you were in the pre state tells you
     * little; it's the next state(s) that are informative.  But some of them
     * may have other inarcs, i.e. it may be possible to make actual progress
     * and then return to one of them.  We must de-optimize such cases,
     * splitting each such state into progress and no-progress states.
     */

    /* first, make a list of the states */
    slist = NULL;
    for (a = pre->outs; a != NULL; a = a->outchain)
    {
        s = a->to;
        for (b = s->ins; b != NULL; b = b->inchain)
            if (b->from != pre)
                break;
        if (b != NULL && s->tmp == NULL)
        {
            /*
             * Must be split if not already in the list (fixes bugs 505048,
             * 230589, 840258, 504785).
             */
            s->tmp = slist;
            slist = s;
        }
    }

    /* do the splits */
    for (s = slist; s != NULL; s = s2)
    {
        s2 = newstate(nfa);
        copyouts(nfa, s, s2, 1);
        for (a = s->ins; a != NULL; a = b)
        {
            b = a->inchain;
            if (a->from != pre)
            {
                cparc(nfa, a, a->from, s2);
                freearc(nfa, a);
            }
        }
        s2 = s->tmp;
        s->tmp = NULL;          /* clean up while we're at it */
    }
}

static void markcanreach ( struct nfa ,
struct state ,
struct state ,
struct state  
) [static]
static void markreachable ( struct nfa ,
struct state ,
struct state ,
struct state  
) [static]
static void markst ( struct subre t  )  [static]

Definition at line 1728 of file regcomp.c.

References assert, subre::flags, subre::left, NULL, and subre::right.

Referenced by pg_regcomp().

{
    assert(t != NULL);

    t->flags |= INUSE;
    if (t->left != NULL)
        markst(t->left);
    if (t->right != NULL)
        markst(t->right);
}

static color maxcolor ( struct colormap  )  [static]
static void moresubs ( struct vars v,
int  wanted 
) [static]

Definition at line 465 of file regcomp.c.

References assert, ERR, MALLOC, vars::nsubs, NULL, REALLOC, REG_ESPACE, vars::sub10, vars::subs, and VS.

Referenced by parseqatom().

{
    struct subre **p;
    size_t      n;

    assert(wanted > 0 && (size_t) wanted >= v->nsubs);
    n = (size_t) wanted *3 / 2 + 1;

    if (v->subs == v->sub10)
    {
        p = (struct subre **) MALLOC(n * sizeof(struct subre *));
        if (p != NULL)
            memcpy(VS(p), VS(v->subs),
                   v->nsubs * sizeof(struct subre *));
    }
    else
        p = (struct subre **) REALLOC(v->subs, n * sizeof(struct subre *));
    if (p == NULL)
    {
        ERR(REG_ESPACE);
        return;
    }
    v->subs = p;
    for (p = &v->subs[v->nsubs]; v->nsubs < n; p++, v->nsubs++)
        *p = NULL;
    assert(v->nsubs == n);
    assert((size_t) wanted < v->nsubs);
}

static void moveins ( struct nfa ,
struct state ,
struct state  
) [static]

Referenced by parsebranch(), parseqatom(), and repeat().

static void moveouts ( struct nfa ,
struct state ,
struct state  
) [static]

Referenced by parseqatom(), and repeat().

static void newarc ( struct nfa ,
int  ,
pcolor  ,
struct state ,
struct state  
) [static]
static color newcolor ( struct colormap  )  [static]
static struct cvec* newcvec ( int  ,
int   
) [static, read]

Referenced by pg_regcomp().

static struct state* newfstate ( struct nfa ,
int  flag 
) [static, read]
static int newlacon ( struct vars v,
struct state begin,
struct state end,
int  pos 
) [static]

Definition at line 1817 of file regcomp.c.

References subre::begin, subre::cnfa, subre::end, ERR, vars::lacons, MALLOC, vars::nlacons, NULL, REALLOC, REG_ESPACE, subre::subno, and ZAPCNFA.

Referenced by parseqatom().

{
    int         n;
    struct subre *sub;

    if (v->nlacons == 0)
    {
        v->lacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
        n = 1;                  /* skip 0th */
        v->nlacons = 2;
    }
    else
    {
        v->lacons = (struct subre *) REALLOC(v->lacons,
                                    (v->nlacons + 1) * sizeof(struct subre));
        n = v->nlacons++;
    }
    if (v->lacons == NULL)
    {
        ERR(REG_ESPACE);
        return 0;
    }
    sub = &v->lacons[n];
    sub->begin = begin;
    sub->end = end;
    sub->subno = pos;
    ZAPCNFA(sub->cnfa);
    return n;
}

static chr newline ( void   )  [static]

Referenced by pg_regcomp().

static struct nfa* newnfa ( struct vars ,
struct colormap ,
struct nfa  
) [static, read]

Referenced by nfanode(), and pg_regcomp().

static struct state* newstate ( struct nfa  )  [static, read]
static color newsub ( struct colormap ,
pcolor   
) [static]
static int next ( struct vars  )  [static]
static long nfanode ( struct vars v,
struct subre t,
FILE *  f 
) [static]

Definition at line 1780 of file regcomp.c.

References assert, subre::begin, vars::cm, subre::cnfa, compact(), dupnfa(), subre::end, nfa::final, freenfa(), nfa::init, ISERR, newnfa(), vars::nfa, NOERRZ, NULL, optimize(), and specialcolors().

Referenced by nfatree(), and pg_regcomp().

{
    struct nfa *nfa;
    long        ret = 0;

    assert(t->begin != NULL);

#ifdef REG_DEBUG
    if (f != NULL)
    {
        char        idbuf[50];

        fprintf(f, "\n\n\n========= TREE NODE %s ==========\n",
                stid(t, idbuf, sizeof(idbuf)));
    }
#endif
    nfa = newnfa(v, v->cm, v->nfa);
    NOERRZ();
    dupnfa(nfa, t->begin, t->end, nfa->init, nfa->final);
    if (!ISERR())
    {
        specialcolors(nfa);
        ret = optimize(nfa, f);
    }
    if (!ISERR())
        compact(nfa, &t->cnfa);

    freenfa(nfa);
    return ret;
}

static long nfatree ( struct vars v,
struct subre t,
FILE *  f 
) [static]

Definition at line 1762 of file regcomp.c.

References assert, subre::begin, subre::left, nfanode(), NULL, and subre::right.

Referenced by pg_regcomp().

{
    assert(t != NULL && t->begin != NULL);

    if (t->left != NULL)
        (DISCARD) nfatree(v, t->left, f);
    if (t->right != NULL)
        (DISCARD) nfatree(v, t->right, f);

    return nfanode(v, t, f);
}

static int nonemptyins ( struct state  )  [static]
static int nonemptyouts ( struct state  )  [static]
static void nonword ( struct vars v,
int  dir,
struct state lp,
struct state rp 
) [static]

Definition at line 1187 of file regcomp.c.

References AHEAD, assert, BEHIND, vars::cm, colorcomplement(), newarc(), vars::nfa, and vars::wordchrs.

Referenced by parseqatom().

{
    int         anchor = (dir == AHEAD) ? '$' : '^';

    assert(dir == AHEAD || dir == BEHIND);
    newarc(v->nfa, anchor, 1, lp, rp);
    newarc(v->nfa, anchor, 0, lp, rp);
    colorcomplement(v->nfa, v->cm, dir, v->wordchrs, lp, rp);
    /* (no need for special attention to \n) */
}

static int numst ( struct subre t,
int  start 
) [static]

Definition at line 1708 of file regcomp.c.

References assert, i, subre::id, subre::left, NULL, and subre::right.

Referenced by pg_regcomp().

{
    int         i;

    assert(t != NULL);

    i = start;
    t->id = (short) i++;
    if (t->left != NULL)
        i = numst(t->left, i);
    if (t->right != NULL)
        i = numst(t->right, i);
    return i;
}

static void okcolors ( struct nfa ,
struct colormap  
) [static]

Referenced by bracket(), parseqatom(), and pg_regcomp().

static void onechr ( struct vars v,
chr  c,
struct state lp,
struct state rp 
) [static]

Definition at line 1523 of file regcomp.c.

References allcases(), vars::cflags, vars::cm, dovec(), newarc(), vars::nfa, PLAIN, REG_ICASE, and subcolor().

Referenced by brackpart(), and parseqatom().

{
    if (!(v->cflags & REG_ICASE))
    {
        newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp);
        return;
    }

    /* rats, need general case anyway... */
    dovec(v, allcases(v, c), lp, rp);
}

static long optimize ( struct nfa ,
FILE *   
) [static]

Referenced by nfanode(), and pg_regcomp().

static void optst ( struct vars v,
struct subre t 
) [static]

Definition at line 1692 of file regcomp.c.

Referenced by pg_regcomp().

{
    /*
     * DGP (2007-11-13): I assume it was the programmer's intent to eventually
     * come back and add code to optimize subRE trees, but the routine coded
     * just spends effort traversing the tree and doing nothing. We can do
     * nothing with less effort.
     */
    return;
}

static struct subre * parse ( struct vars v,
int  stopper,
int  type,
struct state init,
struct state final 
) [static, read]

Definition at line 613 of file regcomp.c.

References assert, EAT, EMPTYARC, EOS, ERR, subre::flags, freesubre(), subre::left, LONGER, MESSY, newstate(), vars::nfa, NOERRN, NULL, subre::op, parsebranch(), REG_EPAREN, subre::right, SEE, subre(), and UP.

Referenced by _outPlannerInfo(), choose_hashed_distinct(), choose_hashed_grouping(), convert_ANY_sublink_to_join(), convert_EXISTS_sublink_to_join(), expand_inherited_rtentry(), flatten_simple_union_all(), grouping_planner(), inheritance_planner(), make_subplanTargetList(), make_windowInputTargetList(), optimize_minmax_aggregates(), parseqatom(), pg_regcomp(), plan_set_operations(), preprocess_groupclause(), preprocess_limit(), preprocess_minmax_aggregates(), preprocess_rowmarks(), preprocess_targetlist(), pull_up_simple_subquery(), query_planner(), set_subquery_pathlist(), and standard_qp_callback().

{
    struct state *left;         /* scaffolding for branch */
    struct state *right;
    struct subre *branches;     /* top level */
    struct subre *branch;       /* current branch */
    struct subre *t;            /* temporary */
    int         firstbranch;    /* is this the first branch? */

    assert(stopper == ')' || stopper == EOS);

    branches = subre(v, '|', LONGER, init, final);
    NOERRN();
    branch = branches;
    firstbranch = 1;
    do
    {                           /* a branch */
        if (!firstbranch)
        {
            /* need a place to hang it */
            branch->right = subre(v, '|', LONGER, init, final);
            NOERRN();
            branch = branch->right;
        }
        firstbranch = 0;
        left = newstate(v->nfa);
        right = newstate(v->nfa);
        NOERRN();
        EMPTYARC(init, left);
        EMPTYARC(right, final);
        NOERRN();
        branch->left = parsebranch(v, stopper, type, left, right, 0);
        NOERRN();
        branch->flags |= UP(branch->flags | branch->left->flags);
        if ((branch->flags & ~branches->flags) != 0)    /* new flags */
            for (t = branches; t != branch; t = t->right)
                t->flags |= branch->flags;
    } while (EAT('|'));
    assert(SEE(stopper) || SEE(EOS));

    if (!SEE(stopper))
    {
        assert(stopper == ')' && SEE(EOS));
        ERR(REG_EPAREN);
    }

    /* optimize out simple cases */
    if (branch == branches)
    {                           /* only one branch */
        assert(branch->right == NULL);
        t = branch->left;
        branch->left = NULL;
        freesubre(v, branches);
        branches = t;
    }
    else if (!MESSY(branches->flags))
    {                           /* no interesting innards */
        freesubre(v, branches->left);
        branches->left = NULL;
        freesubre(v, branches->right);
        branches->right = NULL;
        branches->op = '=';
    }

    return branches;
}

static struct subre * parsebranch ( struct vars v,
int  stopper,
int  type,
struct state left,
struct state right,
int  partial 
) [static, read]

Definition at line 692 of file regcomp.c.

References assert, EMPTYARC, EOS, moveins(), newstate(), vars::nfa, NOERRN, NOTE, parseqatom(), REG_UUNSPEC, SEE, and subre().

Referenced by parse(), and parseqatom().

{
    struct state *lp;           /* left end of current construct */
    int         seencontent;    /* is there anything in this branch yet? */
    struct subre *t;

    lp = left;
    seencontent = 0;
    t = subre(v, '=', 0, left, right);  /* op '=' is tentative */
    NOERRN();
    while (!SEE('|') && !SEE(stopper) && !SEE(EOS))
    {
        if (seencontent)
        {                       /* implicit concat operator */
            lp = newstate(v->nfa);
            NOERRN();
            moveins(v->nfa, right, lp);
        }
        seencontent = 1;

        /* NB, recursion in parseqatom() may swallow rest of branch */
        parseqatom(v, stopper, type, lp, right, t);
        NOERRN();
    }

    if (!seencontent)
    {                           /* empty branch */
        if (!partial)
            NOTE(REG_UUNSPEC);
        assert(lp == left);
        EMPTYARC(left, right);
    }

    return t;
}

static void parseqatom ( struct vars v,
int  stopper,
int  type,
struct state lp,
struct state rp,
struct subre top 
) [static]

Definition at line 741 of file regcomp.c.

References AHEAD, ARCV, assert, BACKR, BACKREF, subre::begin, BEHIND, bracket(), CAP, cbracket(), vars::cflags, vars::cm, COLORLESS, COMBINE, delsub(), DIGIT, dupnfa(), EAT, EMPTYARC, subre::end, EOS, ERR, subre::flags, freesubre(), INFINITY, INSIST, ISERR, LACON, subre::left, LONGER, subre::max, MESSY, subre::min, moresubs(), moveins(), moveouts(), newlacon(), newstate(), NEXT, vars::nexttype, vars::nextvalue, vars::nfa, state::nins, vars::nlcolor, NOERR, nonword(), NOTE, state::nouts, vars::nsubexp, vars::nsubs, NULL, NWBDRY, okcolors(), onechr(), subre::op, parse(), parsebranch(), PLAIN, PREF, rainbow(), REG_ADVANCED, REG_ASSERT, REG_BADBR, REG_BADRPT, REG_EPAREN, REG_ESUBREG, REG_EXTENDED, REG_NLANCH, REG_NLSTOP, REG_UPBOTCH, repeat(), subre::right, s2, SBEGIN, scannum(), SEE, SEND, SHORTER, subre::subno, subre(), vars::subs, UP, WBDRY, word(), and wordchrs().

Referenced by parsebranch().

{
    struct state *s;            /* temporaries for new states */
    struct state *s2;

#define  ARCV(t, val)    newarc(v->nfa, t, val, lp, rp)
    int         m,
                n;
    struct subre *atom;         /* atom's subtree */
    struct subre *t;
    int         cap;            /* capturing parens? */
    int         pos;            /* positive lookahead? */
    int         subno;          /* capturing-parens or backref number */
    int         atomtype;
    int         qprefer;        /* quantifier short/long preference */
    int         f;
    struct subre **atomp;       /* where the pointer to atom is */

    /* initial bookkeeping */
    atom = NULL;
    assert(lp->nouts == 0);     /* must string new code */
    assert(rp->nins == 0);      /* between lp and rp */
    subno = 0;                  /* just to shut lint up */

    /* an atom or constraint... */
    atomtype = v->nexttype;
    switch (atomtype)
    {
            /* first, constraints, which end by returning */
        case '^':
            ARCV('^', 1);
            if (v->cflags & REG_NLANCH)
                ARCV(BEHIND, v->nlcolor);
            NEXT();
            return;
            break;
        case '$':
            ARCV('$', 1);
            if (v->cflags & REG_NLANCH)
                ARCV(AHEAD, v->nlcolor);
            NEXT();
            return;
            break;
        case SBEGIN:
            ARCV('^', 1);       /* BOL */
            ARCV('^', 0);       /* or BOS */
            NEXT();
            return;
            break;
        case SEND:
            ARCV('$', 1);       /* EOL */
            ARCV('$', 0);       /* or EOS */
            NEXT();
            return;
            break;
        case '<':
            wordchrs(v);        /* does NEXT() */
            s = newstate(v->nfa);
            NOERR();
            nonword(v, BEHIND, lp, s);
            word(v, AHEAD, s, rp);
            return;
            break;
        case '>':
            wordchrs(v);        /* does NEXT() */
            s = newstate(v->nfa);
            NOERR();
            word(v, BEHIND, lp, s);
            nonword(v, AHEAD, s, rp);
            return;
            break;
        case WBDRY:
            wordchrs(v);        /* does NEXT() */
            s = newstate(v->nfa);
            NOERR();
            nonword(v, BEHIND, lp, s);
            word(v, AHEAD, s, rp);
            s = newstate(v->nfa);
            NOERR();
            word(v, BEHIND, lp, s);
            nonword(v, AHEAD, s, rp);
            return;
            break;
        case NWBDRY:
            wordchrs(v);        /* does NEXT() */
            s = newstate(v->nfa);
            NOERR();
            word(v, BEHIND, lp, s);
            word(v, AHEAD, s, rp);
            s = newstate(v->nfa);
            NOERR();
            nonword(v, BEHIND, lp, s);
            nonword(v, AHEAD, s, rp);
            return;
            break;
        case LACON:             /* lookahead constraint */
            pos = v->nextvalue;
            NEXT();
            s = newstate(v->nfa);
            s2 = newstate(v->nfa);
            NOERR();
            t = parse(v, ')', LACON, s, s2);
            freesubre(v, t);    /* internal structure irrelevant */
            assert(SEE(')') || ISERR());
            NEXT();
            n = newlacon(v, s, s2, pos);
            NOERR();
            ARCV(LACON, n);
            return;
            break;
            /* then errors, to get them out of the way */
        case '*':
        case '+':
        case '?':
        case '{':
            ERR(REG_BADRPT);
            return;
            break;
        default:
            ERR(REG_ASSERT);
            return;
            break;
            /* then plain characters, and minor variants on that theme */
        case ')':               /* unbalanced paren */
            if ((v->cflags & REG_ADVANCED) != REG_EXTENDED)
            {
                ERR(REG_EPAREN);
                return;
            }
            /* legal in EREs due to specification botch */
            NOTE(REG_UPBOTCH);
            /* fallthrough into case PLAIN */
        case PLAIN:
            onechr(v, v->nextvalue, lp, rp);
            okcolors(v->nfa, v->cm);
            NOERR();
            NEXT();
            break;
        case '[':
            if (v->nextvalue == 1)
                bracket(v, lp, rp);
            else
                cbracket(v, lp, rp);
            assert(SEE(']') || ISERR());
            NEXT();
            break;
        case '.':
            rainbow(v->nfa, v->cm, PLAIN,
                    (v->cflags & REG_NLSTOP) ? v->nlcolor : COLORLESS,
                    lp, rp);
            NEXT();
            break;
            /* and finally the ugly stuff */
        case '(':               /* value flags as capturing or non */
            cap = (type == LACON) ? 0 : v->nextvalue;
            if (cap)
            {
                v->nsubexp++;
                subno = v->nsubexp;
                if ((size_t) subno >= v->nsubs)
                    moresubs(v, subno);
                assert((size_t) subno < v->nsubs);
            }
            else
                atomtype = PLAIN;       /* something that's not '(' */
            NEXT();
            /* need new endpoints because tree will contain pointers */
            s = newstate(v->nfa);
            s2 = newstate(v->nfa);
            NOERR();
            EMPTYARC(lp, s);
            EMPTYARC(s2, rp);
            NOERR();
            atom = parse(v, ')', PLAIN, s, s2);
            assert(SEE(')') || ISERR());
            NEXT();
            NOERR();
            if (cap)
            {
                v->subs[subno] = atom;
                t = subre(v, '(', atom->flags | CAP, lp, rp);
                NOERR();
                t->subno = subno;
                t->left = atom;
                atom = t;
            }
            /* postpone everything else pending possible {0} */
            break;
        case BACKREF:           /* the Feature From The Black Lagoon */
            INSIST(type != LACON, REG_ESUBREG);
            INSIST(v->nextvalue < v->nsubs, REG_ESUBREG);
            INSIST(v->subs[v->nextvalue] != NULL, REG_ESUBREG);
            NOERR();
            assert(v->nextvalue > 0);
            atom = subre(v, 'b', BACKR, lp, rp);
            subno = v->nextvalue;
            atom->subno = subno;
            EMPTYARC(lp, rp);   /* temporarily, so there's something */
            NEXT();
            break;
    }

    /* ...and an atom may be followed by a quantifier */
    switch (v->nexttype)
    {
        case '*':
            m = 0;
            n = INFINITY;
            qprefer = (v->nextvalue) ? LONGER : SHORTER;
            NEXT();
            break;
        case '+':
            m = 1;
            n = INFINITY;
            qprefer = (v->nextvalue) ? LONGER : SHORTER;
            NEXT();
            break;
        case '?':
            m = 0;
            n = 1;
            qprefer = (v->nextvalue) ? LONGER : SHORTER;
            NEXT();
            break;
        case '{':
            NEXT();
            m = scannum(v);
            if (EAT(','))
            {
                if (SEE(DIGIT))
                    n = scannum(v);
                else
                    n = INFINITY;
                if (m > n)
                {
                    ERR(REG_BADBR);
                    return;
                }
                /* {m,n} exercises preference, even if it's {m,m} */
                qprefer = (v->nextvalue) ? LONGER : SHORTER;
            }
            else
            {
                n = m;
                /* {m} passes operand's preference through */
                qprefer = 0;
            }
            if (!SEE('}'))
            {                   /* catches errors too */
                ERR(REG_BADBR);
                return;
            }
            NEXT();
            break;
        default:                /* no quantifier */
            m = n = 1;
            qprefer = 0;
            break;
    }

    /* annoying special case:  {0} or {0,0} cancels everything */
    if (m == 0 && n == 0)
    {
        if (atom != NULL)
            freesubre(v, atom);
        if (atomtype == '(')
            v->subs[subno] = NULL;
        delsub(v->nfa, lp, rp);
        EMPTYARC(lp, rp);
        return;
    }

    /* if not a messy case, avoid hard part */
    assert(!MESSY(top->flags));
    f = top->flags | qprefer | ((atom != NULL) ? atom->flags : 0);
    if (atomtype != '(' && atomtype != BACKREF && !MESSY(UP(f)))
    {
        if (!(m == 1 && n == 1))
            repeat(v, lp, rp, m, n);
        if (atom != NULL)
            freesubre(v, atom);
        top->flags = f;
        return;
    }

    /*
     * hard part:  something messy
     *
     * That is, capturing parens, back reference, short/long clash, or an atom
     * with substructure containing one of those.
     */

    /* now we'll need a subre for the contents even if they're boring */
    if (atom == NULL)
    {
        atom = subre(v, '=', 0, lp, rp);
        NOERR();
    }

    /*----------
     * Prepare a general-purpose state skeleton.
     *
     * In the no-backrefs case, we want this:
     *
     * [lp] ---> [s] ---prefix---> [begin] ---atom---> [end] ---rest---> [rp]
     *
     * where prefix is some repetitions of atom.  In the general case we need
     *
     * [lp] ---> [s] ---iterator---> [s2] ---rest---> [rp]
     *
     * where the iterator wraps around [begin] ---atom---> [end]
     *
     * We make the s state here for both cases; s2 is made below if needed
     *----------
     */
    s = newstate(v->nfa);       /* first, new endpoints for the atom */
    s2 = newstate(v->nfa);
    NOERR();
    moveouts(v->nfa, lp, s);
    moveins(v->nfa, rp, s2);
    NOERR();
    atom->begin = s;
    atom->end = s2;
    s = newstate(v->nfa);       /* set up starting state */
    NOERR();
    EMPTYARC(lp, s);
    NOERR();

    /* break remaining subRE into x{...} and what follows */
    t = subre(v, '.', COMBINE(qprefer, atom->flags), lp, rp);
    t->left = atom;
    atomp = &t->left;

    /* here we should recurse... but we must postpone that to the end */

    /* split top into prefix and remaining */
    assert(top->op == '=' && top->left == NULL && top->right == NULL);
    top->left = subre(v, '=', top->flags, top->begin, lp);
    top->op = '.';
    top->right = t;

    /* if it's a backref, now is the time to replicate the subNFA */
    if (atomtype == BACKREF)
    {
        assert(atom->begin->nouts == 1);        /* just the EMPTY */
        delsub(v->nfa, atom->begin, atom->end);
        assert(v->subs[subno] != NULL);

        /*
         * And here's why the recursion got postponed: it must wait until the
         * skeleton is filled in, because it may hit a backref that wants to
         * copy the filled-in skeleton.
         */
        dupnfa(v->nfa, v->subs[subno]->begin, v->subs[subno]->end,
               atom->begin, atom->end);
        NOERR();
    }

    /*
     * It's quantifier time.  If the atom is just a backref, we'll let it deal
     * with quantifiers internally.
     */
    if (atomtype == BACKREF)
    {
        /* special case:  backrefs have internal quantifiers */
        EMPTYARC(s, atom->begin);       /* empty prefix */
        /* just stuff everything into atom */
        repeat(v, atom->begin, atom->end, m, n);
        atom->min = (short) m;
        atom->max = (short) n;
        atom->flags |= COMBINE(qprefer, atom->flags);
        /* rest of branch can be strung starting from atom->end */
        s2 = atom->end;
    }
    else if (m == 1 && n == 1)
    {
        /* no/vacuous quantifier:  done */
        EMPTYARC(s, atom->begin);       /* empty prefix */
        /* rest of branch can be strung starting from atom->end */
        s2 = atom->end;
    }
    else if (m > 0 && !(atom->flags & BACKR))
    {
        /*
         * If there's no backrefs involved, we can turn x{m,n} into
         * x{m-1,n-1}x, with capturing parens in only the second x.  This is
         * valid because we only care about capturing matches from the final
         * iteration of the quantifier.  It's a win because we can implement
         * the backref-free left side as a plain DFA node, since we don't
         * really care where its submatches are.
         */
        dupnfa(v->nfa, atom->begin, atom->end, s, atom->begin);
        assert(m >= 1 && m != INFINITY && n >= 1);
        repeat(v, s, atom->begin, m - 1, (n == INFINITY) ? n : n - 1);
        f = COMBINE(qprefer, atom->flags);
        t = subre(v, '.', f, s, atom->end);     /* prefix and atom */
        NOERR();
        t->left = subre(v, '=', PREF(f), s, atom->begin);
        NOERR();
        t->right = atom;
        *atomp = t;
        /* rest of branch can be strung starting from atom->end */
        s2 = atom->end;
    }
    else
    {
        /* general case: need an iteration node */
        s2 = newstate(v->nfa);
        NOERR();
        moveouts(v->nfa, atom->end, s2);
        NOERR();
        dupnfa(v->nfa, atom->begin, atom->end, s, s2);
        repeat(v, s, s2, m, n);
        f = COMBINE(qprefer, atom->flags);
        t = subre(v, '*', f, s, s2);
        NOERR();
        t->min = (short) m;
        t->max = (short) n;
        t->left = atom;
        *atomp = t;
        /* rest of branch is to be strung from iteration's end state */
    }

    /* and finally, look after that postponed recursion */
    t = top->right;
    if (!(SEE('|') || SEE(stopper) || SEE(EOS)))
        t->right = parsebranch(v, stopper, type, s2, rp, 1);
    else
    {
        EMPTYARC(s2, rp);
        t->right = subre(v, '=', 0, s2, rp);
    }
    NOERR();
    assert(SEE('|') || SEE(stopper) || SEE(EOS));
    t->flags |= COMBINE(t->flags, t->right->flags);
    top->flags |= COMBINE(top->flags, t->flags);
}

int pg_regcomp ( regex_t re,
const chr string,
size_t  len,
int  flags,
Oid  collation 
)

Definition at line 290 of file regcomp.c.

References assert, casecmp(), guts::cflags, vars::cflags, cleanst(), vars::cm, guts::cmap, cmp(), CNOERR, COLORLESS, compact(), vars::cv, vars::cv2, debug, dumpnfa(), EOS, vars::err, nfa::final, subre::flags, freev(), i, guts::info, nfa::init, initcm(), guts::lacons, vars::lacons, lexstart(), guts::magic, makesearch(), MALLOC, markst(), newcvec(), newline(), newnfa(), vars::nfa, nfanode(), nfatree(), guts::nlacons, vars::nlacons, vars::nlcolor, NOTE, vars::now, guts::nsub, vars::nsubexp, vars::nsubs, guts::ntree, vars::ntree, NULL, numst(), okcolors(), optimize(), optst(), parse(), pg_set_regex_collation(), PLAIN, vars::re, regex_t::re_collation, regex_t::re_csize, regex_t::re_fns, regex_t::re_guts, regex_t::re_info, regex_t::re_magic, regex_t::re_nsub, REG_ADVANCED, REG_DUMP, REG_ESPACE, REG_EXPANDED, REG_EXTENDED, REG_INVARG, REG_NLANCH, REG_NLSTOP, REG_QUOTE, REG_USHORTEST, REMAGIC, vars::savenow, vars::savestop, guts::search, SEE, SHORTER, specialcolors(), vars::stop, vars::sub10, subcolor(), vars::subs, guts::tree, vars::tree, vars::treechain, vars::treefree, VS, vars::wordchrs, and ZAPCNFA.

Referenced by NIAddAffix(), parse_ident_line(), RE_compile(), and RE_compile_and_cache().

{
    struct vars var;
    struct vars *v = &var;
    struct guts *g;
    int         i;
    size_t      j;

#ifdef REG_DEBUG
    FILE       *debug = (flags & REG_PROGRESS) ? stdout : (FILE *) NULL;
#else
    FILE       *debug = (FILE *) NULL;
#endif

#define  CNOERR()    { if (ISERR()) return freev(v, v->err); }

    /* sanity checks */

    if (re == NULL || string == NULL)
        return REG_INVARG;
    if ((flags & REG_QUOTE) &&
        (flags & (REG_ADVANCED | REG_EXPANDED | REG_NEWLINE)))
        return REG_INVARG;
    if (!(flags & REG_EXTENDED) && (flags & REG_ADVF))
        return REG_INVARG;

    /* Initialize locale-dependent support */
    pg_set_regex_collation(collation);

    /* initial setup (after which freev() is callable) */
    v->re = re;
    v->now = string;
    v->stop = v->now + len;
    v->savenow = v->savestop = NULL;
    v->err = 0;
    v->cflags = flags;
    v->nsubexp = 0;
    v->subs = v->sub10;
    v->nsubs = 10;
    for (j = 0; j < v->nsubs; j++)
        v->subs[j] = NULL;
    v->nfa = NULL;
    v->cm = NULL;
    v->nlcolor = COLORLESS;
    v->wordchrs = NULL;
    v->tree = NULL;
    v->treechain = NULL;
    v->treefree = NULL;
    v->cv = NULL;
    v->cv2 = NULL;
    v->lacons = NULL;
    v->nlacons = 0;
    re->re_magic = REMAGIC;
    re->re_info = 0;            /* bits get set during parse */
    re->re_csize = sizeof(chr);
    re->re_collation = collation;
    re->re_guts = NULL;
    re->re_fns = VS(&functions);

    /* more complex setup, malloced things */
    re->re_guts = VS(MALLOC(sizeof(struct guts)));
    if (re->re_guts == NULL)
        return freev(v, REG_ESPACE);
    g = (struct guts *) re->re_guts;
    g->tree = NULL;
    initcm(v, &g->cmap);
    v->cm = &g->cmap;
    g->lacons = NULL;
    g->nlacons = 0;
    ZAPCNFA(g->search);
    v->nfa = newnfa(v, v->cm, (struct nfa *) NULL);
    CNOERR();
    /* set up a reasonably-sized transient cvec for getcvec usage */
    v->cv = newcvec(100, 20);
    if (v->cv == NULL)
        return freev(v, REG_ESPACE);

    /* parsing */
    lexstart(v);                /* also handles prefixes */
    if ((v->cflags & REG_NLSTOP) || (v->cflags & REG_NLANCH))
    {
        /* assign newline a unique color */
        v->nlcolor = subcolor(v->cm, newline());
        okcolors(v->nfa, v->cm);
    }
    CNOERR();
    v->tree = parse(v, EOS, PLAIN, v->nfa->init, v->nfa->final);
    assert(SEE(EOS));           /* even if error; ISERR() => SEE(EOS) */
    CNOERR();
    assert(v->tree != NULL);

    /* finish setup of nfa and its subre tree */
    specialcolors(v->nfa);
    CNOERR();
#ifdef REG_DEBUG
    if (debug != NULL)
    {
        fprintf(debug, "\n\n\n========= RAW ==========\n");
        dumpnfa(v->nfa, debug);
        dumpst(v->tree, debug, 1);
    }
#endif
    optst(v, v->tree);
    v->ntree = numst(v->tree, 1);
    markst(v->tree);
    cleanst(v);
#ifdef REG_DEBUG
    if (debug != NULL)
    {
        fprintf(debug, "\n\n\n========= TREE FIXED ==========\n");
        dumpst(v->tree, debug, 1);
    }
#endif

    /* build compacted NFAs for tree and lacons */
    re->re_info |= nfatree(v, v->tree, debug);
    CNOERR();
    assert(v->nlacons == 0 || v->lacons != NULL);
    for (i = 1; i < v->nlacons; i++)
    {
#ifdef REG_DEBUG
        if (debug != NULL)
            fprintf(debug, "\n\n\n========= LA%d ==========\n", i);
#endif
        nfanode(v, &v->lacons[i], debug);
    }
    CNOERR();
    if (v->tree->flags & SHORTER)
        NOTE(REG_USHORTEST);

    /* build compacted NFAs for tree, lacons, fast search */
#ifdef REG_DEBUG
    if (debug != NULL)
        fprintf(debug, "\n\n\n========= SEARCH ==========\n");
#endif
    /* can sacrifice main NFA now, so use it as work area */
    (DISCARD) optimize(v->nfa, debug);
    CNOERR();
    makesearch(v, v->nfa);
    CNOERR();
    compact(v->nfa, &g->search);
    CNOERR();

    /* looks okay, package it up */
    re->re_nsub = v->nsubexp;
    v->re = NULL;               /* freev no longer frees re */
    g->magic = GUTSMAGIC;
    g->cflags = v->cflags;
    g->info = re->re_info;
    g->nsub = re->re_nsub;
    g->tree = v->tree;
    v->tree = NULL;
    g->ntree = v->ntree;
    g->compare = (v->cflags & REG_ICASE) ? casecmp : cmp;
    g->lacons = v->lacons;
    v->lacons = NULL;
    g->nlacons = v->nlacons;

#ifdef REG_DEBUG
    if (flags & REG_DUMP)
        dump(re, stdout);
#endif

    assert(v->err == 0);
    return freev(v, 0);
}

static int pg_wc_isalnum ( pg_wchar  c  )  [static]
static int pg_wc_isalpha ( pg_wchar  c  )  [static]
static int pg_wc_isdigit ( pg_wchar  c  )  [static]
static int pg_wc_isgraph ( pg_wchar  c  )  [static]
static int pg_wc_islower ( pg_wchar  c  )  [static]
static int pg_wc_isprint ( pg_wchar  c  )  [static]
static int pg_wc_ispunct ( pg_wchar  c  )  [static]
static int pg_wc_isspace ( pg_wchar  c  )  [static]
static int pg_wc_isupper ( pg_wchar  c  )  [static]
static pg_wchar pg_wc_tolower ( pg_wchar  c  )  [static]
static pg_wchar pg_wc_toupper ( pg_wchar  c  )  [static]
static void prefixes ( struct vars  )  [static]
static color pseudocolor ( struct colormap  )  [static]
static int pull ( struct nfa ,
struct arc  
) [static]
static void pullback ( struct nfa ,
FILE *   
) [static]
static int push ( struct nfa ,
struct arc  
) [static]
static void pushfwd ( struct nfa ,
FILE *   
) [static]
static void rainbow ( struct nfa ,
struct colormap ,
int  ,
pcolor  ,
struct state ,
struct state  
) [static]

Referenced by makesearch(), and parseqatom().

static struct cvec* range ( struct vars ,
celt  ,
celt  ,
int   
) [static, read]

Referenced by brackpart().

static void repeat ( struct vars v,
struct state lp,
struct state rp,
int  m,
int  n 
) [static]

Definition at line 1250 of file regcomp.c.

References delsub(), dupnfa(), EMPTYARC, ERR, INF, moveins(), moveouts(), newstate(), vars::nfa, NOERR, PAIR, REDUCE, REG_ASSERT, s2, and SOME.

Referenced by parseqatom().

{
#define  SOME    2
#define  INF     3
#define  PAIR(x, y)  ((x)*4 + (y))
#define  REDUCE(x)   ( ((x) == INFINITY) ? INF : (((x) > 1) ? SOME : (x)) )
    const int   rm = REDUCE(m);
    const int   rn = REDUCE(n);
    struct state *s;
    struct state *s2;

    switch (PAIR(rm, rn))
    {
        case PAIR(0, 0):        /* empty string */
            delsub(v->nfa, lp, rp);
            EMPTYARC(lp, rp);
            break;
        case PAIR(0, 1):        /* do as x| */
            EMPTYARC(lp, rp);
            break;
        case PAIR(0, SOME):     /* do as x{1,n}| */
            repeat(v, lp, rp, 1, n);
            NOERR();
            EMPTYARC(lp, rp);
            break;
        case PAIR(0, INF):      /* loop x around */
            s = newstate(v->nfa);
            NOERR();
            moveouts(v->nfa, lp, s);
            moveins(v->nfa, rp, s);
            EMPTYARC(lp, s);
            EMPTYARC(s, rp);
            break;
        case PAIR(1, 1):        /* no action required */
            break;
        case PAIR(1, SOME):     /* do as x{0,n-1}x = (x{1,n-1}|)x */
            s = newstate(v->nfa);
            NOERR();
            moveouts(v->nfa, lp, s);
            dupnfa(v->nfa, s, rp, lp, s);
            NOERR();
            repeat(v, lp, s, 1, n - 1);
            NOERR();
            EMPTYARC(lp, s);
            break;
        case PAIR(1, INF):      /* add loopback arc */
            s = newstate(v->nfa);
            s2 = newstate(v->nfa);
            NOERR();
            moveouts(v->nfa, lp, s);
            moveins(v->nfa, rp, s2);
            EMPTYARC(lp, s);
            EMPTYARC(s2, rp);
            EMPTYARC(s2, s);
            break;
        case PAIR(SOME, SOME):  /* do as x{m-1,n-1}x */
            s = newstate(v->nfa);
            NOERR();
            moveouts(v->nfa, lp, s);
            dupnfa(v->nfa, s, rp, lp, s);
            NOERR();
            repeat(v, lp, s, m - 1, n - 1);
            break;
        case PAIR(SOME, INF):   /* do as x{m-1,}x */
            s = newstate(v->nfa);
            NOERR();
            moveouts(v->nfa, lp, s);
            dupnfa(v->nfa, s, rp, lp, s);
            NOERR();
            repeat(v, lp, s, m - 1, n);
            break;
        default:
            ERR(REG_ASSERT);
            break;
    }
}

static void replaceempty ( struct nfa ,
struct state ,
struct state  
) [static]
static void rfree ( regex_t re  )  [static]

Definition at line 1871 of file regcomp.c.

References guts::cmap, FREE, freecm(), freecnfa(), freelacons(), freesubre(), guts::lacons, guts::magic, guts::nlacons, NULL, NULLCNFA, regex_t::re_fns, regex_t::re_guts, regex_t::re_magic, REMAGIC, guts::search, and guts::tree.

Referenced by freev().

{
    struct guts *g;

    if (re == NULL || re->re_magic != REMAGIC)
        return;

    re->re_magic = 0;           /* invalidate RE */
    g = (struct guts *) re->re_guts;
    re->re_guts = NULL;
    re->re_fns = NULL;
    if (g != NULL)
    {
        g->magic = 0;
        freecm(&g->cmap);
        if (g->tree != NULL)
            freesubre((struct vars *) NULL, g->tree);
        if (g->lacons != NULL)
            freelacons(g->lacons, g->nlacons);
        if (!NULLCNFA(g->search))
            freecnfa(&g->search);
        FREE(g);
    }
}

static int scannum ( struct vars v  )  [static]

Definition at line 1219 of file regcomp.c.

References DIGIT, DUPMAX, ERR, NEXT, vars::nextvalue, REG_BADBR, and SEE.

Referenced by parseqatom().

{
    int         n = 0;

    while (SEE(DIGIT) && n < DUPMAX)
    {
        n = n * 10 + v->nextvalue;
        NEXT();
    }
    if (SEE(DIGIT) || n > DUPMAX)
    {
        ERR(REG_BADBR);
        return 0;
    }
    return n;
}

static const chr * scanplain ( struct vars v  )  [static]

Definition at line 1498 of file regcomp.c.

References assert, CCLASS, COLLEL, ECLASS, END, ISERR, NEXT, vars::now, PLAIN, and SEE.

Referenced by brackpart().

{
    const chr  *endp;

    assert(SEE(COLLEL) || SEE(ECLASS) || SEE(CCLASS));
    NEXT();

    endp = v->now;
    while (SEE(PLAIN))
    {
        endp = v->now;
        NEXT();
    }

    assert(SEE(END) || ISERR());
    NEXT();

    return endp;
}

static color setcolor ( struct colormap ,
chr  ,
pcolor   
) [static]
static void skip ( struct vars  )  [static]
static void specialcolors ( struct nfa  )  [static]

Referenced by nfanode(), and pg_regcomp().

static void subblock ( struct vars ,
chr  ,
struct state ,
struct state  
) [static]
static color subcolor ( struct colormap ,
chr  c 
) [static]

Referenced by dovec(), onechr(), and pg_regcomp().

static void subrange ( struct vars ,
chr  ,
chr  ,
struct state ,
struct state  
) [static]

Referenced by dovec().

static struct subre * subre ( struct vars v,
int  op,
int  flags,
struct state begin,
struct state end 
) [static, read]

Definition at line 1609 of file regcomp.c.

References assert, subre::begin, subre::chain, subre::cnfa, subre::end, ERR, subre::flags, subre::id, subre::left, MALLOC, subre::max, subre::min, NULL, subre::op, REG_ESPACE, subre::right, subre::subno, vars::treechain, vars::treefree, and ZAPCNFA.

Referenced by parse(), parsebranch(), and parseqatom().

{
    struct subre *ret = v->treefree;

    if (ret != NULL)
        v->treefree = ret->left;
    else
    {
        ret = (struct subre *) MALLOC(sizeof(struct subre));
        if (ret == NULL)
        {
            ERR(REG_ESPACE);
            return NULL;
        }
        ret->chain = v->treechain;
        v->treechain = ret;
    }

    assert(strchr("=b|.*(", op) != NULL);

    ret->op = op;
    ret->flags = flags;
    ret->id = 0;                /* will be assigned later */
    ret->subno = 0;
    ret->min = ret->max = 1;
    ret->left = NULL;
    ret->right = NULL;
    ret->begin = begin;
    ret->end = end;
    ZAPCNFA(ret->cnfa);

    return ret;
}

static void uncolorchain ( struct colormap ,
struct arc  
) [static]
static void word ( struct vars v,
int  dir,
struct state lp,
struct state rp 
) [static]

Definition at line 1205 of file regcomp.c.

References AHEAD, assert, BEHIND, cloneouts(), vars::nfa, and vars::wordchrs.

Referenced by cmpspell(), compareWORD(), parseqatom(), and ScanKeywordLookup().

{
    assert(dir == AHEAD || dir == BEHIND);
    cloneouts(v->nfa, v->wordchrs, lp, rp, dir);
    /* (no need for special attention to \n) */
}

static void wordchrs ( struct vars v  )  [static]

Definition at line 1580 of file regcomp.c.

References assert, bracket(), ISERR, lexword(), newstate(), NEXT, vars::nfa, NOERR, NULL, vars::savenow, SEE, and vars::wordchrs.

Referenced by parseqatom().

{
    struct state *left;
    struct state *right;

    if (v->wordchrs != NULL)
    {
        NEXT();                 /* for consistency */
        return;
    }

    left = newstate(v->nfa);
    right = newstate(v->nfa);
    NOERR();
    /* fine point:  implemented with [::], and lexer will set REG_ULOCALE */
    lexword(v);
    NEXT();
    assert(v->savenow != NULL && SEE('['));
    bracket(v, left, right);
    assert((v->savenow != NULL && SEE(']')) || ISERR());
    NEXT();
    NOERR();
    v->wordchrs = left;
}


Variable Documentation

struct fns functions [static]
Initial value:
 {
    rfree,                      
}

Definition at line 277 of file regcomp.c.