- improve filemarker handling
[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 #include "chksum.h"
29
30 #define IDARRAY_BLOCK     4095
31
32
33 /*
34  * create empty repo
35  * and add to pool
36  */
37
38 Repo *
39 repo_create(Pool *pool, const char *name)
40 {
41   Repo *repo;
42
43   pool_freewhatprovides(pool);
44   repo = (Repo *)solv_calloc(1, sizeof(*repo));
45   pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
46   pool->repos[pool->nrepos++] = repo;
47   repo->repoid = pool->nrepos;
48   repo->name = name ? strdup(name) : 0;
49   repo->pool = pool;
50   repo->start = pool->nsolvables;
51   repo->end = pool->nsolvables;
52   repo->nsolvables = 0;
53   return repo;
54 }
55
56 static void
57 repo_freedata(Repo *repo)
58 {
59   int i;
60   for (i = 0; i < repo->nrepodata; i++)
61     repodata_freedata(repo->repodata + i);
62   solv_free(repo->repodata);
63   solv_free(repo->idarraydata);
64   solv_free(repo->rpmdbid);
65   solv_free(repo->lastidhash);
66   solv_free((char *)repo->name);
67   solv_free(repo);
68 }
69
70 /* delete all solvables and repodata blocks from this repo */
71
72 void
73 repo_empty(Repo *repo, int reuseids)
74 {
75   Pool *pool = repo->pool;
76   Solvable *s;
77   int i;
78
79   pool_freewhatprovides(pool);
80   if (reuseids && repo->end == pool->nsolvables)
81     {
82       /* it's ok to reuse the ids. As this is the last repo, we can
83          just shrink the solvable array */
84       for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
85         if (s->repo != repo)
86           break;
87       pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids);
88     }
89   /* zero out (i.e. free) solvables belonging to this repo */
90   for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
91     if (s->repo == repo)
92       memset(s, 0, sizeof(*s));
93   repo->nsolvables = 0;
94
95   /* free all data belonging to this repo */
96   repo->idarraydata = solv_free(repo->idarraydata);
97   repo->idarraysize = 0;
98   repo->lastoff = 0;
99   repo->rpmdbid = solv_free(repo->rpmdbid);
100   for (i = 0; i < repo->nrepodata; i++)
101     repodata_freedata(repo->repodata + i);
102   solv_free(repo->repodata);
103   repo->repodata = 0;
104   repo->nrepodata = 0;
105 }
106
107 /*
108  * remove repo from pool, delete solvables
109  *
110  */
111
112 void
113 repo_free(Repo *repo, int reuseids)
114 {
115   Pool *pool = repo->pool;
116   int i;
117
118   if (repo == pool->installed)
119     pool->installed = 0;
120   repo_empty(repo, reuseids);
121   for (i = 0; i < pool->nrepos; i++)    /* find repo in pool */
122     if (pool->repos[i] == repo)
123       break;
124   if (i == pool->nrepos)               /* repo not in pool, return */
125     return;
126   if (i < pool->nrepos - 1)
127     {
128       memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *));
129       /* fix repo ids */
130       for (; i < pool->nrepos - 1; i++)
131         pool->repos[i]->repoid = i + 1;
132     }
133   pool->nrepos--;
134   repo_freedata(repo);
135 }
136
137 void
138 repo_freeallrepos(Pool *pool, int reuseids)
139 {
140   int i;
141
142   pool_freewhatprovides(pool);
143   for (i = 0; i < pool->nrepos; i++)
144     repo_freedata(pool->repos[i]);
145   pool->repos = solv_free(pool->repos);
146   pool->nrepos = 0;
147   /* the first two solvables don't belong to a repo */
148   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
149 }
150
151 Id repo_add_solvable(Repo *repo)
152 {
153   Id p = pool_add_solvable(repo->pool);
154   if (!repo->start || repo->start == repo->end)
155     repo->start = repo->end = p;
156   /* warning: sidedata must be extended before adapting start/end */
157   if (repo->rpmdbid)
158     repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, 1); 
159   if (p < repo->start)
160     repo->start = p;
161   if (p + 1 > repo->end)
162     repo->end = p + 1;
163   repo->nsolvables++;
164   repo->pool->solvables[p].repo = repo;
165   return p;
166 }
167
168 Id repo_add_solvable_block(Repo *repo, int count)
169 {
170   Id p;
171   Solvable *s; 
172   if (!count)
173     return 0;
174   p = pool_add_solvable_block(repo->pool, count);
175   if (!repo->start || repo->start == repo->end)
176     repo->start = repo->end = p;
177   /* warning: sidedata must be extended before adapting start/end */
178   if (repo->rpmdbid)
179     repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
180   if (p < repo->start)
181     repo->start = p;
182   if (p + count > repo->end)
183     repo->end = p + count;
184   repo->nsolvables += count;
185   for (s = repo->pool->solvables + p; count--; s++)
186     s->repo = repo;
187   return p;
188 }
189
190 void repo_free_solvable(Repo *repo, Id p, int reuseids)
191 {
192   repo_free_solvable_block(repo, p, 1, reuseids);
193 }
194
195 void repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids)
196 {
197   Solvable *s;
198   Repodata *data;
199   int i;
200   if (start + count == repo->end)
201     repo->end -= count;
202   repo->nsolvables -= count;
203   for (s = repo->pool->solvables + start, i = count; i--; s++)
204     s->repo = 0;
205   pool_free_solvable_block(repo->pool, start, count, reuseids);
206   FOR_REPODATAS(repo, i, data)
207     if (data->end > repo->end)
208       repodata_shrink(data, repo->end);
209 }
210
211
212 /* repository sidedata is solvable data allocated on demand.
213  * It is used for data that is normally not present
214  * in the solvable like the rpmdbid.
215  * The solvable allocation funcions need to make sure that
216  * the sidedata gets extended if new solvables get added.
217  */
218
219 #define REPO_SIDEDATA_BLOCK 63
220
221 void *
222 repo_sidedata_create(Repo *repo, size_t size)
223 {
224   return solv_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
225 }
226
227 void *
228 repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
229 {
230   int n = repo->end - repo->start;
231   if (p < repo->start)
232     {
233       int d = repo->start - p;
234       b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
235       memmove((char *)b + d * size, b, n * size);
236       memset(b, 0, d * size);
237       n += d;
238     }
239   if (p + count > repo->end)
240     {
241       int d = p + count - repo->end;
242       b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
243       memset((char *)b + n * size, 0, d * size);
244     }
245   return b;
246 }
247
248 /*
249  * add Id to idarraydata used to store dependencies
250  * olddeps: old array offset to extend
251  * returns new array offset
252  */
253
254 Offset
255 repo_addid(Repo *repo, Offset olddeps, Id id)
256 {
257   Id *idarray;
258   int idarraysize;
259   int i;
260
261   idarray = repo->idarraydata;
262   idarraysize = repo->idarraysize;
263
264   if (!idarray)                        /* alloc idarray if not done yet */
265     {
266       idarraysize = 1;
267       idarray = solv_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
268       idarray[0] = 0;
269       repo->lastoff = 0;
270     }
271
272   if (!olddeps)                         /* no deps yet */
273     {
274       olddeps = idarraysize;
275       idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
276     }
277   else if (olddeps == repo->lastoff)    /* extend at end */
278     idarraysize--;
279   else                                  /* can't extend, copy old */
280     {
281       i = olddeps;
282       olddeps = idarraysize;
283       for (; idarray[i]; i++)
284         {
285           idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
286           idarray[idarraysize++] = idarray[i];
287         }
288       idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
289     }
290
291   idarray[idarraysize++] = id;          /* insert Id into array */
292   idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
293   idarray[idarraysize++] = 0;           /* ensure NULL termination */
294
295   repo->idarraydata = idarray;
296   repo->idarraysize = idarraysize;
297   repo->lastoff = olddeps;
298
299   return olddeps;
300 }
301
302 #define REPO_ADDID_DEP_HASHTHRES        64
303 #define REPO_ADDID_DEP_HASHMIN          128
304
305 /* 
306  * Optimization for packages with an excessive amount of provides/requires:
307  * if the number of deps exceed a threshold, we build a hash of the already
308  * seen ids.
309  */
310 static Offset
311 repo_addid_dep_hash(Repo *repo, Offset olddeps, Id id, Id marker, int size)
312 {
313   Id oid, *oidp;
314   int before;
315   Hashval h, hh;
316   Id hid;
317
318   before = 0;
319   if (marker)
320     {
321       if (marker < 0)
322         {
323           marker = -marker;
324           before = 1;
325         }
326       if (marker == id)
327         marker = 0;
328     }
329
330   /* maintain hash and lastmarkerpos */
331   if (repo->lastidhash_idarraysize != repo->idarraysize || size * 2 > repo->lastidhash_mask || repo->lastmarker != marker)
332     {
333       repo->lastmarkerpos = 0;
334       if (size * 2 > repo->lastidhash_mask)
335         {
336           repo->lastidhash_mask = mkmask(size < REPO_ADDID_DEP_HASHMIN ? REPO_ADDID_DEP_HASHMIN : size);
337           repo->lastidhash = solv_realloc2(repo->lastidhash, repo->lastidhash_mask + 1, sizeof(Id));
338         }
339       memset(repo->lastidhash, 0, (repo->lastidhash_mask + 1) * sizeof(Id));
340       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
341         {
342           h = oid & repo->lastidhash_mask;
343           hh = HASHCHAIN_START;
344           while (repo->lastidhash[h] != 0)
345             h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
346           repo->lastidhash[h] = oid;
347           if (marker && oid == marker)
348             repo->lastmarkerpos = oidp - repo->idarraydata;
349         }
350       repo->lastmarker = marker;
351       repo->lastidhash_idarraysize = repo->idarraysize;
352     }
353
354   /* check the hash! */
355   h = id & repo->lastidhash_mask;
356   hh = HASHCHAIN_START;
357   while ((hid = repo->lastidhash[h]) != 0 && hid != id)
358     h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
359   /* put new element in hash */
360   if (!hid)
361     repo->lastidhash[h] = id;
362   else if (marker == SOLVABLE_FILEMARKER && (!before || !repo->lastmarkerpos))
363     return olddeps;
364   if (marker && !before && !repo->lastmarkerpos)
365     {
366       /* we have to add the marker first */
367       repo->lastmarkerpos = repo->idarraysize - 1;
368       olddeps = repo_addid(repo, olddeps, marker);
369       /* now put marker in hash */
370       h = marker & repo->lastidhash_mask;
371       hh = HASHCHAIN_START;
372       while (repo->lastidhash[h] != 0)
373         h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
374       repo->lastidhash[h] = marker;
375       repo->lastidhash_idarraysize = repo->idarraysize;
376     }
377   if (!hid)
378     {
379       /* new entry, insert in correct position */
380       if (marker && before && repo->lastmarkerpos)
381         {
382           /* need to add it before the marker */
383           olddeps = repo_addid(repo, olddeps, id);      /* dummy to make room */
384           memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (repo->idarraysize - repo->lastmarkerpos - 2) * sizeof(Id));
385           repo->idarraydata[repo->lastmarkerpos++] = id;
386         }
387       else
388         {
389           /* just append it to the end */
390           olddeps = repo_addid(repo, olddeps, id);
391         }
392       repo->lastidhash_idarraysize = repo->idarraysize;
393       return olddeps;
394     }
395   /* we already have it in the hash */
396   if (!marker)
397     return olddeps;
398   if (marker == SOLVABLE_FILEMARKER)
399     {
400       /* check if it is in the wrong half */
401       /* (we already made sure that "before" and "lastmarkerpos" are set, see above) */
402       for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
403         if (oid == id)
404           break;
405       if (!oid)
406         return olddeps;
407       /* yes, wrong half. copy it over */
408       memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (oidp - (repo->idarraydata + repo->lastmarkerpos)) * sizeof(Id));
409       repo->idarraydata[repo->lastmarkerpos++] = id;
410       return olddeps;
411     }
412   if (before)
413     return olddeps;
414   /* check if it is in the correct half */
415   for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
416     if (oid == id)
417       return olddeps;
418   /* nope, copy it over */
419   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
420     if (oid == id)
421       break;
422   if (!oid)
423     return olddeps;     /* should not happen */
424   memmove(oidp, oidp + 1, (repo->idarraydata + repo->idarraysize - oidp - 2) * sizeof(Id));
425   repo->idarraydata[repo->idarraysize - 2] = id;
426   repo->lastmarkerpos--;        /* marker has been moved */
427   return olddeps;
428 }
429
430 /*
431  * add dependency (as Id) to repo, also unifies dependencies
432  * olddeps = offset into idarraydata
433  * marker= 0 for normal dep
434  * marker > 0 add dep after marker
435  * marker < 0 add dep before -marker
436  * returns new start of dependency array
437  */
438 Offset
439 repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
440 {
441   Id oid, *oidp, *markerp;
442   int before;
443
444   if (!olddeps)
445     {
446       if (marker > 0)
447         olddeps = repo_addid(repo, olddeps, marker);
448       return repo_addid(repo, olddeps, id);
449     }
450
451   /* check if we should use the hash optimization */
452   if (olddeps == repo->lastoff)
453     {
454       int size = repo->idarraysize - 1 - repo->lastoff;
455       if (size >= REPO_ADDID_DEP_HASHTHRES)
456         return repo_addid_dep_hash(repo, olddeps, id, marker, size);
457     }
458
459   before = 0;
460   if (marker)
461     {
462       if (marker < 0)
463         {
464           marker = -marker;
465           before = 1;
466         }
467       if (marker == id)
468         marker = 0;
469     }
470
471   if (!marker)
472     {
473       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
474         if (oid == id)
475           return olddeps;
476       return repo_addid(repo, olddeps, id);
477     }
478
479   markerp = 0;
480   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
481     {
482       if (oid == marker)
483         markerp = oidp;
484       else if (oid == id)
485         break;
486     }
487
488   if (oid)
489     {
490       if (marker == SOLVABLE_FILEMARKER)
491         {
492           if (!markerp || !before)
493             return olddeps;
494           /* we found it, but in the second half */
495           memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
496           *markerp = id;
497           return olddeps;
498         }
499       if (markerp || before)
500         return olddeps;
501       /* we found it, but in the first half */
502       markerp = oidp++;
503       for (; (oid = *oidp) != 0; oidp++)
504         if (oid == marker)
505           break;
506       if (!oid)
507         {
508           /* no marker in array yet */
509           oidp--;
510           if (markerp < oidp)
511             memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
512           *oidp = marker;
513           return repo_addid(repo, olddeps, id);
514         }
515       while (oidp[1])
516         oidp++;
517       memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
518       *oidp = id;
519       return olddeps;
520     }
521   /* id not yet in array */
522   if (!before && !markerp)
523     olddeps = repo_addid(repo, olddeps, marker);
524   else if (before && markerp)
525     {
526       *markerp++ = id;
527       id = *--oidp;
528       if (markerp < oidp)
529         memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
530       *markerp = marker;
531     }
532   return repo_addid(repo, olddeps, id);
533 }
534
535
536 /*
537  * reserve Ids
538  * make space for 'num' more dependencies
539  * returns new start of dependency array
540  *
541  * reserved ids will always begin at offset idarraysize
542  */
543
544 Offset
545 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
546 {
547   num++;        /* room for trailing ID_NULL */
548
549   if (!repo->idarraysize)              /* ensure buffer space */
550     {
551       repo->idarraysize = 1;
552       repo->idarraydata = solv_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
553       repo->idarraydata[0] = 0;
554       repo->lastoff = 1;
555       return 1;
556     }
557
558   if (olddeps && olddeps != repo->lastoff)   /* if not appending */
559     {
560       /* can't insert into idarray, this would invalidate all 'larger' offsets
561        * so create new space at end and move existing deps there.
562        * Leaving 'hole' at old position.
563        */
564
565       Id *idstart, *idend;
566       int count;
567
568       for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
569         ;
570       count = idend - idstart - 1 + num;               /* new size */
571
572       repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
573       /* move old deps to end */
574       olddeps = repo->lastoff = repo->idarraysize;
575       memcpy(repo->idarraydata + olddeps, idstart, count - num);
576       repo->idarraysize = olddeps + count - num;
577
578       return olddeps;
579     }
580
581   if (olddeps)                         /* appending */
582     repo->idarraysize--;
583
584   /* make room*/
585   repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
586
587   /* appending or new */
588   repo->lastoff = olddeps ? olddeps : repo->idarraysize;
589
590   return repo->lastoff;
591 }
592
593
594
595 Offset
596 repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
597 {
598   Pool *pool = repo->pool;
599   Id id, idp, idl;
600   char buf[1024], *p, *dep;
601   int i, l;
602
603   if (provides)
604     {
605       for (i = provides; repo->idarraydata[i]; i++)
606         {
607           id = repo->idarraydata[i];
608           if (ISRELDEP(id))
609             continue;
610           dep = (char *)pool_id2str(pool, id);
611           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
612             {
613               idp = 0;
614               strcpy(buf + 2, dep);
615               dep = buf + 2 + 7;
616               if ((p = strchr(dep, ':')) != 0 && p != dep)
617                 {
618                   *p++ = 0;
619                   idp = pool_str2id(pool, dep, 1);
620                   dep = p;
621                 }
622               id = 0;
623               while ((p = strchr(dep, ';')) != 0)
624                 {
625                   if (p == dep)
626                     {
627                       dep = p + 1;
628                       continue;
629                     }
630                   *p++ = 0;
631 #if 0
632                   strncpy(dep - 9, "language:", 9);
633                   idl = pool_str2id(pool, dep - 9, 1);
634 #else
635                   idl = pool_str2id(pool, dep, 1);
636                   idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
637 #endif
638                   if (id)
639                     id = pool_rel2id(pool, id, idl, REL_OR, 1);
640                   else
641                     id = idl;
642                   dep = p;
643                 }
644               if (dep[0] && dep[1])
645                 {
646                   for (p = dep; *p && *p != ')'; p++)
647                     ;
648                   *p = 0;
649 #if 0
650                   strncpy(dep - 9, "language:", 9);
651                   idl = pool_str2id(pool, dep - 9, 1);
652 #else
653                   idl = pool_str2id(pool, dep, 1);
654                   idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
655 #endif
656                   if (id)
657                     id = pool_rel2id(pool, id, idl, REL_OR, 1);
658                   else
659                     id = idl;
660                 }
661               if (idp)
662                 id = pool_rel2id(pool, idp, id, REL_AND, 1);
663               if (id)
664                 supplements = repo_addid_dep(repo, supplements, id, 0);
665             }
666           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
667             {
668               strcpy(buf, dep);
669               p = buf + (p - dep);
670               *p++ = 0;
671               idp = pool_str2id(pool, buf, 1);
672               /* strip trailing slashes */
673               l = strlen(p);
674               while (l > 1 && p[l - 1] == '/')
675                 p[--l] = 0;
676               id = pool_str2id(pool, p, 1);
677               id = pool_rel2id(pool, idp, id, REL_WITH, 1);
678               id = pool_rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
679               supplements = repo_addid_dep(repo, supplements, id, 0);
680             }
681         }
682     }
683   if (supplements)
684     {
685       for (i = supplements; repo->idarraydata[i]; i++)
686         {
687           id = repo->idarraydata[i];
688           if (ISRELDEP(id))
689             continue;
690           dep = (char *)pool_id2str(pool, id);
691           if (!strncmp(dep, "system:modalias(", 16))
692             dep += 7;
693           if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
694             {
695               strcpy(buf, dep);
696               p = strchr(buf + 9, ':');
697               if (p && p != buf + 9 && strchr(p + 1, ':'))
698                 {
699                   *p++ = 0;
700                   idp = pool_str2id(pool, buf + 9, 1);
701                   p[strlen(p) - 1] = 0;
702                   id = pool_str2id(pool, p, 1);
703                   id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
704                   id = pool_rel2id(pool, idp, id, REL_AND, 1);
705                 }
706               else
707                 {
708                   p = buf + 9;
709                   p[strlen(p) - 1] = 0;
710                   id = pool_str2id(pool, p, 1);
711                   id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
712                 }
713               if (id)
714                 repo->idarraydata[i] = id;
715             }
716           else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
717             {
718               strcpy(buf, dep);
719               id = 0;
720               dep = buf + 11;
721               while ((p = strchr(dep, ':')) != 0)
722                 {
723                   if (p == dep)
724                     {
725                       dep = p + 1;
726                       continue;
727                     }
728                   *p++ = 0;
729                   idp = pool_str2id(pool, dep, 1);
730                   if (id)
731                     id = pool_rel2id(pool, id, idp, REL_AND, 1);
732                   else
733                     id = idp;
734                   dep = p;
735                 }
736               if (dep[0] && dep[1])
737                 {
738                   dep[strlen(dep) - 1] = 0;
739                   idp = pool_str2id(pool, dep, 1);
740                   if (id)
741                     id = pool_rel2id(pool, id, idp, REL_AND, 1);
742                   else
743                     id = idp;
744                 }
745               if (id)
746                 repo->idarraydata[i] = id;
747             }
748           else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
749             {
750               strcpy(buf, dep + 11);
751               if ((p = strrchr(buf, ')')) != 0)
752                 *p = 0;
753               id = pool_str2id(pool, buf, 1);
754               id = pool_rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
755               repo->idarraydata[i] = id;
756             }
757         }
758     }
759   if (freshens && repo->idarraydata[freshens])
760     {
761       Id idsupp = 0, idfresh = 0;
762       if (!supplements)
763         return freshens;
764       for (i = supplements; repo->idarraydata[i]; i++)
765         {
766           if (!idsupp)
767             idsupp = repo->idarraydata[i];
768           else
769             idsupp = pool_rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
770         }
771       for (i = freshens; repo->idarraydata[i]; i++)
772         {
773           if (!idfresh)
774             idfresh = repo->idarraydata[i];
775           else
776             idfresh = pool_rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
777         }
778       if (!idsupp)
779         idsupp = idfresh;
780       else
781         idsupp = pool_rel2id(pool, idsupp, idfresh, REL_AND, 1);
782       supplements = repo_addid_dep(repo, 0, idsupp, 0);
783     }
784   return supplements;
785 }
786
787 Offset
788 repo_fix_conflicts(Repo *repo, Offset conflicts)
789 {
790   char buf[1024], *p, *dep;
791   Pool *pool = repo->pool;
792   Id id;
793   int i;
794
795   if (!conflicts)
796     return conflicts;
797   for (i = conflicts; repo->idarraydata[i]; i++)
798     {
799       id = repo->idarraydata[i];
800       if (ISRELDEP(id))
801         continue;
802       dep = (char *)pool_id2str(pool, id);
803       if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2)
804         {
805           strcpy(buf, dep + 15);
806           if ((p = strchr(buf, ')')) != 0)
807             *p = 0;
808           id = pool_str2id(pool, buf, 1);
809           id = pool_rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
810           repo->idarraydata[i] = id;
811         }
812     }
813   return conflicts;
814 }
815
816 struct matchdata
817 {
818   Pool *pool;
819   int flags;
820   Datamatcher matcher;
821   int stop;
822   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
823   void *callback_data;
824 };
825
826 int
827 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
828 {
829   struct matchdata *md = cbdata;
830
831   if (md->matcher.match)
832     {
833       if (!repodata_stringify(md->pool, data, key, kv, md->flags))
834         return 0;
835       if (!datamatcher_match(&md->matcher, kv->str))
836         return 0;
837     }
838   md->stop = md->callback(md->callback_data, s, data, key, kv);
839   return md->stop;
840 }
841
842
843 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
844   { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
845   { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
846   { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
847   { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
848   { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
849   { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
850   { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
851   { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
852   { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
853   { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
854   { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
855   { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
856   { RPM_RPMDBID,          REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
857 };
858
859 static void
860 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
861 {
862   KeyValue kv;
863   kv.entry = 0;
864   kv.parent = 0;
865   for (; *ida && !md->stop; ida++)
866     {
867       kv.id = *ida;
868       kv.eof = ida[1] ? 0 : 1;
869       repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
870       kv.entry++;
871     }
872 }
873
874 static void
875 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
876 {
877   KeyValue kv;
878   Pool *pool = repo->pool;
879   Repodata *data;
880   int i, j, flags;
881   Solvable *s;
882
883   kv.parent = 0;
884   md->stop = 0;
885   if (!p)
886     {
887       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
888         {
889           if (s->repo == repo)
890             repo_search_md(repo, p, keyname, md);
891           if (md->stop > SEARCH_NEXT_SOLVABLE)
892             break;
893         }
894       return;
895     }
896   else if (p < 0)
897     /* The callback only supports solvables, so we can't iterate over the
898        extra things.  */
899     return;
900   flags = md->flags;
901   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
902     {
903       s = pool->solvables + p;
904       switch(keyname)
905         {
906           case 0:
907           case SOLVABLE_NAME:
908             if (s->name)
909               {
910                 kv.id = s->name;
911                 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
912               }
913             if (keyname || md->stop > SEARCH_NEXT_KEY)
914               return;
915           case SOLVABLE_ARCH:
916             if (s->arch)
917               {
918                 kv.id = s->arch;
919                 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
920               }
921             if (keyname || md->stop > SEARCH_NEXT_KEY)
922               return;
923           case SOLVABLE_EVR:
924             if (s->evr)
925               {
926                 kv.id = s->evr;
927                 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
928               }
929             if (keyname || md->stop > SEARCH_NEXT_KEY)
930               return;
931           case SOLVABLE_VENDOR:
932             if (s->vendor)
933               {
934                 kv.id = s->vendor;
935                 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
936               }
937             if (keyname || md->stop > SEARCH_NEXT_KEY)
938               return;
939           case SOLVABLE_PROVIDES:
940             if (s->provides)
941               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
942             if (keyname || md->stop > SEARCH_NEXT_KEY)
943               return;
944           case SOLVABLE_OBSOLETES:
945             if (s->obsoletes)
946               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
947             if (keyname || md->stop > SEARCH_NEXT_KEY)
948               return;
949           case SOLVABLE_CONFLICTS:
950             if (s->conflicts)
951               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
952             if (keyname || md->stop > SEARCH_NEXT_KEY)
953               return;
954           case SOLVABLE_REQUIRES:
955             if (s->requires)
956               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
957             if (keyname || md->stop > SEARCH_NEXT_KEY)
958               return;
959           case SOLVABLE_RECOMMENDS:
960             if (s->recommends)
961               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
962             if (keyname || md->stop > SEARCH_NEXT_KEY)
963               return;
964           case SOLVABLE_SUPPLEMENTS:
965             if (s->supplements)
966               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
967             if (keyname || md->stop > SEARCH_NEXT_KEY)
968               return;
969           case SOLVABLE_SUGGESTS:
970             if (s->suggests)
971               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
972             if (keyname || md->stop > SEARCH_NEXT_KEY)
973               return;
974           case SOLVABLE_ENHANCES:
975             if (s->enhances)
976               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
977             if (keyname || md->stop > SEARCH_NEXT_KEY)
978               return;
979           case RPM_RPMDBID:
980             if (repo->rpmdbid)
981               {
982                 kv.num = repo->rpmdbid[p - repo->start];
983                 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
984               }
985             if (keyname || md->stop > SEARCH_NEXT_KEY)
986               return;
987             break;
988           default:
989             break;
990         }
991     }
992
993   FOR_REPODATAS(repo, i, data)
994     {
995       if (p < data->start || p >= data->end)
996         continue;
997       if (keyname && !repodata_precheck_keyname(data, keyname))
998         continue;
999       if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST))
1000         {
1001           /* do not search filelist extensions */
1002           if (data->state != REPODATA_AVAILABLE)
1003             continue;
1004           for (j = 1; j < data->nkeys; j++)
1005             if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1006               break;
1007           if (j == data->nkeys)
1008             continue;
1009         }
1010       if (data->state == REPODATA_STUB)
1011         {
1012           if (keyname)
1013             {
1014               for (j = 1; j < data->nkeys; j++)
1015                 if (keyname == data->keys[j].name)
1016                   break;
1017               if (j == data->nkeys)
1018                 continue;
1019             }
1020           /* load it */
1021           if (data->loadcallback)
1022             data->loadcallback(data);
1023           else
1024             data->state = REPODATA_ERROR;
1025         }
1026       if (data->state == REPODATA_ERROR)
1027         continue;
1028       repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
1029       if (md->stop > SEARCH_NEXT_KEY)
1030         break;
1031     }
1032 }
1033
1034 void
1035 repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
1036 {
1037   struct matchdata md;
1038
1039   if (repo->disabled && !(flags & SEARCH_DISABLED_REPOS))
1040     return;
1041   memset(&md, 0, sizeof(md));
1042   md.pool = repo->pool;
1043   md.flags = flags;
1044   md.callback = callback;
1045   md.callback_data = cbdata;
1046   if (match)
1047     datamatcher_init(&md.matcher, match, flags);
1048   repo_search_md(repo, p, keyname, &md);
1049   if (match)
1050     datamatcher_free(&md.matcher);
1051 }
1052
1053 const char *
1054 repo_lookup_str(Repo *repo, Id entry, Id keyname)
1055 {
1056   Pool *pool = repo->pool;
1057   Repodata *data;
1058   int i;
1059   const char *str;
1060
1061   if (entry >= 0)
1062     {
1063       switch (keyname)
1064         {
1065         case SOLVABLE_NAME:
1066           return pool_id2str(pool, pool->solvables[entry].name);
1067         case SOLVABLE_ARCH:
1068           return pool_id2str(pool, pool->solvables[entry].arch);
1069         case SOLVABLE_EVR:
1070           return pool_id2str(pool, pool->solvables[entry].evr);
1071         case SOLVABLE_VENDOR:
1072           return pool_id2str(pool, pool->solvables[entry].vendor);
1073         }
1074     }
1075   FOR_REPODATAS(repo, i, data)
1076     {
1077       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1078         continue;
1079       if (!repodata_precheck_keyname(data, keyname))
1080         continue;
1081       str = repodata_lookup_str(data, entry, keyname);
1082       if (str)
1083         return str;
1084       if (repodata_lookup_type(data, entry, keyname))
1085         return 0;
1086     }
1087   return 0;
1088 }
1089
1090
1091 unsigned int
1092 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned int notfound)
1093 {
1094   Repodata *data;
1095   int i;
1096   unsigned int value;
1097
1098   if (entry >= 0)
1099     {
1100       if (keyname == RPM_RPMDBID)
1101         {
1102           if (repo->rpmdbid && entry >= repo->start && entry < repo->end)
1103             return repo->rpmdbid[entry - repo->start];
1104           return notfound;
1105         }
1106     }
1107   FOR_REPODATAS(repo, i, data)
1108     {
1109       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1110         continue;
1111       if (!repodata_precheck_keyname(data, keyname))
1112         continue;
1113       if (repodata_lookup_num(data, entry, keyname, &value))
1114         return value;
1115       if (repodata_lookup_type(data, entry, keyname))
1116         return notfound;
1117     }
1118   return notfound;
1119 }
1120
1121 Id
1122 repo_lookup_id(Repo *repo, Id entry, Id keyname)
1123 {
1124   Repodata *data;
1125   int i;
1126   Id id;
1127
1128   if (entry >= 0)
1129     {
1130       switch (keyname)
1131         {
1132         case SOLVABLE_NAME:
1133           return repo->pool->solvables[entry].name;
1134         case SOLVABLE_ARCH:
1135           return repo->pool->solvables[entry].arch;
1136         case SOLVABLE_EVR:
1137           return repo->pool->solvables[entry].evr;
1138         case SOLVABLE_VENDOR:
1139           return repo->pool->solvables[entry].vendor;
1140         }
1141     }
1142   FOR_REPODATAS(repo, i, data)
1143     {
1144       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1145         continue;
1146       if (!repodata_precheck_keyname(data, keyname))
1147         continue;
1148       id = repodata_lookup_id(data, entry, keyname);
1149       if (id)
1150         return data->localpool ? repodata_globalize_id(data, id, 1) : id;
1151       if (repodata_lookup_type(data, entry, keyname))
1152         return 0;
1153     }
1154   return 0;
1155 }
1156
1157 static int
1158 lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
1159 {
1160   Id *p;
1161
1162   queue_empty(q);
1163   if (off)
1164     for (p = repo->idarraydata + off; *p; p++)
1165       queue_push(q, *p);
1166   return 1;
1167 }
1168
1169 int
1170 repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
1171 {
1172   Repodata *data;
1173   int i;
1174   if (entry >= 0)
1175     {
1176       switch (keyname)
1177         {
1178         case SOLVABLE_PROVIDES:
1179           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q);
1180         case SOLVABLE_OBSOLETES:
1181           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q);
1182         case SOLVABLE_CONFLICTS:
1183           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q);
1184         case SOLVABLE_REQUIRES:
1185           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q);
1186         case SOLVABLE_RECOMMENDS:
1187           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q);
1188         case SOLVABLE_SUGGESTS:
1189           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q);
1190         case SOLVABLE_SUPPLEMENTS:
1191           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q);
1192         case SOLVABLE_ENHANCES:
1193           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
1194         }
1195     }
1196   FOR_REPODATAS(repo, i, data)
1197     {
1198       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1199         continue;
1200       if (!repodata_precheck_keyname(data, keyname))
1201         continue;
1202       if (repodata_lookup_idarray(data, entry, keyname, q))
1203         {
1204           if (data->localpool)
1205             {
1206               for (i = 0; i < q->count; i++)
1207                 q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
1208             }
1209           return 1;
1210         }
1211       if (repodata_lookup_type(data, entry, keyname))
1212         break;
1213     }
1214   queue_empty(q);
1215   return 0;
1216 }
1217
1218 const unsigned char *
1219 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
1220 {
1221   Repodata *data;
1222   int i;
1223   const unsigned char *chk;
1224
1225   FOR_REPODATAS(repo, i, data)
1226     {
1227       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1228         continue;
1229       if (!repodata_precheck_keyname(data, keyname))
1230         continue;
1231       chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
1232       if (chk)
1233         return chk;
1234       if (repodata_lookup_type(data, entry, keyname))
1235         return 0;
1236     }
1237   *typep = 0;
1238   return 0;
1239 }
1240
1241 const char *
1242 repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
1243 {
1244   const unsigned char *chk = repo_lookup_bin_checksum(repo, entry, keyname, typep);
1245   return chk ? pool_bin2hex(repo->pool, chk, solv_chksum_len(*typep)) : 0;
1246 }
1247
1248 int
1249 repo_lookup_void(Repo *repo, Id entry, Id keyname)
1250 {
1251   Repodata *data;
1252   int i;
1253   Id type;
1254
1255   FOR_REPODATAS(repo, i, data)
1256     {
1257       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1258         continue;
1259       if (!repodata_precheck_keyname(data, keyname))
1260         continue;
1261       type = repodata_lookup_type(data, entry, keyname);
1262       if (type)
1263         return type == REPOKEY_TYPE_VOID;
1264     }
1265   return 0;
1266 }
1267
1268 Id
1269 repo_lookup_type(Repo *repo, Id entry, Id keyname)
1270 {
1271   Repodata *data;
1272   int i;
1273   Id type;
1274
1275   FOR_REPODATAS(repo, i, data)
1276     {
1277       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1278         continue;
1279       if (!repodata_precheck_keyname(data, keyname))
1280         continue;
1281       type = repodata_lookup_type(data, entry, keyname);
1282       if (type)
1283         return type == REPOKEY_TYPE_DELETED ? 0 : type;
1284     }
1285   return 0;
1286 }
1287
1288 /***********************************************************************/
1289
1290 Repodata *
1291 repo_add_repodata(Repo *repo, int flags)
1292 {
1293   int i;
1294   if ((flags & REPO_USE_LOADING) != 0)
1295     {
1296       for (i = repo->nrepodata - 1; i >= 0; i--)
1297         if (repo->repodata[i].state == REPODATA_LOADING)
1298           {
1299             Repodata *data = repo->repodata + i;
1300             /* re-init */
1301             /* hack: we mis-use REPO_REUSE_REPODATA here */
1302             if (!(flags & REPO_REUSE_REPODATA))
1303               repodata_empty(data, (flags & REPO_LOCALPOOL) ? 1 : 0);
1304             return data;
1305           }
1306       return 0; /* must not create a new repodata! */
1307     }
1308   if ((flags & REPO_REUSE_REPODATA) != 0)
1309     {
1310       for (i = repo->nrepodata - 1; i >= 0; i--)
1311         if (repo->repodata[i].state != REPODATA_STUB)
1312           return repo->repodata + i;
1313     }
1314   return repodata_create(repo, (flags & REPO_LOCALPOOL) ? 1 : 0);
1315 }
1316
1317 Repodata *
1318 repo_last_repodata(Repo *repo)
1319 {
1320   int i;
1321   for (i = repo->nrepodata - 1; i >= 0; i--)
1322     if (repo->repodata[i].state != REPODATA_STUB)
1323       return repo->repodata + i;
1324   return repo_add_repodata(repo, 0);
1325 }
1326
1327 void
1328 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
1329 {
1330   Repodata *data;
1331   if (p >= 0)
1332     {
1333       switch (keyname)
1334         {
1335         case SOLVABLE_NAME:
1336           repo->pool->solvables[p].name = id;
1337           return;
1338         case SOLVABLE_ARCH:
1339           repo->pool->solvables[p].arch = id;
1340           return;
1341         case SOLVABLE_EVR:
1342           repo->pool->solvables[p].evr = id;
1343           return;
1344         case SOLVABLE_VENDOR:
1345           repo->pool->solvables[p].vendor = id;
1346           return;
1347         }
1348     }
1349   data = repo_last_repodata(repo);
1350   if (data->localpool)
1351     id = repodata_localize_id(data, id, 1);
1352   repodata_set_id(data, p, keyname, id);
1353 }
1354
1355 void
1356 repo_set_num(Repo *repo, Id p, Id keyname, unsigned int num)
1357 {
1358   Repodata *data;
1359   if (p >= 0)
1360     {
1361       if (keyname == RPM_RPMDBID)
1362         {
1363           if (!repo->rpmdbid)
1364             repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1365           repo->rpmdbid[p] = num;
1366           return;
1367         }
1368     }
1369   data = repo_last_repodata(repo);
1370   repodata_set_num(data, p, keyname, num);
1371 }
1372
1373 void
1374 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
1375 {
1376   Repodata *data;
1377   if (p >= 0)
1378     {
1379       switch (keyname)
1380         {
1381         case SOLVABLE_NAME:
1382         case SOLVABLE_ARCH:
1383         case SOLVABLE_EVR:
1384         case SOLVABLE_VENDOR:
1385           repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
1386           return;
1387         }
1388     }
1389   data = repo_last_repodata(repo);
1390   repodata_set_str(data, p, keyname, str);
1391 }
1392
1393 void
1394 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
1395 {
1396   Repodata *data;
1397   if (p >= 0)
1398     {
1399       switch (keyname)
1400         {
1401         case SOLVABLE_NAME:
1402         case SOLVABLE_ARCH:
1403         case SOLVABLE_EVR:
1404         case SOLVABLE_VENDOR:
1405           repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
1406           return;
1407         }
1408     }
1409   data = repo_last_repodata(repo);
1410   repodata_set_poolstr(data, p, keyname, str);
1411 }
1412
1413 void
1414 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
1415 {
1416   Repodata *data = repo_last_repodata(repo);
1417   repodata_add_poolstr_array(data, p, keyname, str);
1418 }
1419
1420 void
1421 repo_internalize(Repo *repo)
1422 {
1423   int i;
1424   Repodata *data;
1425
1426   FOR_REPODATAS(repo, i, data)
1427     if (data->attrs || data->xattrs)
1428       repodata_internalize(data);
1429 }
1430
1431 void
1432 repo_disable_paging(Repo *repo)
1433 {
1434   int i;
1435   Repodata *data;
1436
1437   FOR_REPODATAS(repo, i, data)
1438     repodata_disable_paging(data);
1439 }
1440 // EOF
1441 /*
1442 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
1443 */