Bug Summary

File:ext/testcase.c
Warning:line 998, column 3
Value stored to 'what' is never read

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;
Value stored to 'what' is never read
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;
1328 intag = 0;
1329
1330 aline = 1024;
1331 line = solv_malloc(aline);
1332 linep = line;
1333 for (;;)
1334 {
1335 if (linep - line + 16 > aline)
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))
1343 break;
1344 linep += strlen(linep);
1345 if (linep == line || linep[-1] != '\n')
1346 continue;
1347 linep[-1] = 0;
1348 linep = line + intag;
1349 if (intag)
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] != ':')
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] != ':')
1370 continue;
1371 tag = line[1] << 16 | line[2] << 8 | line[3];
1372 switch(tag)
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);
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;
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