It could be possible for the case-insensitive
[p5sagit/p5-mst-13.2.git] / regexec.c
index eef5f59..4b073d2 100644 (file)
--- a/regexec.c
+++ b/regexec.c
 #  define Perl_re_intuit_start my_re_intuit_start
 /* *These* symbols are masked to allow static link. */
 #  define Perl_pregexec my_pregexec
-#  define Perl_reginitcolors my_reginitcolors 
+#  define Perl_reginitcolors my_reginitcolors
 #  define Perl_regclass_swash my_regclass_swash
 
 #  define PERL_NO_GET_CONTEXT
-#endif 
+#endif
 
 /*SUPPRESS 112*/
 /*
 #define PERL_IN_REGEXEC_C
 #include "perl.h"
 
-#ifdef PERL_IN_XSUB_RE
-#  if defined(PERL_CAPI) || defined(PERL_OBJECT)
-#    include "XSUB.h"
-#  endif
-#endif
-
 #include "regcomp.h"
 
 #define RF_tainted     1               /* tainted information used? */
  */
 
 #define CHR_SVLEN(sv) (UTF ? sv_len_utf8(sv) : SvCUR(sv))
-#define CHR_DIST(a,b) (DO_UTF8(PL_reg_sv) ? utf8_distance(a,b) : a - b)
+#define CHR_DIST(a,b) (PL_reg_match_utf8 ? utf8_distance(a,b) : a - b)
 
 #define reghop_c(pos,off) ((char*)reghop((U8*)pos, off))
 #define reghopmaybe_c(pos,off) ((char*)reghopmaybe((U8*)pos, off))
-#define HOP(pos,off) (DO_UTF8(PL_reg_sv) ? reghop((U8*)pos, off) : (U8*)(pos + off))
-#define HOPMAYBE(pos,off) (DO_UTF8(PL_reg_sv) ? reghopmaybe((U8*)pos, off) : (U8*)(pos + off))
+#define HOP(pos,off) (PL_reg_match_utf8 ? reghop((U8*)pos, off) : (U8*)(pos + off))
+#define HOPMAYBE(pos,off) (PL_reg_match_utf8 ? reghopmaybe((U8*)pos, off) : (U8*)(pos + off))
 #define HOPc(pos,off) ((char*)HOP(pos,off))
 #define HOPMAYBEc(pos,off) ((char*)HOPMAYBE(pos,off))
 
+#define HOPBACK(pos, off) (            \
+    (UTF && PL_reg_match_utf8)         \
+       ? reghopmaybe((U8*)pos, -off)   \
+    : (pos - off >= PL_bostr)          \
+       ? (U8*)(pos - off)              \
+    : (U8*)NULL                                \
+)
+#define HOPBACKc(pos, off) (char*)HOPBACK(pos, off)
+
 #define reghop3_c(pos,off,lim) ((char*)reghop3((U8*)pos, off, (U8*)lim))
 #define reghopmaybe3_c(pos,off,lim) ((char*)reghopmaybe3((U8*)pos, off, (U8*)lim))
-#define HOP3(pos,off,lim) (DO_UTF8(PL_reg_sv) ? reghop3((U8*)pos, off, (U8*)lim) : (U8*)(pos + off))
-#define HOPMAYBE3(pos,off,lim) (DO_UTF8(PL_reg_sv) ? reghopmaybe3((U8*)pos, off, (U8*)lim) : (U8*)(pos + off))
+#define HOP3(pos,off,lim) (PL_reg_match_utf8 ? reghop3((U8*)pos, off, (U8*)lim) : (U8*)(pos + off))
+#define HOPMAYBE3(pos,off,lim) (PL_reg_match_utf8 ? reghopmaybe3((U8*)pos, off, (U8*)lim) : (U8*)(pos + off))
 #define HOP3c(pos,off,lim) ((char*)HOP3(pos,off,lim))
 #define HOPMAYBE3c(pos,off,lim) ((char*)HOPMAYBE3(pos,off,lim))
 
-static void restore_pos(pTHXo_ void *arg);
+#define LOAD_UTF8_CHARCLASS(a,b) STMT_START { if (!CAT2(PL_utf8_,a)) (void)CAT2(is_utf8_, a)((U8*)b); } STMT_END
 
+/* for use after a quantifier and before an EXACT-like node -- japhy */
+#define JUMPABLE(rn) ( \
+    OP(rn) == OPEN || OP(rn) == CLOSE || OP(rn) == EVAL || \
+    OP(rn) == SUSPEND || OP(rn) == IFMATCH || \
+    OP(rn) == PLUS || OP(rn) == MINMOD || \
+    (PL_regkind[(U8)OP(rn)] == CURLY && ARG1(rn) > 0) \
+)
+
+#define HAS_TEXT(rn) ( \
+    PL_regkind[(U8)OP(rn)] == EXACT || PL_regkind[(U8)OP(rn)] == REF \
+)
+
+#define FIND_NEXT_IMPT(rn) STMT_START { \
+    while (JUMPABLE(rn)) \
+       if (OP(rn) == SUSPEND || OP(rn) == IFMATCH || \
+           PL_regkind[(U8)OP(rn)] == CURLY) \
+           rn = NEXTOPER(NEXTOPER(rn)); \
+       else if (OP(rn) == PLUS) \
+           rn = NEXTOPER(rn); \
+       else rn += NEXT_OFF(rn); \
+} STMT_END 
+
+static void restore_pos(pTHX_ void *arg);
 
 STATIC CHECKPOINT
 S_regcppush(pTHX_ I32 parenfloor)
@@ -134,7 +160,10 @@ S_regcppush(pTHX_ I32 parenfloor)
     int paren_elems_to_push = (PL_regsize - parenfloor) * REGCP_PAREN_ELEMS;
     int p;
 
-#define REGCP_OTHER_ELEMS 5
+    if (paren_elems_to_push < 0)
+       Perl_croak(aTHX_ "panic: paren_elems_to_push < 0");
+
+#define REGCP_OTHER_ELEMS 6
     SSCHECK(paren_elems_to_push + REGCP_OTHER_ELEMS);
     for (p = PL_regsize; p > parenfloor; p--) {
 /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
@@ -146,9 +175,14 @@ S_regcppush(pTHX_ I32 parenfloor)
 /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
     SSPUSHINT(PL_regsize);
     SSPUSHINT(*PL_reglastparen);
+    SSPUSHINT(*PL_reglastcloseparen);
     SSPUSHPTR(PL_reginput);
-    SSPUSHINT(paren_elems_to_push + (REGCP_PAREN_ELEMS - 1));
+#define REGCP_FRAME_ELEMS 2
+/* REGCP_FRAME_ELEMS are part of the REGCP_OTHER_ELEMS and
+ * are needed for the regexp context stack bookkeeping. */
+    SSPUSHINT(paren_elems_to_push + REGCP_OTHER_ELEMS - REGCP_FRAME_ELEMS);
     SSPUSHINT(SAVEt_REGCONTEXT); /* Magic cookie. */
+
     return retval;
 }
 
@@ -175,11 +209,13 @@ S_regcppop(pTHX)
     assert(i == SAVEt_REGCONTEXT); /* Check that the magic cookie is there. */
     i = SSPOPINT; /* Parentheses elements to pop. */
     input = (char *) SSPOPPTR;
+    *PL_reglastcloseparen = SSPOPINT;
     *PL_reglastparen = SSPOPINT;
     PL_regsize = SSPOPINT;
 
     /* Now restore the parentheses context. */
