*/
/*
- * $Id: Storable.xs,v 0.7.1.2 2000/08/14 07:19:27 ram Exp $
+ * $Id: Storable.xs,v 0.7.1.3 2000/08/23 23:00:41 ram Exp $
*
* Copyright (c) 1995-2000, Raphael Manfredi
*
* as specified in the README file that comes with the distribution.
*
* $Log: Storable.xs,v $
+ * Revision 0.7.1.3 2000/08/23 23:00:41 ram
+ * patch3: ANSI-fied most of the code, preparing for Perl core integration
+ * patch3: dispatch tables moved upfront to relieve some compilers
+ * patch3: merged 64-bit fixes from perl5-porters
+ *
* Revision 0.7.1.2 2000/08/14 07:19:27 ram
* patch2: added a refcnt dec in retrieve_tied_key()
*
/*
* Earlier versions of perl might be used, we can't assume they have the latest!
*/
+
+#ifndef PERL_VERSION /* For perls < 5.6 */
+#define PERL_VERSION PATCHLEVEL
#ifndef newRV_noinc
#define newRV_noinc(sv) ((Sv = newRV(sv)), --SvREFCNT(SvRV(Sv)), Sv)
#endif
#ifndef HvSHAREKEYS_off
#define HvSHAREKEYS_off(hv) /* Ignore */
#endif
+#ifndef INT2PTR
+#define INT2PTR(t,v) (t)(IV)(v)
+#endif
+#ifndef AvFILLp /* Older perls (<=5.003) lack AvFILLp */
+#define AvFILLp AvFILL
+#endif
+typedef double NV; /* Older perls lack the NV type */
+#endif /* PERL_VERSION -- perls < 5.6 */
#ifdef DEBUGME
#ifndef DASSERT
static int store_tied(stcxt_t *cxt, SV *sv);
static int store_tied_item(stcxt_t *cxt, SV *sv);
static int store_other(stcxt_t *cxt, SV *sv);
+static int store_blessed(stcxt_t *cxt, SV *sv, int type, HV *pkg);
static int (*sv_store[])() = {
store_ref, /* svis_REF */
#define RETRIEVE(c,x) (*(c)->retrieve_vtbl[(x) >= SX_ERROR ? SX_ERROR : (x)])
-static SV *mbuf2sv();
-static int store_blessed();
+static SV *mbuf2sv(void);
/***
*** Context management.
*
* Called once per "thread" (interpreter) to initialize some global context.
*/
-static void init_perinterp() {
+static void init_perinterp(void)
+{
INIT_STCXT;
cxt->netorder = 0; /* true if network order used */
*
* Initialize a new store context for real recursion.
*/
-static void init_store_context(cxt, f, optype, network_order)
-stcxt_t *cxt;
-PerlIO *f;
-int optype;
-int network_order;
+static void init_store_context(
+ stcxt_t *cxt,
+ PerlIO *f,
+ int optype,
+ int network_order)
{
TRACEME(("init_store_context"));
*
* It is reported fixed in 5.005, hence the #if.
*/
-#if PATCHLEVEL < 5
+#if PERL_VERSION >= 5
#define HBUCKETS 4096 /* Buckets for %hseen */
HvMAX(cxt->hseen) = HBUCKETS - 1; /* keys %hseen = $HBUCKETS; */
#endif
cxt->hclass = newHV(); /* Where seen classnames are stored */
-#if PATCHLEVEL < 5
+#if PERL_VERSION >= 5
HvMAX(cxt->hclass) = HBUCKETS - 1; /* keys %hclass = $HBUCKETS; */
#endif
*
* Clean store context by
*/
-static void clean_store_context(cxt)
-stcxt_t *cxt;
+static void clean_store_context(stcxt_t *cxt)
{
HE *he;
*
* Tells whether we're in the middle of a store operation.
*/
-int is_storing()
+int is_storing(void)
{
dSTCXT;
*
* Tells whether we're in the middle of a retrieve operation.
*/
-int is_retrieving()
+int is_retrieving(void)
{
dSTCXT;
* This is typically out-of-band information that might prove useful
* to people wishing to convert native to network order data when used.
*/
-int last_op_in_netorder()
+int last_op_in_netorder(void)
{
dSTCXT;
* Returns the routine reference as an SV*, or null if neither the package
* nor its ancestors know about the method.
*/
-static SV *pkg_fetchmeth(cache, pkg, method)
-HV *cache;
-HV *pkg;
-char *method;
+static SV *pkg_fetchmeth(
+ HV *cache,
+ HV *pkg,
+ char *method)
{
GV *gv;
SV *sv;
*
* Force cached value to be undef: hook ignored even if present.
*/
-static void pkg_hide(cache, pkg, method)
-HV *cache;
-HV *pkg;
-char *method;
+static void pkg_hide(
+ HV *cache,
+ HV *pkg,
+ char *method)
{
(void) hv_store(cache,
HvNAME(pkg), strlen(HvNAME(pkg)), newSVsv(&PL_sv_undef), 0);
* Returns the routine reference as an SV*, or null if the object does not
* know about the method.
*/
-static SV *pkg_can(cache, pkg, method)
-HV *cache;
-HV *pkg;
-char *method;
+static SV *pkg_can(
+ HV *cache,
+ HV *pkg,
+ char *method)
{
SV **svh;
SV *sv;
* Call routine as obj->hook(av) in scalar context.
* Propagates the single returned value if not called in void context.
*/
-static SV *scalar_call(obj, hook, cloning, av, flags)
-SV *obj;
-SV *hook;
-int cloning;
-AV *av;
-I32 flags;
+static SV *scalar_call(
+ SV *obj,
+ SV *hook,
+ int cloning,
+ AV *av,
+ I32 flags)
{
dSP;
int count;
* Call routine obj->hook(cloning) in list context.
* Returns the list of returned values in an array.
*/
-static AV *array_call(obj, hook, cloning)
-SV *obj;
-SV *hook;
-int cloning;
+static AV *array_call(
+ SV *obj,
+ SV *hook,
+ int cloning)
{
dSP;
int count;
AV *av;
int i;
- TRACEME(("arrary_call (cloning=%d)", cloning));
+ TRACEME(("array_call (cloning=%d)", cloning));
ENTER;
SAVETMPS;
*
* Return true if the class was known, false if the ID was just generated.
*/
-static int known_class(cxt, name, len, classnum)
-stcxt_t *cxt;
-char *name; /* Class name */
-int len; /* Name length */
-I32 *classnum;
+static int known_class(
+ stcxt_t *cxt,
+ char *name, /* Class name */
+ int len, /* Name length */
+ I32 *classnum)
{
SV **svh;
HV *hclass = cxt->hclass;
* Store a reference.
* Layout is SX_REF <object> or SX_OVERLOAD <object>.
*/
-static int store_ref(cxt, sv)
-stcxt_t *cxt;
-SV *sv;
+static int store_ref(stcxt_t *cxt, SV *sv)
{
TRACEME(("store_ref (0x%lx)", (unsigned long) sv));
* If integer or double, the layout is SX_INTEGER <data> or SX_DOUBLE <data>.
* Small integers (within [-127, +127]) are stored as SX_BYTE <byte>.
*/
-static int store_scalar(cxt, sv)
-stcxt_t *cxt;
-SV *sv;
+static int store_scalar(stcxt_t *cxt, SV *sv)
{
IV iv;
char *pv;
* Layout is SX_ARRAY <size> followed by each item, in increading index order.
* Each item is stored as <object>.
*/
-static int store_array(cxt, av)
-stcxt_t *cxt;
-AV *av;
+static int store_array(stcxt_t *cxt, AV *av)
{
SV **sav;
I32 len = av_len(av) + 1;
* Borrowed from perl source file pp_ctl.c, where it is used by pp_sort.
*/
static int
-sortcmp(a, b)
-const void *a;
-const void *b;
+sortcmp(const void *a, const void *b)
{
return sv_cmp(*(SV * const *) a, *(SV * const *) b);
}
* Keys are stored as <length> <data>, the <data> section being omitted
* if length is 0.
*/
-static int store_hash(cxt, hv)
-stcxt_t *cxt;
-HV *hv;
+static int store_hash(stcxt_t *cxt, HV *hv)
{
I32 len = HvKEYS(hv);
I32 i;
* dealing with a tied hash, we store SX_TIED_HASH <hash object>, where
* <hash object> stands for the serialization of the tied hash.
*/
-static int store_tied(cxt, sv)
-stcxt_t *cxt;
-SV *sv;
+static int store_tied(stcxt_t *cxt, SV *sv)
{
MAGIC *mg;
int ret = 0;
* SX_TIED_KEY <object> <key>
* SX_TIED_IDX <object> <index>
*/
-static int store_tied_item(cxt, sv)
-stcxt_t *cxt;
-SV *sv;
+static int store_tied_item(stcxt_t *cxt, SV *sv)
{
MAGIC *mg;
int ret;
* recursion, until we reach flags indicating no recursion, at which point
* we know we've resynchronized with a single layout, after <flags>.
*/
-static int store_hook(cxt, sv, type, pkg, hook)
-stcxt_t *cxt;
-SV *sv;
-HV *pkg;
-SV *hook;
+static int store_hook(
+ stcxt_t *cxt,
+ SV *sv,
+ int type,
+ HV *pkg,
+ SV *hook)
{
I32 len;
char *class;
* where <index> is the classname index, stored on 0 or 4 bytes depending
* on the high-order bit in flag (same encoding as above for <len>).
*/
-static int store_blessed(cxt, sv, type, pkg)
-stcxt_t *cxt;
-SV *sv;
-int type;
-HV *pkg;
+static int store_blessed(
+ stcxt_t *cxt,
+ SV *sv,
+ int type,
+ HV *pkg)
{
SV *hook;
I32 len;
* true value, then don't croak, just warn, and store a placeholder string
* instead.
*/
-static int store_other(cxt, sv)
-stcxt_t *cxt;
-SV *sv;
+static int store_other(stcxt_t *cxt, SV *sv)
{
STRLEN len;
static char buf[80];
* Returns the type of the SV, identified by an integer. That integer
* may then be used to index the dynamic routine dispatch table.
*/
-static int sv_type(sv)
-SV *sv;
+static int sv_type(SV *sv)
{
switch (SvTYPE(sv)) {
case SVt_NULL:
* object (one for which storage has started -- it may not be over if we have
* a self-referenced structure). This data set forms a stored <object>.
*/
-static int store(cxt, sv)
-stcxt_t *cxt;
-SV *sv;
+static int store(stcxt_t *cxt, SV *sv)
{
SV **svh;
int ret;
* Note that no byte ordering info is emitted when <network> is true, since
* integers will be emitted in network order in that case.
*/
-static int magic_write(cxt)
-stcxt_t *cxt;
+static int magic_write(stcxt_t *cxt)
{
char buf[256]; /* Enough room for 256 hexa digits */
unsigned char c;
* It is required to provide a non-null `res' when the operation type is not
* dclone() and store() is performed to memory.
*/
-static int do_store(f, sv, optype, network_order, res)
-PerlIO *f;
-SV *sv;
-int optype;
-int network_order;
-SV **res;
+static int do_store(
+ PerlIO *f,
+ SV *sv,
+ int optype,
+ int network_order,
+ SV **res)
{
dSTCXT;
int status;
* Store the transitive data closure of given object to disk.
* Returns 0 on error, a true value otherwise.
*/
-int pstore(f, sv)
-PerlIO *f;
-SV *sv;
+int pstore(PerlIO *f, SV *sv)
{
TRACEME(("pstore"));
- return do_store(f, sv, 0, FALSE, (SV**)0);
+ return do_store(f, sv, 0, FALSE, (SV**) 0);
}
* Same as pstore(), but network order is used for integers and doubles are
* emitted as strings.
*/
-int net_pstore(f, sv)
-PerlIO *f;
-SV *sv;
+int net_pstore(PerlIO *f, SV *sv)
{
TRACEME(("net_pstore"));
- return do_store(f, sv, 0, TRUE, (SV**)0);
+ return do_store(f, sv, 0, TRUE, (SV**) 0);
}
/***
*
* Build a new SV out of the content of the internal memory buffer.
*/
-static SV *mbuf2sv()
+static SV *mbuf2sv(void)
{
dSTCXT;
* Store the transitive data closure of given object to memory.
* Returns undef on error, a scalar value containing the data otherwise.
*/
-SV *mstore(sv)
-SV *sv;
+SV *mstore(SV *sv)
{
dSTCXT;
SV *out;
TRACEME(("mstore"));
- if (!do_store((PerlIO*)0, sv, 0, FALSE, &out))
+ if (!do_store((PerlIO*) 0, sv, 0, FALSE, &out))
return &PL_sv_undef;
return out;
* Same as mstore(), but network order is used for integers and doubles are
* emitted as strings.
*/
-SV *net_mstore(sv)
-SV *sv;
+SV *net_mstore(SV *sv)
{
dSTCXT;
SV *out;
TRACEME(("net_mstore"));
- if (!do_store((PerlIO*)0, sv, 0, TRUE, &out))
+ if (!do_store((PerlIO*) 0, sv, 0, TRUE, &out))
return &PL_sv_undef;
return out;
* Return an error via croak, since it is not possible that we get here
* under normal conditions, when facing a file produced via pstore().
*/
-static SV *retrieve_other(cxt)
-stcxt_t *cxt;
+static SV *retrieve_other(stcxt_t *cxt)
{
if (
cxt->ver_major != STORABLE_BIN_MAJOR &&
* Layout is SX_IX_BLESS <index> <object> with SX_IX_BLESS already read.
* <index> can be coded on either 1 or 5 bytes.
*/
-static SV *retrieve_idx_blessed(cxt)
-stcxt_t *cxt;
+static SV *retrieve_idx_blessed(stcxt_t *cxt)
{
I32 idx;
char *class;
* Layout is SX_BLESS <len> <classname> <object> with SX_BLESS already read.
* <len> can be coded on either 1 or 5 bytes.
*/
-static SV *retrieve_blessed(cxt)
-stcxt_t *cxt;
+static SV *retrieve_blessed(stcxt_t *cxt)
{
I32 len;
SV *sv;
* is an unknown amount of serialized objects after the SX_HOOK mark. Until
* we reach a <flags> marker with the recursion bit cleared.
*/
-static SV *retrieve_hook(cxt)
-stcxt_t *cxt;
+static SV *retrieve_hook(stcxt_t *cxt)
{
I32 len;
char buf[LG_BLESS + 1]; /* Avoid malloc() if possible */
* Retrieve reference to some other scalar.
* Layout is SX_REF <object>, with SX_REF already read.
*/
-static SV *retrieve_ref(cxt)
-stcxt_t *cxt;
+static SV *retrieve_ref(stcxt_t *cxt)
{
SV *rv;
SV *sv;
* Retrieve reference to some other scalar with overloading.
* Layout is SX_OVERLOAD <object>, with SX_OVERLOAD already read.
*/
-static SV *retrieve_overloaded(cxt)
-stcxt_t *cxt;
+static SV *retrieve_overloaded(stcxt_t *cxt)
{
SV *rv;
SV *sv;
* Retrieve tied array
* Layout is SX_TIED_ARRAY <object>, with SX_TIED_ARRAY already read.
*/
-static SV *retrieve_tied_array(cxt)
-stcxt_t *cxt;
+static SV *retrieve_tied_array(stcxt_t *cxt)
{
SV *tv;
SV *sv;
* Retrieve tied hash
* Layout is SX_TIED_HASH <object>, with SX_TIED_HASH already read.
*/
-static SV *retrieve_tied_hash(cxt)
-stcxt_t *cxt;
+static SV *retrieve_tied_hash(stcxt_t *cxt)
{
SV *tv;
SV *sv;
* Retrieve reference to value in a tied hash.
* Layout is SX_TIED_KEY <object> <key>, with SX_TIED_KEY already read.
*/
-static SV *retrieve_tied_key(cxt)
-stcxt_t *cxt;
+static SV *retrieve_tied_key(stcxt_t *cxt)
{
SV *tv;
SV *sv;
* Retrieve reference to value in a tied array.
* Layout is SX_TIED_IDX <object> <idx>, with SX_TIED_IDX already read.
*/
-static SV *retrieve_tied_idx(cxt)
-stcxt_t *cxt;
+static SV *retrieve_tied_idx(stcxt_t *cxt)
{
SV *tv;
SV *sv;
* The scalar is "long" in that <length> is larger than LG_SCALAR so it
* was not stored on a single byte.
*/
-static SV *retrieve_lscalar(cxt)
-stcxt_t *cxt;
+static SV *retrieve_lscalar(stcxt_t *cxt)
{
STRLEN len;
SV *sv;
* The scalar is "short" so <length> is single byte. If it is 0, there
* is no <data> section.
*/
-static SV *retrieve_scalar(cxt)
-stcxt_t *cxt;
+static SV *retrieve_scalar(stcxt_t *cxt)
{
int len;
SV *sv;
* Retrieve defined integer.
* Layout is SX_INTEGER <data>, whith SX_INTEGER already read.
*/
-static SV *retrieve_integer(cxt)
-stcxt_t *cxt;
+static SV *retrieve_integer(stcxt_t *cxt)
{
SV *sv;
IV iv;
* Retrieve defined integer in network order.
* Layout is SX_NETINT <data>, whith SX_NETINT already read.
*/
-static SV *retrieve_netint(cxt)
-stcxt_t *cxt;
+static SV *retrieve_netint(stcxt_t *cxt)
{
SV *sv;
int iv;
* Retrieve defined double.
* Layout is SX_DOUBLE <data>, whith SX_DOUBLE already read.
*/
-static SV *retrieve_double(cxt)
-stcxt_t *cxt;
+static SV *retrieve_double(stcxt_t *cxt)
{
SV *sv;
NV nv;
* Retrieve defined byte (small integer within the [-128, +127] range).
* Layout is SX_BYTE <data>, whith SX_BYTE already read.
*/
-static SV *retrieve_byte(cxt)
-stcxt_t *cxt;
+static SV *retrieve_byte(stcxt_t *cxt)
{
SV *sv;
int siv;
*
* Return the undefined value.
*/
-static SV *retrieve_undef(cxt)
-stcxt_t *cxt;
+static SV *retrieve_undef(stcxt_t *cxt)
{
SV* sv;
*
* Return the immortal undefined value.
*/
-static SV *retrieve_sv_undef(cxt)
-stcxt_t *cxt;
+static SV *retrieve_sv_undef(stcxt_t *cxt)
{
SV *sv = &PL_sv_undef;
*
* Return the immortal yes value.
*/
-static SV *retrieve_sv_yes(cxt)
-stcxt_t *cxt;
+static SV *retrieve_sv_yes(stcxt_t *cxt)
{
SV *sv = &PL_sv_yes;
*
* Return the immortal no value.
*/
-static SV *retrieve_sv_no(cxt)
-stcxt_t *cxt;
+static SV *retrieve_sv_no(stcxt_t *cxt)
{
SV *sv = &PL_sv_no;
*
* When we come here, SX_ARRAY has been read already.
*/
-static SV *retrieve_array(cxt)
-stcxt_t *cxt;
+static SV *retrieve_array(stcxt_t *cxt)
{
I32 len;
I32 i;
*
* When we come here, SX_HASH has been read already.
*/
-static SV *retrieve_hash(cxt)
-stcxt_t *cxt;
+static SV *retrieve_hash(stcxt_t *cxt)
{
I32 len;
I32 size;
*
* When we come here, SX_ARRAY has been read already.
*/
-static SV *old_retrieve_array(cxt)
-stcxt_t *cxt;
+static SV *old_retrieve_array(stcxt_t *cxt)
{
I32 len;
I32 i;
continue; /* av_extend() already filled us with undef */
}
if (c != SX_ITEM)
- (void) retrieve_other(0); /* Will croak out */
+ (void) retrieve_other((stcxt_t *) 0); /* Will croak out */
TRACEME(("(#%d) item", i));
- sv = retrieve(cxt); /* Retrieve item */
+ sv = retrieve(cxt); /* Retrieve item */
if (!sv)
return (SV *) 0;
if (av_store(av, i, sv) == 0)
*
* When we come here, SX_HASH has been read already.
*/
-static SV *old_retrieve_hash(cxt)
-stcxt_t *cxt;
+static SV *old_retrieve_hash(stcxt_t *cxt)
{
I32 len;
I32 size;
if (!sv)
return (SV *) 0;
} else
- (void) retrieve_other(0); /* Will croak out */
+ (void) retrieve_other((stcxt_t *) 0); /* Will croak out */
/*
* Get key.
GETMARK(c);
if (c != SX_KEY)
- (void) retrieve_other(0); /* Will croak out */
+ (void) retrieve_other((stcxt_t *) 0); /* Will croak out */
RLEN(size); /* Get key size */
KBUFCHK(size); /* Grow hash key read pool if needed */
if (size)
* Note that there's no byte ordering info emitted when network order was
* used at store time.
*/
-static SV *magic_check(cxt)
-stcxt_t *cxt;
+static SV *magic_check(stcxt_t *cxt)
{
char buf[256];
char byteorder[256];
* root SV (which may be an AV or an HV for what we care).
* Returns null if there is a problem.
*/
-static SV *retrieve(cxt)
-stcxt_t *cxt;
+static SV *retrieve(stcxt_t *cxt)
{
int type;
SV **svh;
* Retrieve data held in file and return the root object.
* Common routine for pretrieve and mretrieve.
*/
-static SV *do_retrieve(f, in, optype)
-PerlIO *f;
-SV *in;
-int optype;
+static SV *do_retrieve(
+ PerlIO *f,
+ SV *in,
+ int optype)
{
dSTCXT;
SV *sv;
*
* Retrieve data held in file and return the root object, undef on error.
*/
-SV *pretrieve(f)
-PerlIO *f;
+SV *pretrieve(PerlIO *f)
{
TRACEME(("pretrieve"));
return do_retrieve(f, Nullsv, 0);
*
* Retrieve data held in scalar and return the root object, undef on error.
*/
-SV *mretrieve(sv)
-SV *sv;
+SV *mretrieve(SV *sv)
{
TRACEME(("mretrieve"));
- return do_retrieve((PerlIO*)0, sv, 0);
+ return do_retrieve((PerlIO*) 0, sv, 0);
}
/***
* there. Not that efficient, but it should be faster than doing it from
* pure perl anyway.
*/
-SV *dclone(sv)
-SV *sv;
+SV *dclone(SV *sv)
{
dSTCXT;
int size;
* we need to allocate one because we're deep cloning from a hook.
*/
- if (!do_store((PerlIO*)0, sv, ST_CLONE, FALSE, (SV**)0))
+ if (!do_store((PerlIO*) 0, sv, ST_CLONE, FALSE, (SV**) 0))
return &PL_sv_undef; /* Error during store */
/*
TRACEME(("dclone stored %d bytes", size));
MBUF_INIT(size);
- out = do_retrieve((PerlIO*)0, Nullsv, ST_CLONE); /* Will free non-root context */
+ out = do_retrieve((PerlIO*) 0, Nullsv, ST_CLONE); /* Will free non-root context */
TRACEME(("dclone returns 0x%lx", (unsigned long) out));