+static void
+dataiterator_newdata(Dataiterator *di)
+{
+ Id keyname = di->keyname;
+ Repodata *data = di->data;
+ di->nextkeydp = 0;
+
+ if (data->state == REPODATA_STUB)
+ {
+ if (keyname)
+ {
+ int j;
+ for (j = 1; j < data->nkeys; j++)
+ if (keyname == data->keys[j].name)
+ break;
+ if (j == data->nkeys)
+ return;
+ }
+ /* load it */
+ if (data->loadcallback)
+ data->loadcallback(data);
+ else
+ data->state = REPODATA_ERROR;
+ }
+ if (data->state == REPODATA_ERROR)
+ return;
+
+ Id schema;
+ unsigned char *dp = data->incoredata + data->incoreoffset[di->solvid - data->start];
+ dp = data_read_id(dp, &schema);
+ Id *keyp = data->schemadata + data->schemata[schema];
+ if (keyname)
+ {
+ Id k, *kp;
+ /* search in a specific key */
+ for (kp = keyp; (k = *kp++) != 0; )
+ if (data->keys[k].name == keyname)
+ break;
+ if (k == 0)
+ return;
+ dp = forward_to_key(data, k, schema, dp);
+ if (!dp)
+ return;
+ keyp = kp - 1;
+ }
+ Id keyid = *keyp++;
+ if (!keyid)
+ return;
+
+ di->data = data;
+ di->key = di->data->keys + keyid;
+ di->keyp = keyp;
+ di->dp = 0;
+
+ di->nextkeydp = dp;
+ di->dp = get_data(di->data, di->key, &di->nextkeydp);
+ di->kv.eof = 0;
+}
+
+void
+dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
+ const char *match, int flags)
+{
+ di->flags = flags;
+ if (p)
+ {
+ di->solvid = p;
+ di->flags |= __SEARCH_ONESOLVABLE;
+ di->data = repo->repodata - 1;
+ if (flags & SEARCH_NO_STORAGE_SOLVABLE)
+ di->state = 0;
+ else
+ di->state = 1;
+ }
+ else
+ {
+ di->solvid = repo->start - 1;
+ di->data = repo->repodata + repo->nrepodata - 1;
+ di->state = 0;
+ }
+ di->match = match;
+ di->keyname = keyname;
+ static Id zeroid = 0;
+ di->keyp = &zeroid;
+ di->kv.eof = 1;
+ di->repo = repo;
+ di->idp = 0;
+}
+
+/* FIXME factor and merge with repo_matchvalue */
+static int
+dataiterator_match(Dataiterator *di, KeyValue *kv)
+{
+ int flags = di->flags;
+
+ if ((flags & SEARCH_STRINGMASK) != 0)
+ {
+ switch (di->key->type)
+ {
+ case REPOKEY_TYPE_ID:
+ case REPOKEY_TYPE_IDARRAY:
+ if (di->data && di->data->localpool)
+ kv->str = stringpool_id2str(&di->data->spool, kv->id);
+ else
+ kv->str = id2str(di->repo->pool, kv->id);
+ break;
+ case REPOKEY_TYPE_STR:
+ break;
+ default:
+ return 0;
+ }
+ switch ((flags & SEARCH_STRINGMASK))
+ {
+ case SEARCH_SUBSTRING:
+ if (flags & SEARCH_NOCASE)
+ {
+ if (!strcasestr(kv->str, di->match))
+ return 0;
+ }
+ else
+ {
+ if (!strstr(kv->str, di->match))
+ return 0;
+ }
+ break;
+ case SEARCH_STRING:
+ if (flags & SEARCH_NOCASE)
+ {
+ if (strcasecmp(di->match, kv->str))
+ return 0;
+ }
+ else
+ {
+ if (strcmp(di->match, kv->str))
+ return 0;
+ }
+ break;
+ case SEARCH_GLOB:
+ if (fnmatch(di->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
+ return 0;
+ break;
+#if 0
+ case SEARCH_REGEX:
+ if (regexec(&di->regexp, kv->str, 0, NULL, 0))
+ return 0;
+#endif
+ default:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
+ { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { SOLVABLE_FRESHENS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+ { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
+};
+
+int
+dataiterator_step(Dataiterator *di)
+{
+restart:
+ while (1)
+ {
+ if (di->state)
+ {
+ if (di->idp)
+ {
+ Id *idp = di->idp;
+ if (*idp)
+ {
+ di->kv.id = *idp;
+ di->idp++;
+ di->kv.eof = idp[1] ? 0 : 1;
+ goto weg2;
+ }
+ else
+ di->idp = 0;
+ }
+ Solvable *s = di->repo->pool->solvables + di->solvid;
+ int state = di->state;
+ di->key = solvablekeys + state - 1;
+ if (di->keyname)
+ di->state = RPM_RPMDBID;
+ else
+ di->state++;
+ if (state == 1)
+ {
+ di->data = 0;
+ if (di->keyname)
+ state = di->keyname - 1;
+ }
+ switch (state + 1)
+ {
+ case SOLVABLE_NAME:
+ if (!s->name)
+ continue;
+ di->kv.id = s->name;
+ break;
+ case SOLVABLE_ARCH:
+ if (!s->arch)
+ continue;
+ di->kv.id = s->arch;
+ break;
+ case SOLVABLE_EVR:
+ if (!s->evr)
+ continue;
+ di->kv.id = s->evr;
+ break;
+ case SOLVABLE_VENDOR:
+ if (!s->vendor)
+ continue;
+ di->kv.id = s->vendor;
+ break;
+ case SOLVABLE_PROVIDES:
+ di->idp = s->provides
+ ? di->repo->idarraydata + s->provides : 0;
+ continue;
+ case SOLVABLE_OBSOLETES:
+ di->idp = s->obsoletes
+ ? di->repo->idarraydata + s->obsoletes : 0;
+ continue;
+ case SOLVABLE_CONFLICTS:
+ di->idp = s->conflicts
+ ? di->repo->idarraydata + s->conflicts : 0;
+ continue;
+ case SOLVABLE_REQUIRES:
+ di->idp = s->requires
+ ? di->repo->idarraydata + s->requires : 0;
+ continue;
+ case SOLVABLE_RECOMMENDS:
+ di->idp = s->recommends
+ ? di->repo->idarraydata + s->recommends : 0;
+ continue;
+ case SOLVABLE_SUPPLEMENTS:
+ di->idp = s->supplements
+ ? di->repo->idarraydata + s->supplements : 0;
+ continue;
+ case SOLVABLE_SUGGESTS:
+ di->idp = s->suggests
+ ? di->repo->idarraydata + s->suggests : 0;
+ continue;
+ case SOLVABLE_ENHANCES:
+ di->idp = s->enhances
+ ? di->repo->idarraydata + s->enhances : 0;
+ continue;
+ case SOLVABLE_FRESHENS:
+ di->idp = s->freshens
+ ? di->repo->idarraydata + s->freshens : 0;
+ continue;
+ case RPM_RPMDBID:
+ if (!di->repo->rpmdbid)
+ continue;
+ di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
+ break;
+ default:
+ di->data = di->repo->repodata - 1;
+ di->kv.eof = 1;
+ di->state = 0;
+ continue;
+ }
+ }
+ else
+ {
+ if (di->kv.eof)
+ di->dp = 0;
+ else
+ di->dp = data_fetch(di->dp, &di->kv, di->key);
+
+ while (!di->dp)
+ {
+ Id keyid;
+ if (di->keyname || !(keyid = *di->keyp++))
+ {
+ while (1)
+ {
+ Repo *repo = di->repo;
+ Repodata *data = ++di->data;
+ if (data >= repo->repodata + repo->nrepodata)
+ {
+ if (di->flags & __SEARCH_ONESOLVABLE)
+ return 0;
+ while (++di->solvid < repo->end)
+ if (repo->pool->solvables[di->solvid].repo == repo)
+ break;
+ if (di->solvid >= repo->end)
+ return 0;
+ di->data = repo->repodata - 1;
+ if (di->flags & SEARCH_NO_STORAGE_SOLVABLE)
+ continue;
+ static Id zeroid = 0;
+ di->keyp = &zeroid;
+ di->state = 1;
+ goto restart;
+ }
+ if (di->solvid >= data->start && di->solvid < data->end)
+ {
+ dataiterator_newdata(di);
+ if (di->nextkeydp)
+ break;
+ }
+ }
+ }
+ else
+ {
+ di->key = di->data->keys + keyid;
+ di->dp = get_data(di->data, di->key, &di->nextkeydp);
+ }
+ di->dp = data_fetch(di->dp, &di->kv, di->key);
+ }
+ }
+weg2:
+ if (!di->match
+ || dataiterator_match(di, &di->kv))
+ break;
+ }
+ return 1;
+}