📄 apitest.xs
字号:
#define PERL_IN_XS_APITEST#include "EXTERN.h"#include "perl.h"#include "XSUB.h"/* for my_cxt tests */#define MY_CXT_KEY "XS::APItest::_guts" XS_VERSIONtypedef struct { int i; SV *sv;} my_cxt_t;START_MY_CXT/* indirect functions to test the [pa]MY_CXT macros */intmy_cxt_getint_p(pMY_CXT){ return MY_CXT.i;}voidmy_cxt_setint_p(pMY_CXT_ int i){ MY_CXT.i = i;}SV*my_cxt_getsv_interp(void){#ifdef PERL_IMPLICIT_CONTEXT dTHX; dMY_CXT_INTERP(my_perl);#else dMY_CXT;#endif return MY_CXT.sv;}voidmy_cxt_setsv_p(SV* sv _pMY_CXT){ MY_CXT.sv = sv;}/* from exception.c */int apitest_exception(int);/* from core_or_not.inc */bool sv_setsv_cow_hashkey_core(void);bool sv_setsv_cow_hashkey_notcore(void);/* A routine to test hv_delayfree_ent (which itself is tested by testing on hv_free_ent */typedef void (freeent_function)(pTHX_ HV *, register HE *);voidtest_freeent(freeent_function *f) { dTHX; dSP; HV *test_hash = newHV(); HE *victim; SV *test_scalar; U32 results[4]; int i;#ifdef PURIFY victim = (HE*)safemalloc(sizeof(HE));#else /* Storing then deleting something should ensure that a hash entry is available. */ hv_store(test_hash, "", 0, &PL_sv_yes, 0); hv_delete(test_hash, "", 0, 0); /* We need to "inline" new_he here as it's static, and the functions we test expect to be able to call del_HE on the HE */ if (!PL_body_roots[HE_SVSLOT]) croak("PL_he_root is 0"); victim = (HE*) PL_body_roots[HE_SVSLOT]; PL_body_roots[HE_SVSLOT] = HeNEXT(victim);#endif victim->hent_hek = Perl_share_hek(aTHX_ "", 0, 0); test_scalar = newSV(0); SvREFCNT_inc(test_scalar); HeVAL(victim) = test_scalar; /* Need this little game else we free the temps on the return stack. */ results[0] = SvREFCNT(test_scalar); SAVETMPS; results[1] = SvREFCNT(test_scalar); f(aTHX_ test_hash, victim); results[2] = SvREFCNT(test_scalar); FREETMPS; results[3] = SvREFCNT(test_scalar); i = 0; do { mPUSHu(results[i]); } while (++i < sizeof(results)/sizeof(results[0])); /* Goodbye to our extra reference. */ SvREFCNT_dec(test_scalar);}static I32bitflip_key(pTHX_ IV action, SV *field) { MAGIC *mg = mg_find(field, PERL_MAGIC_uvar); SV *keysv; if (mg && (keysv = mg->mg_obj)) { STRLEN len; const char *p = SvPV(keysv, len); if (len) { SV *newkey = newSV(len); char *new_p = SvPVX(newkey); if (SvUTF8(keysv)) { const char *const end = p + len; while (p < end) { STRLEN len; UV chr = utf8_to_uvuni((U8 *)p, &len); new_p = (char *)uvuni_to_utf8((U8 *)new_p, chr ^ 32); p += len; } SvUTF8_on(newkey); } else { while (len--) *new_p++ = *p++ ^ 32; } *new_p = '\0'; SvCUR_set(newkey, SvCUR(keysv)); SvPOK_on(newkey); mg->mg_obj = newkey; } } return 0;}static I32rot13_key(pTHX_ IV action, SV *field) { MAGIC *mg = mg_find(field, PERL_MAGIC_uvar); SV *keysv; if (mg && (keysv = mg->mg_obj)) { STRLEN len; const char *p = SvPV(keysv, len); if (len) { SV *newkey = newSV(len); char *new_p = SvPVX(newkey); /* There's a deliberate fencepost error here to loop len + 1 times to copy the trailing \0 */ do { char new_c = *p++; /* Try doing this cleanly and clearly in EBCDIC another way: */ switch (new_c) { case 'A': new_c = 'N'; break; case 'B': new_c = 'O'; break; case 'C': new_c = 'P'; break; case 'D': new_c = 'Q'; break; case 'E': new_c = 'R'; break; case 'F': new_c = 'S'; break; case 'G': new_c = 'T'; break; case 'H': new_c = 'U'; break; case 'I': new_c = 'V'; break; case 'J': new_c = 'W'; break; case 'K': new_c = 'X'; break; case 'L': new_c = 'Y'; break; case 'M': new_c = 'Z'; break; case 'N': new_c = 'A'; break; case 'O': new_c = 'B'; break; case 'P': new_c = 'C'; break; case 'Q': new_c = 'D'; break; case 'R': new_c = 'E'; break; case 'S': new_c = 'F'; break; case 'T': new_c = 'G'; break; case 'U': new_c = 'H'; break; case 'V': new_c = 'I'; break; case 'W': new_c = 'J'; break; case 'X': new_c = 'K'; break; case 'Y': new_c = 'L'; break; case 'Z': new_c = 'M'; break; case 'a': new_c = 'n'; break; case 'b': new_c = 'o'; break; case 'c': new_c = 'p'; break; case 'd': new_c = 'q'; break; case 'e': new_c = 'r'; break; case 'f': new_c = 's'; break; case 'g': new_c = 't'; break; case 'h': new_c = 'u'; break; case 'i': new_c = 'v'; break; case 'j': new_c = 'w'; break; case 'k': new_c = 'x'; break; case 'l': new_c = 'y'; break; case 'm': new_c = 'z'; break; case 'n': new_c = 'a'; break; case 'o': new_c = 'b'; break; case 'p': new_c = 'c'; break; case 'q': new_c = 'd'; break; case 'r': new_c = 'e'; break; case 's': new_c = 'f'; break; case 't': new_c = 'g'; break; case 'u': new_c = 'h'; break; case 'v': new_c = 'i'; break; case 'w': new_c = 'j'; break; case 'x': new_c = 'k'; break; case 'y': new_c = 'l'; break; case 'z': new_c = 'm'; break; } *new_p++ = new_c; } while (len--); SvCUR_set(newkey, SvCUR(keysv)); SvPOK_on(newkey); if (SvUTF8(keysv)) SvUTF8_on(newkey); mg->mg_obj = newkey; } } return 0;}#include "const-c.inc"MODULE = XS::APItest:Hash PACKAGE = XS::APItest::HashINCLUDE: const-xs.incvoidrot13_hash(hash) HV *hash CODE: { struct ufuncs uf; uf.uf_val = rot13_key; uf.uf_set = 0; uf.uf_index = 0; sv_magic((SV*)hash, NULL, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf)); }voidbitflip_hash(hash) HV *hash CODE: { struct ufuncs uf; uf.uf_val = bitflip_key; uf.uf_set = 0; uf.uf_index = 0; sv_magic((SV*)hash, NULL, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf)); }#define UTF8KLEN(sv, len) (SvUTF8(sv) ? -(I32)len : (I32)len)boolexists(hash, key_sv) PREINIT: STRLEN len; const char *key; INPUT: HV *hash SV *key_sv CODE: key = SvPV(key_sv, len); RETVAL = hv_exists(hash, key, UTF8KLEN(key_sv, len)); OUTPUT: RETVALboolexists_ent(hash, key_sv) PREINIT: INPUT: HV *hash SV *key_sv CODE: RETVAL = hv_exists_ent(hash, key_sv, 0); OUTPUT: RETVALSV *delete(hash, key_sv, flags = 0) PREINIT: STRLEN len; const char *key; INPUT: HV *hash SV *key_sv I32 flags; CODE: key = SvPV(key_sv, len); /* It's already mortal, so need to increase reference count. */ RETVAL = SvREFCNT_inc(hv_delete(hash, key, UTF8KLEN(key_sv, len), flags)); OUTPUT: RETVALSV *delete_ent(hash, key_sv, flags = 0) INPUT: HV *hash SV *key_sv I32 flags; CODE: /* It's already mortal, so need to increase reference count. */ RETVAL = SvREFCNT_inc(hv_delete_ent(hash, key_sv, flags, 0)); OUTPUT: RETVALSV *store_ent(hash, key, value) PREINIT: SV *copy; HE *result; INPUT: HV *hash SV *key SV *value CODE: copy = newSV(0); result = hv_store_ent(hash, key, copy, 0); SvSetMagicSV(copy, value); if (!result) { SvREFCNT_dec(copy); XSRETURN_EMPTY; } /* It's about to become mortal, so need to increase reference count. */ RETVAL = SvREFCNT_inc(HeVAL(result)); OUTPUT: RETVALSV *store(hash, key_sv, value) PREINIT: STRLEN len; const char *key; SV *copy; SV **result; INPUT: HV *hash SV *key_sv SV *value CODE: key = SvPV(key_sv, len); copy = newSV(0); result = hv_store(hash, key, UTF8KLEN(key_sv, len), copy, 0); SvSetMagicSV(copy, value); if (!result) { SvREFCNT_dec(copy); XSRETURN_EMPTY; } /* It's about to become mortal, so need to increase reference count. */ RETVAL = SvREFCNT_inc(*result); OUTPUT: RETVALSV *fetch_ent(hash, key_sv) PREINIT: HE *result; INPUT: HV *hash SV *key_sv CODE: result = hv_fetch_ent(hash, key_sv, 0, 0); if (!result) { XSRETURN_EMPTY; } /* Force mg_get */ RETVAL = newSVsv(HeVAL(result)); OUTPUT: RETVALSV *fetch(hash, key_sv) PREINIT: STRLEN len; const char *key; SV **result; INPUT: HV *hash SV *key_sv CODE: key = SvPV(key_sv, len); result = hv_fetch(hash, key, UTF8KLEN(key_sv, len), 0); if (!result) { XSRETURN_EMPTY; } /* Force mg_get */ RETVAL = newSVsv(*result); OUTPUT: RETVALSV *common(params) INPUT: HV *params PREINIT: HE *result; HV *hv = NULL; SV *keysv = NULL; const char *key = NULL; STRLEN klen = 0; int flags = 0; int action = 0; SV *val = NULL; U32 hash = 0; SV **svp; CODE: if ((svp = hv_fetchs(params, "hv", 0))) { SV *const rv = *svp; if (!SvROK(rv)) croak("common passed a non-reference for parameter hv"); hv = (HV *)SvRV(rv); } if ((svp = hv_fetchs(params, "keysv", 0))) keysv = *svp; if ((svp = hv_fetchs(params, "keypv", 0))) { key = SvPV_const(*svp, klen); if (SvUTF8(*svp)) flags = HVhek_UTF8; } if ((svp = hv_fetchs(params, "action", 0))) action = SvIV(*svp); if ((svp = hv_fetchs(params, "val", 0))) val = *svp; if ((svp = hv_fetchs(params, "hash", 0))) action = SvUV(*svp); result = (HE *)hv_common(hv, keysv, key, klen, flags, action, val, hash); if (!result) { XSRETURN_EMPTY; } /* Force mg_get */ RETVAL = newSVsv(HeVAL(result)); OUTPUT: RETVALvoidtest_hv_free_ent() PPCODE: test_freeent(&Perl_hv_free_ent); XSRETURN(4);voidtest_hv_delayfree_ent() PPCODE: test_freeent(&Perl_hv_delayfree_ent); XSRETURN(4);SV *test_share_unshare_pvn(input) PREINIT: STRLEN len; U32 hash; char *pvx; char *p; INPUT: SV *input CODE: pvx = SvPV(input, len); PERL_HASH(hash, pvx, len); p = sharepvn(pvx, len, hash); RETVAL = newSVpvn(p, len); unsharepvn(p, len, hash); OUTPUT: RETVALboolrefcounted_he_exists(key, level=0) SV *key IV level CODE: if (level) { croak("level must be zero, not %"IVdf, level); } RETVAL = (Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash, key, NULL, 0, 0, 0) != &PL_sv_placeholder); OUTPUT: RETVALSV *refcounted_he_fetch(key, level=0) SV *key IV level CODE: if (level) { croak("level must be zero, not %"IVdf, level); } RETVAL = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash, key, NULL, 0, 0, 0); SvREFCNT_inc(RETVAL); OUTPUT: RETVAL =podsub TIEHASH { bless {}, $_[0] }sub STORE { $_[0]->{$_[1]} = $_[2] }sub FETCH { $_[0]->{$_[1]} }sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }sub NEXTKEY { each %{$_[0]} }sub EXISTS { exists $_[0]->{$_[1]} }sub DELETE { delete $_[0]->{$_[1]} }sub CLEAR { %{$_[0]} = () }=cutMODULE = XS::APItest PACKAGE = XS::APItestPROTOTYPES: DISABLEBOOT:{ MY_CXT_INIT; MY_CXT.i = 99; MY_CXT.sv = newSVpv("initial",0);} voidCLONE(...) CODE: MY_CXT_CLONE; MY_CXT.sv = newSVpv("initial_clone",0);voidprint_double(val) double val CODE: printf("%5.3f\n",val);inthave_long_double() CODE:#ifdef HAS_LONG_DOUBLE RETVAL = 1;#else RETVAL = 0;#endif OUTPUT: RETVALvoidprint_long_double() CODE:#ifdef HAS_LONG_DOUBLE# if defined(PERL_PRIfldbl) && (LONG_DOUBLESIZE > DOUBLESIZE) long double val = 7.0; printf("%5.3" PERL_PRIfldbl "\n",val);# else double val = 7.0; printf("%5.3f\n",val);# endif#endifvoidprint_int(val) int val CODE: printf("%d\n",val);voidprint_long(val) long val CODE: printf("%ld\n",val);voidprint_float(val) float val CODE: printf("%5.3f\n",val); voidprint_flush() CODE: fflush(stdout);voidmpushp() PPCODE: EXTEND(SP, 3); mPUSHp("one", 3); mPUSHp("two", 3); mPUSHp("three", 5); XSRETURN(3);voidmpushn() PPCODE: EXTEND(SP, 3); mPUSHn(0.5); mPUSHn(-0.25); mPUSHn(0.125); XSRETURN(3);voidmpushi() PPCODE: EXTEND(SP, 3); mPUSHi(-1); mPUSHi(2); mPUSHi(-3); XSRETURN(3);voidmpushu() PPCODE: EXTEND(SP, 3); mPUSHu(1); mPUSHu(2); mPUSHu(3); XSRETURN(3);voidmxpushp() PPCODE: mXPUSHp("one", 3); mXPUSHp("two", 3); mXPUSHp("three", 5); XSRETURN(3);voidmxpushn() PPCODE: mXPUSHn(0.5); mXPUSHn(-0.25); mXPUSHn(0.125); XSRETURN(3);voidmxpushi() PPCODE: mXPUSHi(-1); mXPUSHi(2); mXPUSHi(-3); XSRETURN(3);voidmxpushu() PPCODE: mXPUSHu(1); mXPUSHu(2); mXPUSHu(3); XSRETURN(3);voidcall_sv(sv, flags, ...) SV* sv I32 flags PREINIT: I32 i; PPCODE: for (i=0; i<items-2; i++) ST(i) = ST(i+2); /* pop first two args */ PUSHMARK(SP); SP += items - 2; PUTBACK; i = call_sv(sv, flags); SPAGAIN; EXTEND(SP, 1); PUSHs(sv_2mortal(newSViv(i)));voidcall_pv(subname, flags, ...) char* subname I32 flags PREINIT: I32 i; PPCODE: for (i=0; i<items-2; i++) ST(i) = ST(i+2); /* pop first two args */ PUSHMARK(SP); SP += items - 2; PUTBACK; i = call_pv(subname, flags); SPAGAIN; EXTEND(SP, 1); PUSHs(sv_2mortal(newSViv(i)));voidcall_method(methname, flags, ...) char* methname I32 flags PREINIT: I32 i; PPCODE: for (i=0; i<items-2; i++) ST(i) = ST(i+2); /* pop first two args */ PUSHMARK(SP); SP += items - 2; PUTBACK; i = call_method(methname, flags); SPAGAIN; EXTEND(SP, 1); PUSHs(sv_2mortal(newSViv(i)));voideval_sv(sv, flags) SV* sv I32 flags PREINIT: I32 i; PPCODE: PUTBACK; i = eval_sv(sv, flags); SPAGAIN; EXTEND(SP, 1); PUSHs(sv_2mortal(newSViv(i)));voideval_pv(p, croak_on_error) const char* p I32 croak_on_error PPCODE: PUTBACK; EXTEND(SP, 1); PUSHs(eval_pv(p, croak_on_error));voidrequire_pv(pv) const char* pv PPCODE: PUTBACK; require_pv(pv);intapitest_exception(throw_e) int throw_e OUTPUT: RETVALvoidmycroak(sv) SV* sv CODE: if (SvOK(sv)) { Perl_croak(aTHX_ "%s", SvPV_nolen(sv)); } else { Perl_croak(aTHX_ NULL); }SV*strtab() CODE: RETVAL = newRV_inc((SV*)PL_strtab); OUTPUT: RETVALintmy_cxt_getint() CODE: dMY_CXT; RETVAL = my_cxt_getint_p(aMY_CXT); OUTPUT: RETVALvoidmy_cxt_setint(i) int i; CODE: dMY_CXT; my_cxt_setint_p(aMY_CXT_ i);voidmy_cxt_getsv() PPCODE: EXTEND(SP, 1); ST(0) = my_cxt_getsv_interp(); XSRETURN(1);voidmy_cxt_setsv(sv) SV *sv; CODE: dMY_CXT; SvREFCNT_dec(MY_CXT.sv); my_cxt_setsv_p(sv _aMY_CXT); SvREFCNT_inc(sv);boolsv_setsv_cow_hashkey_core()boolsv_setsv_cow_hashkey_notcore()voidBEGIN() CODE: sv_inc(get_sv("XS::APItest::BEGIN_called", GV_ADD|GV_ADDMULTI));voidCHECK() CODE: sv_inc(get_sv("XS::APItest::CHECK_called", GV_ADD|GV_ADDMULTI));voidUNITCHECK() CODE: sv_inc(get_sv("XS::APItest::UNITCHECK_called", GV_ADD|GV_ADDMULTI));voidINIT() CODE: sv_inc(get_sv("XS::APItest::INIT_called", GV_ADD|GV_ADDMULTI));voidEND() CODE: sv_inc(get_sv("XS::APItest::END_called", GV_ADD|GV_ADDMULTI));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -