Very thorough re-write of how values are returned from FETCH. See docs.

CVS patchset: 4027
CVS date: 2000/08/06 08:57:09
This commit is contained in:
rjray 2000-08-06 08:57:09 +00:00
parent df88ea3994
commit 727057b831
1 changed files with 234 additions and 120 deletions

View File

@ -4,7 +4,8 @@
#include "RPM.h"
static char * const rcsid = "$Id: Header.xs,v 1.11 2000/08/02 08:05:00 rjray Exp $";
static char * const rcsid = "$Id: Header.xs,v 1.12 2000/08/06 08:57:09 rjray Exp $";
static int scalar_tag(pTHX_ SV *, int);
/*
Use this define for deriving the saved Header struct, rather than coding
@ -47,7 +48,8 @@ static SV* ikey2sv(pTHX_ int key)
}
/* This creates a header data-field from the passed-in data */
static AV* rpmhdr_create(pTHX_ const char* data, int type, int size)
static SV* rpmhdr_create(pTHX_ const char* data, int type, int size,
int scalar)
{
char urk[2];
AV* new_list;
@ -62,7 +64,7 @@ static AV* rpmhdr_create(pTHX_ const char* data, int type, int size)
*/
if (type == RPM_NULL_TYPE)
{
return new_list;
return newSVsv(&PL_sv_undef);
}
else if (type == RPM_BIN_TYPE)
{
@ -170,7 +172,12 @@ static AV* rpmhdr_create(pTHX_ const char* data, int type, int size)
}
}
return new_list;
if (scalar)
new_item = newSVsv(*(av_fetch(new_list, 0, FALSE)));
else
new_item = newRV((SV *)new_list);
return new_item;
}
/* These three are for reading the header data from external sources */
@ -277,7 +284,7 @@ RPM__Header rpmhdr_TIEHASH(pTHX_ SV* class, SV* source, int flags)
return TIEHASH;
}
AV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
const char* data_in, int type_in, int size_in)
{
const char* name; /* For the actual name out of (SV *)key */
@ -285,12 +292,11 @@ AV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
char* uc_name; /* UC'd version of name */
RPM_Header* hdr; /* Pointer to C-level struct */
SV** svp;
SV* ret_undef;
AV* FETCH;
int i;
SV* FETCH;
int i, tag_by_num;
char errmsg[256];
FETCH = newAV();
av_store(FETCH, 0, newSVsv(&PL_sv_undef));
FETCH = newSVsv(&PL_sv_undef);
header_from_object_ret(svp, hdr, self, FETCH);
@ -303,13 +309,22 @@ AV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
uc_name[i] = toUPPER(name[i]);
uc_name[i] = '\0';
/* Get the #define value for the tag from the hash made at boot */
if (! (tag_by_num = tag2num(aTHX_ uc_name)))
{
snprintf(errmsg, 256, "RPM::Header::FETCH: unknown tag '%s'", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
Safefree(uc_name);
return FETCH;
}
/* Check the three keys that are cached directly on the struct itself: */
if (! strcmp(uc_name, "NAME"))
av_store(FETCH, 0, newSVpv((char *)hdr->name, 0));
FETCH = newSVpv((char *)hdr->name, 0);
else if (! strcmp(uc_name, "VERSION"))
av_store(FETCH, 0, newSVpv((char *)hdr->version, 0));
FETCH = newSVpv((char *)hdr->version, 0);
else if (! strcmp(uc_name, "RELEASE"))
av_store(FETCH, 0, newSVpv((char *)hdr->release, 0));
FETCH = newSVpv((char *)hdr->release, 0);
else
{
/* If it wasn't one of those three, then we have to explicitly fetch
@ -317,53 +332,49 @@ AV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
hv_fetch_nomg(svp, self, uc_name, namelen, FALSE);
if (svp && SvOK(*svp))
{
av_undef(FETCH);
FETCH = (AV *)SvRV(*svp);
FETCH = newSVsv(*svp);
if (SvROK(FETCH))
FETCH = SvRV(FETCH);
}
else if (data_in)
{
/* In some cases (particarly the iterators) we could be called
with the data already available, but not hashed just yet. */
AV* new_item = rpmhdr_create(aTHX_ data_in, type_in, size_in);
SV* new_item = rpmhdr_create(aTHX_ data_in, type_in, size_in,
scalar_tag(aTHX_ Nullsv, tag_by_num));
hv_store_nomg(self, uc_name, namelen, newRV_noinc((SV *)new_item),
hv_store_nomg(self, uc_name, namelen, newRV((SV *)new_item),
FALSE);
hv_store_nomg(self, strcat(uc_name, "_t"), (namelen + 2),
newSViv(type_in), FALSE);
av_undef(FETCH);
FETCH = new_item;
}
else
{
AV* new_item;
SV* new_item;
char* new_item_p;
int new_item_type;
int tag_by_num;
int size;
char urk[2];
/* Get the #define value for the tag from the hash made at boot */
if (! (tag_by_num = tag2num(aTHX_ uc_name)))
{
/* Later we need to set some sort of error message */
Safefree(uc_name);
return FETCH;
}
/* Pull the tag by the int value we now have */
if (! headerGetEntry(hdr->hdr, tag_by_num,
&new_item_type, (void **)&new_item_p, &size))
{
snprintf(errmsg, 256,
"RPM::Header::FETCH: no tag '%s' in header", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
Safefree(uc_name);
return FETCH;
}
new_item = rpmhdr_create(aTHX_ new_item_p, new_item_type, size);
new_item = rpmhdr_create(aTHX_ new_item_p, new_item_type, size,
scalar_tag(aTHX_ Nullsv, tag_by_num));
hv_store_nomg(self, uc_name, namelen, newRV_noinc((SV *)new_item),
hv_store_nomg(self, uc_name, namelen, newRV((SV *)new_item),
FALSE);
hv_store_nomg(self, strcat(uc_name, "_t"), (namelen + 2),
newSViv(new_item_type), FALSE);
av_undef(FETCH);
FETCH = new_item;
}
}
@ -376,15 +387,17 @@ AV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
Store the data in "value" both in the header and in the hash associated
with "self".
*/
int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, SV* value)
{
SV** svp;
const char* name;
char* uc_name;
char errmsg[256];
STRLEN namelen;
int size, i;
int size, i, is_scalar;
I32 num_ent, data_type, data_key;
void* data;
AV* a_value = Nullav;
RPM_Header* hdr;
header_from_object_ret(svp, hdr, self, 0);
@ -403,40 +416,137 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
/* Get the numerical tag value for this name. If none exists, this means
that there is no such tag, which is an error in this case */
if (! (num_ent = tag2num(aTHX_ uc_name)))
{
snprintf(errmsg, 256, "RPM::Header::STORE: No such tag '%s'", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
return 0;
}
is_scalar = scalar_tag(Nullsv, num_ent);
if (SvROK(value))
{
/*
This is complicated. We have to allow for straight-in AV*, or a
single-pair HV* that provides the type indexing the data. Then
we get to decide if the data part needs to be promoted to an AV*.
*/
if (SvTYPE(SvRV(value)) == SVt_PVHV)
{
HE* iter;
SV* key;
SV* new_value;
HV* hv_value = (HV *)SvRV(value);
/* There should be exactly one key */
if (hv_iterinit(hv_value) != 1)
{
snprintf(errmsg, 256,
"RPM::Header::STORE: Hash reference passed in for "
"tag '%s' has invalid content", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
return 0;
}
iter = hv_iternext(hv_value);
key = HeSVKEY(iter);
new_value = HeVAL(iter);
if (! (SvIOK(key) && (data_type = SvIV(key))))
{
snprintf(errmsg, 256,
"RPM::Header::STORE: Hash reference key passed in "
"for tag '%s' is invalid", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
return 0;
}
/* Clear this for later sanity-check */
value = Nullsv;
/* Now let's look at new_value */
if (SvROK(new_value))
{
if (SvTYPE(SvRV(new_value)) == SVt_PVAV)
a_value = (AV *)SvRV(new_value);
else
/* Hope for the best... */
value = SvRV(new_value);
}
else
value = new_value;
}
else if (SvTYPE(SvRV(value)) == SVt_PVAV)
{
/*
If they passed a straight-through AV*, de-ref it and mark type
to be filled in later
*/
a_value = (AV *)SvRV(value);
data_type = -1;
value = Nullsv;
}
else
{
/* De-reference it and hope it passes muster as a scalar */
value = SvRV(value);
}
}
/* The only way value will still be set is if nothing else matched */
if (value != Nullsv)
{
/*
The case-block below is already set up to handle data in a manner
transparent to the quantity or type. We can fake this with a_value
and not worry again until actually storing on the hash table for
self.
*/
a_value = newAV();
av_store(a_value, 0, value);
/* Mark type for later setting */
data_type = -1;
}
size = av_len(a_value) + 1;
/*
Setting/STORE-ing means do the following:
1. Confirm that data adheres to type (mostly check against int types)
2. Create the blob in **data
2. Create the blob in **data (based on is_scalar)
3. Store to the header struct
4. Store the AV* on the hash
4. Store the SV* on the hash
*/
/* How many elements being passed? */
size = av_len(value) + 1;
/* This will permanently concat "_t" to uc_name. But we'll craftily
manipulate that later on with namelen. */
hv_fetch_nomg(svp, self, strcat(uc_name, "_t"), (namelen + 2), FALSE);
/* This should NOT happen, but I prefer caution: */
if (! (svp && SvOK(*svp)))
return 0;
data_type = SvIV(*svp);
SvREFCNT_dec(*svp);
if (data_type == -1)
{
/* This will permanently concat "_t" to uc_name. But we'll craftily
manipulate that later on with namelen. */
hv_fetch_nomg(svp, self, strcat(uc_name, "_t"), (namelen + 2), FALSE);
if (! (svp && SvOK(*svp)))
{
/*
If NAME_t does not exist, then this has not been fetched
previously, and worse, we don't really know what the type is
supposed to be. So we state in the docs that the default is
RPM_STRING_TYPE.
*/
data_type = RPM_STRING_TYPE;
}
else
{
data_type = SvIV(*svp);
SvREFCNT_dec(*svp);
}
}
if (data_type == RPM_INT8_TYPE ||
data_type == RPM_INT16_TYPE ||
data_type == RPM_INT32_TYPE)
{
/* Cycle over the array and verify that all elements are valid IVs */
for (i = 0; i <= size; i++)
for (i = 0; i < size; i++)
{
svp = av_fetch(value, i, FALSE);
svp = av_fetch(a_value, i, FALSE);
if (! (SvOK(*svp) && SvIOK(*svp)))
{
rpm_error(aTHX_ RPMERR_BADARG,
"Non-integer value passed for integer-type tag");
"RPM::Header::STORE: Non-integer value passed for "
"integer-type tag");
return 0;
}
}
@ -457,7 +567,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
{
char* data_p;
svp = av_fetch(value, 0, FALSE);
svp = av_fetch(a_value, 0, FALSE);
if (svp && SvPOK(*svp))
data_p = SvPV(*svp, size);
else
@ -482,7 +592,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
efficient way, but it made the rest of things a lot
cleaner. To be safe, only take the initial character from
each SV. */
svp = av_fetch(value, i, FALSE);
svp = av_fetch(a_value, i, FALSE);
if (svp && SvPOK(*svp))
{
str_sv = SvPV(*svp, len);
@ -503,7 +613,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
for (i = 0; i < size; i++)
{
svp = av_fetch(value, i, FALSE);
svp = av_fetch(a_value, i, FALSE);
if (svp && SvIOK(*svp))
*(data_p[i]) = (I8)SvIV(*svp);
else
@ -521,7 +631,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
for (i = 0; i < size; i++)
{
svp = av_fetch(value, i, FALSE);
svp = av_fetch(a_value, i, FALSE);
if (svp && SvIOK(*svp))
*(data_p[i]) = (I16)SvIV(*svp);
else
@ -539,7 +649,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
for (i = 0; i < size; i++)
{
svp = av_fetch(value, i, FALSE);
svp = av_fetch(a_value, i, FALSE);
if (svp && SvIOK(*svp))
*(data_p[i]) = SvIV(*svp);
else
@ -561,7 +671,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
if (data_type == RPM_STRING_TYPE && size == 1)
{
/* Special case for exactly one RPM_STRING_TYPE */
svp = av_fetch(value, 0, FALSE);
svp = av_fetch(a_value, 0, FALSE);
if (svp && SvPOK(*svp))
{
str_sv = SvPV(*svp, len);
@ -579,7 +689,7 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
for (i = 0; i < size; i++)
{
svp = av_fetch(value, i, FALSE);
svp = av_fetch(a_value, i, FALSE);
if (svp && SvPOK(*svp))
{
str_sv = SvPV(*svp, len);
@ -606,7 +716,9 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, AV* value)
/* Store the new data */
headerAddEntry(hdr->hdr, num_ent, data_type, data, size);
/* Store on the hash */
hv_store_nomg(self, uc_name, namelen, newRV_noinc((SV *)value), FALSE);
hv_store_nomg(self, uc_name, namelen,
(is_scalar) ? newSVsv(value) : newRV_noinc((SV *)a_value),
FALSE);
return 1;
}
@ -695,7 +807,7 @@ int rpmhdr_EXISTS(pTHX_ RPM__Header self, SV* key)
return (headerIsEntry(hdr->hdr, tag_by_num));
}
int rpmhdr_FIRSTKEY(pTHX_ RPM__Header self, SV** key, AV** value)
int rpmhdr_FIRSTKEY(pTHX_ RPM__Header self, SV** key, SV** value)
{
SV** svp;
RPM_Header* hdr;
@ -728,7 +840,7 @@ int rpmhdr_FIRSTKEY(pTHX_ RPM__Header self, SV** key, AV** value)
}
int rpmhdr_NEXTKEY(pTHX_ RPM__Header self, SV* key,
SV** nextkey, AV** nextvalue)
SV** nextkey, SV** nextvalue)
{
SV** svp;
RPM_Header* hdr;
@ -822,7 +934,7 @@ int rpmhdr_tagtype(pTHX_ RPM__Header self, SV* key)
key that holds the type isn't available, either. */
/* Do a plain fetch (that is, leave magic on) to populate the other */
AV* sub_fetch = rpmhdr_FETCH(aTHX_ self, key, Nullch, 0, 0);
SV* sub_fetch = rpmhdr_FETCH(aTHX_ self, key, Nullch, 0, 0);
if (sub_fetch)
{
@ -911,47 +1023,9 @@ int rpmhdr_cmpver(pTHX_ RPM__Header self, RPM__Header other)
one that returns a scalar (yields a true return value) or one that returns
an array reference (yields a false value).
*/
int rpmhdr_scalar_tag(pTHX_ SV* self, SV* tag)
static int scalar_tag(pTHX_ SV* self, int tag_value)
{
int tag_value;
/* self is passed in as SV*, and unused, because this is a class method */
if (SvPOK(tag))
{
const char* name;
int i, namelen;
char* uc_name;
name = sv2key(aTHX_ tag);
if (! (name && (namelen = strlen(name))))
return 0;
uc_name = safemalloc(namelen + 1);
for (i = 0; i < namelen; i++)
uc_name[i] = toUPPER(name[i]);
uc_name[i] = '\0';
if (! (tag_value = tag2num(aTHX_ uc_name)))
{
char errmsg[256];
snprintf(errmsg, 256,
"RPM::Header::scalar_tag: unknown tag %s", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
Safefree(uc_name);
return 0;
}
}
else if (SvIOK(tag))
{
tag_value = SvIV(tag);
}
else
{
rpm_error(aTHX_ RPMERR_BADARG,
"RPM::Header::scalar_tag: argument must be string or int");
return 0;
}
switch (tag_value)
{
case RPMTAG_ARCH:
@ -996,6 +1070,7 @@ int rpmhdr_scalar_tag(pTHX_ SV* self, SV* tag)
/* not reached */
}
MODULE = RPM::Header PACKAGE = RPM::Header PREFIX = rpmhdr_
@ -1010,7 +1085,7 @@ rpmhdr_TIEHASH(class, source=NULL, flags=0)
OUTPUT:
RETVAL
AV*
SV*
rpmhdr_FETCH(self, key)
RPM::Header self;
SV* key;
@ -1029,19 +1104,9 @@ rpmhdr_STORE(self, key, value)
PREINIT:
AV* avalue;
CODE:
{
if (sv_isa(value, "AVPtr"))
avalue = (AV *)SvRV(value);
else
{
avalue = newAV();
av_store(avalue, 0, value);
}
RETVAL = rpmhdr_STORE(aTHX_ self, key, avalue);
}
RETVAL = rpmhdr_STORE(aTHX_ self, key, value);
OUTPUT:
RETVAL
RETVAL
int
rpmhdr_DELETE(self, key)
@ -1063,7 +1128,7 @@ rpmhdr_CLEAR(self)
RETVAL = 0;
}
OUTPUT:
RETVAL
RETVAL
int
rpmhdr_EXISTS(self, key)
@ -1081,17 +1146,17 @@ rpmhdr_FIRSTKEY(self)
PROTOTYPE: $
PREINIT:
SV* key;
AV* value;
SV* value;
int i;
PPCODE:
{
if (! rpmhdr_FIRSTKEY(aTHX_ self, &key, &value))
{
key = newSVsv(&PL_sv_undef);
value = newAV();
value = newSVsv(&PL_sv_undef);
}
XPUSHs(sv_2mortal(newRV((SV *)value)));
XPUSHs(sv_2mortal(newSVsv(value)));
XPUSHs(sv_2mortal(newSVsv(key)));
}
@ -1102,17 +1167,17 @@ rpmhdr_NEXTKEY(self, key=NULL)
PROTOTYPE: $;$
PREINIT:
SV* nextkey;
AV* nextvalue;
SV* nextvalue;
int i;
PPCODE:
{
if (! rpmhdr_NEXTKEY(aTHX_ self, key, &nextkey, &nextvalue))
{
nextkey = newSVsv(&PL_sv_undef);
nextvalue = newAV();
nextvalue = newSVsv(&PL_sv_undef);
}
XPUSHs(sv_2mortal(newRV((SV *)nextvalue)));
XPUSHs(sv_2mortal(newSVsv(nextvalue)));
XPUSHs(sv_2mortal(newSVsv(nextkey)));
}
@ -1160,7 +1225,7 @@ rpmhdr_write(self, gv, magicp=0)
RETVAL = rpmhdr_write(aTHX_ self, gv, flag);
}
OUTPUT:
RETVAL
RETVAL
int
rpmhdr_is_source(self)
@ -1206,6 +1271,55 @@ rpmhdr_scalar_tag(self, tag)
SV* tag;
PROTOTYPE: $$
CODE:
RETVAL = rpmhdr_scalar_tag(aTHX_ self, tag);
int tag_value;
if (SvPOK(tag))
{
const char* name;
int i, namelen;
char* uc_name;
/*
A matter of explanation:
By doing this bit here, I can let the real scalar_tag take an
integer argument directly. That means I can call it all over the
place in here, without the overhead of the SV-to-int conversion
below. Only use from outside of the XS code pays that penalty.
*/
name = sv2key(aTHX_ tag);
if (! (name && (namelen = strlen(name))))
RETVAL = 0;
else
{
uc_name = safemalloc(namelen + 1);
for (i = 0; i < namelen; i++)
uc_name[i] = toUPPER(name[i]);
uc_name[i] = '\0';
if (! (tag_value = tag2num(aTHX_ uc_name)))
{
char errmsg[256];
snprintf(errmsg, 256,
"RPM::Header::scalar_tag: unknown tag %s", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
Safefree(uc_name);
RETVAL = 0;
}
RETVAL = scalar_tag(aTHX_ self, tag_value);
}
}
else if (SvIOK(tag))
{
tag_value = SvIV(tag);
RETVAL = scalar_tag(aTHX_ self, tag_value);
}
else
{
rpm_error(aTHX_ RPMERR_BADARG,
"RPM::Header::scalar_tag: argument must be string or int");
RETVAL = 0;
}
OUTPUT:
RETVAL