This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Under GLOBAL_STRUCT mgvtbl-s are const, which angers g++.
[perl5.git] / ext / XS-APItest / APItest.xs
index 8eaabdb..0269ded 100644 (file)
@@ -2,6 +2,7 @@
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#include "fakesdio.h"   /* Causes us to use PerlIO below */
 
 typedef SV *SVREF;
 typedef PTR_TBL_t *XS__APItest__PtrTable;
@@ -82,7 +83,6 @@ typedef void (freeent_function)(pTHX_ HV *, HE *);
 
 void
 test_freeent(freeent_function *f) {
-    dTHX;
     dSP;
     HV *test_hash = newHV();
     HE *victim;
@@ -148,8 +148,8 @@ bitflip_key(pTHX_ IV action, SV *field) {
                const char *const end = p + len;
                while (p < end) {
                    STRLEN len;
-                   UV chr = utf8_to_uvuni_buf((U8 *)p, (U8 *) end, &len);
-                   new_p = (char *)uvuni_to_utf8((U8 *)new_p, chr ^ 32);
+                   UV chr = utf8_to_uvchr_buf((U8 *)p, (U8 *) end, &len);
+                   new_p = (char *)uvchr_to_utf8((U8 *)new_p, chr ^ 32);
                    p += len;
                }
                SvUTF8_on(newkey);
@@ -274,7 +274,7 @@ blockhook_csc_start(pTHX_ int full)
         I32 i;
         AV *const new_av = newAV();
 
-        for (i = 0; i <= av_len(cur); i++) {
+        for (i = 0; i <= av_tindex(cur); i++) {
             av_store(new_av, i, newSVsv(*av_fetch(cur, i, 0)));
         }
 
@@ -532,12 +532,14 @@ STATIC void
 THX_run_cleanup(pTHX_ void *cleanup_code_ref)
 {
     dSP;
+    PUSHSTACK;
     ENTER;
     SAVETMPS;
     PUSHMARK(SP);
     call_sv((SV*)cleanup_code_ref, G_VOID|G_DISCARD);
     FREETMPS;
     LEAVE;
+    POPSTACK;
 }
 
 STATIC OP *
@@ -1049,7 +1051,6 @@ peep_xop(pTHX_ OP *o, OP *oldop)
 static I32
 filter_call(pTHX_ int idx, SV *buf_sv, int maxlen)
 {
-    SV   *my_sv = FILTER_DATA(idx);
     char *p;
     char *end;
     int n = FILTER_READ(idx + 1, buf_sv, maxlen);
@@ -1151,7 +1152,7 @@ bytes_cmp_utf8(bytes, utf8)
        RETVAL
 
 AV *
-test_utf8n_to_uvuni(s, len, flags)
+test_utf8n_to_uvchr(s, len, flags)
 
         SV *s
         SV *len
@@ -1162,7 +1163,7 @@ test_utf8n_to_uvuni(s, len, flags)
         STRLEN slen;
 
     CODE:
-        /* Call utf8n_to_uvuni() with the inputs.  It always asks for the
+        /* Call utf8n_to_uvchr() with the inputs.  It always asks for the
          * actual length to be returned
          *
          * Length to assume <s> is; not checked, so could have buffer overflow
@@ -1171,7 +1172,7 @@ test_utf8n_to_uvuni(s, len, flags)
         sv_2mortal((SV*)RETVAL);
 
         ret
-         = utf8n_to_uvuni((U8*) SvPV(s, slen), SvUV(len), &retlen, SvUV(flags));
+         = utf8n_to_uvchr((U8*) SvPV(s, slen), SvUV(len), &retlen, SvUV(flags));
 
         /* Returns the return value in [0]; <retlen> in [1] */
         av_push(RETVAL, newSVuv(ret));
@@ -1455,13 +1456,17 @@ common(params)
        if ((svp = hv_fetchs(params, "hash", 0)))
            hash = SvUV(*svp);
 
-       if ((svp = hv_fetchs(params, "hash_pv", 0))) {
+       if (hv_fetchs(params, "hash_pv", 0)) {
+            assert(key);
            PERL_HASH(hash, key, klen);
        }
-       if ((svp = hv_fetchs(params, "hash_sv", 0))) {
-           STRLEN len;
-           const char *const p = SvPV(keysv, len);
-           PERL_HASH(hash, p, len);
+       if (hv_fetchs(params, "hash_sv", 0)) {
+            assert(keysv);
+            {
+              STRLEN len;
+              const char *const p = SvPV(keysv, len);
+              PERL_HASH(hash, p, len);
+            }
        }
 
        result = (HE *)hv_common(hv, keysv, key, klen, flags, action, val, hash);
@@ -1534,6 +1539,22 @@ refcounted_he_fetch(key, level=0)
 
 #endif
 
+void
+test_force_keys(HV *hv)
+    PREINIT:
+        HE *he;
+       STRLEN count = 0;
+    PPCODE:
+        hv_iterinit(hv);
+        he = hv_iternext(hv);
+        while (he) {
+           SV *sv = HeSVKEY_force(he);
+           ++count;
+           EXTEND(SP, count);
+           PUSHs(sv_mortalcopy(sv));
+            he = hv_iternext(hv);
+        }
+
 =pod
 
 sub TIEHASH  { bless {}, $_[0] }
@@ -1621,6 +1642,7 @@ SV *
 AUTOLOADp(...)
     PROTOTYPE: *$
     CODE:
+        PERL_UNUSED_ARG(items);
        RETVAL = newSVpvn_flags(SvPVX(cv), SvCUR(cv), SvUTF8(cv));
     OUTPUT:
        RETVAL
@@ -1736,6 +1758,28 @@ xop_build_optree ()
     OUTPUT:
         RETVAL
 
+IV
+xop_from_custom_op ()
+    CODE:
+/* author note: this test doesn't imply Perl_custom_op_xop is or isn't public
+   API or that Perl_custom_op_xop is known to be used outside the core */
+        UNOP *unop;
+        XOP *xop;
+
+        NewOp(1102, unop, 1, UNOP);
+        unop->op_type       = OP_CUSTOM;
+        unop->op_ppaddr     = pp_xop;
+        unop->op_flags      = OPf_KIDS;
+        unop->op_private    = 0;
+        unop->op_first      = NULL;
+        unop->op_next       = NULL;
+
+        xop = Perl_custom_op_xop(aTHX_ (OP *)unop);
+        FreeOp(unop);
+        RETVAL = PTR2IV(xop);
+    OUTPUT:
+        RETVAL
+
 BOOT:
 {
     MY_CXT_INIT;
@@ -1904,6 +1948,81 @@ mxpushu()
        mXPUSHu(3);
        XSRETURN(3);
 
+void
+call_sv_C()
+PREINIT:
+    CV * i_sub;
+    GV * i_gv;
+    I32 retcnt;
+    SV * errsv;
+    char * errstr;
+    SV * miscsv = sv_newmortal();
+    HV * hv = (HV*)sv_2mortal((SV*)newHV());
+CODE:
+    i_sub = get_cv("i", 0);
+    PUSHMARK(SP);
+    /* PUTBACK not needed since this sub was called with 0 args, and is calling
+      0 args, so global SP doesn't need to be moved before a call_* */
+    retcnt = call_sv((SV*)i_sub, 0); /* try a CV* */
+    SPAGAIN;
+    SP -= retcnt; /* dont care about return count, wipe everything off */
+    sv_setpvs(miscsv, "i");
+    PUSHMARK(SP);
+    retcnt = call_sv(miscsv, 0); /* try a PV */
+    SPAGAIN;
+    SP -= retcnt;
+    /* no add and SVt_NULL are intentional, sub i should be defined already */
+    i_gv = gv_fetchpvn_flags("i", sizeof("i")-1, 0, SVt_NULL);
+    PUSHMARK(SP);
+    retcnt = call_sv((SV*)i_gv, 0); /* try a GV* */
+    SPAGAIN;
+    SP -= retcnt;
+    /* the tests below are not declaring this being public API behavior,
+       only current internal behavior, these tests can be changed in the
+       future if necessery */
+    PUSHMARK(SP);
+    retcnt = call_sv(&PL_sv_yes, 0); /* does nothing */
+    SPAGAIN;
+    SP -= retcnt;
+    PUSHMARK(SP);
+    retcnt = call_sv(&PL_sv_no, G_EVAL);
+    SPAGAIN;
+    SP -= retcnt;
+    errsv = ERRSV;
+    errstr = SvPV_nolen(errsv);
+    if(strnEQ(errstr, "Undefined subroutine &main:: called at",
+              sizeof("Undefined subroutine &main:: called at") - 1)) {
+        PUSHMARK(SP);
+        retcnt = call_sv((SV*)i_sub, 0); /* call again to increase counter */
+        SPAGAIN;
+        SP -= retcnt;
+    }
+    PUSHMARK(SP);
+    retcnt = call_sv(&PL_sv_undef,  G_EVAL);
+    SPAGAIN;
+    SP -= retcnt;
+    errsv = ERRSV;
+    errstr = SvPV_nolen(errsv);
+    if(strnEQ(errstr, "Can't use an undefined value as a subroutine reference at",
+              sizeof("Can't use an undefined value as a subroutine reference at") - 1)) {
+        PUSHMARK(SP);
+        retcnt = call_sv((SV*)i_sub, 0); /* call again to increase counter */
+        SPAGAIN;
+        SP -= retcnt;
+    }
+    PUSHMARK(SP);
+    retcnt = call_sv((SV*)hv,  G_EVAL);
+    SPAGAIN;
+    SP -= retcnt;
+    errsv = ERRSV;
+    errstr = SvPV_nolen(errsv);
+    if(strnEQ(errstr, "Not a CODE reference at",
+              sizeof("Not a CODE reference at") - 1)) {
+        PUSHMARK(SP);
+        retcnt = call_sv((SV*)i_sub, 0); /* call again to increase counter */
+        SPAGAIN;
+        SP -= retcnt;
+    }
 
 void
 call_sv(sv, flags, ...)
@@ -1965,7 +2084,7 @@ newCONSTSUB(stash, name, flags, sv)
     ALIAS:
        newCONSTSUB_flags = 1
     PREINIT:
-       CV* mycv;
+       CV* mycv = NULL;
        STRLEN len;
        const char *pv = SvPV(name, len);
     PPCODE:
@@ -1980,6 +2099,7 @@ newCONSTSUB(stash, name, flags, sv)
                break;
         }
         EXTEND(SP, 2);
+        assert(mycv);
         PUSHs( CvCONST(mycv) ? &PL_sv_yes : &PL_sv_no );
         PUSHs((SV*)CvGV(mycv));
 
@@ -2023,7 +2143,7 @@ gv_fetchmeth_type(stash, methname, type, level, flags)
     PREINIT:
         STRLEN len;
         const char * const name = SvPV_const(methname, len);
-       GV* gv;
+       GV* gv = NULL;
     PPCODE:
         switch (type) {
            case 0:
@@ -2051,7 +2171,7 @@ gv_fetchmeth_autoload_type(stash, methname, type, level, flags)
     PREINIT:
         STRLEN len;
         const char * const name = SvPV_const(methname, len);
-       GV* gv;
+       GV* gv = NULL;
     PPCODE:
         switch (type) {
            case 0:
@@ -2076,7 +2196,7 @@ gv_fetchmethod_flags_type(stash, methname, type, flags)
     int type
     I32 flags
     PREINIT:
-       GV* gv;
+       GV* gv = NULL;
     PPCODE:
         switch (type) {
            case 0:
@@ -2106,7 +2226,7 @@ gv_autoload_type(stash, methname, type, method)
     PREINIT:
         STRLEN len;
         const char * const name = SvPV_const(methname, len);
-       GV* gv;
+       GV* gv = NULL;
        I32 flags = method ? GV_AUTOLOAD_ISMETHOD : 0;
     PPCODE:
         switch (type) {
@@ -2132,7 +2252,7 @@ whichsig_type(namesv, type)
     PREINIT:
         STRLEN len;
         const char * const name = SvPV_const(namesv, len);
-        I32 i;
+        I32 i = 0;
     PPCODE:
         switch (type) {
            case 0:
@@ -2313,7 +2433,7 @@ my_caller(level)
         ST(4) = cop_hints_fetch_pvs(cx->blk_oldcop, "foo", 0);
         ST(5) = cop_hints_fetch_pvn(cx->blk_oldcop, "foo", 3, 0, 0);
         ST(6) = cop_hints_fetch_sv(cx->blk_oldcop, 
-                sv_2mortal(newSVpvn("foo", 3)), 0, 0);
+                sv_2mortal(newSVpvs("foo")), 0, 0);
 
         hv = cop_hints_2hv(cx->blk_oldcop, 0);
         ST(7) = hv ? sv_2mortal(newRV_noinc((SV *)hv)) : &PL_sv_undef;
@@ -2364,6 +2484,7 @@ utf16_to_utf8 (sv, ...)
        SV *dest;
        I32 got; /* Gah, badly thought out APIs */
     CODE:
+       if (ix) (void)SvPV_force_nolen(sv);
        source = (U8 *)SvPVbyte(sv, len);
        /* Optionally only convert part of the buffer.  */      
        if (items > 1) {
@@ -2507,13 +2628,12 @@ void
 test_rv2cv_op_cv()
     PROTOTYPE:
     PREINIT:
-       GV *troc_gv, *wibble_gv;
+       GV *troc_gv;
        CV *troc_cv;
        OP *o;
     CODE:
        troc_gv = gv_fetchpv("XS::APItest::test_rv2cv_op_cv", 0, SVt_PVGV);
        troc_cv = get_cv("XS::APItest::test_rv2cv_op_cv", 0);
-       wibble_gv = gv_fetchpv("XS::APItest::wibble", 0, SVt_PVGV);
        o = newCVREF(0, newGVOP(OP_GV, 0, troc_gv));
        if (rv2cv_op_cv(o, 0) != troc_cv) croak_fail();
        if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV) != (CV*)troc_gv)
@@ -3075,6 +3195,7 @@ CODE:
        MULTICALL;
     }
     POP_MULTICALL;
+    PERL_UNUSED_VAR(newsp);
     XSRETURN_UNDEF;
 }
 
@@ -3319,10 +3440,8 @@ OUTPUT:
 
 void
 stringify(SV *sv)
-PREINIT:
-    const char *pv;
 CODE:
-    pv = SvPV_nolen(sv);
+    (void)SvPV_nolen(sv);
 
 SV *
 HvENAME(HV *hv)
@@ -3350,6 +3469,8 @@ OUTPUT:
 SV *
 xs_cmp_undef(SV *a, SV *b)
 CODE:
+    PERL_UNUSED_ARG(a);
+    PERL_UNUSED_ARG(b);
     RETVAL = &PL_sv_undef;
 OUTPUT:
     RETVAL
@@ -3394,7 +3515,6 @@ test_newFOROP_without_slab()
 CODE:
     {
        const I32 floor = start_subparse(0,0);
-       CV * const cv = PL_compcv;
        /* The slab allocator does not like CvROOT being set. */
        CvROOT(PL_compcv) = (OP *)1;
        op_free(newFOROP(0, 0, newOP(OP_PUSHMARK, 0), 0, 0));
@@ -3459,6 +3579,14 @@ sv_mortalcopy(SV *sv)
     OUTPUT:
        RETVAL
 
+SV *
+newRV(SV *sv)
+
+void
+alias_av(AV *av, IV ix, SV *sv)
+    CODE:
+       av_store(av, ix, SvREFCNT_inc(sv));
+
 MODULE = XS::APItest PACKAGE = XS::APItest::AUTOLOADtest
 
 int
@@ -3467,6 +3595,7 @@ AUTOLOAD(...)
     SV* comms;
     SV* class_and_method;
   CODE:
+    PERL_UNUSED_ARG(items);
     class_and_method = GvSV(CvGV(cv));
     comms = get_sv("main::the_method", 1);
     if (class_and_method == NULL) {
@@ -3517,7 +3646,7 @@ test_get_vtbl()
        MGVTBL *want;
     CODE:
 #define test_get_this_vtable(name) \
-       want = CAT2(&PL_vtbl_, name); \
+       want = (MGVTBL*)CAT2(&PL_vtbl_, name); \
        have = get_vtbl(CAT2(want_vtbl_, name)); \
        if (have != want) \
            croak("fail %p!=%p for get_vtbl(want_vtbl_" STRINGIFY(name) ") at " __FILE__ " line %d", have, want, __LINE__)
@@ -4667,3 +4796,18 @@ test_toTITLE_utf8(SV * p)
         RETVAL = av;
     OUTPUT:
         RETVAL
+
+SV *
+test_Gconvert(SV * number, SV * num_digits)
+    PREINIT:
+        char buffer[100];
+        int len;
+    CODE:
+        len = (int) SvIV(num_digits);
+        if (len > 99) croak("Too long a number for test_Gconvert");
+        PERL_UNUSED_RESULT(Gconvert(SvNV(number), len,
+                 0,    /* No trailing zeroes */
+                 buffer));
+        RETVAL = newSVpv(buffer, 0);
+    OUTPUT:
+        RETVAL