/*
- * Store and retrieve mechanism.
- */
-
-/*
- * $Id: Storable.xs,v 1.0.1.10 2001/08/28 21:52:14 ram Exp $
+ * Store and retrieve mechanism.
*
* Copyright (c) 1995-2000, Raphael Manfredi
*
#include <EXTERN.h>
#include <perl.h>
-#include <patchlevel.h> /* Perl's one, needed since 5.6 */
#include <XSUB.h>
+#ifndef PATCHLEVEL
+# include <patchlevel.h> /* Perl's one, needed since 5.6 */
+# if !(defined(PERL_VERSION) || (SUBVERSION > 0 && defined(PATCHLEVEL)))
+# include <could_not_find_Perl_patchlevel.h>
+# endif
+#endif
+
#ifndef NETWARE
#if 0
#define DEBUGME /* Debug mode, turns assertions on as well */
#define SX_UTF8STR C(23) /* UTF-8 string forthcoming (small) */
#define SX_LUTF8STR C(24) /* UTF-8 string forthcoming (large) */
#define SX_FLAG_HASH C(25) /* Hash with flags forthcoming (size, flags, key/flags/value triplet list) */
-#define SX_ERROR C(26) /* Error */
+#define SX_CODE C(26) /* Code references as perl source code */
+#define SX_ERROR C(27) /* Error */
/*
* Those are only used to retrieve "old" pre-0.6 binary images.
int netorder; /* true if network order used */
int s_tainted; /* true if input source is tainted, at retrieve time */
int forgive_me; /* whether to be forgiving... */
+ int deparse; /* whether to deparse code refs */
+ SV *eval; /* whether to eval source code */
int canonical; /* whether to store hashes sorted by key */
#ifndef HAS_RESTRICTED_HASHES
int derestrict; /* whether to downgrade restrcted hashes */
#else /* !MULTIPLICITY && !PERL_OBJECT && !PERL_CAPI */
-static stcxt_t Context;
-static stcxt_t *Context_ptr = &Context;
+static stcxt_t *Context_ptr = NULL;
#define dSTCXT stcxt_t *cxt = Context_ptr
+#define SET_STCXT(x) Context_ptr = x
#define INIT_STCXT \
dSTCXT; \
- NEW_STORABLE_CXT_OBJ(cxt)
+ NEW_STORABLE_CXT_OBJ(cxt); \
+ SET_STCXT(cxt)
-#define SET_STCXT(x) Context_ptr = x
#endif /* MULTIPLICITY || PERL_OBJECT || PERL_CAPI */
if (!mbase) { \
TRACEME(("** allocating mbase of %d bytes", MGROW)); \
New(10003, mbase, MGROW, char); \
- msiz = MGROW; \
+ msiz = (STRLEN)MGROW; \
} \
mptr = mbase; \
if (x) \
#define svis_HASH 3
#define svis_TIED 4
#define svis_TIED_ITEM 5
-#define svis_OTHER 6
+#define svis_CODE 6
+#define svis_OTHER 7
/*
* Flags for SX_HOOK.
#define MAGICSTR_BYTES 'p','s','t','0'
#define OLDMAGICSTR_BYTES 'p','e','r','l','-','s','t','o','r','e'
+/* 5.6.x introduced the ability to have IVs as long long.
+ However, Configure still defined BYTEORDER based on the size of a long.
+ Storable uses the BYTEORDER value as part of the header, but doesn't
+ explicity store sizeof(IV) anywhere in the header. Hence on 5.6.x built
+ with IV as long long on a platform that uses Configure (ie most things
+ except VMS and Windows) headers are identical for the different IV sizes,
+ despite the files containing some fields based on sizeof(IV)
+ Erk. Broken-ness.
+ 5.8 is consistent - the following redifinition kludge is only needed on
+ 5.6.x, but the interwork is needed on 5.8 while data survives in files
+ with the 5.6 header.
+
+*/
+
+#if defined (IVSIZE) && (IVSIZE == 8) && (LONGSIZE == 4)
+#ifndef NO_56_INTERWORK_KLUDGE
+#define USE_56_INTERWORK_KLUDGE
+#endif
+#if BYTEORDER == 0x1234
+#undef BYTEORDER
+#define BYTEORDER 0x12345678
+#else
+#if BYTEORDER == 0x4321
+#undef BYTEORDER
+#define BYTEORDER 0x87654321
+#endif
+#endif
+#endif
+
#if BYTEORDER == 0x1234
#define BYTEORDER_BYTES '1','2','3','4'
#else
#if BYTEORDER == 0x12345678
#define BYTEORDER_BYTES '1','2','3','4','5','6','7','8'
+#ifdef USE_56_INTERWORK_KLUDGE
+#define BYTEORDER_BYTES_56 '1','2','3','4'
+#endif
#else
#if BYTEORDER == 0x87654321
#define BYTEORDER_BYTES '8','7','6','5','4','3','2','1'
+#ifdef USE_56_INTERWORK_KLUDGE
+#define BYTEORDER_BYTES_56 '4','3','2','1'
+#endif
#else
#if BYTEORDER == 0x4321
#define BYTEORDER_BYTES '4','3','2','1'
#endif
static const char byteorderstr[] = {BYTEORDER_BYTES, 0};
+#ifdef USE_56_INTERWORK_KLUDGE
+static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0};
+#endif
#define STORABLE_BIN_MAJOR 2 /* Binary major "version" */
-#define STORABLE_BIN_MINOR 5 /* Binary minor "version" */
+#define STORABLE_BIN_MINOR 6 /* Binary minor "version" */
/* If we aren't 5.7.3 or later, we won't be writing out files that use the
* new flagged hash introdued in 2.5, so put 2.4 in the binary header to
* As of perl 5.7.3, utf8 hash key is introduced.
* So this must change -- dankogai
*/
-#define STORABLE_BIN_WRITE_MINOR 5
+#define STORABLE_BIN_WRITE_MINOR 6
#endif /* (PATCHLEVEL <= 6) */
/*
#define STORE_SCALAR(pv, len) STORE_PV_LEN(pv, len, SX_SCALAR, SX_LSCALAR)
/*
- * Store undef in arrays and hashes without recursing through store().
+ * Store &PL_sv_undef in arrays without recursing through store().
*/
-#define STORE_UNDEF() \
+#define STORE_SV_UNDEF() \
STMT_START { \
cxt->tagnum++; \
- PUTMARK(SX_UNDEF); \
+ PUTMARK(SX_SV_UNDEF); \
} STMT_END
/*
static int store_hash(stcxt_t *cxt, HV *hv);
static int store_tied(stcxt_t *cxt, SV *sv);
static int store_tied_item(stcxt_t *cxt, SV *sv);
+static int store_code(stcxt_t *cxt, CV *cv);
static int store_other(stcxt_t *cxt, SV *sv);
static int store_blessed(stcxt_t *cxt, SV *sv, int type, HV *pkg);
(int (*)(stcxt_t *cxt, SV *sv)) store_hash, /* svis_HASH */
store_tied, /* svis_TIED */
store_tied_item, /* svis_TIED_ITEM */
+ (int (*)(stcxt_t *cxt, SV *sv)) store_code, /* svis_CODE */
store_other, /* svis_OTHER */
};
retrieve_other, /* SX_UTF8STR not supported */
retrieve_other, /* SX_LUTF8STR not supported */
retrieve_other, /* SX_FLAG_HASH not supported */
+ retrieve_other, /* SX_CODE not supported */
retrieve_other, /* SX_ERROR */
};
static SV *retrieve_tied_key(stcxt_t *cxt, char *cname);
static SV *retrieve_tied_idx(stcxt_t *cxt, char *cname);
static SV *retrieve_flag_hash(stcxt_t *cxt, char *cname);
+static SV *retrieve_code(stcxt_t *cxt, char *cname);
static SV *(*sv_retrieve[])(stcxt_t *cxt, char *cname) = {
0, /* SX_OBJECT -- entry unused dynamically */
retrieve_utf8str, /* SX_UTF8STR */
retrieve_lutf8str, /* SX_LUTF8STR */
retrieve_flag_hash, /* SX_HASH */
+ retrieve_code, /* SX_CODE */
retrieve_other, /* SX_ERROR */
};
cxt->netorder = network_order;
cxt->forgive_me = -1; /* Fetched from perl if needed */
+ cxt->deparse = -1; /* Idem */
+ cxt->eval = NULL; /* Idem */
cxt->canonical = -1; /* Idem */
cxt->tagnum = -1; /* Reset tag numbers */
cxt->classnum = -1; /* Reset class numbers */
if (cxt->hseen) {
hv_iterinit(cxt->hseen);
while ((he = hv_iternext(cxt->hseen))) /* Extra () for -Wall, grr.. */
- HeVAL(he) = &PL_sv_undef;
+ HeVAL(he) = &PL_sv_placeholder;
}
if (cxt->hclass) {
hv_iterinit(cxt->hclass);
while ((he = hv_iternext(cxt->hclass))) /* Extra () for -Wall, grr.. */
- HeVAL(he) = &PL_sv_undef;
+ HeVAL(he) = &PL_sv_placeholder;
}
/*
}
cxt->forgive_me = -1; /* Fetched from perl if needed */
+ cxt->deparse = -1; /* Idem */
+ if (cxt->eval) {
+ SvREFCNT_dec(cxt->eval);
+ }
+ cxt->eval = NULL; /* Idem */
cxt->canonical = -1; /* Idem */
reset_context(cxt);
* new retrieve routines.
*/
- cxt->hseen = ((cxt->retrieve_vtbl == sv_old_retrieve) ? newHV() : 0);
+ cxt->hseen = (((void*)cxt->retrieve_vtbl == (void*)sv_old_retrieve)
+ ? newHV() : 0);
cxt->aseen = newAV(); /* Where retrieved objects are kept */
cxt->aclass = newAV(); /* Where seen classnames are kept */
#else
SvIV_please(sv);
- if (SvIOK(sv)) {
+ if (SvIOK_notUV(sv)) {
iv = SvIV(sv);
goto integer; /* Share code above */
}
sav = av_fetch(av, i, 0);
if (!sav) {
TRACEME(("(#%d) undef item", i));
- STORE_UNDEF();
+ STORE_SV_UNDEF();
continue;
}
TRACEME(("(#%d) item", i));
= (((hash_flags & SHV_RESTRICTED)
&& SvREADONLY(val))
? SHV_K_LOCKED : 0);
- if (val == &PL_sv_undef)
+ if (val == &PL_sv_placeholder)
flags |= SHV_K_PLACEHOLDER;
keyval = SvPV(key, keylen_tmp);
/*
* Storing in "random" order (in the order the keys are stored
- * within the the hash). This is the default and will be faster!
+ * within the hash). This is the default and will be faster!
*/
for (i = 0; i < len; i++) {
= (((hash_flags & SHV_RESTRICTED)
&& SvREADONLY(val))
? SHV_K_LOCKED : 0);
- if (val == &PL_sv_undef)
+ if (val == &PL_sv_placeholder)
flags |= SHV_K_PLACEHOLDER;
hek = HeKEY_hek(he);
}
/*
+ * store_code
+ *
+ * Store a code reference.
+ *
+ * Layout is SX_CODE <length> followed by a scalar containing the perl
+ * source code of the code reference.
+ */
+static int store_code(stcxt_t *cxt, CV *cv)
+{
+#if PERL_VERSION < 6
+ /*
+ * retrieve_code does not work with perl 5.005 or less
+ */
+ return store_other(cxt, (SV*)cv);
+#else
+ dSP;
+ I32 len;
+ int count, reallen;
+ SV *text, *bdeparse;
+
+ TRACEME(("store_code (0x%"UVxf")", PTR2UV(cv)));
+
+ if (
+ cxt->deparse == 0 ||
+ (cxt->deparse < 0 && !(cxt->deparse =
+ SvTRUE(perl_get_sv("Storable::Deparse", TRUE)) ? 1 : 0))
+ ) {
+ return store_other(cxt, (SV*)cv);
+ }
+
+ /*
+ * Require B::Deparse. At least B::Deparse 0.61 is needed for
+ * blessed code references.
+ */
+ /* XXX sv_2mortal seems to be evil here. why? */
+ load_module(PERL_LOADMOD_NOIMPORT, newSVpvn("B::Deparse",10), newSVnv(0.61));
+
+ ENTER;
+ SAVETMPS;
+
+ /*
+ * create the B::Deparse object
+ */
+
+ PUSHMARK(sp);
+ XPUSHs(sv_2mortal(newSVpvn("B::Deparse",10)));
+ PUTBACK;
+ count = call_method("new", G_SCALAR);
+ SPAGAIN;
+ if (count != 1)
+ CROAK(("Unexpected return value from B::Deparse::new\n"));
+ bdeparse = POPs;
+
+ /*
+ * call the coderef2text method
+ */
+
+ PUSHMARK(sp);
+ XPUSHs(bdeparse); /* XXX is this already mortal? */
+ XPUSHs(sv_2mortal(newRV_inc((SV*)cv)));
+ PUTBACK;
+ count = call_method("coderef2text", G_SCALAR);
+ SPAGAIN;
+ if (count != 1)
+ CROAK(("Unexpected return value from B::Deparse::coderef2text\n"));
+
+ text = POPs;
+ len = SvLEN(text);
+ reallen = strlen(SvPV_nolen(text));
+
+ /*
+ * Empty code references or XS functions are deparsed as
+ * "(prototype) ;" or ";".
+ */
+
+ if (len == 0 || *(SvPV_nolen(text)+reallen-1) == ';') {
+ CROAK(("The result of B::Deparse::coderef2text was empty - maybe you're trying to serialize an XS function?\n"));
+ }
+
+ /*
+ * Signal code by emitting SX_CODE.
+ */
+
+ PUTMARK(SX_CODE);
+ TRACEME(("size = %d", len));
+ TRACEME(("code = %s", SvPV_nolen(text)));
+
+ /*
+ * Now store the source code.
+ */
+
+ STORE_SCALAR(SvPV_nolen(text), len);
+
+ FREETMPS;
+ LEAVE;
+
+ TRACEME(("ok (code)"));
+
+ return 0;
+#endif
+}
+
+/*
* store_tied
*
* When storing a tied object (be it a tied scalar, array or hash), we lay out
static int store_tied(stcxt_t *cxt, SV *sv)
{
MAGIC *mg;
+ SV *obj = NULL;
int ret = 0;
int svt = SvTYPE(sv);
char mtype = 'P';
* accesses on the retrieved object will indeed call the magic methods...
*/
- if ((ret = store(cxt, mg->mg_obj))) /* Extra () for -Wall, grr... */
+ /* [#17040] mg_obj is NULL for scalar self-ties. AMS 20030416 */
+ obj = mg->mg_obj ? mg->mg_obj : newSV(0);
+ if ((ret = store(cxt, obj)))
return ret;
TRACEME(("ok (tied)"));
* If they returned more than one item, we need to serialize some
* extra references if not already done.
*
- * Loop over the array, starting at postion #1, and for each item,
+ * Loop over the array, starting at position #1, and for each item,
* ensure it is a reference, serialize it if not already done, and
* replace the entry with the tag ID of the corresponding serialized
* object.
if (SvRMAGICAL(sv) && (mg_find(sv, 'P')))
return svis_TIED;
return svis_HASH;
+ case SVt_PVCV:
+ return svis_CODE;
default:
break;
}
*
* NOTA BENE, for 64-bit machines: the "*svh" below does not yield a
* real pointer, rather a tag number (watch the insertion code below).
- * That means it pobably safe to assume it is well under the 32-bit limit,
+ * That means it probably safe to assume it is well under the 32-bit limit,
* and makes the truncation safe.
* -- RAM, 14/09/1999
*/
(unsigned char) sizeof(char *),
(unsigned char) sizeof(NV)
};
+#ifdef USE_56_INTERWORK_KLUDGE
+ static const unsigned char file_header_56[] = {
+ MAGICSTR_BYTES,
+ (STORABLE_BIN_MAJOR << 1) | 0,
+ STORABLE_BIN_WRITE_MINOR,
+ /* sizeof the array includes the 0 byte at the end: */
+ (char) sizeof (byteorderstr_56) - 1,
+ BYTEORDER_BYTES_56,
+ (unsigned char) sizeof(int),
+ (unsigned char) sizeof(long),
+ (unsigned char) sizeof(char *),
+ (unsigned char) sizeof(NV)
+ };
+#endif
const unsigned char *header;
SSize_t length;
header = network_file_header;
length = sizeof (network_file_header);
} else {
- header = file_header;
- length = sizeof (file_header);
+#ifdef USE_56_INTERWORK_KLUDGE
+ if (SvTRUE(perl_get_sv("Storable::interwork_56_64bit", TRUE))) {
+ header = file_header_56;
+ length = sizeof (file_header_56);
+ } else
+#endif
+ {
+ header = file_header;
+ length = sizeof (file_header);
+ }
}
if (!cxt->fio) {
length -= sizeof (magicstr) - 1;
}
- WRITE(header, length);
+ WRITE( (unsigned char*) header, length);
if (!cxt->netorder) {
TRACEME(("ok (magic_write byteorder = 0x%lx [%d], I%d L%d P%d D%d)",
* We don't need to remember the addresses returned by retrieval, because
* all the references will be obtained through indirection via the object
* tags in the object-ID list.
+ *
+ * We need to decrement the reference count for these objects
+ * because, if the user doesn't save a reference to them in the hook,
+ * they must be freed when this context is cleaned.
*/
while (flags & SHF_NEED_RECURSE) {
rv = retrieve(cxt, 0);
if (!rv)
return (SV *) 0;
+ SvREFCNT_dec(rv);
TRACEME(("retrieve_hook back with rv=0x%"UVxf,
PTR2UV(rv)));
GETMARK(flags);
* an SX_OBJECT indication, a ref count increment was done.
*/
- sv_upgrade(rv, SVt_RV);
+ if (cname) {
+ /* Do not use sv_upgrade to preserve STASH */
+ SvFLAGS(rv) &= ~SVTYPEMASK;
+ SvFLAGS(rv) |= SVt_RV;
+ } else {
+ sv_upgrade(rv, SVt_RV);
+ }
+
SvRV(rv) = sv; /* $rv = \$sv */
SvROK_on(rv);
static SV *retrieve_tied_scalar(stcxt_t *cxt, char *cname)
{
SV *tv;
- SV *sv;
+ SV *sv, *obj = NULL;
TRACEME(("retrieve_tied_scalar (#%d)", cxt->tagnum));
tv = NEWSV(10002, 0);
SEEN(tv, cname); /* Will return if rv is null */
sv = retrieve(cxt, 0); /* Retrieve <object> */
- if (!sv)
+ if (!sv) {
return (SV *) 0; /* Failed */
+ }
+ else if (SvTYPE(sv) != SVt_NULL) {
+ obj = sv;
+ }
sv_upgrade(tv, SVt_PVMG);
- sv_magic(tv, sv, 'q', Nullch, 0);
- SvREFCNT_dec(sv); /* Undo refcnt inc from sv_magic() */
+ sv_magic(tv, obj, 'q', Nullch, 0);
+
+ if (obj) {
+ /* Undo refcnt inc from sv_magic() */
+ SvREFCNT_dec(obj);
+ }
TRACEME(("ok (retrieve_tied_scalar at 0x%"UVxf")", PTR2UV(tv)));
if (flags & SHV_K_PLACEHOLDER) {
SvREFCNT_dec (sv);
- sv = &PL_sv_undef;
+ sv = &PL_sv_placeholder;
store_flags |= HVhek_PLACEHOLD;
}
if (flags & SHV_K_UTF8) {
}
/*
+ * retrieve_code
+ *
+ * Return a code reference.
+ */
+static SV *retrieve_code(stcxt_t *cxt, char *cname)
+{
+#if PERL_VERSION < 6
+ CROAK(("retrieve_code does not work with perl 5.005 or less\n"));
+#else
+ dSP;
+ int type, count;
+ SV *cv;
+ SV *sv, *text, *sub;
+
+ TRACEME(("retrieve_code (#%d)", cxt->tagnum));
+
+ /*
+ * Retrieve the source of the code reference
+ * as a small or large scalar
+ */
+
+ GETMARK(type);
+ switch (type) {
+ case SX_SCALAR:
+ text = retrieve_scalar(cxt, cname);
+ break;
+ case SX_LSCALAR:
+ text = retrieve_lscalar(cxt, cname);
+ break;
+ default:
+ CROAK(("Unexpected type %d in retrieve_code\n", type));
+ }
+
+ /*
+ * prepend "sub " to the source
+ */
+
+ sub = newSVpvn("sub ", 4);
+ sv_catpv(sub, SvPV_nolen(text)); /* XXX no sv_catsv! */
+ SvREFCNT_dec(text);
+
+ /*
+ * evaluate the source to a code reference and use the CV value
+ */
+
+ if (cxt->eval == NULL) {
+ cxt->eval = perl_get_sv("Storable::Eval", TRUE);
+ SvREFCNT_inc(cxt->eval);
+ }
+ if (!SvTRUE(cxt->eval)) {
+ if (
+ cxt->forgive_me == 0 ||
+ (cxt->forgive_me < 0 && !(cxt->forgive_me =
+ SvTRUE(perl_get_sv("Storable::forgive_me", TRUE)) ? 1 : 0))
+ ) {
+ CROAK(("Can't eval, please set $Storable::Eval to a true value"));
+ } else {
+ sv = newSVsv(sub);
+ return sv;
+ }
+ }
+
+ ENTER;
+ SAVETMPS;
+
+ if (SvROK(cxt->eval) && SvTYPE(SvRV(cxt->eval)) == SVt_PVCV) {
+ SV* errsv = get_sv("@", TRUE);
+ sv_setpv(errsv, ""); /* clear $@ */
+ PUSHMARK(sp);
+ XPUSHs(sv_2mortal(newSVsv(sub)));
+ PUTBACK;
+ count = call_sv(cxt->eval, G_SCALAR);
+ SPAGAIN;
+ if (count != 1)
+ CROAK(("Unexpected return value from $Storable::Eval callback\n"));
+ cv = POPs;
+ if (SvTRUE(errsv)) {
+ CROAK(("code %s caused an error: %s",
+ SvPV_nolen(sub), SvPV_nolen(errsv)));
+ }
+ PUTBACK;
+ } else {
+ cv = eval_pv(SvPV_nolen(sub), TRUE);
+ }
+ if (cv && SvROK(cv) && SvTYPE(SvRV(cv)) == SVt_PVCV) {
+ sv = SvRV(cv);
+ } else {
+ CROAK(("code %s did not evaluate to a subroutine reference\n", SvPV_nolen(sub)));
+ }
+
+ SvREFCNT_inc(sv); /* XXX seems to be necessary */
+ SvREFCNT_dec(sub);
+
+ FREETMPS;
+ LEAVE;
+
+ SEEN(sv, cname);
+ return sv;
+#endif
+}
+
+/*
* old_retrieve_array
*
* Retrieve a whole array in pre-0.6 binary format.
TRACEME(("byte order '%.*s' %d", c, buf, c));
- if ((c != (sizeof (byteorderstr) - 1)) || memNE(buf, byteorderstr, c))
- CROAK(("Byte order is not compatible"));
+#ifdef USE_56_INTERWORK_KLUDGE
+ /* No point in caching this in the context as we only need it once per
+ retrieve, and we need to recheck it each read. */
+ if (SvTRUE(perl_get_sv("Storable::interwork_56_64bit", TRUE))) {
+ if ((c != (sizeof (byteorderstr_56) - 1))
+ || memNE(buf, byteorderstr_56, c))
+ CROAK(("Byte order is not compatible"));
+ } else
+#endif
+ {
+ if ((c != (sizeof (byteorderstr) - 1)) || memNE(buf, byteorderstr, c))
+ CROAK(("Byte order is not compatible"));
+ }
current = buf + c;
/* sizeof(char *) */
if ((int) *current != sizeof(char *))
- CROAK(("Pointer integer size is not compatible"));
+ CROAK(("Pointer size is not compatible"));
if (use_NV_size) {
/* sizeof(NV) */
if (!sv) {
TRACEME(("retrieve ERROR"));
+#if (PATCHLEVEL <= 4)
+ /* perl 5.00405 seems to screw up at this point with an
+ 'attempt to modify a read only value' error reported in the
+ eval { $self = pretrieve(*FILE) } in _retrieve.
+ I can't see what the cause of this error is, but I suspect a
+ bug in 5.004, as it seems to be capable of issuing spurious
+ errors or core dumping with matches on $@. I'm not going to
+ spend time on what could be a fruitless search for the cause,
+ so here's a bodge. If you're running 5.004 and don't like
+ this inefficiency, either upgrade to a newer perl, or you are
+ welcome to find the problem and send in a patch.
+ */
+ return newSV(0);
+#else
return &PL_sv_undef; /* Something went wrong, return undef */
+#endif
}
TRACEME(("retrieve got %s(0x%"UVxf")",
BOOT:
init_perinterp();
+ gv_fetchpv("Storable::drop_utf8", GV_ADDMULTI, SVt_PV);
#ifdef DEBUGME
/* Only disable the used only once warning if we are in debugging mode. */
gv_fetchpv("Storable::DEBUGME", GV_ADDMULTI, SVt_PV);
#endif
+#ifdef USE_56_INTERWORK_KLUDGE
+ gv_fetchpv("Storable::interwork_56_64bit", GV_ADDMULTI, SVt_PV);
+#endif
int
pstore(f,obj)