diff options
-rw-r--r-- | Perl-RPM/Makefile.PL | 5 | ||||
-rw-r--r-- | Perl-RPM/RPM.h | 80 | ||||
-rw-r--r-- | Perl-RPM/RPM.xs | 3 | ||||
-rw-r--r-- | Perl-RPM/RPM/Database.pm | 5 | ||||
-rw-r--r-- | Perl-RPM/RPM/Database.xs | 130 | ||||
-rw-r--r-- | Perl-RPM/RPM/Header.pm | 5 | ||||
-rw-r--r-- | Perl-RPM/RPM/Header.xs | 223 | ||||
-rwxr-xr-x | Perl-RPM/t/01_database.t | 59 | ||||
-rw-r--r-- | Perl-RPM/typemap | 41 |
9 files changed, 266 insertions, 285 deletions
diff --git a/Perl-RPM/Makefile.PL b/Perl-RPM/Makefile.PL index e4618cb7b..349488753 100644 --- a/Perl-RPM/Makefile.PL +++ b/Perl-RPM/Makefile.PL @@ -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 } ); diff --git a/Perl-RPM/RPM.h b/Perl-RPM/RPM.h index fb745e31a..270179e04 100644 --- a/Perl-RPM/RPM.h +++ b/Perl-RPM/RPM.h @@ -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); diff --git a/Perl-RPM/RPM.xs b/Perl-RPM/RPM.xs index 865560df6..092ce11c0 100644 --- a/Perl-RPM/RPM.xs +++ b/Perl-RPM/RPM.xs @@ -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); diff --git a/Perl-RPM/RPM/Database.pm b/Perl-RPM/RPM/Database.pm index d5933568e..e1e2df2e8 100644 --- a/Perl-RPM/RPM/Database.pm +++ b/Perl-RPM/RPM/Database.pm @@ -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); } ############################################################################### diff --git a/Perl-RPM/RPM/Database.xs b/Perl-RPM/RPM/Database.xs index f33399010..bfbd6a3ef 100644 --- a/Perl-RPM/RPM/Database.xs +++ b/Perl-RPM/RPM/Database.xs @@ -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); diff --git a/Perl-RPM/RPM/Header.pm b/Perl-RPM/RPM/Header.pm index 6e3e39dae..fd2dc2025 100644 --- a/Perl-RPM/RPM/Header.pm +++ b/Perl-RPM/RPM/Header.pm @@ -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); } ############################################################################### diff --git a/Perl-RPM/RPM/Header.xs b/Perl-RPM/RPM/Header.xs index fc6da1f94..1e30f1aa6 100644 --- a/Perl-RPM/RPM/Header.xs +++ b/Perl-RPM/RPM/Header.xs @@ -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) { diff --git a/Perl-RPM/t/01_database.t b/Perl-RPM/t/01_database.t index d4188de09..80955d290 100755 --- a/Perl-RPM/t/01_database.t +++ b/Perl-RPM/t/01_database.t @@ -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; diff --git a/Perl-RPM/typemap b/Perl-RPM/typemap index cce50bcc5..a6028019e 100644 --- a/Perl-RPM/typemap +++ b/Perl-RPM/typemap @@ -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 - 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 +O_RPM_Tied 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 |