-    for (i -= (REGCP_PAREN_ELEMS - 1); i > 0; i -= REGCP_PAREN_ELEMS) {
+    for (i -= (REGCP_OTHER_ELEMS - REGCP_FRAME_ELEMS);
+        i > 0; i -= REGCP_PAREN_ELEMS) {
        paren = (U32)SSPOPINT;
        PL_reg_start_tmp[paren] = (char *) SSPOPPTR;
        PL_regstartp[paren] = SSPOPINT;
@@ -189,9 +225,9 @@ S_regcppop(pTHX)
        DEBUG_r(
            PerlIO_printf(Perl_debug_log,
                          "     restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n",
-                         (UV)paren, (IV)PL_regstartp[paren], 
+                         (UV)paren, (IV)PL_regstartp[paren],
                          (IV)(PL_reg_start_tmp[paren] - PL_bostr),
-                         (IV)PL_regendp[paren], 
+                         (IV)PL_regendp[paren],
                          (paren > *PL_reglastparen ? "(no)" : ""));
        );
     }
@@ -276,7 +312,7 @@ Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *stren
 /* nosave: For optimizations. */
 {
     return
-       regexec_flags(prog, stringarg, strend, strbeg, minend, screamer, NULL, 
+       regexec_flags(prog, stringarg, strend, strbeg, minend, screamer, NULL,
                      nosave ? 0 : REXEC_COPY_STR);
 }
 
@@ -288,11 +324,11 @@ S_cache_re(pTHX_ regexp *prog)
     PL_regprogram = prog->program;
 #endif
     PL_regnpar = prog->nparens;
-    PL_regdata = prog->data;    
-    PL_reg_re = prog;    
+    PL_regdata = prog->data;
+    PL_reg_re = prog;
 }
 
-/* 
+/*
  * Need to implement the following flags for reg_anch:
  *
  * USE_INTUIT_NOML             - Useful to call re_intuit_start() first
@@ -342,39 +378,45 @@ char *
 Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
                     char *strend, U32 flags, re_scream_pos_data *data)
 {
-    register I32 start_shift;
+    register I32 start_shift = 0;
     /* Should be nonnegative! */
-    register I32 end_shift;
+    register I32 end_shift   = 0;
     register char *s;
     register SV *check;
     char *strbeg;
     char *t;
     I32 ml_anch;
-    char *tmp;
     register char *other_last = Nullch;        /* other substr checked before this */
-    char *check_at;                    /* check substr found at this pos */
+    char *check_at = Nullch;           /* check substr found at this pos */
 #ifdef DEBUGGING
     char *i_strpos = strpos;
+    SV *dsv = PERL_DEBUG_PAD_ZERO(0);
 #endif
 
-    DEBUG_r( if (!PL_colorset) reginitcolors() );
-    DEBUG_r(PerlIO_printf(Perl_debug_log,
-                     "%sGuessing start of match, REx%s `%s%.60s%s%s' against `%s%.*s%s%s'...\n",
-                     PL_colors[4],PL_colors[5],PL_colors[0],
-                     prog->precomp,
-                     PL_colors[1],
-                     (strlen(prog->precomp) > 60 ? "..." : ""),
-                     PL_colors[0],
-                     (int)(strend - strpos > 60 ? 60 : strend - strpos),
-                     strpos, PL_colors[1],
-                     (strend - strpos > 60 ? "..." : ""))
-       );
+    DEBUG_r({
+        char*s   = UTF ? sv_uni_display(dsv, sv, 60, 0) : strpos;
+        int  len = UTF ? strlen(s) : strend - strpos;
+        if (!PL_colorset)
+             reginitcolors();
+        PerlIO_printf(Perl_debug_log,
+                      "%sGuessing start of match, REx%s `%s%.60s%s%s' against `%s%.*s%s%s'...\n",
+                      PL_colors[4],PL_colors[5],PL_colors[0],
+                      prog->precomp,
+                      PL_colors[1],
+                      (strlen(prog->precomp) > 60 ? "..." : ""),
+                      PL_colors[0],
+                      (int)(len > 60 ? 60 : len),
+                      s, PL_colors[1],
+                      (len > 60 ? "..." : "")
+             );
+    });
 
     if (prog->reganch & ROPT_UTF8)
        PL_reg_flags |= RF_utf8;
 
     if (prog->minlen > CHR_DIST((U8*)strend, (U8*)strpos)) {
-       DEBUG_r(PerlIO_printf(Perl_debug_log, "String too short...\n"));
+       DEBUG_r(PerlIO_printf(Perl_debug_log,
+                             "String too short... [re_intuit_start]\n"));
        goto fail;
     }
     strbeg = (sv && SvPOK(sv)) ? strend - SvCUR(sv) : strpos;
@@ -386,14 +428,16 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
                          && !PL_multiline ) ); /* Check after \n? */
 
        if (!ml_anch) {
-         if ( !(prog->reganch & ROPT_ANCH_GPOS) /* Checked by the caller */
+         if ( !(prog->reganch & (ROPT_ANCH_GPOS /* Checked by the caller */
+                                 | ROPT_IMPLICIT)) /* not a real BOL */
               /* SvCUR is not set on references: SvRV and SvPVX overlap */
               && sv && !SvROK(sv)
               && (strpos != strbeg)) {
              DEBUG_r(PerlIO_printf(Perl_debug_log, "Not at start...\n"));
              goto fail;
          }
-         if (prog->check_offset_min == prog->check_offset_max) {
+         if (prog->check_offset_min == prog->check_offset_max &&
+             !(prog->reganch & ROPT_CANY_SEEN)) {
            /* Substring at constant offset from beg-of-str... */
            I32 slen;
 
@@ -401,7 +445,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
            if (SvTAIL(check)) {
                slen = SvCUR(check);    /* >= 1 */
 
-               if ( strend - s > slen || strend - s < slen - 1 
+               if ( strend - s > slen || strend - s < slen - 1
                     || (strend - s == slen && strend[-1] != '\n')) {
                    DEBUG_r(PerlIO_printf(Perl_debug_log, "String too long...\n"));
                    goto fail_finish;
@@ -462,13 +506,17 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
            || ( BmRARE(check) == '\n'
                 && (BmPREVIOUS(check) == SvCUR(check) - 1)
                 && SvTAIL(check) ))
-           s = screaminstr(sv, check, 
+           s = screaminstr(sv, check,
                            start_shift + (s - strbeg), end_shift, pp, 0);
        else
            goto fail_finish;
        if (data)
            *data->scream_olds = s;
     }
+    else if (prog->reganch & ROPT_CANY_SEEN)
+       s = fbm_instr((U8*)(s + start_shift),
+                     (U8*)(strend - end_shift),
+                     check, PL_multiline ? FBMrf_MULTILINE : 0);
     else
        s = fbm_instr(HOP3(s, start_shift, strend),
                      HOP3(strend, -end_shift, strbeg),
@@ -647,7 +695,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
                               Thus we can arrive here only if check substr
                               is float.  Redo checking for "other"=="fixed".
                             */
-                           strpos = t + 1;                         
+                           strpos = t + 1;                     
                            DEBUG_r(PerlIO_printf(Perl_debug_log, "Found /%s^%s/m at offset %ld, rescanning for anchored from offset %ld...\n",
                                PL_colors[0],PL_colors[1], (long)(strpos - i_strpos), (long)(strpos - i_strpos + prog->anchored_offset)));
                            goto do_other_anchored;
@@ -751,10 +799,10 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
            PL_regdata = prog->data;
            PL_bostr = startpos;
        }
-        s = find_byclass(prog, prog->regstclass, s, endpos, startpos, 1);
+       s = find_byclass(prog, prog->regstclass, s, endpos, startpos, 1);
        if (!s) {
 #ifdef DEBUGGING
-           char *what;
+           char *what = 0;
 #endif
            if (endpos == strend) {
                DEBUG_r( PerlIO_printf(Perl_debug_log,
@@ -788,7 +836,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
                if (t + start_shift >= check_at) /* Contradicts floating=check */
                    goto retry_floating_check;
                /* Recheck anchored substring, but not floating... */
-               s = check_at; 
+               s = check_at;
                if (!check)
                    goto giveup;
                DEBUG_r( PerlIO_printf(Perl_debug_log,
@@ -815,13 +863,17 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
            DEBUG_r( what = "floating" );
            goto hop_and_restart;
        }
-       DEBUG_r( if (t != s)
-                    PerlIO_printf(Perl_debug_log, 
+       if (t != s) {
+            DEBUG_r(PerlIO_printf(Perl_debug_log,
                        "By STCLASS: moving %ld --> %ld\n",
-                       (long)(t - i_strpos), (long)(s - i_strpos));
-                else
-                    PerlIO_printf(Perl_debug_log, 
-                       "Does not contradict STCLASS...\n") );
+                                  (long)(t - i_strpos), (long)(s - i_strpos))
+                   );
+        }
+        else {
+            DEBUG_r(PerlIO_printf(Perl_debug_log,
+                                  "Does not contradict STCLASS...\n"); 
+                   );
+        }
     }
   giveup:
     DEBUG_r(PerlIO_printf(Perl_debug_log, "%s%s:%s match at offset %ld\n",
@@ -849,7 +901,7 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
        unsigned int c2;
        char *e;
        register I32 tmp = 1;   /* Scratch variable? */
-       register bool do_utf8 = DO_UTF8(PL_reg_sv);
+       register bool do_utf8 = PL_reg_match_utf8;
 
        /* We know what class it must start with. */
        switch (OP(c)) {
@@ -866,12 +918,28 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
                s += do_utf8 ? UTF8SKIP(s) : 1;
            }
            break;
+       case CANY:
+           while (s < strend) {
+               if (tmp && (norun || regtry(prog, s)))
+                   goto got_it;
+               else
+                   tmp = doevery;
+               s++;
+           }
+           break;
        case EXACTF:
            m = STRING(c);
            ln = STR_LEN(c);
            if (UTF) {
-               c1 = to_utf8_lower((U8*)m);
-               c2 = to_utf8_upper((U8*)m);
+               STRLEN ulen1, ulen2;
+               U8 tmpbuf1[UTF8_MAXLEN*2+1];
+               U8 tmpbuf2[UTF8_MAXLEN*2+1];
+
+               to_utf8_lower((U8*)m, tmpbuf1, &ulen1);
+               to_utf8_upper((U8*)m, tmpbuf2, &ulen2);
+
+               c1 = utf8_to_uvuni(tmpbuf1, 0);
+               c2 = utf8_to_uvuni(tmpbuf2, 0);
            }
            else {
                c1 = *(U8*)m;
@@ -891,17 +959,30 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
 
            if (do_utf8) {
                STRLEN len;
+               /* The ibcmp_utf8() uses to_uni_fold() which is more
+                * correct folding for Unicode than using lowercase.
+                * However, it doesn't work quite fully since the folding
+                * is a one-to-many mapping and the regex optimizer is
+                * unaware of this, so it may throw out good matches.
+                * Fortunately, not getting this right is allowed
+                * for Unicode Regular Expression Support level 1,
+                * only one-to-one matching is required. --jhi */
                if (c1 == c2)
                    while (s <= e) {
-                       if ( utf8_to_uv_simple((U8*)s, &len) == c1
-                            && regtry(prog, s) )
+                       if ( utf8_to_uvchr((U8*)s, &len) == c1
+                            && (ln == 1 ||
+                                ibcmp_utf8(s, do_utf8,  strend - s,
+                                           m, UTF, ln)) )
                            goto got_it;
                        s += len;
                    }
                else
                    while (s <= e) {
-                       UV c = utf8_to_uv_simple((U8*)s, &len);
-                       if ( (c == c1 || c == c2) && regtry(prog, s) )
+                       UV c = utf8_to_uvchr((U8*)s, &len);
+                       if ( (c == c1 || c == c2)
+                            && (ln == 1 ||
+                                ibcmp_utf8(s, do_utf8, strend - s,
+                                           m, UTF, ln)) )
                            goto got_it;
                        s += len;
                    }
@@ -934,18 +1015,20 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            /* FALL THROUGH */
        case BOUND:
            if (do_utf8) {
-               if (s == startpos)
+               if (s == PL_bostr)
                    tmp = '\n';
                else {
                    U8 *r = reghop3((U8*)s, -1, (U8*)startpos);
-                   
-                   tmp = (I32)utf8_to_uv(r, s - (char*)r, 0, 0);
+               
+                   if (s > (char*)r)
+                       tmp = (I32)utf8n_to_uvchr(r, s - (char*)r, 0, 0);
                }
                tmp = ((OP(c) == BOUND ?
-                       isALNUM_uni(tmp) : isALNUM_LC_uni(tmp)) != 0);
+                       isALNUM_uni(tmp) : isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp))) != 0);
+               LOAD_UTF8_CHARCLASS(alnum,"a");
                while (s < strend) {
                    if (tmp == !(OP(c) == BOUND ?
-                                swash_fetch(PL_utf8_alnum, (U8*)s) :
+                                swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8) :
                                 isALNUM_LC_utf8((U8*)s)))
                    {
                        tmp = !tmp;
@@ -956,7 +1039,7 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
                }
            }
            else {
-               tmp = (s != startpos) ? UCHARAT(s - 1) : '\n';
+               tmp = (s != PL_bostr) ? UCHARAT(s - 1) : '\n';
                tmp = ((OP(c) == BOUND ? isALNUM(tmp) : isALNUM_LC(tmp)) != 0);
                while (s < strend) {
                    if (tmp ==
@@ -976,18 +1059,20 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            /* FALL THROUGH */
        case NBOUND:
            if (do_utf8) {
-               if (s == startpos)
+               if (s == PL_bostr)
                    tmp = '\n';
                else {
                    U8 *r = reghop3((U8*)s, -1, (U8*)startpos);
-                   
-                   tmp = (I32)utf8_to_uv(r, s - (char*)r, 0, 0);
+               
+                   if (s > (char*)r)
+                       tmp = (I32)utf8n_to_uvchr(r, s - (char*)r, 0, 0);
                }
                tmp = ((OP(c) == NBOUND ?
-                       isALNUM_uni(tmp) : isALNUM_LC_uni(tmp)) != 0);
+                       isALNUM_uni(tmp) : isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp))) != 0);
+               LOAD_UTF8_CHARCLASS(alnum,"a");
                while (s < strend) {
                    if (tmp == !(OP(c) == NBOUND ?
-                                swash_fetch(PL_utf8_alnum, (U8*)s) :
+                                swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8) :
                                 isALNUM_LC_utf8((U8*)s)))
                        tmp = !tmp;
                    else if ((norun || regtry(prog, s)))
@@ -996,7 +1081,7 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
                }
            }
            else {
-               tmp = (s != startpos) ? UCHARAT(s - 1) : '\n';
+               tmp = (s != PL_bostr) ? UCHARAT(s - 1) : '\n';
                tmp = ((OP(c) == NBOUND ?
                        isALNUM(tmp) : isALNUM_LC(tmp)) != 0);
                while (s < strend) {
@@ -1013,8 +1098,9 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            break;
        case ALNUM:
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(alnum,"a");
                while (s < strend) {
-                   if (swash_fetch(PL_utf8_alnum, (U8*)s)) {
+                   if (swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8)) {
                        if (tmp && (norun || regtry(prog, s)))
                            goto got_it;
                        else
@@ -1070,8 +1156,9 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            break;
        case NALNUM:
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(alnum,"a");
                while (s < strend) {
-                   if (!swash_fetch(PL_utf8_alnum, (U8*)s)) {
+                   if (!swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8)) {
                        if (tmp && (norun || regtry(prog, s)))
                            goto got_it;
                        else
@@ -1127,8 +1214,9 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            break;
        case SPACE:
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(space," ");
                while (s < strend) {
-                   if (*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s)) {
+                   if (*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, do_utf8)) {
                        if (tmp && (norun || regtry(prog, s)))
                            goto got_it;
                        else
@@ -1184,8 +1272,9 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            break;
        case NSPACE:
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(space," ");
                while (s < strend) {
-                   if (!(*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s))) {
+                   if (!(*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, do_utf8))) {
                        if (tmp && (norun || regtry(prog, s)))
                            goto got_it;
                        else
@@ -1241,8 +1330,9 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            break;
        case DIGIT:
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(digit,"0");
                while (s < strend) {
-                   if (swash_fetch(PL_utf8_digit,(U8*)s)) {
+                   if (swash_fetch(PL_utf8_digit,(U8*)s, do_utf8)) {
                        if (tmp && (norun || regtry(prog, s)))
                            goto got_it;
                        else
@@ -1298,8 +1388,9 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta
            break;
        case NDIGIT:
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(digit,"0");
                while (s < strend) {
-                   if (!swash_fetch(PL_utf8_digit,(U8*)s)) {
+                   if (!swash_fetch(PL_utf8_digit,(U8*)s, do_utf8)) {
                        if (tmp && (norun || regtry(prog, s)))
                            goto got_it;
                        else
@@ -1386,12 +1477,15 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     char *scream_olds;
     SV* oreplsv = GvSV(PL_replgv);
     bool do_utf8 = DO_UTF8(sv);
+#ifdef DEBUGGING
+    SV *dsv = PERL_DEBUG_PAD_ZERO(0);
+#endif
 
     PL_regcc = 0;
 
     cache_re(prog);
 #ifdef DEBUGGING
-    PL_regnarrate = PL_debug & 512;
+    PL_regnarrate = DEBUG_r_TEST;
 #endif
 
     /* Be paranoid... */
@@ -1401,24 +1495,10 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     }
 
     minlen = prog->minlen;
-    if (do_utf8) {
-      if (utf8_distance((U8*)strend, (U8*)startpos) < minlen) goto phooey;
-    }
-    else {
-      if (strend - startpos < minlen) goto phooey;
-    }
-
-    if (startpos == strbeg)    /* is ^ valid at stringarg? */
-       PL_regprev = '\n';
-    else {
-        if (prog->reganch & ROPT_UTF8 && do_utf8) {
-           U8 *s = reghop3((U8*)stringarg, -1, (U8*)strbeg);
-           PL_regprev = utf8_to_uv(s, (U8*)stringarg - s, NULL, 0);
-       }
-       else
-           PL_regprev = (U32)stringarg[-1];
-       if (!PL_multiline && PL_regprev == '\n')
-           PL_regprev = '\0';          /* force ^ to NOT match */
+    if (strend - startpos < minlen) {
+        DEBUG_r(PerlIO_printf(Perl_debug_log,
+                             "String too short [regexec_flags]...\n"));
+       goto phooey;
     }
 
     /* Check validity of program. */
@@ -1457,10 +1537,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
            PL_reg_ganch = startpos;
        else if (sv && SvTYPE(sv) >= SVt_PVMG
                  && SvMAGIC(sv)
-                 && (mg = mg_find(sv, 'g')) && mg->mg_len >= 0) {
+                 && (mg = mg_find(sv, PERL_MAGIC_regex_global))
+                 && mg->mg_len >= 0) {
            PL_reg_ganch = strbeg + mg->mg_len; /* Defined pos() */
            if (prog->reganch & ROPT_ANCH_GPOS) {
-               if (s > PL_reg_ganch)
+               if (s > PL_reg_ganch)
                    goto phooey;
                s = PL_reg_ganch;
            }
@@ -1476,22 +1557,29 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
        d.scream_olds = &scream_olds;
        d.scream_pos = &scream_pos;
        s = re_intuit_start(prog, sv, s, strend, flags, &d);
-       if (!s)
+       if (!s) {
+           DEBUG_r(PerlIO_printf(Perl_debug_log, "Not present...\n"));
            goto phooey;        /* not present */
+       }
     }
 
-    DEBUG_r( if (!PL_colorset) reginitcolors() );
-    DEBUG_r(PerlIO_printf(Perl_debug_log,
-                     "%sMatching REx%s `%s%.60s%s%s' against `%s%.*s%s%s'\n",
-                     PL_colors[4],PL_colors[5],PL_colors[0],
-                     prog->precomp,
-                     PL_colors[1],
-                     (strlen(prog->precomp) > 60 ? "..." : ""),
-                     PL_colors[0],
-                     (int)(strend - startpos > 60 ? 60 : strend - startpos),
-                     startpos, PL_colors[1],
-                     (strend - startpos > 60 ? "..." : ""))
-       );
+    DEBUG_r({
+        char *s   = do_utf8 ? sv_uni_display(dsv, sv, 60, 0) : startpos;
+        int   len = do_utf8 ? strlen(s) : strend - startpos;
+        if (!PL_colorset)
+            reginitcolors();
+        PerlIO_printf(Perl_debug_log,
+                      "%sMatching REx%s `%s%.60s%s%s' against `%s%.*s%s%s'\n",
+                      PL_colors[4],PL_colors[5],PL_colors[0],
+                      prog->precomp,
+                      PL_colors[1],
+                      (strlen(prog->precomp) > 60 ? "..." : ""),
+                      PL_colors[0],
+                      (int)(len > 60 ? 60 : len),
+                      s, PL_colors[1],
+                      (len > 60 ? "..." : "")
+             );
+    });
 
     /* Simplest case:  anchored match need be tried only once. */
     /*  [unless only anchor is BOL and multiline is set] */
@@ -1543,7 +1631,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     }
 
     /* Messy cases:  unanchored match. */
-    if (prog->anchored_substr && prog->reganch & ROPT_SKIP) { 
+    if (prog->anchored_substr && prog->reganch & ROPT_SKIP) {
        /* we have /x+whatever/ */
        /* it must be a one character string (XXXX Except UTF?) */
        char ch = SvPVX(prog->anchored_substr)[0];
@@ -1575,20 +1663,21 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
                s++;
            }
        }
-       DEBUG_r(did_match ||
+       DEBUG_r(if (!did_match)
                PerlIO_printf(Perl_debug_log,
-                             "Did not find anchored character...\n"));
+                                  "Did not find anchored character...\n")
+               );
     }
     /*SUPPRESS 560*/
     else if (do_utf8 == (UTF!=0) &&
             (prog->anchored_substr != Nullsv
-             || (prog->float_substr != Nullsv 
+             || (prog->float_substr != Nullsv
                  && prog->float_max_offset < strend - s))) {
-       SV *must = prog->anchored_substr 
+       SV *must = prog->anchored_substr
            ? prog->anchored_substr : prog->float_substr;
-       I32 back_max = 
+       I32 back_max =
            prog->anchored_substr ? prog->anchored_offset : prog->float_max_offset;
-       I32 back_min = 
+       I32 back_min =
            prog->anchored_substr ? prog->anchored_offset : prog->float_min_offset;
        char *last = HOP3c(strend,      /* Cannot start after this */
                          -(I32)(CHR_SVLEN(must)
@@ -1609,11 +1698,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
        dontbother = end_shift;
        strend = HOPc(strend, -dontbother);
        while ( (s <= last) &&
-               ((flags & REXEC_SCREAM) 
+               ((flags & REXEC_SCREAM)
                 ? (s = screaminstr(sv, must, HOP3c(s, back_min, strend) - strbeg,
                                    end_shift, &scream_pos, 0))
                 : (s = fbm_instr((unsigned char*)HOP3(s, back_min, strend),
-                                 (unsigned char*)strend, must, 
+                                 (unsigned char*)strend, must,
                                  PL_multiline ? FBMrf_MULTILINE : 0))) ) {
            DEBUG_r( did_match = 1 );
            if (HOPc(s, -back_max) > last1) {
@@ -1641,14 +1730,16 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
                }
            }
        }
-       DEBUG_r(did_match ||
-               PerlIO_printf(Perl_debug_log, "Did not find %s substr `%s%.*s%s'%s...\n",
+       DEBUG_r(if (!did_match)
+                    PerlIO_printf(Perl_debug_log, 
+                                  "Did not find %s substr `%s%.*s%s'%s...\n",
                              ((must == prog->anchored_substr)
                               ? "anchored" : "floating"),
                              PL_colors[0],
                              (int)(SvCUR(must) - (SvTAIL(must)!=0)),
                              SvPVX(must),
-                             PL_colors[1], (SvTAIL(must) ? "$" : "")));
+                                  PL_colors[1], (SvTAIL(must) ? "$" : ""))
+               );
        goto phooey;
     }
     else if ((c = prog->regstclass)) {
@@ -1658,7 +1749,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
        DEBUG_r({
            SV *prop = sv_newmortal();
            regprop(prop, c);
-           PerlIO_printf(Perl_debug_log, "Matching stclass `%s' against `%s'\n", SvPVX(prop), s);
+           PerlIO_printf(Perl_debug_log, "Matching stclass `%s' against `%s'\n", SvPVX(prop), UTF ? sv_uni_display(dsv, sv, 60, 0) : s);
        });
        if (find_byclass(prog, c, s, strend, startpos, 0))
            goto got_it;
@@ -1683,13 +1774,13 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
                    if (memEQ(strend - len + 1, little, len - 1))
                        last = strend - len + 1;
                    else if (!PL_multiline)
-                       last = memEQ(strend - len, little, len) 
+                       last = memEQ(strend - len, little, len)
                            ? strend - len : Nullch;
                    else
                        goto find_last;
                } else {
                  find_last:
-                   if (len) 
+                   if (len)
                        last = rninstr(s, strend, little, little + len);
                    else
                        last = strend;  /* matching `$' */
@@ -1736,7 +1827,7 @@ got_it:
            sv_setsv(oreplsv, GvSV(PL_replgv));/* So that when GvSV(replgv) is
                                                  restored, the value remains
                                                  the same. */
-       restore_pos(aTHXo_ 0);
+       restore_pos(aTHX_ 0);
     }
 
     /* make sure $`, $&, $', and $digit will work later */
@@ -1758,14 +1849,14 @@ got_it:
            prog->sublen = PL_regeol - strbeg;  /* strend may have been modified */
        }
     }
-    
+
     return 1;
 
 phooey:
     DEBUG_r(PerlIO_printf(Perl_debug_log, "%sMatch failed%s\n",
                          PL_colors[4],PL_colors[5]));
     if (PL_reg_eval_set)
-       restore_pos(aTHXo_ 0);
+       restore_pos(aTHX_ 0);
     return 0;
 }
 
@@ -1802,25 +1893,37 @@ S_regtry(pTHX_ regexp *prog, char *startpos)
        if (PL_reg_sv) {
            /* Make $_ available to executed code. */
            if (PL_reg_sv != DEFSV) {
-               /* SAVE_DEFSV does *not* suffice here for USE_THREADS */
+               /* SAVE_DEFSV does *not* suffice here for USE_5005THREADS */
                SAVESPTR(DEFSV);
                DEFSV = PL_reg_sv;
            }
        
-           if (!(SvTYPE(PL_reg_sv) >= SVt_PVMG && SvMAGIC(PL_reg_sv) 
-                 && (mg = mg_find(PL_reg_sv, 'g')))) {
+           if (!(SvTYPE(PL_reg_sv) >= SVt_PVMG && SvMAGIC(PL_reg_sv)
+                 && (mg = mg_find(PL_reg_sv, PERL_MAGIC_regex_global)))) {
                /* prepare for quick setting of pos */
-               sv_magic(PL_reg_sv, (SV*)0, 'g', Nullch, 0);
-               mg = mg_find(PL_reg_sv, 'g');
+               sv_magic(PL_reg_sv, (SV*)0,
+                       PERL_MAGIC_regex_global, Nullch, 0);
+               mg = mg_find(PL_reg_sv, PERL_MAGIC_regex_global);
                mg->mg_len = -1;
            }
            PL_reg_magic    = mg;
            PL_reg_oldpos   = mg->mg_len;
            SAVEDESTRUCTOR_X(restore_pos, 0);
         }
-       if (!PL_reg_curpm)
+        if (!PL_reg_curpm) {
            Newz(22,PL_reg_curpm, 1, PMOP);
-       PL_reg_curpm->op_pmregexp = prog;
+#ifdef USE_ITHREADS
+            {
+                SV* repointer = newSViv(0);
+                /* so we know which PL_regex_padav element is PL_reg_curpm */
+                SvFLAGS(repointer) |= SVf_BREAK;
+                av_push(PL_regex_padav,repointer);
+                PL_reg_curpm->op_pmoffset = av_len(PL_regex_padav);
+                PL_regex_pad = AvARRAY(PL_regex_padav);
+            }
+#endif      
+        }
+       PM_SETRE(PL_reg_curpm, prog);
        PL_reg_oldcurpm = PL_curpm;
        PL_curpm = PL_reg_curpm;
        if (RX_MATCH_COPIED(prog)) {
@@ -1841,6 +1944,7 @@ S_regtry(pTHX_ regexp *prog, char *startpos)
     PL_regstartp = prog->startp;
     PL_regendp = prog->endp;
     PL_reglastparen = &prog->lastparen;
+    PL_reglastcloseparen = &prog->lastcloseparen;
     prog->lastparen = 0;
     PL_regsize = 0;
     DEBUG_r(PL_reg_starttry = startpos);
@@ -1852,6 +1956,12 @@ S_regtry(pTHX_ regexp *prog, char *startpos)
             New(22,PL_reg_start_tmp, PL_reg_start_tmpl, char*);
     }
 
+#ifdef DEBUGGING
+    sv_setpvn(PERL_DEBUG_PAD(0), "", 0);
+    sv_setpvn(PERL_DEBUG_PAD(1), "", 0);
+    sv_setpvn(PERL_DEBUG_PAD(2), "", 0);
+#endif
+
     /* XXXX What this code is doing here?!!!  There should be no need
        to do this again and again, PL_reglastparen should take care of
        this!  --ilya*/
@@ -1915,6 +2025,16 @@ typedef union re_unwind_t {
     re_unwind_branch_t branch;
 } re_unwind_t;
 
+#define sayYES goto yes
+#define sayNO goto no
+#define sayYES_FINAL goto yes_final
+#define sayYES_LOUD  goto yes_loud
+#define sayNO_FINAL  goto no_final
+#define sayNO_SILENT goto do_no
+#define saySAME(x) if (x) goto yes; else goto no
+
+#define REPORT_CODE_OFF 24
+
 /*
  - regmatch - main matching routine
  *
@@ -1938,14 +2058,21 @@ S_regmatch(pTHX_ regnode *prog)
     register I32 nextchr;      /* renamed nextchr - nextchar colides with
                                   function of same name */
     register I32 n;            /* no or next */
-    register I32 ln;           /* len or last */
-    register char *s;          /* operand or save */
+    register I32 ln = 0;       /* len or last */
+    register char *s = Nullch; /* operand or save */
     register char *locinput = PL_reginput;
-    register I32 c1, c2, paren;        /* case fold search, parenth */
+    register I32 c1 = 0, c2 = 0, paren;        /* case fold search, parenth */
     int minmod = 0, sw = 0, logical = 0;
     I32 unwind = 0;
+#if 0
     I32 firstcp = PL_savestack_ix;
-    register bool do_utf8 = DO_UTF8(PL_reg_sv);
+#endif
+    register bool do_utf8 = PL_reg_match_utf8;
+#ifdef DEBUGGING
+    SV *dsv0 = PERL_DEBUG_PAD_ZERO(0);
+    SV *dsv1 = PERL_DEBUG_PAD_ZERO(1);
+    SV *dsv2 = PERL_DEBUG_PAD_ZERO(2);
+#endif
 
 #ifdef DEBUGGING
     PL_regindent++;
@@ -1955,26 +2082,8 @@ S_regmatch(pTHX_ regnode *prog)
     nextchr = UCHARAT(locinput);
     scan = prog;
     while (scan != NULL) {
-#define sayNO_L (logical ? (logical = 0, sw = 0, goto cont) : sayNO)
-#if 1
-#  define sayYES goto yes
-#  define sayNO goto no
-#  define sayYES_FINAL goto yes_final
-#  define sayYES_LOUD  goto yes_loud
-#  define sayNO_FINAL  goto no_final
-#  define sayNO_SILENT goto do_no
-#  define saySAME(x) if (x) goto yes; else goto no
-#  define REPORT_CODE_OFF 24
-#else
-#  define sayYES return 1
-#  define sayNO return 0
-#  define sayYES_FINAL return 1
-#  define sayYES_LOUD  return 1
-#  define sayNO_FINAL  return 0
-#  define sayNO_SILENT return 0
-#  define saySAME(x) return x
-#endif
-       DEBUG_r( {
+
+        DEBUG_r( {
            SV *prop = sv_newmortal();
            int docolor = *PL_colors[0];
            int taill = (docolor ? 10 : 7); /* 3 chars for "> <" */
@@ -1985,37 +2094,59 @@ S_regmatch(pTHX_ regnode *prog)
               after the current position the third one.
               We assume that pref0_len <= pref_len, otherwise we
               decrease pref0_len.  */
-           int pref_len = (locinput - PL_bostr) > (5 + taill) - l 
+           int pref_len = (locinput - PL_bostr) > (5 + taill) - l
                ? (5 + taill) - l : locinput - PL_bostr;
            int pref0_len;
 
-           while (UTF8_IS_CONTINUATION(*(U8*)(locinput - pref_len)))
+           while (do_utf8 && UTF8_IS_CONTINUATION(*(U8*)(locinput - pref_len)))
                pref_len++;
            pref0_len = pref_len  - (locinput - PL_reg_starttry);
            if (l + pref_len < (5 + taill) && l < PL_regeol - locinput)
-               l = ( PL_regeol - locinput > (5 + taill) - pref_len 
+               l = ( PL_regeol - locinput > (5 + taill) - pref_len
                      ? (5 + taill) - pref_len : PL_regeol - locinput);
-           while (UTF8_IS_CONTINUATION(*(U8*)(locinput + l)))
+           while (do_utf8 && UTF8_IS_CONTINUATION(*(U8*)(locinput + l)))
                l--;
            if (pref0_len < 0)
                pref0_len = 0;
            if (pref0_len > pref_len)
                pref0_len = pref_len;
            regprop(prop, scan);
-           PerlIO_printf(Perl_debug_log, 
-                         "%4"IVdf" <%s%.*s%s%s%.*s%s%s%s%.*s%s>%*s|%3"IVdf":%*s%s\n",
-                         (IV)(locinput - PL_bostr), 
-                         PL_colors[4], pref0_len, 
-                         locinput - pref_len, PL_colors[5],
-                         PL_colors[2], pref_len - pref0_len, 
-                         locinput - pref_len + pref0_len, PL_colors[3],
-                         (docolor ? "" : "> <"),
-                         PL_colors[0], l, locinput, PL_colors[1],
-                         15 - l - pref_len + 1,
-                         "",
-                         (IV)(scan - PL_regprogram), PL_regindent*2, "",
-                         SvPVX(prop));
-       } );
+           {
+             char *s0 =
+               do_utf8 ?
+               pv_uni_display(dsv0, (U8*)(locinput - pref_len),
+                              pref0_len, 60, 0) :
+               locinput - pref_len;
+             int len0 = do_utf8 ? strlen(s0) : pref0_len;
+             char *s1 = do_utf8 ?
+               pv_uni_display(dsv1, (U8*)(locinput - pref_len + pref0_len),
+                              pref_len - pref0_len, 60, 0) :
+               locinput - pref_len + pref0_len;
+             int len1 = do_utf8 ? strlen(s1) : pref_len - pref0_len;
+             char *s2 = do_utf8 ?
+               pv_uni_display(dsv2, (U8*)locinput,
+                              PL_regeol - locinput, 60, 0) :
+               locinput;
+             int len2 = do_utf8 ? strlen(s2) : l;
+             PerlIO_printf(Perl_debug_log,
+                           "%4"IVdf" <%s%.*s%s%s%.*s%s%s%s%.*s%s>%*s|%3"IVdf":%*s%s\n",
+                           (IV)(locinput - PL_bostr),
+                           PL_colors[4],
+                           len0, s0,
+                           PL_colors[5],
+                           PL_colors[2],
+                           len1, s1,
+                           PL_colors[3],
+                           (docolor ? "" : "> <"),
+                           PL_colors[0],
+                           len2, s2,
+                           PL_colors[1],
+                           15 - l - pref_len + 1,
+                           "",
+                           (IV)(scan - PL_regprogram), PL_regindent*2, "",
+                           SvPVX(prop));
+           }
+       });
 
        next = scan + NEXT_OFF(scan);
        if (next == scan)
@@ -2023,19 +2154,16 @@ S_regmatch(pTHX_ regnode *prog)
 
        switch (OP(scan)) {
        case BOL:
-           if (locinput == PL_bostr
-               ? PL_regprev == '\n'
-               : (PL_multiline && 
-                  (nextchr || locinput < PL_regeol) && locinput[-1] == '\n') )
+           if (locinput == PL_bostr || (PL_multiline &&
+               (nextchr || locinput < PL_regeol) && locinput[-1] == '\n') )
            {
                /* regtill = regbol; */
                break;
            }
            sayNO;
        case MBOL:
-           if (locinput == PL_bostr
-               ? PL_regprev == '\n'
-               : ((nextchr || locinput < PL_regeol) && locinput[-1] == '\n') )
+           if (locinput == PL_bostr ||
+               ((nextchr || locinput < PL_regeol) && locinput[-1] == '\n'))
            {
                break;
            }
@@ -2070,13 +2198,18 @@ S_regmatch(pTHX_ regnode *prog)
                sayNO;
            break;
        case SANY:
-           if (do_utf8) {
-               locinput += PL_utf8skip[nextchr];
+           if (!nextchr && locinput >= PL_regeol)
+               sayNO;
+           if (do_utf8) {
+               locinput += PL_utf8skip[nextchr];
                if (locinput > PL_regeol)
-                   sayNO;
-               nextchr = UCHARAT(locinput);
-               break;
-           }
+                   sayNO;
+               nextchr = UCHARAT(locinput);
+           }
+           else
+               nextchr = UCHARAT(++locinput);
+           break;
+       case CANY:
            if (!nextchr && locinput >= PL_regeol)
                sayNO;
            nextchr = UCHARAT(++locinput);
@@ -2097,31 +2230,40 @@ S_regmatch(pTHX_ regnode *prog)
            s = STRING(scan);
            ln = STR_LEN(scan);
            if (do_utf8 != (UTF!=0)) {
+               /* The target and the pattern have differing "utf8ness". */
                char *l = locinput;
                char *e = s + ln;
                STRLEN len;
-               if (do_utf8)
+
+               if (do_utf8) {
+                   /* The target is utf8, the pattern is not utf8. */
                    while (s < e) {
                        if (l >= PL_regeol)
-                           sayNO;
-                       if (*((U8*)s) != utf8_to_uv_simple((U8*)l, &len))
-                           sayNO;
-                       s++;
+                            sayNO;
+                       if (NATIVE_TO_UNI(*(U8*)s) !=
+                           utf8_to_uvchr((U8*)l, &len))
+                            sayNO;
                        l += len;
+                       s ++;
                    }
-               else
+               }
+               else {
+                   /* The target is not utf8, the pattern is utf8. */
                    while (s < e) {
                        if (l >= PL_regeol)
                            sayNO;
-                       if (*((U8*)l) != utf8_to_uv_simple((U8*)s, &len))
+                       if (NATIVE_TO_UNI(*((U8*)l)) !=
+                           utf8_to_uvchr((U8*)s, &len))
                            sayNO;
                        s += len;
-                       l++;
+                       l ++;
                    }
+               }
                locinput = l;
                nextchr = UCHARAT(locinput);
                break;
            }
+           /* The target and the pattern have the same "utf8ness". */
            /* Inline the first character, for speed. */
            if (UCHARAT(s) != nextchr)
                sayNO;
@@ -2142,17 +2284,17 @@ S_regmatch(pTHX_ regnode *prog)
            if (do_utf8) {
                char *l = locinput;
                char *e;
+               STRLEN ulen;
+               U8 tmpbuf[UTF8_MAXLEN*2+1];
                e = s + ln;
-               c1 = OP(scan) == EXACTF;
                while (s < e) {
-                   if (l >= PL_regeol) {
+                   if (l >= PL_regeol)
                        sayNO;
-                   }
-                   if ((UTF ? utf8_to_uv((U8*)s, e - s, 0, 0) : *((U8*)s)) !=
-                       (c1 ? toLOWER_utf8((U8*)l) : toLOWER_LC_utf8((U8*)l)))
-                           sayNO;
-                   s += UTF ? UTF8SKIP(s) : 1;
-                   l += UTF8SKIP(l);
+                   toLOWER_utf8((U8*)l, tmpbuf, &ulen);
+                   if (memNE(s, (char*)tmpbuf, ulen))
+                       sayNO;
+                   s += UTF8SKIP(s);
+                   l += ulen;
                }
                locinput = l;
                nextchr = UCHARAT(locinput);
@@ -2199,8 +2341,9 @@ S_regmatch(pTHX_ regnode *prog)
            if (!nextchr)
                sayNO;
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(alnum,"a");
                if (!(OP(scan) == ALNUM
-                     ? swash_fetch(PL_utf8_alnum, (U8*)locinput)
+                     ? swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8)
                      : isALNUM_LC_utf8((U8*)locinput)))
                {
                    sayNO;
@@ -2221,8 +2364,9 @@ S_regmatch(pTHX_ regnode *prog)
            if (!nextchr && locinput >= PL_regeol)
                sayNO;
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(alnum,"a");
                if (OP(scan) == NALNUM
-                   ? swash_fetch(PL_utf8_alnum, (U8*)locinput)
+                   ? swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8)
                    : isALNUM_LC_utf8((U8*)locinput))
                {
                    sayNO;
@@ -2244,25 +2388,26 @@ S_regmatch(pTHX_ regnode *prog)
        case NBOUND:
            /* was last char in word? */
            if (do_utf8) {
-               if (locinput == PL_regbol)
-                   ln = PL_regprev;
+               if (locinput == PL_bostr)
+                   ln = '\n';
                else {
                    U8 *r = reghop((U8*)locinput, -1);
-                   
-                   ln = utf8_to_uv(r, s - (char*)r, 0, 0);
+               
+                   ln = utf8n_to_uvchr(r, s - (char*)r, 0, 0);
                }
                if (OP(scan) == BOUND || OP(scan) == NBOUND) {
                    ln = isALNUM_uni(ln);
-                   n = swash_fetch(PL_utf8_alnum, (U8*)locinput);
+                   LOAD_UTF8_CHARCLASS(alnum,"a");
+                   n = swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8);
                }
                else {
-                   ln = isALNUM_LC_uni(ln);
+                   ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
                    n = isALNUM_LC_utf8((U8*)locinput);
                }
            }
            else {
-               ln = (locinput != PL_regbol) ?
-                   UCHARAT(locinput - 1) : PL_regprev;
+               ln = (locinput != PL_bostr) ?
+                   UCHARAT(locinput - 1) : '\n';
                if (OP(scan) == BOUND || OP(scan) == NBOUND) {
                    ln = isALNUM(ln);
                    n = isALNUM(nextchr);
@@ -2284,8 +2429,9 @@ S_regmatch(pTHX_ regnode *prog)
                sayNO;
            if (do_utf8) {
                if (UTF8_IS_CONTINUED(nextchr)) {
+                   LOAD_UTF8_CHARCLASS(space," ");
                    if (!(OP(scan) == SPACE
-                         ? swash_fetch(PL_utf8_space, (U8*)locinput)
+                         ? swash_fetch(PL_utf8_space, (U8*)locinput, do_utf8)
                          : isSPACE_LC_utf8((U8*)locinput)))
                    {
                        sayNO;
@@ -2313,8 +2459,9 @@ S_regmatch(pTHX_ regnode *prog)
            if (!nextchr && locinput >= PL_regeol)
                sayNO;
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(space," ");
                if (OP(scan) == NSPACE
-                   ? swash_fetch(PL_utf8_space, (U8*)locinput)
+                   ? swash_fetch(PL_utf8_space, (U8*)locinput, do_utf8)
                    : isSPACE_LC_utf8((U8*)locinput))
                {
                    sayNO;
@@ -2335,8 +2482,9 @@ S_regmatch(pTHX_ regnode *prog)
            if (!nextchr)
                sayNO;
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(digit,"0");
                if (!(OP(scan) == DIGIT
-                     ? swash_fetch(PL_utf8_digit, (U8*)locinput)
+                     ? swash_fetch(PL_utf8_digit, (U8*)locinput, do_utf8)
                      : isDIGIT_LC_utf8((U8*)locinput)))
                {
                    sayNO;
@@ -2357,8 +2505,9 @@ S_regmatch(pTHX_ regnode *prog)
            if (!nextchr && locinput >= PL_regeol)
                sayNO;
            if (do_utf8) {
+               LOAD_UTF8_CHARCLASS(digit,"0");
                if (OP(scan) == NDIGIT
-                   ? swash_fetch(PL_utf8_digit, (U8*)locinput)
+                   ? swash_fetch(PL_utf8_digit, (U8*)locinput, do_utf8)
                    : isDIGIT_LC_utf8((U8*)locinput))
                {
                    sayNO;
@@ -2373,10 +2522,13 @@ S_regmatch(pTHX_ regnode *prog)
            nextchr = UCHARAT(++locinput);
            break;
        case CLUMP:
-           if (locinput >= PL_regeol || swash_fetch(PL_utf8_mark,(U8*)locinput))
+           LOAD_UTF8_CHARCLASS(mark,"~");
+           if (locinput >= PL_regeol ||
+               swash_fetch(PL_utf8_mark,(U8*)locinput, do_utf8))
                sayNO;
            locinput += PL_utf8skip[nextchr];
-           while (locinput < PL_regeol && swash_fetch(PL_utf8_mark,(U8*)locinput))
+           while (locinput < PL_regeol &&
+                  swash_fetch(PL_utf8_mark,(U8*)locinput, do_utf8))
                locinput += UTF8SKIP(locinput);
            if (locinput > PL_regeol)
                sayNO;
@@ -2405,23 +2557,18 @@ S_regmatch(pTHX_ regnode *prog)
                 * have to map both upper and title case to lower case.
                 */
                if (OP(scan) == REFF) {
+                   STRLEN ulen1, ulen2;
+                   U8 tmpbuf1[UTF8_MAXLEN*2+1];
+                   U8 tmpbuf2[UTF8_MAXLEN*2+1];
                    while (s < e) {
                        if (l >= PL_regeol)
                            sayNO;
-                       if (toLOWER_utf8((U8*)s) != toLOWER_utf8((U8*)l))
+                       toLOWER_utf8((U8*)s, tmpbuf1, &ulen1);
+                       toLOWER_utf8((U8*)l, tmpbuf2, &ulen2);
+                       if (ulen1 != ulen2 || memNE((char *)tmpbuf1, (char *)tmpbuf2, ulen1))
                            sayNO;
-                       s += UTF8SKIP(s);
-                       l += UTF8SKIP(l);
-                   }
-               }
-               else {
-                   while (s < e) {
-                       if (l >= PL_regeol)
-                           sayNO;
-                       if (toLOWER_LC_utf8((U8*)s) != toLOWER_LC_utf8((U8*)l))
-                           sayNO;
-                       s += UTF8SKIP(s);
-                       l += UTF8SKIP(l);
+                       s += ulen1;
+                       l += ulen2;
                    }
                }
                locinput = l;
@@ -2460,18 +2607,25 @@ S_regmatch(pTHX_ regnode *prog)
            COP *ocurcop = PL_curcop;
            SV **ocurpad = PL_curpad;
            SV *ret;
-           
+       
            n = ARG(scan);
            PL_op = (OP_4tree*)PL_regdata->data[n];
            DEBUG_r( PerlIO_printf(Perl_debug_log, "  re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) );
            PL_curpad = AvARRAY((AV*)PL_regdata->data[n + 2]);
            PL_regendp[0] = PL_reg_magic->mg_len = locinput - PL_bostr;
 
-           CALLRUNOPS(aTHX);                   /* Scalar context. */
-           SPAGAIN;
-           ret = POPs;
-           PUTBACK;
-           
+           {
+               SV **before = SP;
+               CALLRUNOPS(aTHX);                       /* Scalar context. */
+               SPAGAIN;
+               if (SP == before)
+                   ret = Nullsv;   /* protect against empty (?{}) blocks. */
+               else {
+                   ret = POPs;
+                   PUTBACK;
+               }
+           }
+
            PL_op = oop;
            PL_curpad = ocurpad;
            PL_curcop = ocurcop;
@@ -2486,7 +2640,7 @@ S_regmatch(pTHX_ regnode *prog)
                        SV *sv = SvROK(ret) ? SvRV(ret) : ret;
 
                        if(SvMAGICAL(sv))
-                           mg = mg_find(sv, 'r');
+                           mg = mg_find(sv, PERL_MAGIC_qr);
                    }
                    if (mg) {
                        re = (regexp *)mg->mg_obj;
@@ -2500,17 +2654,18 @@ S_regmatch(pTHX_ regnode *prog)
                        I32 osize = PL_regsize;
                        I32 onpar = PL_regnpar;
 
-                       pm.op_pmflags = 0;
+                       Zero(&pm, 1, PMOP);
                        re = CALLREGCOMP(aTHX_ t, t + len, &pm);
-                       if (!(SvFLAGS(ret) 
+                       if (!(SvFLAGS(ret)
                              & (SVs_TEMP | SVs_PADTMP | SVf_READONLY)))
-                           sv_magic(ret,(SV*)ReREFCNT_inc(re),'r',0,0);
+                           sv_magic(ret,(SV*)ReREFCNT_inc(re),
+                                       PERL_MAGIC_qr,0,0);
                        PL_regprecomp = oprecomp;
                        PL_regsize = osize;
                        PL_regnpar = onpar;
                    }
                    DEBUG_r(
-                       PerlIO_printf(Perl_debug_log, 
+                       PerlIO_printf(Perl_debug_log,
                                      "Entering embedded `%s%.60s%s%s'\n",
                                      PL_colors[0],
                                      re->precomp,
@@ -2523,12 +2678,13 @@ S_regmatch(pTHX_ regnode *prog)
                    state.re = PL_reg_re;
 
                    PL_regcc = 0;
-                   
+               
                    cp = regcppush(0);  /* Save *all* the positions. */
                    REGCP_SET(lastcp);
                    cache_re(re);
                    state.ss = PL_savestack_ix;
                    *PL_reglastparen = 0;
+                   *PL_reglastcloseparen = 0;
                    PL_reg_call_cc = &state;
                    PL_reginput = locinput;
 
@@ -2565,6 +2721,7 @@ S_regmatch(pTHX_ regnode *prog)
                    /* XXXX This is too dramatic a measure... */
                    PL_reg_maxiter = 0;
 
+                   logical = 0;
                    sayNO;
                }
                sw = SvTRUE(ret);
@@ -2586,6 +2743,7 @@ S_regmatch(pTHX_ regnode *prog)
            PL_regendp[n] = locinput - PL_bostr;
            if (n > *PL_reglastparen)
                *PL_reglastparen = n;
+           *PL_reglastcloseparen = n;
            break;
        case GROUPP:
            n = ARG(scan);  /* which paren pair */
@@ -2612,7 +2770,7 @@ S_regmatch(pTHX_ regnode *prog)
 
    1) After matching X, regnode for CURLYX is processed;
 
-   2) This regnode creates infoblock on the stack, and calls 
+   2) This regnode creates infoblock on the stack, and calls
       regmatch() recursively with the starting point at WHILEM node;
 
    3) Each hit of WHILEM node tries to match A and Z (in the order
@@ -2633,7 +2791,7 @@ S_regmatch(pTHX_ regnode *prog)
  and whatever it mentions via ->next, and additional attached trees
  corresponding to temporarily unset infoblocks as in "5" above.
 
- In the following picture infoblocks for outer loop of 
+ In the following picture infoblocks for outer loop of
  (Y(A)*?Z)*?T are denoted O, for inner I.  NULL starting block
  is denoted by x.  The matched string is YAAZYAZT.  Temporarily postponed
  infoblocks are drawn below the "reset" infoblock.
@@ -2726,10 +2884,10 @@ S_regmatch(pTHX_ regnode *prog)
                PL_reginput = locinput;
 
                DEBUG_r(
-                   PerlIO_printf(Perl_debug_log, 
-                                 "%*s  %ld out of %ld..%ld  cc=%lx\n", 
+                   PerlIO_printf(Perl_debug_log,
+                                 "%*s  %ld out of %ld..%ld  cc=%lx\n",
                                  REPORT_CODE_OFF+PL_regindent*2, "",
-                                 (long)n, (long)cc->min, 
+                                 (long)n, (long)cc->min,
                                  (long)cc->max, (long)cc)
                    );
 
@@ -2828,7 +2986,7 @@ S_regmatch(pTHX_ regnode *prog)
                    PL_regcc = cc;
 
                    if (n >= cc->max) { /* Maximum greed exceeded? */
-                       if (ckWARN(WARN_REGEXP) && n >= REG_INFTY 
+                       if (ckWARN(WARN_REGEXP) && n >= REG_INFTY
                            && !(PL_reg_flags & RF_warned)) {
                            PL_reg_flags |= RF_warned;
                            Perl_warner(aTHX_ WARN_REGEXP, "%s limit (%d) exceeded",
@@ -2880,7 +3038,7 @@ S_regmatch(pTHX_ regnode *prog)
                                      REPORT_CODE_OFF+PL_regindent*2, "")
                        );
                }
-               if (ckWARN(WARN_REGEXP) && n >= REG_INFTY 
+               if (ckWARN(WARN_REGEXP) && n >= REG_INFTY
                        && !(PL_reg_flags & RF_warned)) {
                    PL_reg_flags |= RF_warned;
                    Perl_warner(aTHX_ WARN_REGEXP, "%s limit (%d) exceeded",
@@ -2902,17 +3060,16 @@ S_regmatch(pTHX_ regnode *prog)
                sayNO;
            }
            /* NOT REACHED */
-       case BRANCHJ: 
+       case BRANCHJ:
            next = scan + ARG(scan);
            if (next == scan)
                next = NULL;
            inner = NEXTOPER(NEXTOPER(scan));
            goto do_branch;
-       case BRANCH: 
+       case BRANCH:
            inner = NEXTOPER(scan);
          do_branch:
            {
-               CHECKPOINT lastcp;
                c1 = OP(scan);
                if (OP(next) != c1)     /* No choice. */
                    next = inner;       /* Avoid recursion. */
@@ -2951,7 +3108,7 @@ S_regmatch(pTHX_ regnode *prog)
        {
            I32 l = 0;
            CHECKPOINT lastcp;
-           
+       
            /* We suppose that the next guy does not need
               backtracking: in particular, it is of constant length,
               and has no parenths to influence future backrefs. */
@@ -2972,24 +3129,50 @@ S_regmatch(pTHX_ regnode *prog)
                minmod = 0;
                if (ln && regrepeat_hard(scan, ln, &l) < ln)
                    sayNO;
-               if (ln && l == 0 && n >= ln
-                   /* In fact, this is tricky.  If paren, then the
-                      fact that we did/didnot match may influence
-                      future execution. */
-                   && !(paren && ln == 0))
-                   ln = n;
+               /* if we matched something zero-length we don't need to
+                  backtrack - capturing parens are already defined, so
+                  the caveat in the maximal case doesn't apply
+
+                  XXXX if ln == 0, we can redo this check first time
+                  through the following loop
+               */
+               if (ln && l == 0)
+                   n = ln;     /* don't backtrack */
                locinput = PL_reginput;
-               if (PL_regkind[(U8)OP(next)] == EXACT) {
-                   c1 = (U8)*STRING(next);
-                   if (OP(next) == EXACTF)
-                       c2 = PL_fold[c1];
-                   else if (OP(next) == EXACTFL)
-                       c2 = PL_fold_locale[c1];
-                   else
-                       c2 = c1;
+               if (HAS_TEXT(next) || JUMPABLE(next)) {
+                   regnode *text_node = next;
+
+                   if (! HAS_TEXT(text_node)) FIND_NEXT_IMPT(text_node);
+
+                   if (! HAS_TEXT(text_node)) c1 = c2 = -1000;
+                   else {
+                       if (PL_regkind[(U8)OP(text_node)] == REF) {
+                           I32 n, ln;
+                           n = ARG(text_node);  /* which paren pair */
+                           ln = PL_regstartp[n];
+                           /* assume yes if we haven't seen CLOSEn */
+                           if (
+                               *PL_reglastparen < n ||
+                               ln == -1 ||
+                               ln == PL_regendp[n]
+                           ) {
+                               c1 = c2 = -1000;
+                               goto assume_ok_MM;
+                           }
+                           c1 = *(PL_bostr + ln);
+                       }
+                       else { c1 = (U8)*STRING(text_node); }
+                       if (OP(text_node) == EXACTF || OP(text_node) == REFF)
+                           c2 = PL_fold[c1];
+                       else if (OP(text_node) == EXACTFL || OP(text_node) == REFFL)
+                           c2 = PL_fold_locale[c1];
+                       else
+                           c2 = c1;
+                   }
                }
                else
                    c1 = c2 = -1000;
+           assume_ok_MM:
                REGCP_SET(lastcp);
                /* This may be improved if l == 0.  */
                while (n >= ln || (n == REG_INFTY && ln > 0 && l)) { /* ln overflow ? */
@@ -2999,7 +3182,7 @@ S_regmatch(pTHX_ regnode *prog)
                        UCHARAT(PL_reginput) == c2)
                    {
                        if (paren) {
-                           if (n) {
+                           if (ln) {
                                PL_regstartp[paren] =
                                    HOPc(PL_reginput, -l) - PL_bostr;
                                PL_regendp[paren] = PL_reginput - PL_bostr;
@@ -3023,12 +3206,13 @@ S_regmatch(pTHX_ regnode *prog)
            }
            else {
                n = regrepeat_hard(scan, n, &l);
-               if (n != 0 && l == 0
-                   /* In fact, this is tricky.  If paren, then the
-                      fact that we did/didnot match may influence
-                      future execution. */
-                   && !(paren && ln == 0))
-                   ln = n;
+               /* if we matched something zero-length we don't need to
+                  backtrack, unless the minimum count is zero and we
+                  are capturing the result - in that case the capture
+                  being defined or not may affect later execution
+               */
+               if (n != 0 && l == 0 && !(paren && ln == 0))
+                   ln = n;     /* don't backtrack */
                locinput = PL_reginput;
                DEBUG_r(
                    PerlIO_printf(Perl_debug_log,
@@ -3037,18 +3221,42 @@ S_regmatch(pTHX_ regnode *prog)
                                  (IV) n, (IV)l)
                    );
                if (n >= ln) {
-                   if (PL_regkind[(U8)OP(next)] == EXACT) {
-                       c1 = (U8)*STRING(next);
-                       if (OP(next) == EXACTF)
-                           c2 = PL_fold[c1];
-                       else if (OP(next) == EXACTFL)
-                           c2 = PL_fold_locale[c1];
-                       else
-                           c2 = c1;
+                   if (HAS_TEXT(next) || JUMPABLE(next)) {
+                       regnode *text_node = next;
+
+                       if (! HAS_TEXT(text_node)) FIND_NEXT_IMPT(text_node);
+
+                       if (! HAS_TEXT(text_node)) c1 = c2 = -1000;
+                       else {
+                           if (PL_regkind[(U8)OP(text_node)] == REF) {
+                               I32 n, ln;
+                               n = ARG(text_node);  /* which paren pair */
+                               ln = PL_regstartp[n];
+                               /* assume yes if we haven't seen CLOSEn */
+                               if (
+                                   *PL_reglastparen < n ||
+                                   ln == -1 ||
+                                   ln == PL_regendp[n]
+                               ) {
+                                   c1 = c2 = -1000;
+                                   goto assume_ok_REG;
+                               }
+                               c1 = *(PL_bostr + ln);
+                           }
+                           else { c1 = (U8)*STRING(text_node); }
+
+                           if (OP(text_node) == EXACTF || OP(text_node) == REFF)
+                               c2 = PL_fold[c1];
+                           else if (OP(text_node) == EXACTFL || OP(text_node) == REFFL)
+                               c2 = PL_fold_locale[c1];
+                           else
+                               c2 = c1;
+                       }
                    }
                    else
                        c1 = c2 = -1000;
                }
+           assume_ok_REG:
                REGCP_SET(lastcp);
                while (n >= ln) {
                    /* If it could work, try it. */
@@ -3114,27 +3322,66 @@ S_regmatch(pTHX_ regnode *prog)
            * Lookahead to avoid useless match attempts
            * when we know what character comes next.
            */
-           if (PL_regkind[(U8)OP(next)] == EXACT) {
-               U8 *s = (U8*)STRING(next);
-               if (!UTF) {
-                   c2 = c1 = *s;
-                   if (OP(next) == EXACTF)
-                       c2 = PL_fold[c1];
-                   else if (OP(next) == EXACTFL)
-                       c2 = PL_fold_locale[c1];
-               }
-               else { /* UTF */
-                   if (OP(next) == EXACTF) {
-                       c1 = to_utf8_lower(s);
-                       c2 = to_utf8_upper(s);
+
+           /*
+           * Used to only do .*x and .*?x, but now it allows
+           * for )'s, ('s and (?{ ... })'s to be in the way
+           * of the quantifier and the EXACT-like node.  -- japhy
+           */
+
+           if (HAS_TEXT(next) || JUMPABLE(next)) {
+               U8 *s;
+               regnode *text_node = next;
+
+               if (! HAS_TEXT(text_node)) FIND_NEXT_IMPT(text_node);
+
+               if (! HAS_TEXT(text_node)) c1 = c2 = -1000;
+               else {
+                   if (PL_regkind[(U8)OP(text_node)] == REF) {
+                       I32 n, ln;
+                       n = ARG(text_node);  /* which paren pair */
+                       ln = PL_regstartp[n];
+                       /* assume yes if we haven't seen CLOSEn */
+                       if (
+                           *PL_reglastparen < n ||
+                           ln == -1 ||
+                           ln == PL_regendp[n]
+                       ) {
+                           c1 = c2 = -1000;
+                           goto assume_ok_easy;
+                       }
+                       s = (U8*)PL_bostr + ln;
                    }
-                   else {
-                       c2 = c1 = utf8_to_uv_simple(s, NULL);
+                   else { s = (U8*)STRING(text_node); }
+
+                   if (!UTF) {
+                       c2 = c1 = *s;
+                       if (OP(text_node) == EXACTF || OP(text_node) == REFF)
+                           c2 = PL_fold[c1];
+                       else if (OP(text_node) == EXACTFL || OP(text_node) == REFFL)
+                           c2 = PL_fold_locale[c1];
+                   }
+                   else { /* UTF */
+                       if (OP(text_node) == EXACTF || OP(text_node) == REFF) {
+                            STRLEN ulen1, ulen2;
+                            U8 tmpbuf1[UTF8_MAXLEN*2+1];
+                            U8 tmpbuf2[UTF8_MAXLEN*2+1];
+
+                            to_utf8_lower((U8*)s, tmpbuf1, &ulen1);
+                            to_utf8_upper((U8*)s, tmpbuf2, &ulen2);
+
+                            c1 = utf8_to_uvuni(tmpbuf1, 0);
+                            c2 = utf8_to_uvuni(tmpbuf2, 0);
+                       }
+                       else {
+                           c2 = c1 = utf8_to_uvchr(s, NULL);
+                       }
                    }
                }
            }
            else
                c1 = c2 = -1000;
+       assume_ok_easy:
            PL_reginput = locinput;
            if (minmod) {
                CHECKPOINT lastcp;
@@ -3169,12 +3416,13 @@ S_regmatch(pTHX_ regnode *prog)
                        /* Find place 'next' could work */
                        if (!do_utf8) {
                            if (c1 == c2) {
-                               while (locinput <= e && *locinput != c1)
+                               while (locinput <= e &&
+                                      UCHARAT(locinput) != c1)
                                    locinput++;
                            } else {
-                               while (locinput <= e 
-                                      && *locinput != c1
-                                      && *locinput != c2)
+                               while (locinput <= e
+                                      && UCHARAT(locinput) != c1
+                                      && UCHARAT(locinput) != c2)
                                    locinput++;
                            }
                            count = locinput - old;
@@ -3184,20 +3432,20 @@ S_regmatch(pTHX_ regnode *prog)
                            if (c1 == c2) {
                                for (count = 0;
                                     locinput <= e &&
-                                        utf8_to_uv_simple((U8*)locinput, &len) != c1;
+                                        utf8_to_uvchr((U8*)locinput, &len) != c1;
                                     count++)
                                    locinput += len;
                                
                            } else {
                                for (count = 0; locinput <= e; count++) {
-                                   UV c = utf8_to_uv_simple((U8*)locinput, &len);
+                                   UV c = utf8_to_uvchr((U8*)locinput, &len);
                                    if (c == c1 || c == c2)
                                        break;
-                                   locinput += len;                        
+                                   locinput += len;                    
                                }
                            }
                        }
-                       if (locinput > e) 
+                       if (locinput > e)
                            sayNO;
                        /* PL_reginput == old now */
                        if (locinput != old) {
@@ -3222,12 +3470,18 @@ S_regmatch(pTHX_ regnode *prog)
                    UV c;
                    if (c1 != -1000) {
                        if (do_utf8)
-                           c = utf8_to_uv_simple((U8*)PL_reginput, NULL);
+                           c = utf8_to_uvchr((U8*)PL_reginput, NULL);
                        else
-                           c = UCHARAT(PL_reginput); 
+                           c = UCHARAT(PL_reginput);
+                       /* If it could work, try it. */
+                       if (c == c1 || c == c2)
+                       {
+                           TRYPAREN(paren, n, PL_reginput);
+                           REGCP_UNWIND(lastcp);
+                       }
                    }
                    /* If it could work, try it. */
-                   if (c1 == -1000 || c == c1 || c == c2)
+                   else if (c1 == -1000)
                    {
                        TRYPAREN(paren, n, PL_reginput);
                        REGCP_UNWIND(lastcp);
@@ -3257,13 +3511,13 @@ S_regmatch(pTHX_ regnode *prog)
                }
                REGCP_SET(lastcp);
                if (paren) {
-                   UV c;
+                   UV c = 0;
                    while (n >= ln) {
                        if (c1 != -1000) {
                            if (do_utf8)
-                               c = utf8_to_uv_simple((U8*)PL_reginput, NULL);
+                               c = utf8_to_uvchr((U8*)PL_reginput, NULL);
                            else
-                               c = UCHARAT(PL_reginput); 
+                               c = UCHARAT(PL_reginput);
                        }
                        /* If it could work, try it. */
                        if (c1 == -1000 || c == c1 || c == c2)
@@ -3277,13 +3531,13 @@ S_regmatch(pTHX_ regnode *prog)
                    }
                }
                else {
-                   UV c;
+                   UV c = 0;
                    while (n >= ln) {
                        if (c1 != -1000) {
                            if (do_utf8)
-                               c = utf8_to_uv_simple((U8*)PL_reginput, NULL);
+                               c = utf8_to_uvchr((U8*)PL_reginput, NULL);
                            else
-                               c = UCHARAT(PL_reginput); 
+                               c = UCHARAT(PL_reginput);
                        }
                        /* If it could work, try it. */
                        if (c1 == -1000 || c == c1 || c == c2)
@@ -3351,24 +3605,14 @@ S_regmatch(pTHX_ regnode *prog)
        case SUSPEND:
            n = 1;
            PL_reginput = locinput;
-           goto do_ifmatch;        
+           goto do_ifmatch;    
        case UNLESSM:
            n = 0;
            if (scan->flags) {
-               if (UTF) {              /* XXXX This is absolutely
-                                          broken, we read before
-                                          start of string. */
-                   s = HOPMAYBEc(locinput, -scan->flags);
-                   if (!s)
-                       goto say_yes;
-                   PL_reginput = s;
-               }
-               else {
-                   if (locinput < PL_bostr + scan->flags) 
-                       goto say_yes;
-                   PL_reginput = locinput - scan->flags;
-                   goto do_ifmatch;
-               }
+               s = HOPBACKc(locinput, scan->flags);
+               if (!s)
+                   goto say_yes;
+               PL_reginput = s;
            }
            else
                PL_reginput = locinput;
@@ -3376,20 +3620,10 @@ S_regmatch(pTHX_ regnode *prog)
        case IFMATCH:
            n = 1;
            if (scan->flags) {
-               if (UTF) {              /* XXXX This is absolutely
-                                          broken, we read before
-                                          start of string. */
-                   s = HOPMAYBEc(locinput, -scan->flags);
-                   if (!s || s < PL_bostr)
-                       goto say_no;
-                   PL_reginput = s;
-               }
-               else {
-                   if (locinput < PL_bostr + scan->flags) 
-                       goto say_no;
-                   PL_reginput = locinput - scan->flags;
-                   goto do_ifmatch;
-               }
+               s = HOPBACKc(locinput, scan->flags);
+               if (!s)
+                   goto say_no;
+               PL_reginput = s;
            }
            else
                PL_reginput = locinput;
@@ -3478,14 +3712,14 @@ do_no:
        {
            re_unwind_branch_t *uwb = &(uw->branch);
            I32 lastparen = uwb->lastparen;
-           
+       
            REGCP_UNWIND(uwb->lastcp);
            for (n = *PL_reglastparen; n > lastparen; n--)
                PL_regendp[n] = -1;
            *PL_reglastparen = n;
            scan = next = uwb->next;
-           if ( !scan || 
-                OP(scan) != (uwb->type == RE_UNWIND_BRANCH 
+           if ( !scan ||
+                OP(scan) != (uwb->type == RE_UNWIND_BRANCH
                              ? BRANCH : BRANCHJ) ) {           /* Failure */
                unwind = uwb->prev;
 #ifdef DEBUGGING
@@ -3539,7 +3773,7 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     register I32 c;
     register char *loceol = PL_regeol;
     register I32 hardcount = 0;
-    register bool do_utf8 = DO_UTF8(PL_reg_sv);
+    register bool do_utf8 = PL_reg_match_utf8;
 
     scan = PL_reginput;
     if (max != REG_INFTY && max < loceol - scan)
@@ -3558,15 +3792,10 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
        }
        break;
     case SANY:
-       if (do_utf8) {
-           loceol = PL_regeol;
-           while (hardcount < max && scan < loceol) {
-               scan += UTF8SKIP(scan);
-               hardcount++;
-           }
-       } else {
-           scan = loceol;
-       }
+       scan = loceol;
+       break;
+    case CANY:
+       scan = loceol;
        break;
     case EXACT:                /* length of string is 1 */
        c = (U8)*STRING(p);
@@ -3602,8 +3831,9 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     case ALNUM:
        if (do_utf8) {
            loceol = PL_regeol;
+           LOAD_UTF8_CHARCLASS(alnum,"a");
            while (hardcount < max && scan < loceol &&
-                  swash_fetch(PL_utf8_alnum, (U8*)scan)) {
+                  swash_fetch(PL_utf8_alnum, (U8*)scan, do_utf8)) {
                scan += UTF8SKIP(scan);
                hardcount++;
            }
@@ -3629,8 +3859,9 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     case NALNUM:
        if (do_utf8) {
            loceol = PL_regeol;
+           LOAD_UTF8_CHARCLASS(alnum,"a");
            while (hardcount < max && scan < loceol &&
-                  !swash_fetch(PL_utf8_alnum, (U8*)scan)) {
+                  !swash_fetch(PL_utf8_alnum, (U8*)scan, do_utf8)) {
                scan += UTF8SKIP(scan);
                hardcount++;
            }
@@ -3656,8 +3887,10 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     case SPACE:
        if (do_utf8) {
            loceol = PL_regeol;
+           LOAD_UTF8_CHARCLASS(space," ");
            while (hardcount < max && scan < loceol &&
-                  (*scan == ' ' || swash_fetch(PL_utf8_space,(U8*)scan))) {
+                  (*scan == ' ' ||
+                   swash_fetch(PL_utf8_space,(U8*)scan, do_utf8))) {
                scan += UTF8SKIP(scan);
                hardcount++;
            }
@@ -3683,8 +3916,10 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     case NSPACE:
        if (do_utf8) {
            loceol = PL_regeol;
+           LOAD_UTF8_CHARCLASS(space," ");
            while (hardcount < max && scan < loceol &&
-                  !(*scan == ' ' || swash_fetch(PL_utf8_space,(U8*)scan))) {
+                  !(*scan == ' ' ||
+                    swash_fetch(PL_utf8_space,(U8*)scan, do_utf8))) {
                scan += UTF8SKIP(scan);
                hardcount++;
            }
@@ -3710,8 +3945,9 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     case DIGIT:
        if (do_utf8) {
            loceol = PL_regeol;
+           LOAD_UTF8_CHARCLASS(digit,"0");
            while (hardcount < max && scan < loceol &&
-                  swash_fetch(PL_utf8_digit,(U8*)scan)) {
+                  swash_fetch(PL_utf8_digit, (U8*)scan, do_utf8)) {
                scan += UTF8SKIP(scan);
                hardcount++;
            }
@@ -3723,8 +3959,9 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
     case NDIGIT:
        if (do_utf8) {
            loceol = PL_regeol;
+           LOAD_UTF8_CHARCLASS(digit,"0");
            while (hardcount < max && scan < loceol &&
-                  !swash_fetch(PL_utf8_digit,(U8*)scan)) {
+                  !swash_fetch(PL_utf8_digit, (U8*)scan, do_utf8)) {
                scan += UTF8SKIP(scan);
                hardcount++;
            }
@@ -3743,29 +3980,29 @@ S_regrepeat(pTHX_ regnode *p, I32 max)
        c = scan - PL_reginput;
     PL_reginput = scan;
 
-    DEBUG_r( 
+    DEBUG_r(
        {
                SV *prop = sv_newmortal();
 
                regprop(prop, p);
-               PerlIO_printf(Perl_debug_log, 
-                             "%*s  %s can match %"IVdf" times out of %"IVdf"...\n", 
+               PerlIO_printf(Perl_debug_log,
+                             "%*s  %s can match %"IVdf" times out of %"IVdf"...\n",
                              REPORT_CODE_OFF+1, "", SvPVX(prop),(IV)c,(IV)max);
        });
-    
+
     return(c);
 }
 
 /*
  - regrepeat_hard - repeatedly match something, report total lenth and length
- * 
+ *
  * The repeater is supposed to have constant length.
  */
 
 STATIC I32
 S_regrepeat_hard(pTHX_ regnode *p, I32 max, I32 *lp)
 {
-    register char *scan;
+    register char *scan = Nullch;
     register char *start;
     register char *loceol = PL_regeol;
     I32 l = 0;
@@ -3775,7 +4012,7 @@ S_regrepeat_hard(pTHX_ regnode *p, I32 max, I32 *lp)
        return 0;
 
     start = PL_reginput;
-    if (DO_UTF8(PL_reg_sv)) {
+    if (PL_reg_match_utf8) {
        while (PL_reginput < loceol && (scan = PL_reginput, res = regmatch(p))) {
            if (!count++) {
                l = 0;
@@ -3804,7 +4041,7 @@ S_regrepeat_hard(pTHX_ regnode *p, I32 max, I32 *lp)
     }
     if (!res)
        PL_reginput = scan;
-    
+
     return count;
 }
 
@@ -3825,10 +4062,10 @@ Perl_regclass_swash(pTHX_ register regnode* node, bool doinit, SV** initsvp)
            SV *rv = (SV*)PL_regdata->data[n];
            AV *av = (AV*)SvRV((SV*)rv);
            SV **a;
-           
+       
            si = *av_fetch(av, 0, FALSE);
            a  =  av_fetch(av, 1, FALSE);
-           
+       
            if (a)
                sw = *a;
            else if (si && doinit) {
@@ -3854,36 +4091,29 @@ S_reginclass(pTHX_ register regnode *n, register U8* p, register bool do_utf8)
     char flags = ANYOF_FLAGS(n);
     bool match = FALSE;
     UV c;
-    STRLEN len;
+    STRLEN len = 0;
 
-    if (do_utf8)
-       c = utf8_to_uv_simple(p, &len);
-    else
-       c = *p;
+    c = do_utf8 ? utf8_to_uvchr(p, &len) : *p;
 
     if (do_utf8 || (flags & ANYOF_UNICODE)) {
        if (do_utf8 && !ANYOF_RUNTIME(n)) {
            if (len != (STRLEN)-1 && c < 256 && ANYOF_BITMAP_TEST(n, c))
                match = TRUE;
        }
-       if (do_utf8 && flags & ANYOF_UNICODE_ALL && c >= 256)
+       if (!match && do_utf8 && (flags & ANYOF_UNICODE_ALL) && c >= 256)
            match = TRUE;
        if (!match) {
            SV *sw = regclass_swash(n, TRUE, 0);
        
            if (sw) {
-               if (swash_fetch(sw, p))
+               if (swash_fetch(sw, p, do_utf8))
                    match = TRUE;
                else if (flags & ANYOF_FOLD) {
-                   U8 tmpbuf[UTF8_MAXLEN+1];
-                   
-                   if (flags & ANYOF_LOCALE) {
-                       PL_reg_flags |= RF_tainted;
-                       uv_to_utf8(tmpbuf, toLOWER_LC_utf8(p));
-                   }
-                   else
-                       uv_to_utf8(tmpbuf, toLOWER_utf8(p));
-                   if (swash_fetch(sw, tmpbuf))
+                   STRLEN ulen;
+                   U8 tmpbuf[UTF8_MAXLEN*2+1];
+
+                   toLOWER_utf8(p, tmpbuf, &ulen);
+                   if (swash_fetch(sw, tmpbuf, do_utf8))
                        match = TRUE;
                }
            }
@@ -3893,7 +4123,7 @@ S_reginclass(pTHX_ register regnode *n, register U8* p, register bool do_utf8)
        if (ANYOF_BITMAP_TEST(n, c))
            match = TRUE;
        else if (flags & ANYOF_FOLD) {
-           I32 f;
+         I32 f;
 
            if (flags & ANYOF_LOCALE) {
                PL_reg_flags |= RF_tainted;
@@ -3950,13 +4180,13 @@ S_reginclass(pTHX_ register regnode *n, register U8* p, register bool do_utf8)
 
 STATIC U8 *
 S_reghop(pTHX_ U8 *s, I32 off)
-{                               
+{
     return S_reghop3(aTHX_ s, off, (U8*)(off >= 0 ? PL_regeol : PL_bostr));
 }
 
 STATIC U8 *
 S_reghop3(pTHX_ U8 *s, I32 off, U8* lim)
-{                               
+{
     if (off >= 0) {
        while (off-- && s < lim) {
            /* XXX could check well-formedness here */
@@ -3980,7 +4210,7 @@ S_reghop3(pTHX_ U8 *s, I32 off, U8* lim)
 
 STATIC U8 *
 S_reghopmaybe(pTHX_ U8 *s, I32 off)
-{                               
+{
     return S_reghopmaybe3(aTHX_ s, off, (U8*)(off >= 0 ? PL_regeol : PL_bostr));
 }
 
@@ -4014,12 +4244,8 @@ S_reghopmaybe3(pTHX_ U8* s, I32 off, U8* lim)
     return s;
 }
 
-#ifdef PERL_OBJECT
-#include "XSUB.h"
-#endif
-
 static void
-restore_pos(pTHXo_ void *arg)
+restore_pos(pTHX_ void *arg)
 {
     if (PL_reg_eval_set) {
        if (PL_reg_oldsaved) {