- Change provide iterator from ID pointer to ID. Before, iterating
[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, wp, *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->whatprovidesdata + pool_whatprovides(pool, name);
479       pp2 = pool->whatprovidesdata + 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->whatprovidesdata + pool_whatprovides(pool, name);
492       while ((p = *pp++) != 0)
493         queue_push(&plist, p);
494       pp = pool->whatprovidesdata + pool_whatprovides(pool, evr);
495       while ((p = *pp++) != 0)
496         queue_pushunique(&plist, p);
497       break;
498     case REL_NAMESPACE:
499       if (name == NAMESPACE_OTHERPROVIDERS)
500         {
501           wp = pool_whatprovides(pool, evr);
502           pool->whatprovides_rel[d] = wp;
503           return wp;
504         }
505       if (pool->nscallback)
506         {
507           /* ask callback which packages provide the dependency
508            * 0:  none
509            * 1:  the system (aka SYSTEMSOLVABLE)
510            * >1: a set of packages, stored as offset on whatprovidesdata
511            */
512           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
513           if (p > 1)
514             {
515               queue_free(&plist);
516               pool->whatprovides_rel[d] = p;
517               return p;
518             }
519           if (p == 1)
520             queue_push(&plist, SYSTEMSOLVABLE);
521         }
522       break;
523     case REL_ARCH:
524       /* small hack: make it possible to match <pkg>.src
525        * we have to iterate over the solvables as src packages do not
526        * provide anything, thus they are not indexed in our
527        * whatprovides hash */
528       if (evr == ARCH_SRC)
529         {
530           Solvable *s;
531           for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
532             {
533               if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
534                 continue;
535               if (pool_match_nevr(pool, s, name))
536                 queue_push(&plist, p);
537             }
538           break;
539         }
540       wp = pool_whatprovides(pool, name);
541       pp = pool->whatprovidesdata + wp;
542       while ((p = *pp++) != 0)
543         {
544           Solvable *s = pool->solvables + p;
545           if (s->arch == evr)
546             queue_push(&plist, p);
547           else
548             wp = 0;
549         }
550       if (wp)
551         {
552           pool->whatprovides_rel[d] = wp;
553           return wp;
554         }
555       break;
556     default:
557       break;
558     }
559
560   /* convert to whatprovides id */
561 #if 0
562   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
563 #endif
564   if (flags && flags < 8)
565     {
566       pp = pool->whatprovidesdata + pool_whatprovides(pool, name);
567       while (ISRELDEP(name))
568         {
569           rd = GETRELDEP(pool, name);
570           name = rd->name;
571         }
572       while ((p = *pp++) != 0)
573         {
574           Solvable *s = pool->solvables + p;
575 #if 0
576           POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name));
577 #endif
578           if (!s->provides)
579             {
580               /* no provides - check nevr */
581               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
582                 queue_push(&plist, p);
583               continue;
584             }
585           /* solvable p provides name in some rels */
586           pidp = s->repo->idarraydata + s->provides;
587           while ((pid = *pidp++) != 0)
588             {
589               int pflags;
590               Id pevr;
591
592               if (pid == name)
593                 {
594 #ifdef DEBIAN_SEMANTICS
595                   continue;             /* unversioned provides can
596                                          * never match versioned deps */
597 #else
598                   break;                /* yes, provides all versions */
599 #endif
600                 }
601               if (!ISRELDEP(pid))
602                 continue;               /* wrong provides name */
603               prd = GETRELDEP(pool, pid);
604               if (prd->name != name)
605                 continue;               /* wrong provides name */
606               /* right package, both deps are rels */
607               pflags = prd->flags;
608               if (!pflags)
609                 continue;
610               if (flags == 7 || pflags == 7)
611                 break; /* included */
612               if ((pflags & flags & 5) != 0)
613                 break; /* same direction, match */
614               pevr = prd->evr;
615               if (pevr == evr)
616                 {
617                   if ((pflags & flags & 2) != 0)
618                     break; /* both have =, match */
619                 }
620               else
621                 {
622                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
623                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
624                     break;
625                 }
626             }
627           if (!pid)
628             continue;   /* no rel match */
629           queue_push(&plist, p);
630         }
631       /* make our system solvable provide all unknown rpmlib() stuff */
632       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
633         queue_push(&plist, SYSTEMSOLVABLE);
634     }
635   /* add providers to whatprovides */
636 #if 0
637   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
638 #endif
639   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
640   queue_free(&plist);
641
642   return pool->whatprovides_rel[d];
643 }
644
645 /*************************************************************************/
646
647 void
648 pool_debug(Pool *pool, int type, const char *format, ...)
649 {
650   va_list args;
651   char buf[1024];
652
653   if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
654     {
655       if ((pool->debugmask & type) == 0)
656         return;
657     }
658   va_start(args, format);
659   if (!pool->debugcallback)
660     {
661       if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
662         vprintf(format, args);
663       else
664         vfprintf(stderr, format, args);
665       return;
666     }
667   vsnprintf(buf, sizeof(buf), format, args);
668   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
669 }
670
671 void
672 pool_setdebuglevel(Pool *pool, int level)
673 {
674   int mask = SAT_DEBUG_RESULT;
675   if (level > 0)
676     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE;
677   if (level > 1)
678     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
679   if (level > 2)
680     mask |= SAT_DEBUG_PROPAGATE;
681   if (level > 3)
682     mask |= SAT_DEBUG_RULE_CREATION;
683   if (level > 4)
684     mask |= SAT_DEBUG_SCHUBI;
685   pool->debugmask = mask;
686 }
687
688 /*************************************************************************/
689
690 struct searchfiles {
691   Id *ids;
692   char **dirs;
693   char **names;
694   int nfiles;
695   Map seen;
696 };
697
698 #define SEARCHFILES_BLOCK 127
699
700 static void
701 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
702 {
703   Id dep, sid;
704   const char *s, *sr;
705   struct searchfiles *csf;
706
707   while ((dep = *ida++) != 0)
708     {
709       csf = sf;
710       while (ISRELDEP(dep))
711         {
712           Reldep *rd;
713           sid = pool->ss.nstrings + GETRELID(dep);
714           if (MAPTST(&csf->seen, sid))
715             {
716               dep = 0;
717               break;
718             }
719           MAPSET(&csf->seen, sid);
720           rd = GETRELDEP(pool, dep);
721           if (rd->flags < 8)
722             dep = rd->name;
723           else if (rd->flags == REL_NAMESPACE)
724             {
725               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
726                 {
727                   csf = isf;
728                   if (!csf || MAPTST(&csf->seen, sid))
729                     {
730                       dep = 0;
731                       break;
732                     }
733                   MAPSET(&csf->seen, sid);
734                 }
735               dep = rd->evr;
736             }
737           else
738             {
739               Id ids[2];
740               ids[0] = rd->name;
741               ids[1] = 0;
742               pool_addfileprovides_dep(pool, ids, csf, isf);
743               dep = rd->evr;
744             }
745         }
746       if (!dep)
747         continue;
748       if (MAPTST(&csf->seen, dep))
749         continue;
750       MAPSET(&csf->seen, dep);
751       s = id2str(pool, dep);
752       if (*s != '/')
753         continue;
754       csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
755       csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
756       csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
757       csf->ids[csf->nfiles] = dep;
758       sr = strrchr(s, '/');
759       csf->names[csf->nfiles] = strdup(sr + 1);
760       csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1);
761       if (sr != s)
762         strncpy(csf->dirs[csf->nfiles], s, sr - s);
763       csf->dirs[csf->nfiles][sr - s] = 0;
764       csf->nfiles++;
765     }
766 }
767
768 struct addfileprovides_cbdata {
769   int nfiles;
770   Id *ids;
771   char **dirs;
772   char **names;
773
774   Repodata *olddata;
775   Id *dids;
776   Map useddirs;
777 };
778
779 static int
780 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
781 {
782   struct addfileprovides_cbdata *cbd = cbdata;
783   int i;
784
785   if (data != cbd->olddata)
786     {
787       map_free(&cbd->useddirs);
788       map_init(&cbd->useddirs, data->dirpool.ndirs);
789       for (i = 0; i < cbd->nfiles; i++)
790         {
791           Id did = repodata_str2dir(data, cbd->dirs[i], 0);
792           cbd->dids[i] = did;
793           if (did)
794             MAPSET(&cbd->useddirs, did);
795         }
796       cbd->olddata = data;
797     }
798   if (!MAPTST(&cbd->useddirs, value->id))
799     return 0;
800   for (i = 0; i < cbd->nfiles; i++)
801     {
802       if (cbd->dids[i] != value->id)
803         continue;
804       if (!strcmp(cbd->names[i], value->str))
805         break;
806     }
807   if (i == cbd->nfiles)
808     return 0;
809   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
810   return 0;
811 }
812
813
814 static void
815 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
816 {
817   Id p, start, end, *idp;
818   Solvable *s;
819   Repodata *data = 0, *nextdata;
820   Repo *oldrepo = 0;
821   int dataincludes = 0;
822   int i;
823   Map providedids;
824
825   cbd->nfiles = sf->nfiles;
826   cbd->ids = sf->ids;
827   cbd->dirs = sf->dirs;
828   cbd->names = sf->names;
829   cbd->olddata = 0;
830   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
831   if (repoonly)
832     {
833       start = repoonly->start;
834       end = repoonly->end;
835     }
836   else
837     {
838       start = 2;        /* skip system solvable */
839       end = pool->nsolvables;
840     }
841   for (p = start, s = pool->solvables + p; p < end; p++, s++)
842     {
843       if (!s->repo || (repoonly && s->repo != repoonly))
844         continue;
845       if (s->repo != oldrepo || (data && p >= data->end))
846         {
847           data = 0;
848           oldrepo = 0;
849         }
850       if (oldrepo == 0)
851         {
852           nextdata = 0;
853           for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++)
854             {
855               if (!data->addedfileprovides || p >= data->end)
856                 continue;
857               if (!nextdata || nextdata->start > data->start)
858                 nextdata = data;
859               if (p >= data->start)
860                 break;
861             }
862           if (i == s->repo->nrepodata)
863             data = nextdata;
864           if (data)
865             {
866               map_init(&providedids, pool->ss.nstrings);
867               for (idp = data->addedfileprovides; *idp; idp++)
868                 MAPSET(&providedids, *idp);
869               for (i = 0; i < cbd->nfiles; i++)
870                 if (!MAPTST(&providedids, cbd->ids[i]))
871                   {
872                     break;
873                   }
874               map_free(&providedids);
875               dataincludes = i == cbd->nfiles;
876             }
877           oldrepo = s->repo;
878         }
879       if (data && p >= data->start && dataincludes)
880         continue;
881       repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd);
882     }
883 }
884
885 void
886 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
887 {
888   Solvable *s;
889   Repo *repo;
890   struct searchfiles sf, isf, *isfp;
891   struct addfileprovides_cbdata cbd;
892   int i;
893
894   memset(&sf, 0, sizeof(sf));
895   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
896   memset(&isf, 0, sizeof(isf));
897   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
898
899   isfp = installed ? &isf : 0;
900   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
901     {
902       repo = s->repo;
903       if (!repo)
904         continue;
905       if (s->obsoletes)
906         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
907       if (s->conflicts)
908         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
909       if (s->requires)
910         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
911       if (s->recommends)
912         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
913       if (s->suggests)
914         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
915       if (s->supplements)
916         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
917       if (s->enhances)
918         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
919     }
920   map_free(&sf.seen);
921   map_free(&isf.seen);
922   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
923   POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
924   cbd.dids = 0;
925   map_init(&cbd.useddirs, 1);
926   if (idp)
927     *idp = 0;
928   if (sf.nfiles)
929     {
930 #if 0
931       for (i = 0; i < sf.nfiles; i++)
932         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
933 #endif
934       pool_addfileprovides_search(pool, &cbd, &sf, 0);
935       if (idp)
936         {
937           sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
938           sf.ids[sf.nfiles] = 0;
939           *idp = sf.ids;
940           sf.ids = 0;
941         }
942       sat_free(sf.ids);
943       for (i = 0; i < sf.nfiles; i++)
944         {
945           sat_free(sf.dirs[i]);
946           sat_free(sf.names[i]);
947         }
948       sat_free(sf.dirs);
949       sat_free(sf.names);
950     }
951   if (isf.nfiles)
952     {
953 #if 0
954       for (i = 0; i < isf.nfiles; i++)
955         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
956 #endif
957       if (installed)
958         pool_addfileprovides_search(pool, &cbd, &isf, installed);
959       sat_free(isf.ids);
960       for (i = 0; i < isf.nfiles; i++)
961         {
962           sat_free(isf.dirs[i]);
963           sat_free(isf.names[i]);
964         }
965       sat_free(isf.dirs);
966       sat_free(isf.names);
967     }
968   map_free(&cbd.useddirs);
969   sat_free(cbd.dids);
970   pool_freewhatprovides(pool);  /* as we have added provides */
971 }
972
973 void
974 pool_addfileprovides(Pool *pool, Repo *installed)
975 {
976   pool_addfileprovides_ids(pool, installed, 0);
977 }
978
979 void
980 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)
981 {
982   if (p)
983     {
984       if (pool->solvables[p].repo)
985         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
986       return;
987     }
988   /* FIXME: obey callback return value! */
989   for (p = 1; p < pool->nsolvables; p++)
990     if (pool->solvables[p].repo)
991       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
992 }
993
994
995 void
996 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
997 {
998   int i;
999
1000   pool->languagecache = sat_free(pool->languagecache);
1001   pool->languagecacheother = 0;
1002   if (pool->nlanguages)
1003     {
1004       for (i = 0; i < pool->nlanguages; i++)
1005         free((char *)pool->languages[i]);
1006       free(pool->languages);
1007     }
1008   pool->nlanguages = nlanguages;
1009   if (!nlanguages)
1010     return;
1011   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
1012   for (i = 0; i < pool->nlanguages; i++)
1013     pool->languages[i] = strdup(languages[i]);
1014 }
1015
1016 Id
1017 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1018 {
1019   const char *n;
1020   char buf[256], *p;
1021   int l;
1022
1023   if (!lang)
1024     return id;
1025   n = id2str(pool, id);
1026   l = strlen(n) + strlen(lang) + 2;
1027   if (l > sizeof(buf))
1028     p = sat_malloc(strlen(n) + strlen(lang) + 2);
1029   else
1030     p = buf;
1031   sprintf(p, "%s:%s", n, lang);
1032   id = str2id(pool, p, create);
1033   if (p != buf)
1034     free(p);
1035   return id;
1036 }
1037
1038 char *
1039 pool_alloctmpspace(Pool *pool, int len)
1040 {
1041   int n = pool->tmpspacen;
1042   if (!len)
1043     return 0;
1044   if (len > pool->tmpspacelen[n])
1045     {
1046       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
1047       pool->tmpspacelen[n] = len + 32;
1048     }
1049   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
1050   return pool->tmpspacebuf[n];
1051 }
1052
1053 /*******************************************************************/
1054
1055 struct mptree {
1056   Id sibling;
1057   Id child;
1058   const char *comp;
1059   int compl;
1060   Id mountpoint;
1061 };
1062
1063 struct ducbdata {
1064   DUChanges *mps;
1065   struct mptree *mptree;
1066   int addsub;
1067   int hasdu;
1068
1069   Id *dirmap;
1070   int nmap;
1071   Repodata *olddata;
1072 };
1073
1074
1075 static int
1076 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1077 {
1078   struct ducbdata *cbd = cbdata;
1079   Id mp;
1080
1081   if (data != cbd->olddata)
1082     {
1083       Id dn, mp, comp, *dirmap, *dirs;
1084       int i, compl;
1085       const char *compstr;
1086       struct mptree *mptree;
1087
1088       /* create map from dir to mptree */
1089       cbd->dirmap = sat_free(cbd->dirmap);
1090       cbd->nmap = 0;
1091       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
1092       mptree = cbd->mptree;
1093       mp = 0;
1094       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1095         {
1096           comp = *dirs++;
1097           if (comp <= 0)
1098             {
1099               mp = dirmap[-comp];
1100               continue;
1101             }
1102           if (mp < 0)
1103             {
1104               /* unconnected */
1105               dirmap[dn] = mp;
1106               continue;
1107             }
1108           if (!mptree[mp].child)
1109             {
1110               dirmap[dn] = -mp;
1111               continue;
1112             }
1113           if (data->localpool)
1114             compstr = stringpool_id2str(&data->spool, comp);
1115           else
1116             compstr = id2str(data->repo->pool, comp);
1117           compl = strlen(compstr);
1118           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1119             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1120               break;
1121           dirmap[dn] = i ? i : -mp;
1122         }
1123       /* change dirmap to point to mountpoint instead of mptree */
1124       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1125         {
1126           mp = dirmap[dn];
1127           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1128         }
1129       cbd->dirmap = dirmap;
1130       cbd->nmap = data->dirpool.ndirs;
1131       cbd->olddata = data;
1132     }
1133   cbd->hasdu = 1;
1134   if (value->id < 0 || value->id >= cbd->nmap)
1135     return 0;
1136   mp = cbd->dirmap[value->id];
1137   if (mp < 0)
1138     return 0;
1139   if (cbd->addsub > 0)
1140     {
1141       cbd->mps[mp].kbytes += value->num;
1142       cbd->mps[mp].files += value->num2;
1143     }
1144   else
1145     {
1146       cbd->mps[mp].kbytes -= value->num;
1147       cbd->mps[mp].files -= value->num2;
1148     }
1149   return 0;
1150 }
1151
1152 static void
1153 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1154 {
1155   int i;
1156   if (mptree[pos].mountpoint == -1)
1157     mptree[pos].mountpoint = mountpoint;
1158   else
1159     mountpoint = mptree[pos].mountpoint;
1160   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1161     propagate_mountpoints(mptree, i, mountpoint);
1162 }
1163
1164 #define MPTREE_BLOCK 15
1165
1166 void
1167 pool_calc_duchanges(Pool *pool, Repo *oldinstalled, Map *installedmap, DUChanges *mps, int nmps)
1168 {
1169   char *p;
1170   const char *path, *compstr;
1171   struct mptree *mptree;
1172   int i, nmptree;
1173   int pos, compl;
1174   int mp;
1175   struct ducbdata cbd;
1176   Solvable *s;
1177   Id sp;
1178   Map ignoredu;
1179
1180   memset(&ignoredu, 0, sizeof(ignoredu));
1181   cbd.mps = mps;
1182   cbd.addsub = 0;
1183   cbd.dirmap = 0;
1184   cbd.nmap = 0;
1185   cbd.olddata = 0;
1186
1187   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1188
1189   /* our root node */
1190   mptree[0].sibling = 0;
1191   mptree[0].child = 0;
1192   mptree[0].comp = 0;
1193   mptree[0].compl = 0;
1194   mptree[0].mountpoint = -1;
1195   nmptree = 1;
1196   
1197   /* create component tree */
1198   for (mp = 0; mp < nmps; mp++)
1199     {
1200       mps[mp].kbytes = 0;
1201       mps[mp].files = 0;
1202       pos = 0;
1203       path = mps[mp].path;
1204       while(*path == '/')
1205         path++;
1206       while (*path)
1207         {
1208           if ((p = strchr(path, '/')) == 0)
1209             {
1210               compstr = path;
1211               compl = strlen(compstr);
1212               path += compl;
1213             }
1214           else
1215             {
1216               compstr = path;
1217               compl = p - path;
1218               path = p + 1;
1219               while(*path == '/')
1220                 path++;
1221             }
1222           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1223             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1224               break;
1225           if (!i)
1226             {
1227               /* create new node */
1228               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1229               i = nmptree++;
1230               mptree[i].sibling = mptree[pos].child;
1231               mptree[i].child = 0;
1232               mptree[i].comp = compstr;
1233               mptree[i].compl = compl;
1234               mptree[i].mountpoint = -1;
1235               mptree[pos].child = i;
1236             }
1237           pos = i;
1238         }
1239       mptree[pos].mountpoint = mp;
1240     }
1241
1242   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1243
1244 #if 0
1245   for (i = 0; i < nmptree; i++)
1246     {
1247       printf("#%d sibling: %d\n", i, mptree[i].sibling);
1248       printf("#%d child: %d\n", i, mptree[i].child);
1249       printf("#%d comp: %s\n", i, mptree[i].comp);
1250       printf("#%d compl: %d\n", i, mptree[i].compl);
1251       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1252     }
1253 #endif
1254
1255   cbd.mptree = mptree;
1256   cbd.addsub = 1;
1257   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1258     {
1259       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1260         continue;
1261       if (!MAPTST(installedmap, sp))
1262         continue;
1263       cbd.hasdu = 0;
1264       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1265       if (!cbd.hasdu && oldinstalled)
1266         {
1267           Id op, opp;
1268           /* no du data available, ignore data of all installed solvables we obsolete */
1269           if (!ignoredu.map)
1270             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1271           if (s->obsoletes)
1272             {
1273               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1274               while ((obs = *obsp++) != 0)
1275                 FOR_PROVIDES(op, opp, obs)
1276                   if (op >= oldinstalled->start && op < oldinstalled->end)
1277                     MAPSET(&ignoredu, op - oldinstalled->start);
1278             }
1279           FOR_PROVIDES(op, opp, s->name)
1280             if (pool->solvables[op].name == s->name)
1281               if (op >= oldinstalled->start && op < oldinstalled->end)
1282                 MAPSET(&ignoredu, op - oldinstalled->start);
1283         }
1284     }
1285   cbd.addsub = -1;
1286   if (oldinstalled)
1287     {
1288       /* assumes we allways have du data for installed solvables */
1289       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1290         {
1291           if (MAPTST(installedmap, sp))
1292             continue;
1293           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1294             continue;
1295           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1296         }
1297     }
1298   if (ignoredu.map)
1299     map_free(&ignoredu);
1300   sat_free(cbd.dirmap);
1301   sat_free(mptree);
1302 }
1303
1304 int
1305 pool_calc_installsizechange(Pool *pool, Repo *oldinstalled, Map *installedmap)
1306 {
1307   Id sp;
1308   Solvable *s;
1309   int change = 0;
1310
1311   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1312     {
1313       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1314         continue;
1315       if (!MAPTST(installedmap, sp))
1316         continue;
1317       change += repo_lookup_num(s, SOLVABLE_INSTALLSIZE);
1318     }
1319   if (oldinstalled)
1320     {
1321       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1322         {
1323           if (MAPTST(installedmap, sp))
1324             continue;
1325           change -= repo_lookup_num(s, SOLVABLE_INSTALLSIZE);
1326         }
1327     }
1328   return change;
1329 }
1330
1331 /* map:
1332  *  1: installed
1333  *  2: conflicts with installed
1334  *  8: interesting (only true if installed)
1335  * 16: undecided
1336  */
1337  
1338 static inline Id dep2name(Pool *pool, Id dep)
1339 {
1340   while (ISRELDEP(dep))
1341     {
1342       Reldep *rd = rd = GETRELDEP(pool, dep);
1343       dep = rd->name;
1344     }
1345   return dep;
1346 }
1347
1348 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep)
1349 {
1350   Id p, pp;
1351   int r = 0;
1352   FOR_PROVIDES(p, pp, dep)
1353     {
1354       if (p == SYSTEMSOLVABLE)
1355         return 1;       /* always boring, as never constraining */
1356       if ((map[p] & 9) == 9)
1357         return 9;
1358       r |= map[p] & 17;
1359     }
1360   return r;
1361 }
1362
1363 /*
1364  * pool_trivial_installable - calculate if a set of solvables is
1365  * trivial installable without any other installs/deinstalls of
1366  * packages not belonging to the set.
1367  *
1368  * the state is returned in the result queue:
1369  * 1:  solvable is installable without any other package changes
1370  * 0:  solvable is not installable
1371  * -1: solvable is installable, but doesn't constrain any installed packages
1372  */
1373
1374 void
1375 pool_trivial_installable(Pool *pool, Repo *oldinstalled, Map *installedmap, Queue *pkgs, Queue *res)
1376 {
1377   int i, r, m, did;
1378   Id p, *dp, con, *conp, req, *reqp;
1379   unsigned char *map;
1380   Solvable *s;
1381
1382   map = sat_calloc(pool->nsolvables, 1);
1383   for (p = 1; p < pool->nsolvables; p++)
1384     {
1385       if (!MAPTST(installedmap, p))
1386         continue;
1387       map[p] |= 9;
1388       s = pool->solvables + p;
1389       if (!s->conflicts)
1390         continue;
1391       conp = s->repo->idarraydata + s->conflicts;
1392       while ((con = *conp++) != 0)
1393         {
1394           dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
1395           for (; *dp; dp++)
1396             map[p] |= 2;        /* XXX: self conflict ? */
1397         }
1398     }
1399   for (i = 0; i < pkgs->count; i++)
1400     map[pkgs->elements[i]] = 16;
1401
1402   for (i = 0, did = 0; did < pkgs->count; i++, did++)
1403     {
1404       if (i == pkgs->count)
1405         i = 0;
1406       p = pkgs->elements[i];
1407       if ((map[p] & 16) == 0)
1408         continue;
1409       if ((map[p] & 2) != 0)
1410         {
1411           map[p] = 2;
1412           continue;
1413         }
1414       s = pool->solvables + p;
1415       m = 1;
1416       if (s->requires)
1417         {
1418           reqp = s->repo->idarraydata + s->requires;
1419           while ((req = *reqp++) != 0)
1420             {
1421               if (req == SOLVABLE_PREREQMARKER)
1422                 continue;
1423               r = providedbyinstalled(pool, map, req);
1424               if (!r)
1425                 {
1426                   /* decided and miss */
1427                   map[p] = 2;
1428                   break;
1429                 }
1430               m |= r;   /* 1 | 9 | 16 | 17 */
1431             }
1432           if (req)
1433             continue;
1434           if ((m & 9) == 9)
1435             m = 9;
1436         }
1437       if (s->conflicts)
1438         {
1439           conp = s->repo->idarraydata + s->conflicts;
1440           while ((con = *conp++) != 0)
1441             {
1442               if ((providedbyinstalled(pool, map, con) & 1) != 0)
1443                 {
1444                   map[p] = 2;
1445                   break;
1446                 }
1447               if ((m == 1 || m == 17) && ISRELDEP(con))
1448                 {
1449                   con = dep2name(pool, con);
1450                   if ((providedbyinstalled(pool, map, con) & 1) != 0)
1451                     m = 9;
1452                 }
1453             }
1454           if (con)
1455             continue;   /* found a conflict */
1456         }
1457 #if 0
1458       if (s->repo && s->repo != oldinstalled)
1459         {
1460           Id p2, obs, *obsp, *pp;
1461           Solvable *s2;
1462           if (s->obsoletes)
1463             {
1464               obsp = s->repo->idarraydata + s->obsoletes;
1465               while ((obs = *obsp++) != 0)
1466                 {
1467                   if ((providedbyinstalled(pool, map, obs) & 1) != 0)
1468                     {
1469                       map[p] = 2;
1470                       break;
1471                     }
1472                 }
1473               if (obs)
1474                 continue;
1475             }
1476           FOR_PROVIDES(p2, pp, s->name)
1477             {
1478               s2 = pool->solvables + p2;
1479               if (s2->name == s->name && (map[p2] & 1) != 0)
1480                 {
1481                   map[p] = 2;
1482                   break;
1483                 }
1484             }
1485           if (p2)
1486             continue;
1487         }
1488 #endif
1489       if (m != map[p])
1490         {
1491           map[p] = m;
1492           did = 0;
1493         }
1494     }
1495   queue_free(res);
1496   queue_clone(res, pkgs);
1497   for (i = 0; i < pkgs->count; i++)
1498     {
1499       m = map[pkgs->elements[i]];
1500       if ((m & 9) == 9)
1501         r = 1;
1502       else if (m & 1)
1503         r = -1;
1504       else
1505         r = 0;
1506       res->elements[i] = r;
1507     }
1508   free(map);
1509 }
1510
1511 // EOF