This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Minor updates of the charnames documentation.
[perl5.git] / pp_ctl.c
index ed392cc..55ec3c3 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1,6 +1,7 @@
 /*    pp_ctl.c
  *
- *    Copyright (c) 1991-2002, Larry Wall
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ *    2000, 2001, 2002, 2003, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -21,7 +22,7 @@
 #include "perl.h"
 
 #ifndef WORD_ALIGN
-#define WORD_ALIGN sizeof(U16)
+#define WORD_ALIGN sizeof(U32)
 #endif
 
 #define DOCATCH(o) ((CATCH_GET == TRUE) ? docatch(o) : (o))
@@ -97,7 +98,7 @@ PP(pp_regcomp)
            memNE(PM_GETRE(pm)->precomp, t, len))
        {
            if (PM_GETRE(pm)) {
-               ReREFCNT_dec(PM_GETRE(pm));
+               ReREFCNT_dec(PM_GETRE(pm));
                PM_SETRE(pm, Null(REGEXP*));    /* crucial if regcomp aborts */
            }
            if (PL_op->op_flags & OPf_SPECIAL)
@@ -156,9 +157,19 @@ PP(pp_substcont)
     register char *m = cx->sb_m;
     char *orig = cx->sb_orig;
     register REGEXP *rx = cx->sb_rx;
+    SV *nsv = Nullsv;
+
+    { 
+      REGEXP *old = PM_GETRE(pm);
+      if(old != rx) {
+       if(old) 
+         ReREFCNT_dec(old);
+       PM_SETRE(pm,rx);
+      }
+    }
 
     rxres_restore(&cx->sb_rxres, rx);
-    PL_reg_match_utf8 = SvUTF8(cx->sb_targ) ? 1 : 0;
+    RX_MATCH_UTF8_set(rx, SvUTF8(cx->sb_targ));
 
     if (cx->sb_iters++) {
        I32 saviters = cx->sb_iters;
@@ -178,11 +189,22 @@ PP(pp_substcont)
        {
            SV *targ = cx->sb_targ;
 
-           sv_catpvn(dstr, s, cx->sb_strend - s);
+           if (DO_UTF8(dstr) && !SvUTF8(targ))
+               sv_catpvn_utf8_upgrade(dstr, s, cx->sb_strend - s, nsv);
+           else
+               sv_catpvn(dstr, s, cx->sb_strend - s);
            cx->sb_rxtainted |= RX_MATCH_TAINTED(rx);
 
-           (void)SvOOK_off(targ);
-           Safefree(SvPVX(targ));
+#ifdef PERL_COPY_ON_WRITE
+           if (SvIsCOW(targ)) {
+               sv_force_normal_flags(targ, SV_COW_DROP_PV);
+           } else
+#endif
+           {
+               (void)SvOOK_off(targ);
+               if (SvLEN(targ))
+                   Safefree(SvPVX(targ));
+           }
            SvPVX(targ) = SvPVX(dstr);
            SvCUR_set(targ, SvCUR(dstr));
            SvLEN_set(targ, SvLEN(dstr));
@@ -192,7 +214,7 @@ PP(pp_substcont)
            sv_free(dstr);
 
            TAINT_IF(cx->sb_rxtainted & 1);
-           PUSHs(sv_2mortal(newSViv((I32)cx->sb_iters - 1)));
+           PUSHs(sv_2mortal(newSViv(saviters - 1)));
 
            (void)SvPOK_only_UTF8(targ);
            TAINT_IF(cx->sb_rxtainted);
@@ -200,6 +222,7 @@ PP(pp_substcont)
            SvTAINT(targ);
 
            LEAVE_SCOPE(cx->sb_oldsave);
+           ReREFCNT_dec(rx);
            POPSUBST(cx);
            RETURNOP(pm->op_next);
        }
@@ -213,8 +236,12 @@ PP(pp_substcont)
        cx->sb_strend = s + (cx->sb_strend - m);
     }
     cx->sb_m = m = rx->startp[0] + orig;
