X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Upper.xs;h=4e2f45f229452b65447d2af2bbfe0ec92c6f92f3;hb=02798a015a7fae0ff3d924b3270def3996e4210b;hp=657f01ce9637e05769478ccde15d90547bb192b1;hpb=33d8f50585aa060e71a82a5fd414e114e9b1c1c1;p=perl%2Fmodules%2FScope-Upper.git diff --git a/Upper.xs b/Upper.xs index 657f01c..4e2f45f 100644 --- a/Upper.xs +++ b/Upper.xs @@ -6,6 +6,8 @@ #include "perl.h" #include "XSUB.h" +#define __PACKAGE__ "Scope::Upper" + #ifndef SU_DEBUG # define SU_DEBUG 0 #endif @@ -54,6 +56,10 @@ # define PERL_MAGIC_env 'E' #endif +#ifndef NEGATIVE_INDICES_VAR +# define NEGATIVE_INDICES_VAR "NEGATIVE_INDICES" +#endif + #define SU_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S)))))) /* --- Stack manipulations ------------------------------------------------- */ @@ -71,29 +77,58 @@ /* ... Saving array elements ............................................... */ +STATIC I32 su_av_key2idx(pTHX_ AV *av, I32 key) { +#define su_av_key2idx(A, K) su_av_key2idx(aTHX_ (A), (K)) + I32 idx; + + if (key >= 0) + return key; + +/* Added by MJD in perl-5.8.1 with 6f12eb6d2a1dfaf441504d869b27d2e40ef4966a */ +#if SU_HAS_PERL(5, 8, 1) + if (SvRMAGICAL(av)) { + const MAGIC * const tied_magic = mg_find((SV *) av, PERL_MAGIC_tied); + if (tied_magic) { + int adjust_index = 1; + SV * const * const negative_indices_glob = + hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *) (av), tied_magic))), + NEGATIVE_INDICES_VAR, 16, 0); + if (negative_indices_glob && SvTRUE(GvSV(*negative_indices_glob))) + return key; + } + } +#endif + + idx = key + av_len(av) + 1; + if (idx < 0) + return key; + + return idx; +} + #ifndef SAVEADELETE typedef struct { AV *av; - I32 key; + I32 idx; } su_ud_adelete; STATIC void su_adelete(pTHX_ void *ud_) { su_ud_adelete *ud = ud_; - av_delete(ud->av, ud->key, G_DISCARD); + av_delete(ud->av, ud->idx, G_DISCARD); SvREFCNT_dec(ud->av); Safefree(ud); } -STATIC void su_save_adelete(pTHX_ AV *av, I32 key) { +STATIC void su_save_adelete(pTHX_ AV *av, I32 idx) { #define su_save_adelete(A, K) su_save_adelete(aTHX_ (A), (K)) su_ud_adelete *ud; Newx(ud, 1, su_ud_adelete); ud->av = av; - ud->key = key; + ud->idx = idx; SvREFCNT_inc(av); SAVEDESTRUCTOR_X(su_adelete, ud); @@ -105,12 +140,14 @@ STATIC void su_save_adelete(pTHX_ AV *av, I32 key) { STATIC void su_save_aelem(pTHX_ AV *av, SV *key, SV *val) { #define su_save_aelem(A, K, V) su_save_aelem(aTHX_ (A), (K), (V)) - I32 idx = SvIV(key); + I32 idx; I32 preeminent = 1; SV **svp; HV *stash; MAGIC *mg; + idx = su_av_key2idx(av, SvIV(key)); + if (SvCANEXISTDELETE(av)) preeminent = av_exists(av, idx); @@ -485,20 +522,81 @@ done: if (level > cxstack_ix) \ level = cxstack_ix; +#define SU_DOPOPTOCX(t) \ + STMT_START { \ + I32 i, cxix = cxstack_ix, from = 0; \ + if (items) \ + from = SvIV(ST(0)); \ + for (i = cxix - from; i >= 0; --i) { \ + if (CxTYPE(&cxstack[i]) == t) { \ + ST(0) = sv_2mortal(newSViv(cxix - i)); \ + XSRETURN(1); \ + } \ + } \ + XSRETURN_UNDEF; \ + } STMT_END + /* --- XS ------------------------------------------------------------------ */ MODULE = Scope::Upper PACKAGE = Scope::Upper PROTOTYPES: ENABLE +BOOT: +{ + HV *stash = gv_stashpv(__PACKAGE__, 1); + newCONSTSUB(stash, "CURRENT", newSViv(0)); +} + SV * -TOPLEVEL() +TOP() PROTOTYPE: CODE: RETVAL = newSViv(cxstack_ix); OUTPUT: RETVAL +SV * +UP(...) +PROTOTYPE: ;$ +PREINIT: + I32 i = 0; + I32 cxix = cxstack_ix; +CODE: + if (items) + i = SvIV(ST(0)); + if (++i > cxix) + i = cxix; + RETVAL = newSViv(i); +OUTPUT: + RETVAL + +SV * +DOWN(...) +PROTOTYPE: ;$ +PREINIT: + I32 i = 0; +CODE: + if (items) + i = SvIV(ST(0)); + if (--i < 0) + i = 0; + RETVAL = newSViv(i); +OUTPUT: + RETVAL + +void +SUB(...) +PROTOTYPE: ;$ +PPCODE: + SU_DOPOPTOCX(CXt_SUB); + +void +EVAL(...) +PROTOTYPE: ;$ +PPCODE: + SU_DOPOPTOCX(CXt_EVAL); + void reap(SV *hook, ...) PROTOTYPE: &;$