2 * Copyright (c) 2014, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * normalize complex dependencies into CNF/DNF form
23 #ifdef ENABLE_COMPLEX_DEPS
28 pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
32 if (rd->flags == REL_AND || rd->flags == REL_COND) /* those two are the complex ones */
34 if (rd->flags != REL_OR)
36 if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name)))
38 if (!ISRELDEP(rd->evr))
40 rd = GETRELDEP(pool, rd->evr);
44 /* expand simple dependencies into package lists */
46 expand_simpledeps(Pool *pool, Queue *bq, int start, int split)
51 for (i = start; i < end; i++)
54 newsplit = bq->count - (end - start);
56 if (x == pool->nsolvables)
58 Id *dp = pool->whatprovidesdata + bq->elements[++i];
66 newsplit = bq->count - (end - start);
67 queue_deleten(bq, start, end - start);
73 print_depblocks(Pool *pool, Queue *bq, int start)
77 for (i = start; i < bq->count; i++)
79 if (bq->elements[i] == pool->nsolvables)
81 Id *dp = pool->whatprovidesdata + bq->elements[++i];
84 printf(" %s", pool_solvid2str(pool, *dp++));
87 else if (bq->elements[i] > 0)
88 printf(" %s", pool_solvid2str(pool, bq->elements[i]));
89 else if (bq->elements[i] < 0)
90 printf(" -%s", pool_solvid2str(pool, -bq->elements[i]));
98 /* invert all literals in the blocks. note that this also turns DNF into CNF and vice versa */
100 invert_depblocks(Pool *pool, Queue *bq, int start)
103 expand_simpledeps(pool, bq, start, 0);
105 for (i = j = start; i < end; i++)
109 bq->elements[i] = -bq->elements[i];
112 /* end of block reached, reverse */
116 for (k = i - 1; j < k; j++, k--)
118 Id t = bq->elements[j];
119 bq->elements[j] = bq->elements[k];
131 * -1: at least one block
134 normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
136 int bqcnt = bq->count;
138 int todnf = flags & CPLXDEPS_TODNF ? 1 : 0;
142 printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf);
144 if (pool_is_complex_dep(pool, dep))
146 Reldep *rd = GETRELDEP(pool, dep);
147 if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND)
149 int rdflags = rd->flags;
152 /* in inverted mode, COND means AND. otherwise it means OR NOT */
153 if (rdflags == REL_COND && todnf)
155 mode = rdflags == REL_AND ? 0 : 1;
157 /* get blocks of first argument */
158 r = normalize_dep(pool, rd->name, bq, flags);
161 if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0)
163 if (rdflags == REL_COND)
165 r = normalize_dep(pool, rd->evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
166 if (r == 0 || r == 1)
167 return r == 0 ? 1 : 0;
168 invert_depblocks(pool, bq, bqcnt); /* invert block for COND */
171 return normalize_dep(pool, rd->evr, bq, flags);
175 if (rdflags != REL_AND)
177 return normalize_dep(pool, rd->evr, bq, flags);
180 /* get blocks of second argument */
182 /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */
183 r = normalize_dep(pool, rd->evr, bq, rdflags == REL_COND ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags);
186 if (rdflags == REL_OR)
188 if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0)
190 queue_truncate(bq, bqcnt);
191 return rdflags == REL_COND ? 1 : 0;
195 if (rdflags == REL_OR)
197 queue_truncate(bq, bqcnt);
202 if (rdflags == REL_COND)
203 invert_depblocks(pool, bq, bqcnt2); /* invert 2nd block */
206 /* simple case: just join em. nothing more to do here. */
208 printf("SIMPLE JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
214 /* complex case: mix em */
217 printf("COMPLEX JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
219 bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2);
221 for (i = bqcnt; i < bqcnt2; i++)
223 for (j = bqcnt2; j < bqcnt3; j++)
226 int bqcnt4 = bq->count;
229 /* mix i block with j block, both blocks are sorted */
230 while (bq->elements[k] && bq->elements[j])
232 if (bq->elements[k] < bq->elements[j])
233 queue_push(bq, bq->elements[k++]);
236 if (bq->elements[k] == bq->elements[j])
238 queue_push(bq, bq->elements[j++]);
241 while (bq->elements[j])
242 queue_push(bq, bq->elements[j++]);
243 while (bq->elements[k])
244 queue_push(bq, bq->elements[k++]);
246 /* block is finished, check for A + -A */
247 for (a = bqcnt4, b = bq->count - 1; a < b; )
249 if (-bq->elements[a] == bq->elements[b])
251 if (-bq->elements[a] > bq->elements[b])
257 queue_truncate(bq, bqcnt4); /* ignore this block */
259 queue_push(bq, 0); /* finish block */
261 /* advance to next block */
262 while (bq->elements[i])
266 if (bqcnt3 == bq->count) /* ignored all blocks? */
268 queue_deleten(bq, bqcnt, bqcnt3 - bqcnt);
274 /* fallback case: just use package list */
275 dp = pool_whatprovides(pool, dep);
276 if (dp <= 2 || !pool->whatprovidesdata[dp])
277 return dp == 2 ? 1 : 0;
278 if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
281 if ((flags & CPLXDEPS_NAME) != 0)
283 while ((p = pool->whatprovidesdata[dp++]) != 0)
285 if (!pool_match_nevr(pool, pool->solvables + p, dep))
294 while ((p = pool->whatprovidesdata[dp++]) != 0)
295 queue_push2(bq, p, 0);
298 queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker + offset */
299 if (bq->count == bqcnt)
300 return 0; /* no provider */
302 queue_push(bq, 0); /* finish block */
307 pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags)
309 int i, bqcnt = bq->count;
311 i = normalize_dep(pool, dep, bq, flags);
312 if ((flags & CPLXDEPS_EXPAND) != 0)
314 if (i != 0 && i != 1)
315 expand_simpledeps(pool, bq, bqcnt, 0);
317 if ((flags & CPLXDEPS_INVERT) != 0)
319 if (i == 0 || i == 1)
322 invert_depblocks(pool, bq, bqcnt);
330 print_depblocks(pool, bq, bqcnt);
335 #endif /* ENABLE_COMPLEX_DEPS */