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