summaryrefslogtreecommitdiff
path: root/lib/rpmps.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rpmps.c')
-rw-r--r--lib/rpmps.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/lib/rpmps.c b/lib/rpmps.c
new file mode 100644
index 0000000..6e1ab18
--- /dev/null
+++ b/lib/rpmps.c
@@ -0,0 +1,172 @@
+/**
+ * \file lib/rpmps.c
+ */
+
+#include "system.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <rpm/rpmstring.h>
+#include <rpm/rpmps.h>
+
+#include "debug.h"
+
+struct rpmps_s {
+ int numProblems; /*!< Current probs array size. */
+ int numProblemsAlloced; /*!< Allocated probs array size. */
+ rpmProblem *probs; /*!< Array of pointers to specific problems. */
+ int nrefs; /*!< Reference count. */
+};
+
+struct rpmpsi_s {
+ int ix;
+ rpmps ps;
+};
+
+
+static rpmps rpmpsUnlink(rpmps ps)
+{
+ if (ps) {
+ ps->nrefs--;
+ }
+ return NULL;
+}
+
+rpmps rpmpsLink(rpmps ps)
+{
+ if (ps) {
+ ps->nrefs++;
+ }
+ return ps;
+}
+
+int rpmpsNumProblems(rpmps ps)
+{
+ int numProblems = 0;
+ if (ps && ps->probs)
+ numProblems = ps->numProblems;
+ return numProblems;
+}
+
+rpmpsi rpmpsInitIterator(rpmps ps)
+{
+ rpmpsi psi = NULL;
+ if (ps != NULL && ps->numProblems > 0) {
+ psi = xcalloc(1, sizeof(*psi));
+ psi->ps = rpmpsLink(ps);
+ psi->ix = -1;
+ }
+ return psi;
+}
+
+rpmpsi rpmpsFreeIterator(rpmpsi psi)
+{
+ if (psi != NULL) {
+ rpmpsUnlink(psi->ps);
+ free(psi);
+ }
+ return NULL;
+}
+
+rpmProblem rpmpsiNext(rpmpsi psi)
+{
+ rpmProblem p = NULL;
+ if (psi != NULL && psi->ps != NULL && ++psi->ix >= 0) {
+ rpmps ps = psi->ps;
+ if (psi->ix < ps->numProblems) {
+ p = ps->probs[psi->ix];
+ } else {
+ psi->ix = -1;
+ }
+ }
+ return p;
+}
+
+int rpmpsNextIterator(rpmpsi psi)
+{
+ return (rpmpsiNext(psi) != NULL) ? psi->ix : -1;
+}
+
+rpmProblem rpmpsGetProblem(rpmpsi psi)
+{
+ rpmProblem p = NULL;
+ if (psi != NULL && psi->ix >= 0 && psi->ix < rpmpsNumProblems(psi->ps)) {
+ p = psi->ps->probs[psi->ix];
+ }
+ return p;
+}
+
+rpmps rpmpsCreate(void)
+{
+ rpmps ps = xcalloc(1, sizeof(*ps));
+ return rpmpsLink(ps);
+}
+
+rpmps rpmpsFree(rpmps ps)
+{
+ if (ps == NULL) return NULL;
+ if (ps->nrefs > 1) {
+ return rpmpsUnlink(ps);
+ }
+
+ if (ps->probs) {
+ rpmpsi psi = rpmpsInitIterator(ps);
+ while (rpmpsNextIterator(psi) >= 0) {
+ rpmProblemFree(rpmpsGetProblem(psi));
+ }
+ rpmpsFreeIterator(psi);
+ ps->probs = _free(ps->probs);
+ }
+ ps = _free(ps);
+ return NULL;
+}
+
+void rpmpsAppendProblem(rpmps ps, rpmProblem prob)
+{
+ if (ps == NULL || prob == NULL) return;
+
+ if (ps->numProblems == ps->numProblemsAlloced) {
+ if (ps->numProblemsAlloced)
+ ps->numProblemsAlloced *= 2;
+ else
+ ps->numProblemsAlloced = 2;
+ ps->probs = xrealloc(ps->probs,
+ ps->numProblemsAlloced * sizeof(ps->probs));
+ }
+
+ ps->probs[ps->numProblems] = rpmProblemLink(prob);
+ ps->numProblems++;
+}
+
+/*
+ * TODO: filter out duplicates while merging. Also horribly inefficient... */
+int rpmpsMerge(rpmps dest, rpmps src)
+{
+ int rc = 0;
+ if (dest != NULL) {
+ rpmProblem p;
+ rpmpsi spi = rpmpsInitIterator(src);
+ while ((p = rpmpsiNext(spi)) != NULL) {
+ rpmpsAppendProblem(dest, p);
+ rc++;
+ }
+ rpmpsFreeIterator(spi);
+ }
+ return rc;
+}
+
+void rpmpsPrint(FILE *fp, rpmps ps)
+{
+ rpmProblem p;
+ rpmpsi psi = rpmpsInitIterator(ps);
+ FILE *f = (fp != NULL) ? fp : stderr;
+
+ while ((p = rpmpsiNext(psi))) {
+ char *msg = rpmProblemString(p);
+ fprintf(f, "\t%s\n", msg);
+ free(msg);
+ }
+ rpmpsFreeIterator(psi);
+}
+