- the big solv data change
[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, REPOENTRY_META, REPOSITORY_ADDEDFILEPROVIDES, 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
1013 void
1014 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
1015 {
1016   int i;
1017
1018   pool->languagecache = sat_free(pool->languagecache);
1019   pool->languagecacheother = 0;
1020   if (pool->nlanguages)
1021     {
1022       for (i = 0; i < pool->nlanguages; i++)
1023         free((char *)pool->languages[i]);
1024       free(pool->languages);
1025     }
1026   pool->nlanguages = nlanguages;
1027   if (!nlanguages)
1028     return;
1029   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
1030   for (i = 0; i < pool->nlanguages; i++)
1031     pool->languages[i] = strdup(languages[i]);
1032 }
1033
1034 Id
1035 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1036 {
1037   const char *n;
1038   char buf[256], *p;
1039   int l;
1040
1041   if (!lang)
1042     return id;
1043   n = id2str(pool, id);
1044   l = strlen(n) + strlen(lang) + 2;
1045   if (l > sizeof(buf))
1046     p = sat_malloc(strlen(n) + strlen(lang) + 2);
1047   else
1048     p = buf;
1049   sprintf(p, "%s:%s", n, lang);
1050   id = str2id(pool, p, create);
1051   if (p != buf)
1052     free(p);
1053   return id;
1054 }
1055
1056 char *
1057 pool_alloctmpspace(Pool *pool, int len)
1058 {
1059   int n = pool->tmpspacen;
1060   if (!len)
1061     return 0;
1062   if (len > pool->tmpspacelen[n])
1063     {
1064       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
1065       pool->tmpspacelen[n] = len + 32;
1066     }
1067   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
1068   return pool->tmpspacebuf[n];
1069 }
1070
1071 /*******************************************************************/
1072
1073 struct mptree {
1074   Id sibling;
1075   Id child;
1076   const char *comp;
1077   int compl;
1078   Id mountpoint;
1079 };
1080
1081 struct ducbdata {
1082   DUChanges *mps;
1083   struct mptree *mptree;
1084   int addsub;
1085   int hasdu;
1086
1087   Id *dirmap;
1088   int nmap;
1089   Repodata *olddata;
1090 };
1091
1092
1093 static int
1094 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1095 {
1096   struct ducbdata *cbd = cbdata;
1097   Id mp;
1098
1099   if (data != cbd->olddata)
1100     {
1101       Id dn, mp, comp, *dirmap, *dirs;
1102       int i, compl;
1103       const char *compstr;
1104       struct mptree *mptree;
1105
1106       /* create map from dir to mptree */
1107       cbd->dirmap = sat_free(cbd->dirmap);
1108       cbd->nmap = 0;
1109       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
1110       mptree = cbd->mptree;
1111       mp = 0;
1112       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1113         {
1114           comp = *dirs++;
1115           if (comp <= 0)
1116             {
1117               mp = dirmap[-comp];
1118               continue;
1119             }
1120           if (mp < 0)
1121             {
1122               /* unconnected */
1123               dirmap[dn] = mp;
1124               continue;
1125             }
1126           if (!mptree[mp].child)
1127             {
1128               dirmap[dn] = -mp;
1129               continue;
1130             }
1131           if (data->localpool)
1132             compstr = stringpool_id2str(&data->spool, comp);
1133           else
1134             compstr = id2str(data->repo->pool, comp);
1135           compl = strlen(compstr);
1136           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1137             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1138               break;
1139           dirmap[dn] = i ? i : -mp;
1140         }
1141       /* change dirmap to point to mountpoint instead of mptree */
1142       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1143         {
1144           mp = dirmap[dn];
1145           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1146         }
1147       cbd->dirmap = dirmap;
1148       cbd->nmap = data->dirpool.ndirs;
1149       cbd->olddata = data;
1150     }
1151   cbd->hasdu = 1;
1152   if (value->id < 0 || value->id >= cbd->nmap)
1153     return 0;
1154   mp = cbd->dirmap[value->id];
1155   if (mp < 0)
1156     return 0;
1157   if (cbd->addsub > 0)
1158     {
1159       cbd->mps[mp].kbytes += value->num;
1160       cbd->mps[mp].files += value->num2;
1161     }
1162   else
1163     {
1164       cbd->mps[mp].kbytes -= value->num;
1165       cbd->mps[mp].files -= value->num2;
1166     }
1167   return 0;
1168 }
1169
1170 static void
1171 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1172 {
1173   int i;
1174   if (mptree[pos].mountpoint == -1)
1175     mptree[pos].mountpoint = mountpoint;
1176   else
1177     mountpoint = mptree[pos].mountpoint;
1178   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1179     propagate_mountpoints(mptree, i, mountpoint);
1180 }
1181
1182 #define MPTREE_BLOCK 15
1183
1184 void
1185 pool_calc_duchanges(Pool *pool, Repo *oldinstalled, Map *installedmap, DUChanges *mps, int nmps)
1186 {
1187   char *p;
1188   const char *path, *compstr;
1189   struct mptree *mptree;
1190   int i, nmptree;
1191   int pos, compl;
1192   int mp;
1193   struct ducbdata cbd;
1194   Solvable *s;
1195   Id sp;
1196   Map ignoredu;
1197
1198   memset(&ignoredu, 0, sizeof(ignoredu));
1199   cbd.mps = mps;
1200   cbd.addsub = 0;
1201   cbd.dirmap = 0;
1202   cbd.nmap = 0;
1203   cbd.olddata = 0;
1204
1205   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1206
1207   /* our root node */
1208   mptree[0].sibling = 0;
1209   mptree[0].child = 0;
1210   mptree[0].comp = 0;
1211   mptree[0].compl = 0;
1212   mptree[0].mountpoint = -1;
1213   nmptree = 1;
1214   
1215   /* create component tree */
1216   for (mp = 0; mp < nmps; mp++)
1217     {
1218       mps[mp].kbytes = 0;
1219       mps[mp].files = 0;
1220       pos = 0;
1221       path = mps[mp].path;
1222       while(*path == '/')
1223         path++;
1224       while (*path)
1225         {
1226           if ((p = strchr(path, '/')) == 0)
1227             {
1228               compstr = path;
1229               compl = strlen(compstr);
1230               path += compl;
1231             }
1232           else
1233             {
1234               compstr = path;
1235               compl = p - path;
1236               path = p + 1;
1237               while(*path == '/')
1238                 path++;
1239             }
1240           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1241             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1242               break;
1243           if (!i)
1244             {
1245               /* create new node */
1246               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1247               i = nmptree++;
1248               mptree[i].sibling = mptree[pos].child;
1249               mptree[i].child = 0;
1250               mptree[i].comp = compstr;
1251               mptree[i].compl = compl;
1252               mptree[i].mountpoint = -1;
1253               mptree[pos].child = i;
1254             }
1255           pos = i;
1256         }
1257       mptree[pos].mountpoint = mp;
1258     }
1259
1260   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1261
1262 #if 0
1263   for (i = 0; i < nmptree; i++)
1264     {
1265       printf("#%d sibling: %d\n", i, mptree[i].sibling);
1266       printf("#%d child: %d\n", i, mptree[i].child);
1267       printf("#%d comp: %s\n", i, mptree[i].comp);
1268       printf("#%d compl: %d\n", i, mptree[i].compl);
1269       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1270     }
1271 #endif
1272
1273   cbd.mptree = mptree;
1274   cbd.addsub = 1;
1275   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1276     {
1277       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1278         continue;
1279       if (!MAPTST(installedmap, sp))
1280         continue;
1281       cbd.hasdu = 0;
1282       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1283       if (!cbd.hasdu && oldinstalled)
1284         {
1285           Id op, opp;
1286           /* no du data available, ignore data of all installed solvables we obsolete */
1287           if (!ignoredu.map)
1288             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1289           if (s->obsoletes)
1290             {
1291               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1292               while ((obs = *obsp++) != 0)
1293                 FOR_PROVIDES(op, opp, obs)
1294                   if (op >= oldinstalled->start && op < oldinstalled->end)
1295                     MAPSET(&ignoredu, op - oldinstalled->start);
1296             }
1297           FOR_PROVIDES(op, opp, s->name)
1298             if (pool->solvables[op].name == s->name)
1299               if (op >= oldinstalled->start && op < oldinstalled->end)
1300                 MAPSET(&ignoredu, op - oldinstalled->start);
1301         }
1302     }
1303   cbd.addsub = -1;
1304   if (oldinstalled)
1305     {
1306       /* assumes we allways have du data for installed solvables */
1307       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1308         {
1309           if (MAPTST(installedmap, sp))
1310             continue;
1311           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1312             continue;
1313           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1314         }
1315     }
1316   if (ignoredu.map)
1317     map_free(&ignoredu);
1318   sat_free(cbd.dirmap);
1319   sat_free(mptree);
1320 }
1321
1322 int
1323 pool_calc_installsizechange(Pool *pool, Repo *oldinstalled, Map *installedmap)
1324 {
1325   Id sp;
1326   Solvable *s;
1327   int change = 0;
1328
1329   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1330     {
1331       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1332         continue;
1333       if (!MAPTST(installedmap, sp))
1334         continue;
1335       change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1336     }
1337   if (oldinstalled)
1338     {
1339       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1340         {
1341           if (MAPTST(installedmap, sp))
1342             continue;
1343           change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1344         }
1345     }
1346   return change;
1347 }
1348
1349 /* map:
1350  *  1: installed
1351  *  2: conflicts with installed
1352  *  8: interesting (only true if installed)
1353  * 16: undecided
1354  */
1355  
1356 static inline Id dep2name(Pool *pool, Id dep)
1357 {
1358   while (ISRELDEP(dep))
1359     {
1360       Reldep *rd = rd = GETRELDEP(pool, dep);
1361       dep = rd->name;
1362     }
1363   return dep;
1364 }
1365
1366 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep)
1367 {
1368   Id p, pp;
1369   int r = 0;
1370   FOR_PROVIDES(p, pp, dep)
1371     {
1372       if (p == SYSTEMSOLVABLE)
1373         return 1;       /* always boring, as never constraining */
1374       if ((map[p] & 9) == 9)
1375         return 9;
1376       r |= map[p] & 17;
1377     }
1378   return r;
1379 }
1380
1381 /*
1382  * pool_trivial_installable - calculate if a set of solvables is
1383  * trivial installable without any other installs/deinstalls of
1384  * packages not belonging to the set.
1385  *
1386  * the state is returned in the result queue:
1387  * 1:  solvable is installable without any other package changes
1388  * 0:  solvable is not installable
1389  * -1: solvable is installable, but doesn't constrain any installed packages
1390  */
1391
1392 void
1393 pool_trivial_installable(Pool *pool, Repo *oldinstalled, Map *installedmap, Queue *pkgs, Queue *res)
1394 {
1395   int i, r, m, did;
1396   Id p, *dp, con, *conp, req, *reqp;
1397   unsigned char *map;
1398   Solvable *s;
1399
1400   map = sat_calloc(pool->nsolvables, 1);
1401   for (p = 1; p < pool->nsolvables; p++)
1402     {
1403       if (!MAPTST(installedmap, p))
1404         continue;
1405       map[p] |= 9;
1406       s = pool->solvables + p;
1407       if (!s->conflicts)
1408         continue;
1409       conp = s->repo->idarraydata + s->conflicts;
1410       while ((con = *conp++) != 0)
1411         {
1412           dp = pool->whatprovidesdata + pool_whatprovides(pool, con);
1413           for (; *dp; dp++)
1414             map[p] |= 2;        /* XXX: self conflict ? */
1415         }
1416     }
1417   for (i = 0; i < pkgs->count; i++)
1418     map[pkgs->elements[i]] = 16;
1419
1420   for (i = 0, did = 0; did < pkgs->count; i++, did++)
1421     {
1422       if (i == pkgs->count)
1423         i = 0;
1424       p = pkgs->elements[i];
1425       if ((map[p] & 16) == 0)
1426         continue;
1427       if ((map[p] & 2) != 0)
1428         {
1429           map[p] = 2;
1430           continue;
1431         }
1432       s = pool->solvables + p;
1433       m = 1;
1434       if (s->requires)
1435         {
1436           reqp = s->repo->idarraydata + s->requires;
1437           while ((req = *reqp++) != 0)
1438             {
1439               if (req == SOLVABLE_PREREQMARKER)
1440                 continue;
1441               r = providedbyinstalled(pool, map, req);
1442               if (!r)
1443                 {
1444                   /* decided and miss */
1445                   map[p] = 2;
1446                   break;
1447                 }
1448               m |= r;   /* 1 | 9 | 16 | 17 */
1449             }
1450           if (req)
1451             continue;
1452           if ((m & 9) == 9)
1453             m = 9;
1454         }
1455       if (s->conflicts)
1456         {
1457           conp = s->repo->idarraydata + s->conflicts;
1458           while ((con = *conp++) != 0)
1459             {
1460               if ((providedbyinstalled(pool, map, con) & 1) != 0)
1461                 {
1462                   map[p] = 2;
1463                   break;
1464                 }
1465               if ((m == 1 || m == 17) && ISRELDEP(con))
1466                 {
1467                   con = dep2name(pool, con);
1468                   if ((providedbyinstalled(pool, map, con) & 1) != 0)
1469                     m = 9;
1470                 }
1471             }
1472           if (con)
1473             continue;   /* found a conflict */
1474         }
1475 #if 0
1476       if (s->repo && s->repo != oldinstalled)
1477         {
1478           Id p2, obs, *obsp, *pp;
1479           Solvable *s2;
1480           if (s->obsoletes)
1481             {
1482               obsp = s->repo->idarraydata + s->obsoletes;
1483               while ((obs = *obsp++) != 0)
1484                 {
1485                   if ((providedbyinstalled(pool, map, obs) & 1) != 0)
1486                     {
1487                       map[p] = 2;
1488                       break;
1489                     }
1490                 }
1491               if (obs)
1492                 continue;
1493             }
1494           FOR_PROVIDES(p2, pp, s->name)
1495             {
1496               s2 = pool->solvables + p2;
1497               if (s2->name == s->name && (map[p2] & 1) != 0)
1498                 {
1499                   map[p] = 2;
1500                   break;
1501                 }
1502             }
1503           if (p2)
1504             continue;
1505         }
1506 #endif
1507       if (m != map[p])
1508         {
1509           map[p] = m;
1510           did = 0;
1511         }
1512     }
1513   queue_free(res);
1514   queue_clone(res, pkgs);
1515   for (i = 0; i < pkgs->count; i++)
1516     {
1517       m = map[pkgs->elements[i]];
1518       if ((m & 9) == 9)
1519         r = 1;
1520       else if (m & 1)
1521         r = -1;
1522       else
1523         r = 0;
1524       res->elements[i] = r;
1525     }
1526   free(map);
1527 }
1528
1529 // EOF