+#define __PACKAGE__ "Variable::Magic"
+
+#ifndef VMG_PERL_PATCHLEVEL
+# ifdef PERL_PATCHNUM
+# define VMG_PERL_PATCHLEVEL PERL_PATCHNUM
+# else
+# define VMG_PERL_PATCHLEVEL 0
+# endif
+#endif
+
+#define VMG_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
+
+#define VMG_HAS_PERL_BRANCH(R, V, S) (PERL_REVISION == (R) && PERL_VERSION == (V) && PERL_SUBVERSION >= (S))
+
+#define VMG_HAS_PERL_MAINT(R, V, S, P) (PERL_REVISION == (R) && PERL_VERSION == (V) && (VMG_PERL_PATCHLEVEL >= (P) || (!VMG_PERL_PATCHLEVEL && PERL_SUBVERSION >= (S))))
+
+/* --- Threads and multiplicity -------------------------------------------- */
+
+#ifndef NOOP
+# define NOOP
+#endif
+
+#ifndef dNOOP
+# define dNOOP
+#endif
+
+#ifndef VMG_MULTIPLICITY
+# if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
+# define VMG_MULTIPLICITY 1
+# else
+# define VMG_MULTIPLICITY 0
+# endif
+#endif
+#if VMG_MULTIPLICITY && !defined(tTHX)
+# define tTHX PerlInterpreter*
+#endif
+
+#if VMG_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV))
+# define VMG_THREADSAFE 1
+# ifndef MY_CXT_CLONE
+# define MY_CXT_CLONE \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
+ Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+# endif
+#else
+# define VMG_THREADSAFE 0
+# undef dMY_CXT
+# define dMY_CXT dNOOP
+# undef MY_CXT
+# define MY_CXT vmg_globaldata
+# undef START_MY_CXT
+# define START_MY_CXT STATIC my_cxt_t MY_CXT;
+# undef MY_CXT_INIT
+# define MY_CXT_INIT NOOP
+# undef MY_CXT_CLONE
+# define MY_CXT_CLONE NOOP
+#endif
+
+#if VMG_THREADSAFE
+
+STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) {
+#define vmg_clone(P, O) vmg_clone(aTHX_ (P), (O))
+ CLONE_PARAMS param;
+ param.stashes = NULL; /* don't need it unless sv is a PVHV */
+ param.flags = 0;
+ param.proto_perl = owner;
+ return sv_dup(sv, ¶m);
+}
+
+#endif /* VMG_THREADSAFE */
+
+/* --- Compatibility ------------------------------------------------------- */
+
+#ifndef Newx
+# define Newx(v, n, c) New(0, v, n, c)
+#endif
+
+#ifndef SvMAGIC_set
+# define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val))
+#endif
+
+#ifndef mPUSHu
+# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U)))
+#endif
+
+#ifndef SvPV_const
+# define SvPV_const SvPV
+#endif
+
+#ifndef PERL_MAGIC_ext
+# define PERL_MAGIC_ext '~'
+#endif
+
+#ifndef PERL_MAGIC_tied
+# define PERL_MAGIC_tied 'P'
+#endif
+
+#ifndef MGf_COPY
+# define MGf_COPY 0
+#endif
+
+#ifndef MGf_DUP
+# define MGf_DUP 0
+#endif
+
+#ifndef MGf_LOCAL
+# define MGf_LOCAL 0
+#endif
+
+#ifndef IN_PERL_COMPILETIME
+# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling)
+#endif
+
+#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser)
+# ifndef PL_error_count
+# define PL_error_count PL_parser->error_count
+# endif
+#else
+# ifndef PL_error_count
+# define PL_error_count PL_Ierror_count
+# endif
+#endif
+
+/* uvar magic and Hash::Util::FieldHash were commited with 28419 */
+#if VMG_HAS_PERL_MAINT(5, 9, 4, 28419) || VMG_HAS_PERL(5, 10, 0)
+# define VMG_UVAR 1
+#else
+# define VMG_UVAR 0
+#endif
+
+/* Applied to dev-5.9 as 25854, integrated to maint-5.8 as 28160 */
+#ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN
+# if VMG_HAS_PERL_MAINT(5, 8, 9, 28160) || VMG_HAS_PERL_MAINT(5, 9, 3, 25854) || VMG_HAS_PERL(5, 10, 0)
+# define VMG_COMPAT_ARRAY_PUSH_NOLEN 1
+# else
+# define VMG_COMPAT_ARRAY_PUSH_NOLEN 0
+# endif
+#endif
+
+/* Applied to dev-5.11 as 34908 */
+#if VMG_HAS_PERL_MAINT(5, 11, 0, 34908)
+# define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 1
+#else
+# define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 0
+#endif
+
+/* Applied to dev-5.9 as 31473 (see #43357), integrated to maint-5.8 as 32542 */
+#if VMG_HAS_PERL_MAINT(5, 8, 9, 32542) || VMG_HAS_PERL_MAINT(5, 9, 5, 31473) || VMG_HAS_PERL(5, 10, 0)
+# define VMG_COMPAT_ARRAY_UNDEF_CLEAR 1
+#else
+# define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0
+#endif
+
+#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969)
+# define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1
+#else
+# define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0
+#endif
+
+#if VMG_UVAR
+
+/* Bug-free mg_magical - see http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html - but specialized to our needs. */
+STATIC void vmg_sv_magicuvar(pTHX_ SV *sv, const char *uf, I32 len) {
+#define vmg_sv_magicuvar(S, U, L) vmg_sv_magicuvar(aTHX_ (S), (U), (L))
+ const MAGIC* mg;
+ sv_magic(sv, NULL, PERL_MAGIC_uvar, uf, len);
+ /* uvar magic has set and get magic, hence this has set SVs_GMG and SVs_SMG. */
+ if ((mg = SvMAGIC(sv))) {
+ SvRMAGICAL_off(sv);
+ do {
+ const MGVTBL* const vtbl = mg->mg_virtual;
+ if (vtbl) {
+ if (vtbl->svt_clear) {
+ SvRMAGICAL_on(sv);
+ break;
+ }
+ }
+ } while ((mg = mg->mg_moremagic));
+ }
+}
+
+#endif /* VMG_UVAR */
+
+/* --- Stolen chunk of B --------------------------------------------------- */
+
+typedef enum {
+ OPc_NULL = 0,
+ OPc_BASEOP = 1,
+ OPc_UNOP = 2,
+ OPc_BINOP = 3,
+ OPc_LOGOP = 4,
+ OPc_LISTOP = 5,
+ OPc_PMOP = 6,
+ OPc_SVOP = 7,
+ OPc_PADOP = 8,
+ OPc_PVOP = 9,
+ OPc_LOOP = 10,
+ OPc_COP = 11,
+ OPc_MAX = 12
+} opclass;
+
+STATIC const char *const vmg_opclassnames[] = {
+ "B::NULL",
+ "B::OP",
+ "B::UNOP",
+ "B::BINOP",
+ "B::LOGOP",
+ "B::LISTOP",
+ "B::PMOP",
+ "B::SVOP",
+ "B::PADOP",
+ "B::PVOP",
+ "B::LOOP",
+ "B::COP"
+};
+
+STATIC opclass vmg_opclass(const OP *o) {
+#if 0
+ if (!o)
+ return OPc_NULL;
+#endif
+
+ if (o->op_type == 0)
+ return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
+
+ if (o->op_type == OP_SASSIGN)
+ return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
+
+ if (o->op_type == OP_AELEMFAST) {
+ if (o->op_flags & OPf_SPECIAL)
+ return OPc_BASEOP;
+ else
+#ifdef USE_ITHREADS
+ return OPc_PADOP;
+#else
+ return OPc_SVOP;
+#endif
+ }
+
+#ifdef USE_ITHREADS
+ if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_RCATLINE)
+ return OPc_PADOP;
+#endif
+
+ switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
+ case OA_BASEOP:
+ return OPc_BASEOP;
+ case OA_UNOP:
+ return OPc_UNOP;
+ case OA_BINOP:
+ return OPc_BINOP;
+ case OA_LOGOP:
+ return OPc_LOGOP;
+ case OA_LISTOP:
+ return OPc_LISTOP;
+ case OA_PMOP:
+ return OPc_PMOP;
+ case OA_SVOP:
+ return OPc_SVOP;
+ case OA_PADOP:
+ return OPc_PADOP;
+ case OA_PVOP_OR_SVOP:
+ return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF)) ? OPc_SVOP : OPc_PVOP;
+ case OA_LOOP:
+ return OPc_LOOP;
+ case OA_COP:
+ return OPc_COP;
+ case OA_BASEOP_OR_UNOP:
+ return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
+ case OA_FILESTATOP:
+ return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
+#ifdef USE_ITHREADS
+ (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
+#else
+ (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
+#endif
+ case OA_LOOPEXOP:
+ if (o->op_flags & OPf_STACKED)
+ return OPc_UNOP;
+ else if (o->op_flags & OPf_SPECIAL)
+ return OPc_BASEOP;
+ else
+ return OPc_PVOP;
+ }
+
+ return OPc_BASEOP;
+}
+
+/* --- Context-safe global data -------------------------------------------- */