-    if (m > s)
-       sv_catpvn(dstr, s, m-s);
+    if (m > s) {
+       if (DO_UTF8(dstr) && !SvUTF8(cx->sb_targ)) 
+           sv_catpvn_utf8_upgrade(dstr, s, m - s, nsv);
+       else
+           sv_catpvn(dstr, s, m-s);
+    }
     cx->sb_s = rx->endp[0] + orig;
     { /* Update the pos() information. */
        SV *sv = cx->sb_targ;
@@ -231,6 +258,7 @@ PP(pp_substcont)
            sv_pos_b2u(sv, &i);
        mg->mg_len = i;
     }
+    ReREFCNT_inc(rx);
     cx->sb_rxtainted |= RX_MATCH_TAINTED(rx);
     rxres_save(&cx->sb_rxres, rx);
     RETURNOP(pm->op_pmreplstart);
@@ -243,7 +271,11 @@ Perl_rxres_save(pTHX_ void **rsp, REGEXP *rx)
     U32 i;
 
     if (!p || p[1] < rx->nparens) {
+#ifdef PERL_COPY_ON_WRITE
+       i = 7 + rx->nparens * 2;
+#else
        i = 6 + rx->nparens * 2;
+#endif
        if (!p)
            New(501, p, i, UV);
        else
@@ -254,6 +286,11 @@ Perl_rxres_save(pTHX_ void **rsp, REGEXP *rx)
     *p++ = PTR2UV(RX_MATCH_COPIED(rx) ? rx->subbeg : Nullch);
     RX_MATCH_COPIED_off(rx);
 
+#ifdef PERL_COPY_ON_WRITE
+    *p++ = PTR2UV(rx->saved_copy);
+    rx->saved_copy = Nullsv;
+#endif
+
     *p++ = rx->nparens;
 
     *p++ = PTR2UV(rx->subbeg);
@@ -270,11 +307,17 @@ Perl_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
     UV *p = (UV*)*rsp;
     U32 i;
 
-    if (RX_MATCH_COPIED(rx))
-       Safefree(rx->subbeg);
+    RX_MATCH_COPY_FREE(rx);
     RX_MATCH_COPIED_set(rx, *p);
     *p++ = 0;
 
+#ifdef PERL_COPY_ON_WRITE
+    if (rx->saved_copy)
+       SvREFCNT_dec (rx->saved_copy);
+    rx->saved_copy = INT2PTR(SV*,*p);
+    *p++ = 0;
+#endif
+
     rx->nparens = *p++;
 
     rx->subbeg = INT2PTR(char*,*p++);
@@ -292,6 +335,11 @@ Perl_rxres_free(pTHX_ void **rsp)
 
     if (p) {
        Safefree(INT2PTR(char*,*p));
+#ifdef PERL_COPY_ON_WRITE
+       if (p[1]) {
+           SvREFCNT_dec (INT2PTR(SV*,p[1]));
+       }
+#endif
        Safefree(p);
        *rsp = Null(void*);
     }
@@ -301,7 +349,7 @@ PP(pp_formline)
 {
     dSP; dMARK; dORIGMARK;
     register SV *tmpForm = *++MARK;
-    register U16 *fpc;
+    register U32 *fpc;
     register char *t;
     register char *f;
     register char *s;
@@ -319,7 +367,9 @@ PP(pp_formline)
     bool gotsome = FALSE;
     STRLEN len;
     STRLEN fudge = SvCUR(tmpForm) * (IN_BYTES ? 1 : 3) + 1;
-    bool item_is_utf = FALSE;
+    bool item_is_utf8 = FALSE;
+    bool targ_is_utf8 = FALSE;
+    SV * nsv = Nullsv;
 
     if (!SvMAGICAL(tmpForm) || !SvCOMPILED(tmpForm)) {
        if (SvREADONLY(tmpForm)) {
@@ -330,15 +380,16 @@ PP(pp_formline)
        else
            doparseform(tmpForm);
     }
-
     SvPV_force(PL_formtarget, len);
+    if (DO_UTF8(PL_formtarget))
+       targ_is_utf8 = TRUE;
     t = SvGROW(PL_formtarget, len + fudge + 1);  /* XXX SvCUR bad */
     t += len;
     f = SvPV(tmpForm, len);
     /* need to jump to the next word */
     s = f + len + WORD_ALIGN - SvCUR(tmpForm) % WORD_ALIGN;
 
-    fpc = (U16*)s;
+    fpc = (U32*)s;
 
     for (;;) {
        DEBUG_f( {
@@ -378,6 +429,21 @@ PP(pp_formline)
 
        case FF_LITERAL:
            arg = *fpc++;
+           if (targ_is_utf8 && !SvUTF8(tmpForm)) {
+               SvCUR_set(PL_formtarget, t - SvPVX(PL_formtarget));
+               *t = '\0';
+               sv_catpvn_utf8_upgrade(PL_formtarget, f, arg, nsv);
+               t = SvEND(PL_formtarget);
+               break;
+           }
+           if (!targ_is_utf8 && DO_UTF8(tmpForm)) {
+               SvCUR_set(PL_formtarget, t - SvPVX(PL_formtarget));
+               *t = '\0';
+               sv_utf8_upgrade(PL_formtarget);
+               SvGROW(PL_formtarget, SvCUR(PL_formtarget) + fudge + 1);
+               t = SvEND(PL_formtarget);
+               targ_is_utf8 = TRUE;
+           }
            while (arg--)
                *t++ = *f++;
            break;
@@ -422,13 +488,13 @@ PP(pp_formline)
                            break;
                        s++;
                    }
-                   item_is_utf = TRUE;
+                   item_is_utf8 = TRUE;
                    itemsize = s - item;
                    sv_pos_b2u(sv, &itemsize);
                    break;
                }
            }
-           item_is_utf = FALSE;
+           item_is_utf8 = FALSE;
            if (itemsize > fieldsize)
                itemsize = fieldsize;
            send = chophere = s + itemsize;
@@ -483,11 +549,11 @@ PP(pp_formline)
                        itemsize = chophere - item;
                        sv_pos_b2u(sv, &itemsize);
                    }
-                   item_is_utf = TRUE;
+                   item_is_utf8 = TRUE;
                    break;
                }
            }
-           item_is_utf = FALSE;
+           item_is_utf8 = FALSE;
            if (itemsize <= fieldsize) {
                send = chophere = s + itemsize;
                while (s < send) {
@@ -543,7 +609,15 @@ PP(pp_formline)
        case FF_ITEM:
            arg = itemsize;
            s = item;
-           if (item_is_utf) {
+           if (item_is_utf8) {
+               if (!targ_is_utf8) {
+                   SvCUR_set(PL_formtarget, t - SvPVX(PL_formtarget));
+                   *t = '\0';
+                   sv_utf8_upgrade(PL_formtarget);
+                   SvGROW(PL_formtarget, SvCUR(PL_formtarget) + fudge + 1);
+                   t = SvEND(PL_formtarget);
+                   targ_is_utf8 = TRUE;
+               }
                while (arg--) {
                    if (UTF8_IS_CONTINUED(*s)) {
                        STRLEN skip = UTF8SKIP(s);
@@ -569,6 +643,21 @@ PP(pp_formline)
                }
                break;
            }
+           if (targ_is_utf8 && !item_is_utf8) {
+               SvCUR_set(PL_formtarget, t - SvPVX(PL_formtarget));
+               *t = '\0';
+               sv_catpvn_utf8_upgrade(PL_formtarget, s, arg, nsv);
+               for (; t < SvEND(PL_formtarget); t++) {
+#ifdef EBCDIC
+                   int ch = *t++ = *s++;
+                   if (iscntrl(ch))
+#else
+                   if (!(*t & ~31))
+#endif
+                       *t = ' ';
+               }
+               break;
+           }
            while (arg--) {
 #ifdef EBCDIC
                int ch = *t++ = *s++;
@@ -592,22 +681,32 @@ PP(pp_formline)
        case FF_LINEGLOB:
            item = s = SvPV(sv, len);
            itemsize = len;
-           item_is_utf = FALSE;                /* XXX is this correct? */
+           if ((item_is_utf8 = DO_UTF8(sv)))
+               itemsize = sv_len_utf8(sv);         
            if (itemsize) {
+               bool chopped = FALSE;
                gotsome = TRUE;
-               send = s + itemsize;
+               send = s + len;
                while (s < send) {
                    if (*s++ == '\n') {
-                       if (s == send)
+                       if (s == send) {
                            itemsize--;
+                           chopped = TRUE;
+                       }
                        else
                            lines++;
                    }
                }
                SvCUR_set(PL_formtarget, t - SvPVX(PL_formtarget));
-               sv_catpvn(PL_formtarget, item, itemsize);
+               if (targ_is_utf8)
+                   SvUTF8_on(PL_formtarget);
+               sv_catsv(PL_formtarget, sv);
+               if (chopped)
+                   SvCUR_set(PL_formtarget, SvCUR(PL_formtarget) - 1);
                SvGROW(PL_formtarget, SvCUR(PL_formtarget) + fudge + 1);
                t = SvPVX(PL_formtarget) + SvCUR(PL_formtarget);
+               if (item_is_utf8)
+                   targ_is_utf8 = TRUE;
            }
            break;
 
@@ -703,6 +802,8 @@ PP(pp_formline)
                        if (strnEQ(linemark, linemark - arg, arg))
                            DIE(aTHX_ "Runaway format");
                    }
+                   if (targ_is_utf8)
+                       SvUTF8_on(PL_formtarget);
                    FmLINES(PL_formtarget) = lines;
                    SP = ORIGMARK;
                    RETURNOP(cLISTOP->op_first);
@@ -742,6 +843,8 @@ PP(pp_formline)
        case FF_END:
            *t = '\0';
            SvCUR_set(PL_formtarget, t - SvPVX(PL_formtarget));
+           if (targ_is_utf8)
+               SvUTF8_on(PL_formtarget);
            FmLINES(PL_formtarget) += lines;
            SP = ORIGMARK;
            RETPUSHYES;
@@ -1226,8 +1329,6 @@ OP *
 Perl_die_where(pTHX_ char *message, STRLEN msglen)
 {
     STRLEN n_a;
-    IO *io;
-    MAGIC *mg;
 
     if (PL_in_eval) {
        I32 cxix;
@@ -1262,8 +1363,6 @@ Perl_die_where(pTHX_ char *message, STRLEN msglen)
                sv_setpvn(ERRSV, message, msglen);
            }
        }
-       else
-           message = SvPVx(ERRSV, msglen);
 
        while ((cxix = dopoptoeval(cxstack_ix)) < 0
               && PL_curstackinfo->si_prev)
@@ -1280,6 +1379,8 @@ Perl_die_where(pTHX_ char *message, STRLEN msglen)
 
            POPBLOCK(cx,PL_curpm);
            if (CxTYPE(cx) != CXt_EVAL) {
+               if (!message)
+                   message = SvPVx(ERRSV, msglen);
                PerlIO_write(Perl_error_log, "panic: die ", 11);
                PerlIO_write(Perl_error_log, message, msglen);
                my_exit(1);
@@ -1309,30 +1410,7 @@ Perl_die_where(pTHX_ char *message, STRLEN msglen)
     if (!message)
        message = SvPVx(ERRSV, msglen);
 
-    /* if STDERR is tied, print to it instead */
-    if (PL_stderrgv && (io = GvIOp(PL_stderrgv))
-       && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) {
-       dSP; ENTER;
-       PUSHMARK(SP);
-       XPUSHs(SvTIED_obj((SV*)io, mg));
-       XPUSHs(sv_2mortal(newSVpvn(message, msglen)));
-       PUTBACK;
-       call_method("PRINT", G_SCALAR);
-       LEAVE;
-    }
-    else {
-#ifdef USE_SFIO
-       /* SFIO can really mess with your errno */
-       int e = errno;
-#endif
-       PerlIO *serr = Perl_error_log;
-
-       PERL_WRITE_MSG_TO_CONSOLE(serr, message, msglen);
-       (void)PerlIO_flush(serr);
-#ifdef USE_SFIO
-       errno = e;
-#endif
-    }
+    write_to_stderr(message, msglen);
     my_failure_exit();
     /* NOTREACHED */
     return 0;
@@ -1544,8 +1622,18 @@ PP(pp_caller)
                (old_warnings == pWARN_STD && (PL_dowarn & G_WARN_ON) == 0))
             mask = newSVpvn(WARN_NONEstring, WARNsize) ;
         else if (old_warnings == pWARN_ALL ||
-                 (old_warnings == pWARN_STD && PL_dowarn & G_WARN_ON))
-            mask = newSVpvn(WARN_ALLstring, WARNsize) ;
+                 (old_warnings == pWARN_STD && PL_dowarn & G_WARN_ON)) {
+           /* Get the bit mask for $warnings::Bits{all}, because
+            * it could have been extended by warnings::register */
+           SV **bits_all;
+           HV *bits = get_hv("warnings::Bits", FALSE);
+           if (bits && (bits_all=hv_fetch(bits, "all", 3, FALSE))) {
+               mask = newSVsv(*bits_all);
+           }
+           else {
+               mask = newSVpvn(WARN_ALLstring, WARNsize) ;
+           }
+       }
         else
             mask = newSVsv(old_warnings);
         PUSHs(sv_2mortal(mask));
@@ -1582,7 +1670,8 @@ PP(pp_dbstate)
     PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
     FREETMPS;
 
-    if (PL_op->op_private || SvIV(PL_DBsingle) || SvIV(PL_DBsignal) || SvIV(PL_DBtrace))
+    if (PL_op->op_flags & OPf_SPECIAL /* breakpoint */
+           || SvIV(PL_DBsingle) || SvIV(PL_DBsignal) || SvIV(PL_DBtrace))
     {
        dSP;
        register CV *cv;
@@ -1611,7 +1700,7 @@ PP(pp_dbstate)
 
        push_return(PL_op->op_next);
        PUSHBLOCK(cx, CXt_SUB, SP);
-       PUSHSUB(cx);
+       PUSHSUB_DB(cx);
        CvDEPTH(cv)++;
        (void)SvREFCNT_inc(cv);
        PAD_SET_CUR(CvPADLIST(cv),1);
@@ -1847,6 +1936,7 @@ PP(pp_return)
     }
     PL_stack_sp = newsp;
 
+    LEAVE;
     /* Stack values are safe: */
     if (popsub2) {
        POPSUB(cx,sv);  /* release CV and @_ ... */
@@ -1855,7 +1945,6 @@ PP(pp_return)
        sv = Nullsv;
     PL_curpm = newpm;  /* ... and pop $1 et al */
 
-    LEAVE;
     LEAVESUB(sv);
     if (clear_errsv)
        sv_setpv(ERRSV,"");
@@ -1931,6 +2020,7 @@ PP(pp_last)
     SP = newsp;
     PUTBACK;
 
+    LEAVE;
     /* Stack values are safe: */
     switch (pop2) {
     case CXt_LOOP:
@@ -1943,7 +2033,6 @@ PP(pp_last)
     }
     PL_curpm = newpm;  /* ... and pop $1 et al */
 
-    LEAVE;
     LEAVESUB(sv);
     return nextop;
 }
@@ -2013,6 +2102,7 @@ S_dofindlabel(pTHX_ OP *o, char *label, OP **opstack, OP **oplimit)
     if (o->op_type == OP_LEAVE ||
        o->op_type == OP_SCOPE ||
        o->op_type == OP_LEAVELOOP ||
+       o->op_type == OP_LEAVESUB ||
        o->op_type == OP_LEAVETRY)
     {
        *ops++ = cUNOPo->op_first;
@@ -2100,6 +2190,8 @@ PP(pp_goto)
            }
 
            /* First do some returnish stuff. */
+           SvREFCNT_inc(cv); /* avoid premature free during unwind */
+           FREETMPS;
            cxix = dopoptosub(cxstack_ix);
            if (cxix < 0)
                DIE(aTHX_ "Can't goto subroutine outside a subroutine");
@@ -2128,6 +2220,8 @@ PP(pp_goto)
                    AvFLAGS(av) = AVf_REIFY;
                    PAD_SVl(0) = (SV*)(cx->blk_sub.argarray = av);
                }
+               else
+                   CLEAR_ARGARRAY(av);
            }
            else if (CvXSUB(cv)) {      /* put GvAV(defgv) back onto stack */
                AV* av;
@@ -2146,6 +2240,7 @@ PP(pp_goto)
 
            /* Now do some callish stuff. */
            SAVETMPS;
+           SAVEFREESV(cv); /* later, undo the 'avoid premature free' hack */
            if (CvXSUB(cv)) {
 #ifdef PERL_XSUB_OLDSTYLE
                if (CvOLDSTYLE(cv)) {
@@ -2239,7 +2334,10 @@ PP(pp_goto)
                    CV *gotocv;
                
                    if (PERLDB_SUB_NN) {
-                       SvIVX(sv) = PTR2IV(cv); /* Already upgraded, saved */
+                       (void)SvUPGRADE(sv, SVt_PVIV);
+                       (void)SvIOK_on(sv);
+                       SAVEIV(SvIVX(sv));
+                       SvIVX(sv) = PTR2IV(cv); /* Do it the quickest way */
                    } else {
                        save_item(sv);
                        gv_efullname3(sv, CvGV(cv), Nullch);
@@ -2270,6 +2368,7 @@ PP(pp_goto)
     if (label && *label) {
        OP *gotoprobe = 0;
        bool leaving_eval = FALSE;
+       bool in_block = FALSE;
         PERL_CONTEXT *last_eval_cx = 0;
 
        /* find label */
@@ -2281,7 +2380,7 @@ PP(pp_goto)
            switch (CxTYPE(cx)) {
            case CXt_EVAL:
                leaving_eval = TRUE;
-                if (CxREALEVAL(cx)) {
+                if (!CxTRYBLOCK(cx)) {
                    gotoprobe = (last_eval_cx ?
                                last_eval_cx->blk_eval.old_eval_root :
                                PL_eval_root);
@@ -2295,9 +2394,10 @@ PP(pp_goto)
            case CXt_SUBST:
                continue;
            case CXt_BLOCK:
-               if (ix)
+               if (ix) {
                    gotoprobe = cx->blk_oldcop->op_sibling;
-               else
+                   in_block = TRUE;
+               } else
                    gotoprobe = PL_main_root;
                break;
            case CXt_SUB:
@@ -2354,7 +2454,8 @@ PP(pp_goto)
 
        if (*enterops && enterops[1]) {
            OP *oldop = PL_op;
-           for (ix = 1; enterops[ix]; ix++) {
+           ix = enterops[1]->op_type == OP_ENTER && in_block ? 2 : 1;
+           for (; enterops[ix]; ix++) {
                PL_op = enterops[ix];
                /* Eventually we may want to stack the needed arguments
                 * for each op.  For now, we punt on the hard ones. */
@@ -2730,8 +2831,7 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
     else
        sv_setpv(ERRSV,"");
     if (yyparse() || PL_error_count || !PL_eval_root) {
-       SV **newsp;
-       I32 gimme;
+       SV **newsp;                     /* Used by POPBLOCK. */
        PERL_CONTEXT *cx;
        I32 optype = 0;                 /* Might be reset by POPEVAL. */
        STRLEN n_a;
@@ -2775,7 +2875,16 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
        *startop = PL_eval_root;
     } else
        SAVEFREEOP(PL_eval_root);
-    if (gimme & G_VOID)
+
+    /* Set the context for this new optree.
+     * If the last op is an OP_REQUIRE, force scalar context.
+     * Otherwise, propagate the context from the eval(). */
+    if (PL_eval_root->op_type == OP_LEAVEEVAL
+           && cUNOPx(PL_eval_root)->op_first->op_type == OP_LINESEQ
+           && cLISTOPx(cUNOPx(PL_eval_root)->op_first)->op_last->op_type
+           == OP_REQUIRE)
+       scalar(PL_eval_root);
+    else if (gimme & G_VOID)
        scalarvoid(PL_eval_root);
     else if (gimme & G_ARRAY)
        list(PL_eval_root);
@@ -2807,8 +2916,9 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
 }
 
 STATIC PerlIO *
-S_doopen_pmc(pTHX_ const char *name, const char *mode)
+S_doopen_pm(pTHX_ const char *name, const char *mode)
 {
+#ifndef PERL_DISABLE_PMC
     STRLEN namelen = strlen(name);
     PerlIO *fp;
 
@@ -2836,6 +2946,9 @@ S_doopen_pmc(pTHX_ const char *name, const char *mode)
        fp = PerlIO_open(name, mode);
     }
     return fp;
+#else
+    return PerlIO_open(name, mode);
+#endif /* !PERL_DISABLE_PMC */
 }
 
 PP(pp_require)
@@ -2934,7 +3047,7 @@ PP(pp_require)
 
     if (path_is_absolute(name)) {
        tryname = name;
-       tryrsfp = doopen_pmc(name,PERL_SCRIPT_MODE);
+       tryrsfp = doopen_pm(name,PERL_SCRIPT_MODE);
     }
 #ifdef MACOS_TRADITIONAL
     if (!tryrsfp) {
@@ -2943,7 +3056,7 @@ PP(pp_require)
        MacPerl_CanonDir(name, newname, 1);
        if (path_is_absolute(newname)) {
            tryname = newname;
-           tryrsfp = doopen_pmc(newname,PERL_SCRIPT_MODE);
+           tryrsfp = doopen_pm(newname,PERL_SCRIPT_MODE);
        }
     }
 #endif
@@ -3098,7 +3211,7 @@ PP(pp_require)
 #endif
                    TAINT_PROPER("require");
                    tryname = SvPVX(namesv);
-                   tryrsfp = doopen_pmc(tryname, PERL_SCRIPT_MODE);
+                   tryrsfp = doopen_pm(tryname, PERL_SCRIPT_MODE);
                    if (tryrsfp) {
                        if (tryname[0] == '.' && tryname[1] == '/')
                            tryname += 2;
@@ -3439,16 +3552,25 @@ S_doparseform(pTHX_ SV *sv)
     bool noblank   = FALSE;
     bool repeat    = FALSE;
     bool postspace = FALSE;
-    U16 *fops;
-    register U16 *fpc;
-    U16 *linepc = 0;
+    U32 *fops;
+    register U32 *fpc;
+    U32 *linepc = 0;
     register I32 arg;
     bool ischop;
+    int maxops = 2; /* FF_LINEMARK + FF_END) */
 
     if (len == 0)
        Perl_croak(aTHX_ "Null picture in formline");
 
-    New(804, fops, (send - s)*3+10, U16);    /* Almost certainly too long... */
+    /* estimate the buffer size needed */
+    for (base = s; s <= send; s++) {
+       if (*s == '\n' || *s == '@' || *s == '^')
+           maxops += 10;
+    }
+    s = base;
+    base = Nullch;
+
+    New(804, fops, maxops, U32);
     fpc = fops;
 
     if (s < send) {
@@ -3611,14 +3733,15 @@ S_doparseform(pTHX_ SV *sv)
     }
     *fpc++ = FF_END;
 
+    assert (fpc <= fops + maxops); /* ensure our buffer estimate was valid */
     arg = fpc - fops;
     { /* need to jump to the next word */
         int z;
        z = WORD_ALIGN - SvCUR(sv) % WORD_ALIGN;
-       SvGROW(sv, SvCUR(sv) + z + arg * sizeof(U16) + 4);
+       SvGROW(sv, SvCUR(sv) + z + arg * sizeof(U32) + 4);
        s = SvPVX(sv) + SvCUR(sv) + z;
     }
-    Copy(fops, s, arg, U16);
+    Copy(fops, s, arg, U32);
     Safefree(fops);
     sv_magic(sv, Nullsv, PERL_MAGIC_fm, Nullch, 0);
     SvCOMPILED_on(sv);