Re: Analysis of problems with mixed encoding case insensitive matches in regex engine.
[p5sagit/p5-mst-13.2.git] / regexec.c
index e382a2a..aea0ad6 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -184,25 +184,24 @@ S_regcppush(pTHX_ I32 parenfloor)
     if (paren_elems_to_push < 0)
        Perl_croak(aTHX_ "panic: paren_elems_to_push < 0");
 
-#define REGCP_OTHER_ELEMS 8
+#define REGCP_OTHER_ELEMS 7
     SSGROW(paren_elems_to_push + REGCP_OTHER_ELEMS);
     
     for (p = PL_regsize; p > parenfloor; p--) {
 /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
-       SSPUSHINT(PL_regendp[p]);
-       SSPUSHINT(PL_regstartp[p]);
+       SSPUSHINT(PL_regoffs[p].end);
+       SSPUSHINT(PL_regoffs[p].start);
        SSPUSHPTR(PL_reg_start_tmp[p]);
        SSPUSHINT(p);
        DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
          "     saving \\%"UVuf" %"IVdf"(%"IVdf")..%"IVdf"\n",
-                     (UV)p, (IV)PL_regstartp[p],
+                     (UV)p, (IV)PL_regoffs[p].start,
                      (IV)(PL_reg_start_tmp[p] - PL_bostr),
-                     (IV)PL_regendp[p]
+                     (IV)PL_regoffs[p].end
        ));
     }
 /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
-    SSPUSHPTR(PL_regstartp);
-    SSPUSHPTR(PL_regendp);
+    SSPUSHPTR(PL_regoffs);
     SSPUSHINT(PL_regsize);
     SSPUSHINT(*PL_reglastparen);
     SSPUSHINT(*PL_reglastcloseparen);
@@ -249,8 +248,7 @@ S_regcppop(pTHX_ const regexp *rex)
     *PL_reglastcloseparen = SSPOPINT;
     *PL_reglastparen = SSPOPINT;
     PL_regsize = SSPOPINT;
-    PL_regendp=(I32 *) SSPOPPTR;
-    PL_regstartp=(I32 *) SSPOPPTR;
+    PL_regoffs=(regexp_paren_pair *) SSPOPPTR;
 
     
     /* Now restore the parentheses context. */
@@ -259,16 +257,16 @@ S_regcppop(pTHX_ const regexp *rex)
        I32 tmps;
        U32 paren = (U32)SSPOPINT;
        PL_reg_start_tmp[paren] = (char *) SSPOPPTR;
-       PL_regstartp[paren] = SSPOPINT;
+       PL_regoffs[paren].start = SSPOPINT;
        tmps = SSPOPINT;
        if (paren <= *PL_reglastparen)
-           PL_regendp[paren] = tmps;
+           PL_regoffs[paren].end = tmps;
        DEBUG_BUFFERS_r(
            PerlIO_printf(Perl_debug_log,
                          "     restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n",
-                         (UV)paren, (IV)PL_regstartp[paren],
+                         (UV)paren, (IV)PL_regoffs[paren].start,
                          (IV)(PL_reg_start_tmp[paren] - PL_bostr),
-                         (IV)PL_regendp[paren],
+                         (IV)PL_regoffs[paren].end,
                          (paren > *PL_reglastparen ? "(no)" : ""));
        );
     }
@@ -292,8 +290,8 @@ S_regcppop(pTHX_ const regexp *rex)
      * --jhi */
     for (i = *PL_reglastparen + 1; i <= rex->nparens; i++) {
        if (i > PL_regsize)
-           PL_regstartp[i] = -1;
-       PL_regendp[i] = -1;
+           PL_regoffs[i].start = -1;
+       PL_regoffs[i].end = -1;
     }
 #endif
     return input;
@@ -1112,6 +1110,15 @@ REXEC_FBC_SCAN(                                       \
 if ((!reginfo || regtry(reginfo, &s))) \
     goto got_it
 
+#define REXEC_FBC_CSCAN(CoNdUtF8,CoNd)                         \
+    if (do_utf8) {                                             \
+       REXEC_FBC_UTF8_CLASS_SCAN(CoNdUtF8);                   \
+    }                                                          \
+    else {                                                     \
+       REXEC_FBC_CLASS_SCAN(CoNd);                            \
+    }                                                          \
+    break
+    
 #define REXEC_FBC_CSCAN_PRELOAD(UtFpReLoAd,CoNdUtF8,CoNd)      \
     if (do_utf8) {                                             \
        UtFpReLoAd;                                            \
@@ -1427,6 +1434,31 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                !isDIGIT_LC_utf8((U8*)s),
                !isDIGIT_LC(*s)
            );
+       case LNBREAK:
+           REXEC_FBC_CSCAN(
+               is_LNBREAK_utf8(s),
+               is_LNBREAK_latin1(s)
+           );
+       case VERTWS:
+           REXEC_FBC_CSCAN(
+               is_VERTWS_utf8(s),
+               is_VERTWS_latin1(s)
+           );
+       case NVERTWS:
+           REXEC_FBC_CSCAN(
+               !is_VERTWS_utf8(s),
+               !is_VERTWS_latin1(s)
+           );
+       case HORIZWS:
+           REXEC_FBC_CSCAN(
+               is_HORIZWS_utf8(s),
+               is_HORIZWS_latin1(s)
+           );
+       case NHORIZWS:
+           REXEC_FBC_CSCAN(
+               !is_HORIZWS_utf8(s),
+               !is_HORIZWS_latin1(s)
+           );      
        case AHOCORASICKC:
        case AHOCORASICK: 
            {
@@ -1651,7 +1683,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
 
 static void 
 S_swap_match_buff (pTHX_ regexp *prog) {
-    I32 *t;
+    regexp_paren_pair *t;
 
     if (!prog->swap) {
     /* We have to be careful. If the previous successful match
@@ -1661,17 +1693,11 @@ S_swap_match_buff (pTHX_ regexp *prog) {
        to the re, and switch the buffer each match. If we fail
        we switch it back, otherwise we leave it swapped.
     */
-        Newxz(prog->swap, 1, regexp_paren_ofs);
-        /* no need to copy these */
-        Newxz(prog->swap->startp, 2 * (prog->nparens + 1), I32);
-       prog->swap->endp = prog->swap->startp + prog->nparens + 1;
+        Newxz(prog->swap, (prog->nparens + 1), regexp_paren_pair);
     }
-    t = prog->swap->startp;
-    prog->swap->startp = prog->startp;
-    prog->startp = t;
-    t = prog->swap->endp;
-    prog->swap->endp = prog->endp;
-    prog->endp = t;
+    t = prog->swap;
+    prog->swap = prog->offs;
+    prog->offs = t;
 }    
 
 
@@ -1698,7 +1724,6 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     I32 end_shift = 0;                 /* Same for the end. */         /* CC */
     I32 scream_pos = -1;               /* Internal iterator of scream. */
     char *scream_olds = NULL;
-    SV* const oreplsv = GvSV(PL_replgv);
     const bool do_utf8 = (bool)DO_UTF8(sv);
     I32 multiline;
     RXi_GET_DECL(prog,progi);
@@ -2084,14 +2109,8 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
 got_it:
     RX_MATCH_TAINTED_set(prog, PL_reg_flags & RF_tainted);
 
-    if (PL_reg_eval_set) {
-       /* Preserve the current value of $^R */
-       if (oreplsv != GvSV(PL_replgv))
-           sv_setsv(oreplsv, GvSV(PL_replgv));/* So that when GvSV(replgv) is
-                                                 restored, the value remains
-                                                 the same. */
+    if (PL_reg_eval_set)
        restore_pos(aTHX_ prog);
-    }
     if (prog->paren_names) 
         (void)hv_iterinit(prog->paren_names);
 
@@ -2225,15 +2244,14 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
        prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */
     }
     DEBUG_EXECUTE_r(PL_reg_starttry = *startpos);
-    prog->startp[0] = *startpos - PL_bostr;
+    prog->offs[0].start = *startpos - PL_bostr;
     PL_reginput = *startpos;
     PL_reglastparen = &prog->lastparen;
     PL_reglastcloseparen = &prog->lastcloseparen;
     prog->lastparen = 0;
     prog->lastcloseparen = 0;
     PL_regsize = 0;
-    PL_regstartp = prog->startp;
-    PL_regendp = prog->endp;
+    PL_regoffs = prog->offs;
     if (PL_reg_start_tmpl <= prog->nparens) {
        PL_reg_start_tmpl = prog->nparens*3/2 + 3;
         if(PL_reg_start_tmp)
@@ -2258,18 +2276,18 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
      * --jhi */
 #if 1
     if (prog->nparens) {
-       I32 *sp = PL_regstartp;
-       I32 *ep = PL_regendp;
+       regexp_paren_pair *pp = PL_regoffs;
        register I32 i;
        for (i = prog->nparens; i > (I32)*PL_reglastparen; i--) {
-           *++sp = -1;
-           *++ep = -1;
+           ++pp;
+           pp->start = -1;
+           pp->end = -1;
        }
     }
 #endif
     REGCP_SET(lastcp);
     if (regmatch(reginfo, progi->program + 1)) {
-       PL_regendp[0] = PL_reginput - PL_bostr;
+       PL_regoffs[0].end = PL_reginput - PL_bostr;
        return 1;
     }
     if (reginfo->cutpoint)
@@ -2600,7 +2618,7 @@ S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) {
     I32 *nums=(I32*)SvPVX(sv_dat);
     for ( n=0; n<SvIVX(sv_dat); n++ ) {
         if ((I32)*PL_reglastparen >= nums[n] &&
-            PL_regendp[nums[n]] != -1)
+            PL_regoffs[nums[n]].end != -1)
         {
             return nums[n];
         }
@@ -2608,6 +2626,26 @@ S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) {
     return 0;
 }
 
+
+/* free all slabs above current one  - called during LEAVE_SCOPE */
+
+STATIC void
+S_clear_backtrack_stack(pTHX_ void *p)
+{
+    regmatch_slab *s = PL_regmatch_slab->next;
+    PERL_UNUSED_ARG(p);
+
+    if (!s)
+       return;
+    PL_regmatch_slab->next = NULL;
+    while (s) {
+       regmatch_slab * const osl = s;
+       s = s->next;
+       Safefree(osl);
+    }
+}
+
+
 #define SETREX(Re1,Re2) \
     if (PL_reg_eval_set) PM_SETRE((PL_reg_curpm), (Re2)); \
     Re1 = (Re2)
@@ -2625,8 +2663,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
     regexp *rex = reginfo->prog;
     RXi_GET_DECL(rex,rexi);
     
-    regmatch_slab  *orig_slab;
-    regmatch_state *orig_state;
+    I32        oldsave;
 
     /* the current state. This is a cached copy of PL_regmatch_state */
     register regmatch_state *st;
@@ -2664,6 +2701,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                                during a successfull match */
     U32 lastopen = 0;       /* last open we saw */
     bool has_cutgroup = RX_HAS_CUTGROUP(rex) ? 1 : 0;   
+
+    SV* const oreplsv = GvSV(PL_replgv);
                
     
     /* these three flags are set by various ops to signal information to
@@ -2696,10 +2735,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        PL_regmatch_state = SLAB_FIRST(PL_regmatch_slab);
     }
 
-    /* remember current high-water mark for exit */
-    /* XXX this should be done with SAVE* instead */
-    orig_slab  = PL_regmatch_slab;
-    orig_state = PL_regmatch_state;
+    oldsave = PL_savestack_ix;
+    SAVEDESTRUCTOR_X(S_clear_backtrack_stack, NULL);
+    SAVEVPTR(PL_regmatch_slab);
+    SAVEVPTR(PL_regmatch_state);
 
     /* grab next free state slot */
     st = ++PL_regmatch_state;
@@ -2757,14 +2796,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
        case KEEPS:
            /* update the startpoint */
-           st->u.keeper.val = PL_regstartp[0];
+           st->u.keeper.val = PL_regoffs[0].start;
            PL_reginput = locinput;
-           PL_regstartp[0] = locinput - PL_bostr;
+           PL_regoffs[0].start = locinput - PL_bostr;
            PUSH_STATE_GOTO(KEEPS_next, next);
            /*NOT-REACHED*/
        case KEEPS_next_fail:
            /* rollback the start point change */
-           PL_regstartp[0] = st->u.keeper.val;
+           PL_regoffs[0].start = st->u.keeper.val;
            sayNO_SILENT;
            /*NOT-REACHED*/
        case EOL:
@@ -2983,7 +3022,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
             if ( ST.jump) {
                 REGCP_UNWIND(ST.cp);
                for (n = *PL_reglastparen; n > ST.lastparen; n--)
-                   PL_regendp[n] = -1;
+                   PL_regoffs[n].end = -1;
                *PL_reglastparen = n;
            }
           trie_first_try:
@@ -3202,8 +3241,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                      * pack("U0U*", 0xDF) =~ /ss/i,
                      * the 0xC3 0x9F are the UTF-8
                      * byte sequence for the U+00DF. */
+
                     if (!(do_utf8 &&
-                          toLOWER(s[0]) == 's' &&
+                          toLOWER(s[0]) == 's' &&
                           ln >= 2 &&
                           toLOWER(s[1]) == 's' &&
                           (U8)l[0] == 0xC3 &&
@@ -3498,17 +3538,17 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            n = ARG(scan);  /* which paren pair */
            type = OP(scan);
          do_ref:  
-           ln = PL_regstartp[n];
+           ln = PL_regoffs[n].start;
            PL_reg_leftiter = PL_reg_maxiter;           /* Void cache */
            if (*PL_reglastparen < n || ln == -1)
                sayNO;                  /* Do not match unless seen CLOSEn. */
-           if (ln == PL_regendp[n])
+           if (ln == PL_regoffs[n].end)
                break;
 
            s = PL_bostr + ln;
            if (do_utf8 && type != REF) {       /* REF can do byte comparison */
                char *l = locinput;
-               const char *e = PL_bostr + PL_regendp[n];
+               const char *e = PL_bostr + PL_regoffs[n].end;
                /*
                 * Note that we can't do the "other character" lookup trick as
                 * in the 8-bit case (no pun intended) because in Unicode we
@@ -3541,7 +3581,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                 (UCHARAT(s) != (type == REFF
                                  ? PL_fold : PL_fold_locale)[nextchr])))
                sayNO;
-           ln = PL_regendp[n] - ln;
+           ln = PL_regoffs[n].end - ln;
            if (locinput + ln > PL_regeol)
                sayNO;
            if (ln > 1 && (type == REF
@@ -3612,7 +3652,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, 
                    "  re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) );
                PAD_SAVE_LOCAL(old_comppad, (PAD*)rexi->data->data[n + 2]);
-               PL_regendp[0] = PL_reg_magic->mg_len = locinput - PL_bostr;
+               PL_regoffs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr;
 
                 if (sv_yes_mark) {
                     SV *sv_mrk = get_sv("REGMARK", 1);
@@ -3658,14 +3698,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                        re = reg_temp_copy((regexp *)mg->mg_obj); /*XXX:dmq*/
                    }
                    else {
-                       STRLEN len;
-                       const char * const t = SvPV_const(ret, len);
-                       PMOP pm;
+                       U32 pm_flags = 0;
                        const I32 osize = PL_regsize;
 
-                       Zero(&pm, 1, PMOP);
-                       if (DO_UTF8(ret)) pm.op_pmdynflags |= PMdf_DYN_UTF8;
-                       re = CALLREGCOMP((char*)t, (char*)t + len, &pm);
+                       if (DO_UTF8(ret)) pm_flags |= RXf_UTF8;
+                       re = CALLREGCOMP(ret, pm_flags);
                        if (!(SvFLAGS(ret)
                              & (SVs_TEMP | SVs_PADTMP | SVf_READONLY
                                | SVs_GMG)))
@@ -3698,8 +3735,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                ST.cp = regcppush(0);   /* Save *all* the positions. */
                REGCP_SET(ST.lastcp);
                
-               PL_regstartp = re->startp; /* essentially NOOP on GOSUB */
-               PL_regendp = re->endp;     /* essentially NOOP on GOSUB */
+               PL_regoffs = re->offs; /* essentially NOOP on GOSUB */
                
                *PL_reglastparen = 0;
                *PL_reglastcloseparen = 0;
@@ -3777,8 +3813,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            break;
        case CLOSE:
            n = ARG(scan);  /* which paren pair */
-           PL_regstartp[n] = PL_reg_start_tmp[n] - PL_bostr;
-           PL_regendp[n] = locinput - PL_bostr;
+           PL_regoffs[n].start = PL_reg_start_tmp[n] - PL_bostr;
+           PL_regoffs[n].end = locinput - PL_bostr;
            /*if (n > PL_regsize)
                PL_regsize = n;*/
            if (n > *PL_reglastparen)
@@ -3798,8 +3834,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                     if ( OP(cursor)==CLOSE ){
                         n = ARG(cursor);
                         if ( n <= lastopen ) {
-                            PL_regstartp[n] = PL_reg_start_tmp[n] - PL_bostr;
-                            PL_regendp[n] = locinput - PL_bostr;
+                            PL_regoffs[n].start
+                               = PL_reg_start_tmp[n] - PL_bostr;
+                            PL_regoffs[n].end = locinput - PL_bostr;
                             /*if (n > PL_regsize)
                             PL_regsize = n;*/
                             if (n > *PL_reglastparen)
@@ -3816,7 +3853,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            /*NOTREACHED*/          
        case GROUPP:
            n = ARG(scan);  /* which paren pair */
-           sw = (bool)(*PL_reglastparen >= n && PL_regendp[n] != -1);
+           sw = (bool)(*PL_reglastparen >= n && PL_regoffs[n].end != -1);
            break;
        case NGROUPP:
            /* reg_check_named_buff_matched returns 0 for no match */
@@ -3964,15 +4001,6 @@ NULL
        }
 
        case CURLYX_end: /* just finished matching all of A*B */
-           if (PL_reg_eval_set){
-               SV *pres= GvSV(PL_replgv);
-               SvREFCNT_inc(pres);
-               regcpblow(ST.cp);
-               sv_setsv(GvSV(PL_replgv), pres);
-               SvREFCNT_dec(pres);
-           } else {
-               regcpblow(ST.cp);
-           }
            cur_curlyx = ST.prev_curlyx;
            sayYES;
            /* NOTREACHED */
@@ -4234,7 +4262,7 @@ NULL
            }
            REGCP_UNWIND(ST.cp);
            for (n = *PL_reglastparen; n > ST.lastparen; n--)
-               PL_regendp[n] = -1;
+               PL_regoffs[n].end = -1;
            *PL_reglastparen = n;
            /*dmq: *PL_reglastcloseparen = n; */
            scan = ST.next_branch;
@@ -4399,13 +4427,13 @@ NULL
                /* mark current A as captured */
                I32 paren = ST.me->flags;
                if (ST.count) {
-                   PL_regstartp[paren]
+                   PL_regoffs[paren].start
                        = HOPc(PL_reginput, -ST.alen) - PL_bostr;
-                   PL_regendp[paren] = PL_reginput - PL_bostr;
+                   PL_regoffs[paren].end = PL_reginput - PL_bostr;
                    /*dmq: *PL_reglastcloseparen = paren; */
                }
                else
-                   PL_regendp[paren] = -1;
+                   PL_regoffs[paren].end = -1;
                if (cur_eval && cur_eval->u.eval.close_paren &&
                    cur_eval->u.eval.close_paren == (U32)ST.me->flags) 
                {
@@ -4439,12 +4467,12 @@ NULL
 #define CURLY_SETPAREN(paren, success) \
     if (paren) { \
        if (success) { \
-           PL_regstartp[paren] = HOPc(locinput, -1) - PL_bostr; \
-           PL_regendp[paren] = locinput - PL_bostr; \
+           PL_regoffs[paren].start = HOPc(locinput, -1) - PL_bostr; \
+           PL_regoffs[paren].end = locinput - PL_bostr; \
            *PL_reglastcloseparen = paren; \
        } \
        else \
-           PL_regendp[paren] = -1; \
+           PL_regoffs[paren].end = -1; \
     }
 
        case STAR:              /*  /A*B/ where A is width 1 */
@@ -4617,7 +4645,7 @@ NULL
        case CURLY_B_min_known_fail:
            /* failed to find B in a non-greedy match where c1,c2 valid */
            if (ST.paren && ST.count)
-               PL_regendp[ST.paren] = -1;
+               PL_regoffs[ST.paren].end = -1;
 
            PL_reginput = locinput;     /* Could be reset... */
            REGCP_UNWIND(ST.cp);
@@ -4695,7 +4723,7 @@ NULL
        case CURLY_B_min_fail:
            /* failed to find B in a non-greedy match where c1,c2 invalid */
            if (ST.paren && ST.count)
-               PL_regendp[ST.paren] = -1;
+               PL_regoffs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
            /* failed -- move forward one */
@@ -4742,7 +4770,7 @@ NULL
        case CURLY_B_max_fail:
            /* failed to find B in a greedy match */
            if (ST.paren && ST.count)
-               PL_regendp[ST.paren] = -1;
+               PL_regoffs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
            /*  back up. */
@@ -4976,6 +5004,55 @@ NULL
             sayNO;
             /* NOTREACHED */
 #undef ST
+        case FOLDCHAR:
+            n = ARG(scan);
+            if ( n == what_len_TRICKYFOLD(locinput,do_utf8,ln) ) {
+                locinput += ln;
+            } else if ( 0xDF == n && !do_utf8 && !UTF ) {
+                sayNO;
+            } else  {
+                U8 folded[UTF8_MAXBYTES_CASE+1];
+                STRLEN foldlen;
+                const char * const l = locinput;
+                char *e = PL_regeol;
+                to_uni_fold(n, folded, &foldlen);
+
+                if (ibcmp_utf8(folded, 0,  foldlen, 1,
+                              l, &e, 0,  do_utf8)) {
+                        sayNO;
+                }
+                locinput = e;
+            } 
+            nextchr = UCHARAT(locinput);  
+            break;
+        case LNBREAK:
+            if ((n=is_LNBREAK(locinput,do_utf8))) {
+                locinput += n;
+                nextchr = UCHARAT(locinput);
+            } else
+                sayNO;
+            break;
+
+#define CASE_CLASS(nAmE)                              \
+        case nAmE:                                    \
+            if ((n=is_##nAmE(locinput,do_utf8))) {    \
+                locinput += n;                        \
+                nextchr = UCHARAT(locinput);          \
+            } else                                    \
+                sayNO;                                \
+            break;                                    \
+        case N##nAmE:                                 \
+            if ((n=is_##nAmE(locinput,do_utf8))) {    \
+                sayNO;                                \
+            } else {                                  \
+                locinput += UTF8SKIP(locinput);       \
+                nextchr = UCHARAT(locinput);          \
+            }                                         \
+            break
+
+        CASE_CLASS(VERTWS);
+        CASE_CLASS(HORIZWS);
+#undef CASE_CLASS
 
        default:
            PerlIO_printf(Perl_error_log, "%"UVxf" %d\n",
@@ -5090,6 +5167,15 @@ yes:
     DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch successful!%s\n",
                          PL_colors[4], PL_colors[5]));
 
+    if (PL_reg_eval_set) {
+       /* each successfully executed (?{...}) block does the equivalent of
+        *   local $^R = do {...}
+        * When popping the save stack, all these locals would be undone;
+        * bypass this by setting the outermost saved $^R to the latest
+        * value */
+       if (oreplsv != GvSV(PL_replgv))
+           sv_setsv(oreplsv, GvSV(PL_replgv));
+    }
     result = 1;
     goto final_exit;
 
@@ -5146,20 +5232,9 @@ no_silent:
         sv_setsv(sv_err, sv_commit);
         sv_setsv(sv_mrk, sv_yes_mark);
     }
-    /* restore original high-water mark */
-    PL_regmatch_slab  = orig_slab;
-    PL_regmatch_state = orig_state;
-
-    /* free all slabs above current one */
-    if (orig_slab->next) {
-       regmatch_slab *sl = orig_slab->next;
-       orig_slab->next = NULL;
-       while (sl) {
-           regmatch_slab * const osl = sl;
-           sl = sl->next;
-           Safefree(osl);
-       }
-    }
+
+    /* clean up; in particular, free all slabs above current one */
+    LEAVE_SCOPE(oldsave);
 
     return result;
 }
@@ -5389,7 +5464,77 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
            while (scan < loceol && !isDIGIT(*scan))
                scan++;
        }
+    case LNBREAK:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && (c=is_LNBREAK_utf8(scan))) {
+               scan += c;
+               hardcount++;
+           }
+       } else {
+           /*
+             LNBREAK can match two latin chars, which is ok,
+             because we have a null terminated string, but we
+             have to use hardcount in this situation
+           */
+           while (scan < loceol && (c=is_LNBREAK_latin1(scan)))  {
+               scan+=c;
+               hardcount++;
+           }
+       }       
+       break;
+    case HORIZWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && (c=is_HORIZWS_utf8(scan))) {
+               scan += c;
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && is_HORIZWS_latin1(scan)) 
+               scan++;         
+       }       
+       break;
+    case NHORIZWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && !is_HORIZWS_utf8(scan)) {
+               scan += UTF8SKIP(scan);
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && !is_HORIZWS_latin1(scan))
+               scan++;
+
+       }       
+       break;
+    case VERTWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && (c=is_VERTWS_utf8(scan))) {
+               scan += c;
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && is_VERTWS_latin1(scan)) 
+               scan++;
+
+       }       
        break;
+    case NVERTWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && !is_VERTWS_utf8(scan)) {
+               scan += UTF8SKIP(scan);
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && !is_VERTWS_latin1(scan)) 
+               scan++;
+          
+       }       
+       break;
+
     default:           /* Called on something of 0 width. */
        break;          /* So match right here or not at all. */
     }