Wide-range changes and bugfixing. Commit to sync w/ desktop

CVS patchset: 4249
CVS date: 2000/11/10 08:49:57
This commit is contained in:
rjray 2000-11-10 08:49:57 +00:00
parent 843e9e7763
commit 011f727bbf
9 changed files with 266 additions and 285 deletions

View File

@ -1,6 +1,6 @@
#!/bin/perl
# $Id: Makefile.PL,v 1.13 2000/10/13 08:42:32 rjray Exp $
# $Id: Makefile.PL,v 1.14 2000/11/10 08:49:57 rjray Exp $
use Config;
use ExtUtils::MakeMaker;
@ -95,8 +95,9 @@ WriteMakefile(
XS => \%XS,
EXE_FILES => [ @SAMPLES ],
OBJECT => $OBJECT,
INC => "-I. -I$rpm_libdir",
INC => "-Wunused -I. -I$rpm_libdir",
DIR => [],
XSOPT => '-nolinenumbers',
dist => { COMPRESS => 'gzip -9f' },
clean => { FILES => $CLEAN }
);

View File

@ -1,5 +1,5 @@
/*
* $Id: RPM.h,v 1.12 2000/10/10 08:37:20 rjray Exp $
* $Id: RPM.h,v 1.13 2000/11/10 08:49:57 rjray Exp $
*
* Various C-specific decls/includes/etc. for the RPM linkage
*/
@ -51,9 +51,33 @@
#define RPM_HEADER_READONLY 0x01
#define RPM_HEADER_FROM_REF 0x02
#define RPM_PACKAGE_MASK 0xf0
#define RPM_PACKAGE_READONLY 0x10
#define RPM_PACKAGE_NOREAD 0x20
#define RPM_PACKAGE_MASK 0x0f00
#define RPM_PACKAGE_READONLY 0x0100
#define RPM_PACKAGE_NOREAD 0x0200
/*
Use this define for deriving the saved underlying struct, rather than coding
it a dozen places.
*/
#define struct_from_object_ret(type, header, object, err_ret) \
{ \
MAGIC* mg = mg_find((SV *)(object), '~'); \
if (mg) \
(header) = (type *)SvIV(mg->mg_obj); \
else \
return (err_ret); \
}
/* And a no-return version: */
#define struct_from_object(type, header, object) \
{ \
MAGIC* mg = mg_find((SV *)(object), '~'); \
if (mg) \
(header) = (type *)SvIV(mg->mg_obj); \
else \
(header) = Null(type *); \
}
#define new_RPM_storage(type) (type *)safemalloc(sizeof(type))
/*
* Perl complement: RPM::Database
@ -61,9 +85,7 @@
/*
This is the underlying struct that implements the interface to the RPM
database. Since we need the actual object to be a hash, the struct will
be stored as an SV (actually, a pointer to a struct) on a special key
defined below.
database.
*/
typedef struct {
@ -76,12 +98,12 @@ typedef struct {
int offx;
int* offsets;
#endif
/* This HV will be used to cache key/value pairs to avoid re-computing */
HV* storage;
} RPM_Database;
typedef HV* RPM__Database;
#define new_RPM__Database(x) x = newHV()
/*
* Perl complement: RPM::Header
@ -89,9 +111,7 @@ typedef HV* RPM__Database;
/*
This is the underlying struct that implements the interface to the RPM
headers. As above, we need the actual object to be a hash, so the struct
will be stored as an SV on the same sort of special key as RPM__Database
uses.
headers.
*/
typedef struct {
@ -104,6 +124,8 @@ typedef struct {
int isSource; /* If this header is for a source RPM (SRPM) */
int major; /* Major and minor rev numbers of package's format */
int minor;
/* This HV will be used to cache key/value pairs to avoid re-computing */
HV* storage;
/* Keep a per-header iterator for things like FIRSTKEY and NEXTKEY */
HeaderIterator iterator;
int read_only;
@ -114,8 +136,6 @@ typedef struct {
typedef HV* RPM__Header;
#define new_RPM__Header(x) x = newHV()
/*
* Perl complement: RPM::Package
@ -139,34 +159,12 @@ typedef struct {
int readonly;
/* The current notify/callback function associated with this package */
CV* callback;
/* Any data they want to have passed to the callback */
SV* cb_data;
} RPM_Package;
typedef RPM_Package* RPM__Package;
#define new_RPM__Package(x) x = (RPM__Package)safemalloc(sizeof(RPM_Package))
/*
Because our HV* are going to be set magical, the following is needed for
explicit fetch and store calls that are done within the tied FETCH/STORE
methods.
*/
#define hv_fetch_nomg(SVP, h, k, kl, f) \
SvMAGICAL_off((SV *)(h)); \
(SVP) = hv_fetch((h), (k), (kl), (f)); \
SvMAGICAL_on((SV *)(h))
#define hv_store_nomg(h, k, kl, v, f) \
SvMAGICAL_off((SV *)(h)); \
hv_store((h), (k), (kl), (v), (f)); \
SvMAGICAL_on((SV *)(h))
/*
This silly-looking key is what will be used on the RPM::Header and
RPM::Database objects to stash the underlying struct.
*/
#define STRUCT_KEY "<<<struct>>>"
/* This must match! */
#define STRUCT_KEY_LEN 13
/*
These represent the various interfaces that are allowed for use outside
@ -184,11 +182,11 @@ extern void rpm_error(pTHX_ int, const char *);
/* RPM/Header.xs: */
extern const char* sv2key(pTHX_ SV *);
extern RPM__Header rpmhdr_TIEHASH(pTHX_ SV *, SV *, int);
extern RPM__Header rpmhdr_TIEHASH(pTHX_ char *, SV *, int);
extern SV* rpmhdr_FETCH(pTHX_ RPM__Header, SV *, const char *, int, int);
extern int rpmhdr_STORE(pTHX_ RPM__Header, SV *, SV *);
extern int rpmhdr_DELETE(pTHX_ RPM__Header, SV *);
extern int rpmhdr_EXISTS(pTHX_ RPM__Header, SV *);
extern bool rpmhdr_EXISTS(pTHX_ RPM__Header, SV *);
extern unsigned int rpmhdr_size(pTHX_ RPM__Header);
extern int rpmhdr_tagtype(pTHX_ RPM__Header, SV *);
extern int rpmhdr_write(pTHX_ RPM__Header, SV *, int);
@ -199,7 +197,7 @@ extern int rpmhdr_scalar_tag(pTHX_ SV*, int);
/* RPM/Database.xs: */
extern RPM__Database rpmdb_TIEHASH(pTHX_ char *, SV *);
extern RPM__Header rpmdb_FETCH(pTHX_ RPM__Database, SV *);
extern int rpmdb_EXISTS(pTHX_ RPM__Database, SV *);
extern bool rpmdb_EXISTS(pTHX_ RPM__Database, SV *);
/* RPM/Package.xs: */
extern RPM__Package rpmpkg_new(pTHX_ char *, SV *, int);

View File

@ -4,7 +4,7 @@
#include "RPM.h"
static char * const rcsid = "$Id: RPM.xs,v 1.8 2000/10/13 09:24:05 rjray Exp $";
static char * const rcsid = "$Id: RPM.xs,v 1.9 2000/11/10 08:49:57 rjray Exp $";
extern XS(boot_RPM__Constants);
extern XS(boot_RPM__Header);
@ -59,7 +59,6 @@ const char* num2tag(pTHX_ int num)
{
SV** svp;
char str_num[8];
SV* tmp;
Zero(str_num, 1, 8);
snprintf(str_num, 8, "%d", num);

View File

@ -5,7 +5,7 @@
#
###############################################################################
#
# $Id: Database.pm,v 1.11 2000/10/13 08:47:26 rjray Exp $
# $Id: Database.pm,v 1.12 2000/11/10 08:49:57 rjray Exp $
#
# Description: The RPM::Database class provides access to the RPM database
# as a tied hash, whose keys are taken as the names of
@ -36,7 +36,7 @@ require RPM;
require RPM::Header;
$VERSION = '0.291';
$revision = do { my @r=(q$Revision: 1.11 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
$revision = do { my @r=(q$Revision: 1.12 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
1;
@ -46,7 +46,6 @@ sub new
my %hash = ();
tie %hash, $class;
return (tied %hash);
}
###############################################################################

View File

@ -5,22 +5,7 @@
#include <fcntl.h>
#include "RPM.h"
static char * const rcsid = "$Id: Database.xs,v 1.8 2000/10/05 04:48:59 rjray Exp $";
/*
Use this define for deriving the saved rpmdb struct, rather than coding
it a dozen places. Note that the hv_fetch call is the no-magic one defined
in RPM.h
*/
#define dbstruct_from_object_ret(s_ptr, rdb, object, err_ret) \
hv_fetch_nomg((s_ptr), (object), STRUCT_KEY, STRUCT_KEY_LEN, FALSE); \
(rdb) = ((s_ptr) && SvOK(*(s_ptr))) ? (RPM_Database *)SvIV(*(s_ptr)) : NULL; \
if (! (rdb)) return (err_ret);
/* And a no-return-value version: */
#define dbstruct_from_object(s_ptr, rdb, object) \
hv_fetch_nomg((s_ptr), (object), STRUCT_KEY, STRUCT_KEY_LEN, FALSE); \
(rdb) = ((s_ptr) && SvOK(*(s_ptr))) ? (RPM_Database *)SvIV(*(s_ptr)) : NULL; \
if (! (rdb)) return;
static char * const rcsid = "$Id: Database.xs,v 1.9 2000/11/10 08:49:57 rjray Exp $";
/*
rpmdb_TIEHASH
@ -36,10 +21,10 @@ RPM__Database rpmdb_TIEHASH(pTHX_ char* class, SV* opts)
int mode = O_RDONLY;
mode_t perms = 0;
HV* opt_hash;
SV* value;
SV* t_magic;
SV** svp;
RPM_Database* dbstruct;
RPM__Database TIEHASH;
RPM_Database* retvalp; /* For "private" */
RPM__Database RETVAL;
if (opts)
{
@ -68,29 +53,31 @@ RPM__Database rpmdb_TIEHASH(pTHX_ char* class, SV* opts)
}
/* With that all processed, attempt to open the actual RPM DB */
/* The dbstruct is used for the C-level rpmlib information on databases */
dbstruct = safemalloc(sizeof(RPM_Database));
Zero(dbstruct, 1, RPM_Database);
if (rpmdbOpen(root, &dbstruct->dbp, mode, perms) != 0)
/* The retvalp is used for the C-level rpmlib information on databases */
retvalp = new_RPM_storage(RPM_Database);
if (rpmdbOpen(root, &retvalp->dbp, mode, perms) != 0)
/* rpm lib will have set the error already */
return (Null(RPM__Database));
else
{
dbstruct->current_rec = 0;
retvalp->current_rec = 0;
#if RPM_MAJOR < 4
dbstruct->index_set = (void *)NULL;
retvalp->index_set = (void *)NULL;
#else
dbstruct->noffs = dbstruct->offx = 0;
dbstruct->offsets = (int *)NULL;
retvalp->noffs = retvalp->offx = 0;
retvalp->offsets = (int *)NULL;
#endif
}
new_RPM__Database(TIEHASH);
/* STRUCT_KEY is used to stash the C-level struct on the TIEHASH obj */
hv_store_nomg(TIEHASH,
STRUCT_KEY, STRUCT_KEY_LEN, newSViv((unsigned)dbstruct),
FALSE);
return TIEHASH;
RETVAL = newHV();
retvalp->storage = newHV();
t_magic = newSViv((unsigned)retvalp);
sv_magic((SV *)RETVAL, Nullsv, 'P', Nullch, 0);
sv_magic((SV *)RETVAL, t_magic, '~', Nullch, 0);
SvREFCNT_dec(t_magic);
return RETVAL;
}
RPM__Header rpmdb_FETCH(pTHX_ RPM__Database self, SV* key)
@ -109,7 +96,7 @@ RPM__Header rpmdb_FETCH(pTHX_ RPM__Database self, SV* key)
/* Any successful operation will re-assign this */
FETCH = Null(RPM__Header);
dbstruct_from_object_ret(svp, dbstruct, self, FETCH);
struct_from_object_ret(RPM_Database, dbstruct, self, FETCH);
/* De-reference key, if it is a reference */
if (SvROK(key))
key = SvRV(key);
@ -124,10 +111,10 @@ RPM__Header rpmdb_FETCH(pTHX_ RPM__Database self, SV* key)
/* Step 1: Check to see if this has already been requested and is
thus cached on the hash itself */
hv_fetch_nomg(svp, self, (char *)name, namelen, FALSE);
if (svp && SvOK(*svp))
svp = hv_fetch(dbstruct->storage, (char *)name, namelen, FALSE);
if (svp && SvROK(*svp))
{
FETCH = (RPM__Header)SvIV(*svp);
FETCH = (RPM__Header)SvRV(*svp);
return FETCH;
}
@ -201,15 +188,16 @@ RPM__Header rpmdb_FETCH(pTHX_ RPM__Database self, SV* key)
#if RPM_MAJOR >= 4
hdr = headerLink(hdr);
#endif
FETCH = rpmhdr_TIEHASH(aTHX_ sv_2mortal(newSVpv("RPM::Header", 12)),
sv_2mortal(newRV((SV *)hdr)),
FETCH = rpmhdr_TIEHASH(aTHX_ "RPM::Header",
sv_2mortal(newSViv((unsigned)hdr)),
RPM_HEADER_FROM_REF | RPM_HEADER_READONLY);
/* If name is no longer NULL, it means our vector in was a string
(key), so put the result back into the hash-cache. */
if (name != NULL)
{
hv_store_nomg(self, (char *)name, namelen,
newSViv((unsigned)FETCH), FALSE);
hv_store(dbstruct->storage, (char *)name, namelen,
newRV((SV *)FETCH), FALSE);
SvREFCNT_inc((SV *)FETCH);
}
}
#if RPM_MAJOR >= 4
@ -219,13 +207,12 @@ RPM__Header rpmdb_FETCH(pTHX_ RPM__Database self, SV* key)
return FETCH;
}
int rpmdb_EXISTS(pTHX_ RPM__Database self, SV* key)
bool rpmdb_EXISTS(pTHX_ RPM__Database self, SV* key)
{
SV* tmp;
tmp = (SV *)rpmdb_FETCH(aTHX_ self, key);
/* There is probably a cleaner test for (SV *)tmp == PL_sv_undef */
return (SvANY(tmp) != NULL);
return (tmp != Nullsv);
}
/*
@ -237,9 +224,8 @@ int rpmdb_EXISTS(pTHX_ RPM__Database self, SV* key)
int rpmdb_FIRSTKEY(pTHX_ RPM__Database self, SV** key, RPM__Header* value)
{
RPM_Database* dbstruct;
SV** svp;
dbstruct_from_object_ret(svp, dbstruct, self, 0);
struct_from_object_ret(RPM_Database, dbstruct, self, 0);
#if RPM_MAJOR < 4
/* This more or less resets our "iterator" */
dbstruct->current_rec = 0;
@ -285,9 +271,8 @@ int rpmdb_NEXTKEY(pTHX_ RPM__Database self, SV* key,
SV** nextkey, RPM__Header* nextvalue)
{
RPM_Database* dbstruct;
SV** svp;
dbstruct_from_object_ret(svp, dbstruct, self, 0);
struct_from_object_ret(RPM_Database, dbstruct, self, 0);
#if RPM_MAJOR < 4
if (! (dbstruct->current_rec = rpmdbNextRecNum(dbstruct->dbp,
@ -311,10 +296,9 @@ int rpmdb_NEXTKEY(pTHX_ RPM__Database self, SV* key,
void rpmdb_DESTROY(pTHX_ RPM__Database self)
{
SV** svp;
RPM_Database* dbstruct; /* This is the struct used to hold C-level data */
dbstruct_from_object(svp, dbstruct, self);
struct_from_object(RPM_Database, dbstruct, self);
rpmdbClose(dbstruct->dbp);
#if RPM_MAJOR < 4
@ -323,10 +307,10 @@ void rpmdb_DESTROY(pTHX_ RPM__Database self)
#else
if (dbstruct->offsets)
safefree(dbstruct->offsets);
dbstruct->noffs = dbstruct->offx = 0;
dbstruct->offsets = NULL;
#endif
hv_undef(dbstruct->storage);
safefree(dbstruct);
hv_undef(self);
}
@ -349,7 +333,6 @@ AV* rpmdb_find_by_whatever(pTHX_ RPM__Database self, SV* string, int idx)
{
const char* str = NULL; /* For the actual string out of (SV *)string */
STRLEN len; /* Arg for SvPV(..., len) */
SV** svp;
RPM_Database* dbstruct; /* This is the struct used to hold C-level data */
AV* return_val;
int result, loop;
@ -357,11 +340,11 @@ AV* rpmdb_find_by_whatever(pTHX_ RPM__Database self, SV* string, int idx)
#if RPM_MAJOR >= 4
rpmdbMatchIterator mi;
#endif
/* Any successful operation will store items on this */
return_val = newAV();
dbstruct_from_object_ret(svp, dbstruct, self, return_val);
struct_from_object_ret(RPM_Database, dbstruct, self, return_val);
/* De-reference key, if it is a reference */
if (SvROK(string))
string = SvRV(string);
@ -418,6 +401,7 @@ AV* rpmdb_find_by_whatever(pTHX_ RPM__Database self, SV* string, int idx)
return return_val;
}
MODULE = RPM::Database PACKAGE = RPM::Database PREFIX = rpmdb_
@ -442,8 +426,8 @@ rpmdb_FETCH(self, key)
RETVAL
int
rpmdb_STORE(self, key, value)
RPM::Database self;
rpmdb_STORE(self=NULL, key=NULL, value=NULL)
SV* self;
SV* key;
SV* value;
PROTOTYPE: $$$
@ -455,22 +439,22 @@ rpmdb_STORE(self, key, value)
OUTPUT:
RETVAL
int
rpmdb_DELETE(self, key)
RPM::Database self;
SV*
rpmdb_DELETE(self=NULL, key=NULL)
SV* self;
SV* key;
PROTOTYPE: $$
CODE:
{
rpm_error(aTHX_ RPMERR_NOCREATEDB, "DELETE: operation not permitted");
RETVAL = 0;
RETVAL = Nullsv;
}
OUTPUT:
RETVAL
RETVAL
int
rpmdb_CLEAR(self)
RPM::Database self;
rpmdb_CLEAR(self=NULL)
SV* self;
PROTOTYPE: $
CODE:
{
@ -478,9 +462,9 @@ rpmdb_CLEAR(self)
RETVAL = 0;
}
OUTPUT:
RETVAL
RETVAL
int
bool
rpmdb_EXISTS(self, key)
RPM::Database self;
SV* key;
@ -492,13 +476,12 @@ rpmdb_EXISTS(self, key)
void
rpmdb_FIRSTKEY(self)
RPM::Header self;
RPM::Database self;
PROTOTYPE: $
PREINIT:
SV* key;
SV* value;
PPCODE:
{
SV* key;
SV* value;
RPM__Header hvalue;
if (! rpmdb_FIRSTKEY(aTHX_ self, &key, &hvalue))
@ -519,17 +502,16 @@ rpmdb_NEXTKEY(self, key=NULL)
RPM::Database self;
SV* key;
PROTOTYPE: $;$
PREINIT:
SV* nextkey;
SV* nextvalue;
PPCODE:
{
SV* nextkey;
SV* nextvalue;
RPM__Header hvalue;
if (! rpmdb_NEXTKEY(aTHX_ self, key, &nextkey, &hvalue))
{
nextkey = newSVsv(&PL_sv_undef);
nextvalue = newRV(&PL_sv_undef);
nextvalue = newSVsv(&PL_sv_undef);
}
else
nextvalue = newRV((SV *)hvalue);

View File

@ -5,7 +5,7 @@
#
###############################################################################
#
# $Id: Header.pm,v 1.14 2000/10/13 08:47:26 rjray Exp $
# $Id: Header.pm,v 1.15 2000/11/10 08:49:57 rjray Exp $
#
# Description: The RPM::Header class provides access to the RPM Header
# structure as a tied hash, allowing direct access to the
@ -39,7 +39,7 @@ use RPM::Error;
use RPM::Constants ':rpmerr';
$VERSION = '0.291';
$revision = do { my @r=(q$Revision: 1.14 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
$revision = do { my @r=(q$Revision: 1.15 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
@ISA = qw(Exporter);
@EXPORT = ();
@ -69,7 +69,6 @@ sub new
my %hash = ();
tie %hash, $class, @_;
return (tied %hash);
}
###############################################################################

View File

@ -4,24 +4,30 @@
#include "RPM.h"
static char * const rcsid = "$Id: Header.xs,v 1.19 2000/10/12 05:09:16 rjray Exp $";
static char * const rcsid = "$Id: Header.xs,v 1.20 2000/11/10 08:49:57 rjray Exp $";
static int scalar_tag(pTHX_ SV *, int);
/*
Use this define for deriving the saved Header struct, rather than coding
it a dozen places. Note that the hv_fetch call is the no-magic one defined
in RPM.h
it a dozen places.
*/
#define header_from_object_ret(s_ptr, header, object, err_ret) \
hv_fetch_nomg((s_ptr), (object), STRUCT_KEY, STRUCT_KEY_LEN, FALSE); \
(header) = ((s_ptr) && SvOK(*(s_ptr))) ? (RPM_Header *)SvIV(*(s_ptr)) : NULL; \
if (! (header)) \
return (err_ret);
#define header_from_object_ret(header, object, err_ret) \
{ \
MAGIC* mg = mg_find((SV *)(object), '~'); \
if (mg) \
(header) = (RPM_Header *)SvIV(mg->mg_obj); \
else \
return (err_ret); \
}
/* And a no-return version: */
#define header_from_object(s_ptr, header, object) \
hv_fetch_nomg((s_ptr), (object), STRUCT_KEY, STRUCT_KEY_LEN, FALSE); \
(header) = ((s_ptr) && SvOK(*(s_ptr))) ? (RPM_Header *)SvIV(*(s_ptr)) : NULL;
#define header_from_object(header, object) \
{ \
MAGIC* mg = mg_find((SV *)(object), '~'); \
if (mg) \
(header) = (RPM_Header *)SvIV(mg->mg_obj); \
else \
(header) = Null(RPM_Header *); \
}
/* Any constants that are specific to the RPM::Header class will be exported
from here, via this C-level constant() routine */
@ -75,11 +81,6 @@ SV* key2sv(pTHX_ const char* key)
return (sv_2mortal(newSVpv((char *)key, PL_na)));
}
static SV* ikey2sv(pTHX_ int key)
{
return (sv_2mortal(newSViv(key)));
}
/* This creates a header data-field from the passed-in data */
static SV* rpmhdr_create(pTHX_ const char* data, int type, int size,
int scalar)
@ -250,7 +251,7 @@ static int new_from_fname(pTHX_ const char* source, RPM_Header* new_hdr)
return 0;
}
if (retval = new_from_fd_t(fd, new_hdr))
if ((retval = new_from_fd_t(fd, new_hdr)))
{
Fclose(fd);
new_hdr->source_name = safemalloc(strlen(source) + 1);
@ -260,19 +261,20 @@ static int new_from_fname(pTHX_ const char* source, RPM_Header* new_hdr)
return retval;
}
RPM__Header rpmhdr_TIEHASH(pTHX_ SV* class, SV* source, int flags)
RPM__Header rpmhdr_TIEHASH(pTHX_ char* class, SV* source, int flags)
{
char* fname;
int fname_len;
RPM__Header TIEHASH;
RPM_Header* hdr_struct; /* Use this to store the actual C-level data */
RPM__Header RETVAL;
RPM_Header* retvalp; /* Use this to store the actual C-level data */
SV* t_magic;
hdr_struct = safemalloc(sizeof(RPM_Header));
Zero(hdr_struct, 1, RPM_Header);
TIEHASH = Null(RPM__Header);
retvalp = new_RPM_storage(RPM_Header);
Zero(retvalp, 1, RPM_Header);
RETVAL = Nullhv;
if (! source)
hdr_struct->hdr = headerNew();
retvalp->hdr = headerNew();
else if (! (flags & RPM_HEADER_FROM_REF))
{
/* If we aren't starting out with a pointer to a Header
@ -282,52 +284,59 @@ RPM__Header rpmhdr_TIEHASH(pTHX_ SV* class, SV* source, int flags)
if (SvPOK(source))
{
fname = SvPV(source, fname_len);
if (! new_from_fname(aTHX_ fname, hdr_struct))
if (! new_from_fname(aTHX_ fname, retvalp))
{
return TIEHASH;
return RETVAL;
}
}
else if (IoIFP(sv_2io(source)))
{
if (! new_from_fd(PerlIO_fileno(IoIFP(sv_2io(source))),
hdr_struct))
retvalp))
{
return TIEHASH;
return RETVAL;
}
}
else
{
rpm_error(aTHX_ RPMERR_BADARG,
"Argument 2 must be filename or GLOB");
return TIEHASH;
return RETVAL;
}
}
else
{
hdr_struct->hdr = (Header)SvRV(source);
retvalp->hdr = (Header)SvIV(source);
/* We simply don't know these three settings at this point */
hdr_struct->isSource = 0;
hdr_struct->major = 0;
hdr_struct->minor = 0;
retvalp->isSource = 0;
retvalp->major = 0;
retvalp->minor = 0;
}
/* These three are likely to be most of the data requests, anyway */
headerNVR(hdr_struct->hdr,
&hdr_struct->name, &hdr_struct->version, &hdr_struct->release);
headerNVR(retvalp->hdr,
&retvalp->name, &retvalp->version, &retvalp->release);
/* This defaults to false, but RPM::Database will set it true */
hdr_struct->read_only = flags & RPM_HEADER_READONLY;
retvalp->read_only = flags & RPM_HEADER_READONLY;
hdr_struct->iterator = (HeaderIterator)NULL;
retvalp->iterator = (HeaderIterator)NULL;
new_RPM__Header(TIEHASH);
retvalp->storage = newHV();
RETVAL = newHV();
t_magic = newSViv((unsigned)retvalp);
/* With the actual HV*, store the type-keys for the three cached values: */
hv_store_nomg(TIEHASH, "NAME_t", 7, newSViv(RPM_STRING_TYPE), FALSE);
hv_store_nomg(TIEHASH, "VERSION_t", 10, newSViv(RPM_STRING_TYPE), FALSE);
hv_store_nomg(TIEHASH, "RELEASE_t", 10, newSViv(RPM_STRING_TYPE), FALSE);
hv_store_nomg(TIEHASH,
STRUCT_KEY, STRUCT_KEY_LEN,
newSViv((unsigned)hdr_struct), FALSE);
return TIEHASH;
hv_store(retvalp->storage,
"NAME_t", 7, newSViv(RPM_STRING_TYPE), FALSE);
hv_store(retvalp->storage,
"VERSION_t", 10, newSViv(RPM_STRING_TYPE), FALSE);
hv_store(retvalp->storage,
"RELEASE_t", 10, newSViv(RPM_STRING_TYPE), FALSE);
sv_magic((SV *)RETVAL, Nullsv, 'P', Nullch, 0);
sv_magic((SV *)RETVAL, t_magic, '~', Nullch, 0);
SvREFCNT_dec(t_magic);
return RETVAL;
}
SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
@ -344,7 +353,7 @@ SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
FETCH = newSVsv(&PL_sv_undef);
header_from_object_ret(svp, hdr, self, FETCH);
struct_from_object_ret(RPM_Header, hdr, self, FETCH);
name = sv2key(aTHX_ key);
if (! (name && (namelen = strlen(name))))
@ -375,7 +384,7 @@ SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
{
/* If it wasn't one of those three, then we have to explicitly fetch
it, either from the store in cache or via the headerGetEntry call */
hv_fetch_nomg(svp, self, uc_name, namelen, FALSE);
svp = hv_fetch(hdr->storage, uc_name, namelen, FALSE);
if (svp && SvOK(*svp))
{
FETCH = newSVsv(*svp);
@ -389,10 +398,10 @@ SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
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((SV *)new_item),
FALSE);
hv_store_nomg(self, strcat(uc_name, "_t"), (namelen + 2),
newSViv(type_in), FALSE);
hv_store(hdr->storage, uc_name, namelen, newRV((SV *)new_item),
FALSE);
hv_store(hdr->storage, strcat(uc_name, "_t"), (namelen + 2),
newSViv(type_in), FALSE);
FETCH = new_item;
}
@ -402,7 +411,6 @@ SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
char* new_item_p;
int new_item_type;
int size;
char urk[2];
/* Pull the tag by the int value we now have */
if (! headerGetEntry(hdr->hdr, tag_by_num,
@ -417,10 +425,10 @@ SV* rpmhdr_FETCH(pTHX_ RPM__Header self, SV* key,
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((SV *)new_item),
FALSE);
hv_store_nomg(self, strcat(uc_name, "_t"), (namelen + 2),
newSViv(new_item_type), FALSE);
hv_store(hdr->storage, uc_name, namelen, newRV((SV *)new_item),
FALSE);
hv_store(hdr->storage, strcat(uc_name, "_t"), (namelen + 2),
newSViv(new_item_type), FALSE);
FETCH = new_item;
}
}
@ -441,12 +449,12 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, SV* value)
char errmsg[256];
STRLEN namelen;
int size, i, is_scalar;
I32 num_ent, data_type, data_key;
I32 num_ent, data_type;
void* data;
AV* a_value = Nullav;
RPM_Header* hdr;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
if (hdr->read_only)
return 0;
@ -562,7 +570,8 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, SV* value)
{
/* 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);
svp = hv_fetch(hdr->storage, strcat(uc_name, "_t"), (namelen + 2),
FALSE);
if (! (svp && SvOK(*svp)))
{
/*
@ -771,9 +780,9 @@ int rpmhdr_STORE(pTHX_ RPM__Header self, SV* key, SV* 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,
(is_scalar) ? newSVsv(value) : newRV_noinc((SV *)a_value),
FALSE);
hv_store(hdr->storage, uc_name, namelen,
(is_scalar) ? newSVsv(value) : newRV_noinc((SV *)a_value),
FALSE);
return 1;
}
@ -784,10 +793,9 @@ int rpmhdr_DELETE(pTHX_ RPM__Header self, SV* key)
int namelen; /* Arg for SvPV(..., len) */
char* uc_name; /* UC'd version of name */
RPM_Header* hdr; /* Pointer to C-level struct */
SV** svp;
int retval, num, i;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
if (hdr->read_only)
return 0;
@ -821,11 +829,8 @@ int rpmhdr_DELETE(pTHX_ RPM__Header self, SV* key)
}
else
{
/* Remove magic long enough to do two hv_delete() calls */
SvMAGICAL_off((SV *)self);
hv_delete(self, uc_name, namelen, G_DISCARD);
hv_delete(self, strcat(uc_name, "_t"), namelen + 2, G_DISCARD);
SvMAGICAL_on((SV *)self);
hv_delete(hdr->storage, uc_name, namelen, G_DISCARD);
hv_delete(hdr->storage, strcat(uc_name, "_t"), namelen + 2, G_DISCARD);
retval = 1;
}
@ -833,15 +838,14 @@ int rpmhdr_DELETE(pTHX_ RPM__Header self, SV* key)
return retval;
}
int rpmhdr_EXISTS(pTHX_ RPM__Header self, SV* key)
bool rpmhdr_EXISTS(pTHX_ RPM__Header self, SV* key)
{
const char* name;
char* uc_name;
int namelen, tag_by_num, i;
SV** svp;
RPM_Header* hdr;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
name = sv2key(aTHX_ key);
if (! (name && (namelen = strlen(name))))
return 0;
@ -856,21 +860,27 @@ int rpmhdr_EXISTS(pTHX_ RPM__Header self, SV* key)
tag_by_num = tag2num(aTHX_ uc_name);
Safefree(uc_name);
if (! tag_by_num)
/* Later we need to set some sort of error message */
{
char errmsg[256];
snprintf(errmsg, 256,
"RPM::Header::EXISTS: unknown (to rpm) tag %s", uc_name);
rpm_error(aTHX_ RPMERR_BADARG, errmsg);
Safefree(uc_name);
return 0;
}
return (headerIsEntry(hdr->hdr, tag_by_num));
}
int rpmhdr_FIRSTKEY(pTHX_ RPM__Header self, SV** key, SV** value)
{
SV** svp;
RPM_Header* hdr;
int tag, type, size;
char* ptr;
const char* tagname;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
/* If there is an existing iterator attached to the struct, free it */
if (hdr->iterator)
headerFreeIterator(hdr->iterator);
@ -897,13 +907,12 @@ int rpmhdr_FIRSTKEY(pTHX_ RPM__Header self, SV** key, SV** value)
int rpmhdr_NEXTKEY(pTHX_ RPM__Header self, SV* key,
SV** nextkey, SV** nextvalue)
{
SV** svp;
RPM_Header* hdr;
int tag, type, size;
char* ptr;
const char* tagname;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
/* If there is not an existing iterator, we can't continue */
if (! hdr->iterator)
return 0;
@ -932,10 +941,9 @@ int rpmhdr_NEXTKEY(pTHX_ RPM__Header self, SV* key,
void rpmhdr_DESTROY(pTHX_ RPM__Header self)
{
SV** svp;
RPM_Header* hdr;
header_from_object(svp, hdr, self);
struct_from_object(RPM_Header, hdr, self);
if (! hdr) return;
if (hdr->iterator)
@ -943,15 +951,16 @@ void rpmhdr_DESTROY(pTHX_ RPM__Header self)
if (hdr->hdr)
headerFree(hdr->hdr);
hv_undef(hdr->storage);
Safefree(hdr);
hv_undef(self);
}
unsigned int rpmhdr_size(pTHX_ RPM__Header self)
{
SV** svp;
RPM_Header* hdr;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
if (! hdr->hdr)
return 0;
@ -966,6 +975,9 @@ int rpmhdr_tagtype(pTHX_ RPM__Header self, SV* key)
char* uc_name;
SV** svp;
int i, retval;
RPM_Header* hdr;
struct_from_object_ret(RPM_Header, hdr, self, 0);
name = sv2key(aTHX_ key);
if (! (name && (namelen = strlen(name))))
@ -979,7 +991,7 @@ int rpmhdr_tagtype(pTHX_ RPM__Header self, SV* key)
retval = RPM_NULL_TYPE;
hv_fetch_nomg(svp, self, uc_name, strlen(uc_name) + 1, FALSE);
svp = hv_fetch(hdr->storage, uc_name, strlen(uc_name), FALSE);
if (svp && SvOK(*svp))
{
/* The base tag has already been fetched and thus we have a type */
@ -995,12 +1007,14 @@ int rpmhdr_tagtype(pTHX_ RPM__Header self, SV* key)
if (sub_fetch)
{
hv_fetch_nomg(svp, self, uc_name, strlen(uc_name), FALSE);
svp = hv_fetch(hdr->storage, uc_name, strlen(uc_name), FALSE);
if (svp && SvOK(*svp))
{
/* The base tag has now been fetched */
retval = SvIV(*svp);
}
SvREFCNT_dec(*svp);
SvREFCNT_dec(sub_fetch);
}
}
@ -1015,12 +1029,11 @@ int rpmhdr_write(pTHX_ RPM__Header self, SV* gv_in, int magicp)
FD_t fd;
RPM_Header* hdr;
GV* gv;
SV** svp;
int written = 0;
gv = (SvPOK(gv_in) && (SvTYPE(gv_in) == SVt_PVGV)) ?
(GV *)SvRV(gv_in) : (GV *)gv_in;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
if (!gv || !(io = GvIO(gv)) || !(fp = IoIFP(io)))
return written;
@ -1036,10 +1049,9 @@ int rpmhdr_write(pTHX_ RPM__Header self, SV* gv_in, int magicp)
/* T/F test whether the header references a SRPM */
int rpmhdr_is_source(pTHX_ RPM__Header self)
{
SV** svp;
RPM_Header* hdr;
header_from_object_ret(svp, hdr, self, 0);
struct_from_object_ret(RPM_Header, hdr, self, 0);
if (! hdr->hdr)
return 0;
@ -1055,16 +1067,15 @@ int rpmhdr_cmpver(pTHX_ RPM__Header self, RPM__Header other)
{
RPM_Header* one;
RPM_Header* two;
SV** svp;
header_from_object(svp, one, self);
struct_from_object(RPM_Header, one, self);
if (! one)
{
rpm_error(aTHX_ RPMERR_BADARG,
"RPM::Header::rpmhdr_cmpver: Arg 1 has no header data");
return 0;
}
header_from_object(svp, two, other);
struct_from_object(RPM_Header, two, other);
if (! two)
{
rpm_error(aTHX_ RPMERR_BADARG,
@ -1081,10 +1092,9 @@ int rpmhdr_cmpver(pTHX_ RPM__Header self, RPM__Header other)
*/
char* rpmhdr_source_name(RPM__Header self)
{
SV** svp;
RPM_Header* hdr;
header_from_object(svp, hdr, self);
struct_from_object(RPM_Header, hdr, self);
return hdr->source_name;
}
@ -1146,7 +1156,7 @@ MODULE = RPM::Header PACKAGE = RPM::Header PREFIX = rpmhdr_
RPM::Header
rpmhdr_TIEHASH(class, source=NULL, flags=0)
SV* class;
char* class;
SV* source;
int flags;
PROTOTYPE: $;$$
@ -1171,8 +1181,6 @@ rpmhdr_STORE(self, key, value)
SV* key;
SV* value;
PROTOTYPE: $$$
PREINIT:
AV* avalue;
CODE:
RETVAL = rpmhdr_STORE(aTHX_ self, key, value);
OUTPUT:
@ -1189,8 +1197,8 @@ rpmhdr_DELETE(self, key)
RETVAL
int
rpmhdr_CLEAR(self)
RPM::Header self;
rpmhdr_CLEAR(self=NULL)
SV* self;
PROTOTYPE: $
CODE:
{
@ -1200,7 +1208,7 @@ rpmhdr_CLEAR(self)
OUTPUT:
RETVAL
int
bool
rpmhdr_EXISTS(self, key)
RPM::Header self;
SV* key;
@ -1214,12 +1222,11 @@ void
rpmhdr_FIRSTKEY(self)
RPM::Header self;
PROTOTYPE: $
PREINIT:
SV* key;
SV* value;
int i;
PPCODE:
{
SV* key;
SV* value;
if (! rpmhdr_FIRSTKEY(aTHX_ self, &key, &value))
{
key = newSVsv(&PL_sv_undef);
@ -1235,12 +1242,11 @@ rpmhdr_NEXTKEY(self, key=NULL)
RPM::Header self;
SV* key;
PROTOTYPE: $;$
PREINIT:
SV* nextkey;
SV* nextvalue;
int i;
PPCODE:
{
SV* nextkey;
SV* nextvalue;
if (! rpmhdr_NEXTKEY(aTHX_ self, key, &nextkey, &nextvalue))
{
nextkey = newSVsv(&PL_sv_undef);
@ -1322,10 +1328,9 @@ rpmhdr_NVR(self)
PROTOTYPE: $
PPCODE:
{
SV** svp;
RPM_Header* hdr;
header_from_object(svp, hdr, self);
struct_from_object(RPM_Header, hdr, self);
if (hdr->name)
{

View File

@ -5,10 +5,28 @@ use RPM::Database;
$SIG{__WARN__} = sub { $@ = shift; };
$SIG{__DIE__} = sub { $@ = shift; };
print "1..12\n";
print "1..13\n";
$count = 1;
#
# Prior to starting up, we need to do some less-direct queries of the RPM
# database, so that we have baseline data to test against.
#
@all_packs = `rpm -q -a --queryformat "\%{NAME}\\n"`;
chomp(@all_packs);
$all_packs{$_}++ for (@all_packs);
#
# With a full list of packages now known, find one to use for package existence
# testing.
#
for (qw(rpm kernel bash file passwd))
{
$test_pack = $_, last if (exists $all_packs{$_});
}
tie %DB, "RPM::Database" or print "not ";
print "ok 1\n";
print "ok $count\n"; $count++;
unless (tied %DB)
{
@ -16,28 +34,31 @@ unless (tied %DB)
exit -1;
}
# This package must exist, obviously
$rpm = $DB{rpm};
# Start with the test package
$rpm = $DB{$test_pack};
print "not " unless (defined $rpm and ref $rpm);
print "ok 2\n";
print "ok $count\n"; $count++;
# Verify that STORE, DELETE and CLEAR operations are blocked
# STORE
eval { $DB{foo_package} = 'baz'; print "not " if ($DB{foo_package} eq 'baz') };
print "ok 3\n";
eval {
$DB{foo_package} = 'baz';
print "not " if (exists $DB{foo_package} and ($DB{foo_package} eq 'baz'));
};
print "ok $count\n"; $count++;
# DELETE
eval { delete $DB{foo_package} and print "not " };
print "ok 4\n";
print "ok $count\n"; $count++;
# CLEAR
eval { %DB = () and print "not " };
print "ok 5\n";
print "ok $count\n"; $count++;
# Test the untying
eval { untie %DB };
print "not " if ($@);
print "ok 6\n";
print "ok $count\n"; $count++;
# That should cover the basic TIEHASH operands sufficiently.
@ -49,29 +70,33 @@ print "ok 6\n";
# Test the non-tie approach
$rpm = new RPM::Database;
print "not " unless (defined $rpm and ref $rpm);
print "ok 7\n";
print "ok $count\n"; $count++;
# Ensure that the same test package is visible
print "not " unless (exists $rpm->{$test_pack} and ref($rpm->{$test_pack}));
print "ok $count\n"; $count++;
@matches = $rpm->find_by_file('/bin/rpm');
# There should be exactly one match:
print "not " unless (@matches == 1);
print "ok 8\n";
print "ok $count\n"; $count++;
print "not " unless ($matches[0]->{name} eq 'rpm');
print "ok 9\n";
print "ok $count\n"; $count++;
# There may be more than one package that depends on rpm
@matches = $rpm->find_by_required_by('rpm');
for (@matches) { $_ = $_->{name} }
# As long as we see this one (it has to be present to build this package)
print "not " unless (grep 'rpm-devel', @matches);
print "ok 10\n";
print "not " unless (grep($_ eq 'rpm-devel', @matches));
print "ok $count\n"; $count++;
# Try to fetch a bogus package
$hdr = $rpm->{i_hope_no_one_makes_a_package_by_this_name};
print "not " if $hdr;
print "ok 11\n";
print "ok $count\n"; $count++;
undef $rpm;
print "ok 12\n";
print "ok $count\n"; $count++;
exit 0;

View File

@ -3,35 +3,18 @@
TYPEMAP
const char * T_PTROBJ
RPM::Database O_RPM_Database
RPM::Header O_RPM_Header
RPM::Database O_RPM_Tied
RPM::Header O_RPM_Tied
RPM::Package O_RPM_Blessed
RPM::Transaction O_RPM_Blessed
#
# The following mappings for O_HvRV are taken directly from Dean Roehrich's
# excellent XS Cookbook, vol. A.
#
OUTPUT
O_RPM_Database
O_RPM_Tied
if ($var)
{
$arg = sv_bless(newRV_noinc((SV*)$var),
gv_stashpv("RPM::Database", TRUE));
hv_magic($var, (GV *)Nullhv, 'P');
}
else
{
$arg = newSVsv(&PL_sv_undef);
}
O_RPM_Header
if ($var)
{
$arg = sv_bless(newRV_noinc((SV*)$var),
gv_stashpv("RPM::Header", TRUE));
hv_magic($var, (GV *)Nullhv, 'P');
$arg = sv_bless(sv_2mortal(newRV_noinc((SV*)$var)),
gv_stashpv(\"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",
TRUE));
}
else
{
@ -50,17 +33,7 @@ O_RPM_Blessed
}
INPUT
O_RPM_Database
if (sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV))
$var = (HV*)SvRV($arg);
else
{
rpm_error(aTHX_ RPMERR_BADARG,
\"${Package}::$func_name: not a blessed HV reference\");
XSRETURN_UNDEF;
}
O_RPM_Header
O_RPM_Tied
if (sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV))
$var = (HV*)SvRV($arg);
else