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