- also use matcher in repo_solv
[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
279   if (reuseids && repo->end == pool->nsolvables)
280     {
281       /* it's ok to reuse the ids. As this is the last repo, we can
282          just shrink the solvable array */
283       for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
284         if (s->repo != repo)
285           break;
286       repo->end = i + 1;
287       pool->nsolvables = i + 1;
288     }
289   /* zero out solvables belonging to this repo */
290   for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
291     if (s->repo == repo)
292       memset(s, 0, sizeof(*s));
293   for (i = 0; i < pool->nrepos; i++)    /* find repo in pool */
294     if (pool->repos[i] == repo)
295       break;
296   if (i == pool->nrepos)               /* repo not in pool, return */
297     return;
298   if (i < pool->nrepos - 1)
299     memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *));
300   pool->nrepos--;
301   repo_freedata(repo);
302 }
303
304 void
305 repo_freeallrepos(Pool *pool, int reuseids)
306 {
307   int i;
308
309   pool_freewhatprovides(pool);
310   for (i = 0; i < pool->nrepos; i++)
311     repo_freedata(pool->repos[i]);
312   pool->repos = sat_free(pool->repos);
313   pool->nrepos = 0;
314   /* the first two solvables don't belong to a repo */
315   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
316 }
317
318
319 #define REPO_SIDEDATA_BLOCK 63
320
321 void *
322 repo_sidedata_create(Repo *repo, size_t size)
323 {
324   return sat_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
325 }
326
327 void *
328 repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
329
330   int n = repo->end - repo->start;
331   if (p < repo->start)
332     { 
333       int d = repo->start - p;
334       b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
335       memmove(b + d * size, b, n * size);
336       memset(b, 0, d * size);
337       n += d;
338     }     
339   if (p + count > repo->end)
340     { 
341       int d = p + count - repo->end;
342       b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
343       memset(b + n * size, 0, d * size);
344     }     
345   return b;
346 }
347
348 Offset
349 repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
350 {
351   Pool *pool = repo->pool;
352   Id id, idp, idl;
353   char buf[1024], *p, *dep;
354   int i, l;
355
356   if (provides)
357     {
358       for (i = provides; repo->idarraydata[i]; i++)
359         {
360           id = repo->idarraydata[i];
361           if (ISRELDEP(id))
362             continue;
363           dep = (char *)id2str(pool, id);
364           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
365             {
366               idp = 0;
367               strcpy(buf + 2, dep);
368               dep = buf + 2 + 7;
369               if ((p = strchr(dep, ':')) != 0 && p != dep)
370                 {
371                   *p++ = 0;
372                   idp = str2id(pool, dep, 1);
373                   dep = p;
374                 }
375               id = 0;
376               while ((p = strchr(dep, ';')) != 0)
377                 {
378                   if (p == dep)
379                     {
380                       dep = p + 1;
381                       continue;
382                     }
383                   *p++ = 0;
384 #if 0
385                   strncpy(dep - 9, "language:", 9);
386                   idl = str2id(pool, dep - 9, 1);
387 #else
388                   idl = str2id(pool, dep, 1);
389                   idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
390 #endif
391                   if (id)
392                     id = rel2id(pool, id, idl, REL_OR, 1);
393                   else
394                     id = idl;
395                   dep = p;
396                 }
397               if (dep[0] && dep[1])
398                 {
399                   for (p = dep; *p && *p != ')'; p++)
400                     ;
401                   *p = 0;
402 #if 0
403                   strncpy(dep - 9, "language:", 9);
404                   idl = str2id(pool, dep - 9, 1);
405 #else
406                   idl = str2id(pool, dep, 1);
407                   idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
408 #endif
409                   if (id)
410                     id = rel2id(pool, id, idl, REL_OR, 1);
411                   else
412                     id = idl;
413                 }
414               if (idp)
415                 id = rel2id(pool, idp, id, REL_AND, 1);
416               if (id)
417                 supplements = repo_addid_dep(repo, supplements, id, 0);
418             }
419           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
420             {
421               strcpy(buf, dep);
422               p = buf + (p - dep);
423               *p++ = 0;
424               idp = str2id(pool, buf, 1);
425               /* strip trailing slashes */
426               l = strlen(p);
427               while (l > 1 && p[l - 1] == '/')
428                 p[--l] = 0;
429               id = str2id(pool, p, 1);
430               id = rel2id(pool, idp, id, REL_WITH, 1);
431               id = rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
432               supplements = repo_addid_dep(repo, supplements, id, 0);
433             }
434         }
435     }
436   if (supplements)
437     {
438       for (i = supplements; repo->idarraydata[i]; i++)
439         {
440           id = repo->idarraydata[i];
441           if (ISRELDEP(id))
442             continue;
443           dep = (char *)id2str(pool, id);
444           if (!strncmp(dep, "system:modalias(", 16))
445             dep += 7;
446           if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
447             {
448               strcpy(buf, dep);
449               p = strchr(buf + 9, ':');
450               if (p && p != buf + 9 && strchr(p + 1, ':'))
451                 {
452                   *p++ = 0;
453                   idp = str2id(pool, buf + 9, 1);
454                   p[strlen(p) - 1] = 0;
455                   id = str2id(pool, p, 1);
456                   id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
457                   id = rel2id(pool, idp, id, REL_AND, 1);
458                 }
459               else
460                 {
461                   p = buf + 9;
462                   p[strlen(p) - 1] = 0;
463                   id = str2id(pool, p, 1);
464                   id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
465                 }
466               if (id)
467                 repo->idarraydata[i] = id;
468             }
469           else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
470             {
471               strcpy(buf, dep);
472               id = 0;
473               dep = buf + 11;
474               while ((p = strchr(dep, ':')) != 0)
475                 {
476                   if (p == dep)
477                     {
478                       dep = p + 1;
479                       continue;
480                     }
481                   *p++ = 0;
482                   idp = str2id(pool, dep, 1);
483                   if (id)
484                     id = rel2id(pool, id, idp, REL_AND, 1);
485                   else
486                     id = idp;
487                   dep = p;
488                 }
489               if (dep[0] && dep[1])
490                 {
491                   dep[strlen(dep) - 1] = 0;
492                   idp = str2id(pool, dep, 1);
493                   if (id)
494                     id = rel2id(pool, id, idp, REL_AND, 1);
495                   else
496                     id = idp;
497                 }
498               if (id)
499                 repo->idarraydata[i] = id;
500             }
501           else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
502             {
503               strcpy(buf, dep + 11);
504               if ((p = strrchr(buf, ')')) != 0)
505                 *p = 0;
506               id = str2id(pool, buf, 1);
507               id = rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
508               repo->idarraydata[i] = id;
509             }
510         }
511     }
512   if (freshens && repo->idarraydata[freshens])
513     {
514       Id idsupp = 0, idfresh = 0;
515       if (!supplements)
516         return freshens;
517       for (i = supplements; repo->idarraydata[i]; i++)
518         {
519           if (!idsupp)
520             idsupp = repo->idarraydata[i];
521           else
522             idsupp = rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
523         }
524       for (i = freshens; repo->idarraydata[i]; i++)
525         {
526           if (!idfresh)
527             idfresh = repo->idarraydata[i];
528           else
529             idfresh = rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
530         }
531       if (!idsupp)
532         idsupp = idfresh;
533       else
534         idsupp = rel2id(pool, idsupp, idfresh, REL_AND, 1);
535       supplements = repo_addid_dep(repo, 0, idsupp, 0);
536     }
537   return supplements;
538 }
539
540 Offset
541 repo_fix_conflicts(Repo *repo, Offset conflicts)
542 {
543   char buf[1024], *p, *dep;
544   Pool *pool = repo->pool;
545   Id id;
546   int i;
547
548   if (!conflicts)
549     return conflicts;
550   for (i = conflicts; repo->idarraydata[i]; i++)
551     {
552       id = repo->idarraydata[i];
553       if (ISRELDEP(id))
554         continue;
555       dep = (char *)id2str(pool, id);
556       if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2)
557         {
558           strcpy(buf, dep + 15);
559           if ((p = strchr(buf, ')')) != 0)
560             *p = 0;
561           id = str2id(pool, buf, 1);
562           id = rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
563           repo->idarraydata[i] = id;
564         }
565     }
566   return conflicts;
567 }
568
569 struct matchdata
570 {
571   Pool *pool;
572   int flags;
573   Datamatcher matcher;
574   int stop;
575   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
576   void *callback_data;
577 };
578
579 int
580 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
581 {
582   struct matchdata *md = cbdata;
583
584   if (md->matcher.match && !datamatcher_match(&md->matcher, data, key, kv))
585     return 0;
586   md->stop = md->callback(md->callback_data, s, data, key, kv);
587   return md->stop;
588 }
589
590
591 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
592   { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
593   { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
594   { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
595   { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
596   { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
597   { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
598   { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
599   { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
600   { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
601   { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
602   { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
603   { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
604   { RPM_RPMDBID,          REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
605 };
606
607 static void
608 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
609 {
610   KeyValue kv;
611   kv.entry = 0;
612   kv.parent = 0;
613   for (; *ida && !md->stop; ida++)
614     {
615       kv.id = *ida;
616       kv.eof = ida[1] ? 0 : 1;
617       repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
618       kv.entry++;
619     }
620 }
621
622 static void
623 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
624 {
625   KeyValue kv;
626   Pool *pool = repo->pool;
627   Repodata *data;
628   int i, j, flags;
629   Solvable *s;
630
631   kv.parent = 0;
632   md->stop = 0;
633   if (!p)
634     {
635       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
636         {
637           if (s->repo == repo)
638             repo_search_md(repo, p, keyname, md);
639           if (md->stop > SEARCH_NEXT_SOLVABLE)
640             break;
641         }
642       return;
643     }
644   else if (p < 0)
645     /* The callback only supports solvables, so we can't iterate over the
646        extra things.  */
647     return;
648   flags = md->flags;
649   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
650     {
651       s = pool->solvables + p;
652       switch(keyname)
653         {
654           case 0:
655           case SOLVABLE_NAME:
656             if (s->name)
657               {
658                 kv.id = s->name;
659                 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
660               }
661             if (keyname || md->stop > SEARCH_NEXT_KEY)
662               return;
663           case SOLVABLE_ARCH:
664             if (s->arch)
665               {
666                 kv.id = s->arch;
667                 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
668               }
669             if (keyname || md->stop > SEARCH_NEXT_KEY)
670               return;
671           case SOLVABLE_EVR:
672             if (s->evr)
673               {
674                 kv.id = s->evr;
675                 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
676               }
677             if (keyname || md->stop > SEARCH_NEXT_KEY)
678               return;
679           case SOLVABLE_VENDOR:
680             if (s->vendor)
681               {
682                 kv.id = s->vendor;
683                 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
684               }
685             if (keyname || md->stop > SEARCH_NEXT_KEY)
686               return;
687           case SOLVABLE_PROVIDES:
688             if (s->provides)
689               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
690             if (keyname || md->stop > SEARCH_NEXT_KEY)
691               return;
692           case SOLVABLE_OBSOLETES:
693             if (s->obsoletes)
694               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
695             if (keyname || md->stop > SEARCH_NEXT_KEY)
696               return;
697           case SOLVABLE_CONFLICTS:
698             if (s->conflicts)
699               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
700             if (keyname || md->stop > SEARCH_NEXT_KEY)
701               return;
702           case SOLVABLE_REQUIRES:
703             if (s->requires)
704               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
705             if (keyname || md->stop > SEARCH_NEXT_KEY)
706               return;
707           case SOLVABLE_RECOMMENDS:
708             if (s->recommends)
709               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
710             if (keyname || md->stop > SEARCH_NEXT_KEY)
711               return;
712           case SOLVABLE_SUPPLEMENTS:
713             if (s->supplements)
714               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
715             if (keyname || md->stop > SEARCH_NEXT_KEY)
716               return;
717           case SOLVABLE_SUGGESTS:
718             if (s->suggests)
719               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
720             if (keyname || md->stop > SEARCH_NEXT_KEY)
721               return;
722           case SOLVABLE_ENHANCES:
723             if (s->enhances)
724               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
725             if (keyname || md->stop > SEARCH_NEXT_KEY)
726               return;
727           case RPM_RPMDBID:
728             if (repo->rpmdbid)
729               {
730                 kv.num = repo->rpmdbid[p - repo->start];
731                 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
732               }
733             if (keyname || md->stop > SEARCH_NEXT_KEY)
734               return;
735             break;
736           default:
737             break;
738         }
739     }
740
741   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
742     {
743       if (p < data->start || p >= data->end)
744         continue;
745       if (keyname && !repodata_precheck_keyname(data, keyname))
746         continue;
747       if (data->state == REPODATA_STUB)
748         {
749           if (keyname)
750             {
751               for (j = 1; j < data->nkeys; j++)
752                 if (keyname == data->keys[j].name)
753                   break;
754               if (j == data->nkeys)
755                 continue;
756             }
757           /* load it */
758           if (data->loadcallback)
759             data->loadcallback(data);
760           else
761             data->state = REPODATA_ERROR;
762         }
763       if (data->state == REPODATA_ERROR)
764         continue;
765       repodata_search(data, p, keyname, repo_matchvalue, md);
766       if (md->stop > SEARCH_NEXT_KEY)
767         break;
768     }
769 }
770
771 void
772 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)
773 {
774   struct matchdata md;
775
776   memset(&md, 0, sizeof(md));
777   md.pool = repo->pool;
778   md.flags = flags;
779   md.callback = callback;
780   md.callback_data = cbdata;
781   if (match)
782     datamatcher_init(&md.matcher, md.pool, match, flags);
783   repo_search_md(repo, p, keyname, &md);
784   if (match)
785     datamatcher_free(&md.matcher);
786 }
787
788 const char *
789 repo_lookup_str(Repo *repo, Id entry, Id keyname)
790 {
791   Pool *pool = repo->pool;
792   Repodata *data;
793   int i, j;
794
795   switch(keyname)
796     {
797     case SOLVABLE_NAME:
798       return id2str(pool, pool->solvables[entry].name);
799     case SOLVABLE_ARCH:
800       return id2str(pool, pool->solvables[entry].arch);
801     case SOLVABLE_EVR:
802       return id2str(pool, pool->solvables[entry].evr);
803     case SOLVABLE_VENDOR:
804       return id2str(pool, pool->solvables[entry].vendor);
805     }
806   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
807     {
808       if (entry && (entry < data->start || entry >= data->end))
809         continue;
810       if (!repodata_precheck_keyname(data, keyname))
811         continue;
812       for (j = 1; j < data->nkeys; j++)
813         {
814           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))
815             return repodata_lookup_str(data, entry, keyname);
816         }
817     }
818   return 0;
819 }
820
821
822 unsigned int
823 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned int notfound)
824 {
825   Repodata *data;
826   int i, j;
827
828   if (keyname == RPM_RPMDBID)
829     {
830       if (repo->rpmdbid && entry && entry >= repo->start && entry < repo->end)
831         return repo->rpmdbid[entry - repo->start];
832       return notfound;
833     }
834   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
835     {
836       if (entry && (entry < data->start || entry >= data->end))
837         continue;
838       if (!repodata_precheck_keyname(data, keyname))
839         continue;
840       for (j = 1; j < data->nkeys; j++)
841         {
842           if (data->keys[j].name == keyname
843               && (data->keys[j].type == REPOKEY_TYPE_U32
844                   || data->keys[j].type == REPOKEY_TYPE_NUM
845                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT))
846             {
847               unsigned value;
848               if (repodata_lookup_num(data, entry, keyname, &value))
849                 return value;
850             }
851         }
852     }
853   return notfound;
854 }
855
856 Id
857 repo_lookup_id(Repo *repo, Id entry, Id keyname)
858 {
859   Repodata *data;
860   int i, j;
861
862   switch(keyname)
863     {   
864     case SOLVABLE_NAME:
865       return repo->pool->solvables[entry].name;
866     case SOLVABLE_ARCH:
867       return repo->pool->solvables[entry].arch;
868     case SOLVABLE_EVR:
869       return repo->pool->solvables[entry].evr;
870     case SOLVABLE_VENDOR:
871       return repo->pool->solvables[entry].vendor;
872     }   
873   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
874     {   
875       if (entry && (entry < data->start || entry >= data->end))
876         continue;
877       if (!repodata_precheck_keyname(data, keyname))
878         continue;
879       for (j = 1; j < data->nkeys; j++)
880         {
881           if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID))
882             {
883               Id id = repodata_lookup_id(data, entry, keyname); 
884               if (id)
885                 {
886                   if (data->localpool)
887                     id = repodata_globalize_id(data, id);
888                   return id; 
889                 }
890             }
891         }
892     }   
893   return 0;
894 }
895
896 const unsigned char *
897 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
898 {
899   Repodata *data;
900   int i, j;
901   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
902     {
903       if (entry && (entry < data->start || entry >= data->end))
904         continue;
905       if (!repodata_precheck_keyname(data, keyname))
906         continue;
907       for (j = 1; j < data->nkeys; j++)
908         {
909           if (data->keys[j].name == keyname)
910             {
911               const unsigned char *chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
912               if (chk)
913                 return chk;
914             }
915         }
916     }
917   *typep = 0;
918   return 0;
919 }
920
921 int
922 repo_lookup_void(Repo *repo, Id entry, Id keyname)
923 {
924   Repodata *data;
925   int i, j;
926   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
927     {
928       if (entry && (entry < data->start || entry >= data->end))
929         continue;
930       if (!repodata_precheck_keyname(data, keyname))
931         continue;
932       for (j = 1; j < data->nkeys; j++)
933         {
934           if (data->keys[j].name == keyname
935               && (data->keys[j].type == REPOKEY_TYPE_VOID))
936             {
937               if (repodata_lookup_void(data, entry, keyname))
938                 return 1;
939             }
940         }
941     }
942   return 0;
943 }
944
945 /***********************************************************************/
946
947 Repodata *
948 repo_add_repodata(Repo *repo, int localpool)
949 {
950   Repodata *data;
951
952   repo->nrepodata++;
953   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
954   data = repo->repodata + repo->nrepodata - 1;
955   repodata_init(data, repo, localpool);
956   return data;
957 }
958
959 Repodata *
960 repo_last_repodata(Repo *repo)
961 {
962   int i;
963   for (i = repo->nrepodata - 1; i >= 0; i--)
964     if (repo->repodata[i].state != REPODATA_STUB)
965       return repo->repodata + i;
966   return repo_add_repodata(repo, 0);
967 }
968
969 void
970 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
971 {
972   Repodata *data = repo_last_repodata(repo);
973   repodata_set_id(data, p, keyname, id);
974 }
975
976 void
977 repo_set_num(Repo *repo, Id p, Id keyname, Id num)
978 {
979   Repodata *data = repo_last_repodata(repo);
980   repodata_set_num(data, p, keyname, num);
981 }
982
983 void
984 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
985 {
986   Repodata *data = repo_last_repodata(repo);
987   repodata_set_str(data, p, keyname, str);
988 }
989
990 void
991 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
992 {
993   Repodata *data = repo_last_repodata(repo);
994   repodata_set_poolstr(data, p, keyname, str);
995 }
996
997 void
998 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
999 {
1000   Repodata *data = repo_last_repodata(repo);
1001   repodata_add_poolstr_array(data, p, keyname, str);
1002 }
1003
1004 void
1005 repo_internalize(Repo *repo)
1006 {
1007   int i;
1008   Repodata *data;
1009
1010   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1011     if (data->attrs || data->xattrs)
1012       repodata_internalize(data);
1013 }
1014
1015 void
1016 repo_disable_paging(Repo *repo)
1017 {
1018   int i;
1019   Repodata *data;
1020
1021   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1022     repodata_disable_paging(data);
1023 }
1024 // EOF
1025 /*
1026 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
1027 */