- more cleanups:
[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 static int
814 addfileprovides_setid_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
815 {
816   Map *provideids = cbdata;
817   if (key->type != REPOKEY_TYPE_IDARRAY)
818     return 0;
819   MAPSET(provideids, kv->id);
820   return kv->eof ? SEARCH_NEXT_SOLVABLE : 0;
821 }
822
823
824 static void
825 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
826 {
827   Id p, start, end;
828   Solvable *s;
829   Repodata *data = 0, *nextdata;
830   Repo *oldrepo = 0;
831   int dataincludes = 0;
832   int i, j;
833   Map providedids;
834
835   cbd->nfiles = sf->nfiles;
836   cbd->ids = sf->ids;
837   cbd->dirs = sf->dirs;
838   cbd->names = sf->names;
839   cbd->olddata = 0;
840   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
841   if (repoonly)
842     {
843       start = repoonly->start;
844       end = repoonly->end;
845     }
846   else
847     {
848       start = 2;        /* skip system solvable */
849       end = pool->nsolvables;
850     }
851   for (p = start, s = pool->solvables + p; p < end; p++, s++)
852     {
853       if (!s->repo || (repoonly && s->repo != repoonly))
854         continue;
855       /* check if p is in (oldrepo,data) */
856       if (s->repo != oldrepo || (data && p >= data->end))
857         {
858           data = 0;
859           oldrepo = 0;
860         }
861       if (oldrepo == 0)
862         {
863           /* nope, find new repo/repodata */
864           /* if we don't find a match, set data to the next repodata */
865           nextdata = 0;
866           for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++)
867             {
868               if (p >= data->end)
869                 continue;
870               if (data->state != REPODATA_AVAILABLE)
871                 continue;
872               for (j = 1; j < data->nkeys; j++)
873                 if (data->keys[j].name == REPOSITORY_ADDEDFILEPROVIDES && data->keys[j].type == REPOKEY_TYPE_IDARRAY)
874                   break;
875               if (j == data->nkeys)
876                 continue;
877               /* great, this repodata contains addedfileprovides */
878               if (!nextdata || nextdata->start > data->start)
879                 nextdata = data;
880               if (p >= data->start)
881                 break;
882             }
883           if (i == s->repo->nrepodata)
884             data = nextdata;    /* no direct hit, use next repodata */
885           if (data)
886             {
887               map_init(&providedids, pool->ss.nstrings);
888               repodata_search(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, 0, addfileprovides_setid_cb, &providedids);
889               for (i = 0; i < cbd->nfiles; i++)
890                 if (!MAPTST(&providedids, cbd->ids[i]))
891                   break;
892               map_free(&providedids);
893               dataincludes = i == cbd->nfiles;
894             }
895           oldrepo = s->repo;
896         }
897       if (data && p >= data->start && dataincludes)
898         continue;
899       repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd);
900     }
901 }
902
903 void
904 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
905 {
906   Solvable *s;
907   Repo *repo;
908   struct searchfiles sf, isf, *isfp;
909   struct addfileprovides_cbdata cbd;
910   int i;
911
912   memset(&sf, 0, sizeof(sf));
913   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
914   memset(&isf, 0, sizeof(isf));
915   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
916
917   isfp = installed ? &isf : 0;
918   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
919     {
920       repo = s->repo;
921       if (!repo)
922         continue;
923       if (s->obsoletes)
924         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
925       if (s->conflicts)
926         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
927       if (s->requires)
928         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
929       if (s->recommends)
930         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
931       if (s->suggests)
932         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
933       if (s->supplements)
934         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
935       if (s->enhances)
936         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
937     }
938   map_free(&sf.seen);
939   map_free(&isf.seen);
940   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
941   POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
942   cbd.dids = 0;
943   map_init(&cbd.useddirs, 1);
944   if (idp)
945     *idp = 0;
946   if (sf.nfiles)
947     {
948 #if 0
949       for (i = 0; i < sf.nfiles; i++)
950         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
951 #endif
952       pool_addfileprovides_search(pool, &cbd, &sf, 0);
953       if (idp)
954         {
955           sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
956           sf.ids[sf.nfiles] = 0;
957           *idp = sf.ids;
958           sf.ids = 0;
959         }
960       sat_free(sf.ids);
961       for (i = 0; i < sf.nfiles; i++)
962         {
963           sat_free(sf.dirs[i]);
964           sat_free(sf.names[i]);
965         }
966       sat_free(sf.dirs);
967       sat_free(sf.names);
968     }
969   if (isf.nfiles)
970     {
971 #if 0
972       for (i = 0; i < isf.nfiles; i++)
973         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
974 #endif
975       if (installed)
976         pool_addfileprovides_search(pool, &cbd, &isf, installed);
977       sat_free(isf.ids);
978       for (i = 0; i < isf.nfiles; i++)
979         {
980           sat_free(isf.dirs[i]);
981           sat_free(isf.names[i]);
982         }
983       sat_free(isf.dirs);
984       sat_free(isf.names);
985     }
986   map_free(&cbd.useddirs);
987   sat_free(cbd.dids);
988   pool_freewhatprovides(pool);  /* as we have added provides */
989 }
990
991 void
992 pool_addfileprovides(Pool *pool, Repo *installed)
993 {
994   pool_addfileprovides_ids(pool, installed, 0);
995 }
996
997 void
998 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)
999 {
1000   if (p)
1001     {
1002       if (pool->solvables[p].repo)
1003         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1004       return;
1005     }
1006   /* FIXME: obey callback return value! */
1007   for (p = 1; p < pool->nsolvables; p++)
1008     if (pool->solvables[p].repo)
1009       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1010 }
1011
1012 void
1013 pool_clear_pos(Pool *pool)
1014 {
1015   memset(&pool->pos, 0, sizeof(pool->pos));
1016 }
1017
1018
1019 void
1020 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
1021 {
1022   int i;
1023
1024   pool->languagecache = sat_free(pool->languagecache);
1025   pool->languagecacheother = 0;
1026   if (pool->nlanguages)
1027     {
1028       for (i = 0; i < pool->nlanguages; i++)
1029         free((char *)pool->languages[i]);
1030       free(pool->languages);
1031     }
1032   pool->nlanguages = nlanguages;
1033   if (!nlanguages)
1034     return;
1035   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
1036   for (i = 0; i < pool->nlanguages; i++)
1037     pool->languages[i] = strdup(languages[i]);
1038 }
1039
1040 Id
1041 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1042 {
1043   const char *n;
1044   char buf[256], *p;
1045   int l;
1046
1047   if (!lang)
1048     return id;
1049   n = id2str(pool, id);
1050   l = strlen(n) + strlen(lang) + 2;
1051   if (l > sizeof(buf))
1052     p = sat_malloc(strlen(n) + strlen(lang) + 2);
1053   else
1054     p = buf;
1055   sprintf(p, "%s:%s", n, lang);
1056   id = str2id(pool, p, create);
1057   if (p != buf)
1058     free(p);
1059   return id;
1060 }
1061
1062 char *
1063 pool_alloctmpspace(Pool *pool, int len)
1064 {
1065   int n = pool->tmpspacen;
1066   if (!len)
1067     return 0;
1068   if (len > pool->tmpspacelen[n])
1069     {
1070       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
1071       pool->tmpspacelen[n] = len + 32;
1072     }
1073   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
1074   return pool->tmpspacebuf[n];
1075 }
1076
1077 /*******************************************************************/
1078
1079 struct mptree {
1080   Id sibling;
1081   Id child;
1082   const char *comp;
1083   int compl;
1084   Id mountpoint;
1085 };
1086
1087 struct ducbdata {
1088   DUChanges *mps;
1089   struct mptree *mptree;
1090   int addsub;
1091   int hasdu;
1092
1093   Id *dirmap;
1094   int nmap;
1095   Repodata *olddata;
1096 };
1097
1098
1099 static int
1100 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1101 {
1102   struct ducbdata *cbd = cbdata;
1103   Id mp;
1104
1105   if (data != cbd->olddata)
1106     {
1107       Id dn, mp, comp, *dirmap, *dirs;
1108       int i, compl;
1109       const char *compstr;
1110       struct mptree *mptree;
1111
1112       /* create map from dir to mptree */
1113       cbd->dirmap = sat_free(cbd->dirmap);
1114       cbd->nmap = 0;
1115       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
1116       mptree = cbd->mptree;
1117       mp = 0;
1118       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1119         {
1120           comp = *dirs++;
1121           if (comp <= 0)
1122             {
1123               mp = dirmap[-comp];
1124               continue;
1125             }
1126           if (mp < 0)
1127             {
1128               /* unconnected */
1129               dirmap[dn] = mp;
1130               continue;
1131             }
1132           if (!mptree[mp].child)
1133             {
1134               dirmap[dn] = -mp;
1135               continue;
1136             }
1137           if (data->localpool)
1138             compstr = stringpool_id2str(&data->spool, comp);
1139           else
1140             compstr = id2str(data->repo->pool, comp);
1141           compl = strlen(compstr);
1142           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1143             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1144               break;
1145           dirmap[dn] = i ? i : -mp;
1146         }
1147       /* change dirmap to point to mountpoint instead of mptree */
1148       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1149         {
1150           mp = dirmap[dn];
1151           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1152         }
1153       cbd->dirmap = dirmap;
1154       cbd->nmap = data->dirpool.ndirs;
1155       cbd->olddata = data;
1156     }
1157   cbd->hasdu = 1;
1158   if (value->id < 0 || value->id >= cbd->nmap)
1159     return 0;
1160   mp = cbd->dirmap[value->id];
1161   if (mp < 0)
1162     return 0;
1163   if (cbd->addsub > 0)
1164     {
1165       cbd->mps[mp].kbytes += value->num;
1166       cbd->mps[mp].files += value->num2;
1167     }
1168   else
1169     {
1170       cbd->mps[mp].kbytes -= value->num;
1171       cbd->mps[mp].files -= value->num2;
1172     }
1173   return 0;
1174 }
1175
1176 static void
1177 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1178 {
1179   int i;
1180   if (mptree[pos].mountpoint == -1)
1181     mptree[pos].mountpoint = mountpoint;
1182   else
1183     mountpoint = mptree[pos].mountpoint;
1184   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1185     propagate_mountpoints(mptree, i, mountpoint);
1186 }
1187
1188 #define MPTREE_BLOCK 15
1189
1190 void
1191 pool_calc_duchanges(Pool *pool, Repo *oldinstalled, Map *installedmap, DUChanges *mps, int nmps)
1192 {
1193   char *p;
1194   const char *path, *compstr;
1195   struct mptree *mptree;
1196   int i, nmptree;
1197   int pos, compl;
1198   int mp;
1199   struct ducbdata cbd;
1200   Solvable *s;
1201   Id sp;
1202   Map ignoredu;
1203
1204   memset(&ignoredu, 0, sizeof(ignoredu));
1205   cbd.mps = mps;
1206   cbd.addsub = 0;
1207   cbd.dirmap = 0;
1208   cbd.nmap = 0;
1209   cbd.olddata = 0;
1210
1211   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1212
1213   /* our root node */
1214   mptree[0].sibling = 0;
1215   mptree[0].child = 0;
1216   mptree[0].comp = 0;
1217   mptree[0].compl = 0;
1218   mptree[0].mountpoint = -1;
1219   nmptree = 1;
1220   
1221   /* create component tree */
1222   for (mp = 0; mp < nmps; mp++)
1223     {
1224       mps[mp].kbytes = 0;
1225       mps[mp].files = 0;
1226       pos = 0;
1227       path = mps[mp].path;
1228       while(*path == '/')
1229         path++;
1230       while (*path)
1231         {
1232           if ((p = strchr(path, '/')) == 0)
1233             {
1234               compstr = path;
1235               compl = strlen(compstr);
1236               path += compl;
1237             }
1238           else
1239             {
1240               compstr = path;
1241               compl = p - path;
1242               path = p + 1;
1243               while(*path == '/')
1244                 path++;
1245             }
1246           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1247             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1248               break;
1249           if (!i)
1250             {
1251               /* create new node */
1252               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1253               i = nmptree++;
1254               mptree[i].sibling = mptree[pos].child;
1255               mptree[i].child = 0;
1256               mptree[i].comp = compstr;
1257               mptree[i].compl = compl;
1258               mptree[i].mountpoint = -1;
1259               mptree[pos].child = i;
1260             }
1261           pos = i;
1262         }
1263       mptree[pos].mountpoint = mp;
1264     }
1265
1266   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1267
1268 #if 0
1269   for (i = 0; i < nmptree; i++)
1270     {
1271       printf("#%d sibling: %d\n", i, mptree[i].sibling);
1272       printf("#%d child: %d\n", i, mptree[i].child);
1273       printf("#%d comp: %s\n", i, mptree[i].comp);
1274       printf("#%d compl: %d\n", i, mptree[i].compl);
1275       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1276     }
1277 #endif
1278
1279   cbd.mptree = mptree;
1280   cbd.addsub = 1;
1281   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1282     {
1283       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1284         continue;
1285       if (!MAPTST(installedmap, sp))
1286         continue;
1287       cbd.hasdu = 0;
1288       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1289       if (!cbd.hasdu && oldinstalled)
1290         {
1291           Id op, opp;
1292           /* no du data available, ignore data of all installed solvables we obsolete */
1293           if (!ignoredu.map)
1294             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1295           if (s->obsoletes)
1296             {
1297               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1298               while ((obs = *obsp++) != 0)
1299                 FOR_PROVIDES(op, opp, obs)
1300                   if (op >= oldinstalled->start && op < oldinstalled->end)
1301                     MAPSET(&ignoredu, op - oldinstalled->start);
1302             }
1303           FOR_PROVIDES(op, opp, s->name)
1304             if (pool->solvables[op].name == s->name)
1305               if (op >= oldinstalled->start && op < oldinstalled->end)
1306                 MAPSET(&ignoredu, op - oldinstalled->start);
1307         }
1308     }
1309   cbd.addsub = -1;
1310   if (oldinstalled)
1311     {
1312       /* assumes we allways have du data for installed solvables */
1313       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1314         {
1315           if (MAPTST(installedmap, sp))
1316             continue;
1317           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1318             continue;
1319           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1320         }
1321     }
1322   if (ignoredu.map)
1323     map_free(&ignoredu);
1324   sat_free(cbd.dirmap);
1325   sat_free(mptree);
1326 }
1327
1328 int
1329 pool_calc_installsizechange(Pool *pool, Repo *oldinstalled, Map *installedmap)
1330 {
1331   Id sp;
1332   Solvable *s;
1333   int change = 0;
1334
1335   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1336     {
1337       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1338         continue;
1339       if (!MAPTST(installedmap, sp))
1340         continue;
1341       change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1342     }
1343   if (oldinstalled)
1344     {
1345       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1346         {
1347           if (MAPTST(installedmap, sp))
1348             continue;
1349           change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1350         }
1351     }
1352   return change;
1353 }
1354
1355 /* map:
1356  *  1: installed
1357  *  2: conflicts with installed
1358  *  8: interesting (only true if installed)
1359  * 16: undecided
1360  */
1361  
1362 static inline Id dep2name(Pool *pool, Id dep)
1363 {
1364   while (ISRELDEP(dep))
1365     {
1366       Reldep *rd = rd = GETRELDEP(pool, dep);
1367       dep = rd->name;
1368     }
1369   return dep;
1370 }
1371
1372 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep)
1373 {
1374   Id p, pp;
1375   int r = 0;
1376   FOR_PROVIDES(p, pp, dep)
1377     {
1378       if (p == SYSTEMSOLVABLE)
1379         return 1;       /* always boring, as never constraining */
1380       if ((map[p] & 9) == 9)
1381         return 9;
1382       r |= map[p] & 17;
1383     }
1384   return r;
1385 }
1386
1387 /*
1388  * pool_trivial_installable - calculate if a set of solvables is
1389  * trivial installable without any other installs/deinstalls of
1390  * packages not belonging to the set.
1391  *
1392  * the state is returned in the result queue:
1393  * 1:  solvable is installable without any other package changes
1394  * 0:  solvable is not installable
1395  * -1: solvable is installable, but doesn't constrain any installed packages
1396  */
1397
1398 void
1399 pool_trivial_installable(Pool *pool, Repo *oldinstalled, Map *installedmap, Queue *pkgs, Queue *res)
1400 {
1401   int i, r, m, did;
1402   Id p, *dp, con, *conp, req, *reqp;
1403   unsigned char *map;
1404   Solvable *s;
1405
1406   map = sat_calloc(pool->nsolvables, 1);
1407   for (p = 1; p < pool->nsolvables; p++)
1408     {
1409       if (!MAPTST(installedmap, p))
1410         continue;
1411       map[p] |= 9;
1412       s = pool->solvables + p;
1413       if (!s->conflicts)
1414         continue;
1415       conp = s->repo->idarraydata + s->conflicts;
1416       while ((con = *conp++) != 0)
1417         {
1418           dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
1419           for (; *dp; dp++)
1420             map[p] |= 2;        /* XXX: self conflict ? */
1421         }
1422     }
1423   for (i = 0; i < pkgs->count; i++)
1424     map[pkgs->elements[i]] = 16;
1425
1426   for (i = 0, did = 0; did < pkgs->count; i++, did++)
1427     {
1428       if (i == pkgs->count)
1429         i = 0;
1430       p = pkgs->elements[i];
1431       if ((map[p] & 16) == 0)
1432         continue;
1433       if ((map[p] & 2) != 0)
1434         {
1435           map[p] = 2;
1436           continue;
1437         }
1438       s = pool->solvables + p;
1439       m = 1;
1440       if (s->requires)
1441         {
1442           reqp = s->repo->idarraydata + s->requires;
1443           while ((req = *reqp++) != 0)
1444             {
1445               if (req == SOLVABLE_PREREQMARKER)
1446                 continue;
1447               r = providedbyinstalled(pool, map, req);
1448               if (!r)
1449                 {
1450                   /* decided and miss */
1451                   map[p] = 2;
1452                   break;
1453                 }
1454               m |= r;   /* 1 | 9 | 16 | 17 */
1455             }
1456           if (req)
1457             continue;
1458           if ((m & 9) == 9)
1459             m = 9;
1460         }
1461       if (s->conflicts)
1462         {
1463           conp = s->repo->idarraydata + s->conflicts;
1464           while ((con = *conp++) != 0)
1465             {
1466               if ((providedbyinstalled(pool, map, con) & 1) != 0)
1467                 {
1468                   map[p] = 2;
1469                   break;
1470                 }
1471               if ((m == 1 || m == 17) && ISRELDEP(con))
1472                 {
1473                   con = dep2name(pool, con);
1474                   if ((providedbyinstalled(pool, map, con) & 1) != 0)
1475                     m = 9;
1476                 }
1477             }
1478           if (con)
1479             continue;   /* found a conflict */
1480         }
1481 #if 0
1482       if (s->repo && s->repo != oldinstalled)
1483         {
1484           Id p2, obs, *obsp, *pp;
1485           Solvable *s2;
1486           if (s->obsoletes)
1487             {
1488               obsp = s->repo->idarraydata + s->obsoletes;
1489               while ((obs = *obsp++) != 0)
1490                 {
1491                   if ((providedbyinstalled(pool, map, obs) & 1) != 0)
1492                     {
1493                       map[p] = 2;
1494                       break;
1495                     }
1496                 }
1497               if (obs)
1498                 continue;
1499             }
1500           FOR_PROVIDES(p2, pp, s->name)
1501             {
1502               s2 = pool->solvables + p2;
1503               if (s2->name == s->name && (map[p2] & 1) != 0)
1504                 {
1505                   map[p] = 2;
1506                   break;
1507                 }
1508             }
1509           if (p2)
1510             continue;
1511         }
1512 #endif
1513       if (m != map[p])
1514         {
1515           map[p] = m;
1516           did = 0;
1517         }
1518     }
1519   queue_free(res);
1520   queue_clone(res, pkgs);
1521   for (i = 0; i < pkgs->count; i++)
1522     {
1523       m = map[pkgs->elements[i]];
1524       if ((m & 9) == 9)
1525         r = 1;
1526       else if (m & 1)
1527         r = -1;
1528       else
1529         r = 0;
1530       res->elements[i] = r;
1531     }
1532   free(map);
1533 }
1534
1535 // EOF