Merge branch 'master' of git@git.opensuse.org:projects/zypp/sat-solver
[platform/upstream/libsolv.git] / src / repo.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * repo.c
10  *
11  * Manage metadata coming from one repository
12  * 
13  */
14
15 #define _GNU_SOURCE
16 #include <string.h>
17 #include <fnmatch.h>
18
19 #include <stdio.h>
20 #include <stdlib.h>
21
22
23
24 #include "repo.h"
25 #include "pool.h"
26 #include "poolid_private.h"
27 #include "util.h"
28 #if 0
29 #include "attr_store_p.h"
30 #endif
31
32 #define IDARRAY_BLOCK     4095
33
34
35 /*
36  * create empty repo
37  * and add to pool
38  */
39
40 Repo *
41 repo_create(Pool *pool, const char *name)
42 {
43   Repo *repo;
44
45   pool_freewhatprovides(pool);
46   repo = (Repo *)sat_calloc(1, sizeof(*repo));
47   pool->repos = (Repo **)sat_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
48   pool->repos[pool->nrepos++] = repo;
49   repo->name = name ? strdup(name) : 0;
50   repo->pool = pool;
51   repo->start = pool->nsolvables;
52   repo->end = pool->nsolvables;
53   repo->nsolvables = 0;
54   return repo;
55 }
56
57 static void
58 repo_freedata(Repo *repo)
59 {
60   int i;
61   for (i = 0; i < repo->nrepodata; i++)
62     repodata_free(repo->repodata + i);
63   sat_free(repo->repodata);
64   sat_free(repo->idarraydata);
65   sat_free(repo->rpmdbid);
66   sat_free((char *)repo->name);
67   sat_free(repo);
68 }
69
70 /*
71  * add Id to repo
72  * olddeps = old array to extend
73  * 
74  */
75
76 Offset
77 repo_addid(Repo *repo, Offset olddeps, Id id)
78 {
79   Id *idarray;
80   int idarraysize;
81   int i;
82   
83   idarray = repo->idarraydata;
84   idarraysize = repo->idarraysize;
85
86   if (!idarray)                        /* alloc idarray if not done yet */
87     {
88       idarraysize = 1;
89       idarray = sat_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
90       idarray[0] = 0;
91       repo->lastoff = 0;
92     }
93
94   if (!olddeps)                         /* no deps yet */
95     {   
96       olddeps = idarraysize;
97       idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
98     }   
99   else if (olddeps == repo->lastoff)    /* extend at end */
100     idarraysize--;
101   else                                  /* can't extend, copy old */
102     {
103       i = olddeps;
104       olddeps = idarraysize;
105       for (; idarray[i]; i++)
106         {
107           idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
108           idarray[idarraysize++] = idarray[i];
109         }
110       idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
111     }
112   
113   idarray[idarraysize++] = id;          /* insert Id into array */
114   idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
115   idarray[idarraysize++] = 0;           /* ensure NULL termination */
116
117   repo->idarraydata = idarray;
118   repo->idarraysize = idarraysize;
119   repo->lastoff = olddeps;
120
121   return olddeps;
122 }
123
124
125 /*
126  * add dependency (as Id) to repo, also unifies dependencies
127  * olddeps = offset into idarraydata
128  * marker= 0 for normal dep
129  * marker > 0 add dep after marker
130  * marker < 0 add dep after -marker
131  * 
132  */
133 Offset
134 repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
135 {
136   Id oid, *oidp, *markerp;
137   int before;
138
139   if (!olddeps)
140     {
141       if (marker > 0)
142         olddeps = repo_addid(repo, olddeps, marker);
143       return repo_addid(repo, olddeps, id);
144     }
145
146   if (!marker)
147     {
148       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
149         {
150           if (oid == id)
151             return olddeps;
152         }
153       return repo_addid(repo, olddeps, id);
154     }
155
156   before = 0;
157   markerp = 0;
158   if (marker < 0)
159     {
160       before = 1;
161       marker = -marker;
162     }
163   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
164     {
165       if (oid == marker)
166         markerp = oidp;
167       else if (oid == id)
168         break;
169     }
170
171   if (oid)
172     {
173       if (markerp || before)
174         return olddeps;
175       /* we found it, but in the wrong half */
176       markerp = oidp++;
177       for (; (oid = *oidp) != ID_NULL; oidp++)
178         if (oid == marker)
179           break;
180       if (!oid)
181         {
182           /* no marker in array yet */
183           oidp--;
184           if (markerp < oidp)
185             memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
186           *oidp = marker;
187           return repo_addid(repo, olddeps, id);
188         }
189       while (oidp[1])
190         oidp++;
191       memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
192       *oidp = id;
193       return olddeps;
194     }
195   /* id not yet in array */
196   if (!before && !markerp)
197     olddeps = repo_addid(repo, olddeps, marker);
198   else if (before && markerp)
199     {
200       *markerp++ = id;
201       id = *--oidp;
202       if (markerp < oidp)
203         memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
204       *markerp = marker;
205     }
206   return repo_addid(repo, olddeps, id);
207 }
208
209
210 /*
211  * reserve Ids
212  * make space for 'num' more dependencies
213  */
214
215 Offset
216 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
217 {
218   num++;        /* room for trailing ID_NULL */
219
220   if (!repo->idarraysize)              /* ensure buffer space */
221     {
222       repo->idarraysize = 1;
223       repo->idarraydata = sat_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
224       repo->idarraydata[0] = 0;
225       repo->lastoff = 1;
226       return 1;
227     }
228
229   if (olddeps && olddeps != repo->lastoff)   /* if not appending */
230     {
231       /* can't insert into idarray, this would invalidate all 'larger' offsets
232        * so create new space at end and move existing deps there.
233        * Leaving 'hole' at old position.
234        */
235       
236       Id *idstart, *idend;
237       int count;
238
239       for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
240         ;
241       count = idend - idstart - 1 + num;               /* new size */
242
243       repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
244       /* move old deps to end */
245       olddeps = repo->lastoff = repo->idarraysize;
246       memcpy(repo->idarraydata + olddeps, idstart, count - num);
247       repo->idarraysize = olddeps + count - num;
248
249       return olddeps;
250     }
251
252   if (olddeps)                         /* appending */
253     repo->idarraysize--;
254
255   /* make room*/
256   repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
257
258   /* appending or new */
259   repo->lastoff = olddeps ? olddeps : repo->idarraysize;
260
261   return repo->lastoff;
262 }
263
264
265 /*
266  * remove repo from pool, zero out solvables 
267  * 
268  */
269
270 void
271 repo_free(Repo *repo, int reuseids)
272 {
273   Pool *pool = repo->pool;
274   Solvable *s;
275   int i;
276
277   pool_freewhatprovides(pool);
278   if (repo == pool->installed)
279     pool->installed = 0;
280
281   if (reuseids && repo->end == pool->nsolvables)
282     {
283       /* it's ok to reuse the ids. As this is the last repo, we can
284          just shrink the solvable array */
285       for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
286         if (s->repo != repo)
287           break;
288       repo->end = i + 1;
289       pool->nsolvables = i + 1;
290     }
291   /* zero out solvables belonging to this repo */
292   for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
293     if (s->repo == repo)
294       memset(s, 0, sizeof(*s));
295   for (i = 0; i < pool->nrepos; i++)    /* find repo in pool */
296     if (pool->repos[i] == repo)
297       break;
298   if (i == pool->nrepos)               /* repo not in pool, return */
299     return;
300   if (i < pool->nrepos - 1)
301     memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *));
302   pool->nrepos--;
303   repo_freedata(repo);
304 }
305
306 void
307 repo_freeallrepos(Pool *pool, int reuseids)
308 {
309   int i;
310
311   pool_freewhatprovides(pool);
312   for (i = 0; i < pool->nrepos; i++)
313     repo_freedata(pool->repos[i]);
314   pool->repos = sat_free(pool->repos);
315   pool->nrepos = 0;
316   /* the first two solvables don't belong to a repo */
317   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
318 }
319
320
321 #define REPO_SIDEDATA_BLOCK 63
322
323 void *
324 repo_sidedata_create(Repo *repo, size_t size)
325 {
326   return sat_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
327 }
328
329 void *
330 repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
331
332   int n = repo->end - repo->start;
333   if (p < repo->start)
334     { 
335       int d = repo->start - p;
336       b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
337       memmove((char*)b + d * size, b, n * size);
338       memset(b, 0, d * size);
339       n += d;
340     }     
341   if (p + count > repo->end)
342     { 
343       int d = p + count - repo->end;
344       b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
345       memset((char*)b + n * size, 0, d * size);
346     }     
347   return b;
348 }
349
350 Offset
351 repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
352 {
353   Pool *pool = repo->pool;
354   Id id, idp, idl;
355   char buf[1024], *p, *dep;
356   int i, l;
357
358   if (provides)
359     {
360       for (i = provides; repo->idarraydata[i]; i++)
361         {
362           id = repo->idarraydata[i];
363           if (ISRELDEP(id))
364             continue;
365           dep = (char *)id2str(pool, id);
366           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
367             {
368               idp = 0;
369               strcpy(buf + 2, dep);
370               dep = buf + 2 + 7;
371               if ((p = strchr(dep, ':')) != 0 && p != dep)
372                 {
373                   *p++ = 0;
374                   idp = str2id(pool, dep, 1);
375                   dep = p;
376                 }
377               id = 0;
378               while ((p = strchr(dep, ';')) != 0)
379                 {
380                   if (p == dep)
381                     {
382                       dep = p + 1;
383                       continue;
384                     }
385                   *p++ = 0;
386 #if 0
387                   strncpy(dep - 9, "language:", 9);
388                   idl = str2id(pool, dep - 9, 1);
389 #else
390                   idl = str2id(pool, dep, 1);
391                   idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
392 #endif
393                   if (id)
394                     id = rel2id(pool, id, idl, REL_OR, 1);
395                   else
396                     id = idl;
397                   dep = p;
398                 }
399               if (dep[0] && dep[1])
400                 {
401                   for (p = dep; *p && *p != ')'; p++)
402                     ;
403                   *p = 0;
404 #if 0
405                   strncpy(dep - 9, "language:", 9);
406                   idl = str2id(pool, dep - 9, 1);
407 #else
408                   idl = str2id(pool, dep, 1);
409                   idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
410 #endif
411                   if (id)
412                     id = rel2id(pool, id, idl, REL_OR, 1);
413                   else
414                     id = idl;
415                 }
416               if (idp)
417                 id = rel2id(pool, idp, id, REL_AND, 1);
418               if (id)
419                 supplements = repo_addid_dep(repo, supplements, id, 0);
420             }
421           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
422             {
423               strcpy(buf, dep);
424               p = buf + (p - dep);
425               *p++ = 0;
426               idp = str2id(pool, buf, 1);
427               /* strip trailing slashes */
428               l = strlen(p);
429               while (l > 1 && p[l - 1] == '/')
430                 p[--l] = 0;
431               id = str2id(pool, p, 1);
432               id = rel2id(pool, idp, id, REL_WITH, 1);
433               id = rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
434               supplements = repo_addid_dep(repo, supplements, id, 0);
435             }
436         }
437     }
438   if (supplements)
439     {
440       for (i = supplements; repo->idarraydata[i]; i++)
441         {
442           id = repo->idarraydata[i];
443           if (ISRELDEP(id))
444             continue;
445           dep = (char *)id2str(pool, id);
446           if (!strncmp(dep, "system:modalias(", 16))
447             dep += 7;
448           if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
449             {
450               strcpy(buf, dep);
451               p = strchr(buf + 9, ':');
452               if (p && p != buf + 9 && strchr(p + 1, ':'))
453                 {
454                   *p++ = 0;
455                   idp = str2id(pool, buf + 9, 1);
456                   p[strlen(p) - 1] = 0;
457                   id = str2id(pool, p, 1);
458                   id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
459                   id = rel2id(pool, idp, id, REL_AND, 1);
460                 }
461               else
462                 {
463                   p = buf + 9;
464                   p[strlen(p) - 1] = 0;
465                   id = str2id(pool, p, 1);
466                   id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
467                 }
468               if (id)
469                 repo->idarraydata[i] = id;
470             }
471           else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
472             {
473               strcpy(buf, dep);
474               id = 0;
475               dep = buf + 11;
476               while ((p = strchr(dep, ':')) != 0)
477                 {
478                   if (p == dep)
479                     {
480                       dep = p + 1;
481                       continue;
482                     }
483                   *p++ = 0;
484                   idp = str2id(pool, dep, 1);
485                   if (id)
486                     id = rel2id(pool, id, idp, REL_AND, 1);
487                   else
488                     id = idp;
489                   dep = p;
490                 }
491               if (dep[0] && dep[1])
492                 {
493                   dep[strlen(dep) - 1] = 0;
494                   idp = str2id(pool, dep, 1);
495                   if (id)
496                     id = rel2id(pool, id, idp, REL_AND, 1);
497                   else
498                     id = idp;
499                 }
500               if (id)
501                 repo->idarraydata[i] = id;
502             }
503           else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
504             {
505               strcpy(buf, dep + 11);
506               if ((p = strrchr(buf, ')')) != 0)
507                 *p = 0;
508               id = str2id(pool, buf, 1);
509               id = rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
510               repo->idarraydata[i] = id;
511             }
512         }
513     }
514   if (freshens && repo->idarraydata[freshens])
515     {
516       Id idsupp = 0, idfresh = 0;
517       if (!supplements)
518         return freshens;
519       for (i = supplements; repo->idarraydata[i]; i++)
520         {
521           if (!idsupp)
522             idsupp = repo->idarraydata[i];
523           else
524             idsupp = rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
525         }
526       for (i = freshens; repo->idarraydata[i]; i++)
527         {
528           if (!idfresh)
529             idfresh = repo->idarraydata[i];
530           else
531             idfresh = rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
532         }
533       if (!idsupp)
534         idsupp = idfresh;
535       else
536         idsupp = rel2id(pool, idsupp, idfresh, REL_AND, 1);
537       supplements = repo_addid_dep(repo, 0, idsupp, 0);
538     }
539   return supplements;
540 }
541
542 Offset
543 repo_fix_conflicts(Repo *repo, Offset conflicts)
544 {
545   char buf[1024], *p, *dep;
546   Pool *pool = repo->pool;
547   Id id;
548   int i;
549
550   if (!conflicts)
551     return conflicts;
552   for (i = conflicts; repo->idarraydata[i]; i++)
553     {
554       id = repo->idarraydata[i];
555       if (ISRELDEP(id))
556         continue;
557       dep = (char *)id2str(pool, id);
558       if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2)
559         {
560           strcpy(buf, dep + 15);
561           if ((p = strchr(buf, ')')) != 0)
562             *p = 0;
563           id = str2id(pool, buf, 1);
564           id = rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
565           repo->idarraydata[i] = id;
566         }
567     }
568   return conflicts;
569 }
570
571 struct matchdata
572 {
573   Pool *pool;
574   int flags;
575   Datamatcher matcher;
576   int stop;
577   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
578   void *callback_data;
579 };
580
581 int
582 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
583 {
584   struct matchdata *md = cbdata;
585
586   if (md->matcher.match)
587     {
588       if (!repodata_stringify(md->pool, data, key, kv, md->flags))
589         return 0;
590       if (!datamatcher_match(&md->matcher, kv->str))
591         return 0;
592     }
593   md->stop = md->callback(md->callback_data, s, data, key, kv);
594   return md->stop;
595 }
596
597
598 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
599   { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
600   { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
601   { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
602   { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
603   { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
604   { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
605   { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
606   { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
607   { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
608   { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
609   { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
610   { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
611   { RPM_RPMDBID,          REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
612 };
613
614 static void
615 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
616 {
617   KeyValue kv;
618   kv.entry = 0;
619   kv.parent = 0;
620   for (; *ida && !md->stop; ida++)
621     {
622       kv.id = *ida;
623       kv.eof = ida[1] ? 0 : 1;
624       repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
625       kv.entry++;
626     }
627 }
628
629 static void
630 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
631 {
632   KeyValue kv;
633   Pool *pool = repo->pool;
634   Repodata *data;
635   int i, j, flags;
636   Solvable *s;
637
638   kv.parent = 0;
639   md->stop = 0;
640   if (!p)
641     {
642       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
643         {
644           if (s->repo == repo)
645             repo_search_md(repo, p, keyname, md);
646           if (md->stop > SEARCH_NEXT_SOLVABLE)
647             break;
648         }
649       return;
650     }
651   else if (p < 0)
652     /* The callback only supports solvables, so we can't iterate over the
653        extra things.  */
654     return;
655   flags = md->flags;
656   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
657     {
658       s = pool->solvables + p;
659       switch(keyname)
660         {
661           case 0:
662           case SOLVABLE_NAME:
663             if (s->name)
664               {
665                 kv.id = s->name;
666                 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
667               }
668             if (keyname || md->stop > SEARCH_NEXT_KEY)
669               return;
670           case SOLVABLE_ARCH:
671             if (s->arch)
672               {
673                 kv.id = s->arch;
674                 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
675               }
676             if (keyname || md->stop > SEARCH_NEXT_KEY)
677               return;
678           case SOLVABLE_EVR:
679             if (s->evr)
680               {
681                 kv.id = s->evr;
682                 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
683               }
684             if (keyname || md->stop > SEARCH_NEXT_KEY)
685               return;
686           case SOLVABLE_VENDOR:
687             if (s->vendor)
688               {
689                 kv.id = s->vendor;
690                 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
691               }
692             if (keyname || md->stop > SEARCH_NEXT_KEY)
693               return;
694           case SOLVABLE_PROVIDES:
695             if (s->provides)
696               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
697             if (keyname || md->stop > SEARCH_NEXT_KEY)
698               return;
699           case SOLVABLE_OBSOLETES:
700             if (s->obsoletes)
701               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
702             if (keyname || md->stop > SEARCH_NEXT_KEY)
703               return;
704           case SOLVABLE_CONFLICTS:
705             if (s->conflicts)
706               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
707             if (keyname || md->stop > SEARCH_NEXT_KEY)
708               return;
709           case SOLVABLE_REQUIRES:
710             if (s->requires)
711               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
712             if (keyname || md->stop > SEARCH_NEXT_KEY)
713               return;
714           case SOLVABLE_RECOMMENDS:
715             if (s->recommends)
716               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
717             if (keyname || md->stop > SEARCH_NEXT_KEY)
718               return;
719           case SOLVABLE_SUPPLEMENTS:
720             if (s->supplements)
721               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
722             if (keyname || md->stop > SEARCH_NEXT_KEY)
723               return;
724           case SOLVABLE_SUGGESTS:
725             if (s->suggests)
726               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
727             if (keyname || md->stop > SEARCH_NEXT_KEY)
728               return;
729           case SOLVABLE_ENHANCES:
730             if (s->enhances)
731               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
732             if (keyname || md->stop > SEARCH_NEXT_KEY)
733               return;
734           case RPM_RPMDBID:
735             if (repo->rpmdbid)
736               {
737                 kv.num = repo->rpmdbid[p - repo->start];
738                 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
739               }
740             if (keyname || md->stop > SEARCH_NEXT_KEY)
741               return;
742             break;
743           default:
744             break;
745         }
746     }
747
748   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
749     {
750       if (p < data->start || p >= data->end)
751         continue;
752       if (keyname && !repodata_precheck_keyname(data, keyname))
753         continue;
754       if (data->state == REPODATA_STUB)
755         {
756           if (keyname)
757             {
758               for (j = 1; j < data->nkeys; j++)
759                 if (keyname == data->keys[j].name)
760                   break;
761               if (j == data->nkeys)
762                 continue;
763             }
764           /* load it */
765           if (data->loadcallback)
766             data->loadcallback(data);
767           else
768             data->state = REPODATA_ERROR;
769         }
770       if (data->state == REPODATA_ERROR)
771         continue;
772       repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
773       if (md->stop > SEARCH_NEXT_KEY)
774         break;
775     }
776 }
777
778 void
779 repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
780 {
781   struct matchdata md;
782
783   memset(&md, 0, sizeof(md));
784   md.pool = repo->pool;
785   md.flags = flags;
786   md.callback = callback;
787   md.callback_data = cbdata;
788   if (match)
789     datamatcher_init(&md.matcher, match, flags);
790   repo_search_md(repo, p, keyname, &md);
791   if (match)
792     datamatcher_free(&md.matcher);
793 }
794
795 const char *
796 repo_lookup_str(Repo *repo, Id entry, Id keyname)
797 {
798   Pool *pool = repo->pool;
799   Repodata *data;
800   int i, j;
801
802   switch(keyname)
803     {
804     case SOLVABLE_NAME:
805       return id2str(pool, pool->solvables[entry].name);
806     case SOLVABLE_ARCH:
807       return id2str(pool, pool->solvables[entry].arch);
808     case SOLVABLE_EVR:
809       return id2str(pool, pool->solvables[entry].evr);
810     case SOLVABLE_VENDOR:
811       return id2str(pool, pool->solvables[entry].vendor);
812     }
813   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
814     {
815       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
816         continue;
817       if (!repodata_precheck_keyname(data, keyname))
818         continue;
819       for (j = 1; j < data->nkeys; j++)
820         {
821           if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID || data->keys[j].type == REPOKEY_TYPE_STR))
822             return repodata_lookup_str(data, entry, keyname);
823         }
824     }
825   return 0;
826 }
827
828
829 unsigned int
830 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned int notfound)
831 {
832   Repodata *data;
833   int i, j;
834
835   if (keyname == RPM_RPMDBID)
836     {
837       if (repo->rpmdbid && entry >= repo->start && entry < repo->end)
838         return repo->rpmdbid[entry - repo->start];
839       return notfound;
840     }
841   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
842     {
843       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
844         continue;
845       if (!repodata_precheck_keyname(data, keyname))
846         continue;
847       for (j = 1; j < data->nkeys; j++)
848         {
849           if (data->keys[j].name == keyname
850               && (data->keys[j].type == REPOKEY_TYPE_U32
851                   || data->keys[j].type == REPOKEY_TYPE_NUM
852                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT))
853             {
854               unsigned value;
855               if (repodata_lookup_num(data, entry, keyname, &value))
856                 return value;
857             }
858         }
859     }
860   return notfound;
861 }
862
863 Id
864 repo_lookup_id(Repo *repo, Id entry, Id keyname)
865 {
866   Repodata *data;
867   int i, j;
868
869   switch(keyname)
870     {   
871     case SOLVABLE_NAME:
872       return repo->pool->solvables[entry].name;
873     case SOLVABLE_ARCH:
874       return repo->pool->solvables[entry].arch;
875     case SOLVABLE_EVR:
876       return repo->pool->solvables[entry].evr;
877     case SOLVABLE_VENDOR:
878       return repo->pool->solvables[entry].vendor;
879     }   
880   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
881     {   
882       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
883         continue;
884       if (!repodata_precheck_keyname(data, keyname))
885         continue;
886       for (j = 1; j < data->nkeys; j++)
887         {
888           if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID))
889             {
890               Id id = repodata_lookup_id(data, entry, keyname); 
891               if (id)
892                 {
893                   if (data->localpool)
894                     id = repodata_globalize_id(data, id);
895                   return id; 
896                 }
897             }
898         }
899     }   
900   return 0;
901 }
902
903 const unsigned char *
904 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
905 {
906   Repodata *data;
907   int i, j;
908   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
909     {
910       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
911         continue;
912       if (!repodata_precheck_keyname(data, keyname))
913         continue;
914       for (j = 1; j < data->nkeys; j++)
915         {
916           if (data->keys[j].name == keyname)
917             {
918               const unsigned char *chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
919               if (chk)
920                 return chk;
921             }
922         }
923     }
924   *typep = 0;
925   return 0;
926 }
927
928 int
929 repo_lookup_void(Repo *repo, Id entry, Id keyname)
930 {
931   Repodata *data;
932   int i, j;
933   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
934     {
935       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
936         continue;
937       if (!repodata_precheck_keyname(data, keyname))
938         continue;
939       for (j = 1; j < data->nkeys; j++)
940         {
941           if (data->keys[j].name == keyname
942               && (data->keys[j].type == REPOKEY_TYPE_VOID))
943             {
944               if (repodata_lookup_void(data, entry, keyname))
945                 return 1;
946             }
947         }
948     }
949   return 0;
950 }
951
952 /***********************************************************************/
953
954 Repodata *
955 repo_add_repodata(Repo *repo, int localpool)
956 {
957   Repodata *data;
958
959   repo->nrepodata++;
960   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
961   data = repo->repodata + repo->nrepodata - 1;
962   repodata_init(data, repo, localpool);
963   return data;
964 }
965
966 Repodata *
967 repo_last_repodata(Repo *repo)
968 {
969   int i;
970   for (i = repo->nrepodata - 1; i >= 0; i--)
971     if (repo->repodata[i].state != REPODATA_STUB)
972       return repo->repodata + i;
973   return repo_add_repodata(repo, 0);
974 }
975
976 void
977 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
978 {
979   Repodata *data = repo_last_repodata(repo);
980   repodata_set_id(data, p, keyname, id);
981 }
982
983 void
984 repo_set_num(Repo *repo, Id p, Id keyname, Id num)
985 {
986   Repodata *data = repo_last_repodata(repo);
987   repodata_set_num(data, p, keyname, num);
988 }
989
990 void
991 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
992 {
993   Repodata *data = repo_last_repodata(repo);
994   repodata_set_str(data, p, keyname, str);
995 }
996
997 void
998 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
999 {
1000   Repodata *data = repo_last_repodata(repo);
1001   repodata_set_poolstr(data, p, keyname, str);
1002 }
1003
1004 void
1005 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
1006 {
1007   Repodata *data = repo_last_repodata(repo);
1008   repodata_add_poolstr_array(data, p, keyname, str);
1009 }
1010
1011 void
1012 repo_internalize(Repo *repo)
1013 {
1014   int i;
1015   Repodata *data;
1016
1017   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1018     if (data->attrs || data->xattrs)
1019       repodata_internalize(data);
1020 }
1021
1022 void
1023 repo_disable_paging(Repo *repo)
1024 {
1025   int i;
1026   Repodata *data;
1027
1028   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1029     repodata_disable_paging(data);
1030 }
1031 // EOF
1032 /*
1033 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
1034 */