- add key filtering to repo_write
[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                   strncpy(dep - 9, "language:", 9);
350                   *p++ = 0;
351                   idl = str2id(pool, dep - 9, 1);
352                   if (id)
353                     id = rel2id(pool, id, idl, REL_OR, 1);
354                   else
355                     id = idl;
356                   dep = p;
357                 }
358               if (dep[0] && dep[1])
359                 {
360                   for (p = dep; *p && *p != ')'; p++)
361                     ;
362                   *p = 0;
363                   strncpy(dep - 9, "language:", 9);
364                   idl = str2id(pool, dep - 9, 1);
365                   if (id)
366                     id = rel2id(pool, id, idl, REL_OR, 1);
367                   else
368                     id = idl;
369                 }
370               if (idp)
371                 id = rel2id(pool, idp, id, REL_AND, 1);
372               if (id)
373                 supplements = repo_addid_dep(repo, supplements, id, 0);
374             }
375           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
376             {
377               strcpy(buf, dep);
378               p = buf + (p - dep);
379               *p++ = 0;
380               idp = str2id(pool, buf, 1);
381               id = str2id(pool, p, 1);
382               id = rel2id(pool, idp, id, REL_WITH, 1);
383               id = rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
384               supplements = repo_addid_dep(repo, supplements, id, 0);
385             }
386         }
387     }
388   if (!supplements)
389     return 0;
390   for (i = supplements; repo->idarraydata[i]; i++)
391     {
392       id = repo->idarraydata[i];
393       if (ISRELDEP(id))
394         continue;
395       dep = (char *)id2str(pool, id);
396       if (!strncmp(dep, "system:modalias(", 16))
397         dep += 7;
398       if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
399         {
400           strcpy(buf, dep);
401           p = strchr(buf + 9, ':');
402           if (p && p != buf + 9 && strchr(p + 1, ':'))
403             {
404               *p++ = 0;
405               idp = str2id(pool, buf + 9, 1);
406               p[strlen(p) - 1] = 0;
407               id = str2id(pool, p, 1);
408               id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
409               id = rel2id(pool, idp, id, REL_AND, 1);
410             }
411           else
412             {
413               p = buf + 9;
414               p[strlen(p) - 1] = 0;
415               id = str2id(pool, p, 1);
416               id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
417             }
418           if (id)
419             repo->idarraydata[i] = id;
420         }
421       else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
422         {
423           strcpy(buf, dep);
424           id = 0;
425           dep = buf + 11;
426           while ((p = strchr(dep, ':')) != 0)
427             {
428               if (p == dep)
429                 {
430                   dep = p + 1;
431                   continue;
432                 }
433               *p++ = 0;
434               idp = str2id(pool, dep, 1);
435               if (id)
436                 id = rel2id(pool, id, idp, REL_AND, 1);
437               else
438                 id = idp;
439               dep = p;
440             }
441           if (dep[0] && dep[1])
442             {
443               dep[strlen(dep) - 1] = 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             }
450           if (id)
451             repo->idarraydata[i] = id;
452         }
453     }
454   return supplements;
455 }
456
457 struct matchdata
458 {
459   Pool *pool;
460   const char *match;
461   int flags;
462 #if 0
463   regex_t regex;
464 #endif
465   int stop;
466   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
467   void *callback_data;
468 };
469
470 int
471 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
472 {
473   struct matchdata *md = cbdata;
474   int flags = md->flags;
475
476   if ((flags & SEARCH_STRINGMASK) != 0)
477     {
478       switch (key->type)
479         {
480         case TYPE_ID:
481         case TYPE_IDARRAY:
482           if (data->localpool)
483             kv->str = stringpool_id2str(&data->spool, kv->id);
484           else
485             kv->str = id2str(data->repo->pool, kv->id);
486           break;
487         case TYPE_STR:
488           break;
489         default:
490           return 0;
491         }
492       switch ((flags & SEARCH_STRINGMASK))
493         {
494           case SEARCH_SUBSTRING:
495             if (flags & SEARCH_NOCASE)
496               {
497                 if (!strcasestr(kv->str, md->match))
498                   return 0;
499               }
500             else
501               {
502                 if (!strstr(kv->str, md->match))
503                   return 0;
504               }
505             break;
506           case SEARCH_STRING:
507             if (flags & SEARCH_NOCASE)
508               {
509                 if (strcasecmp(md->match, kv->str))
510                   return 0;
511               }
512             else
513               {
514                 if (strcmp(md->match, kv->str))
515                   return 0;
516               }
517             break;
518           case SEARCH_GLOB:
519             if (fnmatch(md->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
520               return 0;
521             break;
522 #if 0
523           case SEARCH_REGEX:
524             if (regexec(&md->regexp, kv->str, 0, NULL, 0))
525               return 0;
526 #endif
527           default:
528             return 0;
529         }
530     }
531   md->stop = md->callback(md->callback_data, s, data, key, kv);
532   return md->stop;
533 }
534
535
536 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
537   { SOLVABLE_NAME,        TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
538   { SOLVABLE_ARCH,        TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
539   { SOLVABLE_EVR,         TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
540   { SOLVABLE_VENDOR,      TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
541   { SOLVABLE_PROVIDES,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
542   { SOLVABLE_OBSOLETES,   TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
543   { SOLVABLE_CONFLICTS,   TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
544   { SOLVABLE_REQUIRES,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
545   { SOLVABLE_RECOMMENDS,  TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
546   { SOLVABLE_SUGGESTS,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
547   { SOLVABLE_SUPPLEMENTS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
548   { SOLVABLE_ENHANCES,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
549   { SOLVABLE_FRESHENS,    TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
550   { RPM_RPMDBID,          TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
551 };
552
553 static void
554 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
555 {
556   KeyValue kv;
557   for (; *ida && !md->stop; ida++)
558     {
559       kv.id = *ida;
560       kv.eof = ida[1] ? 0 : 1;
561       repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
562     }
563 }
564
565 static void
566 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
567 {
568   KeyValue kv;
569   Pool *pool = repo->pool;
570   Repodata *data;
571   Solvable *s;
572   int i, j, flags;
573
574   md->stop = 0;
575   if (!p)
576     {
577       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
578         {
579           if (s->repo == repo)
580             repo_search_md(repo, p, keyname, md);
581           if (md->stop > SEARCH_NEXT_SOLVABLE)
582             break;
583         }
584       return;
585     }
586   s = pool->solvables + p;
587   flags = md->flags;
588   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
589     {
590       switch(keyname)
591         {
592           case 0:
593           case SOLVABLE_NAME:
594             if (s->name)
595               {
596                 kv.id = s->name;
597                 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
598               }
599             if (keyname || md->stop > SEARCH_NEXT_KEY)
600               return;
601           case SOLVABLE_ARCH:
602             if (s->arch)
603               {
604                 kv.id = s->arch;
605                 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
606               }
607             if (keyname || md->stop > SEARCH_NEXT_KEY)
608               return;
609           case SOLVABLE_EVR:
610             if (s->evr)
611               {
612                 kv.id = s->evr;
613                 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
614               }
615             if (keyname || md->stop > SEARCH_NEXT_KEY)
616               return;
617           case SOLVABLE_VENDOR:
618             if (s->vendor)
619               {
620                 kv.id = s->vendor;
621                 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
622               }
623             if (keyname || md->stop > SEARCH_NEXT_KEY)
624               return;
625           case SOLVABLE_PROVIDES:
626             if (s->provides)
627               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
628             if (keyname || md->stop > SEARCH_NEXT_KEY)
629               return;
630           case SOLVABLE_OBSOLETES:
631             if (s->obsoletes)
632               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
633             if (keyname || md->stop > SEARCH_NEXT_KEY)
634               return;
635           case SOLVABLE_CONFLICTS:
636             if (s->conflicts)
637               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
638             if (keyname || md->stop > SEARCH_NEXT_KEY)
639               return;
640           case SOLVABLE_REQUIRES:
641             if (s->requires)
642               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
643             if (keyname || md->stop > SEARCH_NEXT_KEY)
644               return;
645           case SOLVABLE_RECOMMENDS:
646             if (s->recommends)
647               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
648             if (keyname || md->stop > SEARCH_NEXT_KEY)
649               return;
650           case SOLVABLE_SUPPLEMENTS:
651             if (s->supplements)
652               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
653             if (keyname || md->stop > SEARCH_NEXT_KEY)
654               return;
655           case SOLVABLE_SUGGESTS:
656             if (s->suggests)
657               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
658             if (keyname || md->stop > SEARCH_NEXT_KEY)
659               return;
660           case SOLVABLE_ENHANCES:
661             if (s->enhances)
662               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
663             if (keyname || md->stop > SEARCH_NEXT_KEY)
664               return;
665           case SOLVABLE_FRESHENS:
666             if (s->freshens)
667               domatch_idarray(s, SOLVABLE_FRESHENS, md, repo->idarraydata + s->freshens);
668             if (keyname || md->stop > SEARCH_NEXT_KEY)
669               return;
670           case RPM_RPMDBID:
671             if (repo->rpmdbid)
672               {
673                 kv.num = repo->rpmdbid[p - repo->start];
674                 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
675               }
676             if (keyname || md->stop > SEARCH_NEXT_KEY)
677               return;
678             break;
679           default:
680             break;
681         }
682     }
683
684   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
685     {
686       if (p < data->start || p >= data->end)
687         continue;
688       if (data->state == REPODATA_STUB)
689         {
690           if (keyname)
691             {
692               for (j = 1; j < data->nkeys; j++)
693                 if (keyname == data->keys[j].name)
694                   break;
695               if (j == data->nkeys)
696                 continue;
697             }
698           /* load it */
699           if (data->loadcallback)
700             data->loadcallback(data);
701           else
702             data->state = REPODATA_ERROR;
703         }
704       if (data->state == REPODATA_ERROR)
705         continue;
706       repodata_search(data, p - data->start, keyname, repo_matchvalue, md);
707       if (md->stop > SEARCH_NEXT_KEY)
708         break;
709     }
710 }
711
712 void
713 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)
714 {
715   struct matchdata md;
716
717   memset(&md, 0, sizeof(md));
718   md.pool = repo->pool;
719   md.match = match;
720   md.flags = flags;
721   md.callback = callback;
722   md.callback_data = cbdata;
723   repo_search_md(repo, p, key, &md);
724 }
725
726 const char *
727 repo_lookup_str(Solvable *s, Id key)
728 {
729   Repo *repo = s->repo;
730   Pool *pool = repo->pool;
731   Repodata *data;
732   int i, j, n;
733
734   switch(key)
735     {
736     case SOLVABLE_NAME:
737       return id2str(pool, s->name);
738     case SOLVABLE_ARCH:
739       return id2str(pool, s->arch);
740     case SOLVABLE_EVR:
741       return id2str(pool, s->evr);
742     case SOLVABLE_VENDOR:
743       return id2str(pool, s->vendor);
744     }
745   n = s - pool->solvables;
746   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
747     {
748       if (n < data->start || n >= data->end)
749         continue;
750       for (j = 1; j < data->nkeys; j++)
751         {
752           if (data->keys[j].name == key && (data->keys[j].type == TYPE_ID || data->keys[j].type == TYPE_STR))
753             return repodata_lookup_str(data, n - data->start, j);
754         }
755     }
756   return 0;
757 }
758
759 Repodata *
760 repo_add_repodata(Repo *repo)
761 {
762   Repodata *data;
763
764   repo->nrepodata++;
765   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
766   data = repo->repodata + repo->nrepodata - 1;
767   memset(data, 0, sizeof (*data));
768   data->repo = repo;
769   data->start = repo->start;
770   data->end = repo->end;
771   data->localpool = 0;
772   data->keys = sat_calloc(1, sizeof(Repokey));
773   data->nkeys = 1;
774   data->schemata = sat_calloc(1, sizeof(Id));
775   data->schemadata = sat_calloc(1, sizeof(Id));
776   data->nschemata = 1;
777   data->schemadatalen = 1;
778   data->entryschemau8 = sat_calloc(data->end - data->start, 1);
779   data->incoreoffset = sat_calloc(data->end - data->start, sizeof(Id));
780   return data;
781 }
782
783 static Repodata *findrepodata(Repo *repo, Id p, Id keyname)
784 {
785   int i;
786   Repodata *data;
787
788   /* FIXME: enter nice code here */
789   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
790     if (p >= data->start && p < data->end)
791       return data;
792   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
793     if (p == data->end)
794       break;
795   if (i < repo->nrepodata)
796     {
797       repodata_extend(data, p);
798       return data;
799     }
800   return repo_add_repodata(repo);
801 }
802
803 void
804 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
805 {
806   Repodata *data = findrepodata(repo, p, keyname);
807   repodata_set_id(data, p - data->start, keyname, id);
808 }
809
810 void
811 repo_set_num(Repo *repo, Id p, Id keyname, Id num)
812 {
813   Repodata *data = findrepodata(repo, p, keyname);
814   repodata_set_num(data, p - data->start, keyname, num);
815 }
816
817 void
818 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
819 {
820   Repodata *data = findrepodata(repo, p, keyname);
821   repodata_set_str(data, p - data->start, keyname, str);
822 }
823
824 void
825 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
826 {
827   Repodata *data = findrepodata(repo, p, keyname);
828   repodata_set_poolstr(data, p - data->start, keyname, str);
829 }
830
831 void
832 repo_internalize(Repo *repo)
833 {
834   int i;
835   Repodata *data;
836
837   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
838     if (data->attrs)
839       repodata_internalize(data);
840 }
841
842
843 #if 0
844
845 static int
846 key_cmp (const void *pa, const void *pb)
847 {
848   Repokey *a = (Repokey *)pa;
849   Repokey *b = (Repokey *)pb;
850   return a->name - b->name;
851 }
852
853 void
854 repo_add_attrstore (Repo *repo, Attrstore *s, const char *location)
855 {
856   unsigned i;
857   Repodata *data;
858   /* If this is meant to be the embedded attributes, make sure we don't
859      have them already.  */
860   if (!location)
861     {
862       for (i = 0; i < repo->nrepodata; i++)
863         if (repo->repodata[i].location == 0)
864           break;
865       if (i != repo->nrepodata)
866         {
867           pool_debug (repo->pool, SAT_FATAL, "embedded attribs added twice\n");
868           exit (1);
869         }
870     }
871   repo->nrepodata++;
872   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
873   data = repo->repodata + repo->nrepodata - 1;
874   memset (data, 0, sizeof (*data));
875   data->s = s;
876   data->nkeys = s->nkeys;
877   if (data->nkeys)
878     {
879       data->keys = sat_malloc2(data->nkeys, sizeof(data->keys[0]));
880       for (i = 1; i < data->nkeys; i++)
881         {
882           data->keys[i].name = s->keys[i].name;
883           data->keys[i].type = s->keys[i].type;
884         }
885       if (data->nkeys > 2)
886         qsort(data->keys + 1, data->nkeys - 1, sizeof(data->keys[0]), key_cmp);
887     }
888   if (location)
889     data->location = strdup(location);
890 }
891 #endif
892
893 // EOF