X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Plugin.xs;h=cc90e2b16d5c559aa9e4accf95c1c9c3a84ee019;hb=ba92a5781ed7ee39a62fb0490e291a52b97e69a9;hp=07a73d2f2338216ffc5587b5e3384539561edde6;hpb=def98fc0d7f5e9527b28af6b90d4ddb07fbc845c;p=perl%2Fmodules%2Fre-engine-Plugin.git diff --git a/Plugin.xs b/Plugin.xs index 07a73d2..cc90e2b 100644 --- a/Plugin.xs +++ b/Plugin.xs @@ -1,192 +1,276 @@ +/* This file is part of the re::engine::Plugin Perl module. + * See http://search.cpan.org/dist/re-engine-Plugin/ */ + +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" -#define SAVEPVN(p,n) ((p) ? savepvn(p,n) : NULL) +/* --- Helpers ------------------------------------------------------------- */ -START_EXTERN_C +#define XSH_PACKAGE "re::engine::Plugin" -EXTERN_C const regexp_engine engine_plugin; +#include "xsh/caps.h" +#include "xsh/util.h" -END_EXTERN_C +/* ... Lexical hints ....................................................... */ -/* - * Our struct which gets initiated and used as our object - * ($re). Since we can't count on the regexp structure provided by - * perl to be alive between comp/exec etc. we pull stuff from it and - * save it in our own structure. - * - * Besides, creating Perl accessors which directly muck with perl's - * own regexp structures in different phases of regex execution would - * be a little too evil. - */ -typedef struct replug { - SV * pattern; - char flags[sizeof("ecgimsxp")]; +typedef struct { + SV *comp; + SV *exec; +} xsh_hints_user_t; - I32 minlen; - U32 gofs; +static SV *rep_validate_callback(SV *code) { + if (!SvROK(code)) + return NULL; - SV * stash; + code = SvRV(code); + if (SvTYPE(code) < SVt_PVCV) + return NULL; - U32 nparens; - AV * captures; /* Array of SV* that'll become $1, $2, ... */ -} *re__engine__Plugin; - -SV* -get_H_callback(const char* key) -{ - dVAR; - dSP; + return SvREFCNT_inc_simple_NN(code); +} - SV * callback; +static void xsh_hints_user_init(pTHX_ xsh_hints_user_t *hv, xsh_hints_user_t *v) { + hv->comp = rep_validate_callback(v->comp); + hv->exec = rep_validate_callback(v->exec); - ENTER; - SAVETMPS; - - PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(key, 0))); - PUTBACK; + return; +} - call_pv("re::engine::Plugin::get_callback", G_SCALAR); +#if XSH_THREADSAFE - SPAGAIN; +static void xsh_hints_user_clone(pTHX_ xsh_hints_user_t *nv, xsh_hints_user_t *ov, CLONE_PARAMS *params) { + nv->comp = xsh_dup_inc(ov->comp, params); + nv->exec = xsh_dup_inc(ov->exec, params); - callback = POPs; - SvREFCNT_inc(callback); + return; +} - if (!SvROK(callback)) { callback = NULL; }// croak("ret value not a ref"); } +#endif /* XSH_THREADSAFE */ - PUTBACK; - FREETMPS; - LEAVE; +static void xsh_hints_user_deinit(pTHX_ xsh_hints_user_t *hv) { + SvREFCNT_dec(hv->comp); + SvREFCNT_dec(hv->exec); - return callback; + return; } -/* just learn to use gdb you lazy bum! */ -#if 0 -void -dump_r_info(const char* id, regexp *r) -{ - warn("%s:", id); - warn("\textflags = %d", r->extflags); - warn("\tminlen = %d", r->minlen); - warn("\tminlenren = %d", r->minlenret); - warn("\tgofs = %d", r->gofs); - warn("\tnparens = %d", r->nparens); - warn("\tpprivate = %p", r->pprivate); - warn("\tsubbeg = %s", r->subbeg); - warn("\tsublen = %d", r->sublen); - warn("\tprecomp = %s", r->precomp); - warn("\tprelen = %d", r->prelen); - warn("\twrapped = %s", r->wrapped); - warn("\twraplen = %d", r->wraplen); - warn("\tseen_evals = %d", r->seen_evals); - warn("\trefcnt = %d", r->refcnt); - -} +#define rep_hint() xsh_hints_detag(xsh_hints_fetch()) + +#define XSH_HINTS_TYPE_USER 1 +#define XSH_HINTS_ONLY_COMPILE_TIME 0 + +#include "xsh/hints.h" + +/* ... Thread-local storage ................................................ */ + +#define XSH_THREADS_USER_CONTEXT 0 +#define XSH_THREADS_USER_LOCAL_SETUP 0 +#define XSH_THREADS_USER_LOCAL_TEARDOWN 0 +#define XSH_THREADS_USER_GLOBAL_TEARDOWN 0 +#define XSH_THREADS_COMPILE_TIME_PROTECTION 0 + +#include "xsh/threads.h" + +/* --- Custom regexp engine ------------------------------------------------ */ + +#define GET_SELF_FROM_PPRIVATE(pprivate) \ + re__engine__Plugin self; \ + SELF_FROM_PPRIVATE(self,pprivate); + +/* re__engine__Plugin self; SELF_FROM_PPRIVATE(self,rx->pprivate) */ +#define SELF_FROM_PPRIVATE(self, pprivate) \ + if (sv_isobject(pprivate)) { \ + SV * ref = SvRV((SV*)pprivate); \ + IV tmp = SvIV((SV*)ref); \ + self = INT2PTR(re__engine__Plugin,tmp); \ + } else { \ + Perl_croak(aTHX_ "Not an object"); \ + } + +#if XSH_HAS_PERL(5, 19, 4) +# define REP_ENG_EXEC_MINEND_TYPE SSize_t +#else +# define REP_ENG_EXEC_MINEND_TYPE I32 #endif -regexp * -Plugin_comp(pTHX_ char *exp, char *xend, PMOP *pm) -{ - dSP; - register regexp *r; - int count; - - /* - * Allocate a new regexp struct, we must only write to the intflags, - * engine and private members and the others must be populated, - * internals expect the regex to have certain values least our code - * blow up - */ +START_EXTERN_C +EXTERN_C const regexp_engine engine_plugin; +#if XSH_HAS_PERL(5, 11, 0) +EXTERN_C REGEXP * Plugin_comp(pTHX_ SV * const, U32); +#else +EXTERN_C REGEXP * Plugin_comp(pTHX_ const SV * const, const U32); +#endif +EXTERN_C I32 Plugin_exec(pTHX_ REGEXP * const, char *, char *, + char *, REP_ENG_EXEC_MINEND_TYPE, SV *, void *, U32); +#if XSH_HAS_PERL(5, 19, 1) +EXTERN_C char * Plugin_intuit(pTHX_ REGEXP * const, SV *, const char * const, + char *, char *, U32, re_scream_pos_data *); +#else +EXTERN_C char * Plugin_intuit(pTHX_ REGEXP * const, SV *, char *, + char *, U32, re_scream_pos_data *); +#endif +EXTERN_C SV * Plugin_checkstr(pTHX_ REGEXP * const); +EXTERN_C void Plugin_free(pTHX_ REGEXP * const); +EXTERN_C void * Plugin_dupe(pTHX_ REGEXP * const, CLONE_PARAMS *); +EXTERN_C void Plugin_numbered_buff_FETCH(pTHX_ REGEXP * const, + const I32, SV * const); +EXTERN_C void Plugin_numbered_buff_STORE(pTHX_ REGEXP * const, + const I32, SV const * const); +EXTERN_C I32 Plugin_numbered_buff_LENGTH(pTHX_ REGEXP * const, + const SV * const, const I32); +EXTERN_C SV * Plugin_named_buff (pTHX_ REGEXP * const, SV * const, + SV * const, const U32); +EXTERN_C SV * Plugin_named_buff_iter (pTHX_ REGEXP * const, const SV * const, + const U32); +EXTERN_C SV * Plugin_package(pTHX_ REGEXP * const); +#ifdef USE_ITHREADS +EXTERN_C void * Plugin_dupe(pTHX_ REGEXP * const, CLONE_PARAMS *); +#endif - Newxz(r,1,regexp); +EXTERN_C const regexp_engine engine_plugin; +END_EXTERN_C - /* Set up the regex to be handled by this plugin */ - r->engine = &engine_plugin; +#define RE_ENGINE_PLUGIN (&engine_plugin) +const regexp_engine engine_plugin = { + Plugin_comp, + Plugin_exec, + Plugin_intuit, + Plugin_checkstr, + Plugin_free, + Plugin_numbered_buff_FETCH, + Plugin_numbered_buff_STORE, + Plugin_numbered_buff_LENGTH, + Plugin_named_buff, + Plugin_named_buff_iter, + Plugin_package +#if defined(USE_ITHREADS) + , Plugin_dupe +#endif +#if XSH_HAS_PERL(5, 17, 0) + , 0 +#endif +}; - /* Store the initial flags */ - r->intflags = pm->op_pmflags; - r->pprivate = NULL; /* this is set to our object below */ +typedef struct replug { + /* Pointer back to the containing regexp struct so that accessors + * can modify nparens, gofs etc. */ + struct regexp * rx; - /* - * Populate the regexp members for the engine - */ + /* A copy of the pattern given to comp, for ->pattern */ + SV * pattern; - /* Ref count of the pattern */ - r->refcnt = 1; + /* A copy of the string being matched against, for ->str */ + SV * str; - /* Preserve a copy of the original pattern */ - r->prelen = xend - exp; - r->precomp = SAVEPVN(exp, r->prelen); + /* The ->stash */ + SV * stash; - /* these may be changed by accessors */ - r->minlen = 0; - r->minlenret = 0; - r->gofs = 0; - r->nparens = 0; + /* Callbacks */ + SV * cb_exec; + SV * cb_free; - /* Store the flags as perl expects them */ - r->extflags = pm->op_pmflags & RXf_PMf_COMPILETIME; + /* ->num_captures */ + SV * cb_num_capture_buff_FETCH; + SV * cb_num_capture_buff_STORE; + SV * cb_num_capture_buff_LENGTH; +} *re__engine__Plugin; + +#if XSH_HAS_PERL(5, 11, 0) +# define rxREGEXP(RX) (SvANY(RX)) +# define newREGEXP(RX) ((RX) = ((REGEXP*) newSV_type(SVt_REGEXP))) +#else +# define rxREGEXP(RX) (RX) +# define newREGEXP(RX) (Newxz((RX), 1, struct regexp)) +#endif + +REGEXP * +#if XSH_HAS_PERL(5, 11, 0) +Plugin_comp(pTHX_ SV * const pattern, U32 flags) +#else +Plugin_comp(pTHX_ const SV * const pattern, const U32 flags) +#endif +{ + dSP; + struct regexp * rx; + REGEXP *RX; - /* - * Construct a new B object that'll carry around - * our data inside C<< r->pprivate >>. The object is a blessed void* - * that points to our replug struct which holds any state we want to - * keep. - */ re__engine__Plugin re; - Newz(0, re, 1, struct replug); - - SV *obj = newSV(0); - SvREFCNT_inc(obj); + const xsh_hints_user_t *h; - /* Bless into this package; TODO: make it subclassable */ - const char * pkg = "re::engine::Plugin"; - /* bless it */ - sv_setref_pv(obj, pkg, (void*)re); + STRLEN plen; + char *pbuf; - /* Store our private object */ - r->pprivate = obj; + SV *obj; + + h = rep_hint(); + if (!h) /* This looks like a pragma leak. Apply the default behaviour */ + return re_compile(pattern, flags); - re->pattern = newSVpvn(SAVEPVN(exp, xend - exp), xend - exp); - SvREFCNT_inc(re->pattern); + /* exp/xend version of the pattern & length */ + pbuf = SvPV((SV*)pattern, plen); - /* Concat [ec]gimosxp (egimosxp & cgimosxp into) the flags string as - * appropriate + /* Our blessed object */ + obj = newSV(0); + SvREFCNT_inc_simple_void_NN(obj); + Newxz(re, 1, struct replug); + sv_setref_pv(obj, "re::engine::Plugin", (void*)re); + + newREGEXP(RX); + rx = rxREGEXP(RX); + + re->rx = rx; /* Make the rx accessible from self->rx */ + rx->intflags = flags; /* Flags for internal use */ + rx->extflags = flags; /* Flags for perl to use */ + rx->engine = RE_ENGINE_PLUGIN; /* Compile to use this engine */ + +#if !XSH_HAS_PERL(5, 11, 0) + rx->refcnt = 1; /* Refcount so we won't be destroyed */ + + /* Precompiled pattern for pp_regcomp to use */ + rx->prelen = plen; + rx->precomp = savepvn(pbuf, rx->prelen); + + /* Set up qr// stringification to be equivalent to the supplied + * pattern, this should be done via overload eventually. */ - if (r->intflags & PMf_EVAL) { strcat(re->flags, "e"); } - if (r->intflags & PMf_CONTINUE) { strcat(re->flags, "c"); } - if (r->intflags & PMf_GLOBAL) { strcat(re->flags, "g"); } - if (r->intflags & PMf_FOLD) { strcat(re->flags, "i"); } - if (r->intflags & PMf_MULTILINE) { strcat(re->flags, "m"); } - if (r->intflags & PMf_ONCE) { strcat(re->flags, "o"); } - if (r->intflags & PMf_SINGLELINE) { strcat(re->flags, "s"); } - if (r->intflags & PMf_EXTENDED) { strcat(re->flags, "x"); } - if (((r->extflags & RXf_PMf_KEEPCOPY) == RXf_PMf_KEEPCOPY)) { - strcat(re->flags, "p"); + rx->wraplen = rx->prelen; + Newx(rx->wrapped, rx->wraplen, char); + Copy(rx->precomp, rx->wrapped, rx->wraplen, char); +#endif + + /* Store our private object */ + rx->pprivate = obj; + + /* Store the pattern for ->pattern */ + re->pattern = (SV*)pattern; + SvREFCNT_inc_simple_void(re->pattern); + + /* If there's an exec callback, store it into the private object so + * that it will be the one to be called, even if the engine changes + * in between */ + if (h->exec) { + re->cb_exec = h->exec; + SvREFCNT_inc_simple_void_NN(h->exec); } - /* - * Call our callback function if one was defined, if not we've - * already set up all the stuff we're going to to need for - * subsequent exec and other calls - */ - SV * callback = get_H_callback("comp"); + re->cb_num_capture_buff_FETCH = NULL; + re->cb_num_capture_buff_STORE = NULL; + re->cb_num_capture_buff_LENGTH = NULL; - if (callback) { - ENTER; + /* Call our callback function if one was defined, if not we've + * already set up all the stuff we're going to to need for + * subsequent exec and other calls */ + if (h->comp) { + ENTER; SAVETMPS; - + PUSHMARK(SP); XPUSHs(obj); - XPUSHs(sv_2mortal(newSVpv(exp, xend - exp))); - PUTBACK; - call_sv(get_H_callback("comp"), G_DISCARD); + call_sv(h->comp, G_DISCARD); FREETMPS; LEAVE; @@ -195,200 +279,443 @@ Plugin_comp(pTHX_ char *exp, char *xend, PMOP *pm) /* If any of the comp-time accessors were called we'll have to * update the regexp struct with the new info. */ - if (re->minlen) r->minlen = re->minlen; - if (re->gofs) r->gofs = re->gofs; - if (re->gofs) r->gofs = re->gofs; - if (re->nparens) r->nparens = re->nparens; - int buffers = r->nparens; + Newxz(rx->offs, rx->nparens + 1, regexp_paren_pair); - //r->nparens = (buffers - 1); - Newxz(r->startp, buffers, I32); - Newxz(r->endp, buffers, I32); - - /* return the regexp */ - return r; + return RX; } I32 -Plugin_exec(pTHX_ register regexp *r, char *stringarg, register char *strend, - char *strbeg, I32 minend, SV *sv, void *data, U32 flags) +Plugin_exec(pTHX_ REGEXP * const RX, char *stringarg, char *strend, + char *strbeg, REP_ENG_EXEC_MINEND_TYPE minend, + SV *sv, void *data, U32 flags) { dSP; - I32 rc; - int *ovector; - I32 i; - int count; - int ret; - - /*Newx(ovector,r->nparens,int);*/ + I32 matched; + struct regexp *rx = rxREGEXP(RX); + GET_SELF_FROM_PPRIVATE(rx->pprivate); - SV* callback = get_H_callback("exec"); + if (self->cb_exec) { + SV *ret; - ENTER; - SAVETMPS; - - PUSHMARK(SP); + /* Store the current str for ->str */ + SvREFCNT_dec(self->str); + self->str = sv; + SvREFCNT_inc_simple_void(self->str); - XPUSHs(r->pprivate); - XPUSHs(sv); - - PUTBACK; + ENTER; + SAVETMPS; - count = call_sv(callback, G_ARRAY); - - SPAGAIN; + PUSHMARK(SP); + XPUSHs(rx->pprivate); + XPUSHs(sv); + PUTBACK; - SV * SvRet = POPs; + call_sv(self->cb_exec, G_SCALAR); - if (SvTRUE(SvRet)) { - /* Match vars */ + SPAGAIN; - /* - r->sublen = strend-strbeg; - r->subbeg = savepvn(strbeg,r->sublen); - r->startp[1] = 0; - r->endp[1] = 5; - */ + ret = POPs; + if (SvTRUE(ret)) + matched = 1; + else + matched = 0; - ret = 1; + PUTBACK; + FREETMPS; + LEAVE; } else { - ret = 0; + matched = 0; } - PUTBACK; - FREETMPS; - LEAVE; - - return ret; + return matched; } char * -Plugin_intuit(pTHX_ regexp *prog, SV *sv, char *strpos, - char *strend, U32 flags, re_scream_pos_data *data) +#if XSH_HAS_PERL(5, 19, 1) +Plugin_intuit(pTHX_ REGEXP * const RX, SV *sv, const char * const strbeg, + char *strpos, char *strend, U32 flags, re_scream_pos_data *data) +#else +Plugin_intuit(pTHX_ REGEXP * const RX, SV *sv, char *strpos, + char *strend, U32 flags, re_scream_pos_data *data) +#endif { + PERL_UNUSED_ARG(RX); + PERL_UNUSED_ARG(sv); +#if XSH_HAS_PERL(5, 19, 1) + PERL_UNUSED_ARG(strbeg); +#endif + PERL_UNUSED_ARG(strpos); + PERL_UNUSED_ARG(strend); + PERL_UNUSED_ARG(flags); + PERL_UNUSED_ARG(data); return NULL; } SV * -Plugin_checkstr(pTHX_ regexp *prog) +Plugin_checkstr(pTHX_ REGEXP * const RX) { + PERL_UNUSED_ARG(RX); return NULL; } void -Plugin_free(pTHX_ struct regexp *r) +Plugin_free(pTHX_ REGEXP * const RX) { - /*sv_2mortal(r->pprivate);*/ - /*PerlMemShared_free(r->pprivate);*/ + struct regexp *rx; + re__engine__Plugin self; + + if (PL_dirty) + return; + + rx = rxREGEXP(RX); + SELF_FROM_PPRIVATE(self, rx->pprivate); + + SvREFCNT_dec(self->pattern); + SvREFCNT_dec(self->str); + + SvREFCNT_dec(self->cb_exec); + + SvREFCNT_dec(self->cb_num_capture_buff_FETCH); + SvREFCNT_dec(self->cb_num_capture_buff_STORE); + SvREFCNT_dec(self->cb_num_capture_buff_LENGTH); + + self->rx = NULL; + Safefree(self); + +/* + dSP; + SV * callback; + + callback = self->cb_free; + + if (callback) { + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(rx->pprivate); + PUTBACK; + + call_sv(callback, G_DISCARD); + + PUTBACK; + FREETMPS; + LEAVE; + } + return; +*/ } void * -Plugin_dupe(pTHX_ const regexp *r, CLONE_PARAMS *param) +Plugin_dupe(pTHX_ REGEXP * const RX, CLONE_PARAMS *param) +{ + struct regexp *rx = rxREGEXP(RX); + Perl_croak(aTHX_ "dupe not supported yet"); + return rx->pprivate; +} + + +void +Plugin_numbered_buff_FETCH(pTHX_ REGEXP * const RX, const I32 paren, + SV * const sv) +{ + dSP; + I32 items; + SV * callback; + struct regexp *rx = rxREGEXP(RX); + GET_SELF_FROM_PPRIVATE(rx->pprivate); + + callback = self->cb_num_capture_buff_FETCH; + + if (callback) { + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(rx->pprivate); + XPUSHs(sv_2mortal(newSViv(paren))); + PUTBACK; + + items = call_sv(callback, G_SCALAR); + + if (items == 1) { + SV *ret; + + SPAGAIN; + ret = POPs; + sv_setsv(sv, ret); + } else { + sv_setsv(sv, &PL_sv_undef); + } + + PUTBACK; + FREETMPS; + LEAVE; + } else { + sv_setsv(sv, &PL_sv_undef); + } +} + +void +Plugin_numbered_buff_STORE(pTHX_ REGEXP * const RX, const I32 paren, + SV const * const value) { - return r->pprivate; + dSP; + SV * callback; + struct regexp *rx = rxREGEXP(RX); + GET_SELF_FROM_PPRIVATE(rx->pprivate); + + callback = self->cb_num_capture_buff_STORE; + + if (callback) { + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(rx->pprivate); + XPUSHs(sv_2mortal(newSViv(paren))); + XPUSHs((SV *) value); + PUTBACK; + + call_sv(callback, G_DISCARD); + + PUTBACK; + FREETMPS; + LEAVE; + } +} + +I32 +Plugin_numbered_buff_LENGTH(pTHX_ REGEXP * const RX, const SV * const sv, + const I32 paren) +{ + dSP; + SV * callback; + struct regexp *rx = rxREGEXP(RX); + GET_SELF_FROM_PPRIVATE(rx->pprivate); + + callback = self->cb_num_capture_buff_LENGTH; + + if (callback) { + IV ret; + + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(rx->pprivate); + XPUSHs(sv_2mortal(newSViv(paren))); + PUTBACK; + + call_sv(callback, G_SCALAR); + + SPAGAIN; + + ret = POPi; + + PUTBACK; + FREETMPS; + LEAVE; + + return (I32)ret; + } else { + /* TODO: call FETCH and get the length on that value */ + return 0; + } } + SV* -Plugin_numbered_buff_get(pTHX_ const REGEXP * const rx, I32 paren, SV* usesv) +Plugin_named_buff (pTHX_ REGEXP * const RX, SV * const key, SV * const value, + const U32 flags) { return NULL; } SV* -Plugin_named_buff_get(pTHX_ const REGEXP * const rx, SV* namesv, U32 flags) +Plugin_named_buff_iter (pTHX_ REGEXP * const RX, const SV * const lastkey, + const U32 flags) { return NULL; } -/* - * The function pointers we're telling the regex engine to use - */ -const regexp_engine engine_plugin = { - Plugin_comp, - Plugin_exec, - Plugin_intuit, - Plugin_checkstr, - Plugin_free, - Plugin_numbered_buff_get, - Plugin_named_buff_get, -#if defined(USE_ITHREADS) - Plugin_dupe, -#endif -}; +SV* +Plugin_package(pTHX_ REGEXP * const RX) +{ + PERL_UNUSED_ARG(RX); + return newSVpvs("re::engine::Plugin"); +} -MODULE = re::engine::Plugin PACKAGE = re::engine::Plugin +static void xsh_user_global_setup(pTHX) { + HV *stash; -SV * + stash = gv_stashpvn(XSH_PACKAGE, XSH_PACKAGE_LEN, 1); + newCONSTSUB(stash, "REP_THREADSAFE", newSVuv(XSH_THREADSAFE)); + newCONSTSUB(stash, "REP_FORKSAFE", newSVuv(XSH_FORKSAFE)); + + return; +} + +/* --- XS ------------------------------------------------------------------ */ + +MODULE = re::engine::Plugin PACKAGE = re::engine::Plugin + +PROTOTYPES: DISABLE + +BOOT: +{ + xsh_setup(); +} + +#if XSH_THREADSAFE + +void +CLONE(...) +PPCODE: + xsh_clone(); + XSRETURN(0); + +#endif /* XSH_THREADSAFE */ + +void pattern(re::engine::Plugin self, ...) -CODE: - SvREFCNT_inc(self->pattern); - RETVAL = self->pattern; -OUTPUT: - RETVAL +PPCODE: + XPUSHs(self->pattern); -char* -flags(re::engine::Plugin self, ...) -CODE: - RETVAL = self->flags; -OUTPUT: - RETVAL +void +str(re::engine::Plugin self, ...) +PPCODE: + XPUSHs(self->str); -SV * -stash(re::engine::Plugin self, ...) +void +mod(re::engine::Plugin self) PREINIT: - SV * stash; -CODE: + U32 flags; + char mods[5 + 1]; + int n = 0, i; +PPCODE: + flags = self->rx->intflags; + if (flags & PMf_FOLD) /* /i */ + mods[n++] = 'i'; + if (flags & PMf_MULTILINE) /* /m */ + mods[n++] = 'm'; + if (flags & PMf_SINGLELINE) /* /s */ + mods[n++] = 's'; + if (flags & PMf_EXTENDED) /* /x */ + mods[n++] = 'x'; + if (flags & RXf_PMf_KEEPCOPY) /* /p */ + mods[n++] = 'p'; + mods[n] = '\0'; + EXTEND(SP, 2 * n); + for (i = 0; i < n; ++i) { + mPUSHp(mods + i, 1); + PUSHs(&PL_sv_yes); + } + XSRETURN(2 * n); + +void +stash(re::engine::Plugin self, ...) +PPCODE: if (items > 1) { - self->stash = sv_mortalcopy(ST(1)); - SvREFCNT_inc(self->stash); + SvREFCNT_dec(self->stash); + self->stash = ST(1); + SvREFCNT_inc_simple_void(self->stash); + XSRETURN_EMPTY; + } else { + XPUSHs(self->stash); } - SvREFCNT_inc(self->stash); - RETVAL = self->stash; -OUTPUT: - RETVAL -SV * +void minlen(re::engine::Plugin self, ...) -CODE: +PPCODE: if (items > 1) { - self->minlen = (I32)SvIV(ST(1)); + self->rx->minlen = (I32)SvIV(ST(1)); + XSRETURN_EMPTY; + } else { + if (self->rx->minlen) { + XPUSHs(sv_2mortal(newSViv(self->rx->minlen))); + } else { + XPUSHs(sv_2mortal(&PL_sv_undef)); + } } - RETVAL = self->minlen ? newSViv(self->minlen) : &PL_sv_undef; -OUTPUT: - RETVAL - -SV * +void gofs(re::engine::Plugin self, ...) -CODE: +PPCODE: if (items > 1) { - self->gofs = (U32)SvIV(ST(1)); + self->rx->gofs = (U32)SvIV(ST(1)); + XSRETURN_EMPTY; + } else { + if (self->rx->gofs) { + XPUSHs(sv_2mortal(newSVuv(self->rx->gofs))); + } else { + XPUSHs(sv_2mortal(&PL_sv_undef)); + } } - RETVAL = self->gofs ? newSVuv(self->gofs) : &PL_sv_undef; -OUTPUT: - RETVAL -SV * +void nparens(re::engine::Plugin self, ...) -CODE: +PPCODE: if (items > 1) { - self->nparens = (U32)SvIV(ST(1)); + self->rx->nparens = (U32)SvIV(ST(1)); + XSRETURN_EMPTY; + } else { + if (self->rx->nparens) { + XPUSHs(sv_2mortal(newSVuv(self->rx->nparens))); + } else { + XPUSHs(sv_2mortal(&PL_sv_undef)); + } + } + +void +_exec(re::engine::Plugin self, ...) +PPCODE: + if (items > 1) { + SvREFCNT_dec(self->cb_exec); + self->cb_exec = ST(1); + SvREFCNT_inc_simple_void(self->cb_exec); } - RETVAL = self->gofs ? newSVuv(self->gofs) : &PL_sv_undef; -OUTPUT: - RETVAL void -captures(re::engine::Plugin self, ...) +_num_capture_buff_FETCH(re::engine::Plugin self, ...) PPCODE: if (items > 1) { - self->minlen = (I32)SvIV(ST(1)); + SvREFCNT_dec(self->cb_num_capture_buff_FETCH); + self->cb_num_capture_buff_FETCH = ST(1); + SvREFCNT_inc_simple_void(self->cb_num_capture_buff_FETCH); } - XPUSHs(sv_2mortal(newSViv(5))); - XPUSHs(sv_2mortal(newSViv(10))); void -get_engine_plugin() +_num_capture_buff_STORE(re::engine::Plugin self, ...) +PPCODE: + if (items > 1) { + SvREFCNT_dec(self->cb_num_capture_buff_STORE); + self->cb_num_capture_buff_STORE = ST(1); + SvREFCNT_inc_simple_void(self->cb_num_capture_buff_STORE); + } + +void +_num_capture_buff_LENGTH(re::engine::Plugin self, ...) +PPCODE: + if (items > 1) { + SvREFCNT_dec(self->cb_num_capture_buff_LENGTH); + self->cb_num_capture_buff_LENGTH = ST(1); + SvREFCNT_inc_simple_void(self->cb_num_capture_buff_LENGTH); + } + +SV * +_tag(SV *comp, SV *exec) +PREINIT: + xsh_hints_user_t arg; +CODE: + arg.comp = comp; + arg.exec = exec; + RETVAL = xsh_hints_tag(&arg); +OUTPUT: + RETVAL + +void +ENGINE() PPCODE: XPUSHs(sv_2mortal(newSViv(PTR2IV(&engine_plugin))));