- the big solv data change
[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   const char *match;
573   int flags;
574 #if 0
575   regex_t regex;
576 #endif
577   int stop;
578   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
579   void *callback_data;
580 };
581
582 int
583 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
584 {
585   struct matchdata *md = cbdata;
586   int flags = md->flags;
587
588   if ((flags & SEARCH_STRINGMASK) != 0)
589     {
590       switch (key->type)
591         {
592         case REPOKEY_TYPE_ID:
593         case REPOKEY_TYPE_IDARRAY:
594           if (data && data->localpool)
595             kv->str = stringpool_id2str(&data->spool, kv->id);
596           else
597             kv->str = id2str(s->repo->pool, kv->id);
598           break;
599         case REPOKEY_TYPE_STR:
600           break;
601         default:
602           return 0;
603         }
604       switch ((flags & SEARCH_STRINGMASK))
605         {
606           case SEARCH_SUBSTRING:
607             if (flags & SEARCH_NOCASE)
608               {
609                 if (!strcasestr(kv->str, md->match))
610                   return 0;
611               }
612             else
613               {
614                 if (!strstr(kv->str, md->match))
615                   return 0;
616               }
617             break;
618           case SEARCH_STRING:
619             if (flags & SEARCH_NOCASE)
620               {
621                 if (strcasecmp(md->match, kv->str))
622                   return 0;
623               }
624             else
625               {
626                 if (strcmp(md->match, kv->str))
627                   return 0;
628               }
629             break;
630           case SEARCH_GLOB:
631             if (fnmatch(md->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
632               return 0;
633             break;
634 #if 0
635           case SEARCH_REGEX:
636             if (regexec(&md->regexp, kv->str, 0, NULL, 0))
637               return 0;
638 #endif
639           default:
640             return 0;
641         }
642     }
643   md->stop = md->callback(md->callback_data, s, data, key, kv);
644   return md->stop;
645 }
646
647
648 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
649   { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
650   { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
651   { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
652   { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
653   { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
654   { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
655   { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
656   { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
657   { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
658   { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
659   { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
660   { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
661   { RPM_RPMDBID,          REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
662 };
663
664 static void
665 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
666 {
667   KeyValue kv;
668   kv.entry = 0;
669   kv.parent = 0;
670   for (; *ida && !md->stop; ida++)
671     {
672       kv.id = *ida;
673       kv.eof = ida[1] ? 0 : 1;
674       repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
675       kv.entry++;
676     }
677 }
678
679 static void
680 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
681 {
682   KeyValue kv;
683   Pool *pool = repo->pool;
684   Repodata *data;
685   int i, j, flags;
686   Solvable *s;
687
688   kv.parent = 0;
689   md->stop = 0;
690   if (!p)
691     {
692       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
693         {
694           if (s->repo == repo)
695             repo_search_md(repo, p, keyname, md);
696           if (md->stop > SEARCH_NEXT_SOLVABLE)
697             break;
698         }
699       return;
700     }
701   else if (p < 0)
702     /* The callback only supports solvables, so we can't iterate over the
703        extra things.  */
704     return;
705   flags = md->flags;
706   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
707     {
708       s = pool->solvables + p;
709       switch(keyname)
710         {
711           case 0:
712           case SOLVABLE_NAME:
713             if (s->name)
714               {
715                 kv.id = s->name;
716                 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
717               }
718             if (keyname || md->stop > SEARCH_NEXT_KEY)
719               return;
720           case SOLVABLE_ARCH:
721             if (s->arch)
722               {
723                 kv.id = s->arch;
724                 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
725               }
726             if (keyname || md->stop > SEARCH_NEXT_KEY)
727               return;
728           case SOLVABLE_EVR:
729             if (s->evr)
730               {
731                 kv.id = s->evr;
732                 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
733               }
734             if (keyname || md->stop > SEARCH_NEXT_KEY)
735               return;
736           case SOLVABLE_VENDOR:
737             if (s->vendor)
738               {
739                 kv.id = s->vendor;
740                 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
741               }
742             if (keyname || md->stop > SEARCH_NEXT_KEY)
743               return;
744           case SOLVABLE_PROVIDES:
745             if (s->provides)
746               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
747             if (keyname || md->stop > SEARCH_NEXT_KEY)
748               return;
749           case SOLVABLE_OBSOLETES:
750             if (s->obsoletes)
751               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
752             if (keyname || md->stop > SEARCH_NEXT_KEY)
753               return;
754           case SOLVABLE_CONFLICTS:
755             if (s->conflicts)
756               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
757             if (keyname || md->stop > SEARCH_NEXT_KEY)
758               return;
759           case SOLVABLE_REQUIRES:
760             if (s->requires)
761               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
762             if (keyname || md->stop > SEARCH_NEXT_KEY)
763               return;
764           case SOLVABLE_RECOMMENDS:
765             if (s->recommends)
766               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
767             if (keyname || md->stop > SEARCH_NEXT_KEY)
768               return;
769           case SOLVABLE_SUPPLEMENTS:
770             if (s->supplements)
771               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
772             if (keyname || md->stop > SEARCH_NEXT_KEY)
773               return;
774           case SOLVABLE_SUGGESTS:
775             if (s->suggests)
776               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
777             if (keyname || md->stop > SEARCH_NEXT_KEY)
778               return;
779           case SOLVABLE_ENHANCES:
780             if (s->enhances)
781               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
782             if (keyname || md->stop > SEARCH_NEXT_KEY)
783               return;
784           case RPM_RPMDBID:
785             if (repo->rpmdbid)
786               {
787                 kv.num = repo->rpmdbid[p - repo->start];
788                 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
789               }
790             if (keyname || md->stop > SEARCH_NEXT_KEY)
791               return;
792             break;
793           default:
794             break;
795         }
796     }
797
798   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
799     {
800       if (p < data->start || p >= data->end)
801         continue;
802       if (keyname && !repodata_precheck_keyname(data, keyname))
803         continue;
804       if (data->state == REPODATA_STUB)
805         {
806           if (keyname)
807             {
808               for (j = 1; j < data->nkeys; j++)
809                 if (keyname == data->keys[j].name)
810                   break;
811               if (j == data->nkeys)
812                 continue;
813             }
814           /* load it */
815           if (data->loadcallback)
816             data->loadcallback(data);
817           else
818             data->state = REPODATA_ERROR;
819         }
820       if (data->state == REPODATA_ERROR)
821         continue;
822       repodata_search(data, p, keyname, repo_matchvalue, md);
823       if (md->stop > SEARCH_NEXT_KEY)
824         break;
825     }
826 }
827
828 void
829 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)
830 {
831   struct matchdata md;
832
833   memset(&md, 0, sizeof(md));
834   md.pool = repo->pool;
835   md.match = match;
836   md.flags = flags;
837   md.callback = callback;
838   md.callback_data = cbdata;
839   repo_search_md(repo, p, keyname, &md);
840 }
841
842 const char *
843 repo_lookup_str(Repo *repo, Id entry, Id keyname)
844 {
845   Pool *pool = repo->pool;
846   Repodata *data;
847   int i, j;
848
849   switch(keyname)
850     {
851     case SOLVABLE_NAME:
852       return id2str(pool, pool->solvables[entry].name);
853     case SOLVABLE_ARCH:
854       return id2str(pool, pool->solvables[entry].arch);
855     case SOLVABLE_EVR:
856       return id2str(pool, pool->solvables[entry].evr);
857     case SOLVABLE_VENDOR:
858       return id2str(pool, pool->solvables[entry].vendor);
859     }
860   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
861     {
862       if (entry && (entry < data->start || entry >= data->end))
863         continue;
864       if (!repodata_precheck_keyname(data, keyname))
865         continue;
866       for (j = 1; j < data->nkeys; j++)
867         {
868           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))
869             return repodata_lookup_str(data, entry, keyname);
870         }
871     }
872   return 0;
873 }
874
875
876 unsigned int
877 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned int notfound)
878 {
879   Repodata *data;
880   int i, j;
881
882   if (keyname == RPM_RPMDBID)
883     {
884       if (repo->rpmdbid && entry && entry >= repo->start && entry < repo->end)
885         return repo->rpmdbid[entry - repo->start];
886       return notfound;
887     }
888   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
889     {
890       if (entry && (entry < data->start || entry >= data->end))
891         continue;
892       if (!repodata_precheck_keyname(data, keyname))
893         continue;
894       for (j = 1; j < data->nkeys; j++)
895         {
896           if (data->keys[j].name == keyname
897               && (data->keys[j].type == REPOKEY_TYPE_U32
898                   || data->keys[j].type == REPOKEY_TYPE_NUM
899                   || data->keys[j].type == REPOKEY_TYPE_CONSTANT))
900             {
901               unsigned value;
902               if (repodata_lookup_num(data, entry, keyname, &value))
903                 return value;
904             }
905         }
906     }
907   return notfound;
908 }
909
910 Id
911 repo_lookup_id(Repo *repo, Id entry, Id keyname)
912 {
913   Repodata *data;
914   int i, j;
915
916   switch(keyname)
917     {   
918     case SOLVABLE_NAME:
919       return repo->pool->solvables[entry].name;
920     case SOLVABLE_ARCH:
921       return repo->pool->solvables[entry].arch;
922     case SOLVABLE_EVR:
923       return repo->pool->solvables[entry].evr;
924     case SOLVABLE_VENDOR:
925       return repo->pool->solvables[entry].vendor;
926     }   
927   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
928     {   
929       if (entry && (entry < data->start || entry >= data->end))
930         continue;
931       if (!repodata_precheck_keyname(data, keyname))
932         continue;
933       for (j = 1; j < data->nkeys; j++)
934         {
935           if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID))
936             {
937               Id id = repodata_lookup_id(data, entry, keyname); 
938               if (id)
939                 {
940                   if (data->localpool)
941                     id = repodata_globalize_id(data, id);
942                   return id; 
943                 }
944             }
945         }
946     }   
947   return 0;
948 }
949
950 const unsigned char *
951 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
952 {
953   Repodata *data;
954   int i, j;
955   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
956     {
957       if (entry && (entry < data->start || entry >= data->end))
958         continue;
959       if (!repodata_precheck_keyname(data, keyname))
960         continue;
961       for (j = 1; j < data->nkeys; j++)
962         {
963           if (data->keys[j].name == keyname)
964             {
965               const unsigned char *chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
966               if (chk)
967                 return chk;
968             }
969         }
970     }
971   *typep = 0;
972   return 0;
973 }
974
975 int
976 repo_lookup_void(Repo *repo, Id entry, Id keyname)
977 {
978   Repodata *data;
979   int i, j;
980   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
981     {
982       if (entry && (entry < data->start || entry >= data->end))
983         continue;
984       if (!repodata_precheck_keyname(data, keyname))
985         continue;
986       for (j = 1; j < data->nkeys; j++)
987         {
988           if (data->keys[j].name == keyname
989               && (data->keys[j].type == REPOKEY_TYPE_VOID))
990             {
991               if (repodata_lookup_void(data, entry, keyname))
992                 return 1;
993             }
994         }
995     }
996   return 0;
997 }
998
999 /***********************************************************************/
1000
1001 Repodata *
1002 repo_add_repodata(Repo *repo, int localpool)
1003 {
1004   Repodata *data;
1005
1006   repo->nrepodata++;
1007   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
1008   data = repo->repodata + repo->nrepodata - 1;
1009   repodata_init(data, repo, localpool);
1010   return data;
1011 }
1012
1013 Repodata *
1014 repo_last_repodata(Repo *repo)
1015 {
1016   int i;
1017   for (i = repo->nrepodata - 1; i >= 0; i--)
1018     if (repo->repodata[i].state != REPODATA_STUB)
1019       return repo->repodata + i;
1020   return repo_add_repodata(repo, 0);
1021 }
1022
1023 void
1024 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
1025 {
1026   Repodata *data = repo_last_repodata(repo);
1027   repodata_set_id(data, p, keyname, id);
1028 }
1029
1030 void
1031 repo_set_num(Repo *repo, Id p, Id keyname, Id num)
1032 {
1033   Repodata *data = repo_last_repodata(repo);
1034   repodata_set_num(data, p, keyname, num);
1035 }
1036
1037 void
1038 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
1039 {
1040   Repodata *data = repo_last_repodata(repo);
1041   repodata_set_str(data, p, keyname, str);
1042 }
1043
1044 void
1045 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
1046 {
1047   Repodata *data = repo_last_repodata(repo);
1048   repodata_set_poolstr(data, p, keyname, str);
1049 }
1050
1051 void
1052 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
1053 {
1054   Repodata *data = repo_last_repodata(repo);
1055   repodata_add_poolstr_array(data, p, keyname, str);
1056 }
1057
1058 void
1059 repo_internalize(Repo *repo)
1060 {
1061   int i;
1062   Repodata *data;
1063
1064   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1065     if (data->attrs || data->xattrs)
1066       repodata_internalize(data);
1067 }
1068
1069 void
1070 repo_disable_paging(Repo *repo)
1071 {
1072   int i;
1073   Repodata *data;
1074
1075   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1076     repodata_disable_paging(data);
1077 }
1078 // EOF
1079 /*
1080 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
1081 */