#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include "RPM.h" /* rpmdb_TIEHASH This is the implementation of the tied-hash class constructor. The XS wrapper will verify that the value of class is correct, then massage the arguments as needed. The return value is expected to be either NULL or a valid RPM__Database value (which the XS wrapper will fix up). */ RPM__Database rpmdb_TIEHASH(pTHX_ char* class, SV* opts) { char* root = (char *)NULL; int mode = O_RDONLY; mode_t perms = 0; HV* opt_hash; SV** svp; RPM_Database* retvalp; /* For "private" */ if (opts) { if (SvROK(opts) && (SvTYPE(opts) == SVt_PVHV)) { /* This is a hash reference. We are concerned only with the key "root". "mode" and "perms" don't apply, as we are going to open the database as read-only. */ opt_hash = (HV*)SvRV(opts); svp = hv_fetch(opt_hash, "root", 4, FALSE); if (svp && SvPOK(*svp)) root = SvPV_nolen(*svp); } else if (SvPOK(opts)) { /* They passed a scalar, assumed to be the "root" */ root = SvPV_nolen(opts); } else { rpmError(RPMERR_BADARG, "Wrong type for argument 2 to TIEHASH"); return (Null(RPM__Database)); } } /* With that all processed, attempt to open the actual RPM DB */ /* The retvalp is used for the C-level rpmlib information on databases */ Newz(0, retvalp, 1, RPM_Database); if (rpmdbOpen(root, &retvalp->dbp, mode, perms) != 0) { Safefree(retvalp); /* rpm lib will have set the error already */ return (Null(RPM__Database)); } return retvalp; } RPM__Header rpmdb_FETCH(pTHX_ RPM__Database dbstruct, const char *name) { Header h, hi; rpmdbMatchIterator mi; RPM__Header hdr = Null(RPM__Header); h = Null(Header); mi = rpmdbInitIterator(dbstruct->dbp, RPMTAG_NAME, name, 0); while ((hi = rpmdbNextIterator(mi)) != Null(Header)) { /* There might be more than one match. Find the newest one. */ if (h == Null(Header) || rpmVersionCompare(hi, h) == 1) { headerFree(h); h = headerLink(hi); } } rpmdbFreeIterator(mi); if (h) hdr = rpmhdr_TIEHASH_header(aTHX_ h); return hdr; } bool rpmdb_EXISTS(pTHX_ RPM__Database dbstruct, const char *name) { RPM__Header hdr = rpmdb_FETCH(aTHX_ dbstruct, name); if (hdr) { rpmhdr_DESTROY(aTHX_ hdr); return TRUE; } return FALSE; } int rpmdb_FIRSTKEY(pTHX_ RPM__Database db, const char **namep, RPM__Header *hdrp) { if (db->iterator) rpmdbFreeIterator(db->iterator); db->iterator = rpmdbInitIterator(db->dbp, RPMDBI_PACKAGES, NULL, 0); if (! db->iterator) { warn("%s: rpmdbInitIterator() failed", "RPM::Database::FIRSTKEY"); return 0; } return rpmdb_NEXTKEY(aTHX_ db, Nullch, namep, hdrp); } int rpmdb_NEXTKEY(pTHX_ RPM__Database db, const char *prev_name, const char **namep, RPM__Header *hdrp) { Header h; (void) prev_name; if (! db->iterator) { warn("%s called before FIRSTKEY", "RPM::Database::NEXTKEY"); return 0; } if (! (h = rpmdbNextIterator(db->iterator))) { /* That was last package. Game over. */ rpmdbFreeIterator(db->iterator); db->iterator = Null(rpmdbMatchIterator); return 0; } h = headerLink(h); *hdrp = rpmhdr_TIEHASH_header(aTHX_ h); *namep = (*hdrp)->name; return 1; } void rpmdb_DESTROY(pTHX_ RPM__Database db) { if (db->iterator) rpmdbFreeIterator(db->iterator); rpmdbClose(db->dbp); Safefree(db); } MODULE = RPM::Database PACKAGE = RPM::Database PREFIX = rpmdb_ RPM::Database rpmdb_TIEHASH(class, opts=NULL) char* class; SV* opts; PROTOTYPE: $;$ CODE: RETVAL = rpmdb_TIEHASH(aTHX_ class, opts); OUTPUT: RETVAL RPM::Header rpmdb_FETCH(self, name) RPM::Database self; const char *name; PROTOTYPE: $$ CODE: RETVAL = rpmdb_FETCH(aTHX_ self, name); OUTPUT: RETVAL int rpmdb_STORE(self=NULL, key=NULL, value=NULL) SV* self; SV* key; SV* value; PROTOTYPE: $$$ CODE: { rpmError(RPMERR_NOCREATEDB, "STORE: operation not permitted"); RETVAL = 0; } OUTPUT: RETVAL SV* rpmdb_DELETE(self=NULL, key=NULL) SV* self; SV* key; PROTOTYPE: $$ CODE: { rpmError(RPMERR_NOCREATEDB, "DELETE: operation not permitted"); RETVAL = Nullsv; } OUTPUT: RETVAL int rpmdb_CLEAR(self=NULL) SV* self; PROTOTYPE: $ CODE: { rpmError(RPMERR_NOCREATEDB, "CLEAR: operation not permitted"); RETVAL = 0; } OUTPUT: RETVAL bool rpmdb_EXISTS(self, name) RPM::Database self; const char *name; PROTOTYPE: $$ CODE: RETVAL = rpmdb_EXISTS(aTHX_ self, name); OUTPUT: RETVAL void rpmdb_FIRSTKEY(self) RPM::Database self; PROTOTYPE: $ PPCODE: { const char *name; RPM__Header hdr; if (rpmdb_FIRSTKEY(aTHX_ self, &name, &hdr)) { EXTEND(SP, 2); PUSHs(sv_2mortal(rpm_ptr2hvref(aTHX_ hdr, "RPM::Header"))); PUSHs(sv_2mortal(newSVpv(name, 0))); } } void rpmdb_NEXTKEY(self, prev_name=NULL) RPM::Database self; const char *prev_name; PROTOTYPE: $;$ PPCODE: { const char *name; RPM__Header hdr; if (rpmdb_NEXTKEY(aTHX_ self, prev_name, &name, &hdr)) { EXTEND(SP, 2); PUSHs(sv_2mortal(rpm_ptr2hvref(aTHX_ hdr, "RPM::Header"))); PUSHs(sv_2mortal(newSVpv(name, 0))); } } void rpmdb_DESTROY(self) RPM::Database self; PROTOTYPE: $ CODE: rpmdb_DESTROY(aTHX_ self); bool rpmdb_init(class, root=NULL, perms=O_RDWR) SV* class; const char* root; int perms; PROTOTYPE: $;$$ CODE: if (SvPOK(class) && strEQ(SvPV_nolen(class), "RPM::Database")) RETVAL = !rpmdbInit(root, perms); else { rpmError(RPMERR_BADARG, "%s must be called as a static method", "RPM::Database::init"); RETVAL = FALSE; } OUTPUT: RETVAL bool rpmdb_rebuild(class, root=NULL) SV* class; const char* root; PROTOTYPE: $;$ CODE: if (SvPOK(class) && strEQ(SvPV_nolen(class), "RPM::Database")) #if RPM_VERSION >= 0x040100 RETVAL = !rpmdbRebuild(root, NULL, NULL); #else RETVAL = !rpmdbRebuild(root); #endif else { rpmError(RPMERR_BADARG, "%s must be called as a static method", "RPM::Database::rebuild"); RETVAL = FALSE; } OUTPUT: RETVAL void rpmdb_find_by_file(self, string) RPM::Database self; SV *string; PROTOTYPE: $$ ALIAS: find_by_group = RPMTAG_GROUP find_what_provides = RPMTAG_PROVIDENAME find_what_requires = RPMTAG_REQUIRENAME find_what_conflicts = RPMTAG_CONFLICTNAME find_by_package = RPMTAG_NAME PPCODE: /* This is a front-end to all the rpmdbFindBy*() set, including FindByPackage which differs from FETCH above in that if there is actually more than one match, all will be returned. */ { const char *str = Nullch; RPM_Header *hdr; if (ix == 0) ix = RPMTAG_BASENAMES; hdr = rpm_hvref2ptr(aTHX_ string, "RPM::Header"); if (hdr) str = hdr->name; else str = SvPV_nolen(string); if (! (str && *str)) { rpmError(RPMERR_BADARG, "%s: arg 2 must be either a string" " or valid RPM::Header object", GvNAME(CvGV(cv))); /* Perl_warn(aTHX_ "%s", SvPV_nolen(rpm_errSV)); */ } else { rpmdbMatchIterator mi = rpmdbInitIterator(self->dbp, ix, str, 0); if (mi) { Header h; int n = rpmdbGetIteratorCount(mi); EXTEND(SP, n); while ((h = rpmdbNextIterator(mi)) != Null(Header)) { h = headerLink(h); hdr = rpmhdr_TIEHASH_header(aTHX_ h); PUSHs(sv_2mortal(rpm_ptr2hvref(aTHX_ hdr, "RPM::Header"))); } rpmdbFreeIterator(mi); } } }