1761d42d51e8267e332511b5554f67331d73095c
[platform/upstream/libsolv.git] / src / pool.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  * pool.c
10  * 
11  * The pool contains information about solvables
12  * stored optimized for memory consumption and fast retrieval.
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <unistd.h>
19 #include <string.h>
20
21 #include "pool.h"
22 #include "repo.h"
23 #include "poolid.h"
24 #include "poolid_private.h"
25 #include "poolarch.h"
26 #include "util.h"
27 #include "bitmap.h"
28 #include "evr.h"
29
30 #define SOLVABLE_BLOCK  255
31
32 #define KNOWNID_INITIALIZE
33 #include "knownid.h"
34 #undef KNOWNID_INITIALIZE
35
36 /* create pool */
37 Pool *
38 pool_create(void)
39 {
40   Pool *pool;
41   Solvable *s;
42
43   pool = (Pool *)sat_calloc(1, sizeof(*pool));
44
45   stringpool_init (&pool->ss, initpool_data);
46
47   /* alloc space for RelDep 0 */
48   pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
49   pool->nrels = 1;
50   memset(pool->rels, 0, sizeof(Reldep));
51
52   /* alloc space for Solvable 0 and system solvable */
53   pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
54   pool->nsolvables = 2;
55   memset(pool->solvables, 0, 2 * sizeof(Solvable));
56   s = pool->solvables + SYSTEMSOLVABLE;
57   s->name = SYSTEM_SYSTEM;
58   s->arch = ARCH_NOARCH;
59   s->evr = ID_EMPTY;
60
61   queue_init(&pool->vendormap);
62
63   pool->debugmask = SAT_DEBUG_RESULT;   /* FIXME */
64   return pool;
65 }
66
67
68 /* free all the resources of our pool */
69 void
70 pool_free(Pool *pool)
71 {
72   int i;
73
74   pool_freewhatprovides(pool);
75   pool_freeidhashes(pool);
76   repo_freeallrepos(pool, 1);
77   sat_free(pool->id2arch);
78   sat_free(pool->solvables);
79   stringpool_free(&pool->ss);
80   sat_free(pool->rels);
81   queue_free(&pool->vendormap);
82   for (i = 0; i < POOL_TMPSPACEBUF; i++)
83     sat_free(pool->tmpspacebuf[i]);
84   for (i = 0; i < pool->nlanguages; i++)
85     free((char *)pool->languages[i]);
86   sat_free(pool->languages);
87   sat_free(pool->languagecache);
88   sat_free(pool);
89 }
90
91 Id
92 pool_add_solvable(Pool *pool)
93 {
94   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
95   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
96   return pool->nsolvables++;
97 }
98
99 Id
100 pool_add_solvable_block(Pool *pool, int count)
101 {
102   Id nsolvables = pool->nsolvables;
103   if (!count)
104     return nsolvables;
105   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
106   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
107   pool->nsolvables += count;
108   return nsolvables;
109 }
110
111 void
112 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
113 {
114   if (!count)
115     return;
116   if (reuseids && start + count == pool->nsolvables)
117     {
118       /* might want to shrink solvable array */
119       pool->nsolvables = start;
120       return;
121     }
122   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
123 }
124
125
126 static Pool *pool_shrink_whatprovides_sortcmp_data;
127
128 static int
129 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp)
130 {
131   int r;
132   Pool *pool = pool_shrink_whatprovides_sortcmp_data;
133   Id oa, ob, *da, *db;
134   oa = pool->whatprovides[*(Id *)ap];
135   ob = pool->whatprovides[*(Id *)bp];
136   if (oa == ob)
137     return *(Id *)ap - *(Id *)bp;
138   if (!oa)
139     return -1;
140   if (!ob)
141     return 1;
142   da = pool->whatprovidesdata + oa;
143   db = pool->whatprovidesdata + ob;
144   while (*db)
145     if ((r = (*da++ - *db++)) != 0)
146       return r;
147   if (*da)
148     return *da;
149   return *(Id *)ap - *(Id *)bp;
150 }
151
152 /*
153  * pool_shrink_whatprovides  - unify whatprovides data
154  *
155  * whatprovides_rel must be empty for this to work!
156  *
157  */
158 static void
159 pool_shrink_whatprovides(Pool *pool)
160 {
161   Id i, id;
162   Id *sorted;
163   Id lastid, *last, *dp, *lp;
164   Offset o;
165   int r;
166
167   if (pool->ss.nstrings < 3)
168     return;
169   sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
170   for (id = 0; id < pool->ss.nstrings; id++)
171     sorted[id] = id;
172   pool_shrink_whatprovides_sortcmp_data = pool;
173   qsort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp);
174   last = 0;
175   lastid = 0;
176   for (i = 1; i < pool->ss.nstrings; i++)
177     {
178       id = sorted[i];
179       o = pool->whatprovides[id];
180       if (o == 0 || o == 1)
181         continue;
182       dp = pool->whatprovidesdata + o;
183       if (last)
184         {
185           lp = last;
186           while (*dp)   
187             if (*dp++ != *lp++)
188               {
189                 last = 0;
190                 break;
191               }
192           if (last && *lp)
193             last = 0;
194           if (last)
195             {
196               pool->whatprovides[id] = -lastid;
197               continue;
198             }
199         }
200       last = pool->whatprovidesdata + o;
201       lastid = id;
202     }
203   sat_free(sorted);
204   dp = pool->whatprovidesdata + 2;
205   for (id = 1; id < pool->ss.nstrings; id++)
206     {
207       o = pool->whatprovides[id];
208       if (o == 0 || o == 1)
209         continue;
210       if ((Id)o < 0)
211         {
212           i = -(Id)o;
213           if (i >= id)
214             abort();
215           pool->whatprovides[id] = pool->whatprovides[i];
216           continue;
217         }
218       lp = pool->whatprovidesdata + o;
219       if (lp < dp)
220         abort();
221       pool->whatprovides[id] = dp - pool->whatprovidesdata;
222       while ((*dp++ = *lp++) != 0)
223         ;
224     }
225   o = dp - pool->whatprovidesdata;
226   POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
227   if (pool->whatprovidesdataoff == o)
228     return;
229   r = pool->whatprovidesdataoff - o;
230   pool->whatprovidesdataoff = o;
231   pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
232   if (r > pool->whatprovidesdataleft)
233     r = pool->whatprovidesdataleft;
234   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
235 }
236
237
238 /*
239  * pool_createwhatprovides()
240  * 
241  * create hashes over pool of solvables to ease provide lookups
242  * 
243  */
244 void
245 pool_createwhatprovides(Pool *pool)
246 {
247   int i, num, np, extra;
248   Offset off;
249   Solvable *s;
250   Id id;
251   Offset *idp, n;
252   Offset *whatprovides;
253   Id *whatprovidesdata, *d;
254
255   POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
256   POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
257
258   pool_freeidhashes(pool);      /* XXX: should not be here! */
259   pool_freewhatprovides(pool);
260   num = pool->ss.nstrings;
261   pool->whatprovides = whatprovides = sat_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
262   pool->whatprovides_rel = sat_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
263
264   /* count providers for each name */
265   for (i = 1; i < pool->nsolvables; i++)
266     {
267       Id *pp;
268       s = pool->solvables + i;
269       if (!s->provides)
270         continue;
271       if (!pool_installable(pool, s))
272         continue;
273       pp = s->repo->idarraydata + s->provides;
274       while ((id = *pp++) != ID_NULL)
275         {
276           while (ISRELDEP(id))
277             {
278               Reldep *rd = GETRELDEP(pool, id);
279               id = rd->name;
280             }
281           whatprovides[id]++;          /* inc count of providers */
282         }
283     }
284
285   off = 2;      /* first entry is undef, second is empty list */
286   idp = whatprovides;
287   np = 0;                              /* number of names provided */
288   for (i = 0; i < num; i++, idp++)
289     {
290       n = *idp;
291       if (!n)                          /* no providers */
292         continue;
293       *idp = off;                      /* move from counts to offsets into whatprovidesdata */
294       off += n + 1;                    /* make space for all providers + terminating ID_NULL */
295       np++;                            /* inc # of provider 'slots' */
296     }
297
298   POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
299
300   /* reserve some space for relation data */
301   extra = 2 * pool->nrels;
302   if (extra < 256)
303     extra = 256;
304
305   POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
306
307   /* alloc space for all providers + extra */
308   whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
309
310   /* now fill data for all provides */
311   for (i = 1; i < pool->nsolvables; i++)
312     {
313       Id *pp;
314       s = pool->solvables + i;
315       if (!s->provides)
316         continue;
317       if (!pool_installable(pool, s))
318         continue;
319
320       /* for all provides of this solvable */
321       pp = s->repo->idarraydata + s->provides;
322       while ((id = *pp++) != 0)
323         {
324           while (ISRELDEP(id))
325             {
326               Reldep *rd = GETRELDEP(pool, id);
327               id = rd->name;
328             }
329           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
330           if (*d)
331             {
332               d++;
333               while (*d)               /* find free slot */
334                 d++;
335               if (d[-1] == i)          /* solvable already tacked at end ? */
336                 continue;              /* Y: skip, on to next provides */
337             }
338           *d = i;                      /* put solvable Id into data */
339         }
340     }
341   pool->whatprovidesdata = whatprovidesdata;
342   pool->whatprovidesdataoff = off;
343   pool->whatprovidesdataleft = extra;
344   pool_shrink_whatprovides(pool);
345 }
346
347 /*
348  * free all of our whatprovides data
349  * be careful, everything internalized with pool_queuetowhatprovides is gone, too
350  */
351 void
352 pool_freewhatprovides(Pool *pool)
353 {
354   pool->whatprovides = sat_free(pool->whatprovides);
355   pool->whatprovides_rel = sat_free(pool->whatprovides_rel);
356   pool->whatprovidesdata = sat_free(pool->whatprovidesdata);
357   pool->whatprovidesdataoff = 0;
358   pool->whatprovidesdataleft = 0;
359 }
360
361
362 /******************************************************************************/
363
364 /*
365  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
366  * 
367  * on-demand filling of provider information
368  * move queue data into whatprovidesdata
369  * q: queue of Ids
370  * returns: Offset into whatprovides
371  *
372  */
373 Id
374 pool_queuetowhatprovides(Pool *pool, Queue *q)
375 {
376   Offset off;
377   int count = q->count;
378
379   if (count == 0)                      /* queue empty -> 1 */
380     return 1;
381
382   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
383   if (pool->whatprovidesdataleft < count + 1)
384     {
385       POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
386       pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
387       pool->whatprovidesdataleft = count + 4096;
388     }
389
390   /* copy queue to next free slot */
391   off = pool->whatprovidesdataoff;
392   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
393
394   /* adapt count and ID_NULL-terminate */
395   pool->whatprovidesdataoff += count;
396   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
397   pool->whatprovidesdataleft -= count + 1;
398
399   return (Id)off;
400 }
401
402
403 /*************************************************************************/
404
405 /* check if a package's nevr matches a dependency */
406
407 int
408 pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
409 {
410   Reldep *rd = GETRELDEP(pool, d);
411   Id name = rd->name;
412   Id evr = rd->evr;
413   int flags = rd->flags;
414
415   if (flags > 7)
416     {
417       switch (flags)
418         {
419         case REL_ARCH:
420           if (s->arch != evr)
421             return 0;
422           return pool_match_nevr(pool, s, name);
423         case REL_OR:
424           if (pool_match_nevr(pool, s, name))
425             return 1;
426           return pool_match_nevr(pool, s, evr);
427         case REL_AND:
428         case REL_WITH:
429           if (!pool_match_nevr(pool, s, name))
430             return 0;
431           return pool_match_nevr(pool, s, evr);
432         default:
433           return 0;
434         }
435     }
436   if (!pool_match_nevr(pool, s, name))
437     return 0;
438   if (evr == s->evr)
439     return flags & 2 ? 1 : 0;
440   if (!flags)
441     return 0;
442   if (flags == 7)
443     return 1;
444   if (flags != 2 && flags != 5)
445     flags ^= 5;
446   if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
447     return 1;
448   return 0;
449 }
450
451 /*
452  * addrelproviders
453  * 
454  * add packages fulfilling the relation to whatprovides array
455  * no exact providers, do range match
456  * 
457  */
458
459 Id *
460 pool_addrelproviders(Pool *pool, Id d)
461 {
462   Reldep *rd = GETRELDEP(pool, d);
463   Reldep *prd;
464   Queue plist;
465   Id buf[16];
466   Id name = rd->name;
467   Id evr = rd->evr;
468   int flags = rd->flags;
469   Id pid, *pidp;
470   Id p, *pp, *pp2, *pp3;
471
472   d = GETRELID(d);
473   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
474   switch (flags)
475     {
476     case REL_AND:
477     case REL_WITH:
478       pp = pool_whatprovides(pool, name);
479       pp2 = pool_whatprovides(pool, evr);
480       while ((p = *pp++) != 0)
481         {
482           for (pp3 = pp2; *pp3;)
483             if (*pp3++ == p)
484               {
485                 queue_push(&plist, p);
486                 break;
487               }
488         }
489       break;
490     case REL_OR:
491       pp = pool_whatprovides(pool, name);
492       while ((p = *pp++) != 0)
493         queue_push(&plist, p);
494       pp = pool_whatprovides(pool, evr);
495       while ((p = *pp++) != 0)
496         queue_pushunique(&plist, p);
497       break;
498     case REL_NAMESPACE:
499       if (pool->nscallback)
500         {
501           /* ask callback which packages provide the dependency
502            * 0:  none
503            * 1:  the system (aka SYSTEMSOLVABLE)
504            * >1: a set of packages, stored as offset on whatprovidesdata
505            */
506           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
507           if (p > 1)
508             {
509               queue_free(&plist);
510               pool->whatprovides_rel[d] = p;
511               return pool->whatprovidesdata + p;
512             }
513           if (p == 1)
514             queue_push(&plist, SYSTEMSOLVABLE);
515         }
516       break;
517     case REL_ARCH:
518       /* small hack: make it possible to match <pkg>.src
519        * we have to iterate over the solvables as src packages do not
520        * provide anything, thus they are not indexed in our
521        * whatprovides hash */
522       if (evr == ARCH_SRC)
523         {
524           Solvable *s;
525           for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
526             {
527               if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
528                 continue;
529               if (pool_match_nevr(pool, s, name))
530                 queue_push(&plist, p);
531             }
532           break;
533         }
534       pp = pp2 = pool_whatprovides(pool, name);
535       while ((p = *pp++) != 0)
536         {
537           Solvable *s = pool->solvables + p;
538           if (s->arch == evr)
539             queue_push(&plist, p);
540           else
541             pp2 = 0;
542         }
543       if (pp2)
544         return pp2;
545       break;
546     default:
547       break;
548     }
549
550   /* convert to whatprovides id */
551 #if 0
552   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
553 #endif
554   if (flags && flags < 8)
555     {
556       pp = pool_whatprovides(pool, name);
557       while (ISRELDEP(name))
558         {
559           rd = GETRELDEP(pool, name);
560           name = rd->name;
561         }
562       while ((p = *pp++) != 0)
563         {
564           Solvable *s = pool->solvables + p;
565 #if 0
566           POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name));
567 #endif
568           if (!s->provides)
569             {
570               /* no provides - check nevr */
571               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
572                 queue_push(&plist, p);
573               continue;
574             }
575           /* solvable p provides name in some rels */
576           pidp = s->repo->idarraydata + s->provides;
577           while ((pid = *pidp++) != 0)
578             {
579               int pflags;
580               Id pevr;
581
582               if (pid == name)
583                 {
584 #ifdef DEBIAN_SEMANTICS
585                   continue;             /* unversioned provides can
586                                          * never match versioned deps */
587 #else
588                   break;                /* yes, provides all versions */
589 #endif
590                 }
591               if (!ISRELDEP(pid))
592                 continue;               /* wrong provides name */
593               prd = GETRELDEP(pool, pid);
594               if (prd->name != name)
595                 continue;               /* wrong provides name */
596               /* right package, both deps are rels */
597               pflags = prd->flags;
598               if (!pflags)
599                 continue;
600               if (flags == 7 || pflags == 7)
601                 break; /* included */
602               if ((pflags & flags & 5) != 0)
603                 break; /* same direction, match */
604               pevr = prd->evr;
605               if (pevr == evr)
606                 {
607                   if ((pflags & flags & 2) != 0)
608                     break; /* both have =, match */
609                 }
610               else
611                 {
612                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
613                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
614                     break;
615                 }
616             }
617           if (!pid)
618             continue;   /* no rel match */
619           queue_push(&plist, p);
620         }
621       /* make our system solvable provide all unknown rpmlib() stuff */
622       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
623         queue_push(&plist, SYSTEMSOLVABLE);
624     }
625   /* add providers to whatprovides */
626 #if 0
627   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
628 #endif
629   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
630   queue_free(&plist);
631
632   return pool->whatprovidesdata + pool->whatprovides_rel[d];
633 }
634
635 /*************************************************************************/
636
637 void
638 pool_debug(Pool *pool, int type, const char *format, ...)
639 {
640   va_list args;
641   char buf[1024];
642
643   if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
644     {
645       if ((pool->debugmask & type) == 0)
646         return;
647     }
648   va_start(args, format);
649   if (!pool->debugcallback)
650     {
651       if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
652         vprintf(format, args);
653       else
654         vfprintf(stderr, format, args);
655       return;
656     }
657   vsnprintf(buf, sizeof(buf), format, args);
658   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
659 }
660
661 void
662 pool_setdebuglevel(Pool *pool, int level)
663 {
664   int mask = SAT_DEBUG_RESULT;
665   if (level > 0)
666     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE;
667   if (level > 1)
668     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
669   if (level > 2)
670     mask |= SAT_DEBUG_PROPAGATE;
671   if (level > 3)
672     mask |= SAT_DEBUG_RULE_CREATION;
673   if (level > 4)
674     mask |= SAT_DEBUG_SCHUBI;
675   pool->debugmask = mask;
676 }
677
678 /*************************************************************************/
679
680 struct searchfiles {
681   Id *ids;
682   char **dirs;
683   char **names;
684   int nfiles;
685   Map seen;
686 };
687
688 #define SEARCHFILES_BLOCK 127
689
690 static void
691 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
692 {
693   Id dep, sid;
694   const char *s, *sr;
695   struct searchfiles *csf;
696
697   while ((dep = *ida++) != 0)
698     {
699       csf = sf;
700       while (ISRELDEP(dep))
701         {
702           Reldep *rd;
703           sid = pool->ss.nstrings + GETRELID(dep);
704           if (MAPTST(&csf->seen, sid))
705             {
706               dep = 0;
707               break;
708             }
709           MAPSET(&csf->seen, sid);
710           rd = GETRELDEP(pool, dep);
711           if (rd->flags < 8)
712             dep = rd->name;
713           else if (rd->flags == REL_NAMESPACE)
714             {
715               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
716                 {
717                   csf = isf;
718                   if (!csf || MAPTST(&csf->seen, sid))
719                     {
720                       dep = 0;
721                       break;
722                     }
723                   MAPSET(&csf->seen, sid);
724                 }
725               dep = rd->evr;
726             }
727           else
728             {
729               Id ids[2];
730               ids[0] = rd->name;
731               ids[1] = 0;
732               pool_addfileprovides_dep(pool, ids, csf, isf);
733               dep = rd->evr;
734             }
735         }
736       if (!dep)
737         continue;
738       if (MAPTST(&csf->seen, dep))
739         continue;
740       MAPSET(&csf->seen, dep);
741       s = id2str(pool, dep);
742       if (*s != '/')
743         continue;
744       csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
745       csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
746       csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
747       csf->ids[csf->nfiles] = dep;
748       sr = strrchr(s, '/');
749       csf->names[csf->nfiles] = strdup(sr + 1);
750       csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1);
751       if (sr != s)
752         strncpy(csf->dirs[csf->nfiles], s, sr - s);
753       csf->dirs[csf->nfiles][sr - s] = 0;
754       csf->nfiles++;
755     }
756 }
757
758 struct addfileprovides_cbdata {
759   int nfiles;
760   Id *ids;
761   char **dirs;
762   char **names;
763
764   Repodata *olddata;
765   Id *dids;
766   Map useddirs;
767 };
768
769 static int
770 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
771 {
772   struct addfileprovides_cbdata *cbd = cbdata;
773   int i;
774
775   if (data != cbd->olddata)
776     {
777       map_free(&cbd->useddirs);
778       map_init(&cbd->useddirs, data->dirpool.ndirs);
779       for (i = 0; i < cbd->nfiles; i++)
780         {
781           Id did = repodata_str2dir(data, cbd->dirs[i], 0);
782           cbd->dids[i] = did;
783           if (did)
784             MAPSET(&cbd->useddirs, did);
785         }
786       cbd->olddata = data;
787     }
788   if (!MAPTST(&cbd->useddirs, value->id))
789     return 0;
790   for (i = 0; i < cbd->nfiles; i++)
791     {
792       if (cbd->dids[i] != value->id)
793         continue;
794       if (!strcmp(cbd->names[i], value->str))
795         break;
796     }
797   if (i == cbd->nfiles)
798     return 0;
799   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
800   return 0;
801 }
802
803
804 static void
805 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
806 {
807   Id p, start, end, *idp;
808   Solvable *s;
809   Repodata *data = 0, *nextdata;
810   Repo *oldrepo = 0;
811   int dataincludes = 0;
812   int i;
813   Map providedids;
814
815   cbd->nfiles = sf->nfiles;
816   cbd->ids = sf->ids;
817   cbd->dirs = sf->dirs;
818   cbd->names = sf->names;
819   cbd->olddata = 0;
820   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
821   if (repoonly)
822     {
823       start = repoonly->start;
824       end = repoonly->end;
825     }
826   else
827     {
828       start = 2;        /* skip system solvable */
829       end = pool->nsolvables;
830     }
831   for (p = start, s = pool->solvables + p; p < end; p++, s++)
832     {
833       if (!s->repo || (repoonly && s->repo != repoonly))
834         continue;
835       if (s->repo != oldrepo || (data && p >= data->end))
836         {
837           data = 0;
838           oldrepo = 0;
839         }
840       if (oldrepo == 0)
841         {
842           nextdata = 0;
843           for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++)
844             {
845               if (!data->addedfileprovides || p >= data->end)
846                 continue;
847               if (!nextdata || nextdata->start > data->start)
848                 nextdata = data;
849               if (p >= data->start)
850                 break;
851             }
852           if (i == s->repo->nrepodata)
853             data = nextdata;
854           if (data)
855             {
856               map_init(&providedids, pool->ss.nstrings);
857               for (idp = data->addedfileprovides; *idp; idp++)
858                 MAPSET(&providedids, *idp);
859               for (i = 0; i < cbd->nfiles; i++)
860                 if (!MAPTST(&providedids, cbd->ids[i]))
861                   {
862                     break;
863                   }
864               map_free(&providedids);
865               dataincludes = i == cbd->nfiles;
866             }
867           oldrepo = s->repo;
868         }
869       if (data && p >= data->start && dataincludes)
870         continue;
871       repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd);
872     }
873 }
874
875 void
876 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
877 {
878   Solvable *s;
879   Repo *repo;
880   struct searchfiles sf, isf, *isfp;
881   struct addfileprovides_cbdata cbd;
882   int i;
883
884   memset(&sf, 0, sizeof(sf));
885   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
886   memset(&isf, 0, sizeof(isf));
887   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
888
889   isfp = installed ? &isf : 0;
890   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
891     {
892       repo = s->repo;
893       if (!repo)
894         continue;
895       if (s->obsoletes)
896         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
897       if (s->conflicts)
898         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
899       if (s->requires)
900         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
901       if (s->recommends)
902         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
903       if (s->suggests)
904         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
905       if (s->supplements)
906         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
907       if (s->enhances)
908         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
909     }
910   map_free(&sf.seen);
911   map_free(&isf.seen);
912   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
913   POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
914   cbd.dids = 0;
915   map_init(&cbd.useddirs, 1);
916   if (idp)
917     *idp = 0;
918   if (sf.nfiles)
919     {
920 #if 0
921       for (i = 0; i < sf.nfiles; i++)
922         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
923 #endif
924       pool_addfileprovides_search(pool, &cbd, &sf, 0);
925       if (idp)
926         {
927           sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
928           sf.ids[sf.nfiles] = 0;
929           *idp = sf.ids;
930           sf.ids = 0;
931         }
932       sat_free(sf.ids);
933       for (i = 0; i < sf.nfiles; i++)
934         {
935           sat_free(sf.dirs[i]);
936           sat_free(sf.names[i]);
937         }
938       sat_free(sf.dirs);
939       sat_free(sf.names);
940     }
941   if (isf.nfiles)
942     {
943 #if 0
944       for (i = 0; i < isf.nfiles; i++)
945         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
946 #endif
947       if (installed)
948         pool_addfileprovides_search(pool, &cbd, &isf, installed);
949       sat_free(isf.ids);
950       for (i = 0; i < isf.nfiles; i++)
951         {
952           sat_free(isf.dirs[i]);
953           sat_free(isf.names[i]);
954         }
955       sat_free(isf.dirs);
956       sat_free(isf.names);
957     }
958   map_free(&cbd.useddirs);
959   sat_free(cbd.dids);
960   pool_freewhatprovides(pool);  /* as we have added provides */
961 }
962
963 void
964 pool_addfileprovides(Pool *pool, Repo *installed)
965 {
966   pool_addfileprovides_ids(pool, installed, 0);
967 }
968
969 void
970 pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata)
971 {
972   if (p)
973     {
974       if (pool->solvables[p].repo)
975         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
976       return;
977     }
978   /* FIXME: obey callback return value! */
979   for (p = 1; p < pool->nsolvables; p++)
980     if (pool->solvables[p].repo)
981       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
982 }
983
984
985 void
986 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
987 {
988   int i;
989
990   pool->languagecache = sat_free(pool->languagecache);
991   pool->languagecacheother = 0;
992   if (pool->nlanguages)
993     {
994       for (i = 0; i < pool->nlanguages; i++)
995         free((char *)pool->languages[i]);
996       free(pool->languages);
997     }
998   pool->nlanguages = nlanguages;
999   if (!nlanguages)
1000     return;
1001   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
1002   for (i = 0; i < pool->nlanguages; i++)
1003     pool->languages[i] = strdup(languages[i]);
1004 }
1005
1006 Id
1007 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1008 {
1009   const char *n;
1010   char buf[256], *p;
1011   int l;
1012
1013   if (!lang)
1014     return id;
1015   n = id2str(pool, id);
1016   l = strlen(n) + strlen(lang) + 2;
1017   if (l > sizeof(buf))
1018     p = sat_malloc(strlen(n) + strlen(lang) + 2);
1019   else
1020     p = buf;
1021   sprintf(p, "%s:%s", n, lang);
1022   id = str2id(pool, p, create);
1023   if (p != buf)
1024     free(p);
1025   return id;
1026 }
1027
1028 char *
1029 pool_alloctmpspace(Pool *pool, int len)
1030 {
1031   int n = pool->tmpspacen;
1032   if (!len)
1033     return 0;
1034   if (len > pool->tmpspacelen[n])
1035     {
1036       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
1037       pool->tmpspacelen[n] = len + 32;
1038     }
1039   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
1040   return pool->tmpspacebuf[n];
1041 }
1042
1043 /*******************************************************************/
1044
1045 struct mptree {
1046   Id sibling;
1047   Id child;
1048   const char *comp;
1049   int compl;
1050   Id mountpoint;
1051 };
1052
1053 struct ducbdata {
1054   DUChanges *mps;
1055   struct mptree *mptree;
1056   int addsub;
1057   int hasdu;
1058
1059   Id *dirmap;
1060   int nmap;
1061   Repodata *olddata;
1062 };
1063
1064
1065 static int
1066 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1067 {
1068   struct ducbdata *cbd = cbdata;
1069   Id mp;
1070
1071   if (data != cbd->olddata)
1072     {
1073       Id dn, mp, comp, *dirmap, *dirs;
1074       int i, compl;
1075       const char *compstr;
1076       struct mptree *mptree;
1077
1078       /* create map from dir to mptree */
1079       cbd->dirmap = sat_free(cbd->dirmap);
1080       cbd->nmap = 0;
1081       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
1082       mptree = cbd->mptree;
1083       mp = 0;
1084       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1085         {
1086           comp = *dirs++;
1087           if (comp <= 0)
1088             {
1089               mp = dirmap[-comp];
1090               continue;
1091             }
1092           if (mp < 0)
1093             {
1094               /* unconnected */
1095               dirmap[dn] = mp;
1096               continue;
1097             }
1098           if (!mptree[mp].child)
1099             {
1100               dirmap[dn] = -mp;
1101               continue;
1102             }
1103           if (data->localpool)
1104             compstr = stringpool_id2str(&data->spool, comp);
1105           else
1106             compstr = id2str(data->repo->pool, comp);
1107           compl = strlen(compstr);
1108           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1109             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1110               break;
1111           dirmap[dn] = i ? i : -mp;
1112         }
1113       /* change dirmap to point to mountpoint instead of mptree */
1114       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1115         {
1116           mp = dirmap[dn];
1117           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1118         }
1119       cbd->dirmap = dirmap;
1120       cbd->nmap = data->dirpool.ndirs;
1121       cbd->olddata = data;
1122     }
1123   cbd->hasdu = 1;
1124   if (value->id < 0 || value->id >= cbd->nmap)
1125     return 0;
1126   mp = cbd->dirmap[value->id];
1127   if (mp < 0)
1128     return 0;
1129   if (cbd->addsub > 0)
1130     {
1131       cbd->mps[mp].kbytes += value->num;
1132       cbd->mps[mp].files += value->num2;
1133     }
1134   else
1135     {
1136       cbd->mps[mp].kbytes -= value->num;
1137       cbd->mps[mp].files -= value->num2;
1138     }
1139   return 0;
1140 }
1141
1142 static void
1143 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1144 {
1145   int i;
1146   if (mptree[pos].mountpoint == -1)
1147     mptree[pos].mountpoint = mountpoint;
1148   else
1149     mountpoint = mptree[pos].mountpoint;
1150   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1151     propagate_mountpoints(mptree, i, mountpoint);
1152 }
1153
1154 #define MPTREE_BLOCK 15
1155
1156 void
1157 pool_calc_duchanges(Pool *pool, Repo *oldinstalled, Map *installedmap, DUChanges *mps, int nmps)
1158 {
1159   char *p;
1160   const char *path, *compstr;
1161   struct mptree *mptree;
1162   int i, nmptree;
1163   int pos, compl;
1164   int mp;
1165   struct ducbdata cbd;
1166   Solvable *s;
1167   Id sp;
1168   Map ignoredu;
1169
1170   memset(&ignoredu, 0, sizeof(ignoredu));
1171   cbd.mps = mps;
1172   cbd.addsub = 0;
1173   cbd.dirmap = 0;
1174   cbd.nmap = 0;
1175   cbd.olddata = 0;
1176
1177   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1178
1179   /* our root node */
1180   mptree[0].sibling = 0;
1181   mptree[0].child = 0;
1182   mptree[0].comp = 0;
1183   mptree[0].compl = 0;
1184   mptree[0].mountpoint = -1;
1185   nmptree = 1;
1186   
1187   /* create component tree */
1188   for (mp = 0; mp < nmps; mp++)
1189     {
1190       mps[mp].kbytes = 0;
1191       mps[mp].files = 0;
1192       pos = 0;
1193       path = mps[mp].path;
1194       while(*path == '/')
1195         path++;
1196       while (*path)
1197         {
1198           if ((p = strchr(path, '/')) == 0)
1199             {
1200               compstr = path;
1201               compl = strlen(compstr);
1202               path += compl;
1203             }
1204           else
1205             {
1206               compstr = path;
1207               compl = p - path;
1208               path = p + 1;
1209               while(*path == '/')
1210                 path++;
1211             }
1212           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1213             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1214               break;
1215           if (!i)
1216             {
1217               /* create new node */
1218               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1219               i = nmptree++;
1220               mptree[i].sibling = mptree[pos].child;
1221               mptree[i].child = 0;
1222               mptree[i].comp = compstr;
1223               mptree[i].compl = compl;
1224               mptree[i].mountpoint = -1;
1225               mptree[pos].child = i;
1226             }
1227           pos = i;
1228         }
1229       mptree[pos].mountpoint = mp;
1230     }
1231
1232   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1233
1234 #if 0
1235   for (i = 0; i < nmptree; i++)
1236     {
1237       printf("#%d sibling: %d\n", i, mptree[i].sibling);
1238       printf("#%d child: %d\n", i, mptree[i].child);
1239       printf("#%d comp: %s\n", i, mptree[i].comp);
1240       printf("#%d compl: %d\n", i, mptree[i].compl);
1241       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1242     }
1243 #endif
1244
1245   cbd.mptree = mptree;
1246   cbd.addsub = 1;
1247   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1248     {
1249       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1250         continue;
1251       if (!MAPTST(installedmap, sp))
1252         continue;
1253       cbd.hasdu = 0;
1254       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1255       if (!cbd.hasdu && oldinstalled)
1256         {
1257           Id op, *opp;
1258           /* no du data available, ignore data of all installed solvables we obsolete */
1259           if (!ignoredu.map)
1260             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1261           if (s->obsoletes)
1262             {
1263               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1264               while ((obs = *obsp++) != 0)
1265                 FOR_PROVIDES(op, opp, obs)
1266                   if (op >= oldinstalled->start && op < oldinstalled->end)
1267                     MAPSET(&ignoredu, op - oldinstalled->start);
1268             }
1269           FOR_PROVIDES(op, opp, s->name)
1270             if (pool->solvables[op].name == s->name)
1271               if (op >= oldinstalled->start && op < oldinstalled->end)
1272                 MAPSET(&ignoredu, op - oldinstalled->start);
1273         }
1274     }
1275   cbd.addsub = -1;
1276   if (oldinstalled)
1277     {
1278       /* assumes we allways have du data for installed solvables */
1279       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1280         {
1281           if (MAPTST(installedmap, sp))
1282             continue;
1283           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1284             continue;
1285           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1286         }
1287     }
1288   if (ignoredu.map)
1289     map_free(&ignoredu);
1290   sat_free(cbd.dirmap);
1291   sat_free(mptree);
1292 }
1293
1294 int
1295 pool_calc_installsizechange(Pool *pool, Repo *oldinstalled, Map *installedmap)
1296 {
1297   Id sp;
1298   Solvable *s;
1299   int change = 0;
1300
1301   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1302     {
1303       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1304         continue;
1305       if (!MAPTST(installedmap, sp))
1306         continue;
1307       change += repo_lookup_num(s, SOLVABLE_INSTALLSIZE);
1308     }
1309   if (oldinstalled)
1310     {
1311       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1312         {
1313           if (MAPTST(installedmap, sp))
1314             continue;
1315           change -= repo_lookup_num(s, SOLVABLE_INSTALLSIZE);
1316         }
1317     }
1318   return change;
1319 }
1320
1321 /* map:
1322  *  1: installed
1323  *  2: conflicts with installed
1324  *  8: interesting (only true if installed)
1325  * 16: undecided
1326  */
1327  
1328 static inline Id dep2name(Pool *pool, Id dep)
1329 {
1330   while (ISRELDEP(dep))
1331     {
1332       Reldep *rd = rd = GETRELDEP(pool, dep);
1333       dep = rd->name;
1334     }
1335   return dep;
1336 }
1337
1338 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep)
1339 {
1340   Id p, *pp;
1341   int r = 0;
1342   FOR_PROVIDES(p, pp, dep)
1343     {
1344       if (p == SYSTEMSOLVABLE)
1345         return 1;       /* always boring, as never constraining */
1346       if ((map[p] & 9) == 9)
1347         return 9;
1348       r |= map[p] & 17;
1349     }
1350   return r;
1351 }
1352
1353 /*
1354  * pool_trivial_installable - calculate if a set of solvables is
1355  * trivial installable without any other installs/deinstalls of
1356  * packages not belonging to the set.
1357  *
1358  * the state is returned in the result queue:
1359  * 1:  solvable is installable without any other package changes
1360  * 0:  solvable is not installable
1361  * -1: solvable is installable, but doesn't constrain any installed packages
1362  */
1363
1364 void
1365 pool_trivial_installable(Pool *pool, Repo *oldinstalled, Map *installedmap, Queue *pkgs, Queue *res)
1366 {
1367   int i, r, m, did;
1368   Id p, *dp, con, *conp, req, *reqp;
1369   unsigned char *map;
1370   Solvable *s;
1371
1372   map = sat_calloc(pool->nsolvables, 1);
1373   for (p = 1; p < pool->nsolvables; p++)
1374     {
1375       if (!MAPTST(installedmap, p))
1376         continue;
1377       map[p] |= 9;
1378       s = pool->solvables + p;
1379       if (!s->conflicts)
1380         continue;
1381       conp = s->repo->idarraydata + s->conflicts;
1382       while ((con = *conp++) != 0)
1383         {
1384           dp = pool_whatprovides(pool, con);
1385           for (; *dp; dp++)
1386             map[p] |= 2;        /* XXX: self conflict ? */
1387         }
1388     }
1389   for (i = 0; i < pkgs->count; i++)
1390     map[pkgs->elements[i]] = 16;
1391
1392   for (i = 0, did = 0; did < pkgs->count; i++, did++)
1393     {
1394       if (i == pkgs->count)
1395         i = 0;
1396       p = pkgs->elements[i];
1397       if ((map[p] & 16) == 0)
1398         continue;
1399       if ((map[p] & 2) != 0)
1400         {
1401           map[p] = 2;
1402           continue;
1403         }
1404       s = pool->solvables + p;
1405       m = 1;
1406       if (s->requires)
1407         {
1408           reqp = s->repo->idarraydata + s->requires;
1409           while ((req = *reqp++) != 0)
1410             {
1411               if (req == SOLVABLE_PREREQMARKER)
1412                 continue;
1413               r = providedbyinstalled(pool, map, req);
1414               if (!r)
1415                 {
1416                   /* decided and miss */
1417                   map[p] = 2;
1418                   break;
1419                 }
1420               m |= r;   /* 1 | 9 | 16 | 17 */
1421             }
1422           if (req)
1423             continue;
1424           if ((m & 9) == 9)
1425             m = 9;
1426         }
1427       if (s->conflicts)
1428         {
1429           conp = s->repo->idarraydata + s->conflicts;
1430           while ((con = *conp++) != 0)
1431             {
1432               if ((providedbyinstalled(pool, map, con) & 1) != 0)
1433                 {
1434                   map[p] = 2;
1435                   break;
1436                 }
1437               if ((m == 1 || m == 17) && ISRELDEP(con))
1438                 {
1439                   con = dep2name(pool, con);
1440                   if ((providedbyinstalled(pool, map, con) & 1) != 0)
1441                     m = 9;
1442                 }
1443             }
1444           if (con)
1445             continue;   /* found a conflict */
1446         }
1447 #if 0
1448       if (s->repo && s->repo != oldinstalled)
1449         {
1450           Id p2, obs, *obsp, *pp;
1451           Solvable *s2;
1452           if (s->obsoletes)
1453             {
1454               obsp = s->repo->idarraydata + s->obsoletes;
1455               while ((obs = *obsp++) != 0)
1456                 {
1457                   if ((providedbyinstalled(pool, map, obs) & 1) != 0)
1458                     {
1459                       map[p] = 2;
1460                       break;
1461                     }
1462                 }
1463               if (obs)
1464                 continue;
1465             }
1466           FOR_PROVIDES(p2, pp, s->name)
1467             {
1468               s2 = pool->solvables + p2;
1469               if (s2->name == s->name && (map[p2] & 1) != 0)
1470                 {
1471                   map[p] = 2;
1472                   break;
1473                 }
1474             }
1475           if (p2)
1476             continue;
1477         }
1478 #endif
1479       if (m != map[p])
1480         {
1481           map[p] = m;
1482           did = 0;
1483         }
1484     }
1485   queue_free(res);
1486   queue_clone(res, pkgs);
1487   for (i = 0; i < pkgs->count; i++)
1488     {
1489       m = map[pkgs->elements[i]];
1490       if ((m & 9) == 9)
1491         r = 1;
1492       else if (m & 1)
1493         r = -1;
1494       else
1495         r = 0;
1496       res->elements[i] = r;
1497     }
1498   free(map);
1499 }
1500
1501 // EOF