add a generic attribute lookup function 'repo_lookup'
[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   sat_free(repo->idarraydata);
61   sat_free(repo->rpmdbid);
62   sat_free((char *)repo->name);
63   sat_free(repo);
64 }
65
66 /*
67  * add Id to repo
68  * olddeps = old array to extend
69  * 
70  */
71
72 Offset
73 repo_addid(Repo *repo, Offset olddeps, Id id)
74 {
75   Id *idarray;
76   int idarraysize;
77   int i;
78   
79   idarray = repo->idarraydata;
80   idarraysize = repo->idarraysize;
81
82   if (!idarray)                        /* alloc idarray if not done yet */
83     {
84       idarraysize = 1;
85       idarray = sat_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
86       idarray[0] = 0;
87       repo->lastoff = 0;
88     }
89
90   if (!olddeps)                         /* no deps yet */
91     {   
92       olddeps = idarraysize;
93       idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
94     }   
95   else if (olddeps == repo->lastoff)    /* extend at end */
96     idarraysize--;
97   else                                  /* can't extend, copy old */
98     {
99       i = olddeps;
100       olddeps = idarraysize;
101       for (; idarray[i]; i++)
102         {
103           idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
104           idarray[idarraysize++] = idarray[i];
105         }
106       idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
107     }
108   
109   idarray[idarraysize++] = id;          /* insert Id into array */
110   idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
111   idarray[idarraysize++] = 0;           /* ensure NULL termination */
112
113   repo->idarraydata = idarray;
114   repo->idarraysize = idarraysize;
115   repo->lastoff = olddeps;
116
117   return olddeps;
118 }
119
120
121 /*
122  * add dependency (as Id) to repo, also unifies dependencies
123  * olddeps = offset into idarraydata
124  * marker= 0 for normal dep
125  * marker > 0 add dep after marker
126  * marker < 0 add dep after -marker
127  * 
128  */
129 Offset
130 repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
131 {
132   Id oid, *oidp, *markerp;
133   int before;
134
135   if (!olddeps)
136     {
137       if (marker > 0)
138         olddeps = repo_addid(repo, olddeps, marker);
139       return repo_addid(repo, olddeps, id);
140     }
141
142   if (!marker)
143     {
144       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
145         {
146           if (oid == id)
147             return olddeps;
148         }
149       return repo_addid(repo, olddeps, id);
150     }
151
152   before = 0;
153   markerp = 0;
154   if (marker < 0)
155     {
156       before = 1;
157       marker = -marker;
158     }
159   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
160     {
161       if (oid == marker)
162         markerp = oidp;
163       else if (oid == id)
164         break;
165     }
166
167   if (oid)
168     {
169       if (markerp || before)
170         return olddeps;
171       /* we found it, but in the wrong half */
172       markerp = oidp++;
173       for (; (oid = *oidp) != ID_NULL; oidp++)
174         if (oid == marker)
175           break;
176       if (!oid)
177         {
178           /* no marker in array yet */
179           oidp--;
180           if (markerp < oidp)
181             memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
182           *oidp = marker;
183           return repo_addid(repo, olddeps, id);
184         }
185       while (oidp[1])
186         oidp++;
187       memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
188       *oidp = id;
189       return olddeps;
190     }
191   /* id not yet in array */
192   if (!before && !markerp)
193     olddeps = repo_addid(repo, olddeps, marker);
194   else if (before && markerp)
195     {
196       *markerp++ = id;
197       id = *--oidp;
198       if (markerp < oidp)
199         memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
200       *markerp = marker;
201     }
202   return repo_addid(repo, olddeps, id);
203 }
204
205
206 /*
207  * reserve Ids
208  * make space for 'num' more dependencies
209  */
210
211 Offset
212 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
213 {
214   num++;        /* room for trailing ID_NULL */
215
216   if (!repo->idarraysize)              /* ensure buffer space */
217     {
218       repo->idarraysize = 1;
219       repo->idarraydata = sat_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
220       repo->idarraydata[0] = 0;
221       repo->lastoff = 1;
222       return 1;
223     }
224
225   if (olddeps && olddeps != repo->lastoff)   /* if not appending */
226     {
227       /* can't insert into idarray, this would invalidate all 'larger' offsets
228        * so create new space at end and move existing deps there.
229        * Leaving 'hole' at old position.
230        */
231       
232       Id *idstart, *idend;
233       int count;
234
235       for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
236         ;
237       count = idend - idstart - 1 + num;               /* new size */
238
239       repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
240       /* move old deps to end */
241       olddeps = repo->lastoff = repo->idarraysize;
242       memcpy(repo->idarraydata + olddeps, idstart, count - num);
243       repo->idarraysize = olddeps + count - num;
244
245       return olddeps;
246     }
247
248   if (olddeps)                         /* appending */
249     repo->idarraysize--;
250
251   /* make room*/
252   repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
253
254   /* appending or new */
255   repo->lastoff = olddeps ? olddeps : repo->idarraysize;
256
257   return repo->lastoff;
258 }
259
260
261 /*
262  * remove repo from pool, zero out solvables 
263  * 
264  */
265
266 void
267 repo_free(Repo *repo, int reuseids)
268 {
269   Pool *pool = repo->pool;
270   Solvable *s;
271   int i;
272
273   pool_freewhatprovides(pool);
274
275   if (reuseids && repo->end == pool->nsolvables)
276     {
277       /* it's ok to reuse the ids. As this is the last repo, we can
278          just shrink the solvable array */
279       for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
280         if (s->repo != repo)
281           break;
282       repo->end = i + 1;
283       pool->nsolvables = i + 1;
284     }
285   /* zero out solvables belonging to this repo */
286   for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
287     if (s->repo == repo)
288       memset(s, 0, sizeof(*s));
289   for (i = 0; i < pool->nrepos; i++)    /* find repo in pool */
290     if (pool->repos[i] == repo)
291       break;
292   if (i == pool->nrepos)               /* repo not in pool, return */
293     return;
294   if (i < pool->nrepos - 1)
295     memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *));
296   pool->nrepos--;
297   repo_freedata(repo);
298 }
299
300 void
301 repo_freeallrepos(Pool *pool, int reuseids)
302 {
303   int i;
304
305   pool_freewhatprovides(pool);
306   for (i = 0; i < pool->nrepos; i++)
307     repo_freedata(pool->repos[i]);
308   pool->repos = sat_free(pool->repos);
309   pool->nrepos = 0;
310   /* the first two solvables don't belong to a repo */
311   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
312 }
313
314 Offset
315 repo_fix_legacy(Repo *repo, Offset provides, Offset supplements)
316 {
317   Pool *pool = repo->pool;
318   Id id, idp, idl;
319   char buf[1024], *p, *dep;
320   int i;
321
322   if (provides)
323     {
324       for (i = provides; repo->idarraydata[i]; i++)
325         {
326           id = repo->idarraydata[i];
327           if (ISRELDEP(id))
328             continue;
329           dep = (char *)id2str(pool, id);
330           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
331             {
332               idp = 0;
333               strcpy(buf + 2, dep);
334               dep = buf + 2 + 7;
335               if ((p = strchr(dep, ':')) != 0 && p != dep)
336                 {
337                   *p++ = 0;
338                   idp = str2id(pool, dep, 1);
339                   dep = p;
340                 }
341               id = 0;
342               while ((p = strchr(dep, ';')) != 0)
343                 {
344                   if (p == dep)
345                     {
346                       dep = p + 1;
347                       continue;
348                     }
349                   *p++ = 0;
350 #if 0
351                   strncpy(dep - 9, "language:", 9);
352                   idl = str2id(pool, dep - 9, 1);
353 #else
354                   idl = str2id(pool, dep, 1);
355                   idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
356 #endif
357                   if (id)
358                     id = rel2id(pool, id, idl, REL_OR, 1);
359                   else
360                     id = idl;
361                   dep = p;
362                 }
363               if (dep[0] && dep[1])
364                 {
365                   for (p = dep; *p && *p != ')'; p++)
366                     ;
367                   *p = 0;
368 #if 0
369                   strncpy(dep - 9, "language:", 9);
370                   idl = str2id(pool, dep - 9, 1);
371 #else
372                   idl = str2id(pool, dep, 1);
373                   idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
374 #endif
375                   if (id)
376                     id = rel2id(pool, id, idl, REL_OR, 1);
377                   else
378                     id = idl;
379                 }
380               if (idp)
381                 id = rel2id(pool, idp, id, REL_AND, 1);
382               if (id)
383                 supplements = repo_addid_dep(repo, supplements, id, 0);
384             }
385           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
386             {
387               strcpy(buf, dep);
388               p = buf + (p - dep);
389               *p++ = 0;
390               idp = str2id(pool, buf, 1);
391               id = str2id(pool, p, 1);
392               id = rel2id(pool, idp, id, REL_WITH, 1);
393               id = rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
394               supplements = repo_addid_dep(repo, supplements, id, 0);
395             }
396         }
397     }
398   if (!supplements)
399     return 0;
400   for (i = supplements; repo->idarraydata[i]; i++)
401     {
402       id = repo->idarraydata[i];
403       if (ISRELDEP(id))
404         continue;
405       dep = (char *)id2str(pool, id);
406       if (!strncmp(dep, "system:modalias(", 16))
407         dep += 7;
408       if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
409         {
410           strcpy(buf, dep);
411           p = strchr(buf + 9, ':');
412           if (p && p != buf + 9 && strchr(p + 1, ':'))
413             {
414               *p++ = 0;
415               idp = str2id(pool, buf + 9, 1);
416               p[strlen(p) - 1] = 0;
417               id = str2id(pool, p, 1);
418               id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
419               id = rel2id(pool, idp, id, REL_AND, 1);
420             }
421           else
422             {
423               p = buf + 9;
424               p[strlen(p) - 1] = 0;
425               id = str2id(pool, p, 1);
426               id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
427             }
428           if (id)
429             repo->idarraydata[i] = id;
430         }
431       else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
432         {
433           strcpy(buf, dep);
434           id = 0;
435           dep = buf + 11;
436           while ((p = strchr(dep, ':')) != 0)
437             {
438               if (p == dep)
439                 {
440                   dep = p + 1;
441                   continue;
442                 }
443               *p++ = 0;
444               idp = str2id(pool, dep, 1);
445               if (id)
446                 id = rel2id(pool, id, idp, REL_AND, 1);
447               else
448                 id = idp;
449               dep = p;
450             }
451           if (dep[0] && dep[1])
452             {
453               dep[strlen(dep) - 1] = 0;
454               idp = str2id(pool, dep, 1);
455               if (id)
456                 id = rel2id(pool, id, idp, REL_AND, 1);
457               else
458                 id = idp;
459             }
460           if (id)
461             repo->idarraydata[i] = id;
462         }
463     }
464   return supplements;
465 }
466
467 struct matchdata
468 {
469   Pool *pool;
470   const char *match;
471   int flags;
472 #if 0
473   regex_t regex;
474 #endif
475   int stop;
476   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
477   void *callback_data;
478 };
479
480 int
481 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
482 {
483   struct matchdata *md = cbdata;
484   int flags = md->flags;
485
486   if ((flags & SEARCH_STRINGMASK) != 0)
487     {
488       switch (key->type)
489         {
490         case TYPE_ID:
491         case TYPE_IDARRAY:
492           if (data && data->localpool)
493             kv->str = stringpool_id2str(&data->spool, kv->id);
494           else
495             kv->str = id2str(s->repo->pool, kv->id);
496           break;
497         case TYPE_STR:
498           break;
499         default:
500           return 0;
501         }
502       switch ((flags & SEARCH_STRINGMASK))
503         {
504           case SEARCH_SUBSTRING:
505             if (flags & SEARCH_NOCASE)
506               {
507                 if (!strcasestr(kv->str, md->match))
508                   return 0;
509               }
510             else
511               {
512                 if (!strstr(kv->str, md->match))
513                   return 0;
514               }
515             break;
516           case SEARCH_STRING:
517             if (flags & SEARCH_NOCASE)
518               {
519                 if (strcasecmp(md->match, kv->str))
520                   return 0;
521               }
522             else
523               {
524                 if (strcmp(md->match, kv->str))
525                   return 0;
526               }
527             break;
528           case SEARCH_GLOB:
529             if (fnmatch(md->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
530               return 0;
531             break;
532 #if 0
533           case SEARCH_REGEX:
534             if (regexec(&md->regexp, kv->str, 0, NULL, 0))
535               return 0;
536 #endif
537           default:
538             return 0;
539         }
540     }
541   md->stop = md->callback(md->callback_data, s, data, key, kv);
542   return md->stop;
543 }
544
545
546 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
547   { SOLVABLE_NAME,        TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
548   { SOLVABLE_ARCH,        TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
549   { SOLVABLE_EVR,         TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
550   { SOLVABLE_VENDOR,      TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
551   { SOLVABLE_PROVIDES,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
552   { SOLVABLE_OBSOLETES,   TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
553   { SOLVABLE_CONFLICTS,   TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
554   { SOLVABLE_REQUIRES,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
555   { SOLVABLE_RECOMMENDS,  TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
556   { SOLVABLE_SUGGESTS,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
557   { SOLVABLE_SUPPLEMENTS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
558   { SOLVABLE_ENHANCES,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
559   { SOLVABLE_FRESHENS,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
560   { RPM_RPMDBID,          TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
561 };
562
563 static void
564 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
565 {
566   KeyValue kv;
567   for (; *ida && !md->stop; ida++)
568     {
569       kv.id = *ida;
570       kv.eof = ida[1] ? 0 : 1;
571       repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
572     }
573 }
574
575 static void
576 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
577 {
578   KeyValue kv;
579   Pool *pool = repo->pool;
580   Repodata *data;
581   Solvable *s;
582   int i, j, flags;
583
584   md->stop = 0;
585   if (!p)
586     {
587       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
588         {
589           if (s->repo == repo)
590             repo_search_md(repo, p, keyname, md);
591           if (md->stop > SEARCH_NEXT_SOLVABLE)
592             break;
593         }
594       return;
595     }
596   s = pool->solvables + p;
597   flags = md->flags;
598   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
599     {
600       switch(keyname)
601         {
602           case 0:
603           case SOLVABLE_NAME:
604             if (s->name)
605               {
606                 kv.id = s->name;
607                 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
608               }
609             if (keyname || md->stop > SEARCH_NEXT_KEY)
610               return;
611           case SOLVABLE_ARCH:
612             if (s->arch)
613               {
614                 kv.id = s->arch;
615                 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
616               }
617             if (keyname || md->stop > SEARCH_NEXT_KEY)
618               return;
619           case SOLVABLE_EVR:
620             if (s->evr)
621               {
622                 kv.id = s->evr;
623                 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
624               }
625             if (keyname || md->stop > SEARCH_NEXT_KEY)
626               return;
627           case SOLVABLE_VENDOR:
628             if (s->vendor)
629               {
630                 kv.id = s->vendor;
631                 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
632               }
633             if (keyname || md->stop > SEARCH_NEXT_KEY)
634               return;
635           case SOLVABLE_PROVIDES:
636             if (s->provides)
637               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
638             if (keyname || md->stop > SEARCH_NEXT_KEY)
639               return;
640           case SOLVABLE_OBSOLETES:
641             if (s->obsoletes)
642               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
643             if (keyname || md->stop > SEARCH_NEXT_KEY)
644               return;
645           case SOLVABLE_CONFLICTS:
646             if (s->conflicts)
647               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
648             if (keyname || md->stop > SEARCH_NEXT_KEY)
649               return;
650           case SOLVABLE_REQUIRES:
651             if (s->requires)
652               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
653             if (keyname || md->stop > SEARCH_NEXT_KEY)
654               return;
655           case SOLVABLE_RECOMMENDS:
656             if (s->recommends)
657               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
658             if (keyname || md->stop > SEARCH_NEXT_KEY)
659               return;
660           case SOLVABLE_SUPPLEMENTS:
661             if (s->supplements)
662               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
663             if (keyname || md->stop > SEARCH_NEXT_KEY)
664               return;
665           case SOLVABLE_SUGGESTS:
666             if (s->suggests)
667               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
668             if (keyname || md->stop > SEARCH_NEXT_KEY)
669               return;
670           case SOLVABLE_ENHANCES:
671             if (s->enhances)
672               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
673             if (keyname || md->stop > SEARCH_NEXT_KEY)
674               return;
675           case SOLVABLE_FRESHENS:
676             if (s->freshens)
677               domatch_idarray(s, SOLVABLE_FRESHENS, md, repo->idarraydata + s->freshens);
678             if (keyname || md->stop > SEARCH_NEXT_KEY)
679               return;
680           case RPM_RPMDBID:
681             if (repo->rpmdbid)
682               {
683                 kv.num = repo->rpmdbid[p - repo->start];
684                 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
685               }
686             if (keyname || md->stop > SEARCH_NEXT_KEY)
687               return;
688             break;
689           default:
690             break;
691         }
692     }
693
694   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
695     {
696       if (p < data->start || p >= data->end)
697         continue;
698       if (data->state == REPODATA_STUB)
699         {
700           if (keyname)
701             {
702               for (j = 1; j < data->nkeys; j++)
703                 if (keyname == data->keys[j].name)
704                   break;
705               if (j == data->nkeys)
706                 continue;
707             }
708           /* load it */
709           if (data->loadcallback)
710             data->loadcallback(data);
711           else
712             data->state = REPODATA_ERROR;
713         }
714       if (data->state == REPODATA_ERROR)
715         continue;
716       repodata_search(data, p - data->start, keyname, repo_matchvalue, md);
717       if (md->stop > SEARCH_NEXT_KEY)
718         break;
719     }
720 }
721
722 void
723 repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
724 {
725   struct matchdata md;
726
727   memset(&md, 0, sizeof(md));
728   md.pool = repo->pool;
729   md.match = match;
730   md.flags = flags;
731   md.callback = callback;
732   md.callback_data = cbdata;
733   repo_search_md(repo, p, key, &md);
734 }
735
736 const char *
737 repo_lookup_str(Solvable *s, Id key)
738 {
739   Repo *repo = s->repo;
740   Pool *pool = repo->pool;
741   Repodata *data;
742   int i, j, n;
743
744   switch(key)
745     {
746     case SOLVABLE_NAME:
747       return id2str(pool, s->name);
748     case SOLVABLE_ARCH:
749       return id2str(pool, s->arch);
750     case SOLVABLE_EVR:
751       return id2str(pool, s->evr);
752     case SOLVABLE_VENDOR:
753       return id2str(pool, s->vendor);
754     }
755   n = s - pool->solvables;
756   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
757     {
758       if (n < data->start || n >= data->end)
759         continue;
760       for (j = 1; j < data->nkeys; j++)
761         {
762           if (data->keys[j].name == key && (data->keys[j].type == TYPE_ID || data->keys[j].type == TYPE_STR))
763             return repodata_lookup_str(data, n - data->start, j);
764         }
765     }
766   return 0;
767 }
768
769 int
770 repo_lookup_num(Solvable *s, Id key)
771 {
772   Repo *repo = s->repo;
773   Pool *pool = repo->pool;
774   Repodata *data;
775   int i, j, n;
776
777   n = s - pool->solvables;
778   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
779     {
780       if (n < data->start || n >= data->end)
781         continue;
782       for (j = 1; j < data->nkeys; j++)
783         {
784           if (data->keys[j].name == key
785               && (data->keys[j].type == TYPE_U32
786                   || data->keys[j].type == TYPE_NUM
787                   || data->keys[j].type == TYPE_CONSTANT))
788             {
789               unsigned value;
790               if (repodata_lookup_num(data, n - data->start, j, &value))
791                 return value;
792             }
793         }
794     }
795   return 0;
796 }
797
798
799 /*
800  * generic attribute lookup
801  * returns non-zero if found
802  * zero if not found
803  */
804
805 int
806 repo_lookup(Solvable *s, Id key, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
807 {
808   Repo *repo = s->repo;
809   Pool *pool = repo->pool;
810   Repodata *data;
811   int i, s_id;
812
813   s_id = s - pool->solvables;
814   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
815     {
816       if (s_id < data->start || s_id >= data->end)
817         continue;
818       repodata_search (data, s_id - data->start, key, callback, cbdata);
819       return 1;
820     }
821   return 0;
822 }
823
824
825 Repodata *
826 repo_add_repodata(Repo *repo)
827 {
828   Repodata *data;
829
830   repo->nrepodata++;
831   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
832   data = repo->repodata + repo->nrepodata - 1;
833   memset(data, 0, sizeof (*data));
834   data->repo = repo;
835   data->start = repo->start;
836   data->end = repo->end;
837   data->localpool = 0;
838   data->keys = sat_calloc(1, sizeof(Repokey));
839   data->nkeys = 1;
840   data->schemata = sat_calloc(1, sizeof(Id));
841   data->schemadata = sat_calloc(1, sizeof(Id));
842   data->nschemata = 1;
843   data->schemadatalen = 1;
844   data->incoreoffset = sat_calloc(data->end - data->start, sizeof(Id));
845   return data;
846 }
847
848 static Repodata *
849 findrepodata(Repo *repo, Id p, Id keyname)
850 {
851   int i;
852   Repodata *data;
853
854   /* FIXME: enter nice code here */
855   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
856     if (p >= data->start && p < data->end)
857       return data;
858   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
859     if (p == data->end)
860       break;
861   if (i < repo->nrepodata)
862     {
863       repodata_extend(data, p);
864       return data;
865     }
866   return repo_add_repodata(repo);
867 }
868
869 void
870 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
871 {
872   Repodata *data = findrepodata(repo, p, keyname);
873   repodata_set_id(data, p - data->start, keyname, id);
874 }
875
876 void
877 repo_set_num(Repo *repo, Id p, Id keyname, Id num)
878 {
879   Repodata *data = findrepodata(repo, p, keyname);
880   repodata_set_num(data, p - data->start, keyname, num);
881 }
882
883 void
884 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
885 {
886   Repodata *data = findrepodata(repo, p, keyname);
887   repodata_set_str(data, p - data->start, keyname, str);
888 }
889
890 void
891 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
892 {
893   Repodata *data = findrepodata(repo, p, keyname);
894   repodata_set_poolstr(data, p - data->start, keyname, str);
895 }
896
897 void
898 repo_internalize(Repo *repo)
899 {
900   int i;
901   Repodata *data;
902
903   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
904     if (data->attrs)
905       repodata_internalize(data);
906 }
907
908
909 #if 0
910
911 static int
912 key_cmp (const void *pa, const void *pb)
913 {
914   Repokey *a = (Repokey *)pa;
915   Repokey *b = (Repokey *)pb;
916   return a->name - b->name;
917 }
918
919 void
920 repo_add_attrstore (Repo *repo, Attrstore *s, const char *location)
921 {
922   unsigned i;
923   Repodata *data;
924   /* If this is meant to be the embedded attributes, make sure we don't
925      have them already.  */
926   if (!location)
927     {
928       for (i = 0; i < repo->nrepodata; i++)
929         if (repo->repodata[i].location == 0)
930           break;
931       if (i != repo->nrepodata)
932         {
933           pool_debug (repo->pool, SAT_FATAL, "embedded attribs added twice\n");
934           exit (1);
935         }
936     }
937   repo->nrepodata++;
938   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
939   data = repo->repodata + repo->nrepodata - 1;
940   memset (data, 0, sizeof (*data));
941   data->s = s;
942   data->nkeys = s->nkeys;
943   if (data->nkeys)
944     {
945       data->keys = sat_malloc2(data->nkeys, sizeof(data->keys[0]));
946       for (i = 1; i < data->nkeys; i++)
947         {
948           data->keys[i].name = s->keys[i].name;
949           data->keys[i].type = s->keys[i].type;
950         }
951       if (data->nkeys > 2)
952         qsort(data->keys + 1, data->nkeys - 1, sizeof(data->keys[0]), key_cmp);
953     }
954   if (location)
955     data->location = strdup(location);
956 }
957 #endif
958
959 // EOF