#define PERL_NO_GET_CONTEXT /* we want efficiency */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" /* These are tightly coupled to the RXapif_* flags defined in regexp.h */ #define UNDEF_FATAL 0x80000 #define DISCARD 0x40000 #define EXPECT_SHIFT 24 #define ACTION_MASK 0x000FF #define FETCH_ALIAS (RXapif_FETCH | (2 << EXPECT_SHIFT)) #define STORE_ALIAS (RXapif_STORE | (3 << EXPECT_SHIFT) | UNDEF_FATAL | DISCARD) #define DELETE_ALIAS (RXapif_DELETE | (2 << EXPECT_SHIFT) | UNDEF_FATAL) #define CLEAR_ALIAS (RXapif_CLEAR | (1 << EXPECT_SHIFT) | UNDEF_FATAL | DISCARD) #define EXISTS_ALIAS (RXapif_EXISTS | (2 << EXPECT_SHIFT)) #define SCALAR_ALIAS (RXapif_SCALAR | (1 << EXPECT_SHIFT)) static void tie_it(pTHX_ const char name, UV flag, HV *const stash) { GV *const gv = gv_fetchpvn(&name, 1, GV_ADDMULTI|GV_NOTQUAL, SVt_PVHV); HV *const hv = GvHV(gv); SV *rv = newSV_type(SVt_RV); SvRV_set(rv, newSVuv(flag)); SvROK_on(rv); sv_bless(rv, stash); sv_unmagic((SV *)hv, PERL_MAGIC_tied); sv_magic((SV *)hv, rv, PERL_MAGIC_tied, NULL, 0); SvREFCNT_dec(rv); /* As sv_magic increased it by one. */ } MODULE = Tie::Hash::NamedCapture PACKAGE = Tie::Hash::NamedCapture PROTOTYPES: DISABLE BOOT: { HV *const stash = GvSTASH(CvGV(cv)); tie_it(aTHX_ '-', RXapif_ALL, stash); tie_it(aTHX_ '+', RXapif_ONE, stash); } SV * TIEHASH(package, ...) const char *package; PREINIT: UV flag = RXapif_ONE; CODE: mark += 2; while(mark < sp) { STRLEN len; const char *p = SvPV_const(*mark, len); if(memEQs(p, len, "all")) flag = SvTRUE(mark[1]) ? RXapif_ALL : RXapif_ONE; mark += 2; } RETVAL = newSV_type(SVt_RV); sv_setuv(newSVrv(RETVAL, package), flag); OUTPUT: RETVAL void FETCH(...) ALIAS: Tie::Hash::NamedCapture::FETCH = FETCH_ALIAS Tie::Hash::NamedCapture::STORE = STORE_ALIAS Tie::Hash::NamedCapture::DELETE = DELETE_ALIAS Tie::Hash::NamedCapture::CLEAR = CLEAR_ALIAS Tie::Hash::NamedCapture::EXISTS = EXISTS_ALIAS Tie::Hash::NamedCapture::SCALAR = SCALAR_ALIAS PREINIT: REGEXP *const rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL; U32 flags; SV *ret; const U32 action = ix & ACTION_MASK; const int expect = ix >> EXPECT_SHIFT; PPCODE: if (items != expect) croak_xs_usage(cv, expect == 2 ? "$key" : (expect == 3 ? "$key, $value" : "")); if (!rx || !SvROK(ST(0))) { if (ix & UNDEF_FATAL) Perl_croak_no_modify(aTHX); else XSRETURN_UNDEF; } flags = (U32)SvUV(SvRV(MUTABLE_SV(ST(0)))); PUTBACK; ret = RX_ENGINE(rx)->named_buff(aTHX_ (rx), expect >= 2 ? ST(1) : NULL, expect >= 3 ? ST(2) : NULL, flags | action); SPAGAIN; if (ix & DISCARD) { /* Called with G_DISCARD, so our return stack state is thrown away. Hence if we were returned anything, free it immediately. */ SvREFCNT_dec(ret); } else { PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef); } void FIRSTKEY(...) ALIAS: Tie::Hash::NamedCapture::NEXTKEY = 1 PREINIT: REGEXP *const rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL; U32 flags; SV *ret; const int expect = ix ? 2 : 1; const U32 action = ix ? RXapif_NEXTKEY : RXapif_FIRSTKEY; PPCODE: if (items != expect) croak_xs_usage(cv, expect == 2 ? "$lastkey" : ""); if (!rx || !SvROK(ST(0))) XSRETURN_UNDEF; flags = (U32)SvUV(SvRV(MUTABLE_SV(ST(0)))); PUTBACK; ret = RX_ENGINE(rx)->named_buff_iter(aTHX_ (rx), expect >= 2 ? ST(1) : NULL, flags | action); SPAGAIN; PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef); void flags(...) PPCODE: EXTEND(SP, 2); mPUSHu(RXapif_ONE); mPUSHu(RXapif_ALL);