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