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