Bug Summary

File:ext/testcase.c
Warning:line 1457, column 32
Access to field 'conflicts' results in a dereference of a null pointer (loaded from variable 's')

Annotated Source Code

1/*
2 * Copyright (c) 2012, Novell Inc.
3 *
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
6 */
7
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <errno(*__errno_location ()).h>
14
15#include "pool.h"
16#include "poolarch.h"
17#include "poolvendor.h"
18#include "repo.h"
19#include "repo_solv.h"
20#include "solver.h"
21#include "solverdebug.h"
22#include "chksum.h"
23#include "testcase.h"
24#include "selection.h"
25#include "solv_xfopen.h"
26#if ENABLE_TESTCASE_HELIXREPO
27#include "ext/repo_helix.h"
28#endif
29
30#define DISABLE_JOIN2
31#include "tools_util.h"
32
33static struct job2str {
34 Id job;
35 const char *str;
36} job2str[] = {
37 { SOLVER_NOOP0x0000, "noop" },
38 { SOLVER_INSTALL0x0100, "install" },
39 { SOLVER_ERASE0x0200, "erase" },
40 { SOLVER_UPDATE0x0300, "update" },
41 { SOLVER_WEAKENDEPS0x0400, "weakendeps" },
42 { SOLVER_MULTIVERSION0x0500, "multiversion" },
43 { SOLVER_MULTIVERSION0x0500, "noobsoletes" }, /* old name */
44 { SOLVER_LOCK0x0600, "lock" },
45 { SOLVER_DISTUPGRADE0x0700, "distupgrade" },
46 { SOLVER_VERIFY0x0800, "verify" },
47 { SOLVER_DROP_ORPHANED0x0900, "droporphaned" },
48 { SOLVER_USERINSTALLED0x0a00, "userinstalled" },
49 { SOLVER_ALLOWUNINSTALL0x0b00, "allowuninstall" },
50 { SOLVER_FAVOR0x0c00, "favor" },
51 { SOLVER_DISFAVOR0x0d00, "disfavor" },
52 { 0, 0 }
53};
54
55static struct jobflags2str {
56 Id flag;
57 const char *str;
58} jobflags2str[] = {
59 { SOLVER_WEAK0x010000, "weak" },
60 { SOLVER_ESSENTIAL0x020000, "essential" },
61 { SOLVER_CLEANDEPS0x040000, "cleandeps" },
62 { SOLVER_ORUPDATE0x080000, "orupdate" },
63 { SOLVER_FORCEBEST0x100000, "forcebest" },
64 { SOLVER_TARGETED0x200000, "targeted" },
65 { SOLVER_NOTBYUSER0x400000, "notbyuser" },
66 { SOLVER_SETEV0x01000000, "setev" },
67 { SOLVER_SETEVR0x02000000, "setevr" },
68 { SOLVER_SETARCH0x04000000, "setarch" },
69 { SOLVER_SETVENDOR0x08000000, "setvendor" },
70 { SOLVER_SETREPO0x10000000, "setrepo" },
71 { SOLVER_NOAUTOSET0x20000000, "noautoset" },
72 { 0, 0 }
73};
74
75static struct resultflags2str {
76 Id flag;
77 const char *str;
78} resultflags2str[] = {
79 { TESTCASE_RESULT_TRANSACTION(1 << 0), "transaction" },
80 { TESTCASE_RESULT_PROBLEMS(1 << 1), "problems" },
81 { TESTCASE_RESULT_ORPHANED(1 << 2), "orphaned" },
82 { TESTCASE_RESULT_RECOMMENDED(1 << 3), "recommended" },
83 { TESTCASE_RESULT_UNNEEDED(1 << 4), "unneeded" },
84 { TESTCASE_RESULT_ALTERNATIVES(1 << 5), "alternatives" },
85 { TESTCASE_RESULT_RULES(1 << 6), "rules" },
86 { TESTCASE_RESULT_GENID(1 << 7), "genid" },
87 { TESTCASE_RESULT_REASON(1 << 8), "reason" },
88 { 0, 0 }
89};
90
91static struct solverflags2str {
92 Id flag;
93 const char *str;
94 int def;
95} solverflags2str[] = {
96 { SOLVER_FLAG_ALLOW_DOWNGRADE1, "allowdowngrade", 0 },
97 { SOLVER_FLAG_ALLOW_NAMECHANGE10, "allownamechange", 1 },
98 { SOLVER_FLAG_ALLOW_ARCHCHANGE2, "allowarchchange", 0 },
99 { SOLVER_FLAG_ALLOW_VENDORCHANGE3, "allowvendorchange", 0 },
100 { SOLVER_FLAG_ALLOW_UNINSTALL4, "allowuninstall", 0 },
101 { SOLVER_FLAG_NO_UPDATEPROVIDE5, "noupdateprovide", 0 },
102 { SOLVER_FLAG_SPLITPROVIDES6, "splitprovides", 0 },
103 { SOLVER_FLAG_IGNORE_RECOMMENDED7, "ignorerecommended", 0 },
104 { SOLVER_FLAG_ADD_ALREADY_RECOMMENDED8, "addalreadyrecommended", 0 },
105 { SOLVER_FLAG_NO_INFARCHCHECK9, "noinfarchcheck", 0 },
106 { SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES11, "keepexplicitobsoletes", 0 },
107 { SOLVER_FLAG_BEST_OBEY_POLICY12, "bestobeypolicy", 0 },
108 { SOLVER_FLAG_NO_AUTOTARGET13, "noautotarget", 0 },
109 { SOLVER_FLAG_DUP_ALLOW_DOWNGRADE14, "dupallowdowngrade", 1 },
110 { SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE15, "dupallowarchchange", 1 },
111 { SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE16, "dupallowvendorchange", 1 },
112 { SOLVER_FLAG_DUP_ALLOW_NAMECHANGE17, "dupallownamechange", 1 },
113 { SOLVER_FLAG_KEEP_ORPHANS18, "keeporphans", 0 },
114 { SOLVER_FLAG_BREAK_ORPHANS19, "breakorphans", 0 },
115 { SOLVER_FLAG_FOCUS_INSTALLED20, "focusinstalled", 0 },
116 { SOLVER_FLAG_YUM_OBSOLETES21, "yumobsoletes", 0 },
117 { SOLVER_FLAG_NEED_UPDATEPROVIDE22, "needupdateprovide", 0 },
118 { SOLVER_FLAG_URPM_REORDER23, "urpmreorder", 0 },
119 { SOLVER_FLAG_FOCUS_BEST24, "focusbest", 0 },
120 { SOLVER_FLAG_STRONG_RECOMMENDS25, "strongrecommends", 0 },
121 { SOLVER_FLAG_INSTALL_ALSO_UPDATES26, "installalsoupdates", 0 },
122 { 0, 0, 0 }
123};
124
125static struct poolflags2str {
126 Id flag;
127 const char *str;
128 int def;
129} poolflags2str[] = {
130 { POOL_FLAG_PROMOTEEPOCH1, "promoteepoch", 0 },
131 { POOL_FLAG_FORBIDSELFCONFLICTS2, "forbidselfconflicts", 0 },
132 { POOL_FLAG_OBSOLETEUSESPROVIDES3, "obsoleteusesprovides", 0 },
133 { POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES4, "implicitobsoleteusesprovides", 0 },
134 { POOL_FLAG_OBSOLETEUSESCOLORS5, "obsoleteusescolors", 0 },
135 { POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS10, "implicitobsoleteusescolors", 0 },
136 { POOL_FLAG_NOINSTALLEDOBSOLETES6, "noinstalledobsoletes", 0 },
137 { POOL_FLAG_HAVEDISTEPOCH7, "havedistepoch", 0 },
138 { POOL_FLAG_NOOBSOLETESMULTIVERSION8, "noobsoletesmultiversion", 0 },
139 { POOL_FLAG_ADDFILEPROVIDESFILTERED9, "addfileprovidesfiltered", 0 },
140 { POOL_FLAG_NOWHATPROVIDESAUX11, "nowhatprovidesaux", 0 },
141 { 0, 0, 0 }
142};
143
144static struct disttype2str {
145 Id type;
146 const char *str;
147} disttype2str[] = {
148 { DISTTYPE_RPM0, "rpm" },
149 { DISTTYPE_DEB1, "deb" },
150 { DISTTYPE_ARCH2, "arch" },
151 { DISTTYPE_HAIKU3, "haiku" },
152 { 0, 0 }
153};
154
155static struct selflags2str {
156 Id flag;
157 const char *str;
158} selflags2str[] = {
159 { SELECTION_NAME(1 << 0), "name" },
160 { SELECTION_PROVIDES(1 << 1), "provides" },
161 { SELECTION_FILELIST(1 << 2), "filelist" },
162 { SELECTION_CANON(1 << 3), "canon" },
163 { SELECTION_DOTARCH(1 << 4), "dotarch" },
164 { SELECTION_REL(1 << 5), "rel" },
165 { SELECTION_INSTALLED_ONLY(1 << 8), "installedonly" },
166 { SELECTION_GLOB(1 << 9), "glob" },
167 { SELECTION_FLAT(1 << 10), "flat" },
168 { SELECTION_NOCASE(1 << 11), "nocase" },
169 { SELECTION_SOURCE_ONLY(1 << 12), "sourceonly" },
170 { SELECTION_WITH_SOURCE(1 << 13), "withsource" },
171 { 0, 0 }
172};
173
174static const char *features[] = {
175#ifdef ENABLE_LINKED_PKGS
176 "linked_packages",
177#endif
178#ifdef ENABLE_COMPLEX_DEPS
179 "complex_deps",
180#endif
181#if ENABLE_TESTCASE_HELIXREPO
182 "testcase_helixrepo",
183#endif
184 0
185};
186
187typedef struct strqueue {
188 char **str;
189 int nstr;
190} Strqueue;
191
192#define STRQUEUE_BLOCK63 63
193
194static void
195strqueue_init(Strqueue *q)
196{
197 q->str = 0;
198 q->nstr = 0;
199}
200
201static void
202strqueue_free(Strqueue *q)
203{
204 int i;
205 for (i = 0; i < q->nstr; i++)
206 solv_free(q->str[i]);
207 q->str = solv_free(q->str);
208 q->nstr = 0;
209}
210
211static void
212strqueue_push(Strqueue *q, const char *s)
213{
214 q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK63);
215 q->str[q->nstr++] = solv_strdup(s);
216}
217
218static void
219strqueue_pushjoin(Strqueue *q, const char *s1, const char *s2, const char *s3)
220{
221 q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK63);
222 q->str[q->nstr++] = solv_dupjoin(s1, s2, s3);
223}
224
225static int
226strqueue_sort_cmp(const void *ap, const void *bp, void *dp)
227{
228 const char *a = *(const char **)ap;
229 const char *b = *(const char **)bp;
230 return strcmp(a ? a : "", b ? b : "");
231}
232
233static void
234strqueue_sort(Strqueue *q)
235{
236 if (q->nstr > 1)
237 solv_sort(q->str, q->nstr, sizeof(*q->str), strqueue_sort_cmp, 0);
238}
239
240static void
241strqueue_sort_u(Strqueue *q)
242{
243 int i, j;
244 strqueue_sort(q);
245 for (i = j = 0; i < q->nstr; i++)
246 if (!j || strqueue_sort_cmp(q->str + i, q->str + j - 1, 0) != 0)
247 q->str[j++] = q->str[i];
248 q->nstr = j;
249}
250
251static char *
252strqueue_join(Strqueue *q)
253{
254 int i, l = 0;
255 char *r, *rp;
256 for (i = 0; i < q->nstr; i++)
257 if (q->str[i])
258 l += strlen(q->str[i]) + 1;
259 l++; /* trailing \0 */
260 r = solv_malloc(l);
261 rp = r;
262 for (i = 0; i < q->nstr; i++)
263 if (q->str[i])
264 {
265 strcpy(rp, q->str[i]);
266 rp += strlen(rp);
267 *rp++ = '\n';
268 }
269 *rp = 0;
270 return r;
271}
272
273static void
274strqueue_split(Strqueue *q, const char *s)
275{
276 const char *p;
277 if (!s)
278 return;
279 while ((p = strchr(s, '\n')) != 0)
280 {
281 q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK63);
282 q->str[q->nstr] = solv_malloc(p - s + 1);
283 if (p > s)
284 memcpy(q->str[q->nstr], s, p - s);
285 q->str[q->nstr][p - s] = 0;
286 q->nstr++;
287 s = p + 1;
288 }
289 if (*s)
290 strqueue_push(q, s);
291}
292
293static void
294strqueue_diff(Strqueue *sq1, Strqueue *sq2, Strqueue *osq)
295{
296 int i = 0, j = 0;
297 while (i < sq1->nstr && j < sq2->nstr)
298 {
299 int r = strqueue_sort_cmp(sq1->str + i, sq2->str + j, 0);
300 if (!r)
301 i++, j++;
302 else if (r < 0)
303 strqueue_pushjoin(osq, "-", sq1->str[i++], 0);
304 else
305 strqueue_pushjoin(osq, "+", sq2->str[j++], 0);
306 }
307 while (i < sq1->nstr)
308 strqueue_pushjoin(osq, "-", sq1->str[i++], 0);
309 while (j < sq2->nstr)
310 strqueue_pushjoin(osq, "+", sq2->str[j++], 0);
311}
312
313
314static const char *
315testcase_id2str(Pool *pool, Id id, int isname)
316{
317 const char *s = pool_id2str(pool, id);
318 const char *ss;
319 char *s2, *s2p;
320 int bad = 0, paren = 0, parenbad = 0;
321
322 if (id == 0)
323 return "<NULL>";
324 if (id == 1)
325 return "\\00";
326 if (strchr("[(<=>!", *s))
327 bad++;
328 if (!strncmp(s, "namespace:", 10))
329 bad++;
330 for (ss = s + bad; *ss; ss++)
331 {
332 if (*ss == ' ' || *ss == '\\' || *(unsigned char *)ss < 32 || *ss == '(' || *ss == ')')
333 bad++;
334 if (*ss == '(')
335 paren = paren == 0 ? 1 : -1;
336 else if (*ss == ')')
337 {
338 paren = paren == 1 ? 0 : -1;
339 if (!paren)
340 parenbad += 2;
341 }
342 }
343 if (isname && ss - s > 4 && !strcmp(ss - 4, ":any"))
344 bad++;
345 if (!paren && !(bad - parenbad))
346 return s;
347
348 /* we need escaping! */
349 s2 = s2p = pool_alloctmpspace(pool, strlen(s) + bad * 2 + 1);
350 if (!strncmp(s, "namespace:", 10))
351 {
352 strcpy(s2p, "namespace\\3a");
353 s2p += 12;
354 s += 10;
355 }
356 ss = s;
357 for (; *ss; ss++)
358 {
359 *s2p++ = *ss;
360 if ((ss == s && strchr("[(<=>!", *s)) || *ss == ' ' || *ss == '\\' || *(unsigned char *)ss < 32 || *ss == '(' || *ss == ')')
361 {
362 s2p[-1] = '\\';
363 solv_bin2hex((unsigned char *)ss, 1, s2p);
364 s2p += 2;
365 }
366 }
367 *s2p = 0;
368 if (isname && s2p - s2 > 4 && !strcmp(s2p - 4, ":any"))
369 strcpy(s2p - 4, "\\3aany");
370 return s2;
371}
372
373struct oplist {
374 Id flags;
375 const char *opname;
376} oplist[] = {
377 { REL_EQ2, "=" },
378 { REL_GT1 | REL_LT4 | REL_EQ2, "<=>" },
379 { REL_LT4 | REL_EQ2, "<=" },
380 { REL_GT1 | REL_EQ2, ">=" },
381 { REL_GT1, ">" },
382 { REL_GT1 | REL_LT4, "<>" },
383 { REL_AND16, "&" },
384 { REL_OR17 , "|" },
385 { REL_WITH18 , "+" },
386 { REL_NAMESPACE19 , "<NAMESPACE>" },
387 { REL_ARCH20, "." },
388 { REL_MULTIARCH25, "<MULTIARCH>" },
389 { REL_FILECONFLICT21, "<FILECONFLICT>" },
390 { REL_COND22, "<IF>" },
391 { REL_COMPAT23, "compat >=" },
392 { REL_KIND24, "<KIND>" },
393 { REL_ELSE26, "<ELSE>" },
394 { REL_ERROR27, "<ERROR>" },
395 { REL_LT4, "<" },
396 { 0, 0 }
397};
398
399static char *
400testcase_dep2str_complex(Pool *pool, char *s, Id id, int addparens)
401{
402 Reldep *rd;
403 const char *s2;
404 int needparens;
405 struct oplist *op;
406
407 if (!ISRELDEP(id)(((id) & 0x80000000) != 0))
408 {
409 s2 = testcase_id2str(pool, id, 1);
410 s = pool_tmpappend(pool, s, s2, 0);
411 pool_freetmpspace(pool, s2);
412 return s;
413 }
414 rd = GETRELDEP(pool, id)((pool)->rels + ((id) ^ 0x80000000));
415
416 /* check for special shortcuts */
417 if (rd->flags == REL_NAMESPACE19 && !ISRELDEP(rd->name)(((rd->name) & 0x80000000) != 0) && !strncmp(pool_id2str(pool, rd->name), "namespace:", 10))
418 {
419 s = pool_tmpappend(pool, s, pool_id2str(pool, rd->name), "(");
420 s = testcase_dep2str_complex(pool, s, rd->evr, 0);
421 return pool_tmpappend(pool, s, ")", 0);
422 }
423 if (rd->flags == REL_MULTIARCH25 && !ISRELDEP(rd->name)(((rd->name) & 0x80000000) != 0) && rd->evr == ARCH_ANY)
424 {
425 /* append special :any suffix */
426 s2 = testcase_id2str(pool, rd->name, 1);
427 s = pool_tmpappend(pool, s, s2, ":any");
428 pool_freetmpspace(pool, s2);
429 return s;
430 }
431
432 needparens = 0;
433 if (ISRELDEP(rd->name)(((rd->name) & 0x80000000) != 0))
434 {
435 Reldep *rd2 = GETRELDEP(pool, rd->name)((pool)->rels + ((rd->name) ^ 0x80000000));
436 needparens = 1;
437 if (rd->flags > 7 && rd->flags != REL_COMPAT23 && rd2->flags && rd2->flags <= 7)
438 needparens = 0;
439 }
440
441 if (addparens)
442 s = pool_tmpappend(pool, s, "(", 0);
443 s = testcase_dep2str_complex(pool, s, rd->name, needparens);
444
445 for (op = oplist; op->flags; op++)
446 if (rd->flags == op->flags)
447 break;
448 if (op->flags)
449 {
450 s = pool_tmpappend(pool, s, " ", op->opname);
451 s = pool_tmpappend(pool, s, " ", 0);
452 }
453 else
454 {
455 char buf[64];
456 sprintf(buf, " <%u> ", rd->flags);
457 s = pool_tmpappend(pool, s, buf, 0);
458 }
459
460 needparens = 0;
461 if (ISRELDEP(rd->evr)(((rd->evr) & 0x80000000) != 0))
462 {
463 Reldep *rd2 = GETRELDEP(pool, rd->evr)((pool)->rels + ((rd->evr) ^ 0x80000000));
464 needparens = 1;
465 if (rd->flags > 7 && rd2->flags && rd2->flags <= 7)
466 needparens = 0;
467 if (rd->flags == REL_AND16 && rd2->flags == REL_AND16)
468 needparens = 0; /* chain */
469 if (rd->flags == REL_OR17 && rd2->flags == REL_OR17)
470 needparens = 0; /* chain */
471 if (rd->flags > 0 && rd->flags < 8 && rd2->flags == REL_COMPAT23)
472 needparens = 0; /* chain */
473 }
474 if (!ISRELDEP(rd->evr)(((rd->evr) & 0x80000000) != 0))
475 {
476 s2 = testcase_id2str(pool, rd->evr, 0);
477 s = pool_tmpappend(pool, s, s2, 0);
478 pool_freetmpspace(pool, s2);
479 }
480 else
481 s = (char *)testcase_dep2str_complex(pool, s, rd->evr, needparens);
482 if (addparens)
483 s = pool_tmpappend(pool, s, ")", 0);
484 return s;
485}
486
487const char *
488testcase_dep2str(Pool *pool, Id id)
489{
490 char *s;
491 if (!ISRELDEP(id)(((id) & 0x80000000) != 0))
492 return testcase_id2str(pool, id, 1);
493 s = pool_alloctmpspace(pool, 1);
494 *s = 0;
495 return testcase_dep2str_complex(pool, s, id, 0);
496}
497
498
499/* Convert a simple string. Also handle the :any suffix */
500static Id
501testcase_str2dep_simple(Pool *pool, const char **sp, int isname)
502{
503 int haveesc = 0;
504 int paren = 0;
505 int isany = 0;
506 Id id;
507 const char *s;
508 for (s = *sp; *s; s++)
509 {
510 if (*s == '\\')
511 haveesc++;
512 if (*s == ' ' || *(unsigned char *)s < 32)
513 break;
514 if (*s == '(')
515 paren++;
516 if (*s == ')' && paren-- <= 0)
517 break;
518 }
519 if (isname && s - *sp > 4 && !strncmp(s - 4, ":any", 4))
520 {
521 isany = 1;
522 s -= 4;
523 }
524 if (!haveesc)
525 {
526 if (s - *sp == 6 && !strncmp(*sp, "<NULL>", 6))
527 id = 0;
528 else
529 id = pool_strn2id(pool, *sp, s - *sp, 1);
530 }
531 else if (s - *sp == 3 && !strncmp(*sp, "\\00", 3))
532 id = 1;
533 else
534 {
535 char buf[128], *bp, *bp2;
536 const char *sp2;
537 bp = s - *sp >= 128 ? solv_malloc(s - *sp + 1) : buf;
538 for (bp2 = bp, sp2 = *sp; sp2 < s;)
539 {
540 *bp2++ = *sp2++;
541 if (bp2[-1] == '\\')
542 solv_hex2bin(&sp2, (unsigned char *)bp2 - 1, 1);
543 }
544 *bp2 = 0;
545 id = pool_str2id(pool, bp, 1);
546 if (bp != buf)
547 solv_free(bp);
548 }
549 if (isany)
550 {
551 id = pool_rel2id(pool, id, ARCH_ANY, REL_MULTIARCH25, 1);
552 s += 4;
553 }
554 *sp = s;
555 return id;
556}
557
558
559static Id
560testcase_str2dep_complex(Pool *pool, const char **sp, int relop)
561{
562 const char *s = *sp;
563 Id flags, id, id2, namespaceid = 0;
564 struct oplist *op;
565
566 while (*s == ' ' || *s == '\t')
567 s++;
568 if (!strncmp(s, "namespace:", 10))
569 {
570 /* special namespace hack */
571 const char *s2;
572 for (s2 = s + 10; *s2 && *s2 != '('; s2++)
573 ;
574 if (*s2 == '(')
575 {
576 namespaceid = pool_strn2id(pool, s, s2 - s, 1);
577 s = s2;
578 }
579 }
580 if (*s == '(')
581 {
582 s++;
583 id = testcase_str2dep_complex(pool, &s, 0);
584 if (!s || *s != ')')
585 {
586 *sp = 0;
587 return 0;
588 }
589 s++;
590 }
591 else
592 id = testcase_str2dep_simple(pool, &s, relop ? 0 : 1);
593 if (namespaceid)
594 id = pool_rel2id(pool, namespaceid, id, REL_NAMESPACE19, 1);
595
596 for (;;)
597 {
598 while (*s == ' ' || *s == '\t')
599 s++;
600 if (!*s || *s == ')' || (relop && strncmp(s, "compat >= ", 10) != 0))
601 {
602 *sp = s;
603 return id;
604 }
605
606 /* we have an op! Find the end */
607 flags = -1;
608 if (s[0] == '<' && (s[1] >= '0' && s[1] <= '9'))
609 {
610 const char *s2;
611 for (s2 = s + 1; *s2 >= '0' && *s2 <= '9'; s2++)
612 ;
613 if (*s2 == '>')
614 {
615 flags = strtoul(s + 1, 0, 10);
616 s = s2 + 1;
617 }
618 }
619 if (flags == -1)
620 {
621 for (op = oplist; op->flags; op++)
622 if (!strncmp(s, op->opname, strlen(op->opname)))
623 break;
624 if (!op->flags)
625 {
626 *sp = 0;
627 return 0;
628 }
629 flags = op->flags;
630 s += strlen(op->opname);
631 }
632 id2 = testcase_str2dep_complex(pool, &s, flags > 0 && flags < 8);
633 if (!s)
634 {
635 *sp = 0;
636 return 0;
637 }
638 id = pool_rel2id(pool, id, id2, flags, 1);
639 }
640}
641
642Id
643testcase_str2dep(Pool *pool, const char *s)
644{
645 Id id = testcase_str2dep_complex(pool, &s, 0);
646 return s && !*s ? id : 0;
647}
648
649/**********************************************************/
650
651const char *
652testcase_repoid2str(Pool *pool, Id repoid)
653{
654 Repo *repo = pool_id2repo(pool, repoid);
655 if (repo->name)
656 {
657 char *r = pool_tmpjoin(pool, repo->name, 0, 0);
658 char *rp;
659 for (rp = r; *rp; rp++)
660 if (*rp == ' ' || *rp == '\t')
661 *rp = '_';
662 return r;
663 }
664 else
665 {
666 char buf[20];
667 sprintf(buf, "#%d", repoid);
668 return pool_tmpjoin(pool, buf, 0, 0);
669 }
670}
671
672const char *
673testcase_solvid2str(Pool *pool, Id p)
674{
675 Solvable *s = pool->solvables + p;
676 const char *n, *e, *a;
677 char *str, buf[20];
678
679 if (p == SYSTEMSOLVABLE1)
680 return "@SYSTEM";
681 n = pool_id2str(pool, s->name);
682 e = pool_id2str(pool, s->evr);
683 a = pool_id2str(pool, s->arch);
684 str = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
685 sprintf(str, "%s-%s.%s", n, e, a);
686 if (!s->repo)
687 return pool_tmpappend(pool, str, "@", 0);
688 if (s->repo->name)
689 {
690 int l = strlen(str);
691 char *str2 = pool_tmpappend(pool, str, "@", s->repo->name);
692 for (; str2[l]; l++)
693 if (str2[l] == ' ' || str2[l] == '\t')
694 str2[l] = '_';
695 return str2;
696 }
697 sprintf(buf, "@#%d", s->repo->repoid);
698 return pool_tmpappend(pool, str, buf, 0);
699}
700
701Repo *
702testcase_str2repo(Pool *pool, const char *str)
703{
704 int repoid;
705 Repo *repo = 0;
706 if (str[0] == '#' && (str[1] >= '0' && str[1] <= '9'))
707 {
708 int j;
709 repoid = 0;
710 for (j = 1; str[j] >= '0' && str[j] <= '9'; j++)
711 repoid = repoid * 10 + (str[j] - '0');
712 if (!str[j] && repoid > 0 && repoid < pool->nrepos)
713 repo = pool_id2repo(pool, repoid);
714 }
715 if (!repo)
716 {
717 FOR_REPOS(repoid, repo)for (repoid = 1; repoid < pool->nrepos; repoid++) if ((
repo = pool->repos[repoid]) == 0) continue; else
718 {
719 int i, l;
720 if (!repo->name)
721 continue;
722 l = strlen(repo->name);
723 for (i = 0; i < l; i++)
724 {
725 int c = repo->name[i];
726 if (c == ' ' || c == '\t')
727 c = '_';
728 if (c != str[i])
729 break;
730 }
731 if (i == l && !str[l])
732 break;
733 }
734 if (repoid >= pool->nrepos)
735 repo = 0;
736 }
737 return repo;
738}
739
740Id
741testcase_str2solvid(Pool *pool, const char *str)
742{
743 int i, l = strlen(str);
744 int repostart;
745 Repo *repo;
746 Id arch;
747
748 if (!l)
749 return 0;
750 if (*str == '@' && !strcmp(str, "@SYSTEM"))
751 return SYSTEMSOLVABLE1;
752 repo = 0;
753 for (i = l - 1; i >= 0; i--)
754 if (str[i] == '@' && (repo = testcase_str2repo(pool, str + i + 1)) != 0)
755 break;
756 if (i < 0)
757 i = l;
758 repostart = i;
759 /* now find the arch (if present) */
760 arch = 0;
761 for (i = repostart - 1; i > 0; i--)
762 if (str[i] == '.')
763 {
764 arch = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
765 if (arch)
766 repostart = i;
767 break;
768 }
769 /* now find the name */
770 for (i = repostart - 1; i > 0; i--)
771 {
772 if (str[i] == '-')
773 {
774 Id nid, evrid, p, pp;
775 nid = pool_strn2id(pool, str, i, 0);
776 if (!nid)
777 continue;
778 evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
779 if (!evrid)
780 continue;
781 /* first check whatprovides */
782 FOR_PROVIDES(p, pp, nid)for (pp = pool_whatprovides(pool, nid) ; (p = pool->whatprovidesdata
[pp++]) != 0; )
783 {
784 Solvable *s = pool->solvables + p;
785 if (s->name != nid || s->evr != evrid)
786 continue;
787 if (repo && s->repo != repo)
788 continue;
789 if (arch && s->arch != arch)
790 continue;
791 return p;
792 }
793 /* maybe it's not installable and thus not in whatprovides. do a slow search */
794 if (repo)
795 {
796 Solvable *s;
797 FOR_REPO_SOLVABLES(repo, p, s)for (p = (repo)->start, s = (repo)->pool->solvables +
p; p < (repo)->end; p++, s = (repo)->pool->solvables
+ p) if (s->repo != (repo)) continue; else
798 {
799 if (s->name != nid || s->evr != evrid)
800 continue;
801 if (arch && s->arch != arch)
802 continue;
803 return p;
804 }
805 }
806 else
807 {
808 FOR_POOL_SOLVABLES(p)for (p = 2; p < pool->nsolvables; p++) if (pool->solvables
[p].repo == 0) continue; else
809 {
810 Solvable *s = pool->solvables + p;
811 if (s->name != nid || s->evr != evrid)
812 continue;
813 if (arch && s->arch != arch)
814 continue;
815 return p;
816 }
817 }
818 }
819 }
820 return 0;
821}
822
823const char *
824testcase_job2str(Pool *pool, Id how, Id what)
825{
826 char *ret;
827 const char *jobstr;
828 const char *selstr;
829 const char *pkgstr;
830 int i, o;
831 Id select = how & SOLVER_SELECTMASK0xff;
832
833 for (i = 0; job2str[i].str; i++)
834 if ((how & SOLVER_JOBMASK0xff00) == job2str[i].job)
835 break;
836 jobstr = job2str[i].str ? job2str[i].str : "unknown";
837 if (select == SOLVER_SOLVABLE0x01)
838 {
839 selstr = " pkg ";
840 pkgstr = testcase_solvid2str(pool, what);
841 }
842 else if (select == SOLVER_SOLVABLE_NAME0x02)
843 {
844 selstr = " name ";
845 pkgstr = testcase_dep2str(pool, what);
846 }
847 else if (select == SOLVER_SOLVABLE_PROVIDES0x03)
848 {
849 selstr = " provides ";
850 pkgstr = testcase_dep2str(pool, what);
851 }
852 else if (select == SOLVER_SOLVABLE_ONE_OF0x04)
853 {
854 Id p;
855 selstr = " oneof ";
856 pkgstr = 0;
857 while ((p = pool->whatprovidesdata[what++]) != 0)
858 {
859 const char *s = testcase_solvid2str(pool, p);
860 if (pkgstr)
861 {
862 pkgstr = pool_tmpappend(pool, pkgstr, " ", s);
863 pool_freetmpspace(pool, s);
864 }
865 else
866 pkgstr = s;
867 }
868 if (!pkgstr)
869 pkgstr = "nothing";
870 }
871 else if (select == SOLVER_SOLVABLE_REPO0x05)
872 {
873 Repo *repo = pool_id2repo(pool, what);
874 selstr = " repo ";
875 if (!repo->name)
876 {
877 char buf[20];
878 sprintf(buf, "#%d", repo->repoid);
879 pkgstr = pool_tmpjoin(pool, buf, 0, 0);
880 }
881 else
882 pkgstr = pool_tmpjoin(pool, repo->name, 0, 0);
883 }
884 else if (select == SOLVER_SOLVABLE_ALL0x06)
885 {
886 selstr = " all ";
887 pkgstr = "packages";
888 }
889 else
890 {
891 selstr = " unknown ";
892 pkgstr = "unknown";
893 }
894 ret = pool_tmpjoin(pool, jobstr, selstr, pkgstr);
895 o = strlen(ret);
896 ret = pool_tmpappend(pool, ret, " ", 0);
897 for (i = 0; jobflags2str[i].str; i++)
898 if ((how & jobflags2str[i].flag) != 0)
899 ret = pool_tmpappend(pool, ret, ",", jobflags2str[i].str);
900 if (!ret[o + 1])
901 ret[o] = 0;
902 else
903 {
904 ret[o + 1] = '[';
905 ret = pool_tmpappend(pool, ret, "]", 0);
906 }
907 return ret;
908}
909
910static int
911str2selflags(Pool *pool, char *s) /* modifies the string! */
912{
913 int i, selflags = 0;
914 while (s)
915 {
916 char *se = strchr(s, ',');
917 if (se)
918 *se++ = 0;
919 for (i = 0; selflags2str[i].str; i++)
920 if (!strcmp(s, selflags2str[i].str))
921 {
922 selflags |= selflags2str[i].flag;
923 break;
924 }
925 if (!selflags2str[i].str)
926 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown selection flag '%s'\n", s);
927 s = se;
928 }
929 return selflags;
930}
931
932static int
933str2jobflags(Pool *pool, char *s) /* modifies the string */
934{
935 int i, jobflags = 0;
936 while (s)
937 {
938 char *se = strchr(s, ',');
939 if (se)
940 *se++ = 0;
941 for (i = 0; jobflags2str[i].str; i++)
942 if (!strcmp(s, jobflags2str[i].str))
943 {
944 jobflags |= jobflags2str[i].flag;
945 break;
946 }
947 if (!jobflags2str[i].str)
948 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown job flag '%s'\n", s);
949 s = se;
950 }
951 return jobflags;
952}
953
954Id
955testcase_str2job(Pool *pool, const char *str, Id *whatp)
956{
957 int i;
958 Id job;
959 Id what;
960 char *s;
961 char **pieces = 0;
962 int npieces = 0;
963
964 *whatp = 0;
965 /* so we can patch it */
966 s = pool_tmpjoin(pool, str, 0, 0);
967 /* split it in pieces */
968 for (;;)
969 {
970 while (*s == ' ' || *s == '\t')
971 s++;
972 if (!*s)
973 break;
974 pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
975 pieces[npieces++] = s;
976 while (*s && *s != ' ' && *s != '\t')
977 s++;
978 if (*s)
979 *s++ = 0;
980 }
981 if (npieces < 3)
982 {
983 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: bad line '%s'\n", str);
984 solv_free(pieces);
985 return -1;
986 }
987
988 for (i = 0; job2str[i].str; i++)
989 if (!strcmp(pieces[0], job2str[i].str))
990 break;
991 if (!job2str[i].str)
992 {
993 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown job '%s'\n", str);
994 solv_free(pieces);
995 return -1;
996 }
997 job = job2str[i].job;
998 what = 0;
999 if (npieces > 3)
1000 {
1001 char *flags = pieces[npieces - 1];
1002 if (*flags == '[' && flags[strlen(flags) - 1] == ']')
1003 {
1004 npieces--;
1005 flags++;
1006 flags[strlen(flags) - 1] = 0;
1007 job |= str2jobflags(pool, flags);
1008 }
1009 }
1010 if (!strcmp(pieces[1], "pkg"))
1011 {
1012 if (npieces != 3)
1013 {
1014 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: bad pkg selector in '%s'\n", str);
1015 solv_free(pieces);
1016 return -1;
1017 }
1018 job |= SOLVER_SOLVABLE0x01;
1019 what = testcase_str2solvid(pool, pieces[2]);
1020 if (!what)
1021 {
1022 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown package '%s'\n", pieces[2]);
1023 solv_free(pieces);
1024 return -1;
1025 }
1026 }
1027 else if (!strcmp(pieces[1], "name") || !strcmp(pieces[1], "provides"))
1028 {
1029 /* join em again for dep2str... */
1030 char *sp;
1031 for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
1032 if (*sp == 0)
1033 *sp = ' ';
1034 what = 0;
1035 if (pieces[1][0] == 'p' && strncmp(pieces[2], "namespace:", 10) == 0)
1036 {
1037 char *spe = strchr(pieces[2], '(');
1038 int l = strlen(pieces[2]);
1039 if (spe && pieces[2][l - 1] == ')')
1040 {
1041 /* special namespace provides */
1042 if (strcmp(spe, "(<NULL>)") != 0)
1043 {
1044 pieces[2][l - 1] = 0;
1045 what = testcase_str2dep(pool, spe + 1);
1046 pieces[2][l - 1] = ')';
1047 }
1048 what = pool_rel2id(pool, pool_strn2id(pool, pieces[2], spe - pieces[2], 1), what, REL_NAMESPACE19, 1);
1049 }
1050 }
1051 if (!what)
1052 what = testcase_str2dep(pool, pieces[2]);
1053 if (pieces[1][0] == 'n')
1054 job |= SOLVER_SOLVABLE_NAME0x02;
1055 else
1056 job |= SOLVER_SOLVABLE_PROVIDES0x03;
1057 }
1058 else if (!strcmp(pieces[1], "oneof"))
1059 {
1060 Queue q;
1061 job |= SOLVER_SOLVABLE_ONE_OF0x04;
1062 queue_init(&q);
1063 if (npieces > 3 && strcmp(pieces[2], "nothing") != 0)
1064 {
1065 for (i = 2; i < npieces; i++)
1066 {
1067 Id p = testcase_str2solvid(pool, pieces[i]);
1068 if (!p)
1069 {
1070 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown package '%s'\n", pieces[i]);
1071 queue_free(&q);
1072 solv_free(pieces);
1073 return -1;
1074 }
1075 queue_push(&q, p);
1076 }
1077 }
1078 what = pool_queuetowhatprovides(pool, &q);
1079 queue_free(&q);
1080 }
1081 else if (!strcmp(pieces[1], "repo"))
1082 {
1083 Repo *repo;
1084 if (npieces != 3)
1085 {
1086 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: bad line '%s'\n", str);
1087 solv_free(pieces);
1088 return -1;
1089 }
1090 repo = testcase_str2repo(pool, pieces[2]);
1091 if (!repo)
1092 {
1093 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown repo '%s'\n", pieces[2]);
1094 solv_free(pieces);
1095 return -1;
1096 }
1097 job |= SOLVER_SOLVABLE_REPO0x05;
1098 what = repo->repoid;
1099 }
1100 else if (!strcmp(pieces[1], "all"))
1101 {
1102 if (npieces != 3 && strcmp(pieces[2], "packages") != 0)
1103 {
1104 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: bad line '%s'\n", str);
1105 solv_free(pieces);
1106 return -1;
1107 }
1108 job |= SOLVER_SOLVABLE_ALL0x06;
1109 what = 0;
1110 }
1111 else
1112 {
1113 pool_debug(pool, SOLV_ERROR(1<<1), "str2job: unknown selection in '%s'\n", str);
1114 solv_free(pieces);
1115 return -1;
1116 }
1117 *whatp = what;
1118 solv_free(pieces);
1119 return job;
1120}
1121
1122static int
1123addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue)
1124{
1125 Id job;
1126 int i, r;
1127 int selflags;
1128 Queue sel;
1129
1130 for (i = 0; job2str[i].str; i++)
1131 if (!strcmp(pieces[0], job2str[i].str))
1132 break;
1133 if (!job2str[i].str)
1134 {
1135 pool_debug(pool, SOLV_ERROR(1<<1), "selstr2job: unknown job '%s'\n", pieces[0]);
1136 return -1;
1137 }
1138 job = job2str[i].job;
1139 if (npieces > 3)
1140 {
1141 char *flags = pieces[npieces - 1];
1142 if (*flags == '[' && flags[strlen(flags) - 1] == ']')
1143 {
1144 npieces--;
1145 flags++;
1146 flags[strlen(flags) - 1] = 0;
1147 job |= str2jobflags(pool, flags);
1148 }
1149 }
1150 if (npieces < 4)
1151 {
1152 pool_debug(pool, SOLV_ERROR(1<<1), "selstr2job: no selection flags\n");
1153 return -1;
1154 }
1155 selflags = str2selflags(pool, pieces[3]);
1156 queue_init(&sel);
1157 r = selection_make(pool, &sel, pieces[2], selflags);
1158 for (i = 0; i < sel.count; i += 2)
1159 queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]);
1160 queue_free(&sel);
1161 return r;
1162}
1163
1164static void
1165writedeps(Repo *repo, FILE *fp, const char *tag, Id key, Solvable *s, Offset off)
1166{
1167 Pool *pool = repo->pool;
1168 Id id, *dp;
1169 int tagwritten = 0;
1170 const char *idstr;
1171
1172 if (!off)
1173 return;
1174 dp = repo->idarraydata + off;
1175 while ((id = *dp++) != 0)
1176 {
1177 if (key == SOLVABLE_REQUIRES && id == SOLVABLE_PREREQMARKER)
1178 {
1179 if (tagwritten)
1180 fprintf(fp, "-%s\n", tag);
1181 tagwritten = 0;
1182 tag = "Prq:";
1183 continue;
1184 }
1185 if (key == SOLVABLE_PROVIDES && id == SOLVABLE_FILEMARKER)
1186 continue;
1187 idstr = testcase_dep2str(pool, id);
1188 if (!tagwritten)
1189 {
1190 fprintf(fp, "+%s\n", tag);
1191 tagwritten = 1;
1192 }
1193 fprintf(fp, "%s\n", idstr);
1194 }
1195 if (tagwritten)
1196 fprintf(fp, "-%s\n", tag);
1197}
1198
1199static void
1200writefilelist(Repo *repo, FILE *fp, const char *tag, Solvable *s)
1201{
1202 Pool *pool = repo->pool;
1203 int tagwritten = 0;
1204 Dataiterator di;
1205
1206 dataiterator_init(&di, pool, repo, s - pool->solvables, SOLVABLE_FILELIST, 0, 0);
1207 while (dataiterator_step(&di))
1208 {
1209 const char *s = repodata_dir2str(di.data, di.kv.id, di.kv.str);
1210 if (!tagwritten)
1211 {
1212 fprintf(fp, "+%s\n", tag);
1213 tagwritten = 1;
1214 }
1215 fprintf(fp, "%s\n", s);
1216 }
1217 if (tagwritten)
1218 fprintf(fp, "-%s\n", tag);
1219 dataiterator_free(&di);
1220}
1221
1222int
1223testcase_write_testtags(Repo *repo, FILE *fp)
1224{
1225 Pool *pool = repo->pool;
1226 Solvable *s;
1227 Id p;
1228 const char *name;
1229 const char *evr;
1230 const char *arch;
1231 const char *release;
1232 const char *tmp;
1233 unsigned int ti;
1234 Queue q;
1235
1236 fprintf(fp, "=Ver: 3.0\n");
1237 queue_init(&q);
1238 FOR_REPO_SOLVABLES(repo, p, s)for (p = (repo)->start, s = (repo)->pool->solvables +
p; p < (repo)->end; p++, s = (repo)->pool->solvables
+ p) if (s->repo != (repo)) continue; else
1239 {
1240 name = pool_id2str(pool, s->name);
1241 evr = pool_id2str(pool, s->evr);
1242 arch = pool_id2str(pool, s->arch);
1243 release = strrchr(evr, '-');
1244 if (!release)
1245 release = evr + strlen(evr);
1246 fprintf(fp, "=Pkg: %s %.*s %s %s\n", name, (int)(release - evr), evr, *release && release[1] ? release + 1 : "-", arch);
1247 tmp = solvable_lookup_str(s, SOLVABLE_SUMMARY);
1248 if (tmp)
1249 fprintf(fp, "=Sum: %s\n", tmp);
1250 writedeps(repo, fp, "Req:", SOLVABLE_REQUIRES, s, s->requires);
1251 writedeps(repo, fp, "Prv:", SOLVABLE_PROVIDES, s, s->provides);
1252 writedeps(repo, fp, "Obs:", SOLVABLE_OBSOLETES, s, s->obsoletes);
1253 writedeps(repo, fp, "Con:", SOLVABLE_CONFLICTS, s, s->conflicts);
1254 writedeps(repo, fp, "Rec:", SOLVABLE_RECOMMENDS, s, s->recommends);
1255 writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements);
1256 writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests);
1257 writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances);
1258 if (solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &q))
1259 {
1260 int i;
1261 fprintf(fp, "+Ipr:\n");
1262 for (i = 0; i < q.count; i++)
1263 fprintf(fp, "%s\n", testcase_dep2str(pool, q.elements[i]));
1264 fprintf(fp, "-Ipr:\n");
1265 }
1266 if (s->vendor)
1267 fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor));
1268 ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
1269 if (ti)
1270 fprintf(fp, "=Tim: %u\n", ti);
1271 writefilelist(repo, fp, "Fls:", s);
1272 }
1273 queue_free(&q);
1274 return 0;
1275}
1276
1277static inline Offset
1278adddep(Repo *repo, Offset olddeps, char *str, Id marker)
1279{
1280 Id id = *str == '/' ? pool_str2id(repo->pool, str, 1) : testcase_str2dep(repo->pool, str);
1281 return repo_addid_dep(repo, olddeps, id, marker);
1282}
1283
1284static void
1285finish_v2_solvable(Pool *pool, Repodata *data, Solvable *s, char *filelist, int nfilelist)
1286{
1287 if (nfilelist)
1288 {
1289 int l;
1290 Id did;
1291 for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1)
1292 {
1293 char *p = strrchr(filelist + l, '/');
1294 if (!p)
1295 continue;
1296 *p++ = 0;
1297 did = repodata_str2dir(data, filelist + l, 1);
1298 p[-1] = '/';
1299 if (!did)
1300 did = repodata_str2dir(data, "/", 1);
1301 repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p);
1302 }
1303 }
1304 repo_rewrite_suse_deps(s, 0);
1305}
1306
1307/* stripped down version of susetags parser used for testcases */
1308int
1309testcase_add_testtags(Repo *repo, FILE *fp, int flags)
1310{
1311 Pool *pool = repo->pool;
1312 char *line, *linep;
1313 int aline;
1314 int tag;
1315 Repodata *data;
1316 Solvable *s;
1317 char *sp[5];
1318 unsigned int t;
1319 int intag;
1320 char *filelist = 0;
1321 int afilelist = 0;
1322 int nfilelist = 0;
1323 int tagsversion = 0;
1324 int addselfprovides = 1; /* for compat reasons */
1325
1326 data = repo_add_repodata(repo, flags);
1327 s = 0;
1
Null pointer value stored to 's'
1328 intag = 0;
1329
1330 aline = 1024;
1331 line = solv_malloc(aline);
1332 linep = line;
1333 for (;;)
2
Loop condition is true. Entering loop body
18
Loop condition is true. Entering loop body
34
Loop condition is true. Entering loop body
1334 {
1335 if (linep - line + 16 > aline)
3
Taking false branch
19
Taking false branch
35
Taking false branch
1336 {
1337 aline = linep - line;
1338 line = solv_realloc(line, aline + 512);
1339 linep = line + aline;
1340 aline += 512;
1341 }
1342 if (!fgets(linep, aline - (linep - line), fp))
4
Assuming the condition is false
5
Taking false branch
20
Assuming the condition is false
21
Taking false branch
36
Assuming the condition is false
37
Taking false branch
1343 break;
1344 linep += strlen(linep);
1345 if (linep == line || linep[-1] != '\n')
6
Assuming 'linep' is not equal to 'line'
7
Taking false branch
22
Assuming 'linep' is not equal to 'line'
23
Taking false branch
38
Assuming 'linep' is not equal to 'line'
39
Taking false branch
1346 continue;
1347 linep[-1] = 0;
1348 linep = line + intag;
1349 if (intag)
8
Taking false branch
24
Taking false branch
40
Taking false branch
1350 {
1351 if (line[intag] == '-' && !strncmp(line + 1, line + intag + 1, intag - 2))
1352 {
1353 intag = 0;
1354 linep = line;
1355 continue;
1356 }
1357 }
1358 else if (line[0] == '+' && line[1] && line[1] != ':')
9
Assuming the condition is false
25
Assuming the condition is false
41
Assuming the condition is false
1359 {
1360 char *tagend = strchr(line, ':');
1361 if (!tagend)
1362 continue;
1363 line[0] = '=';
1364 tagend[1] = ' ';
1365 intag = tagend + 2 - line;
1366 linep = line + intag;
1367 continue;
1368 }
1369 if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':')
10
Assuming the condition is false
11
Assuming the condition is false
12
Assuming the condition is false
13
Assuming the condition is false
14
Assuming the condition is false
15
Taking false branch
26
Assuming the condition is false
27
Assuming the condition is false
28
Assuming the condition is false
29
Assuming the condition is false
30
Assuming the condition is false
31
Taking false branch
42
Assuming the condition is false
43
Assuming the condition is false
44
Assuming the condition is false
45
Assuming the condition is false
46
Assuming the condition is false
47
Taking false branch
1370 continue;
1371 tag = line[1] << 16 | line[2] << 8 | line[3];
1372 switch(tag)
16
Control jumps to the 'default' case at line 1477
32
Control jumps to the 'default' case at line 1477
48
Control jumps to 'case 4419438:' at line 1456
1373 {
1374 case 'V' << 16 | 'e' << 8 | 'r':
1375 tagsversion = atoi(line + 6);
1376 addselfprovides = tagsversion < 3 || strstr(line + 6, "addselfprovides") != 0;
1377 break;
1378 case 'P' << 16 | 'k' << 8 | 'g':
1379 if (s)
1380 {
1381 if (tagsversion == 2)
1382 finish_v2_solvable(pool, data, s, filelist, nfilelist);
1383 if (addselfprovides && s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
1384 s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ2, 1), 0);
1385 }
1386 nfilelist = 0;
1387 if (split(line + 5, sp, 5) != 4)
1388 break;
1389 s = pool_id2solvable(pool, repo_add_solvable(repo));
1390 s->name = pool_str2id(pool, sp[0], 1);
1391 /* join back version and release */
1392 if (sp[2] && !(sp[2][0] == '-' && !sp[2][1]))
1393 sp[2][-1] = '-';
1394 s->evr = makeevr(pool, sp[1]);
1395 s->arch = pool_str2id(pool, sp[3], 1);
1396 break;
1397 case 'S' << 16 | 'u' << 8 | 'm':
1398 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6);
1399 break;
1400 case 'V' << 16 | 'n' << 8 | 'd':
1401 s->vendor = pool_str2id(pool, line + 6, 1);
1402 break;
1403 case 'T' << 16 | 'i' << 8 | 'm':
1404 t = atoi(line + 6);
1405 if (t)
1406 repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
1407 break;
1408 case 'R' << 16 | 'e' << 8 | 'q':
1409 s->requires = adddep(repo, s->requires, line + 6, -SOLVABLE_PREREQMARKER);
1410 break;
1411 case 'P' << 16 | 'r' << 8 | 'q':
1412 s->requires = adddep(repo, s->requires, line + 6, SOLVABLE_PREREQMARKER);
1413 break;
1414 case 'P' << 16 | 'r' << 8 | 'v':
1415 /* version 2 had the file list at the end of the provides */
1416 if (tagsversion == 2)
1417 {
1418 if (line[6] == '/')
1419 {
1420 int l = strlen(line + 6) + 1;
1421 if (nfilelist + l > afilelist)
1422 {
1423 afilelist = nfilelist + l + 512;
1424 filelist = solv_realloc(filelist, afilelist);
1425 }
1426 memcpy(filelist + nfilelist, line + 6, l);
1427 nfilelist += l;
1428 break;
1429 }
1430 if (nfilelist)
1431 {
1432 int l;
1433 for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1)
1434 s->provides = repo_addid_dep(repo, s->provides, pool_str2id(pool, filelist + l, 1), 0);
1435 nfilelist = 0;
1436 }
1437 }
1438 s->provides = adddep(repo, s->provides, line + 6, 0);
1439 break;
1440 case 'F' << 16 | 'l' << 8 | 's':
1441 {
1442 char *p = strrchr(line + 6, '/');
1443 Id did;
1444 if (!p)
1445 break;
1446 *p++ = 0;
1447 did = repodata_str2dir(data, line + 6, 1);
1448 if (!did)
1449 did = repodata_str2dir(data, "/", 1);
1450 repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p);
1451 break;
1452 }
1453 case 'O' << 16 | 'b' << 8 | 's':
1454 s->obsoletes = adddep(repo, s->obsoletes, line + 6, 0);
1455 break;
1456 case 'C' << 16 | 'o' << 8 | 'n':
1457 s->conflicts = adddep(repo, s->conflicts, line + 6, 0);
49
Access to field 'conflicts' results in a dereference of a null pointer (loaded from variable 's')
1458 break;
1459 case 'R' << 16 | 'e' << 8 | 'c':
1460 s->recommends = adddep(repo, s->recommends, line + 6, 0);
1461 break;
1462 case 'S' << 16 | 'u' << 8 | 'p':
1463 s->supplements = adddep(repo, s->supplements, line + 6, 0);
1464 break;
1465 case 'S' << 16 | 'u' << 8 | 'g':
1466 s->suggests = adddep(repo, s->suggests, line + 6, 0);
1467 break;
1468 case 'E' << 16 | 'n' << 8 | 'h':
1469 s->enhances = adddep(repo, s->enhances, line + 6, 0);
1470 break;
1471 case 'I' << 16 | 'p' << 8 | 'r':
1472 {
1473 Id id = line[6] == '/' ? pool_str2id(pool, line + 6, 1) : testcase_str2dep(pool, line + 6);
1474 repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id);
1475 break;
1476 }
1477 default:
1478 break;
17
Execution continues on line 1333
33
Execution continues on line 1333
1479 }
1480 }
1481 if (s)
1482 {
1483 if (tagsversion == 2)
1484 finish_v2_solvable(pool, data, s, filelist, nfilelist);
1485 if (addselfprovides && s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
1486 s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ2, 1), 0);
1487 }
1488 solv_free(line);
1489 solv_free(filelist);
1490 repodata_free_dircache(data);
1491 if (!(flags & REPO_NO_INTERNALIZE(1 << 1)))
1492 repodata_internalize(data);
1493 return 0;
1494}
1495
1496const char *
1497testcase_getpoolflags(Pool *pool)
1498{
1499 const char *str = 0;
1500 int i, v;
1501 for (i = 0; poolflags2str[i].str; i++)
1502 {
1503 v = pool_get_flag(pool, poolflags2str[i].flag);
1504 if (v == poolflags2str[i].def)
1505 continue;
1506 str = pool_tmpappend(pool, str, v ? " " : " !", poolflags2str[i].str);
1507 }
1508 return str ? str + 1 : "";
1509}
1510
1511int
1512testcase_setpoolflags(Pool *pool, const char *str)
1513{
1514 const char *p = str, *s;
1515 int i, v;
1516 for (;;)
1517 {
1518 while (*p == ' ' || *p == '\t' || *p == ',')
1519 p++;
1520 v = 1;
1521 if (*p == '!')
1522 {
1523 p++;
1524 v = 0;
1525 }
1526 if (!*p)
1527 break;
1528 s = p;
1529 while (*p && *p != ' ' && *p != '\t' && *p != ',')
1530 p++;
1531 for (i = 0; poolflags2str[i].str; i++)
1532 if (!strncmp(poolflags2str[i].str, s, p - s) && poolflags2str[i].str[p - s] == 0)
1533 break;
1534 if (!poolflags2str[i].str)
1535 {
1536 pool_debug(pool, SOLV_ERROR(1<<1), "setpoolflags: unknown flag '%.*s'\n", (int)(p - s), s);
1537 return 0;
1538 }
1539 pool_set_flag(pool, poolflags2str[i].flag, v);
1540 }
1541 return 1;
1542}
1543
1544void
1545testcase_resetpoolflags(Pool *pool)
1546{
1547 int i;
1548 for (i = 0; poolflags2str[i].str; i++)
1549 pool_set_flag(pool, poolflags2str[i].flag, poolflags2str[i].def);
1550}
1551
1552const char *
1553testcase_getsolverflags(Solver *solv)
1554{
1555 Pool *pool = solv->pool;
1556 const char *str = 0;
1557 int i, v;
1558 for (i = 0; solverflags2str[i].str; i++)
1559 {
1560 v = solver_get_flag(solv, solverflags2str[i].flag);
1561 if (v == solverflags2str[i].def)
1562 continue;
1563 str = pool_tmpappend(pool, str, v ? " " : " !", solverflags2str[i].str);
1564 }
1565 return str ? str + 1 : "";
1566}
1567
1568int
1569testcase_setsolverflags(Solver *solv, const char *str)
1570{
1571 const char *p = str, *s;
1572 int i, v;
1573 for (;;)
1574 {
1575 while (*p == ' ' || *p == '\t' || *p == ',')
1576 p++;
1577 v = 1;
1578 if (*p == '!')
1579 {
1580 p++;
1581 v = 0;
1582 }
1583 if (!*p)
1584 break;
1585 s = p;
1586 while (*p && *p != ' ' && *p != '\t' && *p != ',')
1587 p++;
1588 for (i = 0; solverflags2str[i].str; i++)
1589 if (!strncmp(solverflags2str[i].str, s, p - s) && solverflags2str[i].str[p - s] == 0)
1590 break;
1591 if (!solverflags2str[i].str)
1592 {
1593 pool_debug(solv->pool, SOLV_ERROR(1<<1), "setsolverflags: unknown flag '%.*s'\n", (int)(p - s), s);
1594 return 0;
1595 }
1596 if (solver_set_flag(solv, solverflags2str[i].flag, v) == -1)
1597 {
1598 pool_debug(solv->pool, SOLV_ERROR(1<<1), "setsolverflags: unsupported flag '%s'\n", solverflags2str[i].str);
1599 return 0;
1600 }
1601 }
1602 return 1;
1603}
1604
1605void
1606testcase_resetsolverflags(Solver *solv)
1607{
1608 int i;
1609 for (i = 0; solverflags2str[i].str; i++)
1610 solver_set_flag(solv, solverflags2str[i].flag, solverflags2str[i].def);
1611}
1612
1613static const char *
1614testcase_ruleid(Solver *solv, Id rid)
1615{
1616 Strqueue sq;
1617 Queue q;
1618 int i;
1619 Chksum *chk;
1620 const unsigned char *md5;
1621 int md5l;
1622 const char *s;
1623
1624 queue_init(&q);
1625 strqueue_init(&sq);
1626 solver_ruleliterals(solv, rid, &q);
1627 for (i = 0; i < q.count; i++)
1628 {
1629 Id p = q.elements[i];
1630 s = testcase_solvid2str(solv->pool, p > 0 ? p : -p);
1631 if (p < 0)
1632 s = pool_tmpjoin(solv->pool, "!", s, 0);
1633 strqueue_push(&sq, s);
1634 }
1635 queue_free(&q);
1636 strqueue_sort_u(&sq);
1637 chk = solv_chksum_create(REPOKEY_TYPE_MD5);
1638 for (i = 0; i < sq.nstr; i++)
1639 solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1);
1640 md5 = solv_chksum_get(chk, &md5l);
1641 s = pool_bin2hex(solv->pool, md5, md5l);
1642 chk = solv_chksum_free(chk, 0);
1643 strqueue_free(&sq);
1644 return s;
1645}
1646
1647static const char *
1648testcase_problemid(Solver *solv, Id problem)
1649{
1650 Strqueue sq;
1651 Queue q;
1652 Chksum *chk;
1653 const unsigned char *md5;
1654 int i, md5l;
1655 const char *s;
1656
1657 /* we build a hash of all rules that define the problem */
1658 queue_init(&q);
1659 strqueue_init(&sq);
1660 solver_findallproblemrules(solv, problem, &q);
1661 for (i = 0; i < q.count; i++)
1662 strqueue_push(&sq, testcase_ruleid(solv, q.elements[i]));
1663 queue_free(&q);
1664 strqueue_sort_u(&sq);
1665 chk = solv_chksum_create(REPOKEY_TYPE_MD5);
1666 for (i = 0; i < sq.nstr; i++)
1667 solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1);
1668 md5 = solv_chksum_get(chk, &md5l);
1669 s = pool_bin2hex(solv->pool, md5, 4);
1670 chk = solv_chksum_free(chk, 0);
1671 strqueue_free(&sq);
1672 return s;
1673}
1674
1675static const char *
1676testcase_solutionid(Solver *solv, Id problem, Id solution)
1677{
1678 Id intid;
1679 Chksum *chk;
1680 const unsigned char *md5;
1681 int md5l;
1682 const char *s;
1683
1684 intid = solver_solutionelement_internalid(solv, problem, solution);
1685 /* internal stuff! handle with care! */
1686 if (intid < 0)
1687 {
1688 /* it's a job */
1689 s = testcase_job2str(solv->pool, solv->job.elements[-intid - 1], solv->job.elements[-intid]);
1690 }
1691 else
1692 {
1693 /* it's a rule */
1694 s = testcase_ruleid(solv, intid);
1695 }
1696 chk = solv_chksum_create(REPOKEY_TYPE_MD5);
1697 solv_chksum_add(chk, s, strlen(s) + 1);
1698 md5 = solv_chksum_get(chk, &md5l);
1699 s = pool_bin2hex(solv->pool, md5, 4);
1700 chk = solv_chksum_free(chk, 0);
1701 return s;
1702}
1703
1704static const char *
1705testcase_alternativeid(Solver *solv, int type, Id id, Id from)
1706{
1707 const char *s;
1708 Pool *pool = solv->pool;
1709 Chksum *chk;
1710 const unsigned char *md5;
1711 int md5l;
1712 chk = solv_chksum_create(REPOKEY_TYPE_MD5);
1713 if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS2)
1714 {
1715 s = testcase_solvid2str(pool, from);
1716 solv_chksum_add(chk, s, strlen(s) + 1);
1717 s = testcase_dep2str(pool, id);
1718 solv_chksum_add(chk, s, strlen(s) + 1);
1719 }
1720 else if (type == SOLVER_ALTERNATIVE_TYPE_RULE1)
1721 {
1722 s = testcase_ruleid(solv, id);
1723 solv_chksum_add(chk, s, strlen(s) + 1);
1724 }
1725 md5 = solv_chksum_get(chk, &md5l);
1726 s = pool_bin2hex(pool, md5, 4);
1727 chk = solv_chksum_free(chk, 0);
1728 return s;
1729}
1730
1731static struct class2str {
1732 Id class;
1733 const char *str;
1734} class2str[] = {
1735 { SOLVER_TRANSACTION_ERASE0x10, "erase" },
1736 { SOLVER_TRANSACTION_INSTALL0x20, "install" },
1737 { SOLVER_TRANSACTION_REINSTALLED0x11, "reinstall" },
1738 { SOLVER_TRANSACTION_DOWNGRADED0x12, "downgrade" },
1739 { SOLVER_TRANSACTION_CHANGED0x13, "change" },
1740 { SOLVER_TRANSACTION_UPGRADED0x14, "upgrade" },
1741 { SOLVER_TRANSACTION_OBSOLETED0x15, "obsolete" },
1742 { SOLVER_TRANSACTION_MULTIINSTALL0x30, "multiinstall" },
1743 { SOLVER_TRANSACTION_MULTIREINSTALL0x31, "multireinstall" },
1744 { 0, 0 }
1745};
1746
1747static struct reason2str {
1748 Id reason;
1749 const char *str;
1750} reason2str[] = {
1751 { SOLVER_REASON_UNRELATED0, "unrelated" },
1752 { SOLVER_REASON_UNIT_RULE1, "unit" },
1753 { SOLVER_REASON_KEEP_INSTALLED2, "keep" },
1754 { SOLVER_REASON_RESOLVE_JOB3, "job" },
1755 { SOLVER_REASON_UPDATE_INSTALLED4, "update" },
1756 { SOLVER_REASON_CLEANDEPS_ERASE5, "cleandeps" },
1757 { SOLVER_REASON_RESOLVE6, "resolve" },
1758 { SOLVER_REASON_WEAKDEP7, "weakdep" },
1759 { SOLVER_REASON_RESOLVE_ORPHAN8, "orphan" },
1760
1761 { SOLVER_REASON_RECOMMENDED16, "recommended" },
1762 { SOLVER_REASON_SUPPLEMENTED17, "supplemented" },
1763 { 0, 0 }
1764};
1765
1766static const char *
1767testcase_reason2str(Id reason)
1768{
1769 int i;
1770 for (i = 0; reason2str[i].str; i++)
1771 if (reason == reason2str[i].reason)
1772 return reason2str[i].str;
1773 return "?";
1774}
1775
1776static struct rclass2str {
1777 Id rclass;
1778 const char *str;
1779} rclass2str[] = {
1780 { SOLVER_RULE_PKG, "pkg" },
1781 { SOLVER_RULE_UPDATE, "update" },
1782 { SOLVER_RULE_FEATURE, "feature" },
1783 { SOLVER_RULE_JOB, "job" },
1784 { SOLVER_RULE_DISTUPGRADE, "distupgrade" },
1785 { SOLVER_RULE_INFARCH, "infarch" },
1786 { SOLVER_RULE_CHOICE, "choice" },
1787 { SOLVER_RULE_LEARNT, "learnt" },
1788 { SOLVER_RULE_BEST, "best" },
1789 { SOLVER_RULE_YUMOBS, "yumobs" },
1790 { 0, 0 }
1791};
1792
1793static const char *
1794testcase_rclass2str(Id rclass)
1795{
1796 int i;
1797 for (i = 0; rclass2str[i].str; i++)
1798 if (rclass == rclass2str[i].rclass)
1799 return rclass2str[i].str;
1800 return "unknown";
1801}
1802
1803static int
1804dump_genid(Pool *pool, Strqueue *sq, Id id, int cnt)
1805{
1806 struct oplist *op;
1807 char cntbuf[20];
1808 const char *s;
1809
1810 if (ISRELDEP(id)(((id) & 0x80000000) != 0))
1811 {
1812 Reldep *rd = GETRELDEP(pool, id)((pool)->rels + ((id) ^ 0x80000000));
1813 for (op = oplist; op->flags; op++)
1814 if (rd->flags == op->flags)
1815 break;
1816 cnt = dump_genid(pool, sq, rd->name, cnt);
1817 cnt = dump_genid(pool, sq, rd->evr, cnt);
1818 sprintf(cntbuf, "genid %2d: genid ", cnt++);
1819 s = pool_tmpjoin(pool, cntbuf, "op ", op->flags ? op->opname : "unknown");
1820 }
1821 else
1822 {
1823 sprintf(cntbuf, "genid %2d: genid ", cnt++);
1824 s = pool_tmpjoin(pool, cntbuf, id ? "lit " : "null", id ? pool_id2str(pool, id) : 0);
1825 }
1826 strqueue_push(sq, s);
1827 return cnt;
1828}
1829
1830char *
1831testcase_solverresult(Solver *solv, int resultflags)
1832{
1833 Pool *pool = solv->pool;
1834 int i, j;
1835 Id p, op;
1836 const char *s;
1837 char *result;
1838 Strqueue sq;
1839
1840 strqueue_init(&sq);
1841 if ((resultflags & TESTCASE_RESULT_TRANSACTION(1 << 0)) != 0)
1842 {
1843 Transaction *trans = solver_create_transaction(solv);
1844 Queue q;
1845
1846 queue_init(&q);
1847 for (i = 0; class2str[i].str; i++)
1848 {
1849 queue_empty(&q);
1850 transaction_classify_pkgs(trans, SOLVER_TRANSACTION_KEEP_PSEUDO(1 << 8), class2str[i].class, 0, 0, &q);
1851 for (j = 0; j < q.count; j++)
1852 {
1853 p = q.elements[j];
1854 op = 0;
1855 if (pool->installed && pool->solvables[p].repo == pool->installed)
1856 op = transaction_obs_pkg(trans, p);
1857 s = pool_tmpjoin(pool, class2str[i].str, " ", testcase_solvid2str(pool, p));
1858 if (op)
1859 s = pool_tmpjoin(pool, s, " ", testcase_solvid2str(pool, op));
1860 strqueue_push(&sq, s);
1861 }
1862 }
1863 queue_free(&q);
1864 transaction_free(trans);
1865 }
1866 if ((resultflags & TESTCASE_RESULT_PROBLEMS(1 << 1)) != 0)
1867 {
1868 char *probprefix, *solprefix;
1869 int problem, solution, element;
1870 int pcnt, scnt;
1871
1872 pcnt = solver_problem_count(solv);
1873 for (problem = 1; problem <= pcnt; problem++)
1874 {
1875 Id rid, from, to, dep;
1876 SolverRuleinfo rinfo;
1877 rid = solver_findproblemrule(solv, problem);
1878 s = testcase_problemid(solv, problem);
1879 probprefix = solv_dupjoin("problem ", s, 0);
1880 rinfo = solver_ruleinfo(solv, rid, &from, &to, &dep);
1881 s = pool_tmpjoin(pool, probprefix, " info ", solver_problemruleinfo2str(solv, rinfo, from, to, dep));
1882 strqueue_push(&sq, s);
1883 scnt = solver_solution_count(solv, problem);
1884 for (solution = 1; solution <= scnt; solution++)
1885 {
1886 s = testcase_solutionid(solv, problem, solution);
1887 solprefix = solv_dupjoin(probprefix, " solution ", s);
1888 element = 0;
1889 while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &op)) != 0)
1890 {
1891 if (p == SOLVER_SOLUTION_JOB(0))
1892 s = pool_tmpjoin(pool, solprefix, " deljob ", testcase_job2str(pool, solv->job.elements[op - 1], solv->job.elements[op]));
1893 else if (p > 0 && op == 0)
1894 s = pool_tmpjoin(pool, solprefix, " erase ", testcase_solvid2str(pool, p));
1895 else if (p > 0 && op > 0)
1896 {
1897 s = pool_tmpjoin(pool, solprefix, " replace ", testcase_solvid2str(pool, p));
1898 s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, op));
1899 }
1900 else if (p < 0 && op > 0)
1901 s = pool_tmpjoin(pool, solprefix, " allow ", testcase_solvid2str(pool, op));
1902 else
1903 s = pool_tmpjoin(pool, solprefix, " unknown", 0);
1904 strqueue_push(&sq, s);
1905 }
1906 solv_free(solprefix);
1907 }
1908 solv_free(probprefix);
1909 }
1910 }
1911
1912 if ((resultflags & TESTCASE_RESULT_ORPHANED(1 << 2)) != 0)
1913 {
1914 Queue q;
1915
1916 queue_init(&q);
1917 solver_get_orphaned(solv, &q);
1918 for (i = 0; i < q.count; i++)
1919 {
1920 s = pool_tmpjoin(pool, "orphaned ", testcase_solvid2str(pool, q.elements[i]), 0);
1921 strqueue_push(&sq, s);
1922 }
1923 queue_free(&q);
1924 }
1925
1926 if ((resultflags & TESTCASE_RESULT_RECOMMENDED(1 << 3)) != 0)
1927 {
1928 Queue qr, qs;
1929
1930 queue_init(&qr);
1931 queue_init(&qs);
1932 solver_get_recommendations(solv, &qr, &qs, 0);
1933 for (i = 0; i < qr.count; i++)
1934 {
1935 s = pool_tmpjoin(pool, "recommended ", testcase_solvid2str(pool, qr.elements[i]), 0);
1936 strqueue_push(&sq, s);
1937 }
1938 for (i = 0; i < qs.count; i++)
1939 {
1940 s = pool_tmpjoin(pool, "suggested ", testcase_solvid2str(pool, qs.elements[i]), 0);
1941 strqueue_push(&sq, s);
1942 }
1943 queue_free(&qr);
1944 queue_free(&qs);
1945 }
1946
1947 if ((resultflags & TESTCASE_RESULT_UNNEEDED(1 << 4)) != 0)
1948 {
1949 Queue q, qf;
1950
1951 queue_init(&q);
1952 queue_init(&qf);
1953 solver_get_unneeded(solv, &q, 0);
1954 solver_get_unneeded(solv, &qf, 1);
1955 for (i = j = 0; i < q.count; i++)
1956 {
1957 /* we rely on qf containing a subset of q in the same order */
1958 if (j < qf.count && q.elements[i] == qf.elements[j])
1959 {
1960 s = pool_tmpjoin(pool, "unneeded_filtered ", testcase_solvid2str(pool, q.elements[i]), 0);
1961 j++;
1962 }
1963 else
1964 s = pool_tmpjoin(pool, "unneeded ", testcase_solvid2str(pool, q.elements[i]), 0);
1965 strqueue_push(&sq, s);
1966 }
1967 queue_free(&q);
1968 queue_free(&qf);
1969 }
1970 if ((resultflags & TESTCASE_RESULT_ALTERNATIVES(1 << 5)) != 0)
1971 {
1972 char *altprefix;
1973 Queue q, rq;
1974 int cnt;
1975 Id alternative;
1976 queue_init(&q);
1977 queue_init(&rq);
1978 cnt = solver_alternatives_count(solv);
1979 for (alternative = 1; alternative <= cnt; alternative++)
1980 {
1981 Id id, from, chosen;
1982 char num[20];
1983 int type = solver_get_alternative(solv, alternative, &id, &from, &chosen, &q, 0);
1984 altprefix = solv_dupjoin("alternative ", testcase_alternativeid(solv, type, id, from), " ");
1985 strcpy(num, " 0 ");
1986 if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS2)
1987 {
1988 char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, from));
1989 s = pool_tmpappend(pool, s, " recommends ", testcase_dep2str(pool, id));
1990 strqueue_push(&sq, s);
1991 }
1992 else if (type == SOLVER_ALTERNATIVE_TYPE_RULE1)
1993 {
1994 /* map choice rules back to pkg rules */
1995 if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
1996 id = solver_rule2pkgrule(solv, id);
1997 solver_allruleinfos(solv, id, &rq);
1998 for (i = 0; i < rq.count; i += 4)
1999 {
2000 int rtype = rq.elements[i];
2001 if ((rtype & SOLVER_RULE_TYPEMASK0xff00) == SOLVER_RULE_JOB)
2002 {
2003 const char *js = testcase_job2str(pool, rq.elements[i + 2], rq.elements[i + 3]);
2004 char *s = pool_tmpjoin(pool, altprefix, num, " job ");
2005 s = pool_tmpappend(pool, s, js, 0);
2006 strqueue_push(&sq, s);
2007 }
2008 else if (rtype == SOLVER_RULE_PKG_REQUIRES)
2009 {
2010 char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, rq.elements[i + 1]));
2011 s = pool_tmpappend(pool, s, " requires ", testcase_dep2str(pool, rq.elements[i + 3]));
2012 strqueue_push(&sq, s);
2013 }
2014 }
2015 }
2016 for (i = 0; i < q.count; i++)
2017 {
2018 Id p = q.elements[i];
2019 if (i >= 9)
2020 num[0] = '0' + (i + 1) / 10;
2021 num[1] = '0' + (i + 1) % 10;
2022 if (-p == chosen)
2023 s = pool_tmpjoin(pool, altprefix, num, "+ ");
2024 else if (p < 0)
2025 s = pool_tmpjoin(pool, altprefix, num, "- ");
2026 else if (p >= 0)
2027 s = pool_tmpjoin(pool, altprefix, num, " ");
2028 s = pool_tmpappend(pool, s, testcase_solvid2str(pool, p < 0 ? -p : p), 0);
2029 strqueue_push(&sq, s);
2030 }
2031 solv_free(altprefix);
2032 }
2033 queue_free(&q);
2034 queue_free(&rq);
2035 }
2036 if ((resultflags & TESTCASE_RESULT_RULES(1 << 6)) != 0)
2037 {
2038 /* dump all rules */
2039 Id rid;
2040 SolverRuleinfo rclass;
2041 Queue q;
2042 int i;
2043
2044 queue_init(&q);
2045 for (rid = 1; (rclass = solver_ruleclass(solv, rid)) != SOLVER_RULE_UNKNOWN; rid++)
2046 {
2047 char *prefix = solv_dupjoin("rule ", testcase_rclass2str(rclass), " ");
2048 prefix = solv_dupappend(prefix, testcase_ruleid(solv, rid), 0);
2049 solver_ruleliterals(solv, rid, &q);
2050 if (rclass == SOLVER_RULE_FEATURE && q.count == 1 && q.elements[0] == -SYSTEMSOLVABLE1)
2051 continue;
2052 for (i = 0; i < q.count; i++)
2053 {
2054 Id p = q.elements[i];
2055 const char *s;
2056 if (p < 0)
2057 s = pool_tmpjoin(pool, prefix, " -", testcase_solvid2str(pool, -p));
2058 else
2059 s = pool_tmpjoin(pool, prefix, " ", testcase_solvid2str(pool, p));
2060 strqueue_push(&sq, s);
2061 }
2062 solv_free(prefix);
2063 }
2064 queue_free(&q);
2065 }
2066 if ((resultflags & TESTCASE_RESULT_GENID(1 << 7)) != 0)
2067 {
2068 for (i = 0 ; i < solv->job.count; i += 2)
2069 {
2070 Id id, id2;
2071 if (solv->job.elements[i] != (SOLVER_NOOP0x0000 | SOLVER_SOLVABLE_PROVIDES0x03))
2072 continue;
2073 id = solv->job.elements[i + 1];
2074 s = testcase_dep2str(pool, id);
2075 strqueue_push(&sq, pool_tmpjoin(pool, "genid dep ", s, 0));
2076 if ((id2 = testcase_str2dep(pool, s)) != id)
2077 {
2078 s = pool_tmpjoin(pool, "genid roundtrip error: ", testcase_dep2str(pool, id2), 0);
2079 strqueue_push(&sq, s);
2080 }
2081 dump_genid(pool, &sq, id, 1);
2082 }
2083 }
2084 if ((resultflags & TESTCASE_RESULT_REASON(1 << 8)) != 0)
2085 {
2086 Queue whyq;
2087 queue_init(&whyq);
2088 FOR_POOL_SOLVABLES(p)for (p = 2; p < pool->nsolvables; p++) if (pool->solvables
[p].repo == 0) continue; else
2089 {
2090 Id info, p2, id;
2091 int reason = solver_describe_decision(solv, p, &info);
2092 if (reason == SOLVER_REASON_UNRELATED0)
2093 continue;
2094 if (reason == SOLVER_REASON_WEAKDEP7)
2095 {
2096 solver_describe_weakdep_decision(solv, p, &whyq);
2097 if (whyq.count)
2098 {
2099 for (i = 0; i < whyq.count; i += 3)
2100 {
2101 reason = whyq.elements[i];
2102 p2 = whyq.elements[i + 1];
2103 id = whyq.elements[i + 2];
2104 s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0);
2105 s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason));
2106 s = pool_tmpappend(pool, s, " ", testcase_dep2str(pool, id));
2107 if (p2)
2108 s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, p2));
2109 strqueue_push(&sq, s);
2110 }
2111 continue;
2112 }
2113 }
2114 s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0);
2115 s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason));
2116 if (info)
2117 s = pool_tmpappend(pool, s, " ", testcase_ruleid(solv, info));
2118 strqueue_push(&sq, s);
2119 }
2120 queue_free(&whyq);
2121 }
2122 strqueue_sort(&sq);
2123 result = strqueue_join(&sq);
2124 strqueue_free(&sq);
2125 return result;
2126}
2127
2128
2129static int
2130testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
2131{
2132 Pool *pool = solv->pool;
2133 Repo *repo;
2134 int i;
2135 Id arch, repoid;
2136 Id lowscore;
2137 FILE *fp;
2138 Strqueue sq;
2139 char *cmd, *out;
2140 const char *s;
2141
2142 if (!testcasename)
2143 testcasename = "testcase.t";
2144 if (!resultname)
2145 resultname = "solver.result";
2146
2147 if (mkdir(dir, 0777) && errno(*__errno_location ()) != EEXIST17)
2148 {
2149 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: could not create directory '%s'\n", dir);
2150 return 0;
2151 }
2152 strqueue_init(&sq);
2153 FOR_REPOS(repoid, repo)for (repoid = 1; repoid < pool->nrepos; repoid++) if ((
repo = pool->repos[repoid]) == 0) continue; else
2154 {
2155 const char *name = testcase_repoid2str(pool, repoid);
2156 char priobuf[50];
2157 if (repo->subpriority)
2158 sprintf(priobuf, "%d.%d", repo->priority, repo->subpriority);
2159 else
2160 sprintf(priobuf, "%d", repo->priority);
2161 out = pool_tmpjoin(pool, name, ".repo", ".gz");
2162 for (i = 0; out[i]; i++)
2163 if (out[i] == '/')
2164 out[i] = '_';
2165 cmd = pool_tmpjoin(pool, "repo ", name, " ");
2166 cmd = pool_tmpappend(pool, cmd, priobuf, " ");
2167 cmd = pool_tmpappend(pool, cmd, "testtags ", out);
2168 strqueue_push(&sq, cmd);
2169 out = pool_tmpjoin(pool, dir, "/", out);
2170 if (!(fp = solv_xfopen(out, "w")))
2171 {
2172 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: could not open '%s' for writing\n", out);
2173 strqueue_free(&sq);
2174 return 0;
2175 }
2176 testcase_write_testtags(repo, fp);
2177 if (fclose(fp))
2178 {
2179 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: write error\n");
2180 strqueue_free(&sq);
2181 return 0;
2182 }
2183 }
2184 /* hmm, this is not optimal... we currently search for the lowest score */
2185 lowscore = 0;
2186 arch = pool->solvables[SYSTEMSOLVABLE1].arch;
2187 for (i = 0; i < pool->lastarch; i++)
2188 {
2189 if (pool->id2arch[i] == 1 && !lowscore)
2190 arch = i;
2191 if (pool->id2arch[i] > 0x10000 && (!lowscore || pool->id2arch[i] < lowscore))
2192 {
2193 arch = i;
2194 lowscore = pool->id2arch[i];
2195 }
2196 }
2197 cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "unset", 0);
2198 for (i = 0; disttype2str[i].str != 0; i++)
2199 if (pool->disttype == disttype2str[i].type)
2200 break;
2201 pool_tmpappend(pool, cmd, " ", disttype2str[i].str ? disttype2str[i].str : "unknown");
2202 if (pool->installed)
2203 cmd = pool_tmpappend(pool, cmd, " ", testcase_repoid2str(pool, pool->installed->repoid));
2204 strqueue_push(&sq, cmd);
2205 s = testcase_getpoolflags(solv->pool);
2206 if (*s)
2207 {
2208 cmd = pool_tmpjoin(pool, "poolflags ", s, 0);
2209 strqueue_push(&sq, cmd);
2210 }
2211
2212 if (pool->vendorclasses)
2213 {
2214 cmd = 0;
2215 for (i = 0; pool->vendorclasses[i]; i++)
2216 {
2217 cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", pool->vendorclasses[i]);
2218 if (!pool->vendorclasses[i + 1])
2219 {
2220 strqueue_push(&sq, cmd);
2221 cmd = 0;
2222 i++;
2223 }
2224 }
2225 }
2226
2227 /* dump disabled packages (must come before the namespace/job lines) */
2228 if (pool->considered)
2229 {
2230 Id p;
2231 FOR_POOL_SOLVABLES(p)for (p = 2; p < pool->nsolvables; p++) if (pool->solvables
[p].repo == 0) continue; else
2232 if (!MAPTST(pool->considered, p)((pool->considered)->map[(p) >> 3] & (1 <<
((p) & 7)))
)
2233 {
2234 cmd = pool_tmpjoin(pool, "disable pkg ", testcase_solvid2str(pool, p), 0);
2235 strqueue_push(&sq, cmd);
2236 }
2237 }
2238
2239 s = testcase_getsolverflags(solv);
2240 if (*s)
2241 {
2242 cmd = pool_tmpjoin(pool, "solverflags ", s, 0);
2243 strqueue_push(&sq, cmd);
2244 }
2245
2246 /* now dump all the ns callback values we know */
2247 if (pool->nscallback)
2248 {
2249 Id rid;
2250 int d;
2251 for (rid = 1; rid < pool->nrels; rid++)
2252 {
2253 Reldep *rd = pool->rels + rid;
2254 if (rd->flags != REL_NAMESPACE19 || rd->name == NAMESPACE_OTHERPROVIDERS)
2255 continue;
2256 /* evaluate all namespace ids, skip empty results */
2257 d = pool_whatprovides(pool, MAKERELDEP(rid)((rid) | 0x80000000));
2258 if (!d || !pool->whatprovidesdata[d])
2259 continue;
2260 cmd = pool_tmpjoin(pool, "namespace ", pool_id2str(pool, rd->name), "(");
2261 cmd = pool_tmpappend(pool, cmd, pool_id2str(pool, rd->evr), ")");
2262 for (; pool->whatprovidesdata[d]; d++)
2263 cmd = pool_tmpappend(pool, cmd, " ", testcase_solvid2str(pool, pool->whatprovidesdata[d]));
2264 strqueue_push(&sq, cmd);
2265 }
2266 }
2267
2268 for (i = 0; i < solv->job.count; i += 2)
2269 {
2270 cmd = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]);
2271 cmd = pool_tmpjoin(pool, "job ", cmd, 0);
2272 strqueue_push(&sq, cmd);
2273 }
2274
2275 if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER(1 << 31)) != 0)
2276 {
2277 char *result;
2278 cmd = 0;
2279 for (i = 0; resultflags2str[i].str; i++)
2280 if ((resultflags & resultflags2str[i].flag) != 0)
2281 cmd = pool_tmpappend(pool, cmd, cmd ? "," : 0, resultflags2str[i].str);
2282 cmd = pool_tmpjoin(pool, "result ", cmd ? cmd : "?", 0);
2283 cmd = pool_tmpappend(pool, cmd, " ", resultname);
2284 strqueue_push(&sq, cmd);
2285 result = testcase_solverresult(solv, resultflags);
2286 if (!strcmp(resultname, "<inline>"))
2287 {
2288 int i;
2289 Strqueue rsq;
2290 strqueue_init(&rsq);
2291 strqueue_split(&rsq, result);
2292 for (i = 0; i < rsq.nstr; i++)
2293 {
2294 cmd = pool_tmpjoin(pool, "#>", rsq.str[i], 0);
2295 strqueue_push(&sq, cmd);
2296 }
2297 strqueue_free(&rsq);
2298 }
2299 else
2300 {
2301 out = pool_tmpjoin(pool, dir, "/", resultname);
2302 if (!(fp = fopen(out, "w")))
2303 {
2304 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: could not open '%s' for writing\n", out);
2305 solv_free(result);
2306 strqueue_free(&sq);
2307 return 0;
2308 }
2309 if (result && *result && fwrite(result, strlen(result), 1, fp) != 1)
2310 {
2311 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: write error\n");
2312 solv_free(result);
2313 strqueue_free(&sq);
2314 fclose(fp);
2315 return 0;
2316 }
2317 if (fclose(fp))
2318 {
2319 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: write error\n");
2320 strqueue_free(&sq);
2321 return 0;
2322 }
2323 }
2324 solv_free(result);
2325 }
2326
2327 cmd = strqueue_join(&sq);
2328 out = pool_tmpjoin(pool, dir, "/", testcasename);
2329 if (!(fp = fopen(out, "w")))
2330 {
2331 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: could not open '%s' for writing\n", out);
2332 strqueue_free(&sq);
2333 return 0;
2334 }
2335 if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1)
2336 {
2337 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: write error\n");
2338 strqueue_free(&sq);
2339 fclose(fp);
2340 return 0;
2341 }
2342 if (fclose(fp))
2343 {
2344 pool_debug(solv->pool, SOLV_ERROR(1<<1), "testcase_write: write error\n");
2345 strqueue_free(&sq);
2346 return 0;
2347 }
2348 solv_free(cmd);
2349 strqueue_free(&sq);
2350 return 1;
2351}
2352
2353int
2354testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
2355{
2356 Pool *pool = solv->pool;
2357 int i, r, repoid;
2358 int mangle = 1;
2359 const char **orignames;
2360
2361 /* mangle repo names so that there are no conflicts */
2362 orignames = solv_calloc(pool->nrepos, sizeof(char *));
2363 for (repoid = 1; repoid < pool->nrepos; repoid++)
2364 {
2365 Repo *repo = pool_id2repo(pool, repoid);
2366 char *buf = solv_malloc((repo->name ? strlen(repo->name) : 0) + 40);
2367 char *mp;
2368 orignames[repoid] = repo->name;
2369 if (!repo->name || !repo->name[0])
2370 sprintf(buf, "#%d", repoid);
2371 else
2372 strcpy(buf, repo->name);
2373 for (i = 0; buf[i]; i++)
2374 if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '/')
2375 buf[i] = '_';
2376 mp = buf + strlen(buf);
2377 for (;;)
2378 {
2379 for (i = 1; i < repoid; i++)
2380 if (!strcmp(buf, pool_id2repo(pool, i)->name))
2381 break;
2382 if (i == repoid)
2383 break;
2384 sprintf(mp, "_%d", mangle++);
2385 }
2386 repo->name = buf;
2387 }
2388 r = testcase_write_mangled(solv, dir, resultflags, testcasename, resultname);
2389 for (repoid = 1; repoid < pool->nrepos; repoid++)
2390 {
2391 Repo *repo = pool_id2repo(pool, repoid);
2392 solv_free((void *)repo->name);
2393 repo->name = orignames[repoid];
2394 }
2395 solv_free(orignames);
2396 return r;
2397}
2398
2399static char *
2400read_inline_file(FILE *fp, char **bufp, char **bufpp, int *buflp)
2401{
2402 char *result = solv_malloc(1024);
2403 char *rp = result;
2404 int resultl = 1024;
2405
2406 for (;;)
2407 {
2408 size_t rl;
2409 if (rp - result + 256 >= resultl)
2410 {
2411 resultl = rp - result;
2412 result = solv_realloc(result, resultl + 1024);
2413 rp = result + resultl;
2414 resultl += 1024;
2415 }
2416 if (!fgets(rp, resultl - (rp - result), fp))
2417 *rp = 0;
2418 rl = strlen(rp);
2419 if (rl && (rp == result || rp[-1] == '\n'))
2420 {
2421 if (rl > 1 && rp[0] == '#' && rp[1] == '>')
2422 {
2423 memmove(rp, rp + 2, rl - 2);
2424 rl -= 2;
2425 }
2426 else
2427 {
2428 while (rl + 16 > *buflp)
2429 {
2430 *bufp = solv_realloc(*bufp, *buflp + 512);
2431 *buflp += 512;
2432 }
2433 memmove(*bufp, rp, rl);
2434 if ((*bufp)[rl - 1] == '\n')
2435 {
2436 ungetc('\n', fp);
2437 rl--;
2438 }
2439 (*bufp)[rl] = 0;
2440 (*bufpp) = *bufp + rl;
2441 rl = 0;
2442 }
2443 }
2444 if (rl <= 0)
2445 {
2446 *rp = 0;
2447 break;
2448 }
2449 rp += rl;
2450 }
2451 return result;
2452}
2453
2454static char *
2455read_file(FILE *fp)
2456{
2457 char *result = solv_malloc(1024);
2458 char *rp = result;
2459 int resultl = 1024;
2460
2461 for (;;)
2462 {
2463 size_t rl;
2464 if (rp - result + 256 >= resultl)
2465 {
2466 resultl = rp - result;
2467 result = solv_realloc(result, resultl + 1024);
2468 rp = result + resultl;
2469 resultl += 1024;
2470 }
2471 rl = fread(rp, 1, resultl - (rp - result), fp);
2472 if (rl <= 0)
2473 {
2474 *rp = 0;
2475 break;
2476 }
2477 rp += rl;
2478 }
2479 return result;
2480}
2481
2482static int
2483str2resultflags(Pool *pool, char *s) /* modifies the string! */
2484{
2485 int i, resultflags = 0;
2486 while (s)
2487 {
2488 char *se = strchr(s, ',');
2489 if (se)
2490 *se++ = 0;
2491 for (i = 0; resultflags2str[i].str; i++)
2492 if (!strcmp(s, resultflags2str[i].str))
2493 {
2494 resultflags |= resultflags2str[i].flag;
2495 break;
2496 }
2497 if (!resultflags2str[i].str)
2498 pool_debug(pool, SOLV_ERROR(1<<1), "result: unknown flag '%s'\n", s);
2499 s = se;
2500 }
2501 return resultflags;
2502}
2503
2504Solver *
2505testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **resultp, int *resultflagsp)
2506{
2507 Solver *solv;
2508 char *buf, *bufp;
2509 int bufl;
2510 char *testcasedir, *s;
2511 int l;
2512 char **pieces = 0;
2513 int npieces = 0;
2514 int prepared = 0;
2515 int closefp = !fp;
2516 int poolflagsreset = 0;
2517 int missing_features = 0;
2518 Id *genid = 0;
2519 int ngenid = 0;
2520 Queue autoinstq;
2521
2522 if (resultp)
2523 *resultp = 0;
2524 if (resultflagsp)
2525 *resultflagsp = 0;
2526 if (!fp && !(fp = fopen(testcase, "r")))
2527 {
2528 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: could not open '%s'\n", testcase);
2529 return 0;
2530 }
2531 testcasedir = solv_strdup(testcase);
2532 if ((s = strrchr(testcasedir, '/')) != 0)
2533 s[1] = 0;
2534 else
2535 *testcasedir = 0;
2536 bufl = 1024;
2537 buf = solv_malloc(bufl);
2538 bufp = buf;
2539 solv = 0;
2540 queue_init(&autoinstq);
2541 for (;;)
2542 {
2543 if (bufp - buf + 16 > bufl)
2544 {
2545 bufl = bufp - buf;
2546 buf = solv_realloc(buf, bufl + 512);
2547 bufp = buf + bufl;
2548 bufl += 512;
2549 }
2550 if (!fgets(bufp, bufl - (bufp - buf), fp))
2551 break;
2552 bufp = buf;
2553 l = strlen(buf);
2554 if (!l || buf[l - 1] != '\n')
2555 {
2556 bufp += l;
2557 continue;
2558 }
2559 buf[--l] = 0;
2560 s = buf;
2561 while (*s && (*s == ' ' || *s == '\t'))
2562 s++;
2563 if (!*s || *s == '#')
2564 continue;
2565 npieces = 0;
2566 /* split it in pieces */
2567 for (;;)
2568 {
2569 while (*s == ' ' || *s == '\t')
2570 s++;
2571 if (!*s)
2572 break;
2573 pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
2574 pieces[npieces++] = s;
2575 while (*s && *s != ' ' && *s != '\t')
2576 s++;
2577 if (*s)
2578 *s++ = 0;
2579 }
2580 pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
2581 pieces[npieces] = 0;
2582 if (!strcmp(pieces[0], "repo") && npieces >= 4)
2583 {
2584 Repo *repo = repo_create(pool, pieces[1]);
2585 FILE *rfp;
2586 int prio, subprio;
2587 const char *rdata;
2588
2589 prepared = 0;
2590 if (!poolflagsreset)
2591 {
2592 poolflagsreset = 1;
2593 testcase_resetpoolflags(pool); /* hmm */
2594 }
2595 if (sscanf(pieces[2], "%d.%d", &prio, &subprio) != 2)
2596 {
2597 subprio = 0;
2598 prio = atoi(pieces[2]);
2599 }
2600 repo->priority = prio;
2601 repo->subpriority = subprio;
2602 if (strcmp(pieces[3], "empty") != 0)
2603 {
2604 const char *repotype = pool_tmpjoin(pool, pieces[3], 0, 0); /* gets overwritten in <inline> case */
2605 if (!strcmp(pieces[4], "<inline>"))
2606 {
2607 char *idata = read_inline_file(fp, &buf, &bufp, &bufl);
2608 rdata = "<inline>";
2609 rfp = solv_xfopen_buf(rdata, &idata, 0, "rf");
2610 }
2611 else
2612 {
2613 rdata = pool_tmpjoin(pool, testcasedir, pieces[4], 0);
2614 rfp = solv_xfopen(rdata, "r");
2615 }
2616 if (!rfp)
2617 {
2618 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: could not open '%s'\n", rdata);
2619 }
2620 else if (!strcmp(repotype, "testtags"))
2621 {
2622 testcase_add_testtags(repo, rfp, 0);
2623 fclose(rfp);
2624 }
2625 else if (!strcmp(repotype, "solv"))
2626 {
2627 repo_add_solv(repo, rfp, 0);
2628 fclose(rfp);
2629 }
2630#if ENABLE_TESTCASE_HELIXREPO
2631 else if (!strcmp(repotype, "helix"))
2632 {
2633 repo_add_helix(repo, rfp, 0);
2634 fclose(rfp);
2635 }
2636#endif
2637 else
2638 {
2639 fclose(rfp);
2640 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: unknown repo type for repo '%s'\n", repo->name);
2641 }
2642 }
2643 }
2644 else if (!strcmp(pieces[0], "system") && npieces >= 3)
2645 {
2646 int i;
2647
2648 /* must set the disttype before the arch */
2649 prepared = 0;
2650 if (strcmp(pieces[2], "*") != 0)
2651 {
2652 char *dp = pieces[2];
2653 while (dp && *dp)
2654 {
2655 char *dpe = strchr(dp, ',');
2656 if (dpe)
2657 *dpe = 0;
2658 for (i = 0; disttype2str[i].str != 0; i++)
2659 if (!strcmp(disttype2str[i].str, dp))
2660 break;
2661 if (dpe)
2662 *dpe++ = ',';
2663 if (disttype2str[i].str)
2664 {
2665#ifdef MULTI_SEMANTICS
2666 if (pool->disttype != disttype2str[i].type)
2667 pool_setdisttype(pool, disttype2str[i].type);
2668#endif
2669 if (pool->disttype == disttype2str[i].type)
2670 break;
2671 }
2672 dp = dpe;
2673 }
2674 if (!(dp && *dp))
2675 {
2676 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: system: could not change disttype to '%s'\n", pieces[2]);
2677 missing_features = 1;
2678 }
2679 }
2680 if (strcmp(pieces[1], "unset") == 0)
2681 pool_setarch(pool, 0);
2682 else if (pieces[1][0] == ':')
2683 pool_setarchpolicy(pool, pieces[1] + 1);
2684 else
2685 pool_setarch(pool, pieces[1]);
2686 if (npieces > 3)
2687 {
2688 Repo *repo = testcase_str2repo(pool, pieces[3]);
2689 if (!repo)
2690 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: system: unknown repo '%s'\n", pieces[3]);
2691 else
2692 pool_set_installed(pool, repo);
2693 }
2694 }
2695 else if (!strcmp(pieces[0], "job") && npieces > 1)
2696 {
2697 char *sp;
2698 Id how, what;
2699 if (prepared <= 0)
2700 {
2701 pool_addfileprovides(pool);
2702 pool_createwhatprovides(pool);
2703 prepared = 1;
2704 }
2705 if (npieces >= 3 && !strcmp(pieces[2], "selection"))
2706 {
2707 addselectionjob(pool, pieces + 1, npieces - 1, job);
2708 continue;
2709 }
2710 /* rejoin */
2711 for (sp = pieces[1]; sp < pieces[npieces - 1]; sp++)
2712 if (*sp == 0)
2713 *sp = ' ';
2714 how = testcase_str2job(pool, pieces[1], &what);
2715 if (how >= 0 && job)
2716 queue_push2(job, how, what);
2717 }
2718 else if (!strcmp(pieces[0], "vendorclass") && npieces > 1)
2719 {
2720 pool_addvendorclass(pool, (const char **)(pieces + 1));
2721 }
2722 else if (!strcmp(pieces[0], "namespace") && npieces > 1)
2723 {
2724 int i = strlen(pieces[1]);
2725 s = strchr(pieces[1], '(');
2726 if (!s && pieces[1][i - 1] != ')')
2727 {
2728 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: bad namespace '%s'\n", pieces[1]);
2729 }
2730 else
2731 {
2732 Id name, evr, id;
2733 Queue q;
2734 queue_init(&q);
2735 *s = 0;
2736 pieces[1][i - 1] = 0;
2737 name = pool_str2id(pool, pieces[1], 1);
2738 evr = pool_str2id(pool, s + 1, 1);
2739 *s = '(';
2740 pieces[1][i - 1] = ')';
2741 id = pool_rel2id(pool, name, evr, REL_NAMESPACE19, 1);
2742 for (i = 2; i < npieces; i++)
2743 queue_push(&q, testcase_str2solvid(pool, pieces[i]));
2744 /* now do the callback */
2745 if (prepared <= 0)
2746 {
2747 pool_addfileprovides(pool);
2748 pool_createwhatprovides(pool);
2749 prepared = 1;
2750 }
2751 pool->whatprovides_rel[GETRELID(id)((id) ^ 0x80000000)] = pool_queuetowhatprovides(pool, &q);
2752 queue_free(&q);
2753 }
2754 }
2755 else if (!strcmp(pieces[0], "poolflags"))
2756 {
2757 int i;
2758 if (!poolflagsreset)
2759 {
2760 poolflagsreset = 1;
2761 testcase_resetpoolflags(pool); /* hmm */
2762 }
2763 for (i = 1; i < npieces; i++)
2764 testcase_setpoolflags(pool, pieces[i]);
2765 }
2766 else if (!strcmp(pieces[0], "solverflags") && npieces > 1)
2767 {
2768 int i;
2769 if (!solv)
2770 {
2771 solv = solver_create(pool);
2772 testcase_resetsolverflags(solv);
2773 }
2774 for (i = 1; i < npieces; i++)
2775 testcase_setsolverflags(solv, pieces[i]);
2776 }
2777 else if (!strcmp(pieces[0], "result") && npieces > 1)
2778 {
2779 char *result = 0;
2780 int resultflags = str2resultflags(pool, pieces[1]);
2781 const char *rdata;
2782 if (npieces > 2)
2783 {
2784 rdata = pool_tmpjoin(pool, testcasedir, pieces[2], 0);
2785 if (!strcmp(pieces[2], "<inline>"))
2786 result = read_inline_file(fp, &buf, &bufp, &bufl);
2787 else
2788 {
2789 FILE *rfp = fopen(rdata, "r");
2790 if (!rfp)
2791 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: could not open '%s'\n", rdata);
2792 else
2793 {
2794 result = read_file(rfp);
2795 fclose(rfp);
2796 }
2797 }
2798 }
2799 if (resultp)
2800 *resultp = result;
2801 else
2802 solv_free(result);
2803 if (resultflagsp)
2804 *resultflagsp = resultflags;
2805 }
2806 else if (!strcmp(pieces[0], "nextjob"))
2807 {
2808 if (npieces == 2 && resultflagsp && !strcmp(pieces[1], "reusesolver"))
2809 *resultflagsp |= TESTCASE_RESULT_REUSE_SOLVER(1 << 31);
2810 break;
2811 }
2812 else if (!strcmp(pieces[0], "disable") && npieces == 3)
2813 {
2814 Id p;
2815 if (strcmp(pieces[1], "pkg"))
2816 {
2817 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: bad disable type '%s'\n", pieces[1]);
2818 continue;
2819 }
2820 if (!prepared)
2821 pool_createwhatprovides(pool);
2822 prepared = -1;
2823 if (!pool->considered)
2824 {
2825 pool->considered = solv_calloc(1, sizeof(Map));
2826 map_init(pool->considered, pool->nsolvables);
2827 map_setall(pool->considered);
2828 }
2829 p = testcase_str2solvid(pool, pieces[2]);
2830 if (p)
2831 MAPCLR(pool->considered, p)((pool->considered)->map[(p) >> 3] &= ~(1 <<
((p) & 7)))
;
2832 else
2833 pool_debug(pool, SOLV_ERROR(1<<1), "disable: unknown package '%s'\n", pieces[2]);
2834 }
2835 else if (!strcmp(pieces[0], "feature"))
2836 {
2837 int i, j;
2838 for (i = 1; i < npieces; i++)
2839 {
2840 for (j = 0; features[j]; j++)
2841 if (!strcmp(pieces[i], features[j]))
2842 break;
2843 if (!features[j])
2844 {
2845 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: missing feature '%s'\n", pieces[i]);
2846 missing_features++;
2847 }
2848 }
2849 if (missing_features)
2850 break;
2851 }
2852 else if (!strcmp(pieces[0], "genid") && npieces > 1)
2853 {
2854 Id id;
2855 /* rejoin */
2856 if (npieces > 2)
2857 {
2858 char *sp;
2859 for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
2860 if (*sp == 0)
2861 *sp = ' ';
2862 }
2863 genid = solv_extend(genid, ngenid, 1, sizeof(*genid), 7);
2864 if (!strcmp(pieces[1], "op") && npieces > 2)
2865 {
2866 struct oplist *op;
2867 for (op = oplist; op->flags; op++)
2868 if (!strncmp(pieces[2], op->opname, strlen(op->opname)))
2869 break;
2870 if (!op->flags)
2871 {
2872 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: genid: unknown op '%s'\n", pieces[2]);
2873 break;
2874 }
2875 if (ngenid < 2)
2876 {
2877 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: genid: out of stack\n");
2878 break;
2879 }
2880 ngenid -= 2;
2881 id = pool_rel2id(pool, genid[ngenid] , genid[ngenid + 1], op->flags, 1);
2882 }
2883 else if (!strcmp(pieces[1], "lit"))
2884 id = pool_str2id(pool, npieces > 2 ? pieces[2] : "", 1);
2885 else if (!strcmp(pieces[1], "null"))
2886 id = 0;
2887 else if (!strcmp(pieces[1], "dep"))
2888 id = testcase_str2dep(pool, pieces[2]);
2889 else
2890 {
2891 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: genid: unknown command '%s'\n", pieces[1]);
2892 break;
2893 }
2894 genid[ngenid++] = id;
2895 }
2896 else if (!strcmp(pieces[0], "autoinst") && npieces > 2)
2897 {
2898 if (strcmp(pieces[1], "name"))
2899 {
2900 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: autoinst: illegal mode\n");
2901 break;
2902 }
2903 queue_push(&autoinstq, pool_str2id(pool, pieces[2], 1));
2904 }
2905 else
2906 {
2907 pool_debug(pool, SOLV_ERROR(1<<1), "testcase_read: cannot parse command '%s'\n", pieces[0]);
2908 }
2909 }
2910 while (job && ngenid > 0)
2911 queue_push2(job, SOLVER_NOOP0x0000 | SOLVER_SOLVABLE_PROVIDES0x03, genid[--ngenid]);
2912 if (autoinstq.count)
2913 pool_add_userinstalled_jobs(pool, &autoinstq, job, GET_USERINSTALLED_NAMES(1 << 0) | GET_USERINSTALLED_INVERTED(1 << 1));
2914 queue_free(&autoinstq);
2915 genid = solv_free(genid);
2916 buf = solv_free(buf);
2917 pieces = solv_free(pieces);
2918 solv_free(testcasedir);
2919 if (!prepared)
2920 {
2921 pool_addfileprovides(pool);
2922 pool_createwhatprovides(pool);
2923 }
2924 if (!solv)
2925 {
2926 solv = solver_create(pool);
2927 testcase_resetsolverflags(solv);
2928 }
2929 if (closefp)
2930 fclose(fp);
2931 if (missing_features)
2932 {
2933 solver_free(solv);
2934 solv = 0;
2935 if (resultflagsp)
2936 *resultflagsp = 77; /* hack for testsolv */
2937 }
2938 return solv;
2939}
2940
2941char *
2942testcase_resultdiff(const char *result1, const char *result2)
2943{
2944 Strqueue sq1, sq2, osq;
2945 char *r;
2946 strqueue_init(&sq1);
2947 strqueue_init(&sq2);
2948 strqueue_init(&osq);
2949 strqueue_split(&sq1, result1);
2950 strqueue_split(&sq2, result2);
2951 strqueue_sort(&sq1);
2952 strqueue_sort(&sq2);
2953 strqueue_diff(&sq1, &sq2, &osq);
2954 r = osq.nstr ? strqueue_join(&osq) : 0;
2955 strqueue_free(&sq1);
2956 strqueue_free(&sq2);
2957 strqueue_free(&osq);
2958 return r;
2959}
